Skip to main content
added 455 characters in body
Source Link
Ben Cottrell
  • 12.1k
  • 4
  • 33
  • 44

Even if the original developers delivered bug-ridden code as part of MVP and some of the tests were bad or wrong, automated test coverage establishes a baseline for quality (just as is the case for static code analysis tools), so it also assures that quality can only get better even if the baseline wasn't so great to start with; the fact that it can only go in a positive direction means avoiding code-entropy and gives the code a maintainable future.

Even if the original developers delivered bug-ridden code as part of MVP and some of the tests were bad or wrong, automated test coverage establishes a baseline for quality (just as is the case for static code analysis tools), so it also assures that quality can only get better even if the baseline wasn't so great to start with; the fact that it can only go in a positive direction means avoiding code-entropy and gives the code a maintainable future.

Source Link
Ben Cottrell
  • 12.1k
  • 4
  • 33
  • 44

The cost of writing software

Consider any new 'green field' project which starts from a clean slate; chances are that its developers probably had to produce MVP within a sensible timeframe (Perhaps a year or maybe two at most); many projects often start out with just one small (e.g. "two-pizza") team, or even smaller.

The problem is that this point in a software's overall lifespan is just MVP - software typically isn't just built and just left alone for years; indeed the term soft was originally used to imply that (unlike hardware), it should be easy to change and easily malleable, and stakeholders typically expect and demand it to be easily changed.

Whatever costs were incurred to reach MVP with an initial small team and limited set of simple requirements is often tiny compared to later costs as they accumulate over subsequent years as the product grows; requirements gain more complexity; a codebase has ever-growing moving parts with more and more developers contributing over time, and as the distant memories of the original requirements growing ever-fainter.

The cost of maintaining software

Consider software which reached MVP even 3 years ago; the original team may already have all left their jobs and moved elsewhere, but the stakeholders who paid for it likely still need the software and are also probably highly dependent upon its continued stability and need it to keep evolving and growing in scope.

New developers can't realistically know the history of the code nor its design, nor its original requirements, nor all the decisions or trade-offs which took place in its lifetime, nor all the "gotchas" and other quirks or hidden bits of tech debt that nobody ever had time to fix.

With knowledge of the software and all the decisions being lost (or buried in obscure wikis and other decaying documentation that nobody knows how to navigate) and new developers essentially inheriting legacy code, each time a change happens which impacts the existing code, developers should rightly be expected by stakeholders not to have broken that code, and to release something whose quality is equal to or better than the previous version.

If the original developers covered their code comprehensively in automated tests; the quality is easy to assure because those hundreds (maybe thousands) of tests should run in just a few minutes and highlight the regression errors before anyone even creates a Merge Request. The CI pipeline can immediately warn the current developers when some long-lost requirement in the tests somewhere has gotten broken and prevent the broken functionality being merged into the main branch.

If, on the other hand, the original code was written without tests; consider how many opportunities the intervening years might have created to break that original code and introduce regression issues which a manual tester might miss and could easily end up making it into production or be unnoticed for a long time.

The reality is that code-entropy can grow quickly -- a single change to a single line of code can create a bug; if developers are constantly changing tens/hundreds of lines of code or refactoring and adding/changing/removing logic linked to existing code, then the opportunities to break existing code grows exponentially.

The cost of testing software

while opportunities to break existing code only ever grows, a team's ability to detect those bugs by-hand diminishes; the knowledge gets lost and fades over time, people forget things, the huge increase in scope makes comprehensive manual testing increasingly expensive and less feasible as more code is added and the software deals with an ever-expanding list of increasingly complex requirements.

Testing is the only real protection any team has against existing code getting broken; and there are only two choices - either make it happen automatically, or pay someone to do it manually.

Writing automated tests incurs an up-front cost once; involving the original developer and at a point in time when everyone is fully aware of the requirements and expectations, so everyone has the knowledge fresh in their head.

Writing manual tests incurs repeated costs which grow over time; initially the original QA tester is likely to have been involved in the original discussion around the requirements, and can probably write an excellent set of test procedures, with a reasonable amount of time to pass QA.

Each time a system changes, a manual tester (maybe not the same manual tester) must dig out the same test procedures and try, as faithfully as humanly possible, to replicate all of those tests. If they are the original tester, that's probably going to be a reasonable amount of time -- but it's a violation of the DRY Principle (Don't Repeat Yourself)

(While DRY Principle refers to not replicating knowledge and replacing it with abstractions, an automated test could be considered an abstraction of a manual tester's process)

The cost of manually testing software

The problem of manual testing gets worse with time:

  • The violation of DRY leads to paying for all the time needed for manual testers to run the exact same set of time-consuming and error-prone manual tests over, and over, and over; for many months and years into the future.
  • If there's a rush to get a bugfix out the door, the tester doesn't have time to run all the tests, they'll just pick and choose a few at random and ignore 90% of the tests; that's a good way to let regression bugs into production.
  • If the manual tester isn't the original QA tester who wrote the plan, they need to try to acquire all the knowledge which the original QA tester had in their head to try to execute the plan faithfully and take all the same considerations/observations into account
  • The original tester perhaps assumed a bunch of things that future testers wouldn't know so future testers might interpret things differently because they're only human, and that could cause a lot of confusion, maybe having to go back to the business to question old requirements which haven't changed in years, possibly adding a lot of disruption/delay while the business tries to answer the question.
  • The system itself grows increasingly complex and manual tests need to be maintained and updated just as automated tests need to be maintained and updated; but the additional time to keep re-running and maintaining manual tests also gets worse because manual test plans tend to be written in a very tedious, repetitive way.

When software is not 'soft'

Check this question on SE.SE for an excellent example of what happens when software has grown so unwieldy that it becomes extremely hard for a developer to work with, and causes them to ask a question like this: I've inherited 200K lines of spaghetti code -- what now?

Consider the origin of this code; it probably didn't start out as 200k lines of spaghetti, and it probably worked perfectly for its intended use-case at the time (in fact, the original programmers may have even thought to themselves that it was just a one-off bit of code that would never change).

Code entropy is often the natural and unavoidable fate for nearly all legacy code which doesn't have strong automated test coverage; developers may often not even think their code is going to last very long before someone scraps it but are usually proven wrong.

Software development generally happens on a backdrop of real-world human issues such as time/budget constraints, changing requirements, new/inexperienced developers, mistakes in manual testing, and developers having no "rails" to guide them when they break something by accident.

The best way any software delivery team can provide great value-for-money to their stakeholders is to focus on building very high-quality code which tests itself and therefore protects itself from code-entropy and future regression issues.