Book Image

Hands-On Microservices with C# 8 and .NET Core 3 - Third Edition

By : Gaurav Aroraa, Ed Price
Book Image

Hands-On Microservices with C# 8 and .NET Core 3 - Third Edition

By: Gaurav Aroraa, Ed Price

Overview of this book

<p>The microservice architectural style promotes the development of complex applications as a suite of small services based on specific business capabilities. With this book, you'll take a hands-on approach to build microservices and deploy them using ASP .NET Core and Microsoft Azure. </p><p>You'll start by understanding the concept of microservices and their fundamental characteristics. This microservices book will then introduce a real-world app built as a monolith, currently struggling under increased demand and complexity, and guide you in its transition to microservices using the latest features of C# 8 and .NET Core 3. You'll identify service boundaries, split the application into multiple microservices, and define service contracts. You'll also explore how to configure, deploy, and monitor microservices using Docker and Kubernetes, and implement autoscaling in a microservices architecture for enhanced productivity. Once you've got to grips with reactive microservices, you'll discover how keeping your code base simple enables you to focus on what's important rather than on messy asynchronous calls. Finally, you'll delve into various design patterns and best practices for creating enterprise-ready microservice applications. </p><p>By the end of this book, you'll be able to deconstruct a monolith successfully to create well-defined microservices.</p>
Table of Contents (16 chapters)

Identifying decomposition candidates within monolithic

We have now clearly identified the various problems that the current FlixOne application architecture and its resultant code are posing for the development team. We also understand which business challenges the development team is not able to take up and why.

It is not that the team is not capable enough—it is just the code. Let's move ahead and check out the best strategy to zero in on the various parts of the FlixOne application that we need to move to the microservice-styled architecture. We need to know that we have a candidate with a monolith architecture, which poses problems in one of the following areas:

  • Focused deployment: Although this comes at the final stage of the whole process, it demands more respect, and rightly so. It is important to understand here that this factor shapes and defines the whole development strategy from the initial stages of identification and design. Here's an example of this: the business is asking you to resolve two problems of equal importance. One of the issues might require you to perform testing for many more associated modules, and the resolution for the other might allow you to get away with limited testing. Having to make such a choice would be wrong, and a business shouldn't have the option to do so.
  • Code complexity: Having smaller teams is the key here. You should be able to assign small development teams for a change that is associated with a single functionality. Small teams are comprised of one or two members. Any more than this and a project manager will be needed. This means that something is more interdependent across modules than it should be.
  • Technology adoption: You should be able to upgrade components to a newer version or a different technology without breaking anything. If you have to think about the components that depend on technology, you have more than one candidate. Even if you have to worry about the modules that this component depends on, you'll still have more than one candidate. I remember one of my clients who had a dedicated team to test out whether the technology being released was a suitable candidate for their needs. I learned later that they would actually port one of the modules and measure the performance impact, effort requirement, and turnaround time of the whole system. I don't agree with this, though.
  • High resources: In my opinion, everything in a system, from memory, CPU time, and I/O requirements, should be considered a module. If any one of the modules takes more time, and/or occurs more frequently, it should be singled out. In any operation that involves higher-than-normal memory, the processing time blocks the delay and the I/O keeps the system waiting; this would be good in our case.
  • Human dependency: If moving team members across modules seems like too much work, you have more candidates. Developers are smart, but if they struggle with large systems, it is not their fault. Break the system down into smaller units, and the developers will be both more comfortable and more productive.

This section helped us understand the problems that a monolithic architecture faces. Next, we will move on to some advantages of this architecture.

Important microservices advantages

We have performed the first step of identifying our candidates for moving to microservices. It will be worthwhile to go through the corresponding advantages that microservices provide. Let's understand them in the following sections.

Technology independence

With each of the microservices being independent of each other, we now have the power to use different technologies for each microservice. The payment gateway could be using the latest .NET Framework, whereas the product search could be shifted to any other programming language.

The entire application could be based on a SQL Server for data storage, whereas the inventory could be based on NoSQL. The flexibility is limitless.

Interdependency removal

Since we try to achieve isolated functionality within each microservice, it is easy to add new features, fix bugs, or upgrade technology within each one. This will have no impact on other microservices. Now you have vertical code isolation that enables you to perform all of this and still be as fast with the deployments.

