Clean Architecture: A Craftsman's Guide to Software Structure and Design
Rate it:
Open Preview
Kindle Notes & Highlights
54%
Flag icon
Tests that are not well integrated into the design of the system tend to be fragile, and they make the system rigid and difficult to change.
54%
Flag icon
The solution is to design for testability. The first rule of software design—whether for testability or for any other reason—is always the same: Don’t depend on volatile things. GUIs are volatile. Test suites that operate the system through the GUI must be fragile. Therefore design the system, and the tests, so that business rules can be tested without using the GUI.
54%
Flag icon
This API should have superpowers that allow the tests to avoid security constraints, bypass expensive resources (such as databases), and force the system into particular testable states. This API will be a superset of the suite of interactors and interface adapters that are used by the user interface.
54%
Flag icon
This decoupling encompasses more than just detaching the tests from the UI: The goal is to decouple the structure of the tests from the structure of the application.
54%
Flag icon
STRUCTURAL COUPLING Structural coupling is one of the strongest, and most insidious, forms of test coupling. Imagine a test suite that has a test class for every production class, and a set of test methods for every production method. Such a test suite is deeply coupled to the structure of the application. When one of those production methods or classes changes, a large number of tests must change as well. Consequently, the tests are fragile, and they make the production code rigid.
54%
Flag icon
The role of the testing API is to hide the structure of the application from the tests. This allows the production code to be refactored and evol...
This highlight has been truncated due to consecutive passage length restrictions.
56%
Flag icon
Getting an app to work is what I call the App-titude test for a programmer. Programmers, embedded or not, who just concern themselves with getting their app to work are doing their products and employers a disservice. There is much more to programming than just getting an app to work.
59%
Flag icon
But the database is not the data model. The database is piece of software.
60%
Flag icon
Of course not. You’ll organize it into linked lists, trees, hash tables, stacks, queues, or any of the other myriad data structures, and you’ll access it using pointers or references—because that’s what programmers do.
60%
Flag icon
This reality is why I say that the database is a detail. It’s just a mechanism we use to move the data back and forth between the surface of the disk and RAM.
61%
Flag icon
We see the same kind of marketing campaigns today. The word “enterprise” and the notion of “Service-Oriented Architecture” have much more to do with marketing than with reality.
62%
Flag icon
ASYMMETRIC MARRIAGE
62%
Flag icon
• The architecture of the framework is often not very clean. Frameworks tend to violate the Dependency Rule. They ask you to inherit their code into your business objects—your Entities! They want their framework coupled into that innermost circle. Once in, that framework isn’t coming back out. The wedding ring is on your finger; and it’s going to stay there.
62%
Flag icon
If the framework wants you to derive your business objects from its base classes, say no! Derive proxies instead, and keep those proxies in components that are plugins to your business rules.
63%
Flag icon
An abstract use case is one that sets a general policy that another use case will flesh out.
63%
Flag icon
Keeping these options open will allow us to adapt the way we deploy the system based on how the system changes over time.
64%
Flag icon
The first is the separation of actors based on the Single Responsibility Principle; the second is the Dependency Rule.
64%
Flag icon
The goal of both is to separate components that change for different reasons, and at different rates.
64%
Flag icon
The different reasons correspond to the actors; the different rates correspond to the d...
This highlight has been truncated due to consecutive passage length restrictions.
64%
Flag icon
I often see software development teams realize that they have problems with horizontal layering (“package by layer”) and switch to vertical layering (“package by feature”) instead. In my opinion, both are suboptimal. If you’ve read this book so far, you might be thinking that we can do much better—and you’re right.
64%
Flag icon
As Uncle Bob has said, approaches such as “ports and adapters,” the “hexagonal architecture,” “boundaries, controllers, entities,” and so on aim to create architectures where business/domain-focused code is independent and separate from the technical implementation details such as frameworks and databases.
65%
Flag icon
To summarize, you often see such code bases being composed of an “inside” (domain) and an “outside” (infrastructure), as suggested in Figure 34.3.
65%
Flag icon
The major rule here is that the “outside” depends on the “inside”—never the other way around.
65%
Flag icon
So I’m going to present another option here, which I call “package by component.”
65%
Flag icon
In some situations, this is the intended outcome—if you’re trying to follow the CQRS5 pattern, for example.
65%
Flag icon
Many teams I’ve met simply say, “We enforce this principle through good discipline and code reviews, because we trust our developers.” This confidence is great to hear, but we all know what happens when budgets and deadlines start looming ever closer.
66%
Flag icon
In the same way that ports and adapters treat the web as just another delivery mechanism, “package by component” keeps the user interface separate from these coarse-grained components.
66%
Flag icon
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.
66%
Flag icon
“A grouping of related functionality behind a nice clean interface, which resides inside an execution environment like an application.”
66%
Flag icon
THE DEVIL IS IN THE IMPLEMENTATION DETAILS
66%
Flag icon
Again, the implementation classes can be made package protected and dependency injected at runtime.
67%
Flag icon
This is especially true if you’ve forgotten to apply appropriate access modifiers to that code.
67%
Flag icon
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.
67%
Flag icon
Command Query Responsibility Segregation pattern,
68%
Flag icon
It struck me then that this was nonsense; every line of code contains at least one design decision, and therefore anyone who writes code has a much greater impact on the quality of the software than a PowerPoint jockey like me ever could.
68%
Flag icon
And then, thankfully, the Agile Software Development revolution arrived and put architects like me out of our misery. I’m a programmer. I like programming. And the best way I’ve found to have a positive impact on code is to write it.
68%
Flag icon
The way that software is structured can have a profound impact on our ability to keep adapting and evolving it, even in the short term.
68%
Flag icon
Every design decision needs to leave the door open for future changes.
68%
Flag icon
Writing working code that doesn’t block future code is a non-trivial skillset. It takes years to master.
1 4 6 Next »