Proper software development is complex. Some software engineers are creating complex systems without un
Proper software development is complex. Some software engineers are creating complex systems without understanding the abstract hierarchy of dependencies between different pieces of software code. This can create what is known in complex social systems as tyranny.
Tyranny in Complex Systems
When people hear the word tyranny, they think of corrupt oppressive government rule. Particularly government actors that force arbitrary choices upon individual citizens. These choices, or actions, that are forced upon the individual might be arbitrary to the individual, but perceived to makes sense to the higher system domain (the government).
An obvious example of tyranny is slavery. Governments or powerful citizens forcing back breaking labor upon a subset of individuals in society. Individual freedom, which is important and the lower level of dependencies within the social complex system, is abandoned or ignored by the government for perceived efficiency in the production of material goods or services.
These systems that force higher level concepts onto lower level dependencies become fragile over time. Southern American states that relied on slavery for many decades are still recovering from the fragile state that the tyranny of slavery caused. Slavery weakened or destroyed individual growth and motivation. It violates the rules of tribalism which is vital for social cohesion. All of this leads to a fragile complex system.
Tyranny is forcing concepts or actions at the wrong hierarchy of dependencies in a complex system.
However, social systems that do not force concepts or actions at the wrong hierarchy of dependencies will be robust over time and will have higher probabilities of flourishing in harder times. The federal system is a great example of a social hierarchy of dependencies that has been robust over the years.
Software Tyranny
So if tyranny is forcing concepts or actions at the wrong hierarchy of dependencies, how does this relate to software code?
Below I will provide an example of software code tyranny.
Example Software System Overview
The system is an article system, like Medium, that provides the ability for consumers to create articles and share them.
The Problem
We needed to enhance the system to use a caching system when users outside of the system read the articles, since there are way more users reading articles then editing. But we can’t use the caching system when users are editing the article since we want the current data available as quickly as possible.
The Solution
The article rendering system needs to use a separate cache system for retrieving the data needed to render the article.
The system at the highest level knows about “editing” and “viewing” when a request comes in to render the article via a query parameter. If it is in an editor, the URL will look like this:https://articleservice.com/article?editMode=true.
Below is the server code:
const express = require('express')
const app = express()
const articleStorage = require('articleStorage');
const renderEngine = require('articleRenderingEngine');
app.get('/:articleId', (req, res) => {
//get article data from storage
let articleData = await articleStorage.getArticle(req.articleId);
//convert the article data into HTML for rendering
let html = await renderEngine.renderArticle(articleData);
//send the HTML back to the browser
res.send(html);
})
This is the code of the server for rendering the article. It fetches the data from storage, converts the data to HTML and then sends it back to the browser for rendering.
Solution by Tyranny
Now we have our app, we need to update it to use the cache system. Below I will show you how to use tyranny to update the system to do what needs to be done.
app.get('/:articleId', (req, res) => {
//get article data from storage
let articleData = await articleStorage.getArticle(req.articleId, req.params);
We pass in the params from the request to the ArticleStorage (the ?editMode=true that was discussed above).
Now we will update the dependency code to fetch the article data from the cache system when we are rendering for view mode vs edit mode:
const cacheSystem = require(‘cacheSystem’);
const databaseSystem = require(‘databaseSystem’);
export class ArticleStorage {
async getArticle(articleId, options){
let articleData;
if(options.editMode !== "true"){
articleData = await cacheSystem.getCacheForArticleId(articleId);
}else{
articleData = await databaseSystem.getArticleByID(articleId);
}
return articleData
}
}
Can you spot where the tyranny is happening? It’s the if statement
if(options.editMode !== "true"){
This is a concept (edit mode) that is being forced at the wrong dependency hierarchy. In Domain-Driven Design, the ArticleStorage is in a different domain and the concept of whether to use the cache system should not be coupled to the concept of “editMode”.
“EditMode” is a higher level concept that does not make sense at the storage level code in the system.
The High Quality Systems Solution
The proper solution will look pretty similar, but will have a major impact for the future of the system.
Since the ArticleStorage is in a different domain, the concept needs to be translated.
export class ArticleStorage {
async getArticle(articleId, options){
let articleData;
if(options.useCacheSystem == true){
articleData = await cacheSystem.getCacheForArticleId(articleId);
}else{
articleData = await databaseSystem.getArticleByID(articleId);
}
The ArticleStorage should have an option to useCacheSystem . Now reading the ArticleStorage makes more sense.
The article rendering route should translate the concept of “editMode=true” to “useCacheSystem=true”
...
app.get('/:articleId', (req, res) => {
//create article options
let articleStorageOptions = {
useCacheSystem: (req.params?.editMode == "true")
};
//get article data from storage
let articleData = await articleStorage.getArticle(req.articleId, articleStorageOptions);
...
Now we have a solution that does not force concepts at the wrong hierarchy of dependency.
A Bright Future
The pragmatist will argue that our argument above adds additional code that one will have to support in the future, which will make the future worse for maintaining and enhancing the application.
However, forcing concepts like this in the wrong abstraction layer will only cause issues in the future. What if we want to use the ArticleStorage to retrieve article data for a different part of the system that doesn’t have the concept of “edit mode”? That other part of the system will have to have to translate what “editMode” means, which will add confusion when supporting the code at a later time. Where as the domain translation we introduced is logical and readable, which is more maintainable.
This form of tyranny limits optionality in the future. It also limits the freedom of responsibility that dependencies need in order to create high quality systems (more on both of these points in future articles).
Overview
Tyranny is forcing concepts or actions at the wrong hierarchy of dependencies in a complex system. We have seen this over and over again in complex social systems, but this also takes place in complex software systems. Tyranny should be avoided in any system if that system is to endure the test of time.