- My conclusion is that the rules of software architecture are independent of every other variable.
- Getting software right is hard. It takes knowledge and skills that most young programmers haven’t yet acquired. It requires thought and insight that most programmers don’t take the time to develop. It requires a level of discipline and dedication that most programmers never dreamed they’d need.
- The goal of software architecture is to minimize the human resources required to build and maintain the required system.
- The measure of design quality is simply the measure of the effort required to meet the needs of the customer. If that effort is low, and stays low throughout the lifetime of the system, the design is good. If that effort grows with each new release, the design is bad. It’s as simple as that.
- The fact is that making messes is always slower than staying clean, no matter which time scale you are using.
- The only way to go fast, is to go well.
- Their overconfidence will drive the redesign into the same mess as the original project.
- In every case, the best option is for the development organization to recognize and avoid its own overconfidence and to start taking the quality of its software architecture seriously.
- The first value of software is its behavior. Programmers are hired to make machines behave in a way that makes or saves money for the stakeholders.
- Software was invented to be “soft”. It was intended to be a way to easily change the behavior of machines. If we’d wanted the behavior of machines to be hard to change, we would have called it hardware.
- I have two kinds of problems, the urgent and the important. The urgent are not important, and the important are never urgent.
- Those things that are urgent are rarely of great importance, and those things that are important are seldom of great urgency.
- The first value of software--behavior--is urgent but not always particularly important.
- The dilemma for software developers is that business managers are not equipped to evaluate the importance of architecture. That’s what software developers were hired to do. Therefore it is the responsibility of the software development team to assert the importance of architecture over the urgency of features.
- Just remember: If architecture comes last, then the system will become ever more costly to develop, and eventually change will become practically impossible for part or all of the system.
- Structured programming imposes discipline on direct transfer of control.
- Object-oriented programming imposes discipline on indirect transfer of control.
- Functional programming imposes discipline upon assignment.
- The problem that Dijkstra recognized, early on, was that programming is hard, and that programmers don’t do it very well. A program of any complexity contains too many details for a human brain to manage without help. Overlooking just on small detail results in programs that may seem to work, but fail in surprising ways.
- Structured programming allows modules to be recursively decomposed into provable units, which in turn means that modules can be functionally decomposed.
- Science is fundamentally different from mathematics, in that scientific theories and laws cannot be proven correct.
- That is the nature of scientific theories and laws: They are falsifiable but not provable.
- Science does not work by proving statements true, but rather by proving statements false. Those statements that we cannot prove false, after much effort, we deem to be true enough for our purposes.
- Inheritance is simply the redeclaration of a group of variables and functions within an enclosing scope. This is something C programmers were able to do manually long before there was an OO language.
- The bottom line is that polymorphism is an application of pointers to functions.
- The problem with explicitly using pointers to functions to create polymorphic behavior is that pointers to functions are dangerous. Such use is driven by a set of manual conventions. You have to remember to follow the convention to initialize those pointers. You have to remember to follow the convention to call all your functions through those pointers. If any programmer fails to remember these conventions, the resulting bug can be devilishly hard to track down and eliminate.
- The fact that OO languages provide safe and convenient polymorphism mean that any source code dependency, no matter where it is, can be inverted.
- Variables in functional languages do not vary.
- All race conditions, deadlock, conditions, and concurrent update problems are due to mutable variables. You cannot have a race condition or a concurrent update problem if no variable is ever updated. You cannot have deadlocks without mutable locks.
- Event sourcing is a strategy wherein we store the transactions, but not the state. When state is required, we simply apply all the transactions from the beginning of time.
- Structured programming is discipline imposed upon direct transfer of control.
- Object-oriented programming is discipline imposed upon indirect transfer of control.
- Functional programming is discipline imposed upon variable assignment.
- What we have learned over the last half-century is what not to do.
- Software--the stuff of computer programs--is composed of sequence, selection, iteration, and indirection. Nothing more. Nothing less.
- The SOLID principles tell us how to arrange our functions and data structures into classes, and how those classes should be interconnected.
- The best structure for a software system is heavily influenced by the social structure of the organization that uses it so that each software module has one, and only one, reason to change.
- For software systems to be easy to change, they must be designed to allow the behavior of those systems to be changed by adding new code, rather than changing existing code.
- To build software systems from interchangeable parts, those parts must adhere to a contract that allows those parts to be substituted one for another.
- Avoid depending on things that you don’t use.
- The code that implements high-level policy should not depend on the code that implements low-level details. Rather, details should depend on policies.
- The lesson here is that depending on something that carries baggage that you don’t need can cause you troubles that you didn’t expect.
- Good software designers and architects work hard to reduce the volatility of interfaces. They try to find ways to add functionality to implementations without making changes to the interfaces.
- Murphy’s law of program size: Programs will grow to fill all available compile and link time.
- Gather into components those classes that change for the same reasons and at the same times. Separate into different components those glasses that change at different times and for different reasons.
- For most applications, maintainability is more important than reusability. If the code in an application must change, you would rather that all of the changes occur in one component, rather than being distributed across many components. If changes are confined to a single component, then we need to deploy only the one changed component.
- Gather together those things that change at the same times and for the same reasons. Separate those things that change at different times or for different reasons.
- Don’t force users of a component to depend on things they don’t need.
- Don’t depend on things you don’t need.
- Allow no cycles in the component dependency graph.
- The architecture of a software system is the shape given to that system by those who build it.
- The purpose of that shape is to facilitate the development, deployment, operation, and maintenance of the software system contained within it.
- 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 goals is to minimize the lifetime cost of the system and to maximize programmer productivity.
- To be effective, a software system must be deployable. The higher the cost of deployment, the less useful the system is. A goal of a software architecture, then, should be to make a system that can be easily deployed with a single action.
- Of all the aspects of a software system, maintenance is the most costly. The never-ending parade of new features and the inevitable trail of defects and corrections consume vast amounts of human resources.
- The primary cost of maintenance is in spelunking and risk.
- Spelunking is the cost of digging through the existing software, trying to determine the best place and the best strategy to add a new feature or to repair a defect. While making such changes, the likelihood of creating inadvertent defects is always there, adding to the cost of risk.
- All software systems can be decomposed into two major elements: policy and details. The policy element embodies all the business rules and procedures. The policy is where the true value of the system lives. The details are those things that are necessary to enable humans, other systems, and programmers to communicate with the policy; but that do not impact the behavior of the policy at all.
- The longer you leave options open, the more experiments you can run, the more things you can try, and the more information you will have when you reach the point at which those decisions can no longer be deferred.
- A good architect pretends that the decision has not been made, and shapes the system such that those decisions can still be deferred or changed for as long as possible.
- A good architect maximizes the number of decisions not made.
- Good architects carefully separate details from policy, and then decouple the policy from the details so thoroughly that the policy has no knowledge of the details and does not depend on the details in any way.
- Good architects design the policy so that decisions about the details can be delayed and deferred for as long as possible.
- A good architecture must support:
- The use cases and operation of the system.
- The maintenance of the system.
- The development of the system.
- The deployment of the system.
- Any organization that designs a system will produce a design whose structure is a copy of the organization’s communication structure.
- A good architecture makes the system easy to change, in all the ways that it must change, by leaving options open.
- Duplication is generally a bad thing in software. We don’t like duplicated code. When code is truly duplicated, we are honor-bound as professionals to reduce and eliminate it.
- Recall that the goal of an architect is to minimize the human resources required to build and maintain the required system. What is it that saps this kind of people-power? Coupling--and especially to premature decisions.
- GUIs change at different times and at different rates than business rules, so there should be a boundary between them. Business rules change at different times and for different reasons than dependency injection frameworks, so there should be a boundary between them.
- Communications between components in a monolith are very fast and inexpensive. They are typically just function calls. Consequently, communications across source-level decoupled boundaries can be very chatty.
- Software systems are statements of policy. Indeed, at its core, that’s all a computer program actually is. A computer program is a detailed description of the policy by which inputs are transformed into outputs.
- Source code dependencies must point only inward, toward higher-level policies.
- In every system, there is at least one component that creates, coordinates, and oversees the others. I call this component Main.
- Think of Main as the dirtiest of all the dirty components.
- The first rule of software design--whether for testability or for any other reason--is always the same: Don’t depend on volatile things.
- Although software does not wear out, firmware and hardware become obsolete, thereby requiring software modifications.
- Although software does not wear out, it can be destroyed from within by unmanaged dependencies on firmware and hardware.
- It is not uncommon for embedded software to be denied a potentially long life due to being infected with dependencies on hardware.
- Software and firmware intermingling is an anti-pattern. Code exhibiting this anti-pattern will resist changes.
- A clean embedded architecture software is testable off the target hardware. A successful HAL provides that seam or set of substituting points that facilitate off-target testing.
- To give your embedded code a good chance at a long life, you have to treat the operating system as a detail and protect against OS dependencies.
- Milliseconds might not seem like a lot, but a millisecond is a million times longer than the cycle time of most processors. If that data was not on a disk, it could be accessed in nanoseconds, instead of milliseconds.
- The relationship between you and the framework author is extraordinarily asymmetric. You must make a huge commitment to the framework, but the framework author makes no commitment to you whatsoever.
- Don’t marry the framework!
- Components are the units of deployment. They are the smallest entities that can be deployed as part of a system.
- Be mindful that most software developers are not very architecture-aware.
20190123
Clean Architecture by Robert C. Martin
Labels:
books
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment