
OutSystems and Microservices in Practice
How to create a loosely coupled architecture in a complex environment
Introduction
When involved in a large OutSystems project to replace a custom build ERP like system with hundreds (300+) eSpaces and many extensions to integrate with hundreds of tables, you must organise your architecture in such a way that the impact of changing a library module (eSpace or extension) is minimized. Next to applying the 4 layer canvas and grouping modules in functional components per layer, a microservices architecture can be applied.
In a microservices architecture, the end user applications (front end) are loosely coupled from the integration services (back end) that provide integration with enterprise databases and external services. This loose coupling minimizes the impact of changes in the backend.
This document elaborates the services architecture illustrated with an example. Integrating systems using extensions as well as services are discussed, together with the pros and cons of the microservices architecture.
Architecture
The microservices architecture consist of two infrastructures, the microservices infrastructure that exposes the enterprise capabilities through rest APIs and the application Infrastructure that provides the end user application consuming the rest APIs.
Microservices Infrastructure
External API Level
This level is a composition of APIs that exposes the services to external consumers.
It is merely a technical wrapper for the real services implemented at the Core Services Layer. This level translates those services to the APIs provided to the external systems
Core Services Level
This level implements the services, with all the business rules and core entities
Integration Services
Integration services connect to Backend Systems and Corporate Databases using extensions or consuming APIs.
Applications Infrastructure
Applications or end user layer
OutSystems applications consume the services and web blocks provided by the core and library services layers.
Extended Services
Extends the cores services, caching data in local entities and reusable Web Blocks to promote RAD capabilities.
Integration Services
This is an extra layer that I’ve added to the model, which is consumed by Extended Services. It consumes APIs provided by the microservices or external systems and provides façade server actions. Using a façade ensures that the consumers of the façade server action are independent of the consumed service contract. Thus lowering the impact of a version upgrade or a switch to a completely new service.
Service Façade
A service façade decouples the core service logic from the service contract thus enabling loose coupling. The introduction of the façade component introduces design effort and performance overhead.
Example OSMDb
For the example we modified the OutSystems Movie Database application to implement the architecture.
- The Cinema entity is removed from OSMDb Core and replaced by a MovieTheater entity in a separate MovieTheater Core layer (MovieTheater_CS)
- The Movie entity is renamed to Film and moved to the Film_CS and exposed by the Film_API
- The consumption to the TheMovieDb api is moved to a TheMovieDb_IS eSpace.
- The application is refactored to implement the microservices architecture
The goal of this modifications is to illustrate how you can create a loosely coupled architecture by decoupling the Core and Integration Services layers from the front end layers. Thus minimizing the impact of changes to these lower layers.
The picture below shows the resulting application landscape which we will describe in the next sections.
Movie Theater Domain
MovieTheater API
The MovieTheater API defines the contract and exposes the services for MovieTheater_CS. This ensures decoupling from the implementation details of the core service.
- MovieTheater_API to provide movie theater crud services
- Create — Creates a MovieTheater record
- Delete — Delete the movie theater with the given id.
- GetById — Return a MovieTheater by Id
- GetFiltered — Returns a list of MovieTheaters that meet the SearchKeyword by Name, Description or City
- Update — Updates the MovieTheater record
Movie Domain
MovieDomainAPI
The MovieDomain API defines the contract and exposes the services for Movie_CS. This ensures decoupling from the implementation details of the core service.
- MovieDomain API to provide movie theater crud services
- Create — Creates a Movie record
- Delete — Delete the Movie with the given id.
- GetById — Return a Movie by Id
- GetFiltered — Returns a list of Movies that meet the FilterCriteria
- Update — Updates the Movie record
OSMDb Domain
OSMDb
The OutSystems Movie Database application. See the Developing OutSystems Web Applications excersices for an overview of the application.
For this version the Cinema and Movie entities are not cached. As a consequence all Cinema and Movie aggregates are replaced with corresponding server actions. The drawback is that we lose pagination and column sorting. This can be solved by adding pagination and custom sorting to the APIs. However most use cases do not require pagination but merely a more refined search action.
OSMDB_CS
This is the original OSMDb Core Services layer without the Cinema entity.
Movie_ES
Movie Extended services combines the results of the Movie Domain APIs and TheMovieDb API.
Entities
- Movie
The Movie entity is exposed read only and is used as a dummy entity. No data is kept in this entity. By using an entity instead of a structure we are able to add a caching mechanism. When caching is applied we can also benefit from the platform’s query optimization. The caching mechanism will be elaborated in a future article.
Server Actions
- MovieCreateOrUpdate
- MovieDelete
- MovieGetById
- MovieGetFiltered
For example the MovieGetById Server Action calls the FimlGetById and the TMDB_GetMoviePosterPath façade actions to provide an enhanced movie record.
Cinema_IS
Consumes the MovieTheater_APIs and exposes facade server actions using the OSMDb corporate data model Cinema structure.
Entities
Server Actions
- CinemaCreateOrUpdate
- CinemaDelete
- CinemaGetById
- CinemaGetFiltered
Film_IS
Consumes the Film_API services and exposes the façade server actions
Structures
CDM_Film; Normalized structure independent of the API structrure
Server Actions
- FilmCreate
- FilmGetById
- FilmGetFiltered
- FilmUpdate
TheMovieDB_IS
Consumes TheMovieDB API and exposes a facade server action.
- TMDB_GetMoviePosterPath — Invokes the movie db rest api and returns the retrieved movie poster path
Advantages and disadvantages
Applying a microservices architecture has pros and cons and one should weigh them properly when deciding to implement this architecture or not. In the next sections I’ll list the advantages and disadvantages.
Advantages
- Less impact of changes through loose coupling
- Normalized data definition independent of the datasource
- External data definitions from extensions or consumed api’s is hidden in the façade service.
- Gradual implementation of changes through service versioning
- Enables the migration from an enterprise database to a OutSystems native database
- When using normalized entities instead of structures caching and synchronisation patterns can be applied. See the article on Core Services Abstraction for a description of the patterns.
Disadvantages
- More development effort
- Possible performance degradation by invoking rest services instead of direct calls.
- Loss of accelerators such as scaffolding when using structures
- Must implement a synchronisation pattern when using normalized entities