The law of diminishing returns
If you have worked on a mature product, you have probably seen this: the team is twice the size it was two years ago, and it ships less than it used to. That is not necessarily mismanagement. It is economics.
The law of diminishing returns states that as you keep investing in a production process, the rate of return on those investments starts to fall past a certain point, assuming every other variable stays constant.
This principle holds perfectly for software product development, and it may be even more true here than in other types of production processes. Yet we tend to forget about it and assume that allocating more resources to a mature project will increase output at the same rate it did at the beginning 😢.
Why does this happen?
Mainly because three things grow over time:
- Support and maintenance workload.
- Building difficulty.
- Customers’ expectations and demands.
Let’s go one by one 👇🏼
Support and maintenance workload
When a new product starts out, there are no user tickets to answer, no bugs to fix, and no integrations to maintain. But if the project is successful enough, it will acquire users and expand in features.
Those users will use the product in ways its creators didn’t anticipate, and they will find errors you have to fix. They will also request more features, and every feature adds complexity, which increases the chances of bugs and usability problems, which leads to more tickets…
Meanwhile, your codebase keeps growing: more integrations, more dependencies. And code is not static. Libraries get deprecated, external APIs get updated, and keeping up with all of it eats more of your precious time.
Support and maintenance workload grows exponentially, much faster than the product itself.
Building difficulty
Another thing that grows exponentially is the complexity of your code, which makes it harder to build on top of it.
Imagine a digital product as a house. It starts with a kitchen and two rooms, but it grows fast: more rooms, more pipes, more doors. The house turns into a skyscraper, full of internal and external dependencies. Real skyscrapers, though, don’t change much once they are built. Software does. Imagine saying, “hey, I need you to remove half of floor #81”, or “I want the entrance door on the other side, and a new elevator there”. It’s hard. You would have to re-route pipes and cables, and strengthen beams and other structures.
To make it worse, the people who built the software in the first place are probably no longer working with you. Whoever takes over has to learn how the code works first, and that takes time.
Customers’ expectations and demands
When a product launches, it usually feels exotic… new. What it does is innovative and impressive. Remember the first time you used Instagram, or ran a Google search? But with time and repeated use, what was awesome becomes normal, then expected, then boring. Users climb the expectations ladder, always wanting shinier things.
CRM systems are a good example. They started as a customer database to track contacts and deals, but today that is taken for granted, and many people won’t even pay for something that basic. Customers now expect much more from their CRM: ticketing, customer segmentation, email automation, email analytics, marketing automation, and so on.
What can you do about it?
In the long run, not much… That is why the products that stick around are the ones that make good money. They have the resources to keep investing even at worse return rates.
That does not mean there is nothing you can (or should) do to maximize your returns over time. Some things that help:
- Retain your team. This slows the leak of knowledge, and with it the loss of productivity.
- Document your code. A bit of documentation goes a long way when you have to change code written by somebody else, or by your older self.
- Document your features. Documented features cut down the time spent answering user questions.
- Build a tech-savvy Customer Service team that can solve as many issues as possible without depending on the development team.
- Use modular architectures. Keep things loosely coupled, so each “block” is agnostic and autonomous. This reduces the impact a change in one place has on everything else, which speeds up development.
- Keep integrations to a minimum. Every integration has to be maintained and updated. You do need them, so choose them carefully.
- Write as little code as possible. The last one, and the most important. Less code means fewer bugs, less time explaining and documenting, less to maintain, easier development, shorter deploy times. In general, a software product is better off with a few robust features than with a bunch of mediocre ones.
This is why product managers are always challenging ideas for new features. An essential part of our job is to care for the product as a whole, and over the long term. Where others see “just a simple feature, it won’t take much time”, PMs see one more thing to carry in an already heavy bag, one more thing that will slow us down.
None of this stops the curve from bending. It just keeps you on the left side of it for longer, which is the whole game.
Final idea: shoot with a sniper, not with a machine gun.