background
The concept of micro service has in the past for a long time, the front has practice for a period of time, at different share last year companies have heard about the practice of the micro front-end, overall, micro front end because of the front-end architecture evolve, combining the concept of micro back-end services created, used to solve different front frame, and even different versions of the same frame, How to combine.
Microfront-end is a kind of architecture similar to microservices. It applies the concept of microservices to the browser side, that is, the Web application is transformed from a single single application into a combination of several small front-end applications. Each front-end application can also run, develop and deploy independently.
Before and classmates talked to front-end framework architecture, have been thinking about is that the front end is to be born, can solve the problem of what, at present the scene more seems to be to solve historical system migration issues, on the new system, the front end, especially in a unified system, rarely appear across multiple languages, architecture scene. It’s more about just refactoring and doing a new one.
If the front end can be micro, can the back end be micro? Micro service in some scenarios, to solve the problem of different languages intermodulation, relatively, in fact, there are supporting management and scheduling system, and as mentioned above, in a single language field, users may be more familiar with the development of a large system, which causes the system is getting bigger and more complex.
In a system similar to Ali, there are a lot of Front-end Node.js systems, especially in the middle and background systems, which are combined with the management end and the front end. The business can be very complex, and the front end can be split, while the back end is basically the same. Microservitization or FaaS, there is always an unknown risk. People always say “why upgrade when everything is going well”.
Common background application logic
So we do not want to reverse the history, let users familiar with traditional development step to Serverless, even there are still some difficulties, especially in the face of HTTP traditional application, routing thinking and convenient development environment has been very mature, no matter in the development experience or the underlying concept is difficult to change.
We envision a lot of ways to make applications lighter, thinner, maintainable, scalable. We tried decoupling in Midway the IoC way, replacing traditional instantiations and calls with decorators and injections.
import { provide, controller, inject, get } from 'midway';
@provide()
@controller('/user')
export class UserController {
@inject('userService')
service: IUserService;
@get('/:id')
async getUser(ctx): Promise<void> {
const id: number = ctx.params.id;
const user: IUserResult = await this.service.getUser({id});
ctx.body = {success: true, message: 'OK', data: user}; }}Copy the code
With IoC, the code does not depend on the framework, only on the decorator.
But it doesn’t make the application smaller, it’s still the same application, the logic is still there.
Traditional distributed invocation splits the system into many services, but this sacrifices maintainability, makes troubleshooting difficult, and makes resource overhead difficult to estimate without a mature set of services.
So, is there a way to easily split applications without compromising debugging, resource evaluation, or even maintainability?
The answer may be yes.
We’re always good at solving complex problems in simple ways, but this time there were several problems.
- Local development issues do not affect development
- Deployment issues to minimize cost consumption
- I want it simple, easy to understand and maintain
- For future expansion, migrate to microservices and even FaaS scenarios
Faced with so many problems, we can only think and solve them one by one.
How to break up
Just last year in JSConf 2019, we proposed a splitting method to turn applications into functions, splitting the Router layer separately and the Service logic vertically.
Who remembers the split model from last year’s JSConf 2019?
This method divides applications into two categories (Controller + Service) and services themselves by domain. On this basis, it would be natural for us to domain routing as well, and the controller and Service directories in the original directory structure are good examples of this idea.
The second question is, how does it change the way the code is organized, the development model?
Changes in development methods
Users are too lazy and picky to do anything that increases costs and reduces revenue. If you change the way your code is organized, and you have to change the code, or even change the way you are used to developing, you will be damned.
With the separation of the code, the management mode is fine, and you can now use git repository management or a tool like Lerna to manage the repository. But the development approach is a real experience, how do you break up the logic and increase scalability with as little modification as possible?
This requires the support of frame loading.
We used the example of an Midway project that used Lerna to manage Monorepo to simulate a split.
Let’s simplify the sample directory structure, which looks like this.
. ├ ─ ─ the README. Md └ ─ ─ packages ├ ─ ─ API │ └ ─ ─ the SRC │ ├ ─ ─ app │ │ └ ─ ─ controller │ │ └ ─ ─ controller. The ts │ └ ─ ─ the config │ └ ─ ─ The config. Default. Ts ├ ─ ─ book │ └ ─ ─ the SRC │ ├ ─ ─ app │ │ └ ─ ─ controller │ │ └ ─ ─ bookController. Ts │ ├ ─ ─ the config │ │ └ ─ ─ The config. Default. Ts │ └ ─ ─ service │ └ ─ ─ bookService. Ts ├ ─ ─ the main │ └ ─ ─ the SRC └ ─ ─ video └ ─ ─ the SRC ├ ─ ─ app │ └ ─ ─ controller │ └ ─ ─ VideoController. Ts ├ ─ ─ the config │ └ ─ ─ config. The default. The ts └ ─ ─ service └ ─ ─ videoService. TsCopy the code
Main is the main app, while API, book and video are the corresponding domain modules (sub-applications), containing the capabilities of the corresponding domain, such as providing API, book service and film and television service.
As you can see, the directory structure of our subpackage is the same as the original big application, and the files are the original domain abstraction files (if the original code was well written).
Of course, when you take it down, it won’t work. We got an error when we started, we couldn’t find the subpackage files, and we needed to tweak the framework a little bit.
Those familiar with the Midway framework may know that IoC scans directory files and preloads them into memory to get an instance, but this directory structure is also unscannable. Fortunately, our IoC container supports passing in custom scan paths, so we only need to make a small change so that the IoC container can get the path of the subpackage.
Under Monorepo, the sub-package is also a normal NPM package, so we just let the user define it. For example, there is a file called Configuration. ts, which looks something like this.
@configuration ({imports: [) {imports: ['midway-macro-backends-api'.'midway-macro-backends-book'.'midway-macro-backends-video',]}) // API provides Restful API services @Configuration({imports: ['midway-macro-backends-book'.'midway-macro-backends-video',]})Copy the code
All we need to do is find the address of the subpackage in the framework and add it to the scan path. Following the original dependencies, we added dependencies to the corresponding subpackages (apis) to provide Restful API services.
. ├ ─ ─ the README. Md └ ─ ─ packages ├ ─ ─ API │ └ ─ ─ the SRC │ ├ ─ ─... │ └ ─ ─ the configuration. The ts ├ ─ ─ book │ └ ─ ─ the SRC │ └ ─ ─... ├ ─ ─ the main │ └ ─ ─ the SRC │ └ ─ ─ the configuration. The ts └ ─ ─ video └ ─ ─ the SRC └ ─ ─...Copy the code
In this way, our main and API packages can be developed independently and work independently, and are completely consistent with the original development model.
When used, NPM packages are imported for collaboration, and the standard import syntax is used, as well as the class form, with no special semantics added and no extra learning required.
This is the dream model, which we might call a “micro back end.”
Deployment model
In terms of the development model, we changed the code into sub-modules and made the development mode of the code completely consistent with the previous one through IoC scanning. How about the deployment?
Since the main package does not change much, only the main package can be published separately when publishing the build, which is particularly suitable for the CRM background system, multi-route combination.
The last
Thanks to the IoC system, we can try to export these capabilities to other scenarios. We opened up the code for the Midway FAAS system at the end of 2019, and there was a need to convert some of the Midway code to Midway FAAs or reuse it. So, could we take some of the Midway (Service) code, How about just copying the code into a new module (sub-package) so that the Midway FAAS can run it?
The next release of Midway and Midway FaAS already supports this extension model. You can extend your reusable capabilities at any time. You can split your application and build vertical domain model code. Even migrating from the Midway module to the Midway faAS module.
Technology is endless, and anything is possible, right here at Midway.