Does splitting code actually split its dependencies?
Start with a rule that sends an email. Separate deciding from doing, then inspect layers, objects and abstractions: which parts must still change together when the rule changes?
Questions in this reading · 11
- Where should a business rule end?
- Where do side effects belong?
- Can you isolate side effects in the language you already use?
- What should cross a module boundary?
- Do separate layers really separate concerns?
- Can small components still be tightly coupled?
- Is removing duplication worth another abstraction?
- What makes an object useful?
- When is it time to stop coding and rethink the problem?
- After splitting two classes, what proves they separated?
- Who chooses the options a person gets to see?
Where should a business rule end?
Separating independent concerns becomes concrete in a functional core: compute the decision from values, then let another layer carry out its effects.
Compare original passages and timestamps · 2
start seeing interconnections between things that could be independentan imperative shell that surrounds the functional core.Where do side effects belong?
Overwatch concentrates side effects on one side of an interaction. A functional core similarly leaves database access and email to its surrounding shell.
Compare original passages and timestamps · 2
all major behavioral side effects are localized to that call sidean imperative shell that surrounds the functional core.Can you isolate side effects in the language you already use?
Separate a decision from the code that reads a database or sends mail. The boundary depends on how data flows, and can be introduced within an existing language.
Compare original passages and timestamps · 2
no language features are required to program this stylethe expired users class makes all the decisions and the sweeper class has all the dependencies.What should cross a module boundary?
Values have meanings that callers can inspect independently. A boundary that passes values makes decisions easier to exercise without setting up the surrounding infrastructure.
Compare original passages and timestamps · 2
values are immutable right and values are semantically transparentwe now have values as boundaries.Do separate layers really separate concerns?
Placing code in different layers leaves the underlying concepts free to depend on each other. Trace which changes still require coordinated edits.
Compare original passages and timestamps · 2
it's a mistake to put optionality in aggregate definitionsdon't associate simplicity with partitioning and stratification, right?Can small components still be tightly coupled?
Changing component size and changing how components communicate are separate decisions. Passing a value can remove a dependency on a synchronous call.
Compare original passages and timestamps · 2
make smaller thingswe now have values as boundaries.Is removing duplication worth another abstraction?
Metz weighs the cost of a wrong abstraction against repeated code. Ousterhout asks how much capability a module hides behind a simple interface.
Compare original passages and timestamps · 2
It is far cheaper to keep duplication than it is to have to mess with the wrong abstraction.very simple interface with a very large amount of functionality underneath itWhat makes an object useful?
Compare refactoring a pricing rule into small objects with the cost of coordinating objects that carry mutable state. A class boundary alone says little about how its users interact.
Compare original passages and timestamps · 2
make smaller thingsthe problem is really not classes per seWhen is it time to stop coding and rethink the problem?
Look for concerns that have become intertwined. Stepping away to reconsider the problem can reveal which of those dependencies really belong together.
Compare original passages and timestamps · 2
start seeing interconnections between things that could be independentmost of the big problems we have with software are problems of misconceptionAfter splitting two classes, what proves they separated?
Start with the obstacle, as in the design talk: changing the mail service also changes expiry calculations. A familiar library may feel easier, but Simplicity Matters distinguishes familiarity from coupled responsibilities. Sierra assembles declared dependencies outside the component; a transducer separates per-input processing from its collection or channel. Try two substitutions: change the service without editing the rule, then run that rule over a different input stream. Which still forces a rewrite?
Passages and timestamps · 4
describing, diagnosing, delimiting the problem, choosing a direction at a high levelIt is really about the interleaving, not the cardinality.I'm going to do is declare my dependencies and they'll get filled in laterthe exact same process bags I defined here, this concrete thing being reused in a completely different contextWho chooses the options a person gets to see?
Urmson’s vehicle can slow down when a pedestrian might step out, buying time for another observation. Suarez describes a different decision boundary: when sensor output exceeds human review capacity, software selects what a reviewer sees. Final approval operates only on items admitted to the queue. Draw three steps—obtaining evidence, selecting candidates and authorizing action—and identify who can change what becomes visible at the next step.
Passages and timestamps · 2
Whereas a self-driving system can look at that pedestrian and say, I don't know what they're about to do, slow down, take a better look, and then react appropriately after that.drones will tell humans what to look at, not the other way around.Try it on your own example
Trace one rule change before deciding where the module boundary belongs.