from monolith to open platform

Any software product does not exist in a vacuum and is designed to interact with the user through a user interface (UI) and/or with an external application through an API. It is extremely important to consider the future interface of the application at the design stage, since the requirements for the UI and API can impose significant restrictions on the product architecture. It is not for nothing that the classic user story entering development sounds like this: “As a user, after performing certain actions with the UI, I expect to receive the corresponding result.“. If we project user stories onto the API, we get a scenario for automated tests and test-driven development – TDD, when before the start of development, data structures, API functions and their expected behavior are recorded in tests, and development focuses on ensuring their correct passing.

Anti-pattern of API Design for UI Applications

If the application is primarily used by the user through a graphical interface, you may encounter a situation where the API is not given enough attention when designing the application, and the functions for interaction with other applications are implemented after the feature has been implemented in the UI. This is understandable from the point of view of accelerating development: why waste time on developing and implementing a “secondary” interface – we will implement it later, and first roll out the UI version. But in this case, such API functions form a separate layer, gradually acquiring their own data structures, algorithms, turning into a full-fledged component. And a separate component requires a separate team for its development, which further aggravates the situation, distancing the implementation of the API from the features for which it is written.

IN the optimal API option for features it is necessary to design together with UI, and UI implementation should be built on API. The optimal architecture for building API of a monolithic application in this context is presented in the figure.

Multi-component architecture

As it grows, any monolith inevitably faces the problem of increasing costs of developing new features. The lack of clear boundaries between components and strong code coupling require ever-increasing efforts to integrate new functionality into the existing model. Each new feature begins to require more and more programmers, testers, and time for its implementation, and most importantly, the requirements for the qualifications of specialists who know all the nuances of the monolithic model increase.

The solution to this problem can be to split the monolithic model into separate, fairly independent components, each solving its own set of tasks and having its own API. This allows not only to “cheapen” the development of new features, but also, by opening the API of the components to external developers, to create a kind of “platform” for the implementation of new features and even systems, attracting a wide range of programmers to the development, who only need to study the platform API.

Bounded context

The most difficult task in this case is, perhaps, to find those very boundaries along which we need to divide our monolith into parts. I prefer to stick to the approach of bounded contexts, which Eric Evans described in his book “Domain-Driven Design (DDD). Structuring Complex Software Systems“. The division of the system into components should begin with the division of the set of tasks to be solved into subsets. Such division is most often determined naturally based on expert analysis of the subject area, for example, for the KOMPAS-3D CAD system, the following subareas can be distinguished: 2D modeling, 3D modeling, Specification, Text editor. Such subareas are already quite independent of each other and have a certain degree of autonomy. A limited context is formed when modeling the solution of subarea tasks, must have clear boundaries and uses a unique language. Terms unique language are accessible only within the context. In case of intersection of terms between contexts, each context creates its own entities for them, implemented in the form of its own data structures. Contexts with the entities included in them, which can be identified in the KOMPAS-3D CAD system, are shown in the figure:

Please note that the entity “Execution” occurs in two contexts: 3D (3D modeling) and PD (Product Data). If we talk about a general unified model of the entire subject area, it will have only one corresponding entity, represented by a data structure with a full set of all fields that allow for the most complete description of any object of this type. When dividing a model into limited contexts, each context has its own aspects of the entity used, and data structures for “Performances” in PD and 3D have their own set of fields. When it is necessary to transfer entities from one context to another, data structures can be translated into each other.

Fear of duplication of entities

Isolating bounded contexts with their own unique language often contradicts the developers' desire to reuse existing entities that were created to solve other problems but have similar semantics. Most often, such reuse of entities from other contexts leads to adding new fields to the corresponding data structures and, ultimately, leads to excessive growth of classes and increased code cohesion.

Product data as a limited context in CAD KOMPAS-3D

Extraction of bounded contexts allows obtaining maximally independent autonomous components with their own API and suitable for reuse. For example, as part of the work on extracting the product data management (PD) component, the following entities were extracted: Product, Design, Component of the product, Properties of the component parts of the product etc. For these entities, their own logic and algorithms are implemented within a limited context: for example, support for expressions is implemented for Properties of the components of the productcontaining links to Properties others Components of the product. Product data component (P.D.) can be used both in 3D, and in 2D, and in Specificationswhile in essence Component of the product entities are translated from the context of the Product Data “Inserting a component”, “Body” from 3DMacro”, “Insert fragment”, “Insert view” from 2DSpecification object” from Specifications. In this case, product data can be freely transferred between documents, while maintaining the functionality of all algorithms implemented within the context. Before the allocation of the product data context(P.D.), to obtain the product structure in the Specification, it was necessary to go through all possible sources Components of the product: component inserts, bodies, macros, fragment inserts, view inserts from the connected documents, delving deeply enough into the nuances of implementation 2D And 3D models, and links between properties inserts V 3D and between macro V 2D would demand their implementation.

Conway's Law

Another tool for forming a multi-component architecture for an open platform is the organization's communication structure. Conway's law states: “Any organization that develops a system is forced to create projects whose structures are a copy of the organization's relationship structure.”

Image source https://bonkersworld.net/organizational-charts

The meaning of the law is quite simple: strong communication links within a team determine high cohesion of the code that this team writes, and much weaker inter-team communication links provide weak coupling with the code of other teams. Thus, the code written within one team has the properties of a well-designed component.

According to Conway's law one bounded context should be developed by one teamwhich will naturally maintain its autonomy and isolation. On the contrary, dividing one bounded context between two teams can lead to context fragmentation and will require additional efforts to establish closer communications between the teams.

Summary

The API requires close attention from developers starting from the system design stage. Formation of a multi-component architecture based on the division of the model into limited contexts allows to form a transparent extensible application architecture, greatly increasing the efficiency of development. The open API of components will allow to maximally expand the range of tasks to be solved and, ultimately, the number of users of the system.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *