The client looked at the new quote โ€” 30 days โ€” and for about three seconds he was happy. Then his face went red, and he said: "So the first quote was stuffed. You were adding things to get paid more."

The first quote had said four to five months. The new one was for the same app, as far as he could tell. Same screens, same map. So what had I been charging him for?

Everything he couldn't see. That's what this post is about โ€” the half of custom software development that never shows up in a demo, and why it's usually the half that pays for itself.

What "small" looked like from my side

A local company came to me with what they called a tiny project. A mobile app that syncs some files, and a website that displays some data. In the client's head, that's a few weeks of work.

So we sat together and I walked him through what "syncs some files" actually means. The app has to send data periodically, from phones with bad signal, and when a send fails โ€” it will fail โ€” there has to be a retry protocol. You can't just loop the upload and call it done. On the other side there's an API that receives the data, validates it, and stores it in a database.

Then it gets bigger. The system is multi-tenant, so every record has to be tagged to the right company, and one tenant must never see another tenant's data. The data has to show on a map, accurately. There's export functionality. There are admin pages to manage tenants, and controllers for subscriptions and packages.

And on top of all of it: proper logging, documentation, a way to update every user smoothly, data security, unit tests and end-to-end tests.

He listened to all of it, and then said the sentence every developer has heard: "You know what? Give me the bare bones. I don't want any of this."

So I did. The admin pages went โ€” managing tenants now means someone typing commands on a server. Auto-updates went. Sync retries went. Most of the rest of that list went with them. Four to five months became roughly 30 days.

And that's when he decided the first number had been a scam.

The features nobody asks for

Here's the thing. Clients rarely ask for any of this โ€” not because they don't know it exists, but because they don't think it matters. It isn't on the screen, so it doesn't feel like part of the product. Every one of these items matters on a specific day, though. Here's what that day looks like for each one.

Logging

A user calls and says the app "just stopped working." With logging, you open the logs and see exactly what failed, when, and why. Without it, you're a detective with no crime scene. You ask the user to try again, it works, and everyone moves on until it happens again next week.

Crash reports

Most crashes are never reported. The user closes the app, opens it again, and quietly decides your software is unreliable. Crash reporting means you hear about the problem before your client's customers complain to your client. Honestly, it's the cheapest reputation insurance in software.

Sync retries

A field worker uploads a day's data from a basement with one bar of signal. The upload fails. With a retry protocol, the app tries again later, and nobody ever knows there was a problem. Without it, that data is simply gone โ€” and the first person to notice is usually the manager looking at an empty map.

Auto-updates

You find a bug, fix it in an hour, and now you have to get the fix onto every phone. With auto-updates, it goes out that afternoon. Without them, you're sending messages asking fifty people to please update, and three weeks later half of them are still on the broken version. Now you're supporting two versions of the same app.

Admin tools

A new tenant signs up. With an admin page, someone at the client's office adds them in two minutes. With a command line, they call the developer. Every time. For as long as the system lives.

Tests โ€” unit and end-to-end

Tests are what let you change the system next year without breaking what works today. Without them, every new feature is a gamble, and every fix risks a new bug somewhere nobody thought to check. The system gets slower and more expensive to change, one release at a time.

The compounding effect None of these costs show up on day one. They show up on day ninety, and then again every week after that. The bare-bones version isn't cheaper. The bill arrives later, spread across many small invoices, a lot of lost hours and one user who stopped trusting the app.

You have the source code. You still don't know what happened.

Some clients are more careful. They ask for full documentation and the source code, and they feel covered. They own everything, so they can always get someone to fix it.

Now picture the app crashing on a user's phone. The user describes the incident โ€” incorrectly, because users always describe incidents incorrectly. "I pressed save and it deleted everything." What actually happened is the sync failed an hour earlier and nothing was ever saved. The source code can't tell you that. The documentation can't tell you that. It's the one thing neither of them contains: what happened, on that phone, last Tuesday at 4pm.

Logs can tell you that. The source code tells you how the system should behave. The logs tell you how it actually behaved.

Documentation tells you how the system was built. Logs tell you what it did.

The same goes for distributing a new feature. Owning the code doesn't get that feature onto a hundred phones. An update mechanism does.

Bare bones is not an MVP

Now the honest aside, because I don't want this to read like "always buy the full package." I've written before that you should build the MVP first, and I still mean it. Most products should launch smaller than their owners want.

But an MVP cuts features. It doesn't cut foundations. You can launch without the export button, without the fancy dashboard, without the third subscription package. That's fine. What you shouldn't launch without is the ability to know when it breaks, fix it, and get the fix to your users.

There are genuine cases for bare bones. If you're building a demo for investors, or testing whether anyone wants the thing at all, strip it down โ€” just call it a prototype and plan to rebuild it. The problem starts when a prototype gets real users and real data, and everyone keeps treating it like a product.

And to be fair to my client, some of this is on us developers. If a quote says "mobile app: X weeks" and never names the logging, the retries and the tests as separate lines, the client has no way to see what he's paying for. The invisible half should be visible โ€” at least on paper.

He signed

He signed the 30-day version. That's his call to make, and I'll build exactly what he paid for, properly.

I'm not writing this to prove him wrong. I'm writing it because he'll probably be back โ€” the first time a user says the app lost their data, and nobody can tell him why. When that day comes, the conversation won't be about padding anymore. It'll be about what it costs to add the foundations to a building that's already standing. That's always more than laying them first.

๐Ÿ’ก
First step: Before you cut anything from a software quote, ask the developer three questions. "When a user reports a problem, how will we find out what happened?" "When you fix a bug, how does the fix reach every user?" "When something fails in the background, what happens to the data?" If the answer to any of them is "it won't," you're not cutting fat. You're cutting the foundations.