avatarGabriel Shanahan

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

7719

Abstract

icroservices architecture back to a monolithic architecture</a> due to this very complexity.</p><p id="deff">Well, here are some personal thoughts :</p><ol><li>Managing numerous independent services can be daunting, requiring sophisticated solutions for issues like service discovery, load balancing, and inter-service communication. These elements need careful coordination and advanced tools to ensure seamless operation, which can increase the difficulty of managing the overall system.</li><li>Maintaining data consistency across multiple services can be difficult, and distributed transactions, while theoretically possible — are complex and often discouraged in a microservices setup. This can lead to data integrity issues if not handled correctly.</li><li>Deploying and monitoring a large number of services necessitates the use of advanced tools and practices. Continuous integration and continuous deployment (CI/CD) pipelines, service meshes, and centralized logging are critical to manage these tasks effectively. However, setting up and maintaining these tools can be resource-intensive</li><li>Communication between microservices over a network introduces latency, which can negatively impact performance. Also back to my point of #2, the data transfer and storage costs are also hidden in solutions of this nature.</li></ol><div id="dce3" class="link-block"> <a href="https://amzn.to/4cZRKcz"> <div> <div> <h2>Building Microservices: Designing Fine-Grained Systems</h2> <div><h3>Building Microservices: Designing Fine-Grained Systems [Newman, Sam] on Amazon.com. FREE shipping on qualifying…</h3></div> <div><p>amzn.to</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*KsAS-Lf5SZ6ZEvMH)"></div> </div> </div> </a> </div><h1 id="2c26">The landscape of Microservices is evolving</h1><p id="24aa">As we evaluate the state of microservices in 2024, several trends and technologies have emerged. Here’s my personal summary of some key trends that influence the relevance of microservices:</p><ol><li><b>Kubernetes and Containerization</b>: The rise of <a href="https://cloudmelonvision.com/what-is-kubernetes-really-about/">Kubernetes</a> and <a href="https://cloudmelonvision.com/getting-started-with-devops-containers-and-kubernetes/">containerization</a> has made deploying and managing microservices more straightforward. Kubernetes provides robust orchestration capabilities, simplifying the deployment, scaling, and operation of containerized applications.</li><li><b>Serverless Architectures</b>: <a href="https://cloudmelonvision.com/things-you-didnt-know-about-serverless/">Serverless computing</a>, where developers focus on writing code without worrying about the underlying infrastructure, has gained popularity. Services like AWS Lambda, Azure Functions, and Google Cloud Functions allow developers to build and deploy functions as microservices. This approach reduces operational overhead and can complement microservices by handling specific tasks.</li><li><b>Service Mesh</b>: Service mesh technologies, such as Istio and Linkerd, address many of the networking challenges associated with microservices. They provide features like load balancing, traffic management, and security, simplifying the management of inter-service communication.</li><li><b>Observability and Monitoring</b>: Enhanced <a href="https://cloudmelonvision.com/ranking-top-5-logic-app-monitoring-tools/">observability tools</a> have become essential in managing microservices. Solutions like Prometheus, Grafana, and Jaeger help monitor, trace, and visualize the behavior of microservices, providing insights into performance and aiding in troubleshooting.</li><li><b>API Gateways</b>: API gateways play a crucial role in managing traffic between clients and microservices. They offer features like request routing, rate limiting, and security, ensuring smooth communication and protecting the backend services.</li></ol><blockquote id="6556"><p>organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations<i>. — By M. Conway — <a href="http://www.melconway.com/Home/Conways_Law.html">Conway’s law in 1968</a></i></p></blockquote><div id="9210" class="link-block"> <a href="https://aws.plainenglish.io/navigating-the-cloud-native-landscape-a-glimpse-into-kubecon-europe-2023-17ce4dfc21d7"> <div> <div> <h2>Navigating the Cloud-Native Landscape : A Glimpse into KubeCon Europe 2023</h2> <div><h3>KubeCon has long been my one of favorite events in the community, and this year’s KubeCon + CloudNativeCon Europe 2023…</h3></div> <div><p>aws.plainenglish.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*gZcMCbwOsok0cCnt.png)"></div> </div> </div> </a> </div><h1 id="8f26">Decoding real-life microservices architecture</h1><p id="91dd">As <a href="https://docs.microsoft.com/en-us/azure/architecture/microservices/index">Microsoft defines</a>, a microservices architecture is a system that contains a collection of small, autonomous services. So, let’s walk through and decode a real-life microservice architecture.</p><h1 id="e512">Key principles in action</h1><p id="74da">Here are some principles that I summarized to follow when deploying microservices on Azure:</p><ul><li>One app server per microservice.</li><li>Each microservice has its own data persistent store (backend).</li><li>Each microservice has an independent life cycle.</li><li>No dependency on other modules.</li><li>Small and numerous microservices facilitate fast and frequent deployment.</li><li>Strongly loosely coupled, acting as small elastic units within the distributed system.</li><li>Isolation from the resources of other applications.</li></ul><p id="6384">The direct outcome of this philosophy looks like this :</p><figure id="f183"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*BoQnlWWREiUQOdgP.png"><figcaption></figcaption></figure><h1 id="8873">My personal analysis</h1><p id="1ec8">You see, modern cloud-native applications designed for microservice architecture should be managed in a version control tool like Git, following the principle of “a codebase = 1 repository.” This shows dependencies and systems should be isolated and declared explicitly and independently to facilitate maintenance and administration tasks.</p><p id="e68d">Additionally, code should be separated from configuration files, meaning that code should contain only variables and not application or environment settings. The application should be strictly stateless, with each module sharing nothing with others. Generally, the front end does not store any data. instead, data is always in the backend, possibly exchanged through middleware such as RESTful APIs.</p><p id="e75d">Each application must be autonomous and <b><i>self-contained</i></b>, adhering to the principle of “<b><i>one process, one microservice.</i></b>” This approach allows microservices to be well-structured, making it easy to add or delete processes. During peak times, processes can be scaled by increasing instances, and during downtime, services can be rapidly stopped and started, ensuring a quick return to normal operations.</p><p id="9426">Checking the integrity of event and flow logs is crucial when implementing a monit

