2/3 Polyglot microservice development with Dapr – What are the challenges of polyglot microservice development?
This is the second part of a blogpost series about polyglot microservices, which is based on my master’s thesis on “Polyglot Microservice Development with the Distributed Application Runtime”. In the first part we looked at polyglot microservices, how they differ from single language microservices, what is necessary to implement them and their advantages and disadvantages. Now, in this part we will have a closer look at the challenges that experienced developers face with polyglot microservices. This is valuable for understanding the challenges that modern tooling needs to solve to reduce the additional complexity introduced by polyglot microservices. In the third part we will then look at available tooling and how it might help us to solve these challenges.
- Challenges of polyglot microservices
- Implementing non-functional requirements in different programming languages
- Implementing asynchronous communication, observability, and state management
- Coupling to third-party components and their dependencies in microservices code
- Different tooling in different programming languages
- Needs for tooling that simplifies developing polyglot microservices
- Abstraction layer and a unified, programming language-independent API to third-party components
- Tooling that can be used independently of specific programming languages via an abstraction layer
- Best practices to help select the appropriate technology from the wide range of tools and services available
- Basic components that implement non-functional requirements and can be used independently of programming languages
- 1/3 Polyglot microservice development with Dapr – What are polyglot Microservices?
- 2/3 Polyglot microservice development with Dapr – What are the challenges of polyglot microservice development?
The following sections are based on expert interviews, which were conducted as a part of my master’s thesis. These interviews included six experts with 7 to 20 years of professional experience in software developing and 4 to 7 years of experience with microservices. They were selected from three different companies that are developing and working with small to enterprise-sized software architectures.
The goal of the interviews was to identify the most frequent challenges that developers face with polyglot microservices and based on this, the most common needs for tooling. This was necessary because surprisingly, the subject of polyglot microservices has seen little research so far despite being used by many software developers, according to other studies. Moreover, only parts of the identified challenges were known prior to the interviews, possibly because previous research did not take this perspective into account. Therefore, the results are useful for understanding the causes of the additional complexity introduced by polyglot microservices and what tooling is required to simplify developing them.
Challenges of polyglot microservices
While polyglot microservices have several advantages, using multiple programming languages and thus different libraries, SDKs, and frameworks at the same time has its challenges. According to the results of the expert interviews, the following are the most frequent challenges developers face when developing polyglot microservices.
Implementing non-functional requirements in different programming languages
A major challenge is implementing non-functional requirements in different programming languages. Particularly, the main problem here is a high effort for the implementation of non-functional requirements and their high proportion of the code in a microservice architecture. Especially compared to a monolith. In the context of polyglot microservices this is problematic because the sharing of implementations between different programming languages is difficult. Thus, non-functional requirements are often implemented multiple times.
As a result, a task that is already problematic and requires high effort gets even more expensive with every programming language that is added. Therefore, in practice, only a limited number of programming languages are used. This contradicts the often-mentioned advantage of the free choice of programming language in microservice architectures. Furthermore, according to the results, programming languages are primarily chosen by their community support and the availability of libraries and SDKs.
Implementing asynchronous communication, observability, and state management
While implementing non-functional requirements in different programming languages itself is a major challenge, according to the experts implementing asynchronous communication, observability, and state management is an additional challenge on top. Indeed, the issue is that implementing these requirements is already a challenge in single language microservices. However, in single language microservices this problem can be mitigated by using libraries or frameworks that provide applications with these capabilities.
With polyglot microservices, on the other hand, this gets harder because libraries or frameworks vary in different programming languages. This means developers must implement these non-functional requirements multiple times, even when using libraries or frameworks. In conclusion, this leads to the same issue as before: Requirements that are already hard to implement must be implemented multiple times, thus increasing the complexity of the system.
Coupling to third-party components and their dependencies in microservices code
Tight coupling of microservices and third-party components is another challenge, which was mentioned by most of the experts. In general, changing third-party components after they have been implemented is an expensive task. This is especially the case when integration libraries and SDKs are used directly in the code without an abstraction. But even with an abstraction the challenge is not solved. Of course, an abstraction makes the task easier, but the abstraction will also use integration libraries and SDKs for third-party components. Consequently, in both cases changing third-party components such as databases or a message bus remains an expensive task.
In our context of polyglot microservices this gets even worse, because integrating a third-party component in multiple languages usually means using different SDKs and integration libraries. So, if we try to change our third-party components, we must integrate multiple new integration libraries in our code or abstraction layer. Therefore, in practice, it is avoided to change third-party components unless it is absolutely necessary. But this also means that developers cannot leverage new and innovative components, which hinders innovation.
Different tooling in different programming languages
Finally, different tooling in different programming languages is a challenge that is intertwined with other challenges, is nonetheless, an important one. Usually, knowledge with a specific programming language and the corresponding frameworks, libraries and SDKs cannot be transferred to a different technology stack without hurdles. As a result, developers must learn to use new frameworks, libraries, and SDKs to use another programming language. This is a fact, which makes the adoption of new programming languages hard and expensive. Consequently, if polyglot microservices should be used, a lot of additional overhead is introduced by learning new tools on top of learning new programming languages.
Needs for tooling that simplifies developing polyglot microservices
In addition to the challenges, the experts were also asked about their need for tooling to simplify the development of polyglot microservices. The results are the following topics that were the top needs for tooling based on the interviews. Furthermore, they are mostly correlated with the challenges we have looked on before. So, it can be concluded that if this tooling existed, it would solve most parts of the challenges.
Abstraction layer and a unified, programming language-independent API to third-party components
The first need, which was mentioned by all the experts, is an abstraction layer and a unified, programming language-independent API to third-party components. This need is linked with the challenge of coupling to third-party components and their dependencies in microservices code, which was described earlier. According to the interviewees, this should make it possible to connect to third-party components in any programming language without dependencies in the code. Furthermore, this would reduce dependencies on the hosting platform, which is desirable in modern multi-cloud strategies.
The benefits of such an abstraction layer and API would be easier adoption and changing of third-party components without the risk of expensive refactoring of the code. Additionally, this would reduce the complexity of adapting new programming languages because there would be no need to learn and adopt new libraries and SDKs to interact with third-party components.
Of course, one might say this is already possible with modern cloud services that usually offer a REST API, which provides an abstraction layer. However, working purely with the REST APIs requires a lot more work and knowledge than using the SDKs and Libraries, which codify best-practices and knowledge of the service’s provider. And as the interview results have shown, the problem prevails even in the presence of widely available REST APIs. Therefore, additional tooling is needed to solve this challenge.
Tooling that can be used independently of specific programming languages via an abstraction layer
The second need, which was also mentioned by all the experts, is tooling that can be used independently of specific programming languages, again via an abstraction layer. This need is a consequence of the challenge of implementing non-functional requirements in different programming languages. Because that is a challenging task that requires knowledge in different programming languages, different Libraries, SDKs, and Frameworks, simplifying it, would allow for a much easier adoption of new programming languages. Thus, enhancing the choice of programming languages that are available to implement a microservice.
Additionally, existing implementations of non-functional requirements could be reused between different technology stacks and therefore ease the adoption of polyglot microservices. In conclusion, such an abstraction layer would finally allow the free choice of programming language that is often touted as one of the key benefits of the microservice architecture.
Best practices to help select the appropriate technology from the wide range of tools and services available
According to half of the experts, more best practices are required to help select the appropriate technology from the wide range of tools and services available. In contrast to the previous needs, this need is not directly connected with one of the challenges. However, when viewed from another perspective, it becomes clear that polyglot microservices and thus, multiple programming languages also make choosing tools and services harder because more than one of them must be selected. Especially, when the same tooling and services are not available for all programming languages that are used, which connects to the last need.
An additional point is the challenge of tight coupling of third-party components and code of microservices that makes the selection of a tool or service often a final one. Therefore, more best practices to select the appropriate technology in combination with programming language independent tooling could solve the challenge, which brings us to the last need.
Basic components that implement non-functional requirements and can be used independently of programming languages
Instead of implementing the same non-functional requirements, repeatedly in every programming language, many of the experts voiced a need for basic components that implement non-functional requirements and make them available independently of programming languages. This clearly resembles, what classic libraries already do for us developers. However, they are usually limited to one programming language or a specific technology stack and therefore are no solution for polyglot microservice architectures. To summarize, these basic components would be the transfer of the concept of single language libraries into the world of polyglot and distributed software systems.
The benefits of such a concept could be significant. It would make it possible to develop high-quality components that can be plugged into a software system no matter the technology stack or programming language used in the system. Especially distributed systems, which are hard to do right, could benefit from this by offloading the hard parts of distributed systems to developers that are experts in designing them. Of course, this is already possible with traditional libraries, but this approach is usually limited to popular and widely used programming languages and fails with newer and more exotic programming languages. Consequently, this problem is solved for single language microservices but not for polyglot microservices.
Now that we know the most frequent challenges that experienced developers face when developing polyglot microservices, we have a much clearer understanding of the problems modern tools need to solve to simplify developing them. Furthermore, we also had a look at the kind of tooling that would solve the problems associated with polyglot microservices. Luckily for us, in 2021 exists tooling that might solve these challenges and thus might simplify the task of developing polyglot microservices. But if this is really the case—we will see in the third part of the blogpost series, in which we will have a closer look at various kinds of tooling such as microservice frameworks, Kubernetes, service meshes, and Dapr. Stay tuned!