preface

CNCF and Cloud Native are two technical words that frequently come into the sight of programmers recently. All the software that can be associated with CNCF means standard, open and fashionable, which can also capture the hearts of technical brothers. This article does not want to remind you of the software system behind this word. The author thinks that using these open source software alone does not mean that our own software is Cloud Native. There are two processes between using dumbbells and becoming muscular men: scientific use and self-discipline exercise. Here, I would like to talk to you about the theoretical basis for making our application truly Cloud Native: the twelve elements of microservices. This article also explains the understanding of the first two of the twelve elements — Code Base and Dependency — from the perspective of the author’s own project (an EDAS-based microservice architecture).

There is always a one-to-one correspondence between the Base Code and the application. There is always a one-to-one correspondence between the Base Code and the application. The same application in different environments should come from the same code. My understanding is two:

  1. An application, generated from the same repository.
  2. A repository produces only one application.

Why draw these two conclusions? Let’s look at an actual project first.

Why is it an app?

To give you an example of a warehouse containing multiple applications, one of the author’s own projects is a microservice architecture. Like most microservice architectures, it was disassembled from a single application at the beginning, and after disassembled, it was roughly simplified into four services: Microservice Gateway, two background services (UserService, OrderService), background management console service (Admin), simple architecture diagram is as follows:

At the beginning of the split process, in order to reduce the risk of project launch, all the applications after the split were managed in a GIT repository and shared the same library. After the reconstruction, the warehouse directory is as follows:

~/workspace/ Java /app/ $tree ├── Active FlagGeneric API interface definitions│ ├ ─ ─ userservice - APIDeclaration of the service UserService│ ├ ─ ─ the orderservice - API# service OrderService declaration│ ├ ─ ─ the RPC - APIInterface declaration for remote service invocation│ ├ ─ ─ common - APIA declaration that both UserService and OrderService depend on|... ├ ─ ─ service - impl# Specific business implementation of the corresponding API│ ├ ─ ─ userservice - impl │ ├ ─ ─ the orderservice - impl │ ├ ─ ─ common - impl |... ├ ─ ─ a web app# Web application Engineering│ ├─ admin │ ├─ UserService │ ├─ OrderService │ ├─ GatewayCopy the code

At first these services publish and changes between each other is not affected, the process lasted for about two iterations, with the ongoing of iteration and new people to join, then we found a strange phenomenon, online every time a user enter the refresh order address list, will accompany it to a user Token refresh and lead to the user is kicked out, The online process, with the help of EagleEye, EDAS’s distributed link-tracking system, immediately located the code in question:

// User Service public class User {public voidrefreshOrder Service public class OrderUser extends User {Order Service public class OrderUser extends User { Cause REFRESH to call refresh public void of the parent classrefesh() {// Refresh the address list}}Copy the code

This fault, I first invite you to think about a few questions:

  1. From a coding point of view, how to avoid the above overridden method due to name miswriting failure?
  2. From a design point of view, are OrderUser and User inherited?
  3. What is the root cause of this problem?

Among the above questions, the answer to the first question, as many students know, is to use Java’s annotations @override, which automatically forces to check whether the modified method signature is consistent in the parent class. The second question, from the perspective of domain boundary, is a typical boundary demarcation question, namely: are the users in the order and the users in the member login the same “user”? Members of the user, in fact, only need to care about the user name and password, the other are the attributes of the user; And the order of the user, the most important is certainly contact, that is, a contact, determine a person. Although they are both called users, they are certainly different concepts in each other’s context. Therefore, OrderUser and User cannot be inherited, because they are not an “IS A” relationship. Warehouse sharing, coupled with a poorly thought-out model, leads to dependency chaos; All of this might have been avoided if the two User objects had been code isolated and not so easily “related.”

Why a warehouse?

Strictly speaking, all the code in an application must come from different repositories, right? The tripartite libraries we rely on (Fastjson, Edas-SDK, etc.) must have come from other repositories; These libraries have a specific name and version number, and are already built as work-in-progress. By repository, I mean work-in-progress at the source level. There may not be such a situation in many projects. Take GIT as an example, it usually occurs in projects with submodule organization structure. What is the general scenario? We do have an example of this in our project:

To solve the first problem, we decided to split the warehouse according to the granularity of the application. At the same time, we split all the common related things into a common warehouse. Admin is a background management application that changes frequently and needs to rely on UserService and OrderService for a large number of interfaces. Git subModule: Git subModule: Git SubModule: Git Submodule: Git Submodule: Git Submodule: Git Submodule

I don’t think it would be a problem if there were only one or two people on the project; Any one of the above schemes does not need to spend too much time on special discussions, and there will be no mistake in choosing the scheme with which you are most familiar and most adept. The so-called small team depends on technology, which is the truth; We were a small team at that time, and some students in the team had dealt with similar situations in submodule, so the choice of scheme was quite natural.

Later, as the team grew larger over time, it was found that it was necessary to develop some processes and norms to restrain some behaviors, so as to ensure the team collaboration. At this time, I found that the site that I had fought for by myself became fragile under the writing of many people, especially when another submodule was maintained by a team. The version management of submodule was almost unpredictable, and its interface changes and changes were completely indifferent to the feelings of the dependent parties. Because he does not know whether he is dependent or not; Over time, you will understand what it means to have your project corrupted. To understand the word corruption simply means that you are already afraid of any changes you make because you don’t know if they will cause additional trouble. From this perspective, it is also possible to understand why a language is designed to have such range modifiers as private and __public__. It is these words that make it possible for your business code to be highly cohesive, down to design methods per class, interfaces per service, systems per repository, and the principle remains the same.

The solution to the above problem is very simple, is to become a display dependency relationship, the so-called display dependency refers to the two dependencies are determined. What is certain? Make sure == No Supprise! Yes, whenever, online or offline, I rely on your test environment’s interface to return an integer, and when online, it must return an integer, not a floating point number. What makes certainty feasible is not a gentleman’s agreement; Can only be a version-dependent tool. Take Maven’s formal version dependency in Java.

conclusion

Responsibility cohesion and dependency determination are prerequisites for our application to become truly Cloud Native. Without these basic internal functions, no matter how much you know about open source software and how familiar you are with the microservice stack, there will be all kinds of unexpected things. Just imagine, if the responsibilities of the application are scattered everywhere, who will be expanded? If the dependent party becomes extremely uncertain, who pays for the uncertain cost of each release? Be Cloud Native, start with your home where your application code is hosted.


Welcome to “Alibaba middleware official weibo” does a set of dry goods and avant-garde technology number

Welcome to pay attention to “Alibaba middleware” official public number, and technology counterparts