Thinking vs. Coding
When I was growing up as a programmer, it was the time of object-oriented-everything. You were first supposed to do object-oriented analysis (where you you tried to understand the part of the system/domain you were about to implement), then there was object-oriented design (where you’d come up with the program structures that represent what you’d analysed in a way that had the right -ilities and degrees of freedom) and then, finally, you’d grab your IDE and write the code.
This rather strict sequencing is crazy, especially when, as it was kinda normal at the time, it was combined with a waterfall process; the analysis and design phases could last weeks. There were nice german words for the documents you were supposed to write, the Lastenheft and the Pflichtenheft. And the processes of the day, eg., the Rational Unified Process had dozens of dozens of documents you were supposed to produce before you were supposed to start coding. I remember a project at the end of the 90s where the architect expressed his delight about the fact that the RUP was “customizable” for the context it was used in, and that we only had to write 80 of these prescribed documents (no exaggeration here, it was 80). Luckily, hardly anybody did it this way.
Today we’re living in a world of agile where any kind of document has a bad rep. Remember, the Agile Manifesto states that we value “working software over comprehensive documentation” and “responding to change over following a plan”.
This is often (mis-)interpreted as saying that we should not think about the domain or problem before we start coding; just build it, write tests and then see if it’s useful. The agile pioneers didn’t mean it that way. They wanted to prevent exactly these weeks and months long of paper production phases. This is because they realized that the stakeholders often don’t really know what they want until we start building early versions of a system, that requirements change over time (even during the time it takes to build a system), that requirements documents cannot be tested or otherwise verified for consistency (and so they are often incomplete, inconsistent and inscrutable), and that even developers and requirements analysis cannot build layers and layers of mental models without first implementing something and then continue building mental models on top of that executable system.
But here is the problem: many people today really do understand the Agile “prescriptions” as “let’s talk about what the customer needs for a few minutes, and then let’s build something, we can always iterate and change”. This might work alright for simple systems. But if you’re trying to represent a complex domain in software — for example as a DSL, but also in other shapes — you have to spend some time to try and understand
- what are the core abstractions of the domain and how do they relate
- which variability and special cases exist in these abstractions
- which parts of what people tell you as “requirements” are really relevant for the new system and which are just historic accidents and should be ignored or replaced with something better
- in which form should we let users interact with the domain (syntax, etc.)
These “analysis sessions” can last for hours, usually include software (language) people and domain experts, and yes, sometimes we even produce a couple of pages of written material.
The key to success of such sessions is three things:
- There must be some people in the session with significant knowledge about the domain for which we want to define the system to answer questions about how the to-be-built system should work. If you are building a system that replaces an existing one, they also have to be able to distinguish how the current system works versus how a new system is supposed to work.
- Everybody in the group must be able to abstract. You will be conceiving mental models of how a future system should work. If participants can’t do that, this will be a problem.
- People must also be able to communicate precisely and clearly both about the domain, and about how the currently-designed system works based on the current state of the mental models you are building.
A final very important ingredient for these “thinking sessions” is that you recognize when you have to stop thinking and start coding. The pyramid of mental models can only become so high before even the best abstractionists run out of steam or when feedback from future users is needed. At this point stop the session, build a prototype, and learn from it. Go back thinking later, if needed.