Showing posts with label Architecture. Show all posts
Showing posts with label Architecture. Show all posts

Thursday, May 17, 2018

Microservice Approach for Web Development - Micro Frontends

This post is based on my Oracle Code 2018 Warsaw talk. View presentation on slides share:


Wondering what micro frontends term means? Check micro frontends description here. Simply speaking, micro frontend must implement business logic from top to bottom (database, middleware and UI) in isolated environment, it should be reusable and pluggable into main application UI shell. There must be no shared variables between micro frontends. Advantage - distributed teams can work on separate micro frontends, this improves large and modular system development. There is runtime advantage too - if one of the frontends stops working, main application should continue to work.

I have implemented micro frontends architecture with Oracle JET. Source code is available on GitHub repository. There are three applications, two with micro frontends and one is the master UI shell. Both micro frontends are implemented as JET Composite Components. First is hosted on WebLogic, it calls ADF BC REST service in the backend. Second is hosted on Node.JS and returns static data. First micro frontend implements listener, it allows to handle actions from the outside.


When JET application is accessed in your browser, bunch of HTML, JS and CSS files are downloaded from the server. Core idea with micro frontends - instead of loading HTML, JS and CSS for micro frontend from the same host as master app - load it from different host. JET Composite Component rendered inside master application will be downloaded from different host. Not only downloaded, all backend calls should go to that host too, not to the master host. JET Composite Component integration into master application architecture:


This is how it works in practice. Each of these charts is separate JET Composite Component, loaded as micro frontend from different host into master application. We can see that in network monitor. Loader.js scripts for both micro frontends are downloaded from different hosts:


Runtime advantage - if one or multiple micro frontends are down, application continues to run:


JET Composite Component runs on the client, even it is hosted in its own micro frontend. This gives possibility to subscribe to the events happening in the component in the master app and route that event to another micro frontend. In this example, once item is selected in job chart - employees chart (another micro frontend) is filtered:


Technical implementation

Main application must be configured to support remote module loading for JET Composite Component. Read more about it in Duncan Mills blog post - JET Custom Components XII - Revisiting the Loader Script. In short, you should add Xhr config in JET application main.js:


Server where micro frontend is hosted, must set Access-Control-Allow-Origin header.

Main module where both micro frontends are integrated is using JET module component. Each micro frontend in master UI shell is wrapped into JET module. This allows main application to function, even when micro frontend in the module stops:


JET module is initialized from variable, which returns module name:


Jobs module contains Jobs micro frontend - JET Composite Component. It is hosted and WebLogic and calls ADF BC REST in the backend. Component is assigned with listener:


The most important part is in JS script. Here instead of referencing JET Composite Component locally, we load it from remote host. This allows to develop and host micro frontend JET Composite Component on its own:


Listener refers to c2 element and cals the method. Element c2 in the main app relates to second micro frontend:


This component is loaded from another host, from Node.JS:


Important hint - for JET Composite Component to load from remote host, make sure to add .js for JET Composite Component script, as highlighted (refer to source code):

Saturday, July 1, 2017

Oracle JET Router State Control

In my use case there is requirement to navigate to JET module, without displaying it in menu structure. Navigation is a simple task, more complex is to make sure current menu item will be unselected after navigation to invisible module (so that later we are able to re-open it).

There is accounts module in JET sample app (download it from GitHub - JETModularArchitecture):


Accounts module is included into router, but not included into array of visible menu items:


On button click (dashboard module) we call function, where router navigation happens to accounts module:


Let's see how this functionality works. I click on Accounts button to call a function and force router navigation:


Accounts module will be opened (through router navigation), but currently highlighted menu item will stay as it was (Dashboard). This makes it impossible to navigate back to Dashboard (unless we navigate to another module and then navigate to Dashboard):


Solution for this problem is to change selection property of ojNavigationList component in HTML:


Instead of pointing to router stateId directly, we should point to computed function. This will help to control currently selected menu item. But we still need to update router state, when menu item is selected. For that reason I'm using beforeSelect property, which points to function, where router state is changed:


Selection property value is calculated by function, which returns NULL, if accounts is currently selected module. This allows to remove focus from Dashboard menu item, after navigation to accounts. Once focus is removed, we can click back on Dashboard and navigate. For all other modules - current router state ID is returned. Select handler call router API to navigate to the module:


Navigation to accounts module from dashboard. Dashboard menu item doesn't remain focused anymore:


Navigation back to dashboard work too:

Tuesday, June 27, 2017

Oracle JET Modular Architecture Example

One of my favourite parts in Oracle JET - modular code structuring support. This allows to split application functionality into modules and reusable functions. In this post I will show how you could leverage Oracle JET modular architecture not only by implementing common code functions, but also by managing data maintained in common modules.

