Modularization and Large Scale Architecture in SAPUI5

Most of us can code and program. Some of us can Design. But not all can Architect a Solution. It takes more than programming to build a robust solution. In the process, one should be able to propose and defend ones architecture.

I would like to share some of my experiences in terms of designing a large scale front end architecture and how to implement it in SAPUI5. So in today’s topic, you need to look for 2 main bullet points.

  1. General design of large scale front end architecture.
  2. How to implement it in SAPUI5.

Part 1. Large Scale Front End Architecture – A General Design

Following is the salient feature of any robust application:

  1. Scalability – Easy to change, extend and support
  2. Ease of Working – Multiple teams to work on it seamlessly and at the same time without worrying about interfering with other modules of the same application
  3. Openness – The design should be obvious and easy to understand

Modularization of application and Abstraction of the application logic into different layers help to achieve the above salient points.

Modular design is practically done in all spheres. From your modular kitchen to modular work stations, you find division of labor every where. Let us dissect our regular computer and check how modularization is done in the computer hardware.

Modular Design in Computer Hardware

A computer houses many complex components viz: Hard drive, CPU, Audio, Graphic card, cooler fans etc. If for some reason, there is some issue in the CPU, we can replace it without the headache of buying everything new. That is easy, economical and quick. We do not need to worry, it might hamper other components of the computer. They work together in sync, but do not die together. Now coming back to our front end technology in SAP. How do I determine which pieces should I put into a module? Well, it depends, but going by common sense and by the rule of thumb, we should combine closely related UI pages into one module. On a high level, it would look like below.

Modular Design in Front End Application

Reusable UI Component

  • Application container creates and renders other module as needed.
  • Application container only responsible for common app logic like security check, permission check etc. It should not be involved in any feature business logic.
  • Each module should not be aware of each other.
  • There should be an EventBus communication mechanism at global level. Each module can only communicate throw EventBus.
  • UI component is smaller granular compared to modular design. UI component should be common UI element that can be reused across all modules. It can be a button, list or alert popup etc.

Part 2. Implementation of Modularization Technique in OpenUI5 and SAPUI5

Open UI5

Assumption: You have some basic understanding of openUI5 or SAP UI5 framework. If you don’t, it is highly recommended, you stop here and check out Open UI5 documentation.

2.1 Architecture Overview

Large Scale Architecture in UI5
I have created a simple application in github to demonstrate the implementation. There is an Application Container module and two child modules namely Student and Exam.

  • Student module has two pages: Edit and Search Student.
  • Exam module has two pages: Edit and Search exam.
  • Application Container has a menu bar and main display area.
  • Application Container has only one route pattern: “{module}&:all*:”. It will fit all the pages. All it does is to load modules as needed and render the module into corresponding UI area.
  • Each module will be rendered into the main display area on demand after user click the link from the menu bar.
  • To simplify the demonstartion, only one module can be displayed in the main display area each time. Other modules can be rendered into the main display area though, they will just be hidden.

User interface of the demo

2.2 How to build a module?

UI5 recommend to use UIComponent.js and manifest.json to setup the project. My implementation follows it.

Note: UIComponent.js in UI5 is a different concept from the UI Component design we mentioned in part 1. The corresponding terminology is called UI Control in UI5. SAP UI5 has a very robust UI Control library.

UIComponent.js has been leveraged to implement a module design. The benefit of UIComponent.js are:

  • It is isolated from other modules from the framework level.
  • It can be easily replaced like we plug in/out a USB drive.
  • Each module loads their own css file and i18n labels.
  • Each module bundles their own resource files, it brings better network performance.
  • Each module can be tested separately.

2.3 How to render and display a module into ApplicationContainer?

ComponentLoader control has been created for this purpose. ApplicationContainer composes ComponentLoader. It uses ComponentLoader to render and display the corresponding component into a specific DIV/control. Please check the demo code for more details.

2.4 Navigation

UI5 uses route pattern to represent the browser url address. Let’s take a closer look at the route patterns:

  • Student module has 2 routes and the patterns are: “edit/{id}” and “studentSearch”.
  • Exam module has 2 routes and the patterns are: “edit/{id}” and “search”.
  • ApplicationContainer has only one pattern “{module}&:all*:”

As you can see both Student and Exam module has route pattern “edit/{id}”. So when you put “edit/{id}” in the browser url address bar, ApplicationContainer has no idea which module it should pick and to initialize. So how do we resolve this issue? I came up some approaches as explained below:

Approach 1:

You can define a parent route in the module route config file. But this is not a good idea because this module will be coupled with one particular parent module. It will restrict the module reusability. The child (Student and Exam module) should never be aware of the parent(ApplicationContainer).

Approach 2 (Our application uses this approach):

A new router called ModularRouter which extends from the sap.m.routing.Router is created. ModularRouter does two things:

  1. ModularRouter adds a prefix to the module’s route pattern at run time. The prefix value is passed by the creator of the module, ApplicationContainer in this case.
  2. ModularRouter accepts a callback function which will be called after the router is initialized. This is very useful when you want to do something after you created a module and rendered into the page.

Let’t take a better look at the ApplicationContainer manifest.json:

“sap.ui5”: {
“_version”: “1.1.0”,
“componentUsages”: {
“student”: {
“name”: “com.haojia.test.student”, “componentData”: { “routePatternPrefix”: “student&/”
}
},

“exam”: {
“name”: “com.haojia.test.exam”,
“componentData”: {
“routePatternPrefix”: “exam&/”
}
}
},
“dependencies”: {
“minUI5Version”: “1.30”,
“libs”: {
“sap.m”: {}
},
“components”: {
“com.haojia.test.student”: {}
}
},
“rootView”: “com.haojia.test.applicationContainer.view.App”, “routing”: { “config”: {
“routerClass”: “com.haojia.test.util.ModularRouter”,
“viewType”: “XML”,
“viewPath”: “com.haojia.test.adminLayout.view”,
“transition”: “show”,
“controlId”: “app”,
“clearTarget”: true,
“controlAggregation”: “pages”
},
“routes”: [{
“name”: “App”,
“pattern”: “{module}&:all*:”
}]
} }

Please pay attention to the emphasized text. As a parent module, it defines Student module as dependencis. And passes routePatternPrefix through componentData. By doing so, we can dynamically add a prefix to the route pattern to resolve multiple module pattern conflicts issue.

Each module has its own router and pattern definition. But the browser url bar is global to every module. So that’s been said, one url can be matched by multiple modules. So it is possible that pattern X can be matched by ApplicationContainer and Student module at same time. To leverage that, ApplicationContainer has only one route pattern: “{module}&:all*:”. This is a fuzzy pattern match which will match every module.

Let’s take a real url example, assume the current url in browser address bar is http://www.haojia.space#/student&/edit/abc

  1. Because ApplicationContainer’s route pattern is “{module}&:all*:”, pattern will match and the {module} parameter is “student”. ApplicationContainer will create and render Student module based on the {module} parameter.
    2. Then Student module is been created. The edit route pattern was “edit/{id}” but because of the routePatternPrefix we defined in manifest.json, its runtime route pattern is now “student&/edit/{id}”. Bingo, that url will be matched to edit route without conflicts now!

2.5 Navigation between modules

Modules don’t know each other. But what if you need to navigate from module 1 to module 2? SAP EventBus helps in the cross module communications. Module 1 publishes a event to ApplicationContainer. Then ApplicationContainer renders the destination module 2 accordingly.