Skip to content

Instantly share code, notes, and snippets.

@wataruoguchi
Created July 11, 2021 05:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wataruoguchi/c5a455f1231e4e27013894413f9ecaa3 to your computer and use it in GitHub Desktop.
Save wataruoguchi/c5a455f1231e4e27013894413f9ecaa3 to your computer and use it in GitHub Desktop.
Clean Architecture - PART 6 - Architecture (Chapter 33 - 34) #bookclub

Clean Architecture

PART VI - Details

Chapter 33 - Case Study: Video Sales

The Product

Example project is a website that sells videos. (e-learning. individual customer / business customer)

Use Case Analysis

  • Fig 33.1 A typical use-case analysis

Four actors

  • Author
  • Admin
  • Purchaser
  • Viewer

Component Architecture

  • Fig 33.2 A preliminary component architecture

Would I really break the system up into all these components, and deliver them as .jar or .dll files? Yes and no.

Keeping these options open will allow us to adapt the way we deploy the system based on how the system changes over time.

Dependency Management

All dependencies cross the boundary lines in one direction, and they always point toward the components containing the higher-level policy.

Conclusion

Two dimensions of separation:

  1. Separation of actors based on the Single Responsibility Principle
  2. The Dependency Rule

The goal of both is to separate components that change for different reasons, and at different rates

  1. Different reasons -> correspond to the actors.
  2. Different rates -> correspond to the different levels of policy.

Chapter 34 - The Missing Chapter

Package by Layer

  • Fig 34.1 Package by layer

Layers

  • A layer for the web code
  • A layer for our "business logic"
  • A layer for persistence

Code is sliced horizontally into layers. Layers should depend only one the next adjacent lower layer.

It’s a very quick way to get something up and running without a huge amount of complexity. The problem, as Martin points out, is that once your software grows in scale and complexity, you will quickly find that having three large buckets of code isn’t sufficient, and you will need to think about modularizing further.

Another problem is that, as Uncle Bob has already said, a layered architecture doesn’t scream anything about the business domain. Put the code for two layered architectures, from two very different business domains, side by side and they will likely look eerily similar: web, services, and repositories.

Package by Feature

Vertical slicing based on related features, domain concepts, or aggregate roots.

  • Fig 34.2 Package by feature

It's a refactoring from the "package by layer" style, but it's better because the top-level organization of the code now screams about the business domain.

Ports and Adopters

summarize, you often see such code bases being composed of an “inside” (domain) and an “outside” (infrastructure), as suggested in Figure 34.3.

  • Fig 34.3 A code base with an inside and an outside
  • Fig 34.4 View orders use case

Package by Component

Although I agree wholeheartedly with the discussions about SOLID, REP, CCP, and CRP and most of the advice in this book, I come to a slightly different conclusion about how to organize code.

Fig 34.5 Relaxed layered architecture

What we need here is a guideline - an architectural principle - that says something like, "Web controllers should never access repositories directly." The question is enforcement.

Many teams say "We enforce this principle through good discipline and code reviews, because we trust our developers." It's great but never respected before budgets and deadlines.

Some teams use static analysis tools to check and automatically enforce architecture violations at build time.

But it still fails by being unchecked.

I'd personally like to use the compiler to enforce my architecture if at all possible.

Components are the units of deployment. They are the smallest entities that can be deployed as part of a system. In Java, they are jar files.

  • Fig 34.6 View orders use case

My definition of a component is slightly different: “A grouping of related functionality behind a nice clean interface, which resides inside an execution environment like an application.”

The Devil Is in the Implementation Details

Marking all of your types as public means you’re not taking advantage of the facilities that your programming language provides with regard to encapsulation.

Organization versus Encapsulation

Since public types can be used from anywhere in a code base, you can effectively ignore the packages because they provide very little real value. The net result is that if you ignore the packages (because they don’t provide any means of encapsulation and hiding), it doesn’t really matter which architectural style you’re aspiring to create.

  • Fig 34.7 All four architectural approaches are the same
  • Fig 34.8 Grayed-out types are where the access modifier can be made more restrictive

I would certainly encourage you to lean on the compiler to enforce your architectural principles, rather than relying on self-discipline and post-compilation tooling.

Decouple code trees:

  • The source code for the business and domain
  • The source code for the web
  • The source code for the data persistence

Other Decoupling Modes

Conclusion: The Missing Advice

The whole point of this chapter is to highlight that your best design intentions can be destroyed in a flash if you don’t consider the intricacies of the implementation strategy.

Leave options open where applicable, but be pragmatic, and take into consideration the size of your team, their skill level, and the complexity of the solution in conjunction with your time and budgetary constraints.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment