In the process of designing the service center, it is very important to design the service interface and data model in the service center. Good design principles and methods can guarantee the scalability of the service center to the maximum.

Readers are strongly recommended to follow the most influential book of noted modeling expert Eric Evans’s domain-driven Design-Django in the Heart of Software (” Domain Driven Design: Djz2800 “). Managing Complexity at Software Core) and Thomas Erl’s SOA Principles of Service Design (SOA Service Design Principles), principles and approaches that can be used in most practical Service center Design processes. The purpose of this book is to provide an overview of how best to build a digital enterprise, so it does not delve into this technology.

Facade pattern

The Facade pattern appears several times later as we introduce the principles of service-oriented design.

How the facade pattern works is shown in Figure 4-11.

The advantages of the facade pattern are as follows:

  • Loosely coupled: The facade pattern loosens the coupling between the front-end application and the middle service center, making it easier to extend and maintain modules within the service center.
  • Easy to use: The facade pattern makes the service in the service center easier to use. The foreground application no longer needs to know the internal implementation of the service center, nor need to interact with the numerous functional modules inside the service center. It only needs to interact with the facade class.
  • Better hierarchy of access: You can better divide the hierarchy of access through the proper use of the facade pattern, some of which are outside the system and some of which are used inside the system. Concentrating the functionality that needs to be exposed to the outside into the exterior makes it easy for the client to use and hides the details of the inside.

The use of DTO

The DTO can shield the complex or volatile data objects in the service center from the front desk, so that the front desk has better stability. DTO is a frequently used technique in system layered design and service-oriented architecture, and the concept itself is easy to understand, as shown in Figure 4-12.

Design principles for service interfaces

The core of the business middle desk architecture is the design modeling of each business domain and the design of service interface. Based on the excellent design principles of the industry and my own practice, the author sorts out the typical design principles of service interface as follows for your reference.

1. Contract first

Service interactions between similar to the cooperation between different organizations, in accordance with the normal logic, cooperation between the two groups first priority is to sign a contract, the content of the detailed rules of cooperation, in the form of cooperation, and so on, so as to form a strong constraint and the safeguard for both sides, the work can also be parallel at the same time, don’t have to wait for each other. Therefore, the best practice in service-oriented architecture is service contract first, that is, service contract design first. Service interface design requires the participation of people from different business, product and technical aspects, and defines the corresponding contract, and then implements the specific code.

In an actual China architecture design phase, when collected in different lines of business enterprise business needs, to form product demand research document, need from the perspective of global service center service interface as a whole is designed, which is not in accordance with the single application scenarios, such as only from electricity or only from the perspective of CRM system, carries on the service interface design. Although the front desk system is build up according to the steps, but the service center of interface design first need to business in a global perspective on planning and design, has a clear interface design, the front desk and service centers have interactive boundary clear and relatively stable, can significantly reduce the late implementation and operation period of cooperation cost, higher overall efficiency.

Due to the wide range of users of the service, it is necessary to ensure good stability after the service contract is published to the public, and not to refactor randomly. Even if the service is upgraded, it is necessary to consider downward compatibility as much as possible.

2. Cohesion of service functions

Service function cohesion is almost a basic requirement in any service-oriented design. To create a functionally cohesive service interface, a set of functionally related operations should be aggregated together, and the logic that might affect the business correctness must be provided in the corresponding service, rather than relying on the service caller to follow the correct logic.

For example, the user registration service, which includes the email format for the users, the user name and password strength checking logic, although these logic in the foreground application Web page or App has carried on the relevant calibration, but in the end the foreground application calls to the user when the user registration service center, still need to be implemented in the service of these user attributes validation work, You can’t rely on the foreground application to do these validations, so that you don’t have to sign up because the foreground application misses the validations. A typical example of service function cohesion is shown in Figure 4-13.

3. Service coarse-grained

Service consumers generally have less knowledge of specific business processes than people inside the service center, so the interface design of the service usually requires coarse-grained design. An operation may correspond to a complete business use case or business process, which can reduce the number of remote calls, as well as the learning cost and coupling degree.

For example, the document service provides bulk deleting support for the foreground application, and the interface provides a method called deleteArticle(long ID) that users can loop through to achieve bulk deleting of articles. At this point, it is better for the service center to provide deleteEarticles (Set<Long> IDS) methods for the foreground application to call, reducing the N remote calls to one.

Another example is the use case where the user places an order, with a sequence of operations: addItem (accumulates items) →addTax (calculates tax) →calculateTotalPrice (calculates total price) → placeOrder (creates order)

Trading center, of course, these services can be provided to the front desk in the form of a single interface method application, it needs not only the foreground application for order creation process and logic have higher requirements, but also can increase the probability of the service call mistakes, it is best to encapsulate a coarse-grained methods for users to do one-time remote calls, but also hides a lot of complexity of the internal business. The service caller also went from relying on four methods to relying on one method, which significantly reduced program coupling.

