Make It Work. Make It Right. Make It Fast.
Software development is a problem solving activity. Rarely does the same problem come up again and requires the same solution that you have done before. It usually is another entirely different problem, albeit similar in nature. Having the same step by step solution may be handy, but it rarely helps. What is more beneficial is understanding the reason why it was solved rather than how it was solved.
Writing software is more akin to searching rather than construction. The majority of our work is about poking around and seeing what happens. We correlate cause and effects. This is our primary methodology in understanding the nature, properties and behavior of the software we intend to make. That is why there is so much trial and error in the process, and there is nothing wrong with that as some might say. It’s just inherent to the work.
So, it is then unfair to use assumptions that have been drawn from other domains such as manufacturing and construction because the our activities are not analogous to theirs. There is no “design” that can be done for months that you can build off of for the next two years. Nor are there isolated stations that receive input from a previous station and hand off their output to another. Of course you can structure software development this way (e.g. Waterfall, V Model). But we all know it just doesn’t work.
It is a flawed analogy that led to a lot of developer frustration, anger and resentment. The worst part is that charlatans try to repackage the same flawed ideas into all improved versions (i.e. Scrum is just the new Waterfall). Why do you think corporations love these “new” ideas so much? Because its exactly the same idea, that’s why. Companies are risk-averse and anything is really radical is a threat and would never be adopted. This is why even after decades of research in software engineering, companies still fall back to the construction or manufacturing mindset. It is repeatable and scalable, two things that big companies love. However, it doesn’t mean software can’t be. It just has to be done in another way.
A Different Approach
Almost all activities in software development can fall into these three types: Exploration, Exploitation and Enhancement.
Exploration: this is where the team tries to figure out how to do something or why something doesn’t work as intended (or even why it’s working when it’s not supposed to). This is the phase where the developers gain confidence, knowledge and skill. It is okay to make mistakes. Take as many shortcuts as you need. The goal of this phase is to just make it work.
Exploitation: the phase where everyone already knows what to do and how to do it correctly. People have already made mistakes and would like to do it properly this time. More often than not, this phase never happens in real life as output of the exploration phase has already been used as the basis of all future enhancements. Most of the time, you never get the chance to make it right. Well, until now.
Enhancement: the goal here is not limited to making it fast. This is the optimization part and where the team has the explicit intention of making something reach its superlative form: cheapest, fastest, smallest possible. This is normally done in preparation for scaling. However, that approach is also quit costly. A lot of premature optimization based on guesses will be made, sometime even to the detriment of the quality of the software. This team will be driven by data. As per the Pareto principle, we only need to enhance 20 percent of our product to reach 80 percent efficiency. The decisions be based on real-world usage, so there will be no solving of imaginary scaling issues.
These three should not be done out of order. Make it work first, then make it right. Make it right before making it fast.
In your team, for every implementation there should be a chance to explore before exploiting the solution.We can call sandboxing. We will isolate our explorations into repository branches, alternate deployments or separate accounts. This is to allow the developer to explore as much as they like without fear of any consequences. All explorations are time-boxed so you have to be conscious of your time.
There is no perfect solution. We only need to find the solution that solves our current problem. As long as we implement the solution properly, with tests and proper documentation, later implementations, especially the non-trivial ones, would be less painful.
We should also be grounded in reality when it comes to enhancements. There is no reason to enhance a feature that no one uses, right?