Being minimalist and being axiomatic means we can derive a set of rules from a single definition.
If we build our entire paradigm over one single rule we can Keep It Simple, Stupid and make excellent models and thus excellent software.
One of the most underrated quality attributes on software is the kind of being predictable. We are taught at the university and books that software should be fast, reliable, robust, secure, etc. but being predictable is almost nowhere on the top five design priorities.
We are going to make an exercise on object-oriented software design by stating just one principle:
Each domain object must be represented by a single object in our computable model and vice versa.
The relationship between model objects and entities of real world is 1: 1
We can see the justification of this model in this article:
We will then try to derive design rules and heuristics from that axiom, of course without contradicting it.
We will see that most of the language implementations used in the industry ignore this rule and this causes enormous problems. Invoking
problems that arose in the construction of software 3 or 4 decades ago and that they almost no longer exist or are present in a few domains we continue to make decisions like monkeys that beat others without knowing the reason for such behavior.
When building models of any kind we want to be able to simulate the conditions that occur in the observed real world so that we can follow each element of interest in our simulation and stimulate it to observe the changes in the same way that they happen in the real world.
Meteorologists make mathematical models to predict and anticipate the behavior of climate and most scientific disciplines are based on these simulations. With the rise of machine learning, we build black-box models to predict behaviors in real life.
In the domain of software and under the paradigm of objects we will always have one and only one object representing a real-world entity.
Let’s try to prove by the absurd what would happen if we did not comply with the principles of being a bijection.
Case 1) We have an object in our computable model to represent more than one real-world entity. For example, many programming languages model algebraic measures using only scalar magnitude.
Then we can represent 10 meters and 10 inches (two completely different entities in the real world) by a single object (the number 10) and we could add them together obtaining that in our model the number 10 representing 10 meters) the number 10 (representing 10 inches) is equal to the number 20 (representing who knows what).
This generates problems not always captured on time. Because it is a semantic fault, the error usually occurs long after the failure as in the famous case of the Mars Climate Orbiter.
The probe exploded by mixing different units of measurement.
Case 2) Our computable model represents the same real world entity with two objects.
Suppose we have in our observable real world an athlete John Smith who competes in one discipline but who is also a judge in another athletic discipline.
A single person in real world should be a single object in our computable model. We need to model just the minimum behavior to fulfill our partial simulation.
If we have two different objects (a competitor and a judge) that represent Jane Doe, we will sooner or later have inconsistencies by wanting to assign some responsibility to one of the two and not see it reflected in the other.
To solve these types of problems we must stop seeing entities as data structures with attributes, think of them as objects and understand that they are the same object fulfilling different roles depending on the context in which they are interacting.
We can even decide not not represent Jane but his roles on the simulation.
Case 3) A bitcoin wallet can be represented as an anemic object (with some properties regarding address, balance etc) or by a functional one (with responsibility such as receiving transactions, writing to a blockchain etc) but its clear for someone who is not in software business they are related to the same concept. So the bijection must be held.
Case 4) In most modern object programming languages, a date can be constructed by creating it from its day, month and year.
We all learned that a November 31th, 2020 can be created and that most of the languages will gently return a valid object (probably December 1st, 2020). But this disguised as a benefit is nothing but error hiding, generating a coupling dependency to the design decision made by the programming language and hiding a sure error in the data load.
Coupling: The One and Only Software Designing Problem
The error will appear later on, running a nightly batch of processing these dates far from the root cause violating the Fail Fast principle.
Fail Fast Philosophy, Explained
In this article, we define the only axiomatic design rule that we will respect no matter what by justifying the problems that come with not respecting it and laying the foundations for future definitions derived from it.
Part of the ideas in this article were developed together with Hernan Wilkinson and all the members of Software Engineering Staff at Universidad de Buenos Aires.
Part of the objective of this series of articles is to generate spaces for debate and discussion on software design.
We look forward to comments and suggestions on this article.