Emma, the Software Development Engineer

I had a mentor who once told me about a software development engineer named Emma. She was a true rockstar.

She could estimate delivery dates of projects with 80% accuracy and went on to do great things in her life using this superpower. Some of her achievements are:

  1. She became the first developer to climb Mount Everest without any surprises.
  2. She became the first developer to land on the moon, again, without any surprises.
  3. She became the first developer to land on Mars, again, without surprises.
  4. Oh, and did I tell you about how she discovered cold nuclear fusion in her first try, without surprise?.
  5. Finally, she made machine learning and deep learning work to solve real-world problems!

Some say she is now working on creating a Dyson Sphere in her new stealth mode startup to make humans a type II civilization.

Sounds unbelievable, no? This is the true power of estimation. Even Thanos could not estimate the turn of events in Avengers Endgame!

Estimating delivery dates is hard

There are a lot of things which are hard in computer science. I know you know somewhere deep in your heart that accurate estimation is even harder than these hard problems. After all, we humans are complicated animals.

But do your customers and managers understand?

Program Manager

Customer

Do the above images look familiar to you? Do they bring back painful memories? Or are you one of those rare superstars in the software world (like Emma) who can successfully predict the dates? If you can, you are in the wrong career, and probably will make more money predicting results of Super-Bowl, FIFA World Cup, or Olympics :)

But why is estimating delivery dates hard?

If I get down to list variables and questions involved in a typical estimation of delivery dates, here is a list of some of them, and I am sure you will be able to think of many more.

Requirements: Are they complete? Are they frozen? Are you sure? How can you be sure about that one feature which is still under discussion? Did you know, that one feature also affects 5 other features? Got you there, champs devs!

And wait! Have you reliably validated the requirements? How did you get the requirements? Who gave them to you? Did they validate? Here’s a little code for you:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fun correctnessProbability(
  distanceFromCustomer: Int
) = 
if 
   (distanceFromCustomer == 0) 1
else 
   correctnessProbability(
     distanceFromCustomer - 1
   ) * 0.9
     // 0.9 is an "estimate" again

So, if you are directly interacting with the customer, chances are you will get requirements right with 90% probability. If you are interacting with a program manager who interacts with the customer, this probability drops to 81%. If there are extra layers in between, this probability drops rapidly to 73%, 65% and so on. Suddenly you have a situation similar to a Chinese whispers game, where the customer asked for a burger, requirements that came to you mentioned sandwich, and suddenly you have a disappointed and hungry customer eating a sandwich which he never wanted, but paying the cost of a double-layered burger.

Developers: Will somebody go on leave? Do you have sufficient redundancy? Will someone suddenly be on-call since the actual on-call had diarrhea after drinking coffee with sugar? Will someone suddenly announce his wife had a baby and go on 6 weeks paternity leave, and leave you awake at night thinking why aren’t you married yet (besides your other life choices)?

Hiring and Attrition: Will you need to hire someone for this project? Good luck getting anyone soon enough! Will someone leave the team or the company? Did you see someone with leetcode tab open, but suddenly found him staring at his blank desktop when you reached his desk? (Yay, open-office!)

Stakeholders: Do they agree on how other projects align with this one? Will they pull folks from other projects to ensure your project has enough people? Will they do it again in future and pull out folks from your project for some other high priority tasks, and leave you alone in the dust to build a sandcastle?

Code: Do you and other developers understand the codebase? Do you think you can reuse this class or that function? Can you rely on existing unit tests when you refactor the code for your feature?

Oh, on the topic of code, did you leave enough time for code reviews? I am sure you did, but let me remind you about the one time you had an intern on your team and review of her code took 4 times the usual effort and time (and to be fair, she was still learning conventions and best practices of your company).

What about documentation? And writing more unit tests? And at least a few integration tests? What about the time needed to merge code into the master branch? Did you think about previous backlogs which can affect your delivery?

Team Dynamics: Do you have purists on your team? While having them around is good, often it takes compromises to get things delivered. If some folks take a hard stance about how things should be done, conflict is imminent, and it takes time and energy to resolve that.

