In this series
Separation of concerns in systematic design
Separation of Concerns in Systematic Design 09.2020
Welcome to the the second essay about systematism. The first part of this series examines what kind of tasks are most suitable to be systematized, and how abstraction benefits a system’s longevity.
I have also analyzed the conditions that will allow systematic constructs to thrive, and I have discussed the specific economies created by a thoroughly optimized system.
In the second part I want to build on this foundation and introduce an additional concept which is fundamental to ensure the operational efficiency of a system: separation of concerns.
Separation of concerns
Separation of concerns 1 is an architectural engineering concept which describes the separation of a program into a discrete set of operations which are semantically self-contained.
In relation to systems, separating concerns is a powerful construct that ensures predictability and maintainability, and it is applicable to many different contexts.
The main goal of separation of concerns is to clearly define the scope of each part that constitutes the system. Distinct boundaries are fundamental for concerns to be truly separated, and the criteria by which the scope is defined can vary depending on the goals of the system and how each part within relates to the others. A popular approach for scope definition is the single responsibility principle 2, which dictates that every discreet component of a system is responsible for a unique aspect of functionality provided by the construct it belongs to, and that responsibility should be entirely self-contained. In the context of an organization, assigning each team a specific set of responsibilities allows to reduce duplication of efforts and streamline the workforce.
The earliest definition of concerns separation known in system theory literature appears in the essay On the Role of Scientific Thought 3, where the computer scientist Edsger W. Dijkstra describes separation of concerns as:
What Dijkstra describes is the correlation between clear scope and the level of focus for each area. When teams have clear responsibilities assigned to them, they are able to analyze the problem space in greater depth and develop expertise around the subject, maximizing their chances of success.
Depending on the desired system’s architecture, separation of concerns can follow different models and different levels of scale designed to maintain the system within its optimal output range.
The most common model for separation of concerns is called horizontal 4 and it refers to the logical separation of components as individual layers of functionality. In software engineering, a common example of horizontal separation is the MVC model 5. Let's imagine a car dealership which enables customers to sell and purchase vehicles through an app: if the application's architecture is separated horizontally, the distinction between presentation, logic and data guarantees there will be no functional overlap between any of the three parts. Horizontal separation of concerns can be also referred to as local, since its combined scope is usually limited to a singular system.
Orthogonal to horizontal concerns, vertical separation of concerns follows the structure of business organizational units and is grouped by feature set. This type of separation is often paired with other uncoupling strategies to achieve a more nuanced application architecture.
For example, the same car dealership can organize itself around teams that cater to the specific needs of a customer during each step of their lifecycle. This type of structure could result in a single unit responsible for customer leads, a second in charge of consumer acquisition, a third accountable for conversion and so on, all working in coordination, but independently from one another. Each team can also separate further horizontally, dividing business logic, presentation and data management for each feature they are responsible for. This distribution of concerns is particularly helpful with systems that are too large or complex to be overseen by a single entity and require their scope to be defined at multiple levels.
The last type of separation of concerns is transversal (or aspect-oriented). Transversal concerns are identified as interspersed across the boundaries of various areas within an application. In software development, this particular approach is referred to as aspect-oriented programming 6, a practice aimed at abstracting methods that are used throughout the application so that they can be managed as a centralized function. Let's go back to our car dealership example and imagine that workers on different teams share requirments of managing documentation and debugging their code. Documentation and logging become cross-cutting concerns because they require a shared solution but are incorporated locally at different levels of the codebase.
A transversal concern can be incorporated within existing separations, for example even within a model which already separates concerns horizontally, therefore cross-cutting concerns can be utilized across the boundaries of the application silos to provide common patterns for implementation of reusable features.
A common detracting argument for separation of concerns is that breaking a monolithic toolchain into a series of smaller workflows may cause too much fragmentation, resulting in a system that produces sub-optimal results. While we should not be dogmatic about any of these models, in most cases separating concerns is a useful approach when building systems that are expected to scale.
When designing a new system, system’s architects need to balance today's constraints with tomorrow's ambitions: the system needs to be flexible enough to scale as the business grows and sufficiently nimble not to require any unnecessary overhead. So what does scaling a system exactly mean?
When the required output of a system goes beyond what a single worker or machine can individually support, the system needs to grow. Once a system reaches this inflection point, system administrators generally have two choices: they can seek to optimize the system further so that the output of a single worker can be increased, or they can add additional workers to improve the capacity of the system.
Let’s examine a system that is already running at optimal capacity and can only support additional output by providing additional workers. In a system with a single worker, the first operator has to complete all the tasks required from the system by themselves. The introduction of a second worker allows both operators to divide the required labor, enabling each individual to gain speed and output volume by perfecting the execution of a smaller set of steps, which ultimately contribute to boosting the overall operational efficiency of the system.
In the example above separating concerns between workers provides a pathway towards maximizing efficiency by ring-fencing the operators' responsibilities to a set of processes that are manageable for the individual and that can be kept in memory 7. Neurological studies have demonstrated 8 that the ability to execute a task is stored in our procedural memory and that there is a tax we pay every time we switch between tasks that require a different set of instructions. This means that if a system requires workers to learn and perform tasks beyond what they can comfortably recall and complete, it will incur in context switching debt and it’s output will begin to degrade.
In systems operated by people, the dimension of what a single human can sustainably deliver becomes a guardrail to help creating infrastructures that are well managed and long-lived. The same concept rose in popularity in Britain during the industrial revolution, and resulted in limiting the daily work hours to what is known today as the 8-hour work day. In the following section I will discuss how this principle can also serve systems operated by machines, following a succinct axiom that recites:
Now that we understand how separation of concerns can help to efficiently scale our systems, we can discuss how they should be architected so that they can complement each other and work together as a network. We define interoperability as:
In recent years a number of European governments have started to streamline their bureaucratic burden by offering access to digital services to their citizens. These e-governments 9 are setting new standards on how systems should be constructed, focusing on portability of data which is often collected once, stored in singular repositories, and shared across many different services and providers.
To guarantee the transferability of information across multiple systems, governments and institutions need to address two different obstacles: technical and semantic interoperability.
Technical interoperability addresses the technological requirements two systems must satisfy to communicate securely across a network. It establishes the foundational syntax and protocols of data sharing that need to be fulfilled when a connection is made and it is responsible for developing standards around exchange solutions so that data can be accessed by compliant systems. For example, when transferring data from an API endpoint to a client, both resources need to satistfy the same security requirements for the data transfer to be successful. Technical interoperability ensures that data transfer is possible and that all the required infrastructure is operational.
Semantic interoperability defines the underlying data model which enables mapping between source data sets and its destination endpoints. For example when a patient is transferred from an hospital to another location, institutions share patient data so that doctors can provide continuous treatment. Semantic interoperability ensures that each data point shared between two systems has the same meaning regardless of the entity that stores it (e.g. the patient's "first name" recorded by hospital A is interpreted as such and not as their "middle name" when its received hospital B), and it is crucial in preventing transcription errors and keeping the data readable by humans.
While interoperability may seem a simple concept to grasp, its application requires a conspicuous amount of planning and it is a crucial part of a system's design. As they stand up new systems, architects need to make sure they are not only able to exchange information amongst each other, but can also reference pre-existing data, which might be stored in a different infrastructure. Interoperability considerations become more relevant for larger networks: when a group of systems is able to communicate and coordinate the execution of multiple processes across a network, we define that architecture as a distributed system.
A system is considered distributed when it is composed by a series of interoperable entities, which work on a discreet set of responsibilities, and are able to share information efficiently over a network.
The main characteristics of distributed systems are: scale, interoperability, concurrence, and fault tolerance 10.I have discussed the first two attributes earlier in this essay, so I'll focus on the remaining concepts.
Concurrence is a property of a system that describes the ability of individual concerns to operate at the same time, or in parallel. It is particularly useful in reducing dependencies between tasks that are part of the same system. Workers are not bound to perform tasks sequentially any longer, but can operate in parallel, drastically reducing the execution time of the job the system is hired to perform. As we know from exemplary cases like Amazon Prime delivery or on-demand content, reducing the time it takes to deliver a job can be an incredible advantage over a competitor's system.
Fault tolerance enables a system to continue operating efficiently even in the event of failure of some of its components. Fault-resistant systems are designed to continue their operations even in case of catastrophic failure. There are many approaches to fault tolerance, and the most common of all is redundancy.
Redundancy consists of ensuring that critical parts of the system (e.g. its data storage location, or the tires of a car) are duplicated and backed up by other parts of the infrastructure (and preferably hosted in different locations, like a cloud backup or a spare tire in the trunk), so that in case of failure of the main data source, the system can sustain itself by automatically switching its provisioning to the backup copy (network storage drives or gas-powered generators are other common examples of data and power redundancy).
Distributed systems can also be diversely located. In this essay I have considered distribution primarily from the point of view of separation of concerns, but it is important to acknowledge that another advantage of distributed systems is that they are not bound to a specific geography and do not need to be co-located to operate. A distributed geography can be particularly advantageous in the context of a global economy, allowing different units of a single system to work around the clock across different timezones and to recruit the best talent for a specific job without being constrained by local market rates.
As technology advancements allow for more efficient distribution of labor across different units and locales, newly created systems are paving the way for an emerging systematic model which favors smaller, interoperable (and replaceable) components to larger monolithic constructs, in favor of risk mitigation, scalability and supercharged production lifecycles.
These modern system's architectures are designed to be more flexible and less dependent on each other and allow for a greater speed of deployment and iteration. In our next essay, I will discuss how to optimize a system for continuous delivery and how to boost its distribution strategy so that it can deliver value to customers from its inception.
- Wikipedia, Separtion of Concerns. ↩︎
- Wikipedia, Single Responsibily Principle. ↩︎
- On the Role of Scientific Thought, 1974, Edsger W. Dijkstra. ↩︎
- The Art of Separation of Concerns, January, 2008. ↩︎
- Wikipedia, Model–view–controller. ↩︎
- Wikipedia, Aspect-oriented programming. ↩︎
- How The Brain Learns, July, 2011. ↩︎
- The Role of Working Memory Gating in Task Switching: A Procedural Version of the Reference-Back Paradigm, Yoav Kessle, Frontiers in Psychology, Dec, 2017. ↩︎
- Wikipedia, E-goverment. ↩︎
- Distributed Systems - The Complete Guide. ↩︎