. NET application Architecture design-re-understanding the layered architecture (core design elements of modern enterprise application Tiering architecture)

Source: Internet
Author: User
Tags log log to domain

Read the catalogue:

  • 1. Background information
  • 2. A brief review 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. The command pattern in the business layer (the design pattern of the transaction script pattern is applied, and the static data is well isolated)
  • 4. The service layer is published as an SOA contract the Domainmodel of the DTO and the business layer share basic atomic types
  • 5. Two independent business layer responsibility design methods (can be matched to specific 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. Use IOC ideas to change the data layer's dependence on the business layer directly depending on the data layer (the business layer will be absolutely independent) (more elegant)
  • 6. Summary
1. Background information

Contact layered architecture for a while, from the beginning of hazy understanding to a certain depth of research now, feel the need to share their research results to everyone, learn from each other, but also a summary of their own.

The project structure we face every day can be said to be almost hierarchical structure, or based on the traditional three-tier architecture evolved similar hierarchical structure, the business layer, the data layer, these two layers is a more important design point, it seems that these two layers are independent of each other, but how the two layer design really there are many more subtle places, This article will share with you some of the more feasible design methods that I have come up with in my work including my own research.

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

In fact, this section I did not intend to add, 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 simply over 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 dividing a system into three basic layers according to different responsibilities, separating a complex problem into three mutually cooperative units to accomplish a large task together.

1. Display layer: used to display data or fetch data from the UI, which is primarily used for data display and special effects, and does not include any business logic.

2. Business layer: The business layer contains all of the core business logic in the system, and does not include any code logic related to data display and data access.

3. Data layer: used to provide access to specific data source engines, primarily for direct access to data, excluding business logic processing.

In fact, the basic responsibility of describing the three layers of this is relatively easy, but different people how to understand and design these three layers are different, anyway, I have seen a lot of different hierarchical structure, each has its own characteristics, from a certain 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 an understanding of the layered architecture, such as: often see the "thing Script" mode and "Table module" mode mashup use, resulting in I do not know where to write the code, the extracted code does not know which object to put in.

Although the layer is simple but to use the very difficult, after all, we still stand in a relatively high level of the general level to talk about the hierarchical structure, once implemented into the code is completely different, with no interface to isolate the layers, the interface placed in which layer, these are very subtle, Of course this article is not to illustrate how good the design I have introduced, but to give you a reference to the example.

To get to the bottom, three layers of calls to strictly follow the "upper layer can only call directly below, not ultra vires, and the lower level can not call their own upper layer", this is the basic structure of the call constraints, only in order to ensure a good code structure. The display layer can only call the business layer, the business layer can only call the data layer, in fact, it is so simple, of course, the specific code design can be summarized as two, the first is the instance class or static class directly call; the second is to separate each layer with an interface to isolate each layer, making testing, deployment easy, But if the use of bad words will increase the complexity of the effect is not as straightforward as using static classes directly, but the use of static classes to design business class will make multi-threaded operations difficult to implement, a little attention will be a string of values or errors.

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 the traditional three-tier architecture, and this section provides a brief introduction to the types and responsibilities of modern enterprise application tiering architectures.

As the complexity of enterprise applications increases, the existing three-tier architecture has evolved into an enterprise-level tiered architecture that supports new technologies and code best practices.

In the traditional three-tier structure of the business layer is more than an application layer is also said to be a service layer, the layer is to directly isolate the display layer to invoke the business layer, because today's enterprise applications are basically in the direction of the Internet, the business logic access will not be accessed from within the process, but need to cross the network.

With this layer will let the original display layer calls the business layer of the process becomes more flexible, 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 structure of the book in fact also referred to the "service layer" to coordinate the role, why many of our projects have not appeared, when I saw the book on the explanation after the epiphany. (This section can refer to: "Enterprise Application Architecture Model" "Martin Fowler"; Part II, 9th "service layer")

Figure 1: (Logical layering)


The application layer contains the design part of the service, the application layer concept is slightly larger, not only does not include the service also contains a lot of services unrelated to the application logic, such as: log log, coordinate infrastructure access and so on, is the service layer relaxed understanding.

Figure 2: (Project structure layering)


In the application layer is included in the above-mentioned "service", the "service layer" relaxed after the formation of the current hierarchical structure of the critical "application layer." The application layer will be responsible for the overall coordination of the "business layer" and "Data layer" and "infrastructure", and of course the system runtime environment-related things.

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 expose the dynamic runtime condition mismatch error to the automated regression test on line. Because contracts in the service layer may be at risk of being modified, we have no way of knowing whether our online contract contains a risk of unstable conditions mismatch.

By using the contract design pattern, the contract checker can be executed automatically 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 define an interface for querying the computer resources in an enterprise, and the good design principle is not to directly expose the query fields but to encapsulate them.

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 a little bit 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. The example of that sentence is simple, but the design idea is very good.

The execution of the pre-condition checker can be performed in the client agent, but you can do it yourself. The post-condition checker is not required in general, and if you can guarantee that the data you are testing is correct, then as an automated test, it is not easy to maintain an automated test environment, so it is not appropriate 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, but also can bring some performance improvement. However, in the long run, there are some potential problems in static classes, the data can not be well isolated, duplicate 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 long period of time, such as Project maintainability, I prefer to use "application controllers" to design. It is an image of the coordination of the front-end and back-end responsibilities, but specifically do not handle business logic, and MVC in the controller very much like.

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 can be very clear separation of the application controller, so that the service implementation is a very good provider.

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, of course, here you can add AOP to record various logs.

Unit testing and refactoring can be done well by designing the controller in such a way.

3.3. The command pattern in the business layer (the design pattern of the transaction script pattern is applied, and the static data is well isolated)

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, many transactional scripting patterns are handled using static classes, which are similar to controllers using static classes, and the code is simple and easy to use. But there are still several problems, data isolation, not easy to test refactoring.

It is convenient to use the command pattern for transactional scripting, data isolation, and test refactoring, which is a good structure if you are interested in implementing TDD.

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. A Dominmodel namespace is used, which is a business-related unit that is abstracted through constant refactoring (the content of the business layer is later discussed).

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

Assembly of business code using instance classes will be a matter of no regrets, here we define a commandbase class to do some encapsulation work.

The application controller also uses the Business Command object in the same way as the service class using 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 ();        }    

