Microservices are “sweet” and have many advantages, such as faster development, better scalability, smaller independent teams, and so on. However, many teams struggle with microservices and fail to take advantage of them. What is the reason?
1. Management underestimates the complexity of developing microservices
I’ve worked with a lot of clients who are very bullish on micro services. For them, microservices are the “panacea” for all their problems.
As the discussion progressed, I found that most teams and their management underestimated the complexity of microservices development.
To develop microservices, developers need an efficient local environment setup.
As the number of services in the system began to grow, it became increasingly difficult to run a subset of applications on a single machine. This is especially true if you are building your application in a memory-consuming language such as Java.
Here are some key points related to the local development setup:
- The first important aspect of local development is having a good development machine.
I’ve found that most organizations want to use all the latest and most advanced technology, but they don’t want to replace bad Windows development machines. Developers are limited by their development machines. I’ve seen developers build microservices-based systems using VDI images or cross-configured machines. This not only reduces their productivity, but also prevents them from fully engaging in their work. A side effect of using a bad development machine is that developers don’t get quick feedback. If you know you’ll have to wait a few minutes to run an integration test suite, you won’t write more integration test suites that will make you more miserable. Bad development machines lead to bad development practices.
- Once you have the developers on the right development machine, the next step is to ensure that all services use build tools.
You should be able to build an entire application on a new machine without much configuration. Based on my experience with microservices, it also helps to use a root build script that builds the entire application.
- The next point is to make it easy for developers to run parts of the application on their systems. With all ports and volumes configured, you should use multiple Docker-compose files to provide different services.
- Next, if you use a container choreography tool like Kubernetes, you should invest in a tool like Telepresence to easily debug applications in a Kubernetes cluster.
If organizations lack an understanding of the complexity of microservices development, team speed will slow down over time.
2. Libraries and tools are not updated to the latest version
I find that a new platform has become a legacy. The team did not ensure that the dependencies were up to date or that tools such as databases were upgraded to the latest version.
As a result, the modernisation that began two years ago has been saddled with months of technical debt.
A few years ago, many teams started using the Spring Cloud Netflix OSS project for microservices. They use container choreography tools like Kubernetes, but because they started with Netflix OSS, they didn’t use all the features Kubernetes offered. When Kubernetes built in service discovery, they still use Eureka for service discovery.
Also, with a service grid like Istio, you can get rid of most of the services Netflix OSS provides. This helps reduce complexity and shifts many of the “cross cutting concerns” to the platform.
Another point to keep in mind is to keep the dependency versions of all services in sync.
Recently, I was working with a client that used Spring Boot to build microservices. Over the past two years, they have built more than 20 Spring Boot services. In their environment, they use versions of Spring Boot ranging from 1.5 to 2.1. This means that once someone sets up their machine, they have to download multiple versions of Spring Boot.
In addition, they lack many of the improvements that have been made in Spring Boot since version 1.5.
The recommendation is that the organization should create technical liabilities for these upgrades in its backlog. These technical obligations should be discussed as part of the meetings of the Framework Committee and resolved periodically. On my last project, we set up a one-week sprint every three months to update all dependencies to the latest version.
3. Leverage shared services to facilitate local development
Due to poor local development, most teams have come to rely on shared environments for critical services. The first thing on the developer’s machine is the database. Most young developers don’t realize that development based on shared databases is “evil.”
Here are the main issues I see in shared databases:
- Team members must establish a social contract for their work to avoid the Last write wins (LWW) problem. A developer can delete data that other developers have written for their work. This way of working is painful and failure-prone, and sooner or later it affects the whole team.
- Developers are afraid to experiment because their work affects other team members. We all know that the better way to learn is through experimentation and quick feedback. With a shared database, you can experiment. We need to experiment to come up with database schemas and perform tasks such as performance tuning.
- Another side effect is that it is difficult to test changes individually. Your integration tests will become unreliable, further slowing down development.
- A shared database must be treated like a pet, because you don’t want it in an inconsistent and unpredictable state. You might run into a scenario where developers want to test edge cases when the table is empty, but other developers need a table to record.
- Only the shared database has all the data the system needs to work. Over time, team members lost traceability of changes, so no one knew how they would replicate the same Settings on their machines. The only way to do this is to take the full database dump and use it.
- If you’re not connected to the Internet, it’s hard to do your job. This usually happens when you have a long commute or when you fly.
A database is just one example of a shared service, but it can also be a message queue, a centralized cache (like Redis), or any other service that can change.
The best way to solve this problem is to make it easy for developers to run the database on their machines (as Docker containers) and invest in creating SQL scripts to set the schema and initial master data. These SQL scripts should be kept in version control and maintained just like any other code.
4. Lack of visibility into version control hosting platforms
I once worked with a customer who had over 1,000 warehouses in their version control system. They use the Gitlab version control platform. They have five products, each made up of multiple microservices.
The first question I asked them was to help us understand which services and their respective codebase were part of product A. Their lead architect had to spend A day figuring out all the warehouses for product A. A day later, she still wasn’t sure she had all the services figured out.
The best way to solve this problem is to group your microservices in some way from the beginning so that you can keep track of the product ecosystem. Gitlab provides a way to create a group and then create a project repository within it. Github doesn’t have groups, so you can implement it using themes or naming conventions.
I personally prefer Mono Repos because I find them really convenient. Most developers I’ve met consider it an anti-pattern. I agree with Dan Lua, who mentioned the following benefits of mono Repo:
- Simplified organization
- Simplified dependencies
- tool
- Cross-project change
5. Services are not clearly defined
Most teams have no idea what should be considered a service. There is a lot of confusion and confusion about what constitutes a single microservice.
As an example, suppose your application has a plugin-like architecture in which you integrate multiple third-party services. Should each integration be a microservice? I see many teams creating a microservice for each integration. As the number of integrations increases, this can quickly get out of hand and become unmanageable. These services are often so small that running them as separate processes adds more overhead.
I think it’s better to have even a few big services than too many small ones. I’ll start by creating a service that models an entire department in the business organization. This is also consistent with DDD (Domain Driven Design). I divide a field into subfields and bounded contexts. A bounded context represents a department within a company, such as finance and marketing. You might think that this would lead to big services, and you’d be right.
With more knowledge and experience, you can move to fine-grained microservices that represent smaller problems. You can apply the Single Responsibility Principle to understand whether microservices are getting too big and doing too much.
You can then break it up into smaller, separate services. No service should communicate directly with another service’s database. They should communicate only through published contracts. You can learn more about subdomain decomposition at microservices. IO.
I also followed the advice in the Backendlore documentation.
This recommendation can help limit services to service communication, which is the primary cause of poor performance in microservice systems. If two pieces of information depend on each other, they should belong to the same server. In other words, the natural boundary of a service should be the natural boundary of its data.
6. Code reuse policies are unclear
I once worked with a customer who copied four Java files related to a specific issue across all of their Java-based microservices. Therefore, if a bug is found in the code, it needs to be fixed everywhere. We all know that when we’re pressed for time, we miss applying changes to one or more services. This will waste more time and increase frustration.
It’s not that development teams don’t know the right things. But organizations are structured to default to simple and error-prone ways of doing things.
Instead, use an artifact manager like Bintray or Nexus and publish dependencies there. Each microservice should then rely on this library. You need to build tools so that all microservices should be updated and redeployed when a new version of the library is released.
Using microservices doesn’t mean you shouldn’t use the best practices that have worked for us so far. You need to invest in tools to make it easier to upgrade microservices so that people don’t have to.
Without the right tools and automation, using microservices can lead to disaster.
7. Multi-language programming design
I found teams working with multiple programming languages, multiple databases, multiple caches, and in the name of the best tools. All of these things work at the beginning of the project, but as your product goes into production, these choices begin to show their true colors.
The reason is that we were building a JavaSpringBoot application, but we realized that Java takes up more memory and has poor performance, so we decided to switch to Node.js. On my last assignment, I explained to the team that their reasoning skills were weak.
(1) Note.js has better performance than Java
If your workload is I/O based, Node.js will generally perform better. But For any computationally-intensive workload, Java beats Node.js. By reactive Paradigm, you can use Java to deliver better performance for I/O workloads. The Spring Boot Reactor is comparable to Node.js in terms of I/O workloads.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/javascript.html
https://blogs.sap.com/2018/08/03/spring-boot-reactive-vs.-node.js-in-sap-cloud-platform-reflection-on-throughput-measure ment/
(2) Node.js consumes less memory than Java
Up to a point, this is true. Java Spring Boot applications are not as bad as most people think. I ran load tests on a Spring Boot Java microservice and still didn’t consume more than 1 GB of memory. You can use OpenJ9 JVN to limit classpath dependency and optimize Java memory utilization by tuning default JVM parameters. In addition, there are new alternatives to Spring Boot in Java, such as Micronaut and Quarkus, which consume as much memory as Node.js.
(3) Node.js is more efficient than Java
It depends on the developer who wrote the code. Java using static typing and static analysis tools can help identify problems early in the development life cycle.
In most cases, it all depends on the context. If your developers aren’t mature enough, you’re going to have a terrible product no matter what programming language you use.
I recommend that an organization publish a list of languages that teams can use. I think 2-3 is a good number. Also, make a list of reasons why one language is better than the other.
Here are some questions you should consider before choosing a language:
- How easy is it to find mature enterprise software developers?
- How easy is it to retrain developers in new technology? We found that Java developers can learn Golang relatively easily.
- How easy is it for developers outside the original team to contribute, transfer, and maintain code written by others?
- How mature is the ecosystem in terms of tools and libraries?
This is not limited to programming languages, but also applies to the database world. If you already have MongoDB in your system, why would you use ArangoDB in your ecosystem? Both are primarily document databases.
Always consider the maintenance and operational aspects of using multiple technologies.
8. People dependency
This is not a microservice-specific phenomenon, but it is becoming more common in microservice ecosystems. The reason is that most teams are focused on their specific services, so they don’t understand the full ecosystem. In my work with different clients, I have found that only one group of architects understands the big picture. The problem with these architects, however, is that they are not actively involved in day-to-day activities, so their influence on development is limited.
I think it’s best to make sure that all teams have a representative architecture team so that they can align their team with the roadmap and goals of the entire architecture team. To become a mature organization, you need to invest in establishing a lightweight governance.
9. Lack of documentation
Most of the organizations we’ve talked to over the past few years have struggled with documentation. Most developers and architects either don’t document or write documentation that is useless. Even if they wanted to, they didn’t know how to document their architecture.
We should at least record the following:
- Design document
- Context and container diagrams in the C4 model
- Track key architectural decisions in the form of architectural decision logs
- Beginner’s Guide for developers
10. Features beyond platform maturity
I mentioned this reason briefly among other points, but I think it deserves to be mentioned as a top reason. Microservers are more complex than traditional monolithic applications, because you are building a distributed system with many moving parts. Most developers are not yet aware of the different failure modes of the system. Most microservers are built with happy paths in mind. Therefore, if your management only wants to focus on features, you are doomed to fail. Because features built on weak platforms don’t provide value.
Organizations need platform thinking. Platform thinking means more than just using containers and Kubernetes. They are part of the solution, but not the whole solution by themselves. You also need to consider distributed tracing, observability, chaos testing, function calls and network calls, secure services for communication between services, debugging, and so on. This requires serious effort and investment in building the right platform and tools team.
If you’re a startup with limited resources, my advice is to rethink your microservices strategy. Know what your problem is.
11. Lack of automated testing
Most teams know how important automated testing is to the overall quality of the product, but they still don’t do it.
The microservices architecture provides more options for where and how to test. If you don’t automate thoroughly, you’re going to fail miserably. I won’t dwell on this, because many people have written about it online.
The figure below is what I found in an article on microservices testing from Martin Fowler’s website that discusses the testing pyramid for microservices-based systems.
Microservices test pyramid
Special statement: this article material from the network, only as a share of learning, such as infringement, please contact delete!
Recommended reading
Golden three silver four seasons, Ali has worked for more than 10 years Java giant “experience”, dedicated to you in confusion
- give a like
- collection
- share
-
- The article reported
Frank little yard farmer
Direct messages
Focus on