Modular

Composed of interchangeable parts.


First off, let's remember that the Industrial Revolution started because of two inventions: universal power (steam and later electricity) and interchangeable parts. Many feel that once interchangeable parts become the norm in software that a revolution of similar magnitude will spontaneously occur.

In software interchangeable units are called components or parts. A group of components or a large component is called a module. A group of modules is a partition. A group of partitions is a system.

Modularity is the ability to usefully approach system development from a modular perspective. Simplifying things a bit, the modularity of a system can be measured by the average of three things:

1. The time it takes to add, remove or replace a component or module. (This should be swift.)
2. How well the modified module works within the system. (unless removed)
3. The amount of disruption on the rest of the system when step 1 is done.

Total modularity tends to be dominated by the cost of fixing disruptions. If the cost is low then modularity is high. If cost remains high despite severe attempts to do better, such as extreme unit testing of modules and frequent massive rewrites, then tight coupling and low cohesion are probably present, and the system and module architecture is flawed.

The more modular the system, the lower the system cost, because:

1. Change requests result in more localized work, usually within one module.
2. The use of third party components or subcontracting is easier.
3. Independent teams or developers can focus on modules according to expertise.
4. Reuse tends to be higher due to module reuse.
5. Defect costs tend to be lower since they more often occur in one module.
6. Faster cycle time is less expensive due to many module related reasons.
7. System quality is inherently higher due to easier unit testing, more reuse in the large, looser coupling and higher cohesion.

The module centricness of a system development process can be measured by:

1. The ability to specify and build a module independently of a target system.
2. The ability to duplicate the external behavior of a module from artifacts.
3. The ability to predict successful replacement of a module with a new one.
4. The ability to ship module updates for deployed products without fear of integration defects.

For a module centric process to work, each module needs good analysis, design, construction and a full regression module test. The module test can serve as partial specifications, can greatly help achieve module centricness, and can significantly reduce integration test size and defects.

The main best practices for achieving modularity are, in approximate order of importance:

1. A current, clear architecture model showing all module dependencies.
2. The use of interfaces to specify modules.
3. Publish all module IO. Don't just publish the input, which is methods.
4. The use of strict layers and/or partitions.
5. The use of events.
6. The use of a small number of common stable systemwide services.

Component design, module design, module assembly from components and system assembly from modules into architectural structures with desired properties is still a high art. Gazing deep into our crystal ball, it will become less art and more engineering when:

1. The proper abstraction of software units is discovered, like cells and atoms.
2. The fundamental laws of how software units behave become known.
3. The units themselves can participate in assembly decisions as autonomous agents.
4. Past assembly results can be used to automatically guide future assembly.
5. Most component, module and system evolution occurs while autonomous systems are running.

Architeture without modularity is not architecture.