How do we design a complex behavior or build a complex solution? Can we imagine everything big up front and then just write the full code?
No, probably we will do it incrementally.
We will make progress incrementally and directly to the solution?
Well … it is complicated…
Just tell me how it works.
We will have a first idea of the solution, we will make it work, we will do some tests… and then we will continue with the next increments, but … we will often discover that we need to adapt and change the first code.
There is any danger to be stuck or have some other problems?
Yes, there are more sources of problems. First, if it is too complicated, we can be stuck from the beginning and we can have no idea how to start. Second … when we adapt/change the initial code to add the increments, we can break the behavior previously implemented.
What you say is that when we build something, what we really do is build & change? …and for any change we will need regression test?
Right!
Build real model: Build & Change & Regression Test. Repeat.
You are using test-first approach and auto-tests?
No…
… that mean, in this scenario (without auto-test), the real test will be rather performed when implementation is “ready”?
Yes…. but the ugly part is that we could have many broken parts, and we need to perform again all the tests. Even worse: what we consider as “implemented” will be a big fragile mess, hard to be stabilized.
That mean that, in fact, you will do a lot of tests, you will re-build and repeat many of the tests, with a lot of extra effort and with rather low quality as result?
Something like that.
Summary – designing without auto-tests scenario
- Facing the complexity, we can be stuck from the beginning
- Design it is incremental anyway: build ~ build & change and repeat
- With any change, we will break things
- We will test a lot anyway
- If we will repeat the test after each increment – that will take a lot
- If we will postpone regression test until “implementation end”, we will still test a lot and we will get a big, fragile, buggy mess, very hard to stabilize
- Design improvement is expensive and we will need again the whole spiral of tests
- It is very likely to still have a mess after ”stabilization” and many hidden bugs
So … auto-test will fix all these problems?
Not necessary, you will need some tricks… as Uncle Bob “Getting unstuck”.
Robert C. Martin, Clean Code videos – Episode 19, Advanced TDD part 1, Chapter “Getting unstuck”: <<…and will write the most degenerate tests cases we can, we will very gradually climb the ladder of complexity on little test case at the time and for every test case it fails, will make it pass by generalize the production code, rather than doing some specific fix just to get the test to pass.>>
What is happening here:
- “Getting unstuck”
- We will not be stuck from the beginning, because we can start with simplest test cases
- It is less likely to be stuck later, because by extracting one test cases after another, the complexity of the remaining problems will decrease step by step
- With regression tests available, we are free to adapt and advance to the solution.
- Regression test is inexpensive and fast
- Not breaking things when adding more features
- No big fragile mess at the end
So… that should be enough?
No…. there are also other tricks, such Kent Beck: make it work, make it right, make it fast. You do not want to have a wonderful, fast & clean code and later discover that it is not working.
Summary of the differences
- Getting stuck versus Getting Unstuck
- Throw away the tests with slow re-test versus persistent test with fats re-test
- Break the previous increments versus keeping them working
- Fragile big mess versus robust clean code
Manual tests ~ throw away the tests + re-build them for each regression test