Cheatsheet
Decision Rules
Section titled “Decision Rules”| When… | Do… | Because… |
|---|---|---|
| A small kludge would finish the task faster | Don’t add it; spend the extra time | Complexity is incremental; working code isn’t enough. |
| You’re tempted to split a class or method for size | Check whether the result would be shallow or conjoined | Length alone is rarely a reason; every interface adds cost. |
| Two modules both know the same format or protocol | Merge them, or extract the knowledge behind a simple interface | That’s information leakage. |
| Your modules follow the order of operations | Restructure by knowledge | Temporal decomposition leaks shared knowledge. |
| Almost every caller needs a feature | Make it the default | Make the common case simple (Java buffering vs. Unix I/O). |
| A lower-level class has a method per UI action | Replace them with a few general operations | Special-purpose methods are shallow and leak UI concepts. |
| A class’s methods mostly forward to another class | Expose the lower class, redistribute, or merge | Pass-through methods add interface without function. |
| A value is passed through methods that don’t use it | Put it in a context object | Pass-through variables burden every method on the path. |
| You’d add a parameter because you can’t decide a policy | Compute the value, or give a good default | Configuration parameters push complexity up. |
| You’d throw an exception you don’t know how to handle | Define the error away, mask it, or aggregate it | The caller probably won’t know what to do either. |
| An error is rare and unrecoverable | Crash with a clear message | Handling it adds complexity for little benefit. |
| Code checks a “doesn’t exist” flag everywhere | Represent absence as empty | The normal path then covers the special case. |
| You have your first design | Sketch a radically different second one | Nobody gets large designs right on the first try. |
| A comment is hard to write or must be long | Rethink the design | A hard-to-describe abstraction is a bad one. |
| You’re fixing a bug in old code | Leave the design as if planned for this change | The smallest change makes the design worse each time. |
| You have a “better” convention | Keep the old one unless you have new information and will convert everything | Consistency beats a marginally better approach. |
| Code is slow | Measure first; seek a fundamental fix; else redesign around the critical path | Intuition about performance is unreliable. |
Choosing Between Designs
Section titled “Choosing Between Designs”| Criterion | Prefer |
|---|---|
| Interface vs. implementation | A simple interface over a simple implementation |
| Ease of use | The design that makes higher-level code simplest |
| Generality | Somewhat general-purpose: general interface, current functionality |
| Layers | Each layer a different abstraction from its neighbors |
| Performance | Naturally efficient, if just as simple; extra complexity only if hidden or proven necessary |
Where Should Exceptions Be Handled?
Section titled “Where Should Exceptions Be Handled?”- Can the operation be redefined so the case is normal? → Define it out of existence.
- Can a low-level module (used by many callers) recover? → Mask it there.
- Do many errors end in the same response (such as an error reply per request)? → Aggregate in one handler near the top of the request loop.
- Is it rare, unrecoverable, and likely a bug (out of memory, inconsistent data)? → Crash with diagnostics.
- Does the caller need to know to stay robust? → Expose it and document it.
Thresholds and Defaults
Section titled “Thresholds and Defaults”- Design investment: about 10–20% of development time. Tactical work ends up at least 10–20% slower.
- Comment cost: comments add about 10% to development time at most (Ch 12), or about 5% if half the lines are comments (Ch 15).
- Design it twice: an hour or two for a class.
- Names: two or three words at most; longer names the farther uses are from the declaration.
- Comments: every class, class variable, and method gets one.
- Performance (2018): datacenter round trip 10–50 µs; wide-area 10–100 ms; disk 5–10 ms; flash 10–100 µs; DRAM cache miss a few hundred instruction times. Hash tables can easily be 5–10x faster than ordered maps. Ignoring performance can make a system 5–10x slower than necessary.
Red Flags (quick scan)
Section titled “Red Flags (quick scan)”Shallow Module · Information Leakage · Temporal Decomposition · Overexposure · Pass-Through Method · Repetition · Special-General Mixture · Conjoined Methods · Comment Repeats Code · Implementation Documentation Contaminates Interface · Vague Name · Hard to Pick Name · Hard to Describe · Nonobvious Code. Full table with symptoms in ch21.
Tells and Smells
Section titled “Tells and Smells”- Planning to clean up kludges later → tactical slide; by then the cleanup takes months that the schedule can’t allow.
getCount(),result,status,x/y→ vague names.Pair<Integer, Boolean>in a return type → nonobvious code.getParams()returns aMap→ exposed internal representation.- A reviewer says the code isn’t obvious → “If someone reading your code says it’s not obvious, then it’s not obvious.” Fix the code or comment.