Another problem we will very often see is having developers with huge ego in the team resulting in a barrage of review comments in the code, with each side trying to prove his/her point with links to random best practices, policies, and documentation. Another similar problem with same consequences is having folks simply not liking each other, resulting in major friction in the team. All of it drains time into the gutter.

(Why can’t we simply work without emotions… you know… like machines… why do we need humans to write code? Why can’t AI do it? I am sure some VP or director in your company would be making such remarks…)

Reliance of other teams: Are some of your features dependent on other teams (for example, User Management team has to expose an API for finding the one true soulmate for a user)? If yes, do you have time commitments from them, and can rely on them to stick to their commitments? Let’s not forget they are also human and will run into similar problems which your team can run into. Result? Problems, compounded!

Existing Documentation: What a joke! Go figure out things on your own, you stupid, good for nothing devs. How were you even able to crack our “super hard interview which only hires self-motivated rockstars” and now claiming to not understand our product just by reading the code? It is all in the code, you moron. All the business decisions, all their repercussions, all the tech debts, all the design choices (which seemed obvious at that time), all the inheritance trees which promised super-high extensibility and reusability… it’s all in the code!

And, do it over the weekend. I know you are a rockstar!

Subject matter experts: No documents…no problem. There is always that one person in the team who has been around since the last 9 years and knows things in and out! Assuming his availability, knowledge, and interest in helping the project always seems like a good idea at first while estimating our delivery dates, but falls flat when we are stuck with some critical questions, drop him a meeting invite to discuss things further, and he never accepts (but also does not decline!) the invite. Well, we can always walk up to his desk to ask questions… until one day where he asks us to send a meeting invite to “discuss things further”. And we have a loop!

Processes: Let’s count

  1. Requirements sign-off
  2. System Design sign-off
  3. UX sign-off
  4. Senior/Staff Engineer sign-off (yup.. that is a thing)
  5. UAT sign-off
  6. Security sign-off
  7. Release sign-off

Can you think of a few more? I am sure you can.

Audits: How critical is your code and project? Does it directly impact customer traffic? Does it directly impact the revenue of the company? Get ready for some random audits with some random teams, and some random review sessions with the VP of the company who suddenly wants to understand what is going on now that he is back from playing golf!

Security and Pen-tests: Never, ever compromise on security and user data, period.

User Acceptance Testing a.k.a. The UAT: Ah, the famous UAT, a place where we find all the bugs and finally verify delivery against the real requirements before launching to production. Is it supposed to be 1 week UAT? I am sure that 1 week was allotted assuming it will not have that many bugs discovered, but you know, life is full of surprises.

Final Release: Hurray! We are finally here. But are we on time, and if not, is the delay within 20% of original time estimates? If yes, you have successfully mastered the art of estimation, and you too, my dear developer, can go on to do great things like Emma! May the force be with you! Go on now.. conquer the stars.

Then how do we even start with estimation?

Let’s get a little serious now. Bad estimations have real-world consequences. Missed deadlines mean losing customer trust, or even the customer’s business, and eventually leading to a loss in revenue. And god forbid if it was a compliance project which had a hard deadline (or else fine to be paid to authorities). Missing that would be bad.

