README.md in clean-architecture-0.1.0 vs README.md in clean-architecture-0.2.0

- old
+ new

@@ -21,14 +21,15 @@ The intention of this gem is to help you build applications that are built from the use case down, and decisions about I/O can be deferred until the last possible moment. It relies heavily on the [duckface-interfaces](https://github.com/samuelgiles/duckface) gem to enforce interface implementation. -### Use cases as an organisational principle +## Clean architecture principles -Uncle Bob suggests that your source code organisation should allow developers to easily find a -listing of all use cases your application provides. Here's an example of how this might look in a +### Screaming architecture - use cases as an organisational principle + +Uncle Bob suggests that your source code organisation should allow developers to easily find a listing of all use cases your application provides. Here's an example of how this might look in a Rails application. ``` - lib - my_banking_application @@ -36,10 +37,99 @@ - retail_customer_opens_bank_account.rb - retail_customer_makes_a_deposit.rb - ... ``` -### Clean architecture principles +Note that the use case name contains: + +- the user role +- the action +- the (sometimes implied) subject + +### Design principles + +#### SRP - The Single Responsibility principle + +> A function should do one, and only one, thing + +We satisfy the SRP by following these rules: + +- An **adapter** is solely responsible for presenting the properties of a business object, or a small number of business objects, in a known interface +- A **command** is solely responsible for completing an atomic I/O operation +- An **entity** is solely responsible for representing, in memory, a business object whos properties do not come from a single source +- An **interface** is a module that represents a contract between two classes +- A **serializer** is solely responsible for taking a business object and turning it into a representation made up of purely primitive values +- A **strategy** is an algorithm used by commands to compose atomic I/O operations +- A **use case** is solely responsible for checking whether an actor has permissions to perform a command, and executing that command if so +- A **validator** is solely responsible for validating a business object and returning a validation result + +#### OCP - The Open/Closed Principle, LSP - The Liskov Substitution Principle and DIP - The Dependency Inversion Principle + +> A software artefact should be open for extension but closed for modification + +> A caller should not have to know the type of an object to interact with it + +> Always depend on or derive from a stable abstraction, rather than a volatile concrete class + +We satisfy the OCP, LSP & DIP by following these rules: + +- We create a clean boundary between our business logic, our persistence layer and our application-specific classes using interfaces +- We use interfaces wherever possible, allowing concrete implementations of those interfaces to be extended without breaking the contract +- We write unit tests against interfaces, never against concrete implementations (unless interfaces don't exist) + +#### ISP - The Interface Segregation Principle + +> Where some actors only use a subset of methods available from an interface, the interface should be split into sub-interfaces supporting each type of caller + +We satisfy the ISP by following these rules: + +- Each functional area of our code is split into folders (under `lib` in Rails projects) +- Each functional area defines its own interfaces +- Interfaces are not shared between functional areas + +### Component cohesion + +#### REP - The Reuse/Release Equivalence Principle, CCP - The Common Closure Principle & CRP - The Common Reuse Principle + +> Classes and modules that are grouped together into a component should be releasable together + +> Gather into components those changes the change for the same reasons and at the same times. + +> Classes and modules that tend to be reused together should be placed in the same component + +We satisfy the REP, CCP and CRP by: + +- Having team discussions whenever we make decisions about what a new functional area should be called and what it should contain +- Ensuring that none of our functional areas make direct reference back to the parent application +- Splitting functional areas out into gems when those functional areas change at a different rate than the rest of the codebase +- Splitting functional areas out into standalone applications when it makes sense to do so + +### Component coupling + +#### ADP - The Acyclic Dependencies Principle + +> Don't create circular dependencies + +I don't think I need to explain this. Just don't do it. I like explicitly including dependencies using `require` because it actually prevents you from doing this. Rails, in so many ways, makes one lazy. + +#### SDP - The Stable Dependencies Principle + +> A component always have less things depending on it than it depends on + +We satisfy the SDP by: + +- Putting sensible abstractions in place that adhere to the Single Responsibility principle +- Not sharing abstractions and entities between multiple functional areas + +#### SAP - The Stable Abstractions Principle + +> A component should be as abstract as it is stable + +We satisfy the SAP by: + +- Thinking hard about the methods and parameters we specify in our interfaces. Are they solving for a general problem? Are we likely to have to change them when requirements change, and how we can avoid that? + +## Practical suggestions for implementation * The code that manages your inputs (e.g. a Rails controller) instantiates a persistence layer object - Suggest: a class that implements both the `Persistence` interface and your own persistence interface