Agile development methodologies are increasingly popular. Yet most ‘Agile’ experts and analysts discuss agility in isolation. This oversight is surprising given that ‘Agility’ is an emergent characteristic; this meaning a property of the underlying entity. For an entity to be ‘Agile’ it must have a high degree of structural modularity.
Perhaps as a result of this, many organisations attempt to invest in ‘Agile’ processes without ever considering the structure of their applications. Alongside the question, ‘How might one realise an Agile system?’, one must also ask, ‘How might one build systems with high degrees of structural modularity?’.
We start this series of blog articles by exploring the relationship between structural modularity and agility.
Structure, Modularity & Agility
Business Managers and Application Developers face many of the same fundamental challenges. Whether a business, or a software application serving a business, the entity must be cost effective to create and maintain. If the entity is to endure, it must also be able to rapidly adapt to unforeseen changes in a cost effective manner.
If we hope to effectively manage a System, we must first understand the System. Once we understand a System, manageable Change and directed Evolution are possible.
Yet we do not need to understand all of the fundamental constituents of the System; we only need to understand the relevant attributes and behaviors for the level of the hierarchy we are responsible for managing.
Services should be Opaque
From an external perspective, we are interested in the exposed behavior; the type of Service provided, and the properties of that Service. For example is the Service reliable? Is it competitively priced relative to alternative options?
Figure 1: A consumer of a Service.
As a consumer of the Service I have no interest in how these characteristics are achieved. I am only interested in the advertised Capabilities, which may or may not meet my Requirements.
To Manage I need to understand Structure
Unlike the consumer, the implementation of the Service is of fundamental importance to the Service provider. To achieve an understanding, we create a conceptual model by breaking the System responsible for providing the Service into a set of smaller interconnected pieces. This graph of components may represent an ‘Organization Chart’ , if the entity is a business, or a mapping of the components used, if the entity is a software application.
A first simple attempt to understand our abstract System is shown below.
From this simple representation we immediately know the following:
- The System is composed of 15 Components.
- The names of the Components.
- The dependencies that exist between these Components; though we don’t know why those dependencies exist.
- While we do not know the responsibilities of the individual Components; from the degree on inter-connectedness, we can infer that component ‘Tom’ is probably more important than ‘Dick’.
It is important to note that, we may not have created these Components, we may have no understanding of their internal construction. Just as the consumers of our Service are interested in the Capabilities offered, we, as a consumer of these components, simply Require their Capabilities.
Requirements & Capabilities
At present, we have no idea why the dependencies exist between the Components, just that those dependencies exist. Also, this is a time independent view. What about change over time?
One might initially resort to using versions or version ranges with the named entities; changes in the structure indicated by version changes on the constituents. However, as shown in figure 3, versioned names, while indicating change, fail to explain why Susan 1.0 can work with Tom 2.1, but Susan 2.0 cannot!
Why is this?
Figure 3: How do we track structural change over time? The earlier System functioned correctly; the later System – with an upgraded Component – fails. Why is this?
It is only when we look at the Capabilities and Requirements of the entities involved that we understand the issue. Tom 2.1 Requires a Manager Capability, a capability that can be provided by Susan 1.0. However, at the later point in time Susan 2.0, having reflected upon her career, decided to retrain. Susan 2.0 now no longer advertises a Manager Capability, but instead advertises a Plumber 1.0 Capability.
This simple illustration demonstrates that dependencies need to be expressed in terms of Requirements and Capabilities of the participating entities and not their names.
These descriptions should also be intrinsic to the entities; i.e. components should be self-describing.
Figure 4: An Organizational Structure: Defined in terms of Capabilities & Requirements with the use of Semantic versioning.
As shown, we can completely describe the System in terms of Requirements and Capabilities, without referencing specific named entities.
Evolution and the role of Semantic Versioning
Capabilities and Requirements are now the primary means via which we understand the structure of our System. However we are still left with the problem of understanding change over time.
- In an organization chart; to what degree are the dependencies still valid if an employee is promoted (Capabilities enhanced)?
- In a graph of interconnected software components; to what degree are the dependencies still valid if we refactor one of the components (changing / not changing a public interface)?
By applying simple versioning we can see that changes have occurred; however we do not understand the impact of these changes. However, if instead of simple versioning, semantic versioning is used (see http://www.osgi.org/wiki/uploads/Links/SemanticVersioning.pdf), the potential impact of a change can be communicated.
This is achieved in the following manner:
- Capabilities are versioned with a major.minor.micro versioning scheme. In addition, we collectively agree that – minor or micro version changes represent non-breaking changes; e.g. 2.7.1 ➞ 2.8.7. In contrast major version changes; e.g. 2.7.1. ➞ 3.0.0. represent breaking changes which may affect the users of our component.
- Requirements are now specified in terms of a range of acceptable Capabilities. Square brackets ‘[‘ and ‘]‘ are used to indicate inclusive and parentheses ‘(‘ and ‘)‘ to indicate exclusive. Hence a range [2.7.1, 3.0.0) means any Capability with version at or above 2.7.1 is acceptable up to, but not including 3.0.0.
Using this approach we can see that if Joe is substituted for Helen, Tom’s Requirements are still met. However Harry, while having a Manager Capability, cannot meet Tom’s Requirements as Harry’s 1.7 skill set is outside of the acceptable range for Tom i.e. [2,3).
Via the use of semantic versioning the impact of change can be communicated. Used in conjunction with Requirements and Capabilities we now have sufficient information to be able to substitute components while ensuring that all the structural dependencies continue to be met.
Our job is almost done. Our simple System is Agile & Maintainable!
Agile – All the Way Down
The final challenge concerns complexity. What happens when the size and sophistication of the System increases? An increased number of components and a large increase in inter-dependencies? The reader having already noticed a degree of self-similarity arising in the previous examples may have already guessed the answer.
The Consumer of our Service selected our Service because the advertised Capabilities met the consumers Requirements (see figure 1). The implementation of the System which provided this Service is masked from the consumer. This pattern is once again repeated one layer down. The System’s structure is itself described in-terms of the Capabilities and Requirements of the participating components (see figure 4). This time, the internal structure of the components are masked from the System. As shown in figure 5; this pattern may be re-repeated at many logical layers.
Figure 5: An Agile Hierarchy: Each layer only exposes the necessary information. Each layer is composite with the dependencies between the participating components expressed in-terms of their Requirements and Capabilities.
All truly Agile systems are built this way, consisting of a hierarchy of structural layers. Within each structural layer the components are self-describing: self-describing in terms of information relevant to that layer, with unnecessary detail from lower layers masked.
This pattern is repeated again and again throughout natural and man-made systems. Natural ecosystems build massive structures from nested hierarchies of modular components:
- The Organism
- The Organ
- The Tissue
- The Cell
For good reason, commercial organizations attempt the same structures:
- The Organization
- The Division
- The Team
- The Individual
Hence we might expect a complex Agile software systems to also mirror these best practices:
- The Business Service
- Coarse grained business components.
- Fine grained micro-Services.
- Code level modularity.
This process started in the mid/late 1990‘s as organizations started to adopt coarse grain modularity as embodied by Service Oriented Architectures (SOA) and Enterprise Service Buses (ESB’s). These approaches allowed business applications to be loosely coupled; interacting via well defined service interfaces or message types. SOA advocates promised more ‘Agile’ IT environments as business systems would be easier to upgrade and/or replace.
However, in many cases the core applications never actually changed. Rather the existing application interfaces were simply exposed as SOA Services. When viewed in this light it is not surprising that SOA failed to deliver the promised cost savings and business agility: http://apsblog.burtongroup.com/2009/01/soa-is-dead-long-live-services.html.
Because of the lack of internal modularity, each post-SOA application was as inflexible as its pre-SOA predecessor.
To be Agile?
We conclude this section with a brief summary of the arguments developed so far.
To be ‘Agile’ a System will exhibit the following characteristics:
- A Hierarchical Structure: The System will be hierarchical. Each layer composed from components from the next lower layer.
- Isolation: For each structural layer; strong isolation will ensure that the internal composition of each participating component will be masked.
- Abstraction: For each layer; the behavior of participating components is exposed via stated Requirements and Capabilities.
- Self-Describing: Within each layer the relationship between the participating components will be self-describing; i.e. dependencies will be defined in terms of published Requirements and Capabilities.
- Impact of Change: Via semantic versioning the impact of a change on dependencies can be expressed.
Systems built upon these principles are:
- Understandable: The System’s structure may be understood at each layer in the structural hierarchy.
- Adaptable: At each layer in the hierarchy, structural modularity ensures that changes remains localized to the affect components; the boundaries created by strong structural modularity shielding the rest of the System from these changes.
- Evolvable: Components within each layer may be substituted; the System supports diversity and is therefore evolvable.
The System achieves Agility through structural modularity.
In the next post in this series we will discover how OSGi™ – the Java™ Modularity framework – meets the requirements of structure modularity, and thereby provides the necessary foundations for popular Agile Methodologies and ultimately, Agile businesses.