Modularity & Architecture
I recently wrote about eliminating architecture, and there were a few comments, especially by folks on JavaLobby, who thought I had my head in the clouds. Too much theory. Too many abstract concepts. Not achievable in a real world development scenario. That I’m making a play on words. Let’s take another angle.
There are numerous definitions of architecture. But within each lies a common theme, and some key phrases. Here are a few of the definitions. From Booch, Rumbaugh, and Jacobson in UML User Guide (Addison-Wesley, 1999):
An architecture is the set of significant decisions about the organization of a software system, the selection of the structural elements and their interfaces by which the system is composed, together with their behavior as specified in the collaborations among those elements, the composition of these structural elements and behavioral elements into progressively larger subsystems, and the architecture style that guides this organization — these elements and their interfaces, their collaborations, and their composition.
From the ANSI/IEEE Std 1471-2000:
The fundamental organization of a system, embodied in its components, their relationships to each other and the environment, and the principles governing its design and evolution.
In TOGAF, architecture has two meanings depending on context:
1.) A formal description of a system, or a detailed plan of the system at component level to guide its implementation
2.) The structure of components, their inter-relationships, and the principles and guidelines governing their design and evolution over time.
And in a QCon presentation by James Coplien and Kevlin Henney, architecture is defined as:
1.) Architecture embodies the critical design decisions that typify a system. Relates to cost of change, organizational structure, structure of code, capabilities of a system, etc.
2.) The significance of decisions needs to be understood and assessed. A heavy-weight approach is likely to reduce understanding and our ability to assess
Certainly, we see a pattern here as some key phrases and terms recur. These include “significant/critical decisions”, “components”, “structure”, and “cost of change”. And the definition from the Fowler article (which is actually part of a statement made by Ralph Johnson) introduced in the Eliminate Architecture post uses similar terminology and phrases.
It is these definitions that led us to the goal of architecture - eliminate the cost and impact of change. If we are able to eliminate the cost and impact of change, then change is no longer architecturally significant. If something isn’t architecturally significant, then we don’t consider it architecture. Essentially, we’ve eliminated architecture because the cost of change is no longer significant. That must be what we strive to achieve. And the way to achieve this is by increasing flexibility while taming complexity. Let’s take an analogy.
An OO Analogy
The goal of object-oriented design can be summed pretty effectively using the open-closed principle, which states:
“a system should be open for extension but closed to modification.”
This is done through abstraction and inheritance. If we have abstractions in the right place, we can extend the system by introducing new classes without modifying existing system classes. The key is that we have to recognize which areas of the system require this added flexibility.
Certainly not all areas of the system can possess this flexibility. It’s unrealistic and entirely too complex. But it should still be our goal. It’s the same with architecture. Obviously we cannot eliminate the architectural significance of all change, but it must still be our goal. Otherwise, what goal are we striving to achieve?
Modularity - The Missing Ingredient
Two of the key elements of the architectural definitions are component and composition. Yet there is no standard and agreed upon definition of component (reminding me of architecture, actually), and most use the term pretty loosely to mean just “a chunk of code”. But that doesn’t work, and in the context of OSGi, it’s clear that a module is a software component. That’s excellent fodder for my claim that agile architecture requires modularity because agile architecture demands that we design a flexible system that allows us to make temporal decisions based on shifts that occur throughout development. Modularity has been a missing piece that allows us to more easily accommodate these shifts.
I illustrate this using the simple diagram at right, and it’s what I was referring to in the Eliminate Architecture post when I stated that modularity, in conjunction with design patterns and SOLID principles, represent our best hope to minimize the impact and cost of change. It’s easier to change a design embedded within a module than it is a design that spans modules. I provided a similar example in Modularity by Example.
In other words, it’s easier to isolate change by insulating a design within a module. Designs that span modules are the joints of our system, and changes in these areas are more complex and costly. This is where we need the flexibility. It’s where we need stability. But if we don’t have modularity, we don’t have joints. Or maybe everything becomes a joint? Either way, without modularity we can’t identify the joints so it’s more difficult to identify where we need the flexibility. If we are able to avoid changes that span joints, that change is isolated…insulated…encapsulated within a module, and the impact of change is minimized..
Can we do this in all cases? Of course not! Just like we cannot always design software that’s open for extension but closed to modification. But it must be what we strive to achieve. Again, modularity has been the missing ingredient. And now is a perfect time to start understanding how to design more modular software.