Programming languages
Discussing programming languages is something that can be controversial, primarily because many developers tackle programming languages in a great hurry. However, programming languages should be seen as what they really are, a working tool. Every tool has a specific purpose and programming languages are no different.
It is just an analysis focused on our business, the news portal, which we will use to get to the point of how to select a language.
A big plus point for microservices is the heterogeneity of applications. In other words, it is not necessary to think of a single stack to apply to all business areas. We can thus define each microservice stack that applies, including when it comes to a programming language.
Basically, any programming language that meets the internet can be used in microservices. The difference is due to the requirements and domain boundaries that must be encoded. Some domain indicators can help us in this process.
If a microservice has strong mathematical processing load requirements, or where immutability of values is something positive, functional languages would be an interesting way to go. If there is a demand for processing large masses of data, then a compiled language with a robust virtual machine may be the answer.
Remember that missing this strategy could compromise the project deadline or even the entire application architecture. The fact is that several aspects should be analyzed before any definition, such as:
- Proficiency
- Performance
- Development practicality
- Ecosystem
- Scalability cost
Proficiency
The first goal for a software developer is to achieve proficiency in any programming language or paradigm. Achieving a good level of proficiency is not easy, and some languages may have a steeper learning curve than others.
Problems arise when proficiency in a language ends up creating a comfort zone from which a developer or team finds it difficult to leave. In contrast, a myth must be overthrown: that one programming language is much easier than the other. Obviously, a language may prove simpler than another at first, but in the end what will count is the practice time and the number of scenarios experienced by a developer with a programming language.
Another myth that must be fought is that all languages are equal at their core and that only the syntax changes. This is one of the worst possible errors that can be committed. Languages can be quite different in internal design and performance, although they have similar syntaxes.
Proficiency is something that should be considered when deciding which language to apply for a microservice. However, it should not be as decisive as this one.
Performance
This is a key requirement in choosing a programming language for a microservice. When we talk about performance for microservices, there are many points where performance can be a problem: the network communication layer, access to the database, where the servers are available. All these points can be problematic for microservices. The programming language cannot be another can of slowness.
When the target is microservice performance, no matter the skill of the development team, it should be used for best second language benchmarks and stress tests.
Something that often creates misunderstanding is considering the speed of a development team to implement a feature and performance requirement. Performance is related to a metric similar to how a code behaves when responding to a request or performing a task. Definitely, personal or team performance is not included in this metric.
Development of practicality
This is the requirement responsible for measuring the speed applied to a feature going into production. Development of practicality touches two teams: the development team that already exists and the development team that can come into existence.
As has been said before, the word success can be a problem for an application and consequently for the product owners. Keeping the base code simple and understandable is fundamental to facilitating code changes and for implementing new features.
Good programming practices can help us to understand the legacy code, but often the language itself, because the verbiage is not very friendly.
There are scenarios where a programming language, given its characteristics, is extremely performative. But the cost of time to implement something new, though it may be simple, can be very expensive.
Think of a scenario where a start-up has just launched its product. The product is also a Minimum Viable Product (MVP) and was launched in the market to go through public validation in general. If this MVP succeeds, it is essential to publish new features as quickly as possible. In this case, the performance is not the problem, but the practicality of new interactions on the code.
When we are developing microservices and we decide to use this programming language it is an important aspect to be noted.
Ecosystem
The ecosystem of a programming language is a crucial one.
We all know that parts of the frameworks are almost essential to gain speed and simplicity in the development of any application. With microservices, the scenario is identical.
It is feasible that features are not developed by something being blocked on the technical side. Of course, the microservices architecture is providing a plurality of very broad tool options. However, understanding the possible drawbacks when choosing a programming language, and therefore inheriting its ecosystem, is critical to the engineering team responsible for the implementation.
There are cases where a programming language is very performative, but the ecosystem that would win on development speed compromises performance. This type of situation is far more common than you think.
Another point is when a language is very simple, but the frameworks are not mature enough; you end up generating unnecessary complexity.
Observing the ecosystem of a programming language, and understanding the risks it is assumed we gain by inheritance, is fundamental to the adoption of a language.
Scalability cost
The cost of scaling an application is linked to two major factors. The first is the speed of the selected stack used to implement the software. Specifically, the speed and capacity of processing algorithms and answering requests. The second factor is the ability to scale the application of the business part. How long is it applied to features and especially the predictability of new features? The time to create something new or redesigning something that already exists is also expensive.
With microservices architecture, the cost of scalability is usually related to the concept of having smaller areas and parts which are less integrated. Even then this cost is very important.
Think of two applications, one with strong interactivity with the end user, such as an online game or editing documents in real time. Another application is fully illustrative, has an editorial part, but is not open to all users; a newspaper or streaming provider are good examples.
The application of real-time data processing and response time to requests must be fast and dynamic. In the second, application processing, it is not something that has much relevance, as the information may be in a cache or statically stored.
The cost will be high when you do not understand the nature of the microservice to be developed.
Making choices for our application
Because this is the point to choose a programming language for microservices and applications in general, we will apply this knowledge to select which programming language we use in each area of our service.
We know that our news portal has the following areas:
SportNewsService
PoliticsNewsService
FamousNewsService
RecommendationService
UsersService
Given our fields of business, we can divide them by similarity of features. SportNewsService
, PoliticsNewsService
, and FamousNewsService
have similar behavior. These microservices are news providers and are more focused on the consumption of data than receiving information.
These microservices may have an identical starting stack, which does not mean they should always be identical or that they need evolve in the same direction. Regarding the programming language, performance is not as crucial, but the speed of change and implementation of new features is crucial.
RecommendationService
is very different from the other microservices. There is no direct interaction between the end user and the application. Nor is there a direct interaction between the editorial area and this software. RecommendationService
is a support microservice; there are other microservices and all the interactions and operations are on the technical side. Loading and interaction occur completely asynchronously, but processing will certainly be higher than in other microservices. However, this is not a real-time application.
UserServices
is a microservice with dynamic interaction on all sides, both for the end user as well as the editorial layer. The information from UserService
may also be consumed by the other microservices such as RecommendationService
. It is noteworthy that on this layer, caches can be dangerous, providing wrong information if they are not correctly invalidated. As UserService
is a microservice that supports a direct relationship with the internet, it leads us to a programming language that has the speed of response for requests, processing speed, simplicity in implementing features, and good asynchrony APIs.
With the characteristics of each sector in mind, it is the time to think in a completely practical way to select a programming language that applies to each microservice. Let's consider each of the five aspects mentioned at the beginning of the chapter associated with the nature of the issues.
Comparing programming languages is complex, but in this case, we need to make choices. Many languages could be compared. However, for our application, we have chosen five for the comparison based on popularity, personal experience, documentation, and actual cases of applicability. The languages are Java, C#, Python, JavaScript, and Go.
Java
Java caters perfectly to the object-oriented paradigm. It is very performative, which reduces the cost of scalability. With the developments presented in the language, Java is not as verbose as before but still has a sharp verbiage, requiring developers to have the great proficiency to maintain the code and implement new features. Regarding the ecosystem, Java Virtual Machine is fantastic, mature, and very stable, but the frameworks are usually not as simple as they could be.
C#
Just like Java, C# perfectly meets the OOP paradigm. It is very performative, reducing the cost of scalability. C# has a similar verbiage to Java, with some additional practicalities. Proficiency with C# must also be high to generate speed in development. The ecosystem is very mature, with performers and not as complex frameworks.
Python
Python does not have the syntactic features of Java, C#, and OOP, but it caters well to the paradigm. As a fully interpreted language, it is not as performant as the other languages mentioned previously, which means more servers are required to support the same load that interpreted languages do not support. However, the higher cost of scalability is fully compensated when it comes to code maintenance and new features development, due to the simplicity of the language. A developer needs a fairly short amount of time to achieve proficiency in the language. The ecosystem is full of simple frameworks. Within the same ecosystem, there is a range of options for language interpreters, which helps in additional performance gains.
JavaScript
Undoubtedly, JavaScript is the language that generates less friction between the frontend and backend, as the backend JavaScript is optional, and the frontend is practically mandatory. It is a language with a good level of complexity. The developer needs to know the internal behavior of JavaScript well to not make bizarre mistakes. The paradigm that best applies to JavaScript is functional. The ecosystem has vast frameworks, too many in some cases, generating complexity especially regarding the builds. It has good performance, but it requires good proficiency to maintain the code and write new features.
Go
Go is a compiled programming language and has great performance. No doubt it is one of the languages that has seen growing popularity in recent years. Go is a language with the imperative paradigm, although very few developers understand that there is some level of OOP. The ecosystem's main characteristic is a standard robust library, making frameworks in some cases unnecessary. But the ecosystem is not perfect, with problems in simple things like version control. Go has simple and easily readable syntax. The main feature of the Go syntax is the convenience that it applies and how it handles concurrent programming.
To make it easier to compare, we will use the following chart as support:

In the case of our news portal, these are the languages that will be applied:
SportNewsService
,PoliticsNewsService
, andFamousNewsService
: These microservices make use of Python. It is the typical scenario where language applies very well. The lower performance of Python will not be a problem even if the portal receives many hits.RecommendationService
: This application also uses Python. This choice is fully related to a connection between performance and practicality in using other tools that will make the stack of our microservices. A microservice like this does not have the requirement of being real time; we can use something that has simplified APIs and is not as disruptive to the rest of the ecosystem.UserService
: These microservices apply Go.UserService
is a microservice that interacts with users as well as providing information to other application microservices.
The fact is that there is no perfect tool for everything. All languages have shown positive and negative points. With the great technological plurality that we can apply to the microservices architecture, managing the stack that best applies in each scenario is our role in this case.