In extended code craft training, I work with pairs on a multi-session exercise called “Jason’s Guitar Shack”. They envision and implement a simple solution to solve a stock control problem for a fictional musical instrument store, applying code craft disciplines like Specification By Example, TDD and refactoring as they do it.
The most satisfying part for me is that, at the end, there’s a demonstrable pay-off – a moment where we review what they’ve created and see how the code is simple, readable, low in duplication and highly modular, and how it’s all covered by a suite of good – as in, good at catching it when we break the code – and fast-running automated tests.
We don’t explicitly set out to achieve these things. They’re something of a self-fulfilling prophecy because of the way we worked.
Of course all the code is covered by automated tests: we wrote the tests first, and we didn’t write any code that wasn’t required to pass a failing test.
Of course the code is simple: we did the simplest things to pass our failing tests.
Of course the code is easy to understand: we invested time establishing a shared language working directly with our “customer” that subconsciously influenced the names we chose in our code, and we refactored whenever code needed explaining.
Of course the code is low in duplication: we made a point of refactoring to remove duplication when it made sense.
Of course the code is modular: we implemented it from the outside in, solving one problem at a time and stubbing and mocking the interfaces of other modules that solved sub-problems – so all our modules do one job, hide their internal workings from clients – because to begin with, there were no internal workings – and they’re swappable by dependency injection. Also, their interfaces were designed from the client’s point of view, because we stubbed and mocked them first so we could test the clients.
Of course our tests fail when the code is broken: we specifically made sure they failed when the result was wrong before we made them pass.
Of course most of our tests run fast: we stubbed and mocked external dependencies like web services as part of our outside-in TDD design process.
All of this leads up to our end goal: the ability to deploy new iterations of the software as rapidly as we need to, for as long as we need to.
With their code in version control, built and tested and potentially deployed automatically when they push their changes to the trunk branch, that process ends up being virtually frictionless.
Each of these pay-offs is established in the final few sessions.
First, after we’ve test-driven all the modules in our core logic and the integration code behind that, we write a single full integration test – wiring all the pieces together. Pairs are often surprised – having never tested them together – that it works first time. I’m not surprised. We test-drove the pieces of the jigsaw from the outside in, explicitly defining their contracts before implementing them. So – hey presto – all the pieces fit.
Then we do code reviews to check if the solution is readable, low in duplication, as simple as we could make it, and that the code is modular. Again, I’m not surprised when we find that the code ticks these boxes, even though we didn’t mindfully set out to do so.
Then we measure the code coverage of the tests – 100% or very near. Again, I’m not surprised, even though that was never the goal. But just because 100% of our code is covered by tests, does that mean it’s really being tested. So we perform mutation testing on the code. Again, the coverage is very high. These are test suites that should give us confidence that the code really works.
The final test is to measure the cycle time from completing a change to seeing it production. How long does it take to test, commit, push, build & re-test and then deploy changes into the target environment? The answer is minutes. For developers whose experience of this process is that it can take hours, days or even weeks to get code into production, this is a revelation.
It’s also kind of the whole point. Code craft enables rapid and sustained innovation on software and systems (and the business models that rely on them).
Now, I can tell you this in a 3-day intensive training course. But the extended training – where I work with pairs in weekly sessions over 10-12 weeks – is where you actually get to see it for yourself.
If you’d like to talk about extended code craft training for your team, drop me a line.