Let's jump to the example (download or browse through sample code on GitHub repository - JETModularArchitecture). Sample application is based on JET template. I have created two common modules - dashboardChartHelper and dashboardTableHelper. These modules define data structure to be displayed in the dashboard and provide API to manage this data from consuming module:


Both helper modules are imported into consuming module - dashboard:


Dashboard module defines variables (chart and table data), which are initialized from variables assigned with data structures in helper modules:


There are two wrapper functions, calling API functions from helper modules. API provides data manipulation logic, which changes chart data structure. Wrapper functions are invoked from dashboard UI:


Here is the implementation of API functions - data array changes:


What is great about such structuring - data and data changes logic can be encapsulated in common helper module. As soon as we have observable variable defined in consuming module (dashboard), which points to the method helper method (where data is changed) - changes are automatically visible on UI.

Here is the data coming from helper modules rendered in dashboard module:


Press on Add Group E button, this will call helper module API function to update data array cached in that module. In turn observable variable in dashboard module will be updated and data displayed on UI will be refreshed:


Press on Remove Group E button - chart data will be changed again:

Saturday, October 26, 2013

Reusing and Extending ADF BC Entities from Common Model

This post is about ADF architecture and better application structuring with EO reuse from common model. I describe how to implement additional requirements to common model in extended ADF BC Entities. Great power of ADF framework - reusability. You should reuse as much as possible, this would simplify maintenance and future development of your application. I will be talking about ADF BC Entity Objects (EOs) reuse in this post. I would recommend to keep EOs in common model project and reuse them across the application. Fair requirement would be to have slightly different EO for specific use case - instead of creating new EO for the same DB table, we could extend original EO and implement specific changes. As for example, we may have different set of business rules, different doDML logic.

Sample application developed for this post includes Common Model library and Main application - eoreuse.zip. Common model library is based on Employees and Jobs EOs, associations and EO implementation generic class:


Employees EO from common model library implements business rule for Hire Date attribute - date must be today or in the past. The idea is to show that business rules from common EO will be inherited by extended EO as well:


Generic EO implementation class overrides doDML method, I do this to show the sequence of doDML calls from extended EO:


doDML method from Employees EO is overriden in the same way as in generic EO class:


We switch now to the main application - where common model library is imported successfully. Employees and Jobs EO's are available in the main application:


Here we can create new EO - extending Employees EO from common model:


In order to be able to change properties of specific attribute, we need to override it. Salary attribute is overriden and I have defined additional business rule - salary value check:


As we have extended main Employees EO, we need to define discriminator attribute. This is a key part, otherwise main Employees EO will stop working. As there is no really discriminator attribute in Employees, I'm going to create new transient attribute with default value 0:


Discriminator attribute is included into extended Employees EO, this attribute is set to be hidden - it will be never displayed on UI:


I have defined one additional association in main application - between Employees extended and Jobs EOs. We can assume, this would be required by specific use case:


Employees VO is created inside main application, calculated discriminator attribute is set to be populated from query expression - always returning 0:


This is how value is returned for discriminator attribute from SQL query:


The same value 0 is set for discriminator in VO based on extended Employees EO, it is calculated from SQL query expression:


Query for this VO is the same as for VO based on main Employees EO:


There are two View Links defined for Employees VO based on extended EO. First View Link is reusing Association from common model between employee and manager, this works perfectly for extended EO. Extended EO can reuse Association defined for parent EO:


Second View Link is using Association defined in main application - one between extended Employees EO and Jobs from common model:


Here you can see final ADF BC Data Model structure exposed. Master-Detail relationship between Jobs and Employees from common model, Master-Detail relationship between Employees VO based on extended EO and Jobs from common model, plus employee - manager relationship reusing Association from common model:


Sample application provides ADF UI implementation, where two tabs are given. First tab displays Employees VO structure based on main Employees EO. Second tab displays Employees VO structure based on extended Employees EO.

In the first tab - in the Employees list based on selected Job, business rule common model for Hire Date is working:


In the second tab, Hire Date business rule is working:


Plus additional business rule for Salary attribute, from extended EO is working as well:


Same rule is not reproduced for Employees data in VO based on main EO - as expected:


Make sure to enable ADF logger for application classes, we should check the sequence of doDML calls:


In the case of VO based on main Employees EO - firstly doDML from Employees EO is called and then from generic Entity Impl class:


Now, if you don't want to call doDML from main Employees EO, when calling doDML for extended Employees EO - make sure to change extending class:


As expected - doDML from extended EO is called and then doDML from generic Entity Impl class: