codersite.dev / books

Second edition · Paperback and Kindle

A Practical Guide to Building Software That Can Change

Software design principles, trade-offs and architecture for working developers. Learn when each principle helps, what it costs, and when to leave it alone, by following one real system from its first messy version to a design your team can change without fear.

  • 371 pages
  • Java 17, no frameworks
  • Tested code on GitHub
Cover of A Practical Guide to Building Software That Can Change, Second Edition, by Moises Gamio

Chapter 1 opens with this

The one-line change that took a week

“It should have been a one-line change.”

The product owner lowers the annual discount from 20% to 15%. A developer changes the number, runs the tests and deploys. Two days later the checkout page promises one price and the invoice charges another.

Nothing was wrong with the syntax. The same business rule lived in two places, and only one of them received the change. The book starts here, and every chapter adds one more requirement that tests the design.

CheckoutService.javaprice shown
public BigDecimal priceFor(String plan, boolean annual) {
  BigDecimal monthly = switch (plan) {
    case "BASIC" -> new BigDecimal("9.99");
    case "PRO"   -> new BigDecimal("19.99");
    default -> throw new IllegalArgumentException(
        "Unknown plan: " + plan);
  };
  if (annual) {
    return monthly.multiply(BigDecimal.valueOf(12))
        .multiply(new BigDecimal("0.80"))
        .setScale(2, RoundingMode.HALF_UP);
  }
  return monthly;
}
InvoiceService.javaprice charged
public BigDecimal amountDue(Subscription subscription) {
  BigDecimal monthly = subscription.getPlan().equals("PRO")
      ? new BigDecimal("19.99")
      : new BigDecimal("9.99");   // unknown plan? Basic
  if (subscription.isAnnual()) {
    return monthly.multiply(new BigDecimal("12"))
        .multiply(new BigDecimal("0.8"))
        .setScale(2, RoundingMode.HALF_UP);
  }
  return monthly;
}

2 copies of one pricing rule, already disagreeing about unknown plans.

One system, eleven chapters

Every principle arrives when a real requirement needs it

You follow SubFlow, a subscription-billing service, from a procedural first version to a tested, modular system with a public API, two payment providers and prices that marketing changes without a deployment. The requirements are ordinary. That is the point: you will meet every one of them at work.

Part I · Changeable code

  1. 01Prices copied in three placesOne home for pricing; layers
  2. 02Invalid money; partner pricesValue objects, valid states, composition
  3. 03Promotions, a second payment provider, SMSSOLID: pricing rules and payment ports
  4. 04Customers charged twice after a timeoutIdempotent charges, fakes, contract tests
  5. 05The mobile team wants the pricing codeWhen principles conflict; decision records

Part II · Changeable systems

  1. 06A partner retries; webhooks arrive twiceAPI contracts, idempotency keys, the outbox
  2. 0710,000 requests a minute; provider outagesModular monolith, circuit breaker, failover
  3. 08New developers need to understand itC4 and UML diagrams the build keeps true

Part III · Design in practice

  1. 09Three systems from a blank pageA repeatable seven-step walk-through
  2. 10“Not now” from the head of productThe skills that get a design approved
  3. 11Where do you go from here?A growth path and a last exercise
11chapters in three parts
70figures drawn for this edition
145checklist questions
239passing tests on GitHub
4appendices for daily use

How each principle is taught

The whole picture, including the part most books skip

DRY, KISS, YAGNI, coupling and cohesion, SOLID, testability, boundaries and architecture all follow the same ten steps. Steps 7 and 8 are the reason this book exists: a principle applied without judgment can make code worse, so each one comes with its costs and with the cases where you should not use it.

Chapter 5 then puts principles against each other, DRY against simplicity or reuse against independent evolution, and gives you the questions that settle the argument.

  1. The design problem
  2. A problematic example
  3. Symptoms
  4. The principle
  5. The refactoring, step by step
  6. Benefits
  7. Costs and trade-offs
  8. When not to apply it
  9. Exercises on your own code
  10. A short checklist

Free with every copy, and free here

Try the one-page design review on your current pull request

Appendix A collects every checklist in the book, plus a one-page review of 24 questions for the moment before you start a change or send a pull request. Here are six of them. Tick the ones your current change passes.

0 of 6 checked

See all 24 questions on GitHub
  • Ch. 1
  • Ch. 2
  • Ch. 1, 3
  • Ch. 4, 9
  • Ch. 4
  • Ch. 5

Who it is for

For developers who can already write working code

New to object-oriented design

A structured path from your first refactoring to architecture, with every example running in tests.

Read all chapters in order

Experienced, and want better judgment

The trade-offs and the “when not to” that most introductions leave out.

Chapters 1, 3, 4 and 5

Moving toward a senior or lead role

Boundaries, architecture, diagrams, and how to explain a design to managers and teams.

Chapters 1, 5 to 10

Working mostly on APIs and integrations

Idempotency, error contracts, versioning, failures and three systems designed from scratch.

Chapters 1, 4, 6 and 9
Moises Gamio

About the author

Moises Gamio

A software engineer from Peru with more than twenty-five years of experience building business systems in banking, government, retail, e-commerce and business-to-business integration. Most of that time he worked in companies where software was not the product but the tool that sells, bills and delivers. This book is about the design decisions working developers make under real deadlines.

He writes about software design and architecture at codersite.dev. The first edition of this book, Software Design Principles: A Practical Guide, was published in 2022.

Questions

Before you buy

I don’t write Java. Is it for me?
Yes. The examples use plain Java 17 because it reads clearly, but the principles apply equally to C#, Kotlin, TypeScript, Python and other languages. No framework knowledge is needed.
I read the first edition. What is new?
Everything was rewritten around one growing system, and there are four new chapters: testability, conflicting principles, boundaries and APIs, and architecture. UML became a chapter on communicating design, and four appendices were added.
Where is the code?
On GitHub at github.com/mgamio/subFlow, one Maven module per chapter, with the “before” versions kept next to the refactored ones and tests that prove the behavior stayed the same.
Paperback or Kindle?
The paperback is 6 × 9 inches with figures and code printed for reading on paper. The Kindle edition has the same content, with linked chapters for reading on any device.

Stop fearing the next change request.

Get the second edition and the companion code, and make your next change the easy kind.