Redr · Study Guide
The Pragmatic Programmer
Your Journey to Mastery (20th Anniversary Edition)
David Thomas & Andrew Hunt
Unofficial AI-assisted study guide. Not affiliated with or endorsed by the author or publisher. For educational use — supplements, not replaces, the original work.
Contents
- 01A Pragmatic Philosophy
- 02A Pragmatic Approach
- 03The Basic Tools
- 04Pragmatic Paranoia
- 05Bend, or Break
- 06Concurrency
- 07While You Are Coding
- 08Before the Project
- 09Pragmatic Projects
- Part 01 · A Pragmatic Philosophy & Approach01A Pragmatic Philosophy02A Pragmatic Approach
- Part 02 · Tools & Paranoia03The Basic Tools04Pragmatic Paranoia
- Part 03 · Bend, Break, and Concurrency05Bend, or Break06Concurrency
- Part 04 · Coding, Projects, and Teams07While You Are Coding08Before the Project09Pragmatic Projects
Part 01
A Pragmatic Philosophy & Approach
Ch. 1–2
A Pragmatic Philosophy
Establishes the mindset of a Pragmatic Programmer: own your career, fight software entropy, catalyze change, ship good-enough software, invest in a knowledge portfolio, and communicate deliberately. Programming is a craft demanding personal ownership and continuous learning.
It's Your Life
You own your career, your learning, and your environment. Don't wait passively — if you don't like your job, your skills, or your tools, take action. Pragmatic programmers are active agents in their own lives.
The Cat Ate My Source Code
Take responsibility for outcomes. When something goes wrong, offer options and a path forward rather than excuses. Don't blame the compiler, the cat, or a teammate — provide a solution.
Software Entropy & Broken Windows
Software rot is driven by neglect. One broken window — bad design, wrong decision, ugly code — left unrepaired signals "no one cares" and accelerates decay. Fix broken windows the moment you see them.
Stone Soup and Boiled Frogs
Be a catalyst for change: start something small and useful (the "stone") that others want to join. Conversely, don't be the frog who fails to notice gradual harmful changes — keep an eye on the big picture.
Good-Enough Software
Make quality a requirements issue negotiated with stakeholders. Great software shipped today often beats perfect software shipped never. Know when polishing stops adding value.
Your Knowledge Portfolio
Treat learning like an investment portfolio: invest regularly, diversify, manage risk, rebalance. Learn a new language each year, read widely, take classes, and mix established with emerging tech.
Communicate!
Know your audience, your message, your moment, and your style. Use the WISDOM acrostic: What they want, their Interest, Sophistication, level of Detail, Ownership, and Motivation. Documentation is code.
- Pragmatic Programmer
- An early adopter, inquisitive critical thinker, realistic jack-of-all-trades who cares about craft.
- Software Entropy
- The drift of software toward disorder as complexity and neglect accumulate.
- Broken Window
- A piece of unrepaired bad code or design that signals neglect and invites more decay.
- Stone Soup
- Starting a small useful initiative that catalyzes others to contribute.
- Boiled Frog
- Failing to notice gradual change until it's catastrophic.
- Good-Enough Software
- Quality explicitly negotiated as a requirement, balancing scope vs. delivery.
- Knowledge Portfolio
- Skills and experiences managed deliberately like investments.
- WISDOM
- Communication checklist — What, Interest, Sophistication, Detail, Ownership, Motivation.
Multiple choice
A teammate misses a deadline and tells the project lead, "The build server was flaky and Jenkins lost my artifacts." According to The Cat Ate My Source Code, what's the more pragmatic response?
Spot the issue
A new hire notices a hardcoded password in a config file and a misleading variable name on day one but thinks, "I just started — I'll leave it for someone more senior to clean up." Months later, the module is a tangle of similar shortcuts. What principle did the team violate?
True / False
"Good-enough software" means shipping buggy code and patching it later.
Multiple choice
According to the Knowledge Portfolio metaphor, which habit best matches "diversify and manage risk"?
A Pragmatic Approach
Presents general strategies for writing flexible, adaptable software: ETC, DRY, orthogonality, reversibility, tracer bullets, prototypes, domain languages, and realistic estimating. These approaches survive contact with changing requirements.
ETC — Easier To Change
"Good design is easier to change than bad design." ETC isn't a rule, it's a value: judge every decision by whether it makes future change easier or harder.
DRY — The Evils of Duplication
"Every piece of knowledge must have a single, unambiguous, authoritative representation." DRY covers code, docs, data, and process. Watch for imposed, inadvertent, impatient, and interdeveloper duplication.
Orthogonality
Eliminate effects between unrelated things. Independent components mean changes don't ripple, testing is isolated, and risk is contained. Borrowed from geometry — perpendicular axes don't interfere.
Reversibility
"There are no final decisions." Avoid lock-in to vendors, frameworks, or architectures. Use abstractions and interfaces to keep options open — the world will change underneath you.
Tracer Bullets
Build a thin, end-to-end working slice through every layer of the system early. Unlike a prototype, tracer code becomes part of the final product and gives stakeholders something real to react to.
Prototypes and Post-it Notes
Prototype to learn. Prototypes are disposable and answer a specific question — architecture, UI, performance, feasibility. Throw them away when the question is answered; never ship one.
Domain Languages
Program close to the problem domain. Internal DSLs (embedded in a host language) and external DSLs (with their own parser) let you express solutions in the vocabulary of the problem.
Estimating
Estimate to avoid surprises. Build a model, decompose into components, do the math, then track and refine. Use PERT (optimistic / most-likely / pessimistic) for ranges. Often the best answer is "I'll get back to you."
- ETC
- Easier To Change — the guiding value for design decisions.
- DRY
- Don't Repeat Yourself — one authoritative source for every piece of knowledge.
- Orthogonality
- Independence between components; changes in one don't affect others.
- Reversibility
- Designing so decisions can be undone; avoid technology lock-in.
- Tracer Bullet
- Thin end-to-end implementation that validates architecture and grows into product.
- Prototype
- Disposable code answering a specific learning question.
- Domain Language
- A DSL tailored to express solutions in a problem's native vocabulary.
- PERT
- Estimation method combining optimistic, most-likely, and pessimistic values.
Multiple choice
A team is debating whether to switch from PostgreSQL to a managed proprietary database that locks them into one cloud vendor. Which Pragmatic Approach concept argues most strongly against the switch?
Spot the issue
A product manager asks for a demo of the new checkout flow. The team builds a quick HTML prototype with mock data, JavaScript hacks, and inline styles. The PM loves it and says, "Ship this Monday." The lead agrees and starts hardening the prototype. What's wrong?
Multiple choice
Three modules each compute sales tax with slightly different rounding. Which flavor of duplication is this?
Spot the issue
A junior dev is asked how long a feature will take. They reply, "Probably done by Friday — I'll commit to that." On Wednesday, they realize the integration is harder than expected. What estimating practice did they skip?
Part 02
Tools & Paranoia
Ch. 3–4
The Basic Tools
Basic tools are extensions of a programmer's hands; fluency compounds over a career. Plain text as universal storage, command shells, power editing, version control, debugging, text manipulation, and an engineering daybook form the workbench.
The Power of Plain Text
Store knowledge in human-readable, self-describing formats — JSON, YAML, Markdown, HTML. Plain text outlives the applications that created it and can be processed by virtually any tool you own.
Shell Games
The command shell is the programmer's workbench. GUIs limit you to what designers imagined; shells let you compose tools via pipes for transformations nobody anticipated. Customize aliases, prompts, and completion.
Power Editing
Your editor is an extension of your hand. Move by character, word, line, block. Edit without the mouse. Use macros, multi-cursors, snippets, and language-aware navigation. Use whatever editor you want, but be fluent.
Version Control
Always use version control — for code, notes, dotfiles, everything. VCS is your project's Undo key, enables branching and bisecting, supports blame and time travel, and is the foundation for CI/CD.
Debugging
"Fix the problem, not the blame." Reproduce first, read the error message, don't assume — prove. Use binary search through code and history (`git bisect`), rubber-duck the problem, and never assume the OS or compiler is broken.
Text Manipulation
Learn a general-purpose text manipulation language — Python, Ruby, awk, sed. Use it to generate code, transform data, reshape logs, and bridge tools. Text manipulation is the glue between everything else.
Engineering Daybooks
Keep a paper notebook of what you did, what you learned, sketches, and observations. The daybook acts as a rubber duck, triggers reflection, and gives a searchable history more reliable than memory.
- Plain Text
- Human-readable, self-describing text format including structured formats like JSON and YAML.
- Shell
- Command-line interpreter composing programs via pipes, redirection, and scripts.
- Editor Fluency
- Mouseless text manipulation by syntactic units, with macros and multi-cursors.
- VCS
- Version Control System — tracks every change, supports branching, merging, and bisecting.
- Rubber Duck Debugging
- Explaining code aloud to an inanimate object until articulation reveals the bug.
- Bisect / Binary Chop
- Divide-and-conquer technique for narrowing down a regression's source commit.
- Engineering Daybook
- Paper journal recording actions, ideas, and observations chronologically.
- RTFEM
- Read The F-ing Error Message — error messages usually tell you exactly what's wrong.
Spot the issue
A developer hits a `NullPointerException` and immediately starts editing code to add `if (x != null)` guards in three places, hoping one of them is the right fix. According to Debugging, what's wrong?
Multiple choice
Why does the book recommend storing configuration in plain text (YAML, JSON, Markdown) rather than a proprietary binary format?
Multiple choice
Which scenario is the textbook use case for `git bisect`?
Spot the issue
A developer claims, "I memorize all my debugging sessions — I don't need a notebook. Writing slows me down." Six months later, they hit a familiar bug and can't remember the fix. What practice would have helped?
Pragmatic Paranoia
"You can't write perfect software" — so defend against your own mistakes. Pragmatic paranoia means contracts, assertions, fail-fast crashes, disciplined resource handling, and small feedback-driven steps so failures stay loud, local, and recoverable.
Design by Contract (DBC)
Every routine has a contract: preconditions (what must hold on entry), postconditions (what's guaranteed on exit), and invariants (what's always true). "Be strict in what you accept; promise as little as possible." Lazy code is good code.
Dead Programs Tell No Lies
Crash early. A program that detects an impossible state and dies cleanly is far safer than one that limps along corrupting data. Failing fast surfaces bugs at their source instead of masking them with defensive paste-overs.
Assertive Programming
"Whenever you think 'that could never happen,' add code to check it." Use assertions to enforce invariants you believe hold. Don't disable them in production — production is exactly where you need them. Assertions check impossible states, not expected errors.
How to Balance Resources
"Finish what you start." Whatever allocates a resource — memory, file, lock, transaction — is responsible for releasing it. Deallocate in reverse order, allocate in a consistent order across the codebase, and prefer language constructs (RAII, `with`, `using`) that automate cleanup.
Don't Outrun Your Headlights
You can only see so far. Take small deliberate steps, gather feedback (REPL, tests, demos), and adjust. Avoid fortune-telling long-range estimates and speculative future-proofing — Black Swan events will invalidate them.
- DBC (Design by Contract)
- Routines declare what they require and guarantee; popularized by Bertrand Meyer in Eiffel.
- Precondition
- Condition the caller must satisfy before invoking a routine.
- Postcondition
- Condition the routine guarantees on return.
- Class Invariant
- A condition always true for an object as seen from outside (between calls).
- Assertion
- A runtime check that aborts on an impossible-but-true condition.
- Fail-Fast
- Detect bad state immediately and stop, rather than propagate corruption.
- RAII
- Resource Acquisition Is Initialization — tying resource lifetime to object scope for automatic cleanup.
- Black Swan
- A rare, high-impact, unpredictable event; argues against long-range predictions.
Spot the issue
A payment service detects that an account balance has gone negative — a state the schema declares impossible. The code logs a warning, sets the balance to zero, and continues processing. What's the pragmatic-paranoia objection?
Multiple choice
According to Design by Contract, "Be strict in what you accept; promise as little as possible" means:
Spot the issue
What's the resource-balancing flaw?
def process(path):
f = open(path)
data = parse(f.read())
if not data:
return None # early return on empty parse
transform(data)
f.close()True / False
You should disable assertions in production to improve performance.
Part 03
Bend, Break, and Concurrency
Ch. 5–6
Bend, or Break
Writing flexible, adaptive code that bends with change. Attack coupling from every angle — between objects, events and handlers, data and code, classes in a hierarchy, behavior and environment. Loose coupling, transformations, and external configuration make programs survive reality.
Decoupling
Coupling is the enemy of change. Avoid train wrecks like `customer.orders.find(id).getTotals()`. Follow the Law of Demeter — talk only to immediate friends. Tell objects what to do rather than asking for internals and acting on them externally.
Juggling the Real World (Events)
Real apps must respond to events asynchronously. Four patterns: finite state machines (states + transitions), the observer pattern (registered callbacks), publish/subscribe (decoupled named channels), and reactive streams (events as collections you map and filter).
Transforming Programming
"Programming is about code; programs are about data." Think of programs as a sequence of transformations — input → function → function → output — rather than objects mutating state. Pipeline operators (`|>`, `->>`, Unix `|`) make data flow explicit.
Inheritance Tax
Inheritance is just another form of coupling — "you wanted a banana but got a gorilla holding the banana and the entire jungle." Prefer interfaces for polymorphism, delegation ("has-a trumps is-a") to compose services, and mixins/traits to share behavior.
Configuration
Parameterize behavior with external configuration. Values that vary by environment, customer, or time — credentials, feature flags, log levels, tax rates — belong outside the code. Static files, env vars, databases, or configuration-as-a-service. But don't over-configure.
- Coupling
- A dependency where a change in one component forces changes in another.
- Train Wreck
- A long chain of method calls exposing object internals.
- Law of Demeter
- Methods should only talk to immediate friends — own object, parameters, components, created objects.
- Tell, Don't Ask
- Send messages to objects; don't query state and act on it externally.
- Finite State Machine
- A specification of states, events, and transitions.
- Observer Pattern
- Observable maintains a list of callbacks notified of events.
- Pub/Sub
- Asynchronous event distribution via named channels; publishers and subscribers don't know each other.
- Inheritance Tax
- The hidden cost of class inheritance — coupling to all ancestors and brittle hierarchies.
Spot the issue
What pragmatic principle is being violated?
const total = customer.orders.find(o => o.id === id).items.reduce((s, i) => s + i.price, 0);
applyDiscount(customer.tier.discountRate, total);Multiple choice
"You wanted a banana but got a gorilla holding the banana and the entire jungle" is the book's metaphor for which trap?
Multiple choice
A team hardcodes tax rates, feature flags, and SMTP credentials directly into source code. Which Bend, or Break concept addresses this?
Spot the issue
A developer says, "I always design with classes mutating shared state — pipelines and transformations are just functional fluff." What's the Pragmatic Programmer counter?
Concurrency
Concurrency is a design problem about time, not just threads. Concurrency (apparent simultaneity) differs from parallelism (actual simultaneity). The easiest concurrency bugs to fix are those you never introduced — by breaking temporal coupling and refusing to share mutable state.
Breaking Temporal Coupling
Temporal coupling is when code imposes order or simultaneity the problem doesn't require. Use activity diagrams to find what can run in parallel. Distinguish concurrency (interleaved on one core) from parallelism (truly simultaneous on many). Hungry-consumer queues decouple producers from workers.
Shared State Is Incorrect State
Whenever two threads can read and modify the same mutable resource, you get race conditions — the apple-pie-at-the-diner problem. Even wrapping access with mutexes risks deadlock, lock-order bugs, and forgotten unlocks. Safer: avoid shared mutable state, or make operations atomic.
Actors and Processes
An actor is an independent virtual processor with private state and a mailbox, processing one message at a time to completion, asynchronously, sharing nothing. No locks, no races, no deadlocks. Erlang processes are canonical; actors scale identically across cores or machines.
Blackboards
A blackboard is a shared workspace where independent agents post and retrieve facts via pattern matching — detectives pinning evidence to a corkboard. Originated in AI research, formalized as Linda tuple spaces. Modern Kafka and NATS embody the same idea via event logs and topics.
- Concurrency
- Multiple pieces of code making progress in overlapping time via context switching.
- Parallelism
- Multiple pieces of code executing at the same instant on separate hardware.
- Temporal Coupling
- A dependency in time — required ordering or simultaneity not inherent to the problem.
- Race Condition
- A bug where outcome depends on unpredictable interleaving of operations on shared state.
- Mutex
- A lock allowing one thread at a time into a critical section.
- Deadlock
- A standstill where processes wait on resources each other holds.
- Actor
- An independent processor with private state, a mailbox, and sequential message processing.
- Blackboard / Tuple Space
- Shared workspace where loosely coupled agents post and pattern-match facts.
Multiple choice
Two coroutines on a single-core CPU interleave their execution via context switches. Two threads on different cores execute the same instant. Which terms apply?
Spot the issue
A team wraps every access to a shared cart object in a mutex. They still see race conditions in production and occasional deadlocks. What's the deeper pragmatic answer?
Multiple choice
Which concurrency model has private state per processor, a mailbox, sequential message processing, and no shared memory — eliminating locks and races?
Spot the issue
A senior engineer dismisses Kafka and NATS as "just message buses." A junior engineer points out they share a deeper lineage. What's the connection the chapter draws?
Part 04
Coding, Projects, and Teams
Ch. 7–9
While You Are Coding
Coding is thoughtful, deliberate activity, not mechanical transcription. Constant judgment about design, performance, testing, security, and naming — with conscious craftsmanship beating coincidence at every keystroke.
Listen to Your Lizard Brain
Your nonconscious instincts signal real problems before you can articulate them. Hesitation, fear, or "this code is pushing back" is data. Switch into prototyping mode — write a sticky note that says "I'm just prototyping" — to break analysis paralysis.
Programming by Coincidence
Don't rely on code that just happens to work — understand why. Avoid accidents of implementation (undocumented behavior), context (assumed timezones), close-enough results, and phantom patterns. "Don't program by coincidence."
Algorithm Speed
Estimate resource use with Big-O notation — O(1), O(log n), O(n), O(n log n), O(n²), O(2ⁿ). Verify with profilers and real input. Estimate the order of your algorithms, then test your estimates. Don't prematurely optimize.
Refactoring
Refactoring is disciplined, small, behavior-preserving restructuring — not a rewrite. Do it continuously when DRY violations, non-orthogonality, or new knowledge appear. Never refactor and add features at the same time. Rely on automated tests between every small step.
Test to Code
Testing's biggest payoff is the thinking it forces during design, not catching bugs afterward. "A test is the first user of your code." Design code to be testable — if it's hard to test, the design is wrong. Build end-to-end, not top-down or bottom-up.
Property-Based Testing
Rather than hand-pick examples, declare invariants that must always hold and let a framework (Hypothesis, QuickCheck) generate hundreds of random inputs to falsify them. Failing inputs become permanent regression tests.
Stay Safe Out There
Build security in from day one: minimize attack surface, apply least privilege, use secure defaults, and encrypt sensitive data. Never roll your own crypto. Never commit secrets to version control. Apply security patches quickly.
Naming Things
Names define the reality you create in code. Pause to ask "What is my motivation to create this?" and name by the role it plays. Avoid clever or obscure names. Rename without shame when meaning drifts.
- Lizard Brain
- The nonconscious part of the mind whose unease about code signals real design problems.
- Programming by Coincidence
- Writing code that works by accident, without understanding why.
- Big-O Notation
- Asymptotic expression of how runtime or memory scales with input size n.
- Refactoring
- Small, test-protected restructuring that improves internal structure without changing behavior.
- Property-Based Test
- Automated test asserting an invariant over many auto-generated random inputs.
- Invariant
- A property that must remain true before and after an operation.
- Attack Surface
- The total set of inputs and interfaces an attacker can probe; minimize it.
- Least Privilege
- Grant minimum permissions for minimum time, then drop them.
Spot the issue
A developer writes a date formatter that "works on my machine" but breaks in CI. Investigation reveals the local machine is in UTC; CI runs in PST. The developer shrugs: "Just set the CI timezone." What pragmatic failure is this?
Multiple choice
A function does a linear scan over an array inside a loop that iterates over the same array. What's the dominant asymptotic complexity?
Spot the issue
A pull request is titled "Refactor user service and add subscription billing." The diff touches 47 files: some renames, some new endpoints, some logic changes. What's the Pragmatic Programmer objection?
Multiple choice
You write a function `reverse(reverse(xs)) == xs` and feed it 500 random lists generated by Hypothesis. What kind of testing is this?
True / False
"A test is the first user of your code" — designing for testability primarily helps catch bugs after the fact.
Before the Project
The work that comes before and around code: discovering what to build, breaking through "impossible" problems, working with other humans, and operating in a genuinely agile way. Requirements, solutions, and team practices emerge through tight feedback loops.
The Requirements Pit
No one knows exactly what they want. Programmers help people discover it through iterative dialogue and prototypes, not bulky specs. Work alongside users to think like them. Separate stable requirements from changeable policy — policy is metadata.
Solving Impossible Puzzles
Most "impossible" problems aren't — they're surrounded by assumed constraints. "Don't think outside the box — find the box." Enumerate paths, identify genuinely binding constraints, take breaks to engage the subconscious, rubber-duck, and ask "Why? What's the benefit? Is there a simpler related problem?"
Working Together
"Don't go into the code alone." Real collaboration happens while coding, not in meetings. Conway's Law: systems mirror the communication structure of the org that builds them. Pair programming and mob programming raise quality — start small, criticize code not people.
The Essence of Agility
"Agile is not a noun; agile is how you do things." Agility is a style, not an identity. The recipe is recursive: figure out where you are, take a small step toward the goal, evaluate and correct, repeat — at every level. Rigid "Agile-in-a-Box" methodologies contradict the manifesto.
- Requirements
- Statements of user needs, learned through dialogue rather than gathered upfront.
- User Story
- Short card-sized description of a user need in place of dense specifications.
- Project Glossary
- Shared single-source list of domain terms with consistent definitions.
- Policy as Metadata
- Treating business policy as configurable data rather than hardcoded logic.
- Conway's Law
- Systems are constrained to mirror the communication structures of the organizations that build them.
- Pair Programming
- Two developers at one workstation — one drives, one navigates.
- Mob Programming
- Group programming with rotating typist; includes users and testers.
- Agile Manifesto
- Four values prioritizing individuals, working software, collaboration, and responding to change.
Spot the issue
A product lead hands a 60-page requirements doc to the dev team and says, "Build exactly this — no questions." Six months in, users reject the result. What pragmatic discovery practice was skipped?
Multiple choice
The book reframes "think outside the box" as:
Multiple choice
A startup splits its frontend team across three continents with no shared comms tooling. After a year, the UI is three disjoint single-page apps stitched at the gateway. Which law predicts this?
Spot the issue
A team adopts "Agile" by buying a SaaS tool, scheduling fixed-length sprints, holding three meetings a day, and forbidding any deviation from the playbook. Sprint velocity is the only KPI. What's the Pragmatic Programmer critique?
Pragmatic Projects
Zooms out to project and team level: small stable teams, why cargo-culting others' processes fails, the minimum infrastructure every project needs, focus on user delight rather than mere delivery, and the personal pride that ties it all together.
Pragmatic Teams
Principles scale to teams: no broken windows, watch the bigger picture, schedule maintenance and learning, present one voice externally, build end-to-end with cross-functional teams. Maintain small, stable teams (≈10–12 max). Schedule things to make them happen.
Coconuts Don't Cut It
The cargo cult metaphor: WWII Pacific islanders built fake runways hoping cargo planes would return — they had form but not substance. Copying Spotify or Netflix rituals without understanding *why* they work fails the same way. Do what works, not what's fashionable.
Pragmatic Starter Kit
Every project needs three foundations: Version Control, Ruthless Testing, and Full Automation. Drive builds, tests, and releases from VCS. Test early, often, automatically. "Coding ain't done 'til all the tests run." Find each bug only once. Use saboteurs to test your tests. No manual procedures.
Delight Your Users
Users care about solving business problems, not your code. Ask "How will you measure success after this project ships?" Their answer — retention, cost savings, data quality — is the real target. Exceed it. Delight users, don't just deliver code.
Pride and Prejudice
"Sign your work." Take ownership of and pride in what you build. Pre-industrial craftsmen signed their products; pragmatic programmers do the same. Signature signals craftsmanship, testing, and documentation — without creating territorial silos.
- Pragmatic Team
- Small (≤12), stable, cross-functional team owning code end-to-end.
- Cargo Cult
- Imitating visible artifacts of a successful practice without the principles behind them.
- Continuous Delivery
- Capability to ship to production on demand via VCS, automated tests, and automated deploys.
- Test Automation
- Tests running without human intervention as the gating condition for "done."
- Validation vs. Verification
- Validation = "are we building the right thing?" Verification = "are we building it right?"
- State Coverage
- Coverage measured by logical states and boundaries exercised, not lines executed.
- Saboteur Testing
- Deliberately injecting defects to confirm tests catch them.
- Sign Your Work
- Taking pride and accountability for the code you write, as craftsmen always have.
Spot the issue
A 40-person platform team adopts Spotify's "squads, tribes, chapters, guilds" model wholesale after watching a conference talk. A year later, morale and throughput are worse than before. What's the diagnosis?
Multiple choice
Which trio does the book name as the Pragmatic Starter Kit — the minimum infrastructure every project needs?
Spot the issue
A PM asks the team, "What's the success metric for this project?" The team answers, "We'll ship the four features in the spec by Q3." The PM is unsatisfied. What did the team miss?
Multiple choice
"Sign your work" — the chapter's closing tip — is best understood as:
Key Takeaways
Take responsibility for your career and code — provide options, not excuses, and fix broken windows before entropy compounds.
Good design is design that's easier to change; DRY, orthogonality, and reversibility all serve that single value.
Master your basic tools — plain text, shell, editor, version control, debugger — because fluency compounds across a career.
Practice pragmatic paranoia: design by contract, crash early, assert invariants, and balance every resource you allocate.
Decouple ruthlessly — avoid train wrecks, shared mutable state, and inheritance-driven coupling; prefer transformations, actors, and external configuration.
Test to think, not just to find bugs; refactor in small steps; name things by the role they play; and deliver software your users actually delight in.