Art of Coding, Chapter 13: Testing as a Design Discipline

This is post 18 of 26 in the Art of Coding blog series. The previous post was Art of Coding, Chapter 12: Version Control as a Storytelling Tool.

Testing as a Design Discipline

I used to think of testing as a chore—something to do after the "real work" of writing code was finished. Write the feature, make sure it works, then reluctantly add tests to satisfy the coverage requirement. But somewhere along my career, that mindset flipped. I realized that testing isn't about proving correctness after the fact. It's about sharpening your design before you build it.

When you sit down to test your code, you're forced to look at it from outside. You stop asking, "Does this compile?" and start asking, "Can I describe this behavior clearly enough to verify it?" That shift—from implementation thinking to behavior thinking—is the essence of design.

Well-crafted tests reveal awkward APIs. If a class is impossible to test without pulling in half the codebase, that's feedback that the design is too entangled. If a function needs a dozen parameters to set up a test case, that's a signal the interface might be too complex. Tests are like sketches in an artist's notebook: they help shape the final work.

💡 Key idea: Tests are more than a safety net. They're a design tool. When you write tests early, you're designing the shape of your system—deciding what's essential, what's incidental, and where boundaries need to be.

The best engineers I know flip the script entirely. They write tests as part of the creative process, sometimes before the implementation itself. This practice (often called test-driven development) forces clarity from the beginning. You define the contract before building the implementation. The test becomes living documentation, a narrative showing exactly how the system is supposed to behave.

Tests as Living Specification

Here's something that still amazes me: tests are documentation that never lies. A wiki page can fall out of date in a month. A design doc can describe a system that no longer exists. But a test? It fails loudly the moment reality shifts. It's a specification that reality must match.

Think about what a well-written test actually communicates. A test named test_new_user_starts_with_empty_cart() tells you immediately what the system does. You don't need to read code; the name and structure of the test explain the intent. Add a few well-chosen test cases, and you have a complete picture of how the system is supposed to behave under different conditions.

The best tests read almost like prose. They have a setup phase (here's the world), an action phase (now do this), and an assertion (this should happen). That structure mirrors how humans think about stories. And when tests are written this way, they become more than verification—they become communication. A new developer joining the team doesn't need to ask questions; they can read the tests and understand the rules.

⚠ Warning: A poorly written test suite can be worse than useless. Brittle tests, over-complicated setup, vague assertions—these breed frustration and eventually get ignored. Tests deserve the same care as production code.

The Testing Pyramid: Where Balance Lives

Unit tests are the sharp pencils of testing—precise, fast, revealing detail. But a system rarely lives in isolation. Real software has layers: databases, APIs, user interfaces, third-party services. This is where integration and end-to-end tests matter. They verify that the pieces actually work together.

The testing pyramid is a useful mental model: a wide base of fast unit tests, a middle layer of integration tests covering the seams where components meet, and a thin peak of end-to-end tests for the most critical user journeys. This shape reflects both cost and value. Unit tests are cheap; end-to-end tests are expensive. But end-to-end tests provide a kind of confidence no other test can: they prove the system works from the perspective of the people who actually use it.

The trap is thinking you need 100% of any one type. I've seen teams with thousands of unit tests that still fail in production because nothing was testing how the pieces talk to each other. I've also seen teams with only end-to-end tests, slow and flaky, that teams learn to ignore. The art is balance—choosing the right tests for the right purposes.

The Hidden Cost of Poor Test Design

There's a quiet irony: the thing meant to protect your codebase can become its downfall if done poorly. I've worked in systems where the test suite was thousands of lines of cryptic setup, mocks within mocks, magic variables no one understood. The team stopped trusting it. Tests were disabled before releases. Eventually, they were abandoned entirely.

The lesson: tests are code too. They deserve clarity, consistency, and care. A test should explain what it's testing and why, without requiring you to trace through ten other files. Names matter. Structure matters. Reducing duplication in test setup matters. These practices cost almost nothing upfront but pay enormous dividends.

When your tests are readable and maintainable, something magical happens. They stop feeling like a burden and start feeling like a collaboration. You trust them. Teammates trust them. They become part of the design language, a shared understanding of how the system should behave. And instead of slowing you down, they actually accelerate you—because you can refactor with confidence, knowing the tests will catch regressions.


In the book, I explore the specific practices that make tests shine: how to structure tests for clarity, how to avoid common pitfalls that make tests brittle, how to use tests as a tool for communicating intent. The point isn't to write more tests, but to write better tests—tests that actually improve your design and make your codebase easier to live in.

Want the full exploration? The Art of Coding: Philosophy and Practice for the Age of AI is available on Amazon. Learn how to write tests that sharpen your design, make your code more modular, and become the most reliable documentation your project has.
2026-01-09

Sho Shimoda

I share and organize what I’ve learned and experienced.