The goal of software development is to – SURPRISE! – deliver software. Fancy architecture diagrams, detailed requirements documentation, and comprehensive project plans mean little if we can’t deliver the software that realizes them.
The source code is the detailed specification for a software system, and it is the only specification guaranteed to offer an accurate representation of the system. It is also the only artifact we must create in order to deliver a software system. Assuming an organization views the software system as an asset, then so too is the source code. Source code is a corporate asset that must be carefully guarded!
Guarding the Source
High quality source code is important. A malleable codebase is easier to change, eases maintenace, and speeds delivery. An organization may have a mature change management policy in place, but an application that resists change due to mangled source or architectural inflexibility cannot be modified and delivered quickly. A fully tested codebase is also important. Tests allow us to verify correctness, identify defects, and lend us the courage to make change by providing a safety net to identify the ripple affect of change. Finally, a functional codebase is important. A codebase that is void of compile and test errors can be frequently delivered, allowing us to garner important customer feedback that helps ensure we never stray far from our intended destination.
In other words, if we develop a codebase that is malleable, fully tested, and functionally complete, our team possesses the ability to continuously deliver software in the face of change. By emphasizing creation, growth, verification, and deployment of our code from initial project inception to final solution delivery, we are developing an inherently agile software development environment. At the center of this process is the source code, and we would do well to guard this source code with artifacts that help move it along this path. Ideally, these artifacts are executable.
Executable Artifacts & Fidelity
The traditional software lifecycle consists of high level activities, each producing an artifact fed into subsequent phases. These artifacts are interpreted by humans and manually translated into some other software artifact. Eventually, we get to the source code. This approach lacks fidelity, and valuable information is lost during each translation. It’s a bit like Chinese Whispers, and is fraught with cumulative error and inaccuracies.
Executable artifacts guarantee fidelity. If an artifact ever becomes dated and out of sync with the source code, the artifact breaks. Executable artifacts offer a real-time up-to-date glimpse into the application development effort. Executable artifacts guard the source code in a variety of different ways. Executable artifacts also help increase project transparency. Here are some other advantages of executable artifacts:
- They are an accurate reflection of the code at the point they were run. For most teams, ensuring documentation stays synchronized with the codebase is a daunting task. Because executable artifacts are run against the source code, we can always be certain that they reflect the current state of the source.
- They can be run at any time, with little overhead. After initial setup of the executable artifact, they can be easily run against the source code, usually by issuing a simple command.
- They encourage early and frequent delivery. Since we have a functional codebase, we can garner important feedback throughout the development lifecycle.
- They can be automated. Automating an executable artifact means little manual intervention is required. Additionally, automation reduces the likelihood of errors or omissions that is common with manual processes.
- They maintain a reliable history. An executable artifact, run at frequent and regular intervals, produces output that can be analyzed over time to help the team identify trends in development.
Let’s consider a simple development scenario
The Development Scenario
As a project commences, the development team meets with the customer to elicit high level requirements. In lieu of producing a detailed software requirements specification and obtaining signoff from the customer before moving onto development, the development team adopts a strategy to deliver running tested software on a frequent basis. A business analyst develops a suite of acceptance tests using a tool such as Fitnesse or Selenium. Simultaneously, the developers create an automated and repeatable build process scheduled to run hourly. Incorporating execution of the acceptance tests into the build process ensures that the application always satisfies the current set of acceptance tests, which serve as a set of executable requirements for the application development effort.
The priority of the development team is to ensure the application always remains in a functional state by passing all acceptance tests. Because the application is always functional, the development team can deliver the software into the hands of the customer on a frequent basis. As a stop gap to ensure they maintain a high degree of customer feedback, the development team hosts regular application demonstrations for their customers. As customers participate in these demonstrations or interact with the application, the feedback they offer can be managed via an issues backlog that is a valuable input artifact to subsequent iteration planning sessions. As change trickles in and new features are identified, additional acceptance tests are added to the suite.
To ensure the application architecture maintains a high degree of resiliency and adaptability, the team places constant focus on growing their unit test suite and makes certain all unit tests are executed as part of the build process. By ensuring unit tests verify classes and methods in isolation from outside forces, application components are naturally decoupled. To further enhance application architecture, the development team generates a number of software artifacts as part of the build process. Class and component diagrams in conjunction with dependency metrics offer valuable feedback that lead the development team to targeted refactoring efforts to maintain a high degree of architectural and design resiliency.
Eventually, the build process updates a project dashboard that includes important project metrics, including the number of tested teatures supported in the current software build. All project participants, including the software development team, customer team, and management team, have access to the project dashboard via a URL, ensuring the team always knows the current state of the application. The consistency and repeatability of this micro process allows the team to identify important trends in development, such as development velocity in terms of the number of tested features delivered. They are able to develop burn down charts, backed by evidence, that help the team provide more reliable estimates based on historical evidence.
In this development scenario, executable artifacts serve as a powerful catalyst for other important practices, and enable another key aspect of frequent delivery. Because artifacts are executable, they can be automated. But at the center is software development’s most important artifact – the source code. Once a team begins guarding the source with executable artifacts, a vicious, self-generating, and remarkably powerful process emerges.
As you consider embarking on a software process improvement initiative, begin planning your agile transition, or simply kick-off your next project, reflect for a moment on the ultimate goal. The purpose of any software development effort is software delivery, not software process improvement, documenting requirements, or creating architecture documents. The only artifact required to deliver software is the source code, and all artifacts should feed this requirement. It’s imperative that we treat source code as a corporate asset, and guard it as closely as possible. While other artifacts are inevitably necessary, executable artifacts guarantee fidelity with the source code, and can prove its quality, resiliency and functionality.