We outsourced the development of Blackberry 5, 6, and 7 apps. Please bare in mind that I have absolutely no knowledge of Blackberry development at all.
Development is complete, and they have sent us the source code - a collection of .cod, .csl, .cso, .debug, .jad and .rapc files.
I would at least like to review the code in terms of it's consistency and standards - somewhat a measure of the quality. Clean code is not something specific to any one platform.
I have tried to open each of these files in notepad, but with no source code found.
Please advise me on what I need before I go pay them a visit.
The files you have been given are the files that are created as part of the build of your project and the resultant executable files. There is no source included here.
In a BB OS Build, regardless of the development environment used, the Java source files will all have the suffix .java, and the assets (images etc.) will have a suffix appropriate to the asset (like .png). If you don't see these file suffixes, then you have not been given the actual source. You should be able to view the java files using Notepad, the other files will open in an appropriate application (like paint).
To get the complete source, you should just ask the full 'project' files for your development. This will be a directory with a number of sub directories. The actual names used and the structure will depend on the development tool. If your developer is using Eclipse, then the two important directories are called src for source and res (resources) for the assets. If they are using another development environment, then the directories might have different names. So you should ask them what development environment they are using too.
Two other points:
1) If you are paying for this development and wish to review the code, but are not familiar with Java, then I would recommend that you pay someone to review the code who has knowledge of BB Java. There are two reasons for this:
(a) you will not be able to form a judgement on the appropriateness of the code without some understanding of Java, and
(b) you will not understand if the correct BB Java approaches have been used.
You need to be cautious about this, because programmers will always find fault in other developer's code. The question is how significant the faults are.
2) Some developers might be wary of giving source to their client while some payment is outstanding.
Related
I have a large application to manage consisting of of three or four executables and as many as fifty .dlls. Many of the source code files are shared across many of the projects.
The problem is a familiar one to many of us - if I change some source code I want to be able to identify which of the binaries will change and, therefore, what it is appropriate to retest.
A simple approach would be simply to compare file sizes. That is an 80% acceptable solution, but there is at least a theoretical possibility of missing something. Secondly, it gives me very little indication as to WHAT has changed; It would be ideal to get some form of report on this so I can then filter out irrelevant (e.g. dates/versions copyrights etc..)
On the plus side :
all my .dcus are in a row - I mean they are all built into a single folder
the build is controlled by a script (.bat)(easy, for example, to emit .obj files if that helps)
svn makes it easy to collect together any (two) revisions for comparison
On the minus side
There is no policy to include all used units in all projects; some units get included because they are on a search path.
Just knowing that a changed unit is used/compiled by a project is not sufficient proof that the binary is affected.
Before I begin writing some code to solve the problem I would like to ask the panel what suggestions they might have as to how to approach this.
The rules of StackOverflow forbid me to ask for recommended software, but if anyone has any positive experiences of continuous integration tools that would help - great
I am open to any suggestion or observation that is relevant in this context.
It seems to me that your question boils down to knowing which units are contained in your various executables. Since you are using search paths, it will be hard for you to work this out ahead of time. The most robust way to find out is to consult the .map file that the compiler emits. This contains a list of all units contained in your executable.
Once you know which units are contained in each executable, you need to know whether or not anything has changed in those units. That information is contained in your revision control system. Put this all together and you have the information that you need.
Of course, just because the source code for a unit has changed, you might argue that re-testing is not needed. Perhaps the only change made was the version, or the date in a copyright label or some such. But it is asking too much to be able to ask a computer to make such a judgement. At some point you need a human to step up and take responsibility.
What is odd about this though is that you are asking the question at all. It seems to me to be enormously risky to attempt partial testing. I cannot understand why you don't simply retest the entire product.
After using it for > 10 years for commercial in-house and freelancer work in large projects, I can recommend to try Apache Ant. It is a build tool which supports dependencies, and has many very helpful features.
Apache Ant also integrates nicely with CI tools such as Hudson/Jenkins, Bamboo etc.
Another suggestion - based on experience with Maven - is to design the general software architecture as modular as possible. If modules (single or multiple source or DCU files in one directory) use a version number in the directory name as a version number, it is possible to control exactly how application are composed from these modules.
If you want to program such a tool yourself the approach would be something like this:
First you need to detect wheter there were any changes made to seperate source files. As you already figured out comparing the file size is bad idea as the file size can stay the same despite lots of changes made to it (as long as there is same amount of text in pas file its size won't change). So instead you could check the last modification time for specific file or create some hash value like MD5 hash for comparison (can be quite slow).
Then you need to generate yourself a dependancy tree which will tell you which files are used for which project/subproject.
Finally based on changes detected in seperate files you check the dependancy tree to see which projects needs to be recompiled.
The problem of such approach is that you would probably have to update the dependancy tree manually each time when new unit is added to the project or an existing one is removed from the project.
But the best way would be to go and use some version controll software istead of reinventing the wheel. I myself like the way how GIT works and I belive that with proper implementation of GIT into the project mannager itself could be quite powerfull do to GIT support of branching/subbranching (each project is its own branch, each version of your software can be its own subbranch).
Now latest version of Delphi does have GIT integration done though SVN but this unfortunately limits some of best GIT functionality. So if you maybe decide to go and integrate GIT support directly into Delphi I'm first in line to use it.
I have an application I've been handed to test, and I'm — shall we say — less than impressed?
I believe the company that built the application for my client didn't build it as an iOS native application; my gut feel is they leveraged one of the multi-target platforms because that's what they're comfortable with. The application's usability is particularly poor, and it just doesn't behave the way an iOS application should.
How can I tell whether this application is native or built on some OS-agnostic platform? Any big give-aways that can tell me?
FWIW, the iPad is the only target platform for this device. It won't need to run anywhere else.
Are you saying that it doesn't have the look and feel of a regular iOS app? It's possible that it has been developed in AIR, HTML5, etc. I don't know if there is much way of doing this without jailbreaking the device.
You could, of course, ask around or post a screenshot and see what others think.
Get the binary out of the device, using softs like DiskAid (free for that part - no jailbreak required), and study it. You may get important infos through a disassembler, such as Hopper, which has support for ARM.
If you can't read assembly, study the application's resources. It may also give you some hints. Again, a software like DiskAid will allow that.
While "some OS-agnostic platform" is a bit broad, there is an easy way to tell if an app was made with PhoneGap, arguably one of the most popular OS-agnostic platforms.
Copy the .ipa file you've been sent (or find it on your filesystem
and copy it).
Rename the copy WhatEverTheAppNameIs.zip.
Extract the zipped folder and open it.
Open the folder named "Payload" (If it isn't already).
Right-click on BlahBlah.app and select "Show Package Contents".
Inspect the bundle.
Check for the presence of a www folder. If it's contents are sizable (compared with the packages contents in general) there's a good chance the whole app was made with PhoneGap.
It's also illuminating to click on the index.html file in the www folder just to see how much of the app runs in desktop Safari.
You may also discover other evidence of OS-agnostic platforms by examining the bundle further.
We have a software package which is about 16 years old. It's gone through just about every version of Delphi (besides .NET ones). Over the years, things have become very confusing when it comes to cross-referencing and keeping proper setup for additional packages (like third-party libraries). I was wondering if there is some standard practice when it comes to keeping large projects (and groups of projects) like this organized.
So to explain the current setup...
This is a multi-application system. Meaning, there are 12 executable projects (and a few DLL and service projects) involved. We also keep things in SourceSafe and multiple developers work on the same code on different computers. All of these projects are more-so dumped into a central folder. The "Root" folder contains THE major EXE project (along with about 20 folders, all containing units and forms) and it almost seems like an endless hierarchy of folders and files. This one project alone has half a million lines of code involved.
Then all the additional applications aren't necessarily separated properly from this major project. Each of these projects has its own folder based in the main project's root.
The two major concerns of mine are:
How to properly set up the DCU files so that they aren't mixed in with the projects? DCU's should NOT be placed in the SourceSafe (and any similar file, for that matter) or otherwise, any file compiled from the project. Visual SourceSafe makes files read-only when they're not checked out, and DCU files (and EXE files and more) cannot be written to in this case. So how to properly separate any of such file to a remote location to avoid any mixture with the source code?
How to properly set up packages and libraries? We have the following:
QuickReports 5.05
NativeJpg library V302 -
Another anonymous reporting library
Our own component package, which requires QuickReports, NativeJpg, and the other anonymous library
All 4 of those libraries are stored in completely different places of each computer, and need some centralization. The biggest pain of setting up each new developer's computer is locating these from the lead developer's computer and copying them to the same place on each other computer (and making sure the library path is correct, etc.).
We also need to keep completely separate environments for different versions of Delphi on the same computer. This means a copy of the projects on each computer, a copy of packages and libraries on each computer, a copy of the projects and packages and libraries in the SourceSafe, etc. Each computer needs to have an identical setup. We already utilize environment variables to direct our projects where to look for certain project files (and libraries).
Another new concern: XE2 introduces 64bit capabilities. We don't plan on 64bit compiling yet, but we certainly will in the future. How do I properly differentiate 32bit from 64bit in all these projects?
What I'm really asking for is a reference to a good tutorial on how to optimize such an environment and keep it organized the best. I don't expect anyone to take the time and answer all this in the question. The projects are over 15 years old, have had the hands of 200+ developers from around the world in it, and has a LOT of cross-referencing between projects. For example, one project may use a unit from another project, and vice-versa. I personally don't like this concept, but I also didn't design it to begin with. I've been given the task to get this system organized and thoroughly documented how to set up Delphi on a new computer for new developers to work on our projects. As I'm looking at our projects (as I'm not necessarily a developer of the system, but am being pulled into development), I'm seeing a lot of confusion in how the code is organized.
I am assuming that possibly Embarcadero has some guidelines and standards on setting up such an environment?
Location of DCU files
Regarding the DCUs that are the output of the compilation process, you should specify a DCU output directory in each project file. The default value for this, in the latest version of Delphi would be fine: .\$(Platform)\$(Config). This results in sub-folders of the project directory like this: Win32\DEBUG or Win64\RELEASE.
If you set-up your project files using option sets then you will be able to control this setting (and all others) from a small number of option files.
Location of 3rd party code
You should always use 3rd party library as code. If the vendor charges more to receive the library as code, pay up. Once you have done so you simply include the source code into your version control system (VCS) and treat it largely the same way as you treat your own code. I say largely because you should avoid modifying it.
Once you have all your code in the VCS then you can put the entire source code onto a new machine with a single checkout operation.
Organisation of your projects
I personally have a strong aversion to using compiler search paths. I don't use them and include every unit that is required in a project in the .dpr file.
If you do use search paths then you make it impossible to work on variant projects.So for example, suppose you have a client that has discovered a bug in the version of the software you released 2 years ago. You would like to address that bug by releasing an upgrade to the 2 year old version of the software. It is perfectly plausible that asking them to upgrade to the latest version is not viable. Perhaps they have not paid for the upgrades. Perhaps the full upgrade has breaking changes that they do not want to tackle right now. A perfect example would be all the Delphi developers still using Delphi 7.
Now, having motivated the scenario, how would you create a build environment for the 2 year old project? If you are using search paths then they will refer to today's libraries. You would be forced to change your search path, or copy the old libraries over the top of today's libraries.
That entire headache is trivially side-stepped by not using search paths and by including all your source in the VCS.
What you should be aiming for is to be able to checkout any historic version of your program and have it build immediately. You should be able to do this with full confidence that you are building identical software to what was built at the time that version was released. This also requires you to have build automation but I can't imagine you are lacking that for a project of this size.
I'll address folder organisation. This comes from a software suite which has 50+ exe's and dll's and plenty third party libraries, so I guess I know where you are coming from...
We use Perforce as a source control system, so my default workspace's root folder is called Perforce, but I also have a couple of other workspaces set up and they are in Perforce2, Perforce3, etc.
General folder setup (starting from the workspace root folder)
General
Components
Delphi
Indy
Indy9
Indy10
MadCollection
v2.5.8.0
v2.6.0.0
Plugins
Releases
Released
... a folder for each release we publish ... (and equal to a branch in Perforce)
Work
Acceptance
Sub1
Sub2
My Environment library path in the IDE is empty (not even the BDE standard paths are in there). This ensures that a project's paths declare all path's needed and that projects are not reliant upon a particular machine's IDE setup.
We have an environment var (ie MRJ) set up in our IDE's that points to "General\Components\Delphi" so in a project's options we declare the paths to our components as $(MRJ)\MadCollection\2.6.0.0.
General holds IDE plugins and components used by our projects. We keep all versions we use in source control. That way when I have to switch back to an old release to track down a problem, I can simply pull it and build it as its library paths will still point to the version of the components that this specific release needs.
The organisation of folders in a particular work branch (Acceptance or one of its subbranches) follows this pattern:
General
Includes
MainComponent1
Project1
Project2
Shared
MainComponent2
Project3
Project4
Shared
Shared
Windows
SoftwareSuite
Scripts
Tools
MainComponent1
Project1
Dcus
Project2
Dcus
MainComponent2
Tools
Tool1
Dcus
Tool2
Dcus
The General folder holds all platform independent sources/files, the Windows folder holds all Windows specific files. Each component can hold multiple projects and will have a share folder for sources shared between those projects. The shared folder directly under General holds sources shared by all projects. The Windows folder is set up in a similar manner.
Note that each project has its own dcus folder. This is configured in the project options. As the path can be entered as .dcus, we (at least I) have this set up as the default for any new project. Each project sending its dcus to a unique folder ensures two things:
it is easy to keep dcu's out of version control by simply setting up a filter in your version control software.
more importantly it ensures that compilation/build of a project never interferes with the compilation/build of another project. I can safely change settings and build knowing that I won't be bothered by dcu's lying around from a previous build from another project.
I recommend the following practices:
Keep your library path simple, and make sure everything in the library path is either a folder that ships with delphi, or a DCU binary (library) folder in your d:\Components\ folder.
Use a MODERN type of version control. I recommend Mercurial over others. Source Safe is crap, stop using it.
Back up your environment (export registry keys etc) and restore it to the other developer PCs in a standardized way. You can keep a few .reg and .cmd (batch) files around to automate setup of a new system. you can put these scripts in your component repository in your version control system.
Outside the scope that was largely discuss before, I would recommend :
Unit testing - with DUnit for example
Continuous integration. Just to be sure that all these projects can compile on another machine and that tests are ok.
So this is heavily related to project organization and VCS strategy.
For a similar setup, a company I worked for found this configuration useful:
all third party libraries (components etc.) go to a fixed location (C:\Delphi\name-version)
Delphi projects can be checked out from version control anywhere (drive C: or D: and folder name does not matter), as all projects and scripts use relative paths
all projects are sub folders of one main project folder so checking out this one will bring the Delphi projects and other relevant resources to the workstation, and a version control update is easy to do
we use a build script (written in Apache Ant) which sits in the main folder, and iterates over all folders to build the Delphi apps and run unit and integration tests against a development database server, to verify all changes work before checking in to source control
the build script can also be run automatically on a build server (Hudson CI) on every commit to see if something broke
And a note about component libraries: avoid package installation where possible, prefer creation of components at run time. If you quickly need to apply a fix to a five year old version of a project, uninstalling / installing a dozen of packages can become frustrating. At least for non-visual components, run-time creation is a huge time saver.
Checking in third party code in source control can be very helpful, for example to share fixes which are not yet available as new official releases. Best practices are covered in the Subversion documentation chapter Vendor Branches.
Plus, with Subversion you can use svn:externals to place a specific version (tag) right into a project directory structure. This can be used both with third party library and with your own source code, and makes dependency management easier and workstation setup easier.
p.s. the Ant build script defines the search paths for everything, so it is 'the reference' for all developers how to configure the IDE, where to put the third party libs and which compiler flags to use
p.p.s. your project sounds like a lot of fun - I am open for contract work :)
My team use virtualization and when we see back it was a real good move.
We use MacBook Pro laptops and VmWare Fusion, but I'm sure other packages work fine as well like VirtualBox or VirtualPC.
It is always a good feeling to know that when a new developer starts or an old installation got trouble it is just to copy a new VM image from the master image and the setup is exactly as the original. The master image is stored on a fast USB2-disk. Now when Thunderbolt and USB3 is coming it would be even faster to copy an image. And there is no real concern about performance on a modern computer as long as there is memory. 8 GB should be enough to run 2 images in parallell. Another advantage of virtualization is that it is so easy to try What if scenario. Experiment with different configuarations and versions without any risk to disturb the real working environment.
Btw I also think that SourceSafe is crap... :-)
Somé tips:
Make one groupproject file for all the apps belonging to the project, each app in its own dir under the groupproj file
You should be able to specify which file types to include into your version control system. Make sure you set Delphi to write DFM files in text format.
You could tell Delphi to output DCUs in subdirs named 'dcu' under each app (less visaul clutter).
Third party stuff often insists on installing in distinct locations, there's not much you can do about it. Make a document describing how to setup a complete working environment and keep it up-to-date
Develop in virtual machines. A new developer gets a copy of the VM.
Maintaining for different Delphi versions? Rethink that, try to go to one version. If you absolutely must have two groupprojects and directory structures for each version. [I'm assuming you're not compiling the same app with two Delphi version, that's developer hell]
Delphi XE2 will output to different 32/64 subdirectories, that should give no problems.
Is there a way to group a bunch of DLL's and still use them at run time (not zipped up). Sorry this question sounds terse and stupid, but I'm not sure what more to ask.
I'll explain the situation though:
We've had two standalone Windows Applications and now one of our Applications has swelled to such ungainly proportions that the other application cannot run outside of the scope of the first app. We want to maintain some of the encapsulation we had while letting the smaller program in on some of the bigger program's features.
There is no problem in running the application, other than we don't want to send out all the 20-30 DLL's that the smaller project has.
It is possible to do this by adding startup code which checks if the DLLs are present on the target system and if not then extracts them from the resources section (or simply tagged onto the end of the exe). A good example of this being done is Process Explorer - it's distributed as a single binary, but when run it extracts and installs a driver.
If you have a situation where most, or all, of those assemblies have to be kept together, then I would highly recommend just merging the code files into the same project and recompiling. This would leave you with one assembly.
Of course there are other considerations like compile time, overall size of the final dll, how often various pieces change, and whether each component is deployed without the others.
One example of a company that did this is Telerik. Their dev components are all compiled into the same assembly. This makes deployment an absolute breeze. Contrasting that is Dev Express which put just about each control into it's own assembly. Because of this just maintaining, much less deploying, a Dev Express project is not something for the faint of heart.
(I don't work for either of those companies. However, I have a lot of experience with both toolkits.)
You could store the DLLs as Resources, and use BTMemoryModule, which essentially allows you to LoadLibrary on a Stream.
That way you could compile-in the multiple DLLs straight into the EXE or into a single resource DLL.
see http://www.jasontpenny.com/blog/2009/05/01/using-dlls-stored-as-resources-in-delphi-programs/
We create via "Tools | Options | Environment Variables" Variables like that:
$(Sources) = D:\Sources\Delphi
$(OurLib) = $(Sources)\OurLib\Src
$(OurApp1) = $(Sources)\Applications\App1\3.x
$(ThirdParty) = $(Sources)\ThirdPartyComponents
We use these Variables in the project search path like that:
($OurApp1)\Src\Core;($OurApp1)\Src\GUI;($OurApp1)\Src\Plugins;$(ThirdParty)\JVCL
But this is broken (meanwhile fixed) since Delphi 2009 as these variables are not evaluated completely anymore (see QC #73276). So the files in the directories are not found by the compiler. A workaround: Use only complete directories in the environment variables.
We use this approach because on all developer machines and the build servers the files can be found and we only have to point $(Sources) to the right place.
We don't have anything in our global library path (except the Delphi defaults), because that wouldn't be in the version control and isn't reflected on other developers or build machines.
One problem is: If one unit in $(OurLib) decides to include another new unit maybe in a new path, all projects break because they don't find this new unit. Then we have to go through all projects and add the search path. (BTW: I really hate the search path editor...wouldn't be a simple memo field much better to edit than this replace/add/delete logic?)
Another thing we do is not adding many units to our project. Especially everything from $(OurLib), but we often have units like plugins which add functionality only by including them. For different editions of our products, we want to include different units. As Delphi always messes up $IFDEFs in the uses clause in the .dpr we help us by including units named like "IncludePlugins" which then include the units depending on IFDEFs.
But not including units in the project makes navigating to a pain. The units don't appear in the project, they are not found by Ctrl+12 (Show Units), they are not shown in code completion etc.
Has anybody a better way to cope with these problems?
We use only relative paths, any libraries are always below the libs subdirectory while the project source code resides in the src subdir. So our search paths always look like:
..\libs\library1;..\libs\library2\common;
etc.
All libraries are added as svn:external to each project, so checking out the project will automatically check out the libraries as well and the search path will always point to the correct version of the library for that project.
Not perfect, but it works most of the time.
I have to agree about the search path editor, it is even worse for relative paths because you must not use the "..." buttons otherwise Delphi will insert an absolute path.
We use standard drive mappings.
Our current project is always on W: regardless if it is a network drive or a substitute.
This works great.
When you need to work on a different project, swap the W: and you can continue.
You can copy the search path out to an editor, modify it and then copy it back.
Your search path is much too big. It should contain only the things you want Delphi to recompile with your project. You don't really want to recompile the Jedi VCL every day, do you?
I create a single directory where all compiled units go. Say, C:\dcu. Specify that as the "unit output directory" in all packages. My "search path," then, is always just this:
$(Delphi)\Lib;C:\dcu
The compiler finds everything it needs, and it never finds any source code. The only source code it ever sees is in the files that directly belong to whatever project I'm compiling. The project's own source directories don't need to be on the search path because all of those files are already direct members of the project. The compiler knows exactly where they are.
For me, all a project's source files go in a single directory. If you want separate directories for different parts, like Core and GUI, then I would put those in separate packages so I could work on them and compile them separately. Even if the final program doesn't use the resultant BPLs, packages are still a good way of segmenting your project and defining dependencies.
When compiling units for one project doesn't automatically compile units for all the other projects, you're forced to change active projects. It takes a moment of your time, but it also serves as a mental reminder that you're "changing hats," too.
Although you're producing just one product, that doesn't mean you should have just one project in Delphi. You should have at least one project for each executable module (EXE, DLL, BPL) in your product. Use project groups to manage multiple projects in a single IDE session. No unit should be a member of more than one project.
I don't understand your part about plug-ins and different editions of your project. When you say "plug-in," I assume you're talking about separate executable modules, like DLLs or packages, that the customer can choose to include or not. Couldn't you turn your different editions' features into plug-in modules that simply don't include in the lesser editions? Then you don't have to worry about conditional compilation of your project; just have several different installer packagers that grab different sets of plug-ins.
I have always found it odd that this has never been addressed adequately. I suggested recently to David I that Delphi should allow the user to set up some sort of preferred development structure and that third party library publishers could be made aware of this so that they could automatically adjust their installers to install correctly in the preferred development framework. If the preferred development structure was stored in an XML file or similar, then, it could be copied from one computer to another on a development team.
As an alternative, it could make an interesting project to create a Delphi application that would allow a user to "refactor" their library installation in a high level way. You specify which folders on your system contain source or compiled components or whatever and where you want to keep source files or compiled units, hit Go and your system gets rearranged for you, while updating your Delphi environment so that when you start Delphi, it finds everything it should.
I've just recently discovered a way to have project specific environment variables in delphi builds using XE6, it's not quite as good as a full blown #define like in C but at least I can now have consistent search paths across multiple projects and create some shared option sets.
What I've done is setup environment variables in the same manner as the original poster and then override them in the dproj or optionset.
The BuildPaths.optset added to the project looks like
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<SVN_Root>..\..\..</SVN_Root>
<SVN_Riemann>$(SVN_Root)\Riemann</SVN_Riemann>
<SVN_Library>$(SVN_Root)\Library</SVN_Library>
<SVN_ThirdParty>$(SVN_Library)\Third Party</SVN_ThirdParty>
</PropertyGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>OptionSet</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality/>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
</Project>