. NET application Architecture Design-Learn more about tiered architectures (the core design elements of modern enterprise application Tiering architecture)

Source: Internet
Author: User
Tags to domain

Reading folders:

  • 1. Background information
  • 2. A brief recall of the traditional three-tier architecture
  • 3. Enterprise-Class Application Tiering Architecture (the basic evolution of modern tiered architectures)
    • 3.1. Application of contractual design in the service layer to resolve dynamic condition mismatch errors (exposing problems online through contractual design patterns)
    • 3.2. Application controller mode in the application layer (the role of the application layer is instantiated through the controller mode)
    • 3.3. Command pattern in the business layer (the design pattern of transaction script mode is used, very good isolation of static data)
  • 4. The service layer is published as an SOA contract the Domainmodel of the DTO and the business layer share the primary atomic type
  • 5. Two independent business layer responsibility design methods (can be matched according to detailed business requirements)
    • 5.1. Coordinate the interaction between the data layer and the business layer in the application controller in the application layer (the business layer will be absolutely independent)
    • 5.2. The relationship of the business layer directly dependent on the data layer using IOC thought to change the data layer depends on the business layer (the business layer will be absolutely independent) (more elegant)
  • 6. Summary
1. Background information

There has been a period of exposure to layered architectures, from the beginning of a hazy understanding to a certain depth of research now. Think it necessary to share their own research results to everyone. To learn from each other is also a summary of their own.

The project structure we face every day can be said to be almost hierarchical, or a similar layered structure that evolved from a traditional three-tier architecture. Business layer, data layer is indispensable. These two layers are more important design points, it seems that these two layers are independent of each other, but how the two layers of how to design really there are many more subtle places, this article will share to everyone I have in the work of my own research to draw a more feasible design method.

2. A brief recall of the traditional three-tier architecture

In fact, I did not intend to add this section, about the traditional three-tier architecture I think everyone should understand or very familiar with, but in order to make the integrity of this article, I would like to go through the three-tier architecture, because I think it can make the introduction of the following I have coherence.

The traditional three-tier architecture refers to separating a system according to the different responsibilities of the three main layers to separate the focus, dividing a complex problem into three mutually cooperative units to complete a large task together.

1. Display layer: used to display data or to fetch data from the UI. This layer is primarily used to handle data display and special effects, and does not contain any business logic whatsoever.

2. Business layer: The business layer includes all of the core business logic in the system, excluding code logic that is related to data display and data access.

3. Data layer: used to provide access to a detailed data source engine. It is primarily used for direct access to data and does not include business logic processing.

Its useful text description of the three layers of the basic responsibility is also very easy, but different people how to understand and design these three layers on different forms, anyway, I have seen a lot of different hierarchical structure, each has its own characteristics, from a point of view are very good, but all seem a bit messy. Because there is no unified architecture model to support. The code is filled with a misplaced understanding of the layered architecture, for example: it's common to see the mix of the "things script" pattern and the "table module" pattern so that I don't know where to write the code at the end. The extracted code does not know which object to put in.

Although the layer is simple but want to use is not easy, after all, we still stand on a higher level than the general level to talk about the hierarchical structure. Once implemented into the code, it is completely different. It is very subtle to isolate layers with no interfaces, and which layer the interfaces are placed in. Of course this is not to illustrate how good the design I am introducing is. But to give you a sample that can participate in the test.

Anyway The calls between the three layers are strictly according to the "upper layer can only invoke the direct lower layer." Can not be ultra vires, and the lower layer can not call their own upper ", this is the main layer structure of the call constraints, only have such a talent to ensure a good code structure. The display layer can only invoke the business layer. The business layer can only call the data layer, in fact it is so simple, of course, the detailed code design can be summarized as two, the first is the instance class or static class directly called. The other is that each layer is coupled with an interface to isolate each layer, making it easy to test and deploy. However, assuming that the use of the bad words will add complexity, rather than directly using static classes to direct points, but the use of static classes to design business class will make multi-threaded operation very difficult to implement, a little attention will be a string value or error.

3. Enterprise-Class Application Tiering Architecture (the basic evolution of modern tiered architectures)

In the last section we have a basic understanding of the types and responsibilities of traditional three-tier architectures, and this section provides a brief introduction to the types and responsibilities of modern enterprise application tiering architectures.

As the complexity of enterprise applications is added, the existing three-tier architecture has evolved into today's enterprise-oriented tiered architectures that support new technologies and code best practices.

There is an application layer above the business layer in the traditional three-tier structure, but it is the service layer. This layer is intended to directly isolate the display layer to invoke the business layer. Because today's enterprise applications are basically moving toward the Internet. Access to business logic does not come from within the process, but across the network.

Having this layer will make the original display layer calls the business layer of the process becomes flexible very much, we can add a lot of flexibility in the inside, more importantly, the display layer and the business layer two separate layers to be completely independent, it is necessary to have a layer to assist and coordinate the interaction between them. In the first three-storey book, it actually mentions the role of "service layer" to co-ordinate, why so many of our projects have never appeared, when I see the book in the commentary after the Epiphany. (This section is able to refer to: "Enterprise Application Architecture Model", "Martin Fowler".) The second part. 9th chapter "Service Layer")

Figure 1: (Logical layering)


The design part of the service is included in the application layer. The concept of application layer is slightly larger, not only does not include the service but also includes a lot of application logic that is not related to the service. For example: Record log, coordinate infrastructure access, and so on, is to relax the service layer understanding.

Figure 2: (Project structure layering)


The "services" mentioned above are included in the application layer. Relaxing the "service layer" forms the "application layer" that is critical in today's tiered architecture. The application layer will be responsible for the overall coordination of the "business layer" and "Data layer" and "infrastructure", and of course, the environment-related things when the system executes.

3.1. Application of contractual design in the service layer to resolve dynamic condition mismatch errors (exposing problems online through contractual design patterns)

This design method is mainly to want to be dynamic execution when the condition mismatch error online self-active regression test when exposed. Because the contracts in the service layer are likely to be subject to a change of urgency, we have no way of knowing whether our online contract includes an unstable condition mismatch.

By using the contract design pattern, the contract checker can be run on its own initiative at the time of invocation, and the contract checker is divided into the pre-condition checker and the post-condition checker. Let's look at a simple example.

Using system;using system.collections.generic;using system.linq;using system.text;using System.Threading.Tasks; namespace companysourcesearch.service.contract{    using CompanySourceSearch.ServiceDto.Request;    Using CompanySourceSearch.ServiceDto.Response;     Public interface Isearchcomputer    {        getcomputerbycomputeridresponse Getcomputerbycomputerid ( Getcomputerbycomputeridrequest request);    

In the service contract, I defined an interface for querying computer resources in an enterprise. The good design principle is not to expose the query field directly but to encapsulate it.

namespace companysourcesearch.servicedto{public    abstract class Contractcheckerbase    {        private func< Bool> checkspecification;        Public func<bool> checkspecification        {            get            {                return this.checkspecification;            }            Private set            {                this.checkspecification = value;            }        }         public void Setcheckspecfication (func<bool> checker)        {            checkspecification = checker;        }         Public virtual bool Runcheck ()        {            if (checkspecification! = null)                return checkspecification ();             return false;        }    

then we define a base class to represent the contract checker, which is purely for demonstration purposes, and the code is slightly simpler. The request and response of the service contract is required to implement its own check function by inheriting the Checker class.

namespace companysourcesearch.servicedto.request{public    class Getcomputerbycomputeridrequest: Contractcheckerbase    {public        long ComputerId {get; set;}         Public Getcomputerbycomputeridrequest ()        {this            . Setcheckspecfication (() = computerid > 0/*computerid>0 Check rule */);}}    

The request class initializes the check condition to: ComputerId must be greater than 0 in the constructor.

namespace companysourcesearch.servicedto.response{    using Companysourcesearch.servicedto;     public class Getcomputerbycomputeridresponse:contractcheckerbase    {public        list<computerdto> computerlist {get; set;}         Public Getcomputerbycomputeridresponse ()        {this            . Setcheckspecfication (() = computerlist! = null && computerlist.count > 0);        }    

The same response class also initializes the condition checker in the constructor: Computerlist is not equal to null and count is greater than 0.

Or the same sentence is a simple example of the point. But the design idea is very good.

The pre-condition checker can be run in the client agent, and you can run it yourself, of course.

The post-condition checker is actually not necessary in the ordinary case, assuming you can guarantee that the data you are testing is correct, then it should be necessary to take the initiative to test. It was not easy to maintain a self-motivated test environment at that time, so it would be inappropriate to use the post-condition checker to check the dynamic environment of your data.

3.2. Application controller mode in the application layer (the role of the application layer is instantiated through the controller mode)

In most cases when application layer design we like to use static class to deal with, Static class has good code simplicity, and also can bring some performance improvement. However, there are some potential problems in the long-term thinking about static classes, and the data is not very well isolated. Repeated code is not very good to extract, unit test is not very good to write.

In order to be able to use the instance class design of the application controller for a very long period of time, such as very high project maintainability, I prefer to use "application controllers" to design. It is a very graphic representation of the responsibilities of the front-end and back-end, but it does not deal with the business logic in detail, much like the controller in MVC.

namespace companysourcesearch.applicationcontroller.interface{    using CompanySourceSearch.Service.Contract;    Using CompanySourceSearch.ServiceDto.Response;    Using CompanySourceSearch.ServiceDto.Request;     Public interface Isearchcomputerapplicationcontroller    {        getcomputerbycomputeridresponse Getcomputerbycomputerid (Getcomputerbycomputeridrequest request);    

In the application controller we define a controller interface that is responsible for the computer resources of the above query.


Namespace companysourcesearch.applicationcontroller{    using CompanySourceSearch.ApplicationController.Interface;    Using CompanySourceSearch.ServiceDto.Request;    Using CompanySourceSearch.ServiceDto.Response;     public class Searchcomputerapplicationcontroller:isearchcomputerapplicationcontroller    {        public Getcomputerbycomputeridresponse Getcomputerbycomputerid (getcomputerbycomputeridrequest request)        {            throw New NotImplementedException ();}}}    

Controller implementation class.

This allows for a very clear separation of application controllers, which is a very good provider for service implementations.

namespace companysourcesearch.serviceimplement{    using CompanySourceSearch.Service.Contract;    Using CompanySourceSearch.ServiceDto.Response;    Using CompanySourceSearch.ServiceDto.Request;    Using CompanySourceSearch.ApplicationController.Interface;     public class Searchcomputer:isearchcomputer    {        private readonly Isearchcomputerapplicationcontroller _ Searchcomputerapplicationcontroller;         Public Searchcomputer (Isearchcomputerapplicationcontroller searchcomputerapplicationcontroller)        {            this._ Searchcomputerapplicationcontroller = Searchcomputerapplicationcontroller;        }         Public Getcomputerbycomputeridresponse Getcomputerbycomputerid (getcomputerbycomputeridrequest request)        {            return _searchcomputerapplicationcontroller.getcomputerbycomputerid (Request);        }    

The service only needs to use the IOC framework to inject the controller directly into the application, but here you can add AOP to record the various logs.

By designing the controller in this way, the unit can be tested and reconstructed very well.

3.3. Command pattern in the business layer (the design pattern of transaction script mode is used, very good isolation of static data)

Most business layers in general enterprise applications are designed using the "transactional scripting" pattern, so here I think there is a very good model to draw on. However, very many transactional scripting patterns are handled using static classes, which are similar to controllers using static classes, which are simpler and easier to use. But there are still a few problems, data isolation, not easy to test the reconstruction.

The transactional script is instantiated using the command pattern. Data isolation and test refactoring are very convenient. Assuming that you are interested in implementing TDD will be a good structure.

namespace companysourcesearch.command.interface{    using Companysourcesearch.domainmodel;     Public interface Isearchcomputertransactioncommand    {        list<computer> filtercomputerresource (List< computer> computer);    

A transaction command controller interface that defines an interface for filtering computer resources.

You may have seen me use a Dominmodel namespace. This is a business unit that is related to the service and is abstracted through constant refactoring (the content of the business layer is later).


namespace companysourcesearch.command{    using CompanySourceSearch.Command.Interface;     public class Searchcomputertransactioncommand:commandbase, Isearchcomputertransactioncommand    {public        List <DomainModel.Computer> Filtercomputerresource (list<domainmodel.computer> computer)        {            throw New NotImplementedException ();        }    

Using instance classes to assemble business code will be a matter of no regrets. Here we define a commandbase class to do some encapsulation work.

The application controller is the same as the service class using the Business command object in the same way as the IOC.

Namespace companysourcesearch.applicationcontroller{    using CompanySourceSearch.ApplicationController.Interface;    Using CompanySourceSearch.ServiceDto.Request;    Using CompanySourceSearch.ServiceDto.Response;    Using CompanySourceSearch.Command.Interface;     public class Searchcomputerapplicationcontroller:isearchcomputerapplicationcontroller    {        private readonly Isearchcomputertransactioncommand _searchcomputertransactioncommand;        Public Searchcomputerapplicationcontroller (Isearchcomputertransactioncommand Searchcomputertransactioncommand)        {            This._searchcomputertransactioncommand = Searchcomputertransactioncommand;        }         Public Getcomputerbycomputeridresponse Getcomputerbycomputerid (getcomputerbycomputeridrequest request)        {            throw new NotImplementedException ();        }    

Until now, the interface-oriented programming is maintained between each layer.

4. The service layer is published as an SOA contract the Domainmodel of the DTO and the business layer share the primary atomic type

There's a paradox here that we need to balance, when we define a service contract, we define the DTO used by the service, and in the business layer we define a partial domain model for a very good aggregation of the business model, or exactly, in the framework of the transactional scripting schema, we are using a domain model that is constantly reconstructed. It encapsulates part of the domain logic.

So what if the DTO in the service and the entity in the domain model need to use the same atomic type? For example, the state of a type, and so on.

Assuming a purely isolated two level, we are fully able to define two identical sets of atomic types to use. But this will bring a lot of repetitive code, difficult to maintain. Assuming that you don't define two sets, it's not appropriate to place these shared types in a DTO, and the business model is not likely to refer to things outside. It seems a bit inappropriate to put it in the domain model.

Here I am working with an atomic type independent project. Can be similar to a project such as "CompanySourceSearch.DomainModel.ValueType", which includes only atomic value types that need to be shared with DTOs.

5. Two independent business layer responsibility design methods (can be matched according to detailed business requirements)

Before we talked about the design of the business layer, here we focus on the design of the business layer including interoperability with the data layer.

Starting from the application layer, when we need to process a certain logic from the application controller start may feel directly into the service layer, and then the service layer to call the data layer. In fact, this is just a way of designing.

The advantages of this design approach are simple and straightforward. More convenient to achieve.

However, the problem with this solution is that the business layer is always dependent on the data layer, and the changes in the business layer are still affected by the data layer.

Another problem is that if you design a business layer using a "transactional scripting" pattern, you will naturally write procedural code. Since you are not doing what the application controller was supposed to do to coordinate, it is actually used to coordinate the business layer and the data layer, we do not have to call the data layer in the business layer, but can get the data that the business layer needs from the controller and then pass it into the business layer to deal with. This and directly in the business layer to call the data layer is almost the same, just write code is not in accordance with the process of thinking to write.

Whether we are using Transactional Scripting mode or table module mode or the current more popular domain model pattern. Can be designed using such a method.

5.1. Coordinate the interaction between the data layer and the business layer in the application controller in the application layer (the business layer will be absolutely independent)We will call the data layer method in the application controller to get the data and then transform it into a domain model for processing.

namespace companysourcesearch.database.interface{    using Companysourcesearch.datasourcedto;     Public interface Icomputertablemodule    {        list<computerdto> Getcomputerbyid (long cId);    

We use the "table ingress" data layer pattern to define a method for querying computer.

namespace companysourcesearch.applicationcontroller{using CompanySourceSearch.ApplicationController.Interface;    Using CompanySourceSearch.ServiceDto.Request;    Using CompanySourceSearch.ServiceDto.Response;    Using CompanySourceSearch.Command.Interface;    Using CompanySourceSearch.Database.Interface;    Using Companysourcesearch.datasourcedto;     Using CompanySourceSearch.Application.Common; public class Searchcomputerapplicationcontroller:isearchcomputerapplicationcontroller {private ReadOnly isear        Chcomputertransactioncommand _searchcomputertransactioncommand;        Private ReadOnly Icomputertablemodule _computertablemodule;            Public Searchcomputerapplicationcontroller (Isearchcomputertransactioncommand Searchcomputertransactioncommand, Icomputertablemodule computertablemodule) {This._searchcomputertransactioncommand = SearchComputerTrans            Actioncommand;        This._computertablemodule = Computertablemodule;     }    Public Getcomputerbycomputeridresponse Getcomputerbycomputerid (Getcomputerbycomputeridrequest request) {             var result = new Getcomputerbycomputeridresponse (); var dbcomputer = This._computertablemodule.getcomputerbyid (Request. ComputerId);//Get computer collection from the data source var Dominmodel = Dbcomputer.converttodomainmodelfromdatasourcedto ();//Convert to Domain             Model var Filetedmodel = This._searchcomputertransactioncommand.filtercomputerresource (Dominmodel);//Run Business logic filter         return result; }    }}

Instead of calling the business layer's methods directly, the controller takes the data first and then runs the transformation in the business logic processing. What needs to be clarified here is. At this point I am mixing the read and write in a logical project, so most of the queries do not have the business logic to handle, directly switch to the service DTO return.

Putting read and write on a project enables a common set of business logic models. Of course it's just a personal opinion.

This is the business layer will be completely independent, we can do a full unit test, including migration and public. You can even think about the development of domain-specific frameworks.

5.2. The relationship of the business layer directly dependent on the data layer using IOC thought to change the data layer depends on the business layer (the business layer will be absolutely independent) (more elegant)

The way you use the business layer and the data layer above is probably a bit awkward, so replace it with this section.

We used to call the data layer interface in the business layer to obtain data, at this time we will directly rely on the data layer, we can learn from the IOC thinking, the business layer relies on the data layer for control inversion, so that the data layer relies on our business layer, the business layer to provide dependency injection interface, let the data layer to achieve. The data-tier instance is then injected dynamically when the business Command object is initialized.

Let's say you're used to developing projects using the things scripting pattern. It doesn't matter, you can use this mode to completely isolate the data layer, you can also try to help you in the application controller to share the peripheral functions of things script.

6. Summary

The article shares the I think that to the present more feasible enterprise application architecture design method, does not say that completely conforms to your taste. But can be a good reference, because time is related to this end, thank you.


King Qingyue Culture

Source:http://blog.csdn.net/wangqingpei557

This article is copyrighted by the author and Csdn co-owned. Welcome reprint, but without the author's permission must retain this paragraph of the statement, and in the article page obvious location to the original connection, otherwise reserves the right to hold legal responsibility.

Copyright notice: This article Bo Master original article. Blog, not reproduced without consent.

. NET application Architecture Design-Learn more about tiered architectures (the core design elements of modern enterprise application Tiering architecture)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.