{"id":56,"date":"2024-06-26T17:50:05","date_gmt":"2024-06-26T17:50:05","guid":{"rendered":"https:\/\/twobitranch.io\/?p=56"},"modified":"2026-09-11T14:06:08","modified_gmt":"2026-09-11T14:06:08","slug":"over-promise-and-under-deliver","status":"publish","type":"post","link":"https:\/\/twobitranch.io\/index.php\/2024\/06\/26\/over-promise-and-under-deliver\/","title":{"rendered":"Over promise and under deliver"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">There are two kinds of developers.<\/h2>\n\n\n\n<p>The first kind says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Yeah, I can probably get that done by Friday.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>The second kind says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Absolutely. No problem. I&#8217;ll have it done by tomorrow.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>The first developer has learned from experience.<\/p>\n\n\n\n<p>The second developer has just joined the meeting.<\/p>\n\n\n\n<p>In software development, <strong>over-promising and under-delivering<\/strong> is practically a design pattern.<\/p>\n\n\n\n<p>We don&#8217;t put it in our architecture diagrams, but it&#8217;s there.<\/p>\n\n\n\n<p>Usually somewhere between the API layer and the database.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">It Started With a Simple Requirement<\/h2>\n\n\n\n<p>Every software disaster begins with someone saying:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;It&#8217;s a pretty small change.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>There is no such thing as a small change.<\/p>\n\n\n\n<p>There is only a change whose complexity we haven&#8217;t discovered yet.<\/p>\n\n\n\n<p>&#8220;Just add a button.&#8221;<\/p>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>The button needs to:<\/p>\n\n\n\n<ul>\n<li>Call an API.<\/li>\n\n\n\n<li>Validate permissions.<\/li>\n\n\n\n<li>Check business rules.<\/li>\n\n\n\n<li>Update three tables.<\/li>\n\n\n\n<li>Send an email.<\/li>\n\n\n\n<li>Publish an event.<\/li>\n\n\n\n<li>Update the audit log.<\/li>\n\n\n\n<li>Work on mobile.<\/li>\n\n\n\n<li>Work in Internet Explorer.<\/li>\n<\/ul>\n\n\n\n<p>Okay, maybe not Internet Explorer.<\/p>\n\n\n\n<p>But give it time.<\/p>\n\n\n\n<p>The developer looks at the ticket.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Yeah, probably a day.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>This is the first promise.<\/p>\n\n\n\n<p>The universe has now started a stopwatch.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The .NET Developer&#8217;s Optimism<\/h2>\n\n\n\n<p>.NET developers have a particularly dangerous form of optimism.<\/p>\n\n\n\n<p>We look at a requirement and think:<code>public async Task DoTheThingAsync() { \/\/ TODO: Implement }<\/code><\/p>\n\n\n\n<p>We know exactly how to make an API endpoint.<code>[HttpPost] public async Task&lt;IActionResult&gt; DoTheThing() { return Ok(); }<\/code><\/p>\n\n\n\n<p>Five minutes later, we feel unstoppable.<\/p>\n\n\n\n<p>The endpoint exists.<\/p>\n\n\n\n<p>The compiler is happy.<\/p>\n\n\n\n<p>Visual Studio has no red squiggly lines.<\/p>\n\n\n\n<p>The developer thinks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;This is basically done.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>This is how it begins.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Then Reality Arrives<\/h2>\n\n\n\n<p>The first problem is authentication.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except the endpoint needs a different permission.<\/p>\n\n\n\n<p>Then authorization.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except the permission system hasn&#8217;t been touched since 2018.<\/p>\n\n\n\n<p>Then validation.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except the business rules are documented in a Word document called:<code>Final_Final_Requirements_v7_REALLY_FINAL.docx<\/code><\/p>\n\n\n\n<p>Then the database.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except the stored procedure has 2,700 lines.<\/p>\n\n\n\n<p>Then testing.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except nobody knows how the existing integration tests work.<\/p>\n\n\n\n<p>Then deployment.<\/p>\n\n\n\n<p>Easy.<\/p>\n\n\n\n<p>Except production has a configuration setting that doesn&#8217;t exist locally.<\/p>\n\n\n\n<p>Suddenly:<code>1 day estimate \u2193 3 days \u2193 1 week \u2193 \"We're almost there\" \u2193 \"Just fixing a few things\" \u2193 \"Can we move the deadline?\"<\/code><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">&#8220;It&#8217;s Only a Small API&#8221;<\/h2>\n\n\n\n<p>This phrase has caused more suffering than most production outages.<\/p>\n\n\n\n<p>Someone asks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can you add an endpoint that returns customer orders?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>You think:<code>[HttpGet(\"{customerId}\/orders\")] public async Task&lt;IActionResult&gt; GetOrders(int customerId) { return Ok(await _orderService.GetAsync(customerId)); }<\/code><\/p>\n\n\n\n<p>Simple.<\/p>\n\n\n\n<p>Then someone asks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we filter by date?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we filter by status?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we sort it?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we paginate it?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we export it to Excel?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can the response be backwards compatible with the old endpoint?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Sure.<\/p>\n\n\n\n<p>Then:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we make it real-time?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>At this point, the original endpoint has become a distributed systems problem.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Meeting Estimate<\/h2>\n\n\n\n<p>There is a strange ritual in software development.<\/p>\n\n\n\n<p>Someone describes a feature.<\/p>\n\n\n\n<p>Everyone looks at you.<\/p>\n\n\n\n<p>You are expected to produce a number.<\/p>\n\n\n\n<p>Immediately.<\/p>\n\n\n\n<p>You have never seen the code.<\/p>\n\n\n\n<p>You don&#8217;t know the database.<\/p>\n\n\n\n<p>You don&#8217;t know the deployment process.<\/p>\n\n\n\n<p>You don&#8217;t know the dependencies.<\/p>\n\n\n\n<p>You don&#8217;t know whether the original developer is still with the company.<\/p>\n\n\n\n<p>But someone asks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;How long?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>So you say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Two days.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Why?<\/p>\n\n\n\n<p>Because saying:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I need to investigate the existing architecture, identify dependencies, understand the requirements, validate the data model, and then provide an estimate&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>doesn&#8217;t sound as productive.<\/p>\n\n\n\n<p>So you say two days.<\/p>\n\n\n\n<p>This is how software estimates are born.<\/p>\n\n\n\n<p>Not from engineering.<\/p>\n\n\n\n<p>From social pressure.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Estimate Multiplier<\/h2>\n\n\n\n<p>Experienced developers eventually develop a secret formula.<\/p>\n\n\n\n<p>Someone says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;How long will this take?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Developer thinks:<code>Actual time \u00d7 3<\/code><\/p>\n\n\n\n<p>Manager hears:<code>2 days<\/code><\/p>\n\n\n\n<p>Developer says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Probably about a week.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Manager hears:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Two days.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Developer goes back to their desk.<\/p>\n\n\n\n<p>The manager tells the product owner:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;We&#8217;ll have it by Wednesday.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>The product owner tells the customer:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Definitely this week.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>The customer tells their customers:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;You&#8217;ll have it Friday.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Friday arrives.<\/p>\n\n\n\n<p>Nobody has it.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">&#8220;But You Said It Would Be Done&#8221;<\/h2>\n\n\n\n<p>Yes.<\/p>\n\n\n\n<p>I also once said I&#8217;d understand Kubernetes.<\/p>\n\n\n\n<p>We all make mistakes.<\/p>\n\n\n\n<p>The problem isn&#8217;t estimating incorrectly.<\/p>\n\n\n\n<p>The problem is pretending that uncertainty doesn&#8217;t exist.<\/p>\n\n\n\n<p>Software contains uncertainty everywhere.<\/p>\n\n\n\n<p>We don&#8217;t know:<\/p>\n\n\n\n<ul>\n<li>What we&#8217;ll discover in the existing code.<\/li>\n\n\n\n<li>What requirements will change.<\/li>\n\n\n\n<li>What bugs we&#8217;ll uncover.<\/li>\n\n\n\n<li>What external dependencies will break.<\/li>\n\n\n\n<li>What production configuration differs from development.<\/li>\n\n\n\n<li>What the database will do under real traffic.<\/li>\n\n\n\n<li>What security requirements someone forgot to mention.<\/li>\n<\/ul>\n\n\n\n<p>Yet we frequently give estimates as though we&#8217;re manufacturing identical screws in a factory.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Developer Who Says &#8220;No Problem&#8221;<\/h2>\n\n\n\n<p>Be suspicious of the phrase:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;No problem.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Especially when it&#8217;s said immediately.<\/p>\n\n\n\n<p>Experienced developers tend to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;It depends.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>This sounds less impressive.<\/p>\n\n\n\n<p>But &#8220;it depends&#8221; is often the beginning of an honest engineering conversation.<\/p>\n\n\n\n<p>For example:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we add this feature by Friday?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>A responsible answer might be:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Probably, assuming the existing API supports it and we don&#8217;t need database changes. I&#8217;d like to spend a few hours investigating before committing.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>A dangerous answer is:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Absolutely.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Because &#8220;absolutely&#8221; is just a future apology wearing a confident hat.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Async\/Await Has Given Us False Confidence<\/h2>\n\n\n\n<p>.NET developers have another problem.<\/p>\n\n\n\n<p>We can make almost anything look simple with:<code>await SomethingAsync();<\/code><\/p>\n\n\n\n<p>Look at that.<\/p>\n\n\n\n<p>Beautiful.<\/p>\n\n\n\n<p>Asynchronous.<\/p>\n\n\n\n<p>Modern.<\/p>\n\n\n\n<p>Efficient.<\/p>\n\n\n\n<p>We have no idea what <code>SomethingAsync()<\/code> actually does.<\/p>\n\n\n\n<p>It could be:<code>await SomethingAsync() \u2193 HTTP request \u2193 Retry policy \u2193 OAuth token refresh \u2193 Third-party API \u2193 Database query \u2193 Stored procedure \u2193 Linked server \u2193 Another database<\/code><\/p>\n\n\n\n<p>But our code says:<code>await SomethingAsync();<\/code><\/p>\n\n\n\n<p>So obviously it&#8217;ll take approximately 14 milliseconds.<\/p>\n\n\n\n<p>Right?<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Magic of Dependency Injection<\/h2>\n\n\n\n<p>Dependency injection makes everything look beautifully organized.<code>public OrderService( IOrderRepository repository, IPaymentService paymentService, IEmailSender emailSender, IAuditService auditService, ILogger&lt;OrderService&gt; logger) { }<\/code><\/p>\n\n\n\n<p>Look at that constructor.<\/p>\n\n\n\n<p>So clean.<\/p>\n\n\n\n<p>So maintainable.<\/p>\n\n\n\n<p>So enterprise.<\/p>\n\n\n\n<p>The developer confidently says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;The architecture is flexible.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Then they try to run the application.<code>Unable to resolve service for type 'IPaymentService' while attempting to activate 'OrderService'.<\/code><\/p>\n\n\n\n<p>Ah.<\/p>\n\n\n\n<p>The abstraction is working beautifully.<\/p>\n\n\n\n<p>Nothing has been delivered.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Sprint Commitment<\/h2>\n\n\n\n<p>Sprint planning is where optimism reaches its highest level.<\/p>\n\n\n\n<p>The team looks at 40 tickets.<\/p>\n\n\n\n<p>Someone asks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Can we get all of these done?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Developer:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;If nothing unexpected happens.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Product owner:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Great!&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Developer:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;That&#8217;s not what I\u2014&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Too late.<\/p>\n\n\n\n<p>It&#8217;s committed.<\/p>\n\n\n\n<p>Then someone takes vacation.<\/p>\n\n\n\n<p>Someone else gets pulled into production support.<\/p>\n\n\n\n<p>The CI pipeline breaks.<\/p>\n\n\n\n<p>A security vulnerability appears.<\/p>\n\n\n\n<p>The database migration fails.<\/p>\n\n\n\n<p>The product owner changes the requirement.<\/p>\n\n\n\n<p>And somehow the sprint is still considered unsuccessful because:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;The team didn&#8217;t complete the committed work.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Yes.<\/p>\n\n\n\n<p>Because apparently the sprint was planned in a universe where software behaves predictably.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Under-Deliver Part<\/h2>\n\n\n\n<p>Over-promising is only half the problem.<\/p>\n\n\n\n<p>The other half is what happens when we realize we can&#8217;t deliver.<\/p>\n\n\n\n<p>There are two approaches.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Approach One<\/h3>\n\n\n\n<p>Disappear into the codebase.<\/p>\n\n\n\n<p>Stop replying to messages.<\/p>\n\n\n\n<p>Change your Slack status to:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Deep work.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>This means:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I have no idea what&#8217;s happening.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">Approach Two<\/h3>\n\n\n\n<p>Communicate early.<\/p>\n\n\n\n<p>Say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I underestimated this. I found three dependencies that weren&#8217;t apparent initially. The original estimate is no longer realistic. Here&#8217;s what I can deliver by Friday, and here&#8217;s what needs additional time.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Approach Two is significantly less exciting.<\/p>\n\n\n\n<p>It is also considerably more professional.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The &#8220;Almost Done&#8221; Lie<\/h2>\n\n\n\n<p>Nothing in software is more dangerous than:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;It&#8217;s almost done.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Almost done can mean anything.<\/p>\n\n\n\n<p>It can mean:<code>Code complete<\/code><\/p>\n\n\n\n<p>Or:<code>Code complete Tests missing<\/code><\/p>\n\n\n\n<p>Or:<code>Works locally<\/code><\/p>\n\n\n\n<p>Or:<code>Works with my test data<\/code><\/p>\n\n\n\n<p>Or:<code>Works if you don't click that button<\/code><\/p>\n\n\n\n<p>Or:<code>Production deployment hasn't been attempted yet<\/code><\/p>\n\n\n\n<p>In reality, &#8220;done&#8221; should mean something closer to:<code>Implemented + Tested + Reviewed + Integrated + Deployable + Documented where necessary + Accepted<\/code><\/p>\n\n\n\n<p>Unfortunately, &#8220;almost done&#8221; sounds much better in a status meeting.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The .NET Build Is Green, So We&#8217;re Done<\/h2>\n\n\n\n<p>We&#8217;ve all experienced this.<\/p>\n\n\n\n<p>The build succeeds.<code>Build succeeded. 0 Error(s) 0 Warning(s)<\/code><\/p>\n\n\n\n<p>Beautiful.<\/p>\n\n\n\n<p>You deploy.<\/p>\n\n\n\n<p>Production immediately throws:<code>InvalidOperationException<\/code><\/p>\n\n\n\n<p>Because the build was successful.<\/p>\n\n\n\n<p>It never promised the application would work.<\/p>\n\n\n\n<p>It merely confirmed that the compiler had no objections.<\/p>\n\n\n\n<p>This is an important distinction in software engineering:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p><strong>Compilation is not correctness.<\/strong><\/p>\n<\/blockquote>\n\n\n\n<p>A green build is not a green production environment.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Technical Debt Loves Optimistic Developers<\/h2>\n\n\n\n<p>Every time we say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;We&#8217;ll fix it properly later.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>technical debt quietly opens another account.<code>TODO: Refactor this<\/code><\/p>\n\n\n\n<p>Six months later:<code>TODO: Refactor this<\/code><\/p>\n\n\n\n<p>Two years later:<code>TODO: Refactor this<\/code><\/p>\n\n\n\n<p>The developer who wrote it has left.<\/p>\n\n\n\n<p>The new developer asks:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Why is this like this?&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Someone answers:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Legacy.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Legacy is often what we call our own decisions after we forget why we made them.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">How to Stop Over-Promising<\/h2>\n\n\n\n<p>The solution isn&#8217;t to become the developer who always says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;No.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>The solution is to become the developer who understands uncertainty.<\/p>\n\n\n\n<p>Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I&#8217;ll have it done Friday.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Try:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I expect to have it done Friday, assuming there aren&#8217;t significant changes to the existing implementation.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;That&#8217;s easy.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Try:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;The change looks straightforward, but I haven&#8217;t investigated the existing code yet.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Instead of:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Two days.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Try:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I estimate one to three days. I&#8217;ll know more after I investigate the database and existing API.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>This isn&#8217;t weakness.<\/p>\n\n\n\n<p>It&#8217;s engineering.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Give Estimates as Ranges<\/h2>\n\n\n\n<p>Software estimates often become more useful when expressed as ranges.<\/p>\n\n\n\n<p>Instead of:<code>3 days<\/code><\/p>\n\n\n\n<p>say:<code>2\u20134 days<\/code><\/p>\n\n\n\n<p>And explain what drives the uncertainty.<\/p>\n\n\n\n<p>For example:<code>2 days: Implementation is straightforward. 4 days: Existing database logic requires changes or additional testing.<\/code><\/p>\n\n\n\n<p>Now the estimate communicates information.<\/p>\n\n\n\n<p>The number isn&#8217;t pretending to be a prophecy.<\/p>\n\n\n\n<p>It&#8217;s describing uncertainty.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Under-Promise and Over-Deliver?<\/h2>\n\n\n\n<p>You&#8217;ve probably heard this advice:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Under-promise and over-deliver.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>It sounds great.<\/p>\n\n\n\n<p>But there is a problem.<\/p>\n\n\n\n<p>If you consistently under-promise, you can also become the person who says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;This will take three weeks.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>and delivers it in two days.<\/p>\n\n\n\n<p>Eventually management learns:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Their three-week estimates really mean two days.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Congratulations.<\/p>\n\n\n\n<p>You have created another estimation problem.<\/p>\n\n\n\n<p>The goal isn&#8217;t to manipulate expectations.<\/p>\n\n\n\n<p>The goal is <strong>accurate expectations<\/strong>.<\/p>\n\n\n\n<p>Don&#8217;t under-promise.<\/p>\n\n\n\n<p>Don&#8217;t over-promise.<\/p>\n\n\n\n<p><strong>Communicate honestly about what you know and what you don&#8217;t know.<\/strong><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">The Most Valuable Developer in the Room<\/h2>\n\n\n\n<p>The most valuable developer isn&#8217;t necessarily the one who says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I can build that.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>It&#8217;s often the developer who says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Before we commit to that date, there are a few things we should investigate.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>That&#8217;s not being difficult.<\/p>\n\n\n\n<p>That&#8217;s preventing future disappointment.<\/p>\n\n\n\n<p>They ask:<\/p>\n\n\n\n<ul>\n<li>What does the existing system do?<\/li>\n\n\n\n<li>What dependencies are involved?<\/li>\n\n\n\n<li>What are the unknowns?<\/li>\n\n\n\n<li>What can we deliver incrementally?<\/li>\n\n\n\n<li>What could make the estimate wrong?<\/li>\n\n\n\n<li>What is the minimum useful version?<\/li>\n\n\n\n<li>What needs to be tested?<\/li>\n\n\n\n<li>What happens when something fails?<\/li>\n<\/ul>\n\n\n\n<p>Those questions may slow down the meeting.<\/p>\n\n\n\n<p>They can also prevent a month of misery.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Software Doesn&#8217;t Care About Your Deadline<\/h2>\n\n\n\n<p>This may be the hardest lesson.<\/p>\n\n\n\n<p>You can put:<code>Friday 5:00 PM<\/code><\/p>\n\n\n\n<p>on a project plan.<\/p>\n\n\n\n<p>The database doesn&#8217;t care.<\/p>\n\n\n\n<p>The compiler doesn&#8217;t care.<\/p>\n\n\n\n<p>The external API doesn&#8217;t care.<\/p>\n\n\n\n<p>The production environment definitely doesn&#8217;t care.<\/p>\n\n\n\n<p>Reality wins.<\/p>\n\n\n\n<p>The only thing we control is how honestly we communicate with the people depending on us.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Final Thoughts<\/h2>\n\n\n\n<p>Over-promising usually doesn&#8217;t start with dishonesty.<\/p>\n\n\n\n<p>It starts with optimism.<\/p>\n\n\n\n<p>We want to help.<\/p>\n\n\n\n<p>We want to look capable.<\/p>\n\n\n\n<p>We don&#8217;t want to disappoint people.<\/p>\n\n\n\n<p>We don&#8217;t want to be the developer who says:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I don&#8217;t know.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>So we say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;Sure.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Then we discover that the &#8220;simple change&#8221; requires modifying an API, three services, two stored procedures, a database migration, an authentication policy, a background worker, and a configuration setting that only exists in production.<\/p>\n\n\n\n<p>Suddenly Friday looks very far away.<\/p>\n\n\n\n<p>The answer isn&#8217;t pessimism.<\/p>\n\n\n\n<p>It&#8217;s professionalism.<\/p>\n\n\n\n<p>It&#8217;s okay to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I don&#8217;t know yet.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>It&#8217;s okay to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;I need to investigate.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>It&#8217;s okay to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;That estimate has changed.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>It&#8217;s okay to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;We can deliver part of it by Friday, but the complete feature will take longer.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>And yes, it&#8217;s even okay to say:<\/p>\n\n\n\n<blockquote class=\"wp-block-quote\">\n<p>&#8220;This is more complicated than we originally thought.&#8221;<\/p>\n<\/blockquote>\n\n\n\n<p>Because the goal of software development isn&#8217;t to make impressive promises.<\/p>\n\n\n\n<p>It&#8217;s to build software that actually works.<\/p>\n\n\n\n<p>Preferably before the customer starts asking where it is.<\/p>\n\n\n\n<p>And preferably without discovering that the entire feature depends on a 4,000-line stored procedure named:<code>usp_GetFinalFinalCustomerData_NEW2<\/code><\/p>\n\n\n\n<p><strong>Promise what you reasonably believe you can deliver.<\/strong><\/p>\n\n\n\n<p><strong>Communicate when reality changes.<\/strong><\/p>\n\n\n\n<p><strong>And never trust a requirement that begins with, &#8220;It should only take five minutes.&#8221;<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are two kinds of developers. The first kind says: &#8220;Yeah, I can probably get that done by Friday.&#8221; The second kind says: &#8220;Absolutely. No problem. I&#8217;ll have it done by tomorrow.&#8221; The first developer has learned from experience. The second developer has just joined the meeting. In software development, over-promising and under-delivering is practically&hellip;&nbsp;<a href=\"https:\/\/twobitranch.io\/index.php\/2024\/06\/26\/over-promise-and-under-deliver\/\" class=\"\" rel=\"bookmark\">Read More &raquo;<span class=\"screen-reader-text\">Over promise and under deliver<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/posts\/56"}],"collection":[{"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/comments?post=56"}],"version-history":[{"count":2,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions"}],"predecessor-version":[{"id":67,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/posts\/56\/revisions\/67"}],"wp:attachment":[{"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/media?parent=56"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/categories?post=56"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/twobitranch.io\/index.php\/wp-json\/wp\/v2\/tags?post=56"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}