Generally, the architecture is either an intangible, conceptual aspect of some software systems described in the Word documents, or completely technical-driven ("we use an XML architecture "). Both methods are terrible: the former is difficult to use, while the latter's architectural concepts are covered by technical propaganda.
Related vendor content
Bea virtualization technology frees you from worrying about computing capacity
Books: Use Visual Studio team Foundation server for team development (part 3)
IDC: SOA China Road Map Technical Analysis Report download
Dev2dev technology day: How to Use eclipse, Java, flex, and SOA in the SOA reference architecture?
Books: Use Visual Studio team Foundation server for team development (part 4)
What is a good expression? It should be that with the development of the architecture, a language is evolved to allow you to describe the system from the perspective of the architecture. Based on my experience in multiple real projects, this expression can visually and without ambiguity describe the architecture construction module and the specific system, at the same time, it will not go deep into the technical decision details (technical decisions should be consciously placed in another separate step ).
The first part of this thesis demonstrates this idea through a real story. The second part summarizes the key points of this method.
Background of a story System
I am working with a customer who is one of my clients responsible for regular consulting. The customer decided to build a brand new aviation management system. Airlines use this system to track and publish different information, such as whether the plane lands at the specified airport, whether the flight is delayed, and the technical status of the plane. The system also provides data for the internet online tracking system and information monitors set up at airports. In any aspect, the system belongs to a typical distributed system, and each part of the system runs on different machines. It has a central data center responsible for processing heavy numeric operations, and other machines are distributed in a relatively broad area. Over the years, my customers have been building systems like this, and now they plan to introduce a new generation of systems. The new system must support 15-20 years of evolution. From this demand alone, we can clearly see that they need to abstract the technology, because during the 15-20 years, there may be eight technological changes. Another important reason for abstracting technology is that different parts of the system are built using different technologies, including Java, C ++, and C #. Using multiple technologies is not a special requirement for large-scale distributed systems. In general, we will use Java technology at the backend, And. NET technology at the front end of windows.
Because of the distributed nature of the system, it is impossible to update all components of the system at the same time. This creates another requirement that the system can be updated in part. This in turn requires the ability to manage version conflicts between components of different systems (ensure that component A can still work with it after component B is upgraded to a new version ).
Start Point
When I enter the project, they have decided that the backbone of the system should be a message transmission-based infrastructure (this is a good decision for such systems ), they also evaluated the performance and throughput of different message transmission trunks. They have determined to use a Business Object Model in the entire system to describe system operation data (for such systems, this is actually not a good decision, but it does not affect the conclusion of this story ).
So when I entered the project, they gave me a brief introduction to all the details of the system, as well as the architectural decisions they had made, and asked me if these decisions were correct. However, I soon discovered that although they have understood a lot of requirements and made meticulous decisions on some aspects of the architecture, they have not formed what I said.Consistent Architecture(Consistent architecture): defines the building modules of the actual system, that is, the various things in the system. They have no idea about this system.Language.
In fact, this is just a preliminary impression of my entry into the project. Of course, I think there isHugeProblem: if you do not know what makes up the systemVarious thingsIt is difficult to talk about and describe the system in a consistent manner. Of course, we cannot build the system in a consistent manner. You need to define a language.
Background: What is the language?
When you haveOne LanguageAnd you have a consistent architecture 1 when talking about the system from the perspective of architecture. What is the language? Obviously, it is at least a set of well-defined terms.Well definedFirst, it means that all stakeholders must agree with the meaning of the term. From an informal perspective, the meaning of terms and terms may be enough to define a language.
However, it may seem a little abrupt here-what I have always advocated is to useFormalLanguage to describe architecture 2. To define a formal language, you need more than just the meaning of terms and terms. You also need a syntax to describe how to use these terms to form a "statement" (or model). At the same time, you need a specific syntax to represent them 3.
Using a formal language to describe your architecture will bring many benefits. As the story expands, these benefits will also be exposed. At the same time, I will summarize it at the end of this article.
Develop a language to describe the architecture
Let's continue with this story. Both my customers and I agree that it is worthwhile to spend a day reviewing certain technical requirements and building a formal language for the architecture to reflect these needs. In fact, while discussing the entire architecture, we construct the syntax, some constraints, and an editor (using the oaw xtext tool ).
Start
We start with the concept of components. Our definition of the component concept is relatively loose. It is only the smallest unit of the construction module related to the architecture and encapsulates the functions of the application. At the same time, we assume that the component can be instantiated so that the component concepts in the architecture correspond to classes in OO programming. Therefore, according to the initial syntax we define, the first model constructed should be like this:
component DelayCalculator {}
component InfoScreen {}
component AircraftModule {}
Note: here we did two things: we first defined the existence of the system.ComponentsThe concept (making components the building module of the system we want to build). Secondly, we (initially) Decide that there are three components in the system.Delaycalculator,InfoscreenAndAircraftmodule. We propose a set of building modules for the architecture, as a conceptual architecture, and use a set of specific templates of these building modules as applications.Architecture4.
Interface
Of course, the above concepts about components are not very useful because components cannot interact. The domain logic clearly shows that,DelaycalculatorMust receive fromAircraftmodulesTo calculate the flight delay status, and then forward the resultInfoscreens. We know that they should exchange information in some way (remember: a message transfer decision has been made ). However, we decided not to introduce messages, but to abstract a group of related messages as interface 5.
component DelayCalculator implements IDelayCalculator {}
component InfoScreen implements IInfoScreen {}
component AircraftModule implements IAircraftModule {}
interface IDelayCalculator {}
interface IInfoScreen {}
interface IAircraftModule {}
We realized that the above Code looks a bit like Java code. Don't be surprised. Since my customers have a Java background, the preferred target language for the system is Java. Therefore, we need to extract the well-known concepts from the languages they are used to derived from our own language. However, we soon noticed that this representation is not very useful: we cannot indicate that the component "uses a specific interface (relative to the provided Interface )". It is important to know which interfaces a component needs, because we want to understand (and then use tools for analysis) the dependencies of components. This is important for any system, and especially for version management.
Therefore, the syntax can be modified as follows:
component DelayCalculator {
provides IDelayCalculator
requires IInfoScreen
}
component InfoScreen {
provides IInfoScreen
}
component AircraftModule {
provides IAircraftModule
requires IDelayCalculator
}
interface IDelayCalculator {}
interface IInfoScreen {}
interface IAircraftModule {}
Description System
Let's take a look at how these components are used. We clearly understand that components need to support instantiation. Apparently, there are many planes in the system, each of which runsAircraftmoduleComponents, whileInfoscreensMore instances. It is not clear whether we need multipleDelaycalculatorsBut we decided to postpone the discussion of it and first deal with the problem of Instantiation.
Therefore, we need to be able to represent the instantiation of components.
instance screen1: InfoScreen
instance screen2: InfoScreen
...
Next, we discussed how to connect instances of the system to the online environment: how to expressInfoscreenWithDelaycalculator"Talk "? We must find a way to represent the relationship between instances. Because both types have compatible interfaces,DelaycalculatorYou canInfoscreen"Talk ". However, it is difficult to grasp the "conversation" relationship for the time being. We also noticed thatDelaycalculatorAn instance is usually associated with multipleInfoscreenInstance "dialog ". Therefore, we must introduce subscript in a language to indicate the number of instances.
After several modifications, I introducedPort(In fact, this is a well-known concept in component technology and UML, but it is a new term for my customers ). A port is a communication endpoint defined on the component type. When a component with a port is instantiated, the port is also instantiated. Therefore, we reconstruct the Component Description Language to support the following representation. Port passedProvidesAndRequiresKeyword, followed by the name and subscript of the port, a colon, and the interface associated with the port.
component DelayCalculator {
provides default: IDelayCalculator
requires screens[0..n]: IInfoScreen
}
component InfoScreen {
provides default: IInfoScreen
}
component AircraftModule {
provides default: IAircraftModule
requires calculator[1]: IDelayCalculator
}
The above model indicates that anyDelaycalculatorMultiple instances must be connected.Infoscreens. SlaveDelaycalculatorFrom the code perspectiveScreenPort can access a groupInfoscreen. WhileAircraftmoduleOnly oneDelaycalculator"Dialog", as shown in subscript [1.
The New Interface ID inspired my customersIdelaycalculatorModified because they noticed that there should be different interfaces for different communication objects (so there should be different ports ). We have made the following changes to the application architecture:
component DelayCalculator {
provides aircraft: IAircraftStatus
provides managementConsole: IManagementConsole
requires screens[0..n]: IInfoScreen
}
component Manager {
requires backend[1]: IManagementConsole
}
component InfoScreen {
provides default: IInfoScreen
}
component AircraftModule {
requires calculator[1]: IAircraftStatus
}
Note that the introduction of ports improves the application architecture because we have interfaces that reflect roles (Iaircraftstatus, imanagementconsole).
Now we have a port, so we canNameCommunication endpoint. This makes it easy for us to figure out the system: interconnected component instances. Note that a new structure is introduced.Connect.
instance dc: DelayCalculator
instance screen1: InfoScreen
instance screen2: InfoScreen
connect dc.screens to (screen1.default, screen2.default)
Maintain a general picture
Of course, in some cases, in order not to confuse all components, instances, and connectors, we undoubtedly need to introduce some namespace concept. Naturally, we can also place the content in different files (the tool supports ensuring that "go to definition" and "Search for reference" are still normal ).
namespace com.mycompany {
namespace datacenter {
component DelayCalculator {
provides aircraft: IAircraftStatus
provides managementConsole: IManagementConsole
requires screens[0..n]: IInfoScreen
}
component Manager {
requires backend[1]: IManagementConsole
}
}
namespace mobile {
component InfoScreen {
provides default: IInfoScreen
}
component AircraftModule {
requires calculator[1]: IAircraftStatus
}
}
}
Of course, separating the definition of components and interfaces (essentially the definition of types) from the definition of systems (connected instances) is a good idea, A system is defined as follows:
namespace com.mycompany.test {
system testSystem {
instance dc: DelayCalculator
instance screen1: InfoScreen
instance screen2: InfoScreen
connect dc.screens to (screen1.default, screen2.default)
}
}
In a real system,DelaycalculatorAll availableInfoscreens. It makes no sense to manually describe these connections. Therefore, we need to move on. We have defined a query that can be executed at runtime using the infrastructure of naming/trader/lookup/Registry. The query is executed once every 60 seconds to find any online infoscreens.
namespace com.mycompany.production {
instance dc: DelayCalculator
// InfoScreen instances are created and
// started in other configurations
dynamic connect dc.screens every 60 query {
type = IInfoScreen
status = active
}
}
Similar methods can be used to achieve load balancing or fault tolerance. A static connector can point to a primary instance and backup instance. Alternatively, you can run a dynamic query again when the currently used component Instance becomes unavailable.
To support instance registration, we have added additional syntaxes to their definitions. OneRegisteredThe instance automatically registers itself using its own name (identified by namespace) and all provided interfaces in the registration record. You can also specify additional parameters.DelaycalculatorA primary instance and a backup instance are registered.
namespace com.mycompany.datacenter {
registered instance dc1: DelayCalculator {
registration parameters {role = primary}
}
registered instance dc2: DelayCalculator {
registration parameters {role = backup}
}
}
Part 2: Interface
So far, we have not really defined what an interface is. We know that we prefer to build a system based on a messaging infrastructure. Therefore, interfaces must be defined as a set of messages. So we came up with our original idea: a set of messages, each of which has a name and a set of typed parameters.
interface IInfoScreen {
message expectedAircraftArrivalUpdate(id: ID, time: Time)
message flightCancelled(flightID: ID)
...
}
Of course, you also need the ability to define data structures. Therefore, we added the following content:
typedef long ID
struct Time {
hour: int
min: int
seconds: int
}
After a period of discussion on the interface, it is far from enough to define the interface as a group of messages. The minimum requirement we want to achieve is to define the message direction: it isInboundPort orOutboundPort? Or, more generally, what message interaction modes exist in the system? We have identified several. Here isOnewayAndRequest-replyExample:
interface IAircraftStatus {
oneway message reportPosition(aircraft: ID, pos: Position )
request-reply message reportProblem {
request (aircraft: ID, problem: Problem, comment: String)
reply (repairProcedure: ID)
}
}
Is it a message?
We have discussed various message interaction modes for a long time. Obviously, one of the core use cases of a message is to update the status of various resources and send them to the following parts. For example, if a flight is delayed due to a technical problem of the plane, the information will be sent to allInfoscreens. We have created several types of message prototypes required for the "broadcast" complete update, incremental update, and invalid update Methods of an exact status item.
However, the reality has brought us a heavy blow: we have been working in a wrong abstraction! Although message transmission is a suitable transmission abstraction for these issues, what we really talk about isReplicated Data Structure(Replicated Data Structures). Basically, all these structures work in the same way:
- Defines a data structure (for exampleFlightinfo).
- The system keeps track of such a set of data structures.
- A Data Structure is updated by several components. Generally, this data structure is read by many other components.
- The update policy from the publisher to the receiver always includes complete updates to all items in the data structure of the set, incremental updates to one or more items, and invalid updates.
Of course, once we understand that in addition to messages, the system also includes additional core abstractions, we should add it to our architecture language, and can be written in the following way. We have defined the data structure and replication items. The component can then publish (publish) or use (consume) the replicated data structure.
struct FlightInfo {
from: Airport
to: Airport
scheduled: Time
expected: Time
...
}
replicated singleton flights {
flights: FlightInfo[]
}
component DelayCalculator {
publishes flights
}
component InfoScreen {
consumes flights
}
Undoubtedly, the above description is more accurate than the message-based description. The system automatically generates all kinds of messages required, such as complete update, incremental update, and invalid update. This description also clearly reflects the actual architectural intent: compared to a lower-level description that only expresses how we want to do (send status update messages, the new description better expresses what we want to do (replication status ).
Of course, we cannot stop. Now we have the status replication as a "first-class citizen" to add more information to its technical specifications:
component DelayCalculator {
publishes flights { publication = onchange }
}
component InfoScreen {
consumes flights { init = all update = every(60) }
}
The example above means that as long as the content of the underlying data structure changes, the publisher will publish the copied data. However,InfoscreenYou only need to perform an update every 60 seconds (when it is started, it will perform a complete loading of data ). Based on this information, we can produce all the required messages and generate an update schedule for the participants.
More content?
In the remaining discussion, we identified several other aspects of the architecture and added language abstraction for them:
- To solve version conflicts, we have added a method to specify an existing component to be executed in the new version (replace) mode. The tool ensures "plug-and-play compatibility ".
- In order to be able to express the semantics of messages and their impact on the system status, we have introduced preconditions and preconditions. We have also expanded the concept of components to use stateful as an option.
- Finally, we added configurable parameters for the component. The component specifies parameters, and the component instance must specify values for them.
Conclusion
Using this method, we can quickly grasp the overall architecture of the system. Therefore, we can separate "what do we want the system to do" and "how the system implements it, the technical discussion only refers to the conceptual description provided here to provide implementation details (of course very important implementation details ). We understand the meaning of different terms and give a clear definition. The vague concept of components has a formal and clearly defined meaning in this system.
Of course, it does not end here. Next we will discuss how to encode the component implementation and discuss which part of the system can be automatically generated. For more information, see the next section.
Summary & advantages what have we done
This includes defining a formal language for the conceptual architecture of a project or system. With your in-depth understanding of the architecture, you gradually developed the language. Therefore, the language always corresponds to your complete and clear understanding of the architecture. As we enhance our language, we can use it to describe the application architecture.
Background: DSL
The language we established earlier is a DSL-domain-specific language. The following is my definition of dsls:
DSL is a well-defined and processable language. It can be used to describe a specific focus when we build a system in a specific field. The abstraction and identifier used by it are customized for the stakeholders who specify specific concerns.
Dsls can be used to specify various aspects of the software system. One major aspect is that DSL can be used to describe business functions (for example, calculation rules in the insurance system ). DSL, especially when describing business functions, times its value. Similarly, it is completely worth describing the software architecture with DSL: as we have done here.
Therefore, the architecture language we previously built-and the method I have proposed in this article-has the significance of using DSL technology to define a DSL that describes a specific architecture.
Advantages
Everyone involved can clearly understand the concepts used to describe the system. Provide clear words to describe applications. The created model can be analyzed and used as the basis for code generation (as shown below. Architecture is always unrelated to implementation details, or in other words: the conceptual architecture is decoupled from technical decisions, making them easier for their respective evolutionary development. We can also define a clear programming model based on the conceptual architecture (how to model and encode components using all the previously defined architectural features ). Finally, the architect can directly contribute to the project by building (or helping build) The work pieces that the rest of the team can actually use.
Why text format?
...... Or why not use a Graphic Logo? Text-based dsls has several advantages. First, it is easier to build a language and a good editor. Secondly, text-based artifacts are easier to integrate into existing development tools (CVS/SVN diff/merge) than graphical model libraries. Third, text-based dsls are generally easier for developers to accept, because "Real developers do not draw pictures ".
For some aspects of the system, you can use tools like graphviz or prefuse to identify the relationship between architectural elements. Since the Model contains relevant data in a clear and clean form, we can easily export the model data into a form that graphviz or prefuse can read.
Tools
To make the method described above feasible, you need to use tools to support the efficient definition of dsls. We use openubuntureware xtext. Xtext can do the following for you:
- It provides a way to define the syntax.
- According to the syntax, the tool generates an anlr syntax to complete the actual parsing.
- It will also generate an EMF ecore meta-model; the generated parser will instantiate the meta-model obtained from the language sentence. Then, you can use all EMF-based tools to process these models.
- You can also specify Constraints Based on the generated ecore model. Constraints can be specified using the oaw check language (essentially a simplified OCl.
- Finally, the tool can generate a powerful editor for your DSL. It provides code folding, syntax coloring, And customizable Code Completion functions, as well as an overall summary view and cross-FileGo-to-Definition)AndFind reference). It can also evaluate your language constraints in real time and output error messages.
After a little practice, you can master xtext, which allows you to design languages based on your understanding of the Architecture details and architectural decisions. It may take a long time to customize the code to complete the function, but you can do it again when you are exploring the language.
Verification Model
To formally and accurately describe an architecture, in addition to syntax, we also need to implement verification rules to constrain the model. Simple examples include typical name uniqueness constraints, type checks, and non-null checks. To express these (relative) local constraints, you can directly use OCL or a language similar to OCL.
However, we still need to verify that it is more complex and not so local constraints. For example, in the previous story, the constraints check whether the new versions of components and interfaces are actually compatible with their old versions, so they can be used in the same context. To implement such an important constraint, there are two preconditions:
- Constraints must be descriptive in form, that is, there must be an algorithm that can determine whether the constraints are met. Once you understand this algorithm, you can implement it without considering which constraint language your tool supports (in our example, the constraint language is similar to OCL xtend or Java)
- Another precondition is the data required to run the aforementioned constraint detection algorithm, which must be actually available in the model. For example, if you want to verify whether a specific deployment scheme is feasible, you must put the available network bandwidth, the exact time of the message, and the length of the basic date type in the model 6. Capturing this data sounds a burden, but it is actually an advantage because it is the core architectural knowledge.
Generate code
From this paper, we can gradually clearly understand the key advantages of developing architecture DSL (and using DSL): to clearly understand concepts and formally define them. It helps you understand your system and remove unnecessary technical interference.
Of course, now we have a formal model of the conceptual architecture and a formal description of the system we are building (using language-defined statements (or models )), we will use it to get more benefits:
- We will generate an API for the implementation code. This API is powerful, considering various message transmission paradigms, replication statuses, and so on. The generated API allows developers to encode the implementation in a way that does not depend on any technical decision. The generated API hides the content related to the component implementation code. We will call the entire API and a set of terminologies used for programming models.
- Remember, we expect to run components through a certain component container or middleware platform. Therefore, we use the selected implementation technology to generate the Code necessary to run the component (and the technically neutral implementation of the component. We call this layer of code as the technical ing code (or the Code [glue Code]). It usually also contains configuration files for various related platforms. Sometimes, it also requires an additional "mix in models" to specify the configuration details for the platform. The builder will adopt the best practices of the technologies that developers decide to use.
Of course, an API is generated for multiple target languages (components can be implemented in multiple languages) and/or multiple target platforms (the same component can be executed on different middleware platforms) it is completely feasible to generate the glue code. This well supports the possible multi-platform needs and also provides a way for the infrastructure to expand or evolve over time.
It is also worth noting that you should generally generate code in several stages: the first stage is to generate API code using Type Definitions (components, data structures, and interfaces, in this way, you can encode the implementation. The second stage is to generate the glue code and system configuration code. Finally, it is wise to separate the type definitions from the system definitions in the model: they will be used at different times throughout the process, it is usually created, modified, and processed by different people.
In general, the generated code supports effective, independent technical implementation, and can hide most of the potential technical complexity, making development more efficient.
How to compare it with ADLs and UML
It is not a new idea to describe the architecture in formal languages. We recommend that you use the architecture Description Language (ADLs) or the Unified Modeling Language (UML) to describe the architecture. Some can even generate code from the result model. However, all these methods advocate the useExisting generalLanguage to record the architecture (although some languages can be customized, including UML ).
However (You may see the story above)This completely ignores the focus!I have not seen how much benefit this kind of architecture description can bring to a predefined/standardized language-provided (usually very limited) structure. In the methods described in this paper, one of the core activities is actualBuild your own language to capture the system's conceptual architecture. Adapting your architecture to the concepts provided by ADL or UML is not very helpful for architecture design.
About UML Profile: Yes. You can use the method described above to create a UML profile instead of a text language. I used this method in many projects and concluded that it does not work well in most environments. The reason is as follows:
- When using UML, you need to think more about how to use the existing structure of UML to accurately express your intent and not focus on your architectural concepts. This is an incorrect method of attention!
- In addition, UML tools cannot be integrated with your existing development infrastructure (Editor, CVS/SVN, diff/merge. In an analysis or design phase, using UML won't cause too many problems, but once you use your model as the source code (they actually reflect the system architecture, using them to generate real code) will become a big problem.
- Finally, UML tools are often complex and heavyweight. They are often considered by "real" developers as "bloated software" or "Drawing tools ". Using a good text language can lower the acceptance threshold.
Why not use programming languages directly?
Architecture abstraction, such as messaging or components, is not a "first-class citizen" in today's 3rd-generation programming languages ". Of course, you can use classes to represent them. Using annotations (also known as features), you can even associate metadata with other content (operations and fields) of classes and classes ). Therefore, you can always use the third-generation language to express the content. However, this method has the following problems:
- As in the preceding UML example, this method forces you to harden clear domain-specific concepts into pre-built abstractions. In many ways, annotations/features are nothing more than the stereotype and tagged value of UML. you will encounter similar problems.
- The availability of the model is limited. Although tools such as spoon for Java can analyze models, this analysis is not easier to process than a formal model.
- Finally, using "architecture-enhanced Java or C #" to express the architecture also means that you try to confuse the architectural focus and implementation focus. This will make this distinct distinction turbid and may increase the reliance on technology.
My views on Components
There are many (or formal or informal) definitions of components. Components can be defined from the building module of the software system to the objects with explicit contextual dependencies, to the objects that contain the business logic and run in the container.
I understand that (note, I am not saying that I have put forward a real definition) components are the smallest Architecture building module. When defining the system architecture, you do not need to pay attention to the internal components. Components must specify their Schema-related attributes in a declarative manner (that is, they are specified in metadata or model mode ). Therefore, components can be analyzed and combined using tools. Generally, they all run in the container, and the container is embodied in the framework, processing the runtime-related part of the metadata. The layer at which the container provides technical services (such as logs, monitoring, and Failover) is the boundary of components.
I have no specific requirements on the metadata actually contained by the component (and what attributes the metadata describes. In my opinion, the concept of a component must be defined for each (System/platform/product type) architecture. In fact, this is what we want to do through the language method described earlier.
Component implementation
By default, all components are implemented manually. The implementation code can be compiled based on the previously generated API code. To add manually written code to the skeleton of a component, the developer can directly add the code to the generated class, or -- a better way is to use a combination such as inheritance or partial class ).
There are other alternative methods to implement components. They do not use the 3rd-generation programming language, but adopt special formal means for the behavior to be described.
- Common behaviors can be implemented by generators. You only need to set a small number of well-defined parameters in the model and parameterize them before using the generator. Feature models is good at expressing the diversity of features that need to be judged so that the implemented content can be generated.
- You can use a state machine for state-based behaviors.
- For content such as business rules, you can define a DSL to express these rules directly and use the rules engine to perform operations on them. Multiple rule engines are available now.
- For domain-specific calculations, such as common situations in the insurance field, you may need to provide a special notation to support the mathematical operations required by the domain. Such a language is usually interpreted: the technical implementation of components includes an interpreter used to parameterize the running program.
You can also use the action semantic language (ASLs) as an alternative. However, it is important to note that the language does not provide domain-specific abstraction, but uses the same method as a general modeling language, such as UML. However, if you use a more specific TAG method, you still need to specify the behavior of small fragments in general. A good example is the action in the state machine.
In order to effectively combine the concept of components to define the behavior of various methods, you can use meta-hierarchical subclass to define various components, each component has its own set of representations to define behavior. This principle is illustrated.
Technically, component implementation is related to behavior. Therefore, it is effective to use an interpreter encapsulated in the component.
Finally, it is worth mentioning that we need to realize that the content discussed in this section only covers the specific behavior of the application, rather than all the implementation code. A large amount of implementation code is closely related to the technical infrastructure of the application-remote processing, persistence, and workflow-and they can all be derived from the architecture model.
Role
In today's software engineering practices, pattern is a very important part. For repeated problems, the model is a verified and effective solution. The applicability, advantages and disadvantages, and consequences of the model are verified. So what role does the model play in the method described above?
- The schema and schema language describe the blueprints of Some architectures that have been successfully used. They can inspire you to build your own system architecture. Once you decide to use a pattern (and adjust it to apply it to your specific context), you can make the concept defined in the pattern a "first-class citizen" in the DSL ". In other words, the pattern affects the architecture and the DSL syntax.
- As the name suggests, the design mode is more specific than the architecture mode and closer to the specific implementation. Although the design pattern cannot eventually become the central concept of the Architecture DSL, when the model is used to generate code, the code generated by your code generator is usually similar to some pattern structures. However, it should be noted that the generator cannot decide whether to apply a certain mode: This requires (generator) developers to manually make a trade-off.
When talking about dsls, code generation, and pattern, you must mention that you cannot fully automate the pattern! A mode is not a solution that only contains UML charts. There is a large article in the definition of patterns to explain the power of patterns, when the patterns can be applied, when the patterns should not be applied, and what results will be brought about by the patterns. The pattern document usually records multiple variants of the pattern, each of which has different advantages and disadvantages. If the environment is special, developers must take this into consideration when implementing the model, evaluate them, and make decisions accordingly.
What content needs to be recorded in the document?
I have been advocating that these methods can be used as a way to formally describe system concepts and application architectures. Therefore, it means that it plays a certain document role, right?
Yes, but this does not mean that you do not need to include any other content in the document. You still need to archive the following content:
- Basic principles/architecture Decision-Making: Dsls describes the outline of the architecture, but does not explain the cause. You still need to archive the basic principles and technical decisions of the architecture. Generally, the relevant (non-functional) requirements should be pointed out here as the basis. Note that the DSL syntax of the architecture is very good. In the DSL syntax of the architecture, each structure is derived from a large number of architecture decisions. Therefore, if you explain why each syntax element has a place (and why other alternatives are not selected), you can record important architecture decisions. Similar methods can also be used in the application architecture, that is, DSL instances.
- User Guide: The syntax of a language can be used as a well-defined formal method for obtaining the architecture, but it is not a good teaching tool. Therefore, you need to create guidance documents for your users (application programmers) on how to use the architecture. It includes the content and method of modeling (using DSL), how to generate code, and how to use the programming model (how to populate the implementation code with the generated framework ).
There are still many aspects of the architecture that may be worth editing, but the above two points are the most important.
Further reading
If you like the methods described in this article, you may need to read the architecture model I have compiled. They continue the model topics in this article and provide a theoretical basis for the content introduced in this article. Although this paper is a bit old, the topics are basically the same. You can obtain http://www.voelter.de/data/pub/ubunturepatterns.htm at the address below.
Another thing worth understanding is the complete knowledge of specific language and model-driven software development in the domain. I have written many articles about this. The most important one is 《Model-Driven Software DevelopmentCollaborators in the book-from which you can learn aboutTechnology,Engineering,Management. For more information, visit: http://www.voelter.de/publications/books-mdsd-en.html.
Of course, you usually need to learn more about eclipse modeling, openubuntureware, and xtext. On eclipse.org/gmt/oaw, you can upload a large amount of related information to cover official oawdocuments.
Thank you
I would like to thank Iris groher, Alex chatziparaskewas, Axel Uhl, Michael Kircher, Tom quas, and Stefan tilkov for their wonderful comments on the previous version of this paper.
About the author
Markus völter is an independent consultant and coach in software technology and software engineering. He focuses on software architecture, model-driven software development, domain-specific languages, and product line engineering ). Markus has written many magazine articles, books, and various models in the middleware and model-driven software development field (Cooperation. He often speaks at various world conferences. You can send him an email voelter@acm.org or visit www.voelter.de to get in touch with him.
- Eric Evans is talking about the domain language, which is a language provided for the business functions of the domain and system. This is of course very important, but in this article, I am talking about the language for the architecture.
- No, I'm not talking about ADLs or UML. Next, let's look at it.
- You also need some tools to use this language to write sentences. More content is later.
- It also implies that this method is especially applicable to large systems, product lines, and platforms.
- It is not easy to draw a group of specific components, define the responsibilities of components, and then generate their interfaces. Technologies similar to CRC cards are very useful here.
- In fact, you may put them in different files, so this aspect will not cause pollution to the core model. However, this is a tool issue.
View Original English text:Architecture as language: a story
Note: The above content comes from the Internet and I am not liable for any joint liability.
Article transferred from: http://www.infoq.com/cn/articles/architecture-as-language-a-story