Clean Architecture Feature Design Framework

1. Clarify the Business Need

  • Goal: What user problem or business value does this feature address?

  • Actors: Who interacts with it? (e.g., end-users, external systems)

  • Success Criteria: How will you measure it? (KPIs, user feedback, metrics)


2. Identify Core Entities

  • Entities are the business objects and rules that stay the same.

  • Questions to ask:

  • What domain concepts are involved?

  • What invariants or validations belong here?

  • Output: A list of entity classes/structures with their properties and methods.


3. Define Use Cases (Interactors)

  • Use Cases orchestrate Entities to fulfill a user goal.

  • Questions to ask:

  • Which operations does the feature need? (e.g., CreateOrder, CalculateDiscount)

  • What data do they require and produce?

  • Output: Interfaces or abstract classes for each use case, specifying inputs/outputs.


4. Specify Ports (Interfaces)

  • Inward-facing Ports: interfaces through which controllers invoke use cases.

  • Outward-facing Ports: interfaces through which use cases call external systems (e.g., repositories, gateways).

  • Output: Port definitions (e.g., OrderRepository, PaymentGateway) with method signatures.


5. Sketch Data Flow & Dependencies

  • Draw a simple diagram (or list) showing how:
  1. UI → Controller → Use Case → Port → Adapter → External system

  2. Data returns back up the chain.

  • Key Principle: Dependencies point inward (outer layers depend on inner abstractions).

6. Implement Adapters

  • Controllers/Presenters (UI layer): map HTTP/CLI/GUI input to use-case calls, and format responses.

  • Gateways/Repositories (Infrastructure layer): concrete implementations of ports (e.g., database, REST clients).

  • Output:

  • Controller classes

  • Repository classes

  • Presenter/Serializer classes


7. Wire It Up

  • In your composition root (e.g., application bootstrap):
  1. Instantiate Entities (often not needed explicitly).

  2. Instantiate Repository and Gateway adapters.

  3. Instantiate Use Case implementations, passing adapters into constructors.

  4. Instantiate Controllers, injecting use cases.


8. Write Tests

  • Unit tests for Entities and Use Cases (mock ports).

  • Integration tests for adapters (e.g., in-memory DB, sandbox APIs).

  • Acceptance tests or end-to-end tests covering the full flow.


9. Iterate & Refine

  • Review SOLID compliance:

  • Single Responsibility

  • Open/Closed (add new features by extending, not modifying)

  • Liskov Substitution

  • Interface Segregation

  • Dependency Inversion

  • Refactor as complexity grows.


10. Document & Communicate

  • Update architecture diagrams.

  • Record any new ports, entity rules, or decision rationale.

  • Share with team for alignment.

0
Subscribe to my newsletter

Read articles from El Mahdi Hssaine directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

El Mahdi Hssaine
El Mahdi Hssaine