Inherently Broken and Rotten by Design

It's hard to get things right on the first try and to be honest on the second, third and so on. There is the inherit problem, that as humans we are not able to somewhat reliably determine as a group, if something is correct or better than something else, according to a given knowledge base. On average, we are not even able to determine, the best person for a job. Instead of living in denial, this is an attempt to cope with this situation.

So, it is assumed, that core decisions regarding the software architecture and features will be done incorrectly. The main target is to minimize the damage done by incorrect decisions or human errors during their implementations.

Delaying decisions or their implementation can minimize their caused damage by skipping obsolete actions or by improving their planning based on new information. The basic idea is, that most of the time some knowledge is missing, when a decision is being made. Delaying a decision or an implementation while using the software or developing different features, will provide additional useful info. This info can potentially be used, in order to improve the planning. Even programming parts that are not part of a decision, can provide insights.

Therefore, a minimalistic implementation can be done first, that just barely meets the requirements and does not have any extras. By delaying the complete implementation as much as possible, the usage of the minimalistic implementation can provide more info regarding the features' usefulness and how a correct and full implementation would look like. In other words, technical debt can be build up, in order to finance a technical investment, that may lead to a development loss or profit.

Let's assume, that your application needs an export of table data, so that a user can access it via a spreadsheet program like Excel. You could start implementing a proper export for Excel's XSLX file format, or you could start by implementing a CSV export. The CSV variant would be easier to implement, also the user would have to convert the CSV data.

Of course, you would not implement a proper CSV export first, but a ghetto version. This version just joins together the values of lines via commas and lines via new line symbols, without regards for escaping special characters. After some time, you notice, that the user doesn't actually use Excel, but LibreOffice instead. Therefore, you scrap the plans for an XSLX export and build an ODS export for LibreOffice instead.

This approach creates an inherently broken design, as decisions are delayed or incomplete as much as possible. Every delayed or incomplete decision breaks the contract in some way with requirements of the software. Things like a complete overarching software architecture or explicit requirement engineering are avoided as long as there is no concrete need for it. Therefore, big, deep and fundamental adaptations may need to be done at any moment without any warning, as decisions are revisioned. It is expected that the positives of the technical debt outweigh the negatives. The minimization and containment of the adaptation costs by using migration based development for example is one of the highest priorities, as otherwise these costs will kill the project.

The software is broken by design and therefore, there will be more features implemented than when the software would not be broken by design. The larger amount of features and therefore complexity increases the damage done by a changed line of code, that is not backwards compatible to the rest of the code.

Therefore, any changed line of code should either be done in a backwards compatible way or all other related code should be changed/migrated in the same step so the code as a whole stays correct. The complexer a development step is, the hard and more unlikely it is, that the step is done correctly. Therefore, backwards incompatible changes are preferred and is called migration based development.

Note, that this does not mean, that public APIs do not change. The backwards compatibility of the API is part of the software's requirement and is a decision to be made. By default, public API development is assumed to be backwards incompatible, as backwards compatible development often requires planning and higher resources. These heightened requirements make it unlikely, that an API is backwards compatible, when no decision was done.

The longer and longer the migration based development is applied, the more and more complexity is collected and every code change becomes harder. Use this complexity in order to enforce good programming. In other words, the more complex the software is, the easier it is to write bad code and the more damage such code will create. This in turn increases the incentives to code correctly.

In order to contain the cost of maintaining features, create a hostile environment in regard to errors. The hostile environment's job is to detect any errors with little regard of its significance, to exploit them and to massively increase the cost and damage of doing things wrong. Such environments have to make it easy to fix the found errors, as otherwise the development cost escalate. The things that are checked by the hostile environment have therefore to be carefully balanced, so that the checks are not too strict to avoid the cost of fixing or not creating errors and are not too loose to prevent the cost caused by programmer errors.

This is a stability created by tension. For example, if you want to have a secure infrastructure one could create a hacking group, that has the permission to find and exploit any security issue, is allowed to actively cause real damage and is rewarded for it. When you have such a hacking group the developers will prioritize the security of their software, as they know, that any work done by them can be destroyed by the hacking group at any time.