Clean Architecture failed to meet my expectations on a number of fronts. Despite Mr. Martin's obvious passion for the topic, Clean Architecture is poorly organized, lacks examples, and is silent on working with existing systems. The author missed a major opportunity to teach us when and how to apply these lessons to our own systems. Let me explain.
This book takes a long time to get going. The chapters on design paradigms (structured, object oriented, and functional) seem particularly out of place and unnecessary.
The chapters on the SOLID principles are good. I enjoyed seeing the principles broken down and explained well. And I found it interesting to think about their applicability to system architecture. But Uncle Bob presents the SOLID principles like hard rules, which rubbed me the wrong way. In fact, I'm pretty sure a system that never violated the SOLID principles would be a giant mess.
However, this paragraph from page 137 is important:
The primary purpose of architecture is to support the life cycle of the system. Good architecture makes the system easy to understand, easy to develop, easy to maintain, and easy to deploy. The ultimate goal is to minimize the lifetime cost of the system and to maximize programmer productivity.
That's a great observation. Why didn't Uncle Bob put it in the first chapter?
There are hardly any examples in this book. Chapter 33 contains an example that discusses a video sales e-commerce application. It's okay. But I didn't walk away from it with a firm idea of how I'd apply the concepts to my own systems.
The appendix tells the story of how Uncle Bob came up with the SOLID principles and the rules of clean architecture. It's loaded with examples of past projects. I think it's the most interesting section of the book.
Most developers spend most of their time working on existing systems. So, I expected Clean Architecture to be full of advice on improving existing systems. But the book is conspicuously silent on the subject.
In the first half of the book you'll learn that you create a clean architecture by following the SOLID principles to break your system into components along your system boundaries (I'm paraphrasing). If you stopped reading there, you could be forgiven for having the impression that Uncle Bob would not approve of whatever you've been doing for architecture. You could also be forgiven for thinking that the few options he presents are the "right" way to do things. Yet towards the end of the book you'll read this on page 228:
This example is intended to show that architectural boundaries exist everywhere. We, as architects, must be careful to recognize when they are needed. We also have to be aware that such boundaries, when fully implemented, are expensive.
At the same time, we have to recognize that when such boundaries are ignored, they are very expensive to add in later—even in the presence of comprehensive test-suites and refactoring discipline.
So what do we do, we architects? The answer is dissatisfying. On the one hand, some very smart people have told us, over the years, that we should not anticipate the need for abstraction. This is the philosophy of YAGNI: "You aren’t going to need it." There is wisdom in this message, since over-engineering is often much worse than under-engineering. On the other hand, when you discover that you truly do need an architectural boundary where none exists, the costs and risks can be very high to add such a boundary.
So there you have it. O Software Architect, you must see the future. You must guess—intelligently. You must weigh the costs and determine where the architectural boundaries lie, and which should be fully implemented, and which should be partially implemented, and which should be ignored.
So more than half way through the book he says that it is up to us to decide where we should put the boundaries in our systems. And that boundaries are potentially everywhere. Confusing, right?
So, if the ultimate goal of software architecture is to minimize the lifetime cost of the system, shouldn't a book on architecture help an architect make those decisions?
This book left me with a lot of unanswered questions. Where is the discussion of the economics of the various options? How do I find the optimum architecture for my system? Where's the research?
How do I decide if horizontal layering or vertical slicing or something else will minimize the lifetime cost of my system? Or if I have no clearly defined layers, how do I decide which, if any, layering strategy will minimize my lifetime costs?
I have even more questions. Where should you put your effort if you have a limited amount of time to improve the architecture of an existing system? Is separating the database from the business logic is always a good idea? Which advice should you always follow? Which advice depends on the system?
In Code Complete, Steve McConnell talks about the tradeoffs between different non-functional requirements like reliability, dependability, correctness, maintainability, readability, etc. He explains how some requirements move together and others conflict. I would have loved to see something like that for the architecture decisions discussed in this book.
In Clean Architecture, project size, team size, the consequences of project failure, expected code lifetime, and other important factors are under-emphasized as drivers of architecture. For example, Healthcare.gov needs more architecture than the personal to-do list you are developing, even though they are both web apps backed by databases.
I spent the majority of this book slightly confused. I kind of understood what Uncle Bob was trying to say. But didn't completely get it until I read the appendix. So, let me save you some time.
Imagine you are building a desktop computer for the consumer market (office computers for example). You get to choose the hardware and you are going to write the software for the whole thing (firmware, OS, drivers, applications, everything).
How would you go about it? Would you write a giant program (a monolith) where the code for the spreadsheet knew about the kind of disk you selected for your computer? Can you imagine updating the spreadsheet code and adding 'if' statements everywhere so that it does one thing if you have a SATA drive and another if you have a SCSI drive? And then doing the same thing for VGA vs DVI vs HDMI video? What about different paths for PS/2 vs USB mouse input? And then repeat the process for the word processor and all the other applications you intend to bundle with your computer?
That would be a nightmare to maintain, right? So what's the solution? Architecture! Your spreadsheet shouldn't know what kind of mouse you're using. Nor what kind of display you have. It should be completely oblivious to those details.
And that's what you'll find if you look at your computer. There's embedded software in your mouse that communicates with your operating system. Yet the details are hidden from your applications. Your spreadsheet accepts standardized input without knowing or caring what kind of mouse you are using. Then when someone invents a new input device like the touchpad it works with your spreadsheet automatically.
That's just one of the boundaries in your computer. You'll likely come up with hundreds of them. You might assign different teams to work on different parts of the system. You might create or adopt different specs for the various ways the different components interact.
You're probably saying 'duh' at this point. It's obvious that you wouldn't want to change and recompile your spreadsheet every time your hardware changes. Maintenance would be a nightmare. And I agree.
It's easy to see hardware boundaries. But the same logic that makes hardware boundaries worthwhile also applies to software boundaries. Software boundaries are just harder to see.
So, you might start with the ability to display the spreadsheet on the screen. But you might also want to save it to disk, save it to PDF, save it as a CSV, or print it. So, maybe one of the boundaries in your spreadsheet program is to have an internal data structure that represents each spreadsheet. And then you pass that structure to different code to display, save, or print it in the desired format.
If you keep the data structure completely unaware of how it is displayed, saved, or printed, then you can add a "save to XML" feature down the road without digging through all the code related to the spreadsheet data structure. And if that spreadsheet data structure is several million lines of code, you can imagine how much easier that would be.
That's all Uncle Bob is trying to tell us in this book. You can use the SOLID principles to create boundaries in your systems that hide your implementation details, reduce complexity, and help you reduce the total lifecycle cost of your systems.
In many ways, Patterns of Enterprise Application Architecture by Martin Fowler is far superior to Clean Architecture. Fowler describes the patterns he's observed repeatedly in enterprise applications. He gives a simple example if each pattern, describes how it works, and where to use it. I found Patterns of Enterprise Application Architecture to be very readable and applicable to my systems.
There is valuable information in Clean Architecture but you have to work to find it.
I found the chapter on embedded software one of the easiest to understand. It intuitively makes sense to avoid scattering low-level calls throughout your code base. And it also makes sense to make your logic testable in the absence of the hardware (especially since embedded software is often developed before the hardware is available). If you could only read two chapters of this book, I'd recommend you make it this one and the appendix, regardless of what kind of software you write for a living.
Overall, Clean Architecture is a tough read and Uncle Bob left me with more questions than answers. I definitely wouldn't recommend this as your first book on software architecture (check out Patterns of Enterprise Application Architecture by Martin Fowler instead).
Agree or disagree. I'd love to hear your thoughts.
Enjoy this post? Please "like" it below.