I’m thinking about something I’ve read in a book: “A well designed system is a testable system” and I’m wondering why it is so.
Certainly, a system that is much tested is probably well designed. Build from the ground up on test-first principles and assuming basic competence, it is hard to imagine a very bad design.
But the statement reverses the idea: that a well designed system is testable.
Why? Is it because good tests are small and simple by default, so making good tests on a bad design (where bad design usually means large and complex classes) is more difficult? Or that it is hard to, say, test a single aspect of a class in isolation when the class in question is a god class?
Testability implies loose coupling. A system is significantly more testable if each of its components can be tested in isolation. This is only achievable if the coupling between each components is kept loose.
Loose coupling is an aspect of good design.
Your goal is to release software with a certain level of quality. Assuming you cannot write every single line of code precisely free of bugs or introduce bugs somewhere in the interaction between those lines of code, how do you verify that you’ve achieved that level of quality? What about other team members, who may not be aware of all the implications of their changes, modifying the software you wrote. Or you yourself making changes 6-12 months after you haven’t seen the code? You need to be able to test your software initially and with every change you make to it, and changes will always happen in anything but the most trivial projects.
If you consider act of design as the act of planning and defining structure for your software, then to produce testable software, you need to have good execution on planning and defining that structure. So that kind of follows that one attribute of good design is a software that you can test.
Keep in mind when most say “ability to test”, it is not a binary yes or no, but a linear scale of how much effort it takes to get to certain level of certainty (95%, 99%, almost never a 100%) that your software works. So on one end of the spectrum, you setup a test and you have N people run your piece of code for a full week through every possible scenario, maybe do stress testing to flush out race conditions. On the other end of the spectrum, you run a set of unit tests that you already produced as part of your TDD process, and within 10 seconds, you get 287 OKs and no failures.
I think that sentence asserts definition of “well designed”. If you say it as “For system to be well designed it has to be testable.” then it starts making sense.
Testability is good property of the system, it is much cheaper to be able to create and run automated tests than manual tests.
Another perspective:
One characteristic of a “well-designed” software system, is that it will generally be built up from orthogonal, composable parts. Each part should be conceptually “pure” — it should deal with one and only one “concern” or aspect of the problem to be solved.
Writing programs like this requires a lot of thought to find the right breakdown. But when you do, there are many benefits — testability is usually one of them.