This doesn't end here. The FlixOne team now has the ability to release a new option for the payment gateway, alongside the existing one. Both payment gateways could coexist until both the team and the business owners are satisfied with the reports. This is where the immense power of this architecture comes into play.

Alignment with business goals

It is not necessarily the business owner's concern to understand that certain features are harder or more time-consuming to address. Their responsibility is to keep driving and growing the business. The development team should become a support network for achieving the business goals, not a roadblock.

It is extremely important to understand that quickly responding to business needs and adapting to marketing trends are not by-products of microservices, but goals.

The capability to achieve these goals with smaller teams only makes microservices more suitable for business owners.

Cost benefits

Each microservice becomes an investment for the business, since it can easily be consumed by other microservices, without having to redo the same code again and again. Every time a microservice is reused, time is saved by avoiding the testing and deployment of that part.

The user experience is enhanced, since the downtime is either eliminated or reduced to a minimum.

Easy scalability

With vertical isolation in place and each microservice rendering a specific service to the whole system, it is easy to scale. Not only is the identification easier for the scaling candidates, but the cost is less. This is because we only scale a part of the whole microservice ecosystem.

This exercise can be cost-intensive for the business. Consequently, the prioritization of which microservice is to be scaled first can now be a choice for the business team; this decision no longer has to be a choice for the development team.

Security

Security is similar to what is provided by the traditional layered architecture; microservices can be secured as easily. Different configurations can be used to secure different microservices. You can have a part of the microservice ecosystem behind firewalls and another part for user encryption. Web-facing microservices can be secured differently from the rest of the microservices. You can suit your needs as per choice, technology, or budget.

Data management

It is common to have a single database in the majority of monolithic applications. And almost always, there is a database architect or a designated owner responsible for its integrity and maintenance. The path to any application enhancement that requires a change in the database has to go via this route. For me, it has never been an easy task. This further slows down the process of application enhancement, scalability, and technology adoption.

Because each microservice has its own independent database, the decision-making related to changes required in the database can be easily delegated to the respective team. We don't have to worry about the impact on the rest of the system, as there will not be any.

At the same time, this separation of the database brings forth the possibility for the team to become self-organized. They can now start experimenting.

For example, the team can now consider using Azure Table storage or Azure Cache for Redis to store the massive product catalog instead of the database, as is being done currently. Not only can the team now experiment, but their experience can also easily be replicated across the whole system, as required by other teams in the form of a schedule convenient to them.

In fact, nothing is stopping the FlixOne team now from being innovative and using a multitude of technologies available at the same time, then comparing performance in the real world and making a final decision. Once each microservice has its own database, this is how FlixOne will look:

In the preceding image, each service has its own database and has scalability; the inventory service has caching (Redis server).

Integrating monolithic applications with microservices

Whenever a choice is made to move away from monolithic architecture in favor of microservice-styled architecture, the time and cost axis of the initiative will pose some resistance. A business evaluation might rule against moving some parts of the monolithic application that do not make a business case for the transition.

It would have been a different scenario if we were developing the application from the beginning. However, this is also the power of microservices, in my opinion. The correct evaluation of the entire monolithic architecture can safely identify the monolithic parts to be ported later.

We must safeguard against the risk of integration to ensure that these isolated parts do not cause a problem to other microservices in the future.

While we discussed various parts of the monolithic application, our goal was to create them collaboratively, so that they can communicate with each other on the patterns followed by the application based on the microservice architectural style. To achieve this, there would be a need for various patterns and the technology stack in which the original monolithic application was developed. For example, if we have used the event-driven pattern, our monolithic application should adhere to this pattern in such a way that it consumes and publishes the events. To implement or obey this pattern, we should manage the code of our monolithic application, which basically includes the development efforts to make the changes in the existing code.

Similarly, if there is a need to use the API Gateway pattern, then we should make sure that our gateway should suffice, so that it communicates with the monolith application. To achieve this could be a bit complex or tricky, where the existing monolithic application does not have such functionality to expose web services (RESTful). This would also put pressure on the development team to make changes in the existing code to make the application viable to fit the standard of a gateway. There would be a great chance to make code changes to add or update the RESTful services because these services could be easily consumed by the gateway. To overcome this overburden, we can create a separate microservice so that we can avoid major changes in the source code.

We discussed the integration of monolithic applications in this section, with the help of various approaches, such as the domain-driven pattern, the API Gateway pattern, and so on. The next section discusses Azure Service Fabric.