More on this book
Community
Kindle Notes & Highlights
There is some truth to this belief—but only some. First, history has shown that large enterprise systems can be built from monoliths and component-based systems as well as service-based systems. Thus services are not the only option for building scalable systems.
Second, the decoupling fallacy means that services cannot always be independently developed, deployed, and operated. To the extent that they are coupled by data or behavior, the development, deployment, and operation must be coordinated.
This is the problem with cross-cutting concerns. Every software system must face this problem, whether service oriented or not. Functional decompositions, of the kind depicted in the service diagram in Figure 27.1, are very vulnerable to new features that cut across all those functional behaviors.
These two components override the abstract base classes in the original components using a pattern such as Template Method or Strategy.
Note again that the two new components, Rides and Kittens, follow the Dependency Rule.
Thus the Kitty feature is decoupled, and independently developable and deployable.
Each service has its own internal component design, enabling new features to be added as new derivative classes
What we have learned is that architectural boundaries do not fall between services. Rather, those boundaries run through the services, dividing them into components.
As useful as services are to the scalability and develop-ability of a system, they are not, in and of themselves, architecturally significant elements.
The architecture of a system is defined by the boundaries drawn within that system, and by the dependencies that cross those boundaries. That architecture is not defined by the physical mechanisms by which elements communicate and execute.
The goal is to decouple the structure of the tests from the structure of the application.
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, a...
This highlight has been truncated due to consecutive passage length restrictions.
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 evolved in ways that don’t affect the tests. It also allows the tests to be refactor...
This highlight has been truncated due to consecutive passage length restrictions.
This separation of evolution is necessary because as time passes, the tests tend to become increasing...
This highlight has been truncated due to consecutive passage length restrictions.
In contrast, the production code tends to become increasingly more abstract and general. Strong structural coupling prevents—or at least impedes—this necessary evolution, and prevents the production co...
This highlight has been truncated due to consecutive passage length restrictions.
Tests are not outside the system; rather, they are parts of the system that must be well designed if they are to provide the desired benefits of stability and regression.
Tests that are not designed as part of the system tend to be fragile and difficult to maintain. Such tests often wind up on the maintenance room floor—discarded because they are too difficult to maintain.
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.
Yes, embedded is special. Embedded engineers are special. But embedded development is not so special that the principles in this book are not applicable to embedded systems.
Being able to test only in the target hardware is not good for your product’s long-term health. A clean embedded architecture is good for your product’s long-term health.
From an architectural point of view, the database is a non-entity—it is a detail that does not rise to the level of an architectural element.
Its relationship to the architecture of a software system is rather like the relationship of a doorknob to the architecture of your home.
the database is not the data model.
The database is piece of software. The database is a utility that provides access to the data.
From the architecture’s point of view, that utility is irrelevant because it’s a low-level detail—a mechanism. And a good architect does not allow low-level me...
This highlight has been truncated due to consecutive passage length restrictions.
The relational model is elegant, disciplined, and robust. It is an excellent data storage and access technology.
But no matter how brilliant, useful, and mathematically sound a technology it is, it is still just a technology. And that means it’s a detail.
While relational tables may be convenient for certain forms of data access, there is nothing architecturally significant about arrang...
This highlight has been truncated due to consecutive passage length restrictions.
It originated from the highly effective marketing campaigns employed by the database vendors at the time. They had managed to convince high-level executives that their corporate “data assets” needed protection, and that the database systems they offered were the ideal means of providing that protection.
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.
The organizational structure of data, the data model, is architecturally significant.
The technologies and systems that move data on and off a rotating magnetic surface are not. Relational database systems that force the data to be organized into tables and accessed with SQL have much more to do with the latter than with the former. The data is significant. The database is a detail.
Actually the web didn’t change anything. Or, at least, it shouldn’t have. The web is just the latest in a series of oscillations that our industry has gone through since the 1960s. These oscillations move back and forth between putting all the computer power in central servers and putting all computer power out at the terminals.
Of course, it would be incorrect to think that those oscillations started with the web. Before the web, there was client–server architecture. Before that, there were central minicomputers with arrays of dumb terminals. Before that, there were mainframes with smart green-screen terminals (that were very much analogous to modern-day browsers). Before that, there were computer rooms and punched cards …
The upshot is simply this: The GUI is a detail. The web is a GUI. So the web is a detail.
FRAMEWORKS ARE DETAILS
Don’t marry the framework!
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.
Don’t let frameworks into your core code. Instead, integrate them into components that plug in to your core code, following the Dependency Rule.
When faced with a framework, try not to marry it right away. See if there aren’t ways to date it for a while before you take the plunge.
Now that we know the actors and use cases, we can create a preliminary component architecture
views and presenters will be coded into abstract classes within those components, and that the inheriting components will contain view and presenter classes that will inherit from those abstract classes.
Notice that the arrows do not all flow from the right to the left. In fact, most of them point from left to right. This is because the architecture is following the Dependency Rule.
All dependencies cross the boundary lines in one direction, and they always point toward the components containing the higher-level policy.
Also notice that the using relationships (open arrows) point with the flow of control, and that the inheritance relationships (closed arrows) point against the flow of control. This depicts our use of the Open–Closed Principle to make sure that the dependencies flow in the right direction, and that c...
This highlight has been truncated due to consecutive passage length restrictions.
The architecture diagram in Figure 33.2 includes two dimensions of separation.
The first is the separation of actors based on the Single Responsibility Principle; the second is the Dependency Rule.