Section 1: Cloud-Native Applications
In this section, you will learn what it means for an application to be cloud-native. You will also learn about the basics of MicroProfile and how it provides the tools you need to build your own cloud-native Java applications. In this section, you will also learn about the real-world sample application that will be used throughout the rest of the book.
This section comprises the following chapters:
- Chapter 1, Cloud-Native Applications
- Chapter 2, How Does MicroProfile Fit Into Cloud-Native Application Development?
- Chapter 3, Introducing the IBM Stock Trader Cloud-Native Application
Chapter 1: Cloud-Native Applications
When talking about cloud-native applications, it is important to have a shared understanding of what cloud-native means. There is often an assumption that cloud-native and microservices are the same thing, but actually, microservices are just one architectural pattern that can be used when building cloud-native applications. That leads us to the questions: what is a cloud-native application, and what are the best practices for building them? This will be the focus of this chapter.
In particular, we will cover these main topics:
- What is a cloud-native application?
- Introducing distributed computing
- Exploring cloud-native application architectures
- Cloud-native development best practices
This chapter will provide some grounding for understanding the rest of the book as well as helping you to be successful when building cloud-native applications.
What is a cloud-native application?
Back in 2010, Paul Freemantle wrote an early blog post about cloud-native (http://pzf.fremantle.org/2010/05/cloud-native.html) and used the analogy of trying to drive a horse-drawn cart on a 6-lane highway. No matter how much better a highway is as a road, there is a limit to how much a cart can transport and how quickly. You need vehicles that are designed for driving on a highway. The same is true of applications.
An application designed to run in a traditional data center is not going to run well on the cloud compared to one that was designed specifically to take advantage of the cloud. In other words, a cloud-native application is one that has been specifically designed to take advantage of the capabilities provided by the cloud. The Stock Trader application from Chapter 8, Building and Testing Cloud-Native Applications, is an example of such an application. A real-world example of microservices is Netflix.
Perhaps at its core, the promise of the cloud is being able to get compute resources on-demand, in minutes or seconds rather than days or weeks, and being charged based on incremental usage rather than upfront for potential usage – although, for many, the attraction is just no longer having to manage and maintain multiple data centers. The commoditization of compute resources that the cloud provides leads to a very different way of thinking about, planning for, and designing applications, and these differences significantly affect the application. One of the key changes in application design is the degree to which applications are distributed.
Introducing distributed computing
Most cloud-native architectures involve splitting an application into several discrete services that communicate over a network link rather than an in-process method invocation. This makes cloud-native applications implicitly distributed applications, and while distributed computing is nothing new, it does increase the need to understand the benefits and pitfalls of distributed computing. When building distributed applications, it is important to consider and understand the eight fallacies of distributed computing. These are as follows:
- The network is reliable.
- Latency is zero.
- Bandwidth is infinite.
- The network is secure.
- Topology doesn't change.
- There is one administrator.
- Transport cost is zero.
- The network is homogeneous.
In essence, what these fallacies mean is that a network call is slower, less secure, less reliable, and harder to fix than invoking a Java method call or a C procedure. When creating cloud-native applications, care needs to be taken to ensure these fallacies are correctly accounted for, otherwise, the application will be slow, unreliable, insecure, and impossible to debug.
An application consisting of multiple services interacting across the network can produce many benefits, such as the ability to individually scale and update services, but care must be taken to design services to minimize the number of network interactions required to deliver the ultimate business solution.
As a result, several cloud-native architectures can be used to build cloud-native applications that present different tradeoffs between the benefits and challenges of distributed computing.
Exploring cloud-native application architectures
Since 2019, there has been increasing discussion in the industry about the pros and cons of microservices as a cloud-native application architecture. This has been driven by many microservice-related failures and as a result, people are now discussing whether some applications would be better off using different architectures. There has even been the start of a renaissance around the idea of building monoliths, after several years of those kinds of applications being seen as an anti-pattern.
While it is attractive to think of cloud-native as just being a technology choice, it is important to understand how the development processes, organization structure, and culture affect the evolution of cloud-native applications, the system architecture, and any ultimate success. Conway's Law states the following:
Any organization that designs a system will produce a design whose structure is a copy of the organization's communication structure.
A simple way of thinking of this is if your development organization is successful at building monoliths, it is unlikely to be successful at building microservices without some kind of reorganization. That doesn't mean every team wanting to do cloud-native should go out and reorganize; it means that you should understand your strengths and weaknesses when deciding what architecture to adopt. You should also be open to reorganizing if necessary.
This section discusses a number of the more popular cloud-native application architectures out there and the pros and cons of using them. Let's start with microservices.
Microservices
Although Netflix didn't invent the idea of microservices, their use of the architecture did popularize it. A single microservice is designed to do one thing. It doesn't, despite the name, mean that service is small or lightweight – a single microservice could be millions of lines of code, but the code in the microservice has a high level of cohesion. A microservice would never handle ATM withdrawals and also sell movie tickets. Identifying the best way to design a cloud-native application into a series of well-designed microservices is not a simple task; different people might take different views of whether a deposit into and withdrawal from a bank account would warrant a single microservice or two.
Microservices usually integrate with each other via REST interfaces or messaging systems, although gRPC and GraphQL are growing in popularity. A web-facing microservice is likely to use a REST or GraphQL interface, but an internal one is more likely to use a messaging system such as Apache Kafka. Messaging systems are generally very resilient to network issues, since once the messaging system has accepted the message, it will store the message until it can be successfully processed.
The key promise of the microservice-based architecture is that each microservice can be independently deployed, updated, and scaled, allowing teams that own disparate microservices to work in parallel, making updates without the need to coordinate. This is perhaps the biggest challenge with microservice architectures. It is relatively common for well-meaning developers who set out to build microservices to end up building a distributed monolith instead. This often occurs because of poorly defined and poorly documented APIs between services and insufficient acceptance testing, resulting in a lack of trust in updating a single microservice without impacting the others. This is called a distributed monolith because you end up with all the disadvantages of a monolith and microservices and miss out on the benefits.
In an ideal world, a development organization building microservices will align the microservices with an individual development team. This may be difficult if there are more microservices than development teams. As the number of microservices a team manages increases, more time will be spent managing the services rather than evolving them.
Monoliths
Monoliths are strongly associated with pre-cloud application architectures and are considered an anti-pattern for cloud-native applications. For that reason, it might seem strange that this appears in a discussion of cloud-native architecture. However, there are some reasons for including them.
The first is really just the reality that monoliths are the simplest kind of application to build. While the individual services cannot be independently scaled, as long as the monolith has been designed to scale, this may not be an issue.
The second is that there are a lot of monoliths out there and many enterprises are moving them to the cloud. MicroProfile provides additional APIs to retrofit many cloud-nativ...