How to Actually Give Estimates That Hold

You think you know how long something will take. You don't. Here's the process that gets you close enough to not embarrass yourself.

Everyone is bad at estimating. Senior engineers are bad at it. People who have been building software for twenty years are bad at it. The optimism bias is baked in — you picture the clean path through the problem, not the three wrong turns, the undocumented API, the scope that quietly doubles in week two.

The mistake isn’t being wrong. The mistake is estimating from your head instead of from the problem.

Here’s how I actually work through an estimate before committing to one.

1. Have I done this before?

The first question isn’t “how long will this take” — it’s “how much do I actually know about this?”

If you’ve built something meaningfully similar before, you have real data. Not a feeling, not a guess — actual evidence. How long did the last one take? What surprised you? What turned out to be harder than it looked? Use that. Adjust for the differences in scope and context, but anchor to reality.

If you haven’t done it before, or haven’t done anything close to it, that’s important information. It means your estimate is structurally less reliable, and you should communicate that. “I’ve built something like this before and it took about three days” is a very different statement from “I’ve never done this but I think three days.” Both are estimates. Only one of them is honest about its uncertainty.

The closer your prior experience is to the current problem, the tighter your estimate can be. The further it is, the more buffer you need — not because you’re padding, but because unknowns are genuinely expensive.

2. Is there a library for it?

Before you estimate the implementation, find out if you’re even implementing from scratch.

This sounds obvious, but the amount of time spent estimating — and building — things that already exist as a well-maintained package is significant. Five minutes of searching can remove days from an estimate. It can also reveal that the “simple” thing you were going to wire yourself is actually a solved problem with a hundred edge cases already handled.

The inverse matters too. Sometimes you find a library that almost does what you need, and the cost of bending it to your requirements outweighs building the thing directly. That’s worth knowing before you commit to using it. Libraries are leverage, but they’re also constraints.

Check the obvious places: npm, PyPI, pkg.go.dev, whatever’s relevant to your stack. Check GitHub for similar projects even if they’re not packaged. A five-year-old repo that’s no longer maintained can still tell you a lot about how hard a problem actually is.

3. What are the absolute unknowns?

List every part of the project where you have genuinely never been before. Not “this is a bit unfamiliar” — things you have never worked with in your life. A new API, an infrastructure pattern you haven’t set up, an algorithm you’d need to learn to implement.

These are your high-variance items. Each one is a potential black hole. You cannot estimate time on things you’ve never done with any confidence — you can only acknowledge that they’re unknowns and factor that in.

Once you’ve listed them, ask for each one: is this unknown actually on the critical path? Some unknowns are nice-to-haves or edge cases. Those are fine. The dangerous unknowns are the ones where the core feature doesn’t work until you’ve solved them.

For critical-path unknowns, stop estimating and start researching. Even an hour of reading, watching, or skimming documentation will move you from “no idea” to “rough shape of the problem.” That’s enough to assign a rough estimate. Without it, you’re just guessing.

4. Skim GitHub

Before you write a line of code or commit to a number, search GitHub for the problem.

Not to copy — to calibrate. Search for the core terms: the API you’re integrating, the pattern you’re implementing, the thing you’re building. Look at how other people approached it. How many files did a typical implementation touch? How many issues are open? Are the issues mostly cosmetic, or are there fundamental problems people are still hitting?

A repository with 200 open issues and a lot of “this doesn’t work with X” threads is telling you something. A clean, small implementation with clear commits tells you something else. The shape of other people’s solutions gives you a ground truth that your own mental model can’t.

This is especially useful for the unknowns from step three. If you’ve never worked with a particular API, find three or four real implementations of it on GitHub. Read the code. How complex is the auth flow? How much boilerplate? Are there surprising dependencies? This turns an abstract unknown into a concrete one, and concrete unknowns are estimable.

5. Build a rough MVP in the first two hours

This is the most important step, and the most underused.

Before you give a final estimate — especially for anything longer than a day or two — spend the first two hours building the roughest possible version that covers all the major surfaces. Not a polished MVP. A proof-of-concept that touches every part of the problem: the data flow, the integration points, the tricky bits you identified in steps three and four.

It doesn’t have to be good. It doesn’t have to handle errors. It doesn’t have to be structured properly. It just has to tell you whether your mental model of the problem is correct.

There’s an element of ego in this that’s worth naming. Can you build a rough version of this thing in two hours? Often yes. And that two-hour session will reveal more about the actual scope than any amount of planning will. You’ll find the dead ends. You’ll find the integration that doesn’t work the way the documentation says. You’ll find the thing that seemed simple but actually requires three other things to be in place first.

