Your application or software has recently crossed that magic number of sticky users which validates its usefulness. It is loved by your users not only for what it does but how easy it is becoming every passing day to work with. They see no reason to leave, impressed with how quickly your app (software) is evolving adding new, essential features with every update.
The team executed a solid feature build journey so far and the future pipeline looks even more impressive. As the founder/technical head of the app you can visualise hitting the next milestone on users sooner than the plan, keeping churn non-existent and velocity on new features higher than before! You and the entire team get the feeling,
Something strange then starts to happen midway this growth plan. Customer complaints begins to spike; broken functionality, non-performance, unexpected stoppages, feature bugs and much more. The support team is in overdrive whereas the Dev team is forced to spend more time fixing bugs over building new features. What went wrong? Why this sudden reversal in app performance? Did you discount or overlook something critically important about the app (software) health when planning for user growth?
5 reasons this happened and would continue to happen, sans relief, for the longest of times:
Your team believed in building fast, breaking things faster so far but this strategy begins to backfire at scale. Smaller size meant lesser usage still lesser failures. The version 1 to 5 of your product app was released in no time because everything worked when not every function, feature was used when you were small. This changes dramatically, as expected, with more users not without consequences.
More failures and bugs are reported from the ground not because they were not there in the first place, but because your app has started to be used more intensively. Slowing down the pace of new development is not the option but hastily releasing new buggy features on existing ones just compounds users’ misery faster.
Quality is an afterthought for most teams. Worse is when young companies feel worrying too much about quality will distract them from growing fast in early stages. They soon figure that there is no good time to be ready until it is too late!
Growth is often seen as external validation to no-holds barred development. Most believe when the product is young, peer-review is a more than good substitute to a formal QA process. Unscalable right from start, this strategy begins to backfire when things begin to fail dramatically in later versions of the app or software.
The tenth version of your app will have 1000+ features but needs legacy care for 999 previous ones. 100+ services that power these 1000+ features, talk to each other. Soon intra-service (and 3rd party) interactions become complicated leading to failures not just hard to spot but harder to debug.
Need for speed keeps focus only on new development not on refactoring old clunky code. People in dev teams change or leave over time exacerbating technical understanding of the code-base, feature-sets and the interactions that power them. Technical debt can alone contribute 50% of all failures your app after a stage which soon becomes impossible to undo!
Maybe you have a QA process in place. The Dev team writes unit tests for defence but writing good tests takes more time than writing code. Also, the scope of unit tests does not address the aggregate behaviour of your app composed of multiple code segments.
Maybe you tried application testing using open source tools like Selenium, Cypress with your QA team. Tests were hard to write and maintain. Both teams also have a tough time keeping up with each other. QA team would wait for Dev team to finish a part of product, then test it and report bugs. By that time Devs would already be on the next phase leaving no time to fix the reported errors or work on new features. This cycle can make development unpredictable and failure in spotting bugs before new versions go-live.
Releasing fast and packing as many features as possible together comes at a cost. New functionality breaks not just because it is inadequately tested but also when it goes to users inside a bundle of dozen others. Each new feature as explained in the previous point adds uniquely to growing technical debt.
When staggered over several releases, features can be tested or re-tested with control but when released in a heap, the overall release has the potential to introduce ghost bugs that break the app but are impossible to debug. Ghost Bugs introduce breaking behaviour in the app impossible to reproduce for your QA or Devs and hence impossible to fix!