Options

oring strategy. Since each microservice operates independently but functions as part of a whole system, log implementation should be event-based. Microsoft Azure provides log analytics services and other metrics for monitoring each microservice effectively. Sounds a bit complex right? Let’s take a look at a prime example of microservices!</p><div id="fa01" class="link-block"> <a href="https://aws.plainenglish.io/what-i-wish-i-knew-when-i-got-started-with-kubernetes-177cf717f5ef"> <div> <div> <h2>What I Wish I Knew When I Got Started with Kubernetes</h2> <div><h3>Get acquainted with the key things you need to know to get started with Kubernetes, through hands-on practice.</h3></div> <div><p>aws.plainenglish.io</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*Pt4bR0zjJIZyi4d962_cIg.png)"></div> </div> </div> </a> </div><h1 id="29b0">A prime example of microservices: e-Shop</h1><p id="8e1e">One of the most interesting parts of the workshop analyzes a real-life example built with microservices on Azure called <a href="https://github.com/dotnet/eShop">eShop by Microsoft</a>. This is a microservice architecture-based application that implements an e-commerce website using a services-based architecture with <a href="https://learn.microsoft.com/en-us/dotnet/aspire/get-started/aspire-overview">.NET Aspire</a>.</p><div id="eafe" class="link-block"> <a href="https://github.com/dotnet/eShop"> <div> <div> <h2>GitHub - dotnet/eShop: A reference .NET application implementing an eCommerce site</h2> <div><h3>A reference .NET application implementing an eCommerce site - dotnet/eShop</h3></div> <div><p>github.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*2OMwW_dNGu2ziEd3)"></div> </div> </div> </a> </div><p id="4db6">This project contains different types of microservices and can be managed by API gateway:</p><figure id="29e1"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*Ie6-7U_7AM-USzqA.png"><figcaption></figcaption></figure><p id="0451">Although the orchestration layer is more complex, so the overall systems that you could read from above principles lead the final architecture looks like this :</p><figure id="e601"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/0*CyWeHbTWiDkhAa4N.png"><figcaption></figcaption></figure><p id="a848">If you’re a .Net developer or anyone who is experienced in Microsoft technical solutions, you would definitely benefit from one excellent book that is recommended by Microsoft : <a href="https://aka.ms/microservicesebook"><b><i>.NET Microservices Architecture for Containerized .NET Applications.</i></b></a><b><i> </i></b>This book explains in detail how to develop the microservices architectural style and set up the golden stamps of microservices.</p><div id="d6b3" class="link-block"> <a href="https://dotnet.microsoft.com/en-us/learn/dotnet/architecture-guides"> <div> <div> <h2>.NET Application Architecture Guides</h2> <div><h3>Free e-books and practical advice for developing for web, desktop, mobile, and microservices with Docker.</h3></div> <div><p>dotnet.microsoft.com</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/0*-HOBCuKlHpRdmsoU)"></div> </div> </div> </a> </div><h2 id="b1de">Are Microservices here to stay?</h2><p id="82f8">As we look towards the future, several factors will determine the continued relevance of microservices beyond 2024. <a href="https://cloudmelonvision.com/navigating-the-cloud-native-landscape/">Cloud-native technologies</a> such as <a href="https://cloudmelonvision.com/if-i-were-about-to-get-started-on-kubernetes-in-2024/">Kubernetes</a> and <a href="https://cloudmelonvision.com/decoding-serverless-kubernetes/">serverless</a> are still going strong, and their emerging with technologies like AI and machine learning, leading to smarter and more adaptive systems. And in this emerging section, <a href="https://cloudmelonvision.com/ranking-top-5-logic-app-monitoring-tools/">AI-driven monitoring</a> and self-healing capabilities will further enhance the robustness of microservices architectures.</p><p id="7a86">Please also don’t forget the rise of edge computing, where data processing occurs closer to the source of data generation, will complement microservices by enabling low-latency, real-time applications. Above all, as regulatory requirements evolve, microservices architectures will need to incorporate robust security and compliance measures, with solutions that provide seamless integration of security protocols.</p><p id="8ba7"><b><i>It’s almost a no-brainer that Microservices will continue to stay!</i></b></p><p id="7e27">Improving the developer experience is needed. Tools and frameworks that simplify development, testing, and deployment will encourage adoption and innovation.</p><div id="9056" class="link-block"> <a href="https://pub.towardsai.net/gpus-kubernetes-decoding-next-gen-ai-enabling-workloads-00d7a1f104ae"> <div> <div> <h2>GPUs + Kubernetes =? Decoding Next-gen AI-enabling Workloads</h2> <div><h3>Cloud-native technologies such as Kubernetes and serverless have been revolutionizing modern application design and…</h3></div> <div><p>pub.towardsai.net</p></div> </div> <div> <div style="background-image: url(https://miro.readmedium.com/v2/resize:fit:320/1*YxDPxAlzZyZx8dZ29GgwLw.png)"></div> </div> </div> </a> </div><h1 id="e026">Looking forward</h1><p id="cee0">Personally, I greatly enjoyed the latest deployment methods and creative styles in designing application architecture brought by cloud computing. Cloud computing is boosting our business today. If you like reading stories like this, if you enjoy similar topics, you can follow me <a href="https://www.youtube.com/@CloudMelonVis?sub_confirmation=1">on my YouTube channel</a> or follow me <a href="https://melonyqin.com">@melonyqin here on Medium</a> and subscribe to <a href="https://newsletter.cloudmelonvision.com">my newsletter</a>. See you in the next one! Thanks for your continued support. Let’s stay tuned!</p><h1 id="d2e2">In Plain English 🚀</h1><p id="07aa"><i>Thank you for being a part of the <a href="https://plainenglish.io"><b>In Plain English</b></a> community! Before you go:</i></p><ul><li>Be sure to <b>clap</b> and <b>follow</b> the writer ️👏<b>️️</b></li><li>Follow us: <a href="https://twitter.com/inPlainEngHQ"><b>X</b></a> | <a href="https://www.linkedin.com/company/inplainenglish/"><b>LinkedIn</b></a> | <a href="https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw"><b>YouTube</b></a> | <a href="https://discord.gg/in-plain-english-709094664682340443"><b>Discord</b></a> | <a href="https://newsletter.plainenglish.io/"><b>Newsletter</b></a></li><li>Visit our other platforms: <a href="https://cofeed.app/"><b>CoFeed</b></a> | <a href="https://differ.blog/"><b>Differ</b></a></li><li>More content at <a href="https://plainenglish.io"><b>PlainEnglish.io</b></a></li></ul></article></body>