After two hours you’ll know one of three things:

  • The path is clear and roughly as complex as you thought. Your estimate was probably right.
  • The path is clear but more complex than you thought. Your estimate needs to go up.
  • The path has a problem — a dead end, a missing capability, an incompatibility — and the whole approach might need rethinking before you estimate at all.

The third outcome is the valuable one. It’s much better to find this in a two-hour spike than halfway through a week of work.

Someone has probably already done it

Here’s the funny thing underlying all of this: whatever you’re trying to build, there’s a very good chance someone else has already built it. Maybe not the whole system exactly as you need it, but the pieces — the algorithm, the integration pattern, the data structure, the approach. Scattered across GitHub repos, blog posts, Stack Overflow threads, and half-finished side projects.

There are remarkably few things in software that are genuinely novel. Truly unique systems — ones where no one has ever touched the underlying problem — are rare. Most of what we build day to day is a recombination of patterns that exist, applied to a specific context that’s ours.

This isn’t discouraging. It’s liberating. It means the research steps above aren’t a shot in the dark — they almost always return something useful. Someone has hit the edge case you’re worried about. Someone has integrated that API and written about the gotchas. Someone has open-sourced the rough shape of the thing you’re planning.

The implication for estimates is direct: if you can’t find anything — no library, no GitHub repo, no blog post, no prior art of any kind — that’s a signal. Either you’re searching wrong, or you’re genuinely in uncommon territory. The first is fixable. The second means your unknowns are real and your estimate should reflect that.

Most of the time though, you’ll find something. And what you find will tell you more about how long the work actually takes than anything you could reason about from a blank page.

Putting it together

The process isn’t complicated. Before you give a number:

  1. Check your prior experience — what have you built that’s actually similar, and how long did it take?
  2. Check for libraries — what’s already solved, and what are you actually building?
  3. Identify the absolute unknowns — what’s on the critical path that you’ve genuinely never done?
  4. Skim GitHub — what do real implementations look like, and what do they tell you about the problem?
  5. Build a quick spike — two hours, rough, covers all the surfaces. Now you know.

After that, you have a real basis for an estimate. Not a feeling, not an educated guess — evidence. You’ve seen the problem. You know where the hard parts actually are. You know which unknowns turned out to be nothing and which ones are real.

Estimates are still estimates. They’ll still be wrong sometimes. But they’ll be calibrated wrong rather than optimistically wrong, and there’s a significant difference between the two.

When you really screwed it up

Sometimes the process above doesn’t save you. The spike looked clean, the unknowns seemed manageable, and then the project ate three times the time you said it would. You’re late. People are waiting. And the voice in your head starts going: maybe I’m just not good at this. Maybe I shouldn’t be doing this. Maybe I should go work on a farm.

That voice is not useful. But it’s also not random — it shows up specifically in this situation because bad estimates feel like evidence of incompetence. They’re not. They’re evidence that the problem was harder than it looked, which is a thing that happens to everyone, at every level, on every team.

What you should actually do:

Stop and resurface the scope. The first thing is to understand what actually happened. Not as self-criticism — as diagnosis. Where did the estimate break down? Was there an unknown that turned out to be much larger than expected? Did scope change mid-way? Did an integration behave completely differently than documented? Find the specific thing. Vague “I just misjudged it” doesn’t help you next time. A concrete “I didn’t account for the auth flow being stateful across services” does.

Communicate early, not at the deadline. The worst thing you can do when you realise an estimate is slipping is wait. The longer you wait, the more options other people lose. If you’re three days into a five-day estimate and you know it’s going to be ten days, say so now. Not on day nine. People can work with updated information. They can’t work with a surprise.

This is the part that feels hardest when imposter syndrome is running hot — communicating bad news feels like confirming you’re incompetent. The opposite is true. The people who stay quiet until the deadline are the ones who damage trust. The people who surface problems early are the ones who can be relied on.

Separate the estimate failure from your ability. One bad estimate, or even several, does not tell you whether you’re good at your job. It tells you that estimation is hard and that this particular problem had surprises in it. The engineers you admire have all blown estimates. The ones who seem to always be right are either working on very predictable problems or they’ve padded so aggressively that “always right” is doing a lot of work.

What you learn from a badly missed estimate — if you do the diagnosis — is worth more than ten correctly estimated projects. You now know something real about where your blind spots are.

Update the estimate and keep going. Once you’ve diagnosed it, communicated, and recalibrated, the only thing left is to finish. The farm will still be there if you change your mind. For now: close the tabs, reset the three-item card, and build the next piece.