I’ve been building software since I was 14 years old, and since then, I’ve suffered the consequences of refactoring bad code. First, it was my code that I suffered, then others’ code. Then, that’s how I learned the importance of good software engineering practices and how to make good progress when time is your most valuable asset, which is the topic of today’s post. With it, I hope to convey the intuitions that assist a successful delivery strategy.

The Waterfall of Broken Dreams
During the early days of computing, and as always happens when something new comes along, people hammered a pre-existing mental model and blindly applied it to building software. Then, exactly like building a home, architects, and system analysts would gather requirements, build complicated blueprints and pass them along to the programmers who would produce, after several years, something that wasn’t what the client wanted.
Who was to blame for this? Clearly: communication, or so they thought. Then they designed even more sophisticated software architecture frameworks that would capture implementation details more concisely, only to see the project fail again.
These early cavepeople of software engineering should have recognized the dynamic nature of business and not overestimated the product owners’ understanding of the problem at hand. Then, when this became obvious, they tried designing their software to consider multiple scenarios, making it even more complex and taking much longer to deliver, worsening the problem. When nobody knows the right way to go, clarity in communication loses its value.
I present a simplified diagram of how the waterfall method works to help explain how to optimize it later.

There were several problems with this model, and they’re very well-known and documented, so I want to name the biggest ones as bullets and leave it to you to read more about it.
- It involves very little product owner engagement, only at the project’s beginning and end.
- It takes a significant time to translate all the requirements into development specs (the emphasis on clarity), which is purely overhead and quickly becomes irrelevant.
- It requires a complete understanding of the problem at hand.
Many of the tools and frameworks my generation learned in university worked great in this world. I say this because, just by now, many of my classmates and I hold technical leadership positions in companies, and we are the decision-makers. So, the temptation to standardize on them is natural, it’s what we learned.
Agile Has Been Here Long Enough
I was “captain obvious” in explaining waterfall, and I will not make the same mistake by explaining agile. Almost everyone in the industry knows how agile software development addresses the pitfalls of the waterfall methodology. But then again, why do some insist on building these extensive requirement documents and diagrams and forcing end-to-end clarity? One reason is supportability; when the software is in production, having a way to describe its expected behavior helps discern bugs from usage issues. Another reason is that some companies still have layers of people between product owners and developers (especially when consulting firms are in the mix). Finally, many still can’t abandon the waterfall mentality and adopt a hybrid model.
App Prototyping: Embracing Agile and Ditching Architecture Frameworks
Uncertainty about what to do at the strategic level is the norm during the initial phases of a company, so spending substantial time in an architecture framework doesn’t help to mature the understanding of what the product should be. Furthermore, there must be a tight connection between the product owners (usually marketing) and the developers to quickly iterate into a product that satisfies that initial go-to-market strategy. Also, it is crucial to deliver software of the highest quality to keep early adopters engaged. Then, the best approach is to remove every activity that doesn’t deliver value and switch the emphasis from clarity to adaptability. The interactions must feel like a ping-pong game between developers and product owners.
To make this efficient, developers must build software for immediate change. To this end, the following principles will keep you on track:
- Embrace TDD: If you must write requirements, have them validate and guide the software you build. Building software for automated testing also forces many solution architecture best practices, like “inversion of control,” emphasizing interface design, and reducing the dependency on production-like data.
- Evolve your solution architecture with the product: Over-architected solutions are the enemy of agility. So lay the foundations for change without assuming anything about how it will happen.
- Make it as modular as possible: Small software units adapt quickly to change.
- Connect it With Github: Github (or other source code management systems) offers features that remove the overhead of managing agile projects. Additionally, following practices like atomic commits and pull requests will ensure
- Documentation as Comments: Many languages have constructs to generate documentation from embedded comments in the source code; this moves documentation where it belongs, makes code easier to read and update, and is enforceable through code reviews and automated build checks.
- Embrace CI / CD: Allow the product owners to get their hands on the latest changes as quickly as possible.
- Delay Technology Decisions: We have to make only a few decisions in advance, such as the programming language and the UI framework. We can and must mock production-like data, sign-in technology, and all the boilerplate to allow quick prototyping.
- Think about the users and not the developers: Many technology people favor decisions that make development more elegant instead of more usable software.
- Don’t duplicate the information: If any practice leads you to have two or more views of the same reality, it doesn’t add much value and thus must be avoided.
These are merely the fundamentals, but they constitute a solid base to set you up for success. With these practices in place, we can re-draw the initial waterfall model into this dynamic circle:

Over each iteration, the developer must be able to quickly refactor and adapt the solution architecture to the current needs and deliver the changes that the new circumstances required.
I’m a firm believer that everything we put in place must answer yes to three of the following questions:
- First, will this practice make software delivery quick immediately?
- Second, will this practice help keep and enhance delivery speed in the future?
- Third, will this practice deliver noticeable value?
In Summary
I aim to deliver quick and robust software prototypes in this simplistic view of the world. Furthermore, I recommend favoring activities that provide noticeable value in speed, quality, and ease of change, even if we sacrifice some clarity between the product owner and the developer. These intuitions emphasize quick delivery and software engineering practices that enable it. Finally, I share the three questions that I ask before adopting any practice.
Leave a Reply