- Automated Functional Tests
- Outside-In Development
- Where Do We Start?
- References
Outside-In Development
But there is more to it. In the second part of ATDD by Example: A Practical Guide to Acceptance Test-Driven Development, I show how to drive the domain layer from the acceptance criteria, alongside discovering the domain of the application. While I can already foresee people claiming that I used a simplistic example whose approach worked in the book, but would never work in their complicated codebases, the approach isn't new. The approach that I outlined is called outside-in development by behavior-driven development folks; as mentioned earlier, I've seen references going as far back as 2005. To paraphrase Frank Westphal, outside-in development leads to a totally different solution, because you don't fall too easily for the "solution-problem" trap by focusing on the tool alone. That's what I see most teams doing; they bend themselves and the application domain to fit into any new fancy technology they discover. What these teams should be doing instead is working the application domain from the outside-in, driven by the examples that they and their customers identified together.
Outside-in development is especially difficult if you try to retrofit your examples to a codebase where the domain is mixed into GUI code all over the place. You need some prerequisites. For example, incremental design and architecture is necessary. Instead of fitting your application to the approach of the particular database, application server, and GUI framework, you should work with an adaptable architecture. Alistair Cockburn describes the "ports and adapters" pattern as a hexagonal architecture that serves this purpose. [8] The key idea is to decouple your domain code from any particular framework code, plugging in other architectural layers through ports and adapters. This approach finally leads to an architecture in which you can exchange the database, the user interface, or the application server by implementing a different adapter, leaving your domain objects that use the previously existing ports untouched.
I also consider test-first and test-driven development as necessary to introduce outside-in development. When you automate your examples as functional tests in the glue code, without implementing unit tests alongside, you'll end up with the same problems I described in the book. When trying to extract the evolving domain code from the glue code, you'll end up with a messy domain code that does too much, and you'll have a hard time retrofitting unit tests to your new domain code. Ideally, I love to test-drive my test automation code just as I test-drive my production code.
If I'm able to do this, I have a really minimalistic architecture. My code ends up with just the domain classes that it will need, and I'll have less code to maintain in the long run. Is learning both test-driven development and outside-in development a waste of your time? No, because the long-term benefits far outweigh the short-term learning curve required to learn these techniques. Yet, I consider outside-in development to be a third-level XP practice.