Agile Technology

An Agile Resolution

By: Kirk Knoernschild

Introduction

Agile development continues to gain momentum, but teams embracing agility typically emphasize process and practices, and 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. 'Tis the season, and as a result, I resolve that for 2007 I'll turn focus to the essential characteristics of technology that help maximize the effectiveness of agile practices.

Agile Code

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 some characteristics of agile code.

  • Loosely coupled - 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 helping ease maintenance.
  • Highly cohesive - 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 allows development teams to shift architecture more easily as change surfaces.
  • Fully Tested - 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 helps teams identify areas of the system that are lacking robust tests.
  • Expressive - 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 meaningful class and variable names, consistent formatting, avoiding complex boolean logic and nested conditionals, and appropriate use of whitespace lead to more more expressive code. A robust suite of tests also aids developers by showing different ways that the code is initialized, configured, and exercised.
  • Little Duplication - 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.

    Agile Infrastructure

    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.

  • Shared Environments - A shared environment that is easily accessible by the project team is 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, while automating and streamlining the deployment process encourages frequent delivery. A shared environment also allows for other important activities, such as freqent 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.
  • Source Repository - Maintaining a master copy of source, as well as a history of changes, helps the development team understand the current state of the codebase, as well as track changes over time. Developers know where to obtain the most current copy of source, allowing new developers to setup 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.
  • Build Server - 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.
  • Local Sandbox - 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. Adding new servers to a cluster, increasing capacity and storage space, or 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 their toolset.

  • Testable - Many development teams use third party libraries, such as persistence and web frameworks, to facilitate development. Before adoption, technology should be evaluatedto 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.
  • Non-Invasive - 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, but should conform to how the team works. 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 the ability of 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 for you, it's imperative that developers are able to gain a clear and concise understanding of how it's 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.
  • Flexible - 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, developer's 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.
  • Lightweight - 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.

    Conclusion

    Injecting agile practices into the development process is the first step toward realizing a higher degree of agility. Yet poorly crafted code, a rigid infrastructure, or complex tools and frameworks prevent teams from realizing the full advantage of agile practices. For 2007, I resolve to focus on technologies supporting agile practices that support a teams ability to remain agile.