Every software project has its own aura. That aura existed before the project was even started. It gave the birth to the project and will be alive when the project will be decommissioned and/or replaced with some other project. This aura is The Full Context.
The Full Context consists of all information directly or indirectly related to the project. It's the single source of truth for every single decision related to the project, from the decision to start it to the name of the every variable in the code.
The Full Context is enormously big and contains a lot of business, economical and political information, such as, for example, company finances, influence of persons or groups on particular decisions or even the state of the mood of the developer which affected a particular decision.
Dealing with such amounts of information possible only by layering it into a hierarchy of abstractions. Each layer of the hierarchy consists of elements, where each element can be considered a word and the whole set of elements at the same level of abstraction - the language. This language is then used by the next layer of abstraction to express words used by the layer above, and so on and so forth.
In most cases, there is no single "root" abstraction and no single hierarchy of abstractions. Instead, the context information is structured as a bunch of independent hierarchies.
It should be noted that strict layering of abstractions is essential to keep context comprehensible. Abstractions leaking to upper levels may result in uncontrolled growth of complexity and make context an incomprehensible mess.
The Context
The hierarchical context structure enables us to extract only the technical part of The Full Context, i.e. the part directly related to the project. Let's call this part The Limited Context, or simply The Context. This part of the full context is the only usually necessary for development. To abstract out non-technical aspects, it is convenient to consider The Context as the single source of truth of all made project related technical decisions. This abstraction removes "why?" these decisions were made by removing all non-technical factors. This is a deliberate decision, necessary to limit complexity by keeping only parts essential for software development.
The Context is constantly updated and extended by new technical decisions we're making every day. If some decision is not yet part of The Context, the decision is somehow made (usually using procedures specific to a particular team/company/product/etc.) and put into context. These decisions therefore look like "decision map", which maps each "issue" to a particular "decision" and invokes a predefined procedure if an element is missing.
From general considerations, it makes sense to keep this "decision map" as small as possible because it directly contributes to the complexity of The Context. In other words, it is preferable to have a smaller set of more general/generic decisions, which covers a wider range of similar situations.
Inside The Context
Let's take a closer look at The Context and check what else is there. Besides "decision map", there are:
- real business domain
- business domain model
- real business processes
- model of business processes
The word business
here is rather a placeholder because what is business
is up to each particular project and The Full Context which gave it a birth. In blockchain industry at the top of abstraction hierarchy there will be blockchain domain and blockchain processes. In e-Commerce, it will be e-Commerce business and so an and so forth.
Note that when we start digging in depth of abstractions, we'll find that the business
at each level of abstraction is different. It should be obvious: we split one of the top-level elements into subparts ("words"), where each "word" is responsible only for part of the implementation. This part of the implementation is the business
of this "word". This process goes down and down through the layers and layers of abstractions. At the bottom there are purely technical details like calls to standard library or even more low-level stuff. Actually, detailing can be continued in depth as deep as necessary (perhaps infinitely). From task context switches, through specific CPU instructions and cache lanes, via signals and buses, down to logic elements and physics inside the chip die and PCB.
Usually, there is a reasonable logical limit below which more details do not add any value. Obviously, if you are building an operating system, then system calls are your top-level language, while everything below system calls is part of The Context domain or processes (again, limited to some reasonable level).
Business domain model and model of business processes are our project code. We use programming language to encode and represent parts of the business domain and processes. In other words, code is a formalized encoding of the business, its domain and its processes. It means that code is at best as good as domain and processes. If you have fuzzy domain, bad/inefficient/inconvenient business processes, code is at least as bad (usually worse). Also, map is not territory, hence both models are only approximation of real business domain and processes.
It should be noted that relationships between business parts and their models are bidirectional. More often than not, business is ready to change process to match one proposed by software. The level of flexibility heavily depends on several factors and may vary. Usually, there is a tradeoff between price/time and precision of modelling your processes/domain. From "buy ready to use software/subscription to service AND adjust all your processes to proposed model" (and get software up and running almost instantly for few hundreds/thousands $$) to "software should exactly reproduce our processes even if they are stupid, and we hate them" (and spend years and millions of $$) and everything in between.
But not just processes can change. The domain of the project also may change. Usually, this happens, when project scope is reduced or extended. A decision to reduce or extend scope might be a consequence of the technical assessment or analysis.
Nevertheless, often it is more convenient to consider these relationships as unidirectional (even if they're clearly not) and assume that real domain and processes are the source of truth.
Note that various design documents, architecture designs and other similar stuff is not the part of The Context. They could exist and even be useful if they precisely correspond to code, but the code is the source of truth about domain model and model of business processes.
Once we start thinking about project code with The Context in mind, we quickly discover that relevant decision stored in The Context control code properties:
- How detailed modelling is, comparing to reality
- How precise modelling is
- How easy real context can be restored from code (context readability)
- How long project will be used
- How performant it should be
- etc. etc. etc.
Basically, everything about the project is determined by The Context. For example, if you're implementing a one-time migration tool to migrate a legacy system to a new platform, requirements to code quality, maintainability, test coverage, context readability, etc. will be significantly different from those for backend planned to be used at least next five years from now. Moreover, those requirements not necessarily should be identical across the whole code base. For example, we might sacrifice some context readability in a performance-critical part of the code to achieve necessary performance.
As one can see, context-based approach is very business focused, as opposed to traditional approaches which are primarily focused on software. Of course, connection to the business always existed. But usually, it was just an input for the software development. Specifications and requirements were eventually replaced/complemented by user stories and epics when industry adopted agile methods. This significantly improved connection with the business, but focus on the software was left intact. Context-based view shows that it's not just the connection but tight coupling, where the business is a primary driver.
The Code
The main consequence of understanding of true relationships between business and software is the realization that existing approaches to software development might not be completely up to the task. Even a quick looks shows significant issues with traditional approach based on the best practices.
First thing to note: traditional approach tries to establish identical practices to all projects. As we know, every project is unique, setting identical requirements does not seem like an adequate solution (kind of resembles famous average pilot story).
Second, no less important: significant part of the practices relies on the code readability as a justification. Overall, code readability is often considered as one of the most important properties of the code. Problem is that nobody knows what is "code readability". Of course, every seasoned developer knows that it exists, but there is no reasonable definition for it. Existing ones either self-recursive (i.e. funny but useless) or rely on other undefined terms such as "intent". Lack of definition means that every assessment of code readability is subjective, and there is no way to validate any given best practice which claims that it "improves code readability".
Even the term "code readability" is misleading. If code compiles, it is readable, at least by the compiler. Most likely, with some effort, code also readable by the human too. So, "code readability" is not about reading the code at all.
Without clear understanding what code readability is, the whole traditional approach starts looking like a cargo cult. We're blindly repeating the same practices with the hope to get good result, but we have no idea why particular practices work or don't work in each particular case.
Context-based view clearly lacks issues mentioned above. Code represents parts of context, and The Context defines requirements to the ease of restoring of the encoded context from the code. Much less room for ambiguity, each practice can be easily validated whether it helps preserve a necessary part of context or not in every use case.
All of the above suggests that we need to significantly change our coding practices. But a detailed look into new coding practices is a theme of another article.