Grass Roots Agile
Teams interested in increasing agility often emphasize process and practices, but ignore the technological aspects necessary to increase agility. Are teams agile because they use Scrum? No. Are teams agile because they practice Continuous Integration? No. Are teams agile because they have a project room? No. Agility is not defined by process or practice. Agility is defined by ability. The ability to deliver working software. The ability to respond to change. The ability of software to accommodate change and remain working software. Agile processes and practices serve as wonderful guides to help teams develop higher degrees of agility. But processes and practices that help manage change and emphasize delivery are not enough. Teams must also craft code, develop a supporting infrastructure, and adopt tools and frameworks that encourage and embrace change. Below are some essential characteristics of technology that help maximize the effectiveness of agile practices.
The ability to accommodate changing requirements is directly related to the flexibility and malleability of the code base. High quality code that is easy to maintain fills the gap between a team that embraces agile practices and a team that can follow through by accommodating change quickly and easily. A brittle codebase that lacks design and architectural resiliency prevents teams from realizing the promise of agility. Below are the characteristics of agile code.
Coupling is the degree to which one program module depends on another. Tightly coupled code with excessive dependencies is brittle. Small changes in one area of the system have a ripple affect that impact other areas of the system, often unknowingly. To reduce coupling, dependencies among all modules must be carefully managed. For instance, applying proven design and architectural patterns help modularize large software systems, leading to loosely coupled code, components, and services.
Cohesion is the degree to which a program module performs a specific piece of functionality. Well-written code is highly cohesive. A codebase lacking cohesion is difficult to understand, maintain, test, and reuse. Cohesive code results in smaller, more focused modules that ease change and increase reusability. Cohesive classes packaged into cohesive deployable units defined at an appropriate level of granularity allow development teams to shift architecture more easily as change surfaces.
All software experiences change. Fully tested software embraces change by giving developers the courage to make change. A robust suite of unit tests will help identify areas of the system that may have been unknowingly affected when refactoring. Without tests, developers have no security blanket to prove their change functions as desired. Test coverage metrics help teams identify areas of the system that are lacking robust tests.
Expressive code is easier to understand, maintain, and test. Developers should favor crafting code that humans can easily understand over writing code that only passes compilation. Simple practices, such as using meaningful class and variable names, providing consistent formatting, avoiding complex boolean logic and nested conditionals, and using whitespace appropriately lead to more expressive code. A robust suite of tests also aids developers by showing different ways that the code is initialized, configured, and exercised.
Copying code to reuse all of part of a module burdens the maintenance effort. When logic changes, it’s likely that multiple areas of the application require modification. Duplication also increases the testing effort. Refactoring and nurturing the code is an important step toward maintaining a high integrity codebase with little duplication.
Incremental software delivery is a core tenet of agile development. Delivery does not always correspond to a production release, however. Instead, delivery emphasizes releasing functional software to a stable environment where the application can be verified through quality assurance testing, performance testing, usability testing, and more. In the most agile environments, software is delivered hourly, ensuring any problems discovered are no more than an hour old. In addition to agile practices such as continuous integration, the ability to deliver functional software frequently and incrementally is directly related to a team’s infrastructure components.
A shared environment that is easily accessible by the project team provides a highly visible way to track development progress. The environment should be a close approximation to the target production environment, leading to earlier and more frequent discovery of issues. Releasing early and frequently to a shared environment provides the development team the time necessary to make adjustments; automating and streamlining the deployment process encourages frequent delivery. A shared environment also allows for other important activities, such as frequent application demos. A current integrated version of the software system always exists, providing teams a morale boost early in the lifecycle and avoiding problems where the system might work only on individual developer workstations.
Maintaining a master copy of source, as well as a history of changes, helps the development team understand the current state of the codebase and track changes over time. Since developers know where to obtain the most current copy of source, new developers can set up a development environment quickly and easily. Building and deploying the master copy of source allows the development team to quickly respond to failed builds, failed tests, or corrupt deploys.
Frequent delivery requires frequent builds. An automated and repeatable build process that pulls the master copy of source from the source repository, compiles and executes all tests, and deploys the application to a shared environment enables other important activities early in the lifecycle. But compiling, testing, and deploying frequently can consume a developer’s workstation. Running the automated and repeatable build on a separate build server allows teams to deploy frequently, without consuming developer resources on an hourly basis.
Each developer must have a local environment that can be quickly and easily synchronized with the source repository. Beyond simply a development environment, a local sandbox might include a database schema owned by the developer, local queues for messaging, and other technologies that allow developers to experiment and proof ideas before implementing and deploying to the shared environment.
Flexible Hardware Platform
As with software, it’s not easy to predict how the hardware environment will be exercised over time. Activities such as adding new servers to a cluster, increasing capacity and storage space, and scaling to accommodate increased load are critical to ensure increased demands are met with ease. Fortunately, technology is readily available that allows us to assemble platforms and create virtual servers that abstract away operating system constraints and allocate resources as needed. Tools are also available that allow us to proactively manage server, network, and database environments.
Agile Tools and Frameworks
Many software applications and development efforts rely on third party software. When adopting tools and frameworks, teams must assess the impact a tool or framework has on their ability to work effectively and efficiently. A team’s ability to remain agile is directly related to the tools they use.
Many development teams use third-party libraries, such as persistence and web frameworks, to facilitate development. Before adoption, technology should be evaluated to ensure it does not stand in the way of a team’s ability to test the software. When necessary, appropriate abstractions should be defined that shield the application from aspects of the technology that inhibit testing. For instance, if an MVC framework is tightly coupled to an application server, the team should work hard to ensure that application tests do not rely on the presence of the MVC framework. Such reliance prevents testing outside the context of the application server, bringing more weight to the testing process.
Agile technologies should integrate well with the environment and a team’s style of working. As much as possible, tools and frameworks should avoid dictating how a team works; rather they should conform to how the team works. Effective agile technologies integrate well into the environment and have a small footprint.
Easy to use
An important trait of an agile framework or tool is that it allows the developer to understand what the technology is doing and how it functions. For instance, if a tool is generating code, it’s important that the code is expressive. If a framework is performing persistence functions, it’s imperative that developers are able to gain a clear and concise understanding of how it is accomplishing the task. When choosing a framework or tool, a good initial assessment can be made by simply evaluating the effort required to integrate the technology into an existing environment.
Rigid and inflexible technologies prevent a tool from conforming to a developer or team’s style of working. Agile technologies are configurable and extensible. When using a build tool to compile, test, and deploy an application, developers should be able to configure the tool so that they have control over how the build is performed. Developers should have the ability to extend frameworks by implementing abstractions, knowing that their extensions won’t cause the framework to behave strangely. One sign of flexibility is the ease with which developers can adopt technology without being forced to conform to a specific style of working, or compromising the quality of their design.
Frameworks and tools with excessive dependencies on external components decrease agility. For instance, frameworks tightly coupled to an application server make testing difficult. More flexible technologies are modular, and can be introduced to an environment incrementally.