Every software project starts with problems and uncertainties, continues with problems and uncertainties, and is delivered with… well, you know.
When we write software, we are solving problems—at least the ones we know about. What overwhelms us are precisely the ones we don’t.
Everything would be a little easier if we accepted that every software project has three truths at its core. Understanding them can make our work more manageable and comfortable. They are:
No software project captures all its requirements at the outset
We are taught that requirements gathering should be the first phase of a project. This is a deep subject in its own right, and in business it often gets off to a bad start. Sometimes the people gathering requirements lack the skills to put them into writing in a way the implementation team can understand. Other times, the person responsible isn’t committed to the project and doesn’t care about specifying things well. And quite often, understanding what the client wants is more a matter of psychology than technology.
For one reason or another, the reality is that receiving complete requirements is a utopian ideal. The sooner we grasp this, the more flexibly we can approach our work. This isn’t the place to discuss agile techniques that address this initial gap through continuous reassessment of the requirements backlog—which is the right way to tackle the problem—but in many workplaces, the context makes it impossible to put an agile methodology into practice.
However many requirements we gather at the beginning, they will almost certainly change
We cannot base all our design decisions and implementation on the initial requirements: what is expected of any software project will change over time. I’ve experienced this many times with clients and their “while you’re at it…” requests, without their understanding the disastrous consequences for the software solution of expecting a four-wheeled vehicle to suddenly fly…
Only if we accept that our software must adapt to change to some extent will we take a more open approach to programming: we will modularize better, properly decouple the product’s functional components, make a greater effort to write clean code, allow extensive configuration and customization, and so on. We can do this only if we develop the habit of programming for change.
Any software that cannot evolve or be modified will be thrown away sooner or later.
There will always be more to do than time and money allow
As a project progresses, the possibilities for development, improvement, and new ideas keep opening up and branching out—exponentially.
We have to accept that there will always be more things to do than we can actually take on. Once we accept this, we can prioritize better and decide what matters to the project and what is secondary. This helps us avoid drifting between unfinished tasks without completing any of them, and prevents us from accumulating technical debt that will come back to haunt us months later.
Simple but effective: three truths that are easy to understand, yet I have so often seen them completely misunderstood in the projects I’ve worked on.
Source (besides common sense): the invaluable book by Jonathan Rasmusson, The Agile Samurai: How Agile Masters Deliver Great Software.