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 · 9
- 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?
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 misconceptionTry it on your own example
Trace one rule change before deciding where the module boundary belongs.