So far each layer insists on using interface-oriented programming.

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

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 or a precise point, 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 needs to use the same atomic type as the entity in the domain model? such as a certain type of state and so on.

If we were to isolate two levels purely, we could define two identical atomic types to use, but that would create a lot of repetitive code and would be difficult to maintain. If you do not define two sets then where to put these shared types is appropriate, put in a dto display inappropriate, the business model is not possible to reference outside things, if placed in the domain model seems to be a bit inappropriate.

Here I'm dealing with an atomic type independent project, which can be similar to a project like "CompanySourceSearch.DomainModel.ValueType", which contains only atomic value types that need to be shared with DTOs.

5. Two independent business layer responsibility design methods (can be matched to specific 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 deal with some logic from the application controller may be considered directly into the service layer, and then the service layer to call the data layer, in fact, this is just a way of design. The advantages of such design are simple and clear, easy to implement. But the problem with this approach is that the business layer is always dependent on the data tier, and the changes in the business layer are still affected by the data layer. Another problem is that if you use the "transactional scripting" mode to design the business layer, you will naturally write the process code, because you will be used to coordinate the application controller does not do the thing, 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 be the business layer needs to get the data from the controller and then into the business layer to deal with, which is directly in the business layer to call the data layer is similar, but is written in the code can not follow the process of thinking to write.

This approach can be used regardless of whether we are using Transactional scripting or table module patterns or the current domain model patterns that are more prevalent.

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);//Perform business logic filtering         return result; }    }}

instead of calling the business layer's methods directly, the controller takes the data first and then performs the transformation in the business logic processing. What needs to be clarified here is that I'm mixing read and write in a logical project, so most of the queries do not have the business logic to handle and switch directly to the service DTO to return. put read and write on a project you can share a 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, even you can think of domain-specific framework development.

5.2. Use IOC ideas to change the data layer's dependence on the business layer directly depending on the data layer (the business layer will be absolutely independent) (more elegant)

The way you use the business layer and the data layer above may feel awkward, so replace it with this section.

We used to call the data layer interface in the business layer to obtain data, we will directly rely on the data layer, we can learn from the IOC, 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.

If you're used to developing projects using the things script pattern, you can use this mode to completely isolate the data layer, and you can try to help you share the peripheral functionality of the things scripts in the application controller.

6. Summary

The article shared the I think to the present more feasible enterprise application architecture design method, and can not say exactly in line with your taste, but may be a good reference, because the time related to this end, thank you.


King Qingyue Culture

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

This article is copyrighted by the author and Csdn, welcome reprint, but without the consent of the author must retain this paragraph, and in the article page obvious location to the original link, otherwise reserves the right to pursue legal responsibility.

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.