In addition, from the Angle of the number of service and the interface method, the service will usually as the unit of testing and release, if size too thick, will be a lot of operation is grouped into a single service, may increase the user a single service, so as to service users to quickly find the right operation poses challenges, resulting in poor service experience. To change a service, it is necessary to republish the entire service, affecting a larger number of consumers.

So avoid both extremes of service granularity:

  • Offers many services with only a few methods.
  • Dozens or hundreds of operations are concentrated in a few services.

Consideration should be given to factors such as maintainability, maneuverability, and ease of use, and compromise should be made.

Another way to divide service granularity is to create service interfaces that reflect the state of the life cycle of the business objects. For example, in an expense claim, the life cycle of each expense claim contains four states, as shown in Figure 4-14.

Since business object state often reflects both business and technical aspects, it is perfectly possible to split the ExpenseClaimService into multiple services that fit each state: ClaimEntryService (build service), ClaimApprovalService approval service (expenses), ClaimPaymentService payment services (charges), get the following service code:

ClaimEntryService {
    createClaim(String userId);
    ClaimItemDetails[] getClaimItems(int );
    ClaimErrors[] validateClaim(int claimId);
    void removeClaimItem(int claimId, int itemId);
    int addClaimItem(int claimId, ClaimItemDetails details)
    int submitClaim(int claimId);
}

ClaimApprovalService {
    int approveClaimItem(int claimId, int itemId, String comment);
    void approveClaim(claimId)
    void returnClaim(claimId)
    ClaimItemDetails[] getClaimItems(int );
    ClaimErrors[] validateClaim(int claimId);
}

ClaimPaymentService {
    void payClaim(int claimId);
}

In this way, each service is easier to understand. Furthermore, this partition of the interface is a good fit for how services are developed, deployed, maintained, and consumed. In summary, by placing partitioning logic on the object life cycle, we can build services with the right granularity.

4. Eliminate redundant data

Since the remote invocation of the service requires network overhead, especially in the case of high concurrency, such overhead is not a negligible factor. Therefore, in the input parameters and returned results of the service, redundant fields that are not required by the current business scenario should be avoided as far as possible to reduce the overhead of serialization and transmission. At the same time, removing redundant fields can also simplify the interface and avoid unnecessary confusion to external users.

For example, there is a method in Document Service that returns a list of articles:

List <Article> getArticles(...)

If the business requirement is simply to list the title of the article, then avoid carrying fields such as its content in the returned article object.

A classic solution is to introduce the aforementioned DTO pattern and customize the data fields to be transferred specifically for the front-end business application, where you need to add an additional data transfer object called Ariticlesummary:

List<ArticleSummary> getArticleSummaries(...)

Articlesummary is a good way to avoid redundant data transfers between the service center and the front-end application.

5. Common Contracts

Because the service does not assume a range of users, it typically supports clients in different languages and platforms. However, various languages and platforms have great differences in the richness of functions, which determines that service contracts must take the largest common divisor of common languages, platforms and serialization methods to ensure broad compatibility of services. As a result, service contracts cannot have advanced features found in some languages, and parameters and return values must be simpler data types that are widely supported (such as no object circular references).

For example, the original object model looks like this:

Class Foo {
    private Pattern regex;
}

Among them, Pattern is a precompiled and serializable regular expression unique to Java (which can improve performance). However, in the absence of specific framework support, other development languages may not recognize Pattern, so it is best to change it into a common data type in the way of DTO, as shown below:

Class FooDto {
    private String regex;
}

6, the principle of isolation change

When objects of the service center core domain model enter the foreground application, it is necessary to avoid refactoring within the service center or model changes that cause the foreground application to change as well.

For example, the “Document Service” described above, where the Article object may serve as the domain model for core modeling, or even as object and database mapping, etc., within the service center. If the document service directly returns Article to the service consumer, even without redundant fields, complex types and other problems mentioned above, the external users of the service may have some association with the core domain model of the internal system of the service, or even with O/R mapping mechanism, data table structure and so on. In this way, Internal refactoring is likely to affect users outside the service.

Similarly, facade patterns and DTOs can be used as mediators and buffers to isolate internal and external systems and minimize the impact of changes in internal systems on external systems.

7, contract packaging

Although DTOs and facade patterns are used to isolate changes on the service-producing side from those on the service consuming side, they can be referenced everywhere by the programs on the service consuming side, so that the programs on the consumer side are strongly coupled to the service contract. Once the contract is changed, or the consumer has to choose a completely different service provider (with a different contract), the effort to change it can be overwhelming. In a more ideal service-oriented design, you might consider wrapping the remote Service access logic, also known as the Delegate Service pattern, with the consumer itself taking the lead in defining the interface and parameter types, and forwarding the Service invocation to the real Service client, thus allowing the Service consumer to completely mask the Service contract.

An example of a service proxy is as follows:

Class ArticlesServiceLegate implements ArticlesService {// Let's say it's some kind of automatically generated Service client stub class private ArticleFacadeStub stub; public void deleteArticles(List<Long> ids) { stub.deleteArticles(ids); }}

In the foreground application of this example, all references to the document service invocation are referred to the ArticlesService rather than the ArticleFacadestub provided by the Document Service, so that if the ArticleFacadestub on the service provider is changed or refactored, You just need to make the appropriate adjustments in the ArticlesService class without changing any more code.

Service statelessness principle

To ensure service stability and scalability in the service center, services must be designed to be scalable and deployable into a highly available infrastructure. A corollary to this important principle is that services should not be “stateful.” That is, the service should not depend on a long-standing relationship between the service consumer and the service producer, nor should the service invocation be explicitly or implicitly dependent on the previous invocation. To illustrate this point, let’s take a simple example. Here’s a telephone conversation:

Q: What is Xiao Ming’s account balance?

A: 320 yuan.

Q: What is his credit limit?

A: 2000 yuan.

This example demonstrates a typical stateful pattern. The second question refers to the first question by using “his”. The actions in this example depend on the transformation context. Now let’s consider the response provided, and notice that there is no contextual information in the answer. The answer is meaningful only if the person being asked knows what is being asked. In this example, the consumer is required to maintain the state of the conversation in order to interpret the responses received.

First, let’s consider operations that depend on the context established by the previous operation. If this is an interaction with a call center, the conversation can effectively end as long as the same operator is speaking to it. But let’s assume the call was interrupted, as follows:

Q: What is Xiao Ming’s account balance?

Operator: 1:320 yuan.

At this point, the call is interrupted and transferred to another operator:

Q: What is his credit limit?

Operator 2: Who?

Interrupts cause context to be lost, so the second question is moot. In the case of this phone conversation, we can offset the disruption by re-establishing the context: “I’m asking for information about Xiao Ming’s bank account. Can you tell me his credit limit?” However, in the realm of scalable service invocations, stateful conversations are often more cumbersome, and re-establishing context may be technically feasible, but it is likely to incur significant performance overhead.

Whether associations are required. That is, whether successive requests from the same service consumers must be delivered to the same instance of the service provider. Requiring affinity is a situation where statefulness conflicts with scalability and reliability. In order to maintain the quality of service of the service center’s service capabilities, we must prioritize the scalability and reliability of the final service architecture. So I strongly recommend that services be designed to avoid the need to maintain session context.

Returning to the telephone conversation example above, we can avoid the need for session state by designing the service to include appropriate correlation information in the response, as shown below:

Q: What is Xiao Ming’s credit limit?

A: Xiao Ming’s credit limit is 2,000 yuan.

It is good practice to include correlation information in the response for a number of reasons. First, it simplifies the construction of a scalable solution, provides more diagnostic help, and is important when it is not possible to deliver error responses to the original requester. In summary, careful service design avoids the need for state, simplifying the implementation of a reliable, scalable service architecture.

9. Service naming principles

We have one guiding principle when choosing the names of services, operations, data types, and parameters: we want to maximize the ease of use of the service. We want to help business application developers identify the services and operations needed to implement business processes, so we strongly recommend defining meaningful domain names for service consumers that prioritize business concepts over technical concepts. The suggestion is that services should be named with nouns and operations should be named with verbs. For example, here is a service definition using a phrasal verb and an IT construct:

ManageCustomerData { 
    insertCustomerRecord();
    updateCustomerRecord();
    //etc ... }

Next is a service definition that uses noun and phrasal verbs and business concepts:

CustomerService {
    createNewCustomer();
    changeCustomerAddress();
    correctCustomerAddress();
    // etc ... }

Obviously, the second example is easier to use. In the second example, the business purpose of the service is clear, rather than just indicating its output. Therefore, it is recommended not to use “Update-CustomerRecord” (which can be used for any update for any reason), but instead to use “Enable-OverdraftFacility”. Similarly, when a customer moves, we use the “changeCustomerAddress” method to change the customer address; Use “CorrectCustomerAddress” to correct the customer address when you want to correct invalid data, because it’s easy to see that the two operations use different service logic.

10. Service operation design principles

This is a further development of the naming design principle for service operations: Operations should be defined in terms of specific business meanings rather than generic operations. For example, instead of using the generic update-customerDetails operation, And to create changeCustomerAddress, recordCustomer – such as Marriage and addAlternativeCustomerContactNumber operation. This approach has the following benefits:

  • Operations correspond to specific business scenarios. Such scenarios might involve more than simply updating records in a database. For example, a change of address or marital status may require a change in relevant information in other business modules, such as a change in marital status that may result in a change in membership benefits. Using a less specific operation, such as UpdateCustomerDetails, is not appropriate to implement such a business scenario.
  • The individual operational interfaces will be very simple and easy to understand, resulting in increased ease of use.
  • The update unit for each operation is clearly defined (in our case, address, marital status, and phone number). When implementing systems with high concurrency requirements, we can reduce resource contention by adopting a finer-grained locking strategy based on the requirements of the operation.

Coarse-grained and flexible parameters should be used for the design of parameters in operation, in order to minimize the change of parameter structure caused by the change of requirements.

Take two interfaces for the createNewCustomer operation as an example.

  • The createNewCustomer operation interface with fine-grained parameters is as follows:
int CreateNewCustomer(String familyName,String givenName,
    String initials, int age,String address1,
    String address2, String postcode    // ...  )
  • The createNewCustomer operation interface with a single coarse-grained parameter is as follows:
int CreateNewCustomer( CustomerDetails newDetails)

The above two sample codes show an operation with many fine-grained parameters and an operation that takes a structured type as a single coarse-grained parameter. The use of coarse-grained parameters is recommended because it can largely avoid overall service version upgrades due to fine-grained parameter changes.

From the perspective of parameter flexibility, consider the diversity and flexibility of service requirements. For example, when querying the commodity information, there are many fields defined by the commodity, and different businesses pay different attention to the fields. Therefore, when defining the interface, it can pass in the fields of the commodity that the business party needs to return and save these fields in the List object, and the service can obtain the values of the corresponding fields and return them as the corresponding Map object. In this way, the operation method of commodity query can meet the information acquisition requirements of different application systems for commodity fields.

Essential services cannot depend on non-essential services

The construction of China and Taiwan is service-centered, that is, the interaction between the whole system is carried out in the form of service. Not only do the front-end applications and the service centers in the middle interact as services, but the service centers also interact in this way. In some cases, the front-end application will also establish a service system within the application as the business complexity grows to a certain level. For example, front-end applications such as Tmall and Taobao are already very complex, with a multi-tier service system built up inside. Each service center in the middle of the business is the lowest level of the service system, and each front-end business system above will establish its own service level according to the characteristics of its own business.

In the whole service system, there are very core and important services such as transactions, goods, order related services, and there are relatively unimportant services, such as freight calculation or the services created in the front-end application. The different importance of services can be reflected in terms of the impact degree and service scope of services on the business, and the different importance of services also directly determines the difference in the support and guarantee resources available, which will ultimately be reflected in the stability and reliability of services. Therefore, the lower the service will be more stable, and the higher the service will not be as stable as the lower service in terms of stability and business compatibility.

The principle that “essential services cannot depend on non-essential services” can be more detailed as follows:

  • The upper can depend on the lower. Service implementations at higher levels can depend on services at lower levels or across levels.
  • The bottom can not be relied on. Lower service implementation and operation must not depend on the upper level of service, can appear otherwise because the upper service quality problems and unstable important services affect the performance of the lower level, and lower service failure will affect all rely on the service level service center and the foreground application situation, there will be a serious “avalanche” effect.
  • Horizontal dependencies, avoiding circular dependencies. The most typical manifestation of this principle is that all the service centers in the middle desk of the business are at the same level in the service hierarchy. They all have the same level of service operation requirements and can be interdependent.
  • A higher level cannot depend on a lower level. A service of obviously high business importance should not rely on a service of low business importance. It should do the corresponding service degradation or isolate the service dependency in this case through front office business.

conclusion

Simpleness is beauty, and too many principles may make the overall design bloated. What principles should be adopted under what circumstances should be based on a business understanding and practiced constantly in the practice process, so as to be able to deal with the problems related to service design more calmly.

Source: Technical trivia

Author: Zhong Hua

This article is exclusively authorized by China Machine Industry Press. It is a new work by Zhong Hua, the author of “The Way of Enterprise IT Architecture Transformation”. “The Tao and the Technique of Digital Transformation: Taking Platform Thinking as the Core to Support the Sustainable Development of Corporate Strategy”.

Disclaimer: The article was forwarded on IDCF public account (devopshub) with the authorization of the author. Quality content to share with the technical partners of the Sifou platform, if the original author has other considerations, please contact Xiaobian to delete, thanks.

June every Thursday evening at 8 o ‘clock, [winter brother has words] happy a “summer”. The address can be obtained by leaving a message “happy” on the public account

  • 0603 invincible brother “IDCF talent growth map and 5P” (” end-to-end DevOps continuous delivery (5P) class “the first lesson)
  • 0610 Dong Ge “Take you to play innovative design thinking”
  • 0617 “What is Agile Project Management?”
  • 0624 “Agile Leadership in the Age of Vuca”