Modeling States and Structure: Considerations

Things to take into consideration when using types to make the states and shapes of entities explicit in your code.

— — — — — — — — — — — — — — —

THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.

— — — — — — — — — — — — — — —

Tags: #FUNDAMENTAL CONCEPT

This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.

It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.

In the previous article, we talked about the benefit of modeling different states and structures of core entities as explicit types. However, as is often the case, this technique cannot be applied blindly, and there are some things you need to consider before you decide to use it.

Combinatorics

One potential downside of this approach is that it can result in an exponential increase of classes, which can impact maintainability.

Let’s demonstrate this on an example. Consider a Customer, where we track the name and income source of a customer. The customer is unpersisted by default (i.e. has no id). At the start of the business workflow, we only require the name, but require the customer be “completed” at some (future) point. To complete a customer, information about the income source must be entered as well.

If the source of income is EMPLOYMENT, the job the customer works must be specified as a separate enum. If the job is specified as OTHER, the job name must be specified in an additional field as a string.

Similarly, if the source of income doesn’t fit in the existing enum values, we again use OTHER + specify using a string.

Here’s the data model that corresponds to what I just wrote:

Fourteen interfaces to model a very simple business scenario — that’s a lot. It took me a while and multiple tries to map out the hierarchy in my head and write them all out, and I’m not embarrassed to say that I got lost a few times. To be completely honest, I’m not 100% sure I got them all right. And God forbid we added another “branch” in the data model — e.g. discriminated between customers imported from an external system vs those created by a user. Suddenly, we’d be looking at 28 interfaces.

