In this article, I want to mention about the SOLID principles but this time for cloud-native applications.
As we know, SOLID principles are undoubtedly one of the most important sets of principles in the object-oriented software development world.
We are generally trying to develop our codes based on the SOLID principles when we develop applications, because:
- It provides coding standards in order to be well-designed.
- It also provides easy maintenance.
- In addition Extendability and Reusability.
I wanted to mention a few important points of the SOLID principles. If we start to talk about the SOLID principles, these important points don’t end.
We are trying to develop our applications around these principles at the code level. So what about the application level? Are we paying also attention at the application level? Especially if we talk about the develop cloud-native applications.
A few days ago, I have shared a post via LinkedIn like below.
After shared this post, I got a few question messages about the SOLID principles for cloud-native applications and I decided to mention that with a short article. By the way, Red Hat has very nice articles on this topic.
As you know, in today’s technology age, developing highly scalable cloud-native applications is very important. There are a few container-related best practices and principles that applications must follow in order to be a good cloud-native citizen.
Well, What are the SOLID Principles for Cloud-Native Applications?
These principles are divided into two different categories as “Build time” and “Runtime“.
Build Time Principles
1) Single Concern Principle
The content of this principle similar to the Single Responsibility principle. It says each container should handle just one concern. Thus, the desired container can be scaled or replaced independently.
If different functionalities need to be handled, cloud-native patterns can be used such as sidecar. For example, this pattern allows the container to be consist of isolated heterogeneous components (Logging, Tracing, Proxying).
2) Self-Containment Principle
In a nutshell, this principle says a container should be contained everything (libraries vs…) that needs to be able to run in the build time, except configurations since they can change environment-based.
3) Image Immutability Principle
The goal is a containerized application should be immutable. This means, once an application built, it should not change environment-based and should be configured according to needs. If anything needs to be changed in a containerized application, to do that it should be created a new image and it should be reused across the environments.
1) High Observability Principle
As we know, in the distributed systems, one of the important topics is observability. To be able to see the current health of an application will help us to avoid possible problems easily.
As in the “Logs” section of the Twelve Factor App, especially logging gives us the ability to monitor the behaviour of an application on runtime.
This principle says to treat your containerized applications as a black box, but should be implemented all the necessary APIs (health checks, tracing, logs, etc…) in order to monitor their behaviours.
For example, we can implement Fluentd, Logstash for logging aggregation and also OpenTracing, Jaeger for tracing operations.
2) Lifecycle Conformance Principle
The important point here is that the container should be sensitive to events which are coming from the platform. Also, it should manage its lifecycle with these events.
For example, a containerized application can perform warm-up or graceful shutdown operations as sensitive to the “PostStart” or “PreStop” events.
3) Process Disposability Principle
It is one of the most important principles. Containers should be transient as in the “Disposability” section of the Twelve Factor App.
This principle especially focusing on fast start and shutdown of a containerized application. Thus, at any time, a containerized application can be easily and quickly scaled out or replaced.
4) Runtime Confinement Principle
This principle is one of the most important principles for me. In a nutshell, it says that each container should have its resource usage conditions it will need and the resource usage should be limited with the defined conditions.
For example, it is necessary to specify how much memory or CPU a containerized application will use, also minimum and maximum instance values for auto-scaling settings.
It is possible to easily specify resource limits for a pod in the kubernetes environment as follows.
hpa: enabled: true minReplicas: 1 maxReplicas: 3 targetCPUUtilizationPercentage: 70 resources: limits: cpu: 300m memory: 300Mi requests: cpu: 100m memory: 100Mi
We shouldn’t forget that a containerized application, which doesn’t have its resource limits, can cause unwanted results in runtime. In addition, these unwanted results will adversely affect other services on the platform.
We are aware of the importance of following SOLID principles in object-oriented software development in order to develop a well structured and clean application. In this article, we mentioned about the SOLID principles that the application must follow to be a good cloud-native citizen.
As we know, cloud-native applications enable rapid software development with many great capabilities such as scaling.
Of course, there are many different techniques that can be applied on a case-by-case to make an application a good cloud-native citizen. The principles we have mentioned in the context of this article are the more fundamental and can be applied in many use-cases.