# Clean Architecture

This gem provides helper interfaces and classes to assist in the construction of application with
Clean Architecture, as described in [Robert Martin's seminal book](https://www.amazon.com/gp/product/0134494164).

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'clean-architecture'
```

And then execute:

    $ bundle install
    $ bundle binstubs clean-architecture

## Usage

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

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
    - use_cases
      - retail_customer_opens_bank_account.rb
      - retail_customer_makes_a_deposit.rb
      - ...
```

### Clean architecture principles

* 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

```
  persistence = ActiveRecordPersistence.new
```

* The code that manages your inputs (e.g. a Rails controller) instantiates a use case actor
  object
  - Suggest: a class that implements the `UseCaseActor` interface

```
  use_case_actor = MyUseCaseActorAdapter.new(devise_current_user)
```

* The code that manages your inputs (e.g. a Rails controller) instantiates a use case input port
  object
  - Suggest: a class that implements the `BaseParameters` interface
  - Suggest: implement the `AuthorizationParameters` interface if you want to make authorization
    part of your use case logic
  - Suggest: implement the `TargetedParameters` if your use case operates on a single object
  - Suggest: use the `TargetedParameters` entity for an out-of-the-box class that gives you all of
    these

```
  input_port = CleanArchitecture::Entities::TargetedParameters.new(
    use_case_actor,
    TargetActiveRecordClass.find(params[:id]),
    strong_params,
    persistence,
    other_settings_hash
  )
```

* The code that manages your inputs (e.g. a Rails controller) instantiates a use case object
  - Suggest: a class that implements the `UseCase` interface

```
  use_case = MyBankingApplication::UseCases::RetailCustomerMakesADeposit.new(input_port)
```