More on this book
Community
Kindle Notes & Highlights
The goal of both is to separate components that change for different reasons, and at different rates. The different reasons correspond to the actors; the different rates...
This highlight has been truncated due to consecutive passage length restrictions.
“package by feature” style. This is a vertical slicing, based on related features, domain concepts, or aggregate roots (to use domain-driven design terminology).
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.
code base with an inside and an outside
The “inside” region contains all of the domain concepts, whereas the “outside” region contains the interactions with the outside world (e.g., UIs, databases, third-party integrations).
The major rule here is that the “outside” depends on the “inside”—never...
This highlight has been truncated due to consecutive passage length restrictions.
In a strict layered architecture, the dependency arrows should always point downward, with layers depending only on the next adjacent lower layer. This comes back to creating a nice, clean, acyclic dependency graph,
reporting violations of the architecture principles that you’ve defined as a team and (you hope) failing the build.
The problem with both approaches is that they are fallible, and the feedback loop is longer than it should be. If left unchecked, this practice can turn a code base into a “big ball of mud.”6 I’d personally like to use the compiler to enforce my architecture if at all possible.
This brings us to the “package by component” option. It’s a hybrid approach to everything we’ve seen so far, with the goal of bundling all of the responsibilities related to a single co...
This highlight has been truncated due to consecutive passage length restrictions.
It’s about taking a service-centric view of a software system, which is something we’re seeing with micro-service architectures as well. 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-grain...
This highlight has been truncated due to consecutive passage length restrictions.
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.”
Something I see on a regular basis is an overly liberal use of the public access modifier in languages such as Java.
In some cases, there’s literally nothing preventing somebody from writing some code to instantiate a concrete implementation class directly, violating the intended architecture style.
lean on the compiler to enforce your architectural principles, rather than relying on self-discipline and post-compilation tooling.
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.
Think about how to map your desired design on to code structures, how to organize that code, and which decoupling modes to apply during runtime and compile-time.
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 conjun...
This highlight has been truncated due to consecutive passage length restrictions.
Also think about using your compiler to help you enforce your chosen architectural style, and watch out for coupling in other areas, such as data models. ...
This highlight has been truncated due to consecutive passage length restrictions.
These computers did not come with operating systems. They didn’t even come with file systems. What you got was an assembler.
If you needed to store data on the disk, you stored data on the disk. Not in a file. Not in a directory. You figured out which track, platter, and sector to put the data into, and then you operated the disk to put the data there.
Yes, that means we wrote our own ...
This highlight has been truncated due to consecutive passage length restrictions.
There are two boundaries in this system. The first is the character output boundary. The applications had no idea that their output was going to a 30-cps terminal.
This boundary was dependency normal—that is, dependencies pointed with the flow of control. The applications had compile-time dependencies on the supervisor, and the flow of control passed from the applications to the supervisor.
The boundary prevented the applications from knowing which kind of device the output was going to.
The second boundary was dependency inverted. The supervisor could start the applications, but had no compi...
This highlight has been truncated due to consecutive passage length restrictions.
interface that inverted the dependency was simply this: Every application was started by jumping to the exact same memory address within the overlay area. The boundary prevented the supervisor from knowing anyth...
This highlight has been truncated due to consecutive passage length restrictions.
We had made the chips independently deployable. We had invented polymorphic dispatch. We had invented objects.
Tiger Team failed entirely after burning two or three man-years on a software project that never delivered anything.
it is very difficult for a redesign team to catch up with a large staff of programmers who are actively maintaining the old system.
At about the same time that the SAC was being redesigned in C, the company started to expand sales into Europe. They could not wait for the redesigned software to be finished, so of course, they deployed the old M365 systems into Europe.