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 development in this article is based on automated analysis requirements, and the model is also based on this motivation.
What is the architecture? ?
It is not difficult to model the code of a single language, there are special concepts for a language, such as 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. As a result, Martin Fowler likes to quote Ralph Johnson, one of the GoF (authors of Design Patterns), for the description of the architecture:
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 an 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 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, and so on.
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 to combine relevant strategies and layers? From this pattern, we get an increasingly clear definition.
However, we also encountered a more difficult 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, with 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. Subsystems and components are often described using different views to show the functional and non-functional characteristics of a software system.
A component is an encapsulated part of a software system that contains an interface. Components are the building blocks used to build systems. At the programming language level, components may be represented by modules, classes, objects, or a set of related functions.
Relationships describe the connections between components, which may be static or dynamic. 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, in the 4+1 paper "Architectural Blueprints—The "4+1" View Model of Software Architecture", there is also a formula for describing the architecture: Software architecture = {Elements, Forms, Rationale/Constraints}
.
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 with the code base, which makes 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 "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.
- Execution View: Describes the dynamic elements of the system and the interactions between them.
- Code View: Describes the organization of the source code.
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, 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. For example, what we express in UML (PlantUML notation):
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 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, as well as 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, we also need to consider how to represent the relationship between components?
class Connection(
val connectors: String,
val source: String,
val target: String,
var connectionType: ConnectionType,
val connectorStyles: ConnectorStyle,
)
Therefore, if viewed in a broad definition, components are actually tree structures. 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 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 the dependency information in Gradle, Maven, and NPM. If Dubbo is included, it is regarded as with RPC; if with
java.io.File
, it is regarded as with FileIO - Application Type. Parsing dependency information, such as including
clikt
is 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 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: https://github.com/archguard/archguard/discussions/67
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"
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。