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