Miscellaneous

Are Microservices Right for Me – Enabling Microservices or Monoliths – Shipa

Another conversation that was recently had during our weekly field enablement office hours here at Shipa was “what exactly is a microservice?”. Certainly, a term that has been used to describe a paradigm and architectural practice. One can argue that the breaking down or decomposing of applications has been going on for decades and is not a monumental shift in computing. There are several definitions of microservices from a purist definition to a definition resembling a movement. First, let’s look at two pieces of code.

What Exactly is a Microservice and Monolith

Let’s compare two blocks of code for displaying pi. 

Monolith:

/*
Monolith Pi Eater
@author Ravi Lachhman
*/

public class Main
{
    String pi = String.valueOf(giveMePi());
}

private double giveMePi()
{
    //ToDo: Update Pi to 3.142
    //ToDo: Can we use math? E.g 22/7?
    double pi = 3.14;
    return pi;
}

If you notice in the monolith, that the call for pi is a method call e.g not remote to the application. Everything that the application needs are in the application. Communication is typically done via procedural calls. If we take the suggestions e.g the ToDo’s to change pi, well we have to re-build, re-test, and re-deploy.

Microservice:

/*
Microservice Pi Eater
@author Ravi Lachhman
*/

public class findPi()
{
    //Let this thing figure out Pi
    var client = HttpClient.newHttpClient();

    //What Ever Pi Service Sends Back is Pi
    var request = HttpRequest.newBuilder(
       URI.create("https://piesaregreat.shipa.cloud/?api_key=314"))
       .header("accept", "application/json")
       .build();
    
    //Give me the Pi
    var response = client.send(request, new JsonBodyHandler<>(APOD.class));

    //Get Pi ready to display 
    String pi = String.valueOf(response.body().get().pi);
}

In this example, whatever we use to display is independent of pi. By calling a “pi service” remotely, we are able to make changes to how we display pi. With microservices, remote calls in various formats such as REST, gRPC, etc are how services communicate. Now let’s get into some academics around microservices. 

Are You a Microservice?

After several sprints of building your hard work, you are ready to show off your RESTFul pi endpoint to the world. This has to be a microservice right? Calling your endpoint by any other name would be mean and not being on the straight and narrow with a modern architecture trend would be shameful.

Stringent definitions around microservices could include that your service is message-based aka MOM and communications should be facilitated by messaging patterns. You start to scratch your head about this messaging requirement and no one told you to have a microservice that you had to use messaging.

If you took a look at a steller piece by Martin Fowler explaining microservice design patterns,  a few of those design patterns start to stick out. The biggest piece for me is data governance. For a microservice, the data needs to be independent of other services. Taking that one click down, should not have overlapping data definitions if you make an update to the data structure in your service would not cause structural updates to dependent or calling services. 

Let’s say you were building in your sprints a pi calculating application where you take in decimal points and return pi to a certain decimal point. Also to make things interesting need to log the requests for analytics. Your application most likely would not warrant the transactional support that a JAVA Message Service (JMS)  provider/implementation provides.

With our pi service, we can have a pretty simple schema or document structure. The user logging data can certainly stand alone. When digging into microservices, a going mantra is that to start to build services that are much more granular in scope or accomplish only a singular goal. The quintessential eCommerce microservices example would say that you have a service for your shopping cart, inventory, user management, and so on. Our pi service is starting to smell a lot more like a microservice.

Save Me, Microservice!

The big allure of microservices is the flexibility to be freed from dependency hell. On the flip side of microservice architecture is monolithic architecture. Just as the name suggests, a monolith has one deployable unit with all the functionality needed. In the JAVA days, imagine a large WAR to deploy. Going back to an eCommerce example, all functionality such as shopping cart and inventory are deployed with this single eCommerce.WAR.

Having to make a change in one functionality would require a deployment of the entire application. This can be risky and overkill since making a seemingly small change requires the entire application to be re-deployed. Since the exposure for risk is so high, in monolithic architecture teams tend to deploy at a slower frequency.

Thus the need for a better way to deploy. One team that finishes functionality quicker than other teams doesn’t need to be in lockstep with the deployment. For newer applications, most folks will think of ways to design for more independent deployments embracing smaller services. Though microservices do have challenges, especially around deployment complexity. 

Why Is Everything Not a Microservice 

The brass tacts with microservices is that as dependency complexity is reduced, deployment complexity is increased. With smaller and more granular services, you will have more services. Thus, the number of deployments will increase.

Martin Fowler is also famous for coining The Strangler Pattern where newer parts of the application stack will eventually kill out the older parts. Eventually with the number of services exploding, would be very hard to keep track. An anti-pattern will start to show called Big Ball of Mud. With the Big Ball of Mud, endpoint hell starts to occur with new services just spinning up with no clear and concise design or management for the services.

Several challenges start to pop up. With services being so granular, one service could call several services making several hops which would just be one inside a monolith. Tracing across services is pretty hard, especially if no one wants to take on state per-se. There have been advances with distributed tracing such as Jaeger.

Application infrastructure responsibility starts to shift with microservices. The Full Lifecycle Developer/team model starts to make an appearance as teams start to run soup to nuts on what is required for their endpoints to work. Though back to the database; what if your team or endpoint becomes a run-away success? Could you imagine a DBA-managed Oracle Cluster per service endpoint? Those would be some really expensive microservices.  Expertise in databases might not be your or your team’s forte so application infrastructure expertise starts to shape architecture; you know what you know. 

Deployment complexity certainly increases with microservices which might be counterintuitive to monolithic architecture. With the monolith, the human complexity is there having multiple teams agree on when to deploy. That complexity shifts to systemic complexity with microservices as the number of deployments increases; more services, more deployments. From a platform engineering perspective, if you have to provide a lot of support to developers to just deploy their ideas, then the burden as microservices take over will be significant. Though with Shipa, this becomes a lot easier. 

Microservice or Monolith – Better Together with Shipa

No matter the design paradigm if you chose to leverage a monolith [or distributed monolith these days] or microservices, Shipa has your back. 

The burden to deploy does take a lot of skills that are not functional requirements of the application or service itself such as connectivity. Adding Kubernetes complexities to that just increases the toil that developers face when making architectural decisions. With Shipa, deploying a monolith or microservice is simple.

Cheers,

-Ravi