Obviously, this doesn’t scale well, and we can’t apply this without careful consideration. So, when is it worth doing?

When Is It Worth Doing?

Let’s go back and recap what the actual benefit of this approach are: it removes the need for runtime checks of business preconditions when implementing business scenarios.

So for this approach to modeling to be worth the effort, we need the hierarchy to actually appear in some business logic which contains preconditions that can be removed by modeling the hierarchy in this way. We need to take into consideration not only if these places exist, but how many there are, and most importantly, how many more do we expect to appear as the codebase evolves.

That last one should be the most important deciding factor. It also hints at where this style is most effective, and should most often be used — modeling core domain entities, around which the core business workflows revolve. By definition, these are the entities that appear most often in business code, and will keep appearing in new business code in the future.

Examples and Counter-examples

So, if we’re building a service that allows PDFs to be signed electronically, a PdfDocument entity is a prime candidate to model in this way, but only those parts which actually appear in core business code — e.g. differentiating between a SignedPdfDocument and UnsignedPdfDocument probably makes sense, but differentiating between, I dunno, a SinglePagePdfDocument and MultiPagePdfDocument probably doesn’t (unless, of course, you have a scenario where this distinction matters).

In contrast, if we’re building a fintech service which allows customers to invest their capital, it’s reasonable to assume that we’re probably going to need to upload a scanned PDF of the signed contract at some point in the workflow. This would also be modeled as a PdfDocument entity, but there really is no sense in going crazy with the hierarchy, assuming that all we do is accept it, persist it to some storage and maybe send it to some third-party APIs. Maybe, maybe, it might be worth discriminating betweenPersisted and Unpersisted variants.

To return to the scenario with the Customer above, you can imagine an online trading platform subject to standard KYC guidelines, where you are only able to withdraw your funds after you complete your profile. That is a very core workflow, and you need to strictly separate business logic applicable to “completed” customers from business logic applicable to “incomplete” customers. Everything is much safer if you strictly separate completed customers from the incomplete ones at the type level, and enlist the compilers help in ensuring that the two never get mixed up.

As a counter-example where the same approach wouldn’t make sense, imagine if the Customer was just a DTO that gets built and sent to a third party API. There is no business logic involving it, it just get’s built, validated (i.e. all the fields that are required are there) and sent off to some system. We gain practically nothing by discriminating an EmployedCustomer from the rest.

Sure, created objects are correct by design, and therefore there is no need for validation. It might seem that this allows us to save a few keystrokes, but don’t forget that:

  • in the real world, there are many requirements that cannot be reflected by a static type hierarchy, so we’ll probably need to do some validation anyway
  • these objects need to be built first!

And once you started building them, you would find out that you’re writing exactly the same code as you would have written in the validator:

/**
 * Without hierarchy
 */
val customer = Customer(
    ...
)

// In validator
if(customer.incomeSource == "EMPLOYMENT" && customer.employment == null) {
    // Return error
}

// -----------------

/**
 * With hierarchy
 */
val customer = if(domainObject.incomeSource == "EMPLOYMENT") {
    if(domainObject.employment != null) {
        CompletedEmployedCustomer(...)
    } else {
        // Return error
    }
}

It’s the same code, just in a different part of the application.

To recap, always take into consideration how much this will really help you. Are you working with a core entity that can appear with different structures/in different states, and many business scenarios only make sense for certain structures or certain states? Then by all means, do this! And don’t be daunted even if this approach results in a large number of classes, because honestly — how many classes does your project already have? The one I’m currently working on has hundreds, and I don’t care — it’s my IDE’s job to index them, and I only open up those that I’m interested in. In Kotlin, classes are (visually) cheap.

Go back to Modeling States and Structure, jump to the Table of Contents, or continue to Reified Type Parameters.

Join me in Etnetera
Kotlin
Programming
Object Oriented
Functional Programming
Android Development
Recommended from ReadMedium