How to describe software architecture in code ? Remodeling of architecture
Remodeling of architecture | How to describe software architecture ? |

In the architecture governance platform ArchGuard, in order to realize the governance of the architecture, we need the code + model to describe the content and data to be processed. Therefore, in ArchGuard, we have a code model, a dependent model, a changed model, etc. The remaining two core parts are the architecture model, the architecture governance model, and others such as construction models. It will be continuously introduced into the system in the subsequent process.
PS: The architecture developed in this article is based on automated analysis requirements, and the model is also based on this motivation.
What is architecture??
It is not difficult to model the code of a single language, there are special concepts for a language, such as a package, class, field, function, and so on.
On the basis of a clear concept, combined with our business needs, we can build a model that is too bad. When using DDD modeling methods, the prototype of the model can be constructed by generating consensus, refining knowledge, and forming concepts.
Starting point: Architecture is the important element
However, for architecture, there is no unified definition in the industry. So, for example, Martin Fowler likes to quote the description of the architecture by Ralph Johnson, one of the GoF (authors of “Design Patterns“):
Architecture is the stuff that matters...whatever it is.
The same Grady Booch (one of the inventors of UML) summed up the architecture in a similar way:
Software architecture is a collection of important design decisions in the system design process, and the important dimension of each design decision can be measured by the cost of change.
So, it makes us feel that we say nothing, we have to define what is important. And the important things are different under different people and in different scenarios. Even for the same type of software, in the context of different companies and different stakeholders, the important things are the same.
Principle: But what exactly is important?
So, I tried to cite the latest architecture-related books, such as Neal Ford’s definition of architecture in the book “Software Architecture: Architectural Patterns, Features, and Practice Guide” when I wrote this article:
Software architecture includes the structure of the system, the architectural features the system must support, architectural decisions, and design principles. The structure of a system refers to one or more architectural styles (such as microservices, layers, and microkernels) in which the system is implemented. Architectural characteristics define the success criteria of the system. Architectural decisions define a set of rules about how to build a system. Design principles are optional guidelines on how to build a system.
The definitions in the book also provide flexibility at the level of modeling. For example, in the definition of architectural features, the focus is on various capabilities (ability), such as interoperability, applicability, testability, etc.
Under the existing business scenario of ArchGuard, it is difficult for us to automatically identify various characteristics. Because from a practical point of view, these capabilities are not necessarily realized, it is the target architecture and may only exist on the architectural blueprint. At this level, the architecture defined here tends to be defined at the design level.
On the other hand, architectural decisions are the core of our attention in the process of architectural governance. A DSL that describes the architectural features can be built on the rules of this series of principles later.
Important Elements: Components, Boundaries, and Communication
Next, let’s go back to the definition in Uncle Bob’s (Robert C. Martin’s The Way to Clean Architecture):
The quality of a software system is determined by its builders. The essence of software architecture is to plan how to divide the system into components, arrange the relationship between the components, and the way that the components communicate with each other.
In terms of the Clean Architecture mode, what Uncle Bob has been emphasizing is that the top-level abstraction strategy and the bottom-level implementation must be decoupled. Such as how to draw reasonable boundaries? How do combine relevant strategies and layers? From this pattern, we get an increasingly clear definition.
However, we also encountered a more complex problem is, how to define what a component is? ** Also what is the relationship? **In the preface to the book, Kevlin Henney (co-author of Pattern-Oriented Software Architecture Volumes 4 and 5) gave a more precise description: structure, the process of building from macro to micro, in which the components include components, classes, functions, modules, hierarchies, services, etc.
For large-scale software, its organizational structure is extremely complex, it is very similar to the hierarchical relationship of a country, first-level departments, second-level departments, and so on. And there are complex relationships between departments, and it is the hierarchical relationship + hierarchical components that build this complex system. (PS: In order for the system to work well, that is, for the components (screw) in it to perform according to the rules, an inspection organization is needed.)
Hierarchy: Components and Relationships
Software architecture has been around for decades, and we’ve used the term “pattern” to make a series of summaries of past architectures. Twenty years ago, people initially summarized “Pattern-Oriented Software Architecture” (POSA). Here, just citing Chapter 6 of POSA 1, there is a complete introduction to the hierarchy:
Software architecture describes the subsystems and components of a software system and the relationships between them. Different perspectives are frequently used to describe subsystems and components in order to highlight the functional and non-functional properties of a software system. A component is a software system's enclosed portion that has an interface. A component is a software system's enclosed portion that has an interface. Components can be represented in programming languages as modules, classes, objects, or a group of linked functions. The links between components, which might be static or dynamic, are described by relationships. Static relationships are displayed directly in the source code, and they indicate the layout of components in the architecture; dynamic relationships indicate temporary relationships and dynamic interactions between components that may not be readily apparent from the static structure of the source code. A view presents an aspect of the software architecture, showing some specific characteristics of the software system.……
From today’s point of view, the software architecture itself has not changed much in terms of mode. It’s just that some definitions have changed, such as components and interfaces. In today’s popular microservice architecture style, a microservice can also be regarded as a component, which contains a series of interfaces and provides external reuse capabilities. The elements used to describe their relationship are no longer function calls in the past, but remote calls and event triggers.
Now that we have a detailed definition, some elements may be lacking in modeling, such as how to analyze the relationship between components.
Architectural View 3: Showing Engineering Concerns
In ArchGuard, we use the C4 Architecture Visualization Model as a reference view. This way of implementation is mainly considered from the level of analysis and visualization. In addition to C4, another mainstream approach is the 4 + 1 view. By the way, there’s a representation formula for expressing the architecture in the 4+1 article “Architectural Blueprints—The “4+1” View Model of Software Architecture”: {Element, Forms, Rationale/Constraints} = Software Architecture. A 4+1 approach is good from a broad standpoint.
From a general perspective, a 4+1 view is ideal. However, due to the irrationality of a large number of PaaS, IaaS, and other xx-as-a-service designs, these codes that record basic design-related information are not stored together with the code base, making identification difficult.
Therefore, from the implementation level, here, we want to refer to the architecture of “Software Architecture in Industrial Applications” (also refer to the book “Practical Software Architecture”) mentioned in the “Pattern-Oriented Software Architecture” view:
- Conceptual view: describes the transformation of the entire system requirements into the entire architecture.
- Module View: Describes how to divide the system into modules and organize modules into layers.
- The execution view describes the system’s dynamic parts and their interactions.
- Code View: Describes how the source code is organized.
In the definition of this view, it can more clearly separate several different levels of consideration. To take the example the authors mentioned in their earliest paper:
Software Architecture | Example of use | Examples of Influencing Factors |
Code Architecture | Configuration Management, System Build, OEM Pricing | Programming languages, development tools, and environments, extension subsystems |
module architecture | Module interface control, change impact analysis, interface constraint consistency check, configuration management | Enabling software technology, organizational structure, and design principles |
execution architecture | Performance and schedulability analysis, static and dynamic configuration of systems, porting of systems to different execution environments | Hardware Architecture, Runtime Environment Performance Standards, Communication Mechanisms |
Conceptual Architecture | Design, performance evaluation, safety and reliability analysis, understanding static and dynamic configurability of systems using domain-specific components and connectors | Application areas, abstract software paradigms, design methods |
From the right side of the table, we can directly correspond to the design factors at each level required by the system, such as the programming language and other elements placed on the code structure. In other words, under the microservice and monolithic architecture, you can find your own suitable position.
The end of the concept: the type system that describes the model
Finally, in order to ensure the conceptual integrity of this paper, we also need a way to describe the model of this system and a series of concepts, which formally is a type system. Code View: Describes how the source code is organized.
class Architecture { Component[] components System[] subSystems Relation[] relations ArchStyle archStyle Rule[] archRules ... }
A system for describing types is a type system, which is equivalent to types in a programming language. It can be used to explain a range of concepts and how concepts are connected.
By the way, if we think of a programming language as a system, then we will find interesting things in its design. Type systems and structures (or classes) can be used to build concepts in the system, and expressions are used to build relationships between concepts.
modeling
For concepts, even with so many rich developments, it is not easy to make a summary. What’s more, for the model, it is numerical standardization, a kind of model shape close to the general.
Design: Architectural Model for the First Version
So, my first attempt was to start with the definition of Pattern-Oriented Software Architecture:
class SystemArchitecture( val archStyle: ArchitectureStyle, val subSystem: List<SubSystem>, var components: List<ArchComponent>, val connections: List<ArchConnection> )
Example: For a system, it exists a primary architectural pattern, such as a microservices architecture. In each microservice is equivalent to a subsystem or component. Of course, a subsystem can contain multiple microservices. For a component, it contains input and output and a series of calculation logic. So, a model of it might look like this:
class ArchComponent( val name: String, val type: ArchComponentType, val inbounds: List<String>, val outbound: List<String>, val components: List<ArchComponent> )
The trouble is that components are dynamic, there are relationships between components, and there are relationships within components. So, how do we portray component relationships?
class Connection( val connectors: String, val source: String, val target: String, var connectionType: ConnectionType, val connectorStyles: ConnectorStyle, )
As a result, components are truly tree topologies when examined broadly. Similarly, for the architecture, this Connection also exists. According to the above series of forms, we can get an architectural model of the initial version of the architecture.
For more model-related content, see the original version of Architecture. kt in ArchGuard Scanner.
Implementation idea: generate architecture model
Models in ArchGuard are generated from code. In this business scenario, when building a model, it is necessary to balance design and implementation. Therefore, the view method based on code analysis is more suitable for us. From code and dependencies, we can:
- The hierarchical relationship is analyzed based on the directory structure, and then the structural view of the code is obtained.
- Analyze dependency management tools to get a module view.
- Analyze the dependent software, such as Spring, Dubbo, etc., and then get an execution view.
- Analyze the model in the software to get a conceptual view.
Combined, we can build a more complete architectural model.
Implementation: Abandon the first version of the model
The design was nice, but when I started writing the first line of code, something was wrong: we have an analytical model, but what about the input?
From the analysis of the project, all we get is the code of a code repository. A code repository may be a module, a system, or a service. So, what is our input? Based on the existing analysis, such as project dependencies (dependency management tools), source code structure, language, etc.? We are missing the context needed to build a project.
What we can analyze from the source code is as follows:
data class PotentialExecArch( var protocols: List<String> = listOf(), var appTypes: List<String> = listOf(), var connectorTypes: List<ConnectorType> = listOf(), var coreStacks: List<String> = listOf(), var concepts: List<CodeDataStruct> = listOf() ) Some corresponding analysis details:
Protocol information. Parse the source code and dependency information in Gradle, Maven, and NPM. If Dubbo is included, it is considered to be with RPC; if java.io.Fileit is included, it is considered to be with FileIO
Application Type. Parse dependency information, if it contains click, will be regarded as a Kotlin CLI application.
Connection Type. Ditto
core technology stack. Analyzed by dependency type.
conceptual model. The underlying layered architecture model needs to be analyzed first, and the concept set can be obtained according to the layered architecture model.
Of course, this part of the code has not been written yet, if you are interested, you are welcome to join us.
Multiple architectural models
Therefore, in the context of ArchGuard, the architectural model of “architecture” has many forms:
- The architecture model is in scanning mode (corresponding to ArchGuard Scanner). That is, the architecture model obtained from the source code of each project is calculated from the source code, dependencies, databases, etc.
- The architectural model in the analysis mode (corresponding to ArchGuard Backend). Based on the architecture model in the analysis form, an architecture model containing architecture-related knowledge is constructed.
- Architecture model in display form (corresponding to ArchGuard Frontend). Combined with visual knowledge, the corresponding architecture model is displayed.
Each model adds domain knowledge on the basis of the previous step, so what is domain knowledge? How to do the structure well?
Summary: The Challenge
The model, a start, needs to be continuously evolved to fit the needs. And with a model that can be used, it is just the beginning of this series of work, and we will encounter a series of challenges.
Delineate the target architecture
The architecture in the system only reflects the status quo. How to describe the future architecture and match the two is another very interesting topic.
Measuring variability
Another problem we will face is that software architecture is not static.
Software changes in subtle ways as long as it is being developed. On a macro level, architects try hard not to change the structure on a large scale as much as possible. And we need to face these challenges, such as infrastructure changes, and this change brings temporary intermediate states.
How to represent this temporary intermediate state becomes more interesting.
This is just the first step. If you are interested, welcome to ArchGuard to model the technology.
References
- “The Way to Clean Architecture”
- “The Beauty of Architecture”
- Software Architecture: Architectural Patterns, Characteristics, and a Practical Guide
- Pattern-Oriented Software Architecture Volume 1: Pattern Systems
- “Practical Software Architecture”
- 《Software Architecture in Industrial Applications》
- 《Architectural Blueprints—The “4+1” View Model of Software Architecture》
3 Comments