Anterior-posterior separation is not new, it is practiced everywhere. However, some historical projects have inevitably encountered various problems when moving from integrated Web design to a forward-to-back architecture. Because of the endless problems, even some teams will question, integration is good, why to separate the front and back end?
At the end of the day, it’s not that the separation is bad, it just might not fit, or… Design thinking hasn’t shifted yet…
Integrated Web architecture
Schematic diagram of a forward-forward-separated Web architecture
Why do we separate the front and back ends
A more realistic question than why is it necessary is when, and the application scenarios for, front-end separation.
Speaking of this problem, I remember that around 2011, the company extended the Java team based on the.net development team. Although the two teams are producing different products, we still have a lot of repetitive development, such as WebPage related to organization with ASP.NET WebPage. Use JSP to write again. In this case, the team began to think of a scenario where, if the front-end implementation was independent of the back-end technology, the portions of the page rendered could be shared, and the different back-end technologies only needed to implement the back-end business logic.
The fundamental solution is to separate the data from the page. The technology to cope with this demand is ready-made. The front-end adopts static web-related technology, HTML + CSS + JavaScript, and calls the business interface provided by the back-end through AJAX technology. The interface mode is provided through HTTP and the POST predicate is used uniformly. The data structure of the interface is implemented using XML. It is very convenient for the front-end jQuery to parse XML, and there are more tools for the back-end XML processing…… Later, with the rise of back-end JSON libraries (such as Newtonsoft JSON.NET, Jackson, Gson, etc.), the data structure was replaced with JSON implementation as front-end processing became easier (json.parse () and json.stringify ()).
This architecture is essentially SOA (Service-oriented Architecture). When the back end does not provide pages, but only provides data and business interaction capabilities purely through Web API, the Web front end becomes a pure client role, which belongs to the same role as WinForm and mobile terminal applications. They can be combined together and collectively referred to as the front end. The previous integrated architecture required customized pages to implement Web applications, and at the same time defined a set of WebService/WSDL to provide services to WinForm and mobile terminals. With the switch to the new architecture, all types of front ends can be served uniformly in the form of Web API. As for the RPC encapsulation of this Web API by some type of front end, that’s another matter.
Through this architectural transformation, the front and back ends are actually separated. Leaving aside other types of front ends, I’m only talking about the Web front and back ends. Because of the separation, the Web front end development does not need to know what technology is used by the back end, just what kind of interface can be used to do things. C#/ASP.NET, Java/JEE, database… These technologies can be completely ignored. The back-end.NET team and Java team also get rid of the logic-independent aesthetic thinking, do not need to face the constraints of fine interface design, and do not need to consider how to layout the page while thinking about logical implementation, just need to deal with their own good logic and data.
The separation of the front and back ends makes it easier for developers on both ends and increases productivity due to greater technical and business focus. The benefits of separation gradually began to show up:
1. Separate responsibilities
The front end tends to be presentation, focusing on user experience related issues; The back end is in business logic, data processing, persistence, etc. In the case of clear design, the back end only needs to take data as the center to be responsible for the business processing algorithm, and provide API interface for the front end according to the convention; The front end uses these interfaces to be responsible for the user experience.
2. Technical separation before and after
Front-end can not understand the back-end technology, do not care about the specific back-end technology to achieve, just need to know HTML/CSS/JavaScript can start; The back-end only needs to care about the back-end development technology. In addition to saving the trouble of learning the front-end technology, even the study of the Web framework only needs to focus on the Web API, rather than the MVC technology based on the page view (not to say that MVC is not needed, The data structure rendering of the interface part of the Web API is also a View), without particularly complex data organization and rendering.
3. The separation of the front and back brings about the decoupling of user experience and service understanding
The front end can quickly adapt to the user’s experience needs at different times, with no pressure on the back end. Similarly, the front-end can be unaware of business logic upgrades and data persistence scheme changes at the back end as long as the interfaces are not affected. Of course, if the requirements change and the interface changes, the front and back end need to sit together to synchronize information.
4. The front and back separation can be reduced to the design of both ends respectively
The backend only provides API services, regardless of page rendering. The API to implement SOA architecture can serve various front-end, not just Web front-end, can achieve a set of services, each end use; Meanwhile, for the front end, the front end that does not depend on the back-end technology can be deployed independently or embedded in a Hybrid architecture with various “shells” (such as Electron and Codorva) to quickly realize multi-terminals.
Pre – and post-separation architecture
No technical solution is a silver bullet, and separation brings contradictions as well as benefits. At the beginning of our practice, due to the relatively weak front-end team strength, and in accordance with the convention, almost all business processing is designed and defined by the back end (original technical backbone), the front-end processing often found that the interface definition does not conform to the user operation process, AJAX asynchronous request too much and other problems. After all, there is a difference between back-end thinking and front-end thinking — front-end thinking is more user experience oriented, and back-end thinking is more technical implementation of the business.
In addition, the safety requirements of the front and back separation are slightly different. Since pre – and post-separation is essentially an SOA architecture, authorization needs to be thought of in SOA architecture terms as well. Cookie/Session is available, but not particularly suitable. Token-based authentication is more suitable. Using token-based authentication means that the authentication part of the back end needs to be rewritten… Of course, the back end doesn’t want to rewrite, so it kicks the ball to the front end so that the front end can figure out how to implement Cookie/ session-based authentication… So the front end starts complaining (tragedy)…
Who is going to dominate
The emergence of these contradictions, ultimately lies in the design is not clear and clear. There is no doubt that the architect or designer should take the lead in the development process. In real life, however, architects or designers are often also developers, so their primary technology stack can greatly influence the priorities of the front and back ends in the overall project. Where the backbone is, the ease of development tends to tilt. It’s a bad thing, but we have to deal with it, and I’m sure a lot of smaller teams have similar problems.
Without good process specification, the front end often touches more roles than the back end (most application projects/products, not all cases).
- The front-end developer is directly influenced by the project/product manager or customer: this should be a button, this should be an action… ;
- The front end also connects to the artist — that’s not easy to implement, can you change it to that? The client required this operation, but this design cannot do it;
- The front end also interconnects with the back end, or for some applications, multiple back ends
In other words, the front end can be the center of project communication, so it’s better to take the lead than the back end.
Interface design
The interface is divided into two parts: back-end service implementation and front-end invocation. The technology is mature and not difficult, but the interface design is the difficulty. The previous mention of the front and back ends creates some contradictions. From the perspective of the front end, the focus is on user experience, including the flow direction of users in business operations and related processing; From a back-end perspective, the focus is on data integrity, validity, and security. The contradiction lies in different concerns, asymmetric information, and selfishness. The solution to these contradictions is interface design.
When an interface is designed, its granularity is often a proxy (not absolute, but architecturally relevant) for the amount of work done on the front and back ends. If the interface granularity is too small, the front end will have to deal with too many things, especially for various asynchronous processing may feel overwhelmed; Too much granularity leads to high coupling and reduced flexibility and extensibility, which of course makes the back end work harder. The business side involves specific products and is not discussed here. This is about a little bit of technical stuff.
Formally, a Web API can be defined as REST or RPC, as long as the front and back end negotiations are settled. More importantly, it is best to start with relatively fixed definitions of input parameters and output results, often depending on the front-end architecture or UI framework adopted.
The data forms of common request parameters are as follows:
- Key-value pairs, Payload for methods such as QueryString or POST in urls
- XML/JSON/… Payload, which is usually used for methods such as POST, can also be passed using multipart
- ROUTE, obtained from the URL parsed by back-end routes, is commonly used in RESTful applications
And the data form of the server response is multifarious and varied, usually a complete response needs to contain at least three parts of the content of status code, message, data
- Status code, an HTTP status code or a specific status attribute in response data
- Messages, usually placed in the response content, are part of the data
- Data, depending on the interface protocol, can be in a variety of formats, the most popular being JSON
We use JSON form in practice, initially defining such a form
{
"code": "number"."message": "string"."data": "any"
}
Copy the code
Code is mainly used to guide the front end to perform special operations. For example, 0 indicates that the API invocation is successful, non-0 indicates that the invocation fails, 1 indicates that login is required, and 2 indicates that authorization is not obtained. For this definition, after the front end receives the response, it can perform some general processing at the application framework layer. For example, when code is 1, a login window will pop up asking the user to log in on the current page, while when code is 2, a message will pop up with a link to guide the user to obtain authorization.
See also: Encapsulating Api calls for pre – and post-separation models
There was no problem doing this until the front-end framework switched to jQuery EasyUI. EasyUI, for example, has many UI libraries that support configuring data urls for components. It automatically obtains data through AJAX, but has requirements on data structure. If you still use the response structure you designed earlier, you need to define data filters for the component to process the response results, which is a lot of work to write the filter and declare the filter for the component. In order to reduce the workload, we decided to change the interface.
The new interface is a mutable structure that normally returns the data structure required by the UI, and in the case of an error responds with a data structure of the same type as the original structure:
{
"error": {
"identity": "special identity string"."code": "number"."message": "string"."data": "any"}}Copy the code
For a new response data structure, the front-end framework just needs to determine if there is an error attribute, and if so, check whether its identity attribute is a specified special value (such as a specific GUID), and then handle the error using its code and Message attributes. This misjudgment process is a little more complex, but can be handled uniformly by the front-end application framework.
If RESTful interfaces are used, some status codes can be replaced by HTTP status codes. For example, 401 indicates that login is required, 403 indicates that authorization is not granted, and 500 indicates that an error occurs during program processing. Of course, although HTTP status codes work better with RESTful styles, non-restful styles can also use HTTP status codes instead of err.code.
User authentication
There are many authentication schemes. For example, Cookie/Session is still feasible in some environments. You can also use token-based authentication, OAuth or JWT, or even implement token-based authentication by yourself.
Cookie/ Session-based authentication scheme
Using the traditional Cookie/Session authentication scheme is not impossible, but there are some limitations. If the front-end and back-end parts are the same as each other, such as pages published at http://domain.name/ and Web apis published at http://domain.name/api/, The Cookie/Session scheme from the original all-in-one Web scheme can be migrated directly without stress. However, if the previous release and API release are from different sources, this approach can be complicated.
However, in the general development mode of front and back end separation, whether in the development phase or the release phase, the possibility of different sources accounts for a large proportion, so authentication schemes usually use cookie-independent schemes.
Authentication scheme based on OAuth
At present, the open interfaces of major websites are SOA architectures. If we regard these open interfaces as service providers (servers) and the applications using these open interfaces as clients, then we can produce such a relationship with the separation of the front and the back:
Front-end departure client
⇣
(OAUTH-based certification)
⇡
Back-end terminal
Copy the code
Therefore, the OAuth scheme widely used in open interface for the separation of front and back is feasible, but it is not so easy to implement. Especially in terms of security, because the front end is fully exposed, compared with the OAuth usually implemented environment (back-end terminal), note that the first authentication is not the use of registered AppID and AppToken, but the use of user name and password.
Token/JWT based authentication scheme
Although this scheme is put at the end, it is the most suitable scheme for the separation of front and back ends at present. Various token-based authentication schemes have been discussed for a long time, and JWT is relatively mature and recognized by most people. JWT implementations of various technology stacks can be found on jwt. IO and can be easily applied.
Having said that, there is still a big difference in processing between JWT scheme and Cookie/Session used before, which requires a certain learning cost. There are concerns that the JWT has too much data. This is certainly a problem, but the hardware is not expensive and 4G is starting to move into unlimited data, so you don’t have to worry too much about this in general applications.
Pre – and post-separation tests
After the separation of front and back, the front-end test will be mainly user experience test and integration test, while the back-end is mainly unit test and Web API interface test. Compared to an all-in-one Web application, there is an additional layer of interface testing that can be fully automated and, once the test development is complete, business processing and data errors can be largely controlled. As a result, integration testing is relatively simple and much easier.
The front-end testing work is relatively unmitigated, and the front-end part after the separation takes over the original integration testing work. But integration testing can be done with the assumption that the Web API is correct, and the use cases can focus on front-end experience issues, such as whether the rendering is correct, whether the jump is correct, whether the user steps are correct, whether the prompt is accurate, and so on.
Validation of user input can even be left entirely to Web APIS under tight deadlines. Front end separation or not, there is a common understanding in Web development: Never trust the front end! Since the back end must ensure the security and validity of the data, the omission of this step by the front end poses no real threat to the back end, only a poor user experience at best. However, if data validation is done on both the front and back ends, it must be done strictly according to the documentation, otherwise it is easy to have inconsistent data validation on the front and back ends (this is not a separation of the front and back ends problem, the integrated architecture also has this problem).
summary
Overall, the benefits of fore-and-aft separation are clear. But the concrete implementation of the need for a new way of thinking, rather than based on the original integrated Web development way to think. The open approach of front and back separation frees developers from the complex combination of technologies and allows them to focus on their areas of expertise, but at the same time puts higher demands on the communication between the front and back teams. The front and back end teams must work together to design relatively stable Web API interfaces (this part of the work is necessary with or without the front and back end separation, but the architecture of the front and back separation is more demanding, and more explicitly requires that the interface not only exist in memory, but also be documented and persistent).