ERP software is a good example. Initially, SAP started with the Hana Enterprise Cloud (HEC), where each customer had their own S/4 Hana installation. This kind of cloud solution is called cloud ready, in the sense of: Yes, it can be installed in the cloud computing center, but that is just another location. It is more related to the term “outsourcing” than cloud.
Having to maintain many individual installations is expensive for the cloud provider. It is cheaper for one company to host many similar systems than for each customer to maintain their own installation – there are cost-saving potentials.
Because the ERP application is client-aware, we could call such client-id the tenant of the application. Consequently, one installation supports multiple companies. This is a somewhat better solution. It is problematic to e.g. decide what customers share one system, but it at least reduces the number of systems to maintain. Such instance-sharing, tenant-aware, solutions are the easiest way to get a cloud-native software – the next level of cloud applications.
These can be powerful applications even without a backend and database. For example, the drawing tool draw.io is like a personal installation of Microsoft Visio. The user works only in the browser, including storing the files. When the backend gets more requests and starts to become the bottleneck, another server is added to serve the requests. There are no customer-specific databases or settings, hence each server can be used for any request. The result is perfect scalability and elasticity to match the demand while offering low operational costs. With such a solution, we have achieved the gold standard – a public cloud application.
Business applications require a database for all users to work on the same data. This database can either be an integral part of each service or seen as another service. Cutting the service horizontally means one layer acts as the application providing the UI screens, and the database is another layer. A user connects to any application server, renders the screen, and the data is read from the user’s assigned database. The webserver is a stateless service just like in the example of draw.io above. The database services need their own scaling mechanisms, e.g. by using Hana Cloud Service where SAP promises to take care of the scaling.
A vertically cut service treats the application server instance and the database as one unit, as one service. When more users request the service, the service as a whole – logic and database – should start up another instance. In a pure microservices architecture, this is the preferred approach.
Example: One type of service contains all customer master data, another service all sales orders. Both need to talk to each other a lot, validating that the order is for a valid customer and has a proper delivery address. All the advantages of a database like transactions, data consistency, cross table joins, etc. are lost and need to be implemented on the service layer again. Furthermore, as each service type consists of n instances, these need to be synchronized via some sort of messaging bus.
I remember when initially, the architects wanted to follow the microservices book to the letter and the complexity of recreating the database guarantees overwhelmed the development team soon.
Another area of concern are customizations, which is something that every customer requires – different global settings and individual application code to tailor the application to the customer’s business needs. In the above example, we had a customer-agnostic application logic as service and a customer-specific database. If the requirement is to allow customer-specific application logic as well, we are back to square one: Each customer has their own set of application servers and their own database. That is the HEC cloud-ready architecture we talked about at the beginning as first cloud evolution.
What are the alternatives? On the one hand, I could imagine customizations in the application logic. Simple example: Instead of showing a neutral background image for all customers on the home screen, the screen has the option to specify a company logo. This needs to be built into the application and customers must wait for the feature to be deployed.
On the other hand, if one customer requests a change nobody else needs, the feature will never make it into the product. Depending on the mood of the cloud provider, either only very few customizations are added, or the application gets more and more switches until it is so complex, nobody understands all the – partly contradicting – options.
Requirements define the architecture
When there is no perfect solution, it is important to pick the architecture matching the use case the best. In one project, the team was tasked to build a cloud application. It was a specialized business solution for a handful of customers with a few 100 users each. What was the approach? A stateless microservices architecture, as this was the shiny new trend.
From a requirements point of view, the number of potential users was low, and scaling was the least of the company’s concerns. Furthermore, due to the sensitivity of the data, it was required by law to keep the data physically located in regional data centers. In other words, the requirement was to deploy at least one instance per country, and each would have a low number of users.
The implementation approach, however, was a stateless application aimed at unlimited scaling in a single IT center. This public cloud solution would have been installed and operated in every single country to serve a few customers each. This would have been quite expensive, wouldn’t it?
Looking at S/4 Hana Cloud again, we can see all variants used together, depending on the use case.
- The external APIs are stateless. There are no user sessions, no user defaults, no begin transaction and commit work. An API is called upon, it does something and is done. Period.
- The internal customizations are stateful. For example, BADIs can be used to invoke custom application logic at places SAP imagined a business extension might be needed. This logic is part of the ERP transaction.
- If the customer needs something completely new and for personal use only, a custom service can be added to the system seamlessly.
This is a pragmatic approach for large business applications.
In summary, when building a cloud application, the highest level, a public cloud solution, might not always be the best solution in terms of cost.
For a stateless application, one that is invoked with data and returns information purely based on that data, the best architecture is using Serverless Functions. Every cloud vendor provides that, e.g. AWS Lambda Functions. Hopefully Kubeless, the Kubernetes-native solution, sees a good adoption rate and becomes the standard. Today, we need to write an application with input and output, wrap that into the cloud vendor-specific framework and deploy it. No rocket science either. If no users call this service, then no instance is active. If millions of requests flood the service, instances of the function start up within milliseconds, serving all requests. A perfect public cloud solution.
Business applications favor an architecture where the database is one service and the application another service, combined with stateful sessions. This is a good compromise between functionality, scaling, and flexibility. A user logs in to the application, the backend associates a session-object with this user session and this object contains all company-specific and user-specific settings. Thus, each application can access the settings very fast. SAP S/4 Hana is very close to that, except it puts more emphasis on stateless. Such a solution is more on the cloud-ready side.
A microservices architecture is another approach to public cloud solutions for cases where there is high complexity, and unlimited scaling is required. Getting both properties together requires a complex and hence expensive solution. SAP Cloud Platform proofs the point with its microservices architecture. Approuter, security, deployment, … all is very difficult in the microservices world. For most applications in the business world, there are cheaper ways.
Thanks to containers, a cloud-native application is often the most cost-effective solution. The container provides the starting point and customers can add their customizations, their application logic and new functionalities on top of each container layer. Upgrading a container is no problem, either.
Let’s imagine we have 1,000 users, and all of them need to upgrade one component to the next version for security reasons. Without containers, that would mean 1,000 installations on the operating system level. With containers, the layer containing the library is upgraded. As all 1,000 installations are built on top of that base container, we must only trigger the rebuild of the customer containers. The rebuild takes the base image, adds the custom files on top, and after restart, the new version is available.
Hosting containers is cheap, scaling is also supported; it leaves little to desire. Yes, it does not scale from zero-to-unlimited, but from one-to-a-lot of users which is sufficient in most cases.