Software development deadlines. They haunt our dreams, ruin our weekends, and yet, somehow, we’re always shocked when we miss them. From tiny web projects to colossal AAA games, the software industry has an infamously bad reputation for blowing past deadlines and budgets. But how do software engineers manage to be worse than, say, the folks who bid on highway systems?

The Known Unknowns: We Sort of Know What We’re Dealing With

Before we tackle the real villain, let’s touch on the “known unknowns.” These are the things we anticipate will pose questions or challenges. When a project kicks off, developers huddle with domain experts to map out the grand plan. This early phase is rife with questions:

  1. Architectural Trade-offs: “Should we use Framework X for rapid development? Will it scale if our user base explodes?”
  2. Technical Feasibility: “Is there a library that does what we need? Do we have to build it from scratch?”
  3. Project Management Triangle: “Do we write quick-and-dirty code now, knowing we’ll refactor later, or aim for scalability and security from the get-go?”

These questions are predictable and somewhat manageable. We know they’ll pop up and can plan (read: guesstimate) for them. But then come the…

Unknown Unknowns

Unknown unknowns are the sneaky, unpredictable gremlins that can throw a project into chaos. They are the reason even the most detailed plans can blow up spectacularly.

Examples of Unknown Unknowns

So, what do these elusive unknown unknowns look like in practice? Here are a few examples:

  • The Market/Product Changes: This is the most common. When you’re building software you are building it for an end user with a purpose in mind. But you can never know FOR SURE that you’re building the right thing. You will only really know what needs to change when you first watch a user play with it. That’s why it’s so important to get it into the hands of real users as quickly as possible.
  • Emerging Technology Changes: A new version of a critical framework or library is released midway through your project, rendering your current approach obsolete.
  • Unforeseen Integration Issues: An external API you depend on changes or is deprecated without warning, requiring significant rework. This literally happened to me this week, and I spent two days fixing a problem that worked the first time with the old API. And this was a tiny python script and a Make.com workflow… not some giant HIPAA compliant stack that has five engineers working on it. That kind of change could mess up a project by months.
  • Unexpected User Behavior: During testing, users interact with your software in completely unanticipated ways, uncovering bugs and usability issues that require substantial fixes. Think of yourself as an explorer here; learning new ways your system can be used, and how users can f*@&k it up.
  • Regulatory Changes: New laws or industry regulations come into effect, necessitating changes to your software to remain compliant.
  • Team Changes: Key team members leave the project, taking with them critical knowledge and slowing down progress as new members are onboarded.

The Exploratory Nature of Software Development

Software development often feels like your are Indiana Jones navigating a jungle with a half-baked map. Sure, you have a rough idea of where you’re going, but the terrain can change unexpectedly. When developers estimate how long a task will take, they’re picturing a perfect world scenario. It’s tough to convey to managers or clients—who often see programming as a kind of magic—why one feature is a cakewalk and another is a nightmare.

Agile vs. Waterfall: Why Flexibility Matters

This is why traditional waterfall methodologies, which demand every detail be nailed down upfront, often fail in software development. Designing everything on paper without accounting for unforeseen problems is a recipe for disaster. Agile methodologies, with their iterative and flexible nature, help mitigate the chaos of unknown unknowns by allowing for continuous reassessment and adaptation.

Agile is by no means perfect though. Agile projects fail for different reasons: scope creep, running out of budget, not being disciplined in prioritizing features, not launching quick enough, over-engineering, and plain old building bad software.

The Myth of Big Design Up Front

Big design upfront (BDUF) robs software of its most powerful trait: adaptability. The ability to iterate, update, and improve on the fly is crucial. Agile approaches embrace this, understanding that no one can predict every challenge. The flexibility to pivot based on real-world feedback and emerging obstacles is what keeps projects on track—relatively speaking.

Making Software Development More Predictable

While we can’t eliminate all the unknowns, there are strategies to make software development more predictable. The problem is that most of this stuff makes you slow down. There is always a trade off. So enjoy!

  1. LAUCH EARLY AND OFTEN: Get your system into the hands of real users as soon as possible. If you’re not embarrassed to let users play with it, you’ve launched too late. I just wrote about this.
  2. Adopt Agile Methodologies: Agile frameworks like Scrum and Kanban promote iterative development, continuous feedback, and flexibility, making it easier to adapt to changes and unforeseen issues.
  3. Frequent Check-ins and Reviews: Regularly scheduled reviews, stand-ups, and retrospectives help catch issues early, before they spiral out of control.
  4. Automated Testing: Implement a robust suite of automated tests to catch regressions and integration issues early in the development process.
  5. Continuous Integration/Continuous Deployment (CI/CD): Use CI/CD pipelines to automate the deployment process, ensuring that new code integrates smoothly with existing systems.
  6. Risk Management: Proactively identify potential risks and develop contingency plans to address them if they arise.
  7. Maintain a Flexible Architecture: Design systems with modularity and scalability in mind, allowing easier adjustments as requirements evolve.
  8. Clear Documentation: Ensure comprehensive and up-to-date documentation so that new team members can quickly get up to speed and existing members can easily reference past decisions.
  9. Cross-Training Team Members: Promote knowledge sharing and cross-training within the team to prevent project delays if someone leaves or is unavailable.

Embrace the SOME of the Chaos

Software development is messy, unpredictable, and often maddening. But by recognizing the difference between known unknowns and unknown unknowns, and embracing methodologies that allow for flexibility, we can navigate the chaos more effectively. Next time a deadline whooshes by, remember: it’s not (just) about poor planning. It’s about the nature of the beast itself.

In the end, the key to handling software project deadlines is accepting that some things will always be out of our control. So, let’s embrace SOME of the chaos, adapt on the fly, and maybe, just maybe, we’ll get a bit closer to hitting that elusive target. And if not, there’s always more tea, whiskey and a good sense of humor to see us through. Although that will never make your boss our your client happy.

Previous ArticleNext Article
I help companies turn their technical ideas into reality.

CEO @Sourcetoad and @OnDeck

Founder of Thankscrate and Data and Sons

Author of Herding Cats and Coders

Fan of judo, squash, whiskey, aggressive inline, and temperamental British sports cars.

Leave a Reply

The Million-Line MVP

A founder told me last week that his chatbot understands him better than most people he works with, and he wasn’t joking.

He had been alone in his house for the better part of a year building an app on one of the popular AI coding platforms, and he wanted me to take a look. Almost a million lines of code, one developer (him), no engineering co-founder, no senior reviewer, no nobody. The app had an ERP module, a CRM module, a custom AI agent with a name and a voice, built in mini-games (yes, really), dozens of character personas, a few landing pages, and a small army of social media accounts in multiple languages. He had not yet had a paying user, or even a free one.

He was, by the way, very excited.

(I’ve changed some details, since the pattern is what I want to talk about and not the founder. I see something close to this on roughly one out of every three sales calls now.)

What used to slow you down was the point

Building software used to be annoying for mostly good reasons. You had to hire developers, or learn to code yourself, or convince a co-founder to come along for the ride. Then, you would grind out every line, which would come at a cost (time, money, conversations, arguments, etc.)… basically friction. And that friction was not a bug, but it was like this ting that you are forced you to deal with, before adding any feature, whether the feature actually needed to exist.

Startup advice has been more or less the same for twenty years, maybe more:

  • Build something small
  • Show it to real people
  • Find out what they actually want
  • Don’t build a million things at once.

The Lean Startup came out in 2011 and we have all been quoting it at each other ever since (poorly, mostly).

This is what we talk about when we discuss “startup discipline”. It’s really not very complicated, but it can be really hard. It used to be hard because building was hard, and now it’s hard for a completely different reason.

How does one person build almost a million lines of code in a few months?

The honest answer is they don’t, the AI does, and the AI has no opinion on whether any of the code should exist.

This is the part I want to sit with for a minute, because I think it’s the heart of the problem. Imagine you’re building a startup that lets local news anchors rent out their unused toupees by the hour (try not to overthink this). You sit down with one of the AI coding tools and you say “build me a marketplace where toupees can be listed by the hour,” and the AI builds it. Then you say “actually, add a loyalty rewards program,” and the AI builds that too. Then you say “and also, add a Pokemon-style mini-game where users battle each other’s toupees,” and the AI starts coding.

It doesn’t pause or ask why, and it doesn’t say “dude, I love your enthusiasm but I am genuinely worried we are losing the plot here,” it just builds the toupee-battle-feature.

This removes the single most useful thing about a good engineering team, which is that engineers PUSH BACK. A senior developer, or a seasoned product manger, asked to add a toupee-battle mini-game to a B2B rental marketplace would slowly take off their glasses, set them on the desk, and ask one of those long quiet questions that means “we are not doing this.” The AI this is a sycophantic drone that has the eagerness of an underfed puppy to please you, and it has no glasses to take off. It also has unlimited keystrokes and believes that every single idea you’ve ever come up with is absolutely genius. At least it tells me that everything I’ve ever written or thought about is pretty clever.

A few months ago I ran into the perfect name for this, which is Slurm Coding. I used to call it AI crack coding, because the dopamine loop is very real, and I have really needed another hit of that good AI crack just one more time before I went to bed on more than one occasion. But Slurm is both more insidious in its combination of addictiveness and corporate outreach.

The MVP don’t change

Here’s what hasn’t moved in twenty years of startup thinking:

  1. Build the smallest thing that solves one specific problem for one specific person.
  2. Show it to that person (a real person, probably not your spouse, definitely not your mom, and DEFINITELY not my mom, and 100% not your chatbot).
  3. Find out what they actually do with it (which is probably not what you thought).
  4. Kill features, pivot, or double down based on what you learned.
  5. Repeat.

What’s new is that step one is basically free, and while not perfect, free is very alluring. You can build the smallest thing in an afternoon, or the largest thing if there’s no one around to tell you not to. Steps two through five still require getting out of your house, talking to humans, accepting that most of your assumptions are wrong, and throwing real work away. None of that is faster than it was in 2005, none of it is fun, and none of it scratches the “I NEED MORE SLURM” build-a-thing itch the way an AI tool does.

So a certain kind of founder just skips it, staying in the build phase indefinitely, because the build phase now feels like winning at a casino while getting unlimited free martinis. The feature ship (how to get them onto a server is someone else’s problem) the codebase grows, the agent agrees with everything. Meanwhile the only thing that actually matters, which is whether anyone wants this, goes unanswered.

It’s the founder version of Wilson the volleyball. In your unwashed isolation, you’ve made a friend, you’ve named the friend, and the friend agrees with everything you say. The problem is that the friend is also the boat, the island, and the ocean, and you haven’t actually left the house yet.

To be fair, I am not above this myself, by the way. I have, in my time, built things that nobody asked for and gotten weirdly emotional about them, but the difference is that mine were three hundred lines of code over a weekend, not almost a million lines of code over the better part of a year, which is sort of the whole point. No one asked for my William S. Burroughs poetry writing twitter bot, but I loved it anyway.

Codebases don’t love you back

Code you wrote yourself CAN hard to let go of, and code you wrote with an AI, when you are not a trad-coder, seems to be way harder. Experienced engineers seem to be more than happy to throw away AI code or rebuild it in a heartbeat. But I can see how even if you didn’t actually write the lines, but the shape of the thing is yours (you named the characters, you picked the voice, you spent months in a chair with this thing as your only collaborator), and you have feelings about it.

But one day, if you’re lucky, and it does have SOME product market fit, a real engineering team is going to need to look at your masterpiece. And they are not going to share those feelings. They’re going to tell you, as gently as they can manage, that most of it has to go. Not because they’re mean (they might actually be mean), but because almost a million lines of AI-generated code, written by one person, in one tool, with no architectural review, is never maintainable, almost guaranteed to not be secure, and almost never going to scale past the “prototype” it currently is.

So what should you actually do?

I mean, I already told you… Build the smallest thing you can, then show it to ten strangers and actually listen to them. Throw away half of what you built and build a slightly different smallest thing, and repeat until one of those things is real. Keep your runway reserved for the moment you realize you were WAY off about something important, because, like, you will be, and that moment is what your runway is for.

Use AI tools, because they are legit amazing. But treat them like a coffee machine (fast, useful, no opinions of their own), not like a co-founder or worse, a slot machine. Co-founders are supposed to tell you no, slot machines whisper “just one more hit baby!”