Skip to content

Modularity and Composition

Core Idea

Examples and diagrams in this page follow the shared Hypothetical Scenario.

Modularity splits a system into small units. Each unit holds one clear responsibility. A responsibility is a concrete duty in the system. Examples include match scoring, ownership cost projection, or deal digest export.

The Single Responsibility Principle gives a direct rule. A module should have one reason to change. This rule reduces accidental coupling. This rule keeps review and testing local.

Composition joins focused modules into one business flow. Each module keeps its own duty. Orchestration code connects duties in sequence. The full feature appears from these composed parts.

Conceptual Overview

A mixed module creates common failure patterns. One class may validate input, query storage, apply policy, and call external systems. Small edits then touch many concerns in one file. Defects spread across unrelated behavior.

Composition fixes this structural problem. The system groups behavior into focused modules. Each module stays narrow and testable. The composed flow stays visible and easy to reason about.

Mixed module versus composed modules

Mixed versus composed design. Focused modules keep the workflow explicit.

A concrete example helps. A marketplace recommendation pipeline may run three steps. Step one validates listing and buyer profile metadata. Step two applies match and ownership-cost rules. Step three stores recommendation snapshots and emits a deal event. Each step can evolve with low risk. The pipeline still delivers one cohesive feature.

Responsibility and Single Responsibility

Responsibility is not team ownership alone. Responsibility is the boundary of change for behavior. A module with one responsibility has one change axis.

Single Responsibility creates practical benefits. Error diagnosis gets faster. Test cases stay short. Refactors touch fewer files. Code review gets clearer.

A module breaks this rule when it changes for unrelated policy shifts. A module breaks this rule when storage logic and domain logic live together. A module breaks this rule when transport details leak into core rules.

Single responsibility and change axis

Single responsibility view. Each focused module keeps one change axis.

What Composition Solves

Composition solves the gap between small parts and full system behavior. Small modules alone do not ship features. Large monolith methods ship features but raise coupling. Composition keeps feature delivery and local clarity at the same time.

Composition gives a controlled structure for dependency direction. High level orchestration depends on module contracts. Module internals stay private. One module can be replaced without rewriting the full flow.

Composition gives scale for teams. Parallel work rises through stable module contracts. Merge friction drops when each module has a narrow duty. Release risk drops when edits stay inside one module boundary.

Relationship to Abstraction and Boundaries

Abstraction defines what a module promises. Boundary defines where that promise applies. Responsibility defines what the module owns inside that boundary.

Composition relies on these three ideas together. Abstraction gives a contract. Boundary protects internals. Responsibility limits the scope of change. Then composition can connect modules without hidden coupling.

Weak boundaries harm composition. Leaky abstractions force callers to know internal details. Mixed responsibilities force wide edits. The composed system then becomes fragile and hard to evolve.

Composition with abstraction and boundaries

Composition with abstraction and boundaries. Contracts connect modules and boundaries protect internals.

Computing History

David Parnas published information hiding criteria in 1972. That paper reframed modular design around change boundaries. The NATO software engineering conference in 1968 promoted component style assembly. The Unix pipeline model then popularized composition through small focused tools. These ideas now shape package design, service seams, and ownership rules.

Sources: McIlroy (1968) and Parnas (1972)

Quote

"The only way to go fast, is to go well."

Source: Robert C. Martin, 2003

Practice Checklist

  • Give each module one clear reason to change.
  • Name the responsibility in the module header doc.
  • Keep module contracts small and explicit.
  • Compose features through thin orchestration layers.
  • Keep storage, transport, and policy concerns in separate modules.
  • Ban cyclic dependencies across modules.
  • Track module ownership in version control.

Written by: Pedro Guzmán

See References for complete APA-style bibliographic entries used on this page.