Perfect Source Structure?
Is there a direct connection between how source is structured and how software is designed? No, not in compiled software. When software compiles, this is an indication of its abstraction from the source files. Don't confuse application architecture with source-code management. It's possible to achieve your design goals and reuse across products without heading down the path of sharing source code. The usual suspects of binary compatibility, RPC, and web services are answers to this question that do not effect source code nor introduce additional complexity.
Don't make the mistake of trying to create the ultimate source-code repository as a companion to an idealized application architecture. If the history of software development provides any guidance, then one of these is probably a chimera. Ownership of source code is important for its health and maintenance, therefore some group must take ownership. To accomplish this, ensure that all source code is accounted for and part of a team's roadmap. Avoid getting caught in unrealistic expectations of architecture driven by the source management process. There isn't a singular application architecture that must be subscribed to. After all, every system is unique and requires tradeoffs for longevity. To move the process forward, it's essential to help stakeholders understand that there are many scenariossome better than othersfor structuring source. Strive for as good as possible for the reality of your teams.
Branching and Continuous Integration
Continuous integration (CI) was the initialand still long-termgoal for build automation and concurrent development. But things aren't always that simple. Re-engineering a source-control tool or folder structure are child's play compared with changing how projects are planned and executed. (Read Scott Ambler's "The Agile Edge" column if you don't agree.) A goal of CI is to minimize the number of branches that are necessary for development isolation. This is accomplished by breaking down bigger projects into stories, which can be planned and executed on the trunk of the source tree. For better or worse, this kind of large-scale change in project planning is difficult to attain without direct input or the influence of project planners. In my case, project planning was happening at the same time as new build engineering activities. Synchronizing these was almost impossible. If your organization is one that depends on detailed functional specification documents and you don't see that changing anytime soon, you'll need to be practical and compromise.
With pure CI no longer a realistic option for allowing concurrent development, different branching strategies were investigated. There is plenty of guidance out there on branching, but most of it can be distilled from the smoke and mirrors into one maxim"branch to isolate." When you set a goal to allow isolation, the details around how and when to branch become much simpler. For example, part of the reason we couldn't roll out a more authentic form of CI right away is that projects are in the pipeline up to a year out, but don't all occur serially. They overlap, touch, depend on one another, and consequently, require coordination. Allowing this isolation keeps development rolling as opposed to deteriorating in fire fights on what CI or agile development is and how to get there; see Figure 2. Don't be legalistic: Trade continuous integration for continuous improvement when necessary. Being flexible can bring only benefit in the end, while being rigid in opinions or actions causes your attempts at change to fracture.
That said, some CI concepts are still applicable. Using a tool like CruiseControl.NET allows build automation per developer check-in. There is still immediate developer feedback on the status of the build, except it's not just one buildit's for all isolation branches. It is critical to use a tool (like CCNET or another) to automate CI or you'll soon be spinning your wheels on the minutiae. Figure 3 illustrates multiple branches in isolation.
Under this type of setup, the build server turns into your development lifeline. Its activities are viewed with glee by the process-oriented on the team, or derision by the cowboys. No matter the opinion, this server is extremely important as the workhorse of the team. Making the build fast, concise, and as useful as possible changes opinions dramatically. The CCNET server deployed here used NANT scripts to generate a unique version number embedded in each compiled component. The version number is also used to label the source code after a build and provides traceability of the component all the way to production. After the compile and other tasks, the artifacts are deployed to a predetermined environment. This way, the process is automated, repeatable, and consistent. Take advantage of this kind of infrastructure to add value beyond a compile and deploy.
You should also follow a deployment methodology where branches are not candidates for release. Any given branch must be merged back into the Trunk for integration, be approved, and then have an additional release branch created for it. This creates an additional level of isolationthis time between your testing environment and your development environment. Following these strategies puts you in a good place to move toward true CI if and when the time occurs. Always think long term with these decisions; they form the bedrock for development activities.
Again, the build process is more than compiling source code. There are other activities that need to occur to test and use the newly built software. These activities are usually domain specificperhaps triggering a series of unit tests or starting a system stress test. In my case, a web environment with Microsoft IIS 6 is created for each branch. The ability to quickly build out an environment for a developer or testing server can free precious cycles from your team. Spending time creating a tool to accomplish this yielded big results. The tool can setup the IIS website on any server identical to production. Then, spinning up a new environment is as simple and repeatable as compiling the software that executes in the environment. Are there items in your test environment that are difficult to reproduce? Are developers ever held up changing configurations? Look for opportunities like these to automate as much as possible.
Branching is considered an administrative task and should only be done with team or management agreement. Small checks and balances here prevent bloating of branches and give the development team a signpost to follow. Once the branch is created, someone must be responsible for it. Project leads fit this role best; they can merge changes from the trunk into their branch on a regular basis, or delegate the task to another member on their team. Delegating these responsibilities helps the development team feel ownership over the source code and process.