Estimating is hard because there are many parameters and stages involved to complete the picture, and each of them has a human touch. Then, can we do better than putting random days against features but eventually missing the deadline? Let’s see.

  1. I want to start by pointing out that while estimates are calculated guesses, they are still guesses. Everyone needs to realize this and have plans if the delivery gets delayed. We should seriously avoid a race against time if missing a deadline has serious repercussions (like government compliance projects). It is best to start as early as possible in such cases to avoid the last-minute rush. If that does not seem possible, we should pick the “bare minimum” feature set and work towards delivering those.

  2. The strategy of working backward from deadline to derive the number of days never works unless we are ok with feature cuts and reprioritization before and even during execution. Taking a hard and an honest look at the feature list, prioritizing them ruthlessly, dividing them into stages of delivery (more on this later), and removing the ones which do not fall under the bucket of “bare minimum” feature set for the upcoming stage is probably a better approach.

  3. Similarly, when deadlines are tight, it is best to avoid using “that new shiny technology” and stick to what the team knows works best. I am not against looking at newer technologies and products if they promise to offer a significant saving in terms of cost and time, but in that case, having an expert review your assumptions and offer consultation whenever the team gets blocked on something in that new tech saves a lot of time.

  4. Deliver in stages. The smaller they are, the better. Reason being, it keeps things moving and offers us the luxury of re-working our strategy between stages, while at the same time enabling us to continuously ship features and keeping stakeholders relatively calm. (They will still shout, only a little less!)

  5. Work hard on gathering the requirements, clarifying them as much as possible, and freezing them for good. It should take an elephant (figuratively!) to change them once they are frozen, and if they change, proactively rework the dates and publish the new dates to all the stakeholders (but make no mistakes…they will still shout!). On the topic of talking to customers for gathering requirements, I am not suggesting that you should directly talk to customers if that’s not your job profile, but ensure sufficient rigor has gone in verifying the requirements and freeze them early in the development lifecycle.

  6. Work harder to create a list of potential blockers and last-minute surprises. Most delays stem from these devils which lie in the details. And so looking under layers to find those little devils is the key. And the sooner it is done (probably even before the first piece of code is written), the better.

  7. Have buffers for last-minute surprises and unknown unknowns. I am not saying to have huge buffers for a hypothetical case where half of the team quits mid-delivery (if that happens, we have a bigger problem), but definitely have buffers for things like unplanned leaves, new blockers (like trying to get dependencies to work together…oh the time sink ), design and code reviews, learning curve for legacy code and business processes, security audits and delays, UAT data preparation etc. Having right buffers should be a post in itself, but in short, one of the ways we can approach it while still keeping things simple is by coming up with the best-case and worst-case (but realistic) numbers, taking the worst-case numbers, increasing them by 20% it, and calling that an estimate. Why worst-case and 20% you ask? Sure, if you want it any other way, go ahead. But before that, take a look at historical data in your other projects, your org, and your company to understand the trend and then decide what should these be.

  8. While we are on the topic of buffers, do not forget to add extra buffers if you did not follow point 3, 4, 5, or 6 from this list. How much again you ask? For simplicity, for every point missed, add 20% (compounded!).

  9. Have experienced and proven managers drive projects which have tight deadlines. This one may come out as a bit controversial, but if the stakes are high, it is best to let the experts be the driver. Others are free to learn and drive non-critical projects until they gain significant experience and prove themselves before they take on high-risk deliveries.

  10. Be OK with some tech debt as long as the return is worth the gains. Have the tech debts stored in backlog for someone to pick them in future (in like year 3019!), and avoid the temptation to deliver system which is truly perfect (like there will be no iteration or change in requirements), extremely-reusable and extensible (like it is the only thing you will ever need to build), and scalable beyond imagination (like it will auto-scale to 1 billion TPS automatically while still staying within reasonable cost). Point being, be pragmatic with your expectations and approach. A successful delivery this month is better than a perfect delivery after 1 year.

  11. Be aggressive in curtailing and cutting your losses. Do you have that one developer seriously slacking off and being a burden on others? Or a program manager who is not able to push back on scope creeps? Or an engineering manager not being able to act like an owner, or acting as a lamp-post with a fused bulb with zero understanding of business or engineering? Or a person being too toxic and spreading negativity in the team? Or folks fighting with their petty ego? Ask yourself, Is this pattern repeating? Time for some tough talk, and if the situation is unsalvageable, for some hard actions.

  12. But whatever you do, be a good person. Folks will have a bad day or a bad week. Someone will find the technical stack too daunting or business workflows too confusing. It’s ok. We are all in this together. Improving and maintaining the team’s culture and your character should be one of the most important things, IMHO. Best case, you will slip up on the deadline. Worst case, the product will fail to ship, and the company will fold. But remember, time moves on, and so do people. With good probability, you guys will meet again, work together again in another time, project or company, or will need each other to refer to new positions in another company. Be professional, and do not be rude or demeaning to each other for the sake of this project. Be a good human!