Purpose-Driven Microservice Design

John Vester - Jun 30 '22 - - Dev Community

Article Image

Buzzwords aren’t something I expected when I started my career. In those days, most of the technology news arrived in paper-based weekly publications like InformationWeek and Network World. I remember thinking to myself, “Man, they are using these same words over and over again each week.”

That translated to people using buzzwords … all the time. Back then, my two favorite buzzwords were references to the internet as the “world wide web” and the “information superhighway.” I always wondered if there would be a super-duper-highway at some point.

However, recently, I noticed that buzzwords are used as placeholders where they don’t quite make sense. Terms like microservices, event-driven architecture, AI, and ML are used in contexts which leads me to conclude that many people don’t quite understand these terms. I didn’t expect this either…

Imagine this simple conversation related to a misunderstood question:

Person #1: What time does your flight leave?
Person #2: Later this year.

While Person #2 provides an answer that is not incorrect, the reply does not really yield any value to Person #1’s inquiry.

Along those same lines, the quest to migrate to microservices has endured similar challenges. More often than not, I have worked with clients and corporations whose “microservice” design resulted in a single monoservice. Basically, a monolithic application was replaced with a really big RESTful API.

For this publication, I thought it would be fun to walk through an example of creating a purpose-driven microservice design … the right way.

The Purpose-driven Microservice Design

A purpose-driven microservice is a service that can stand on its own, and it can include a dedicated persistence store when required. By being purpose-driven, the microservice will provide a focused set of information and be the system of record for the data governed within the associated APIs.

By adopting the purpose-driven microservice approach, users can add additional nodes and scale down existing nodes in order to meet the needs of the API for that point in time.

As an example, a purpose-driven microservice focused on an aspect of income taxes may see the highest usage during the first part of the year and require fewer instances running in the second half.

Let’s focus on the creation of a purpose-driven microservice design using a very simple example.

Creating a Docker-based Microservice

The Chinese Gender Predictor is a grid system used to forecast the gender of a baby at birth. This is done by providing the month of conception and the mother’s current age at the time of conception.

Rumor has it that the Qing Dynasty imperial family relied on this same grid for the gender selection of sons, who were favored for the work and money they could provide for their families as well as for carrying on the family lineage.

Below is an illustration of the Chinese Gender Predictor grid:

Chinese Gender Predictor

As an example, an 18-year-old mother who conceived a child in January would produce a female baby.

For this publication, we’ll create a purpose-driven microservice that returns a gender prediction based on the same criteria. The resulting payload for the example above would appear as shown below:

{
    "month": 1,
    "age": 18,
    "gender": "female",
    "errorMessage": null
}
Enter fullscreen mode Exit fullscreen mode

The microservice will utilize Java and Spring Boot and will employ a multi-stage Dockerfile to compile the service and build a Docker image that can host the birth-predictor APIs.

The code for the service can be found on GitLab at the following address:

https://gitlab.com/johnjvester/birth-predictor

Creating a Reproducible Pattern Using Render Blueprints

I’ve written about the Render platform in the following publications:

For my personal instances running on Render, I have used the Go programming language, static sites, and a Postgres instance. This time, I wrote the service in Java/Spring Boot. While native support for Java does not exist yet, the Render platform does include support for anything running in a Docker container.

Since the birth-predictor service includes a multi-stage Dockerfile, I wanted to see how easy it is to deploy a Docker-based service on the Render platform. However, I noticed the Blueprint specification and wanted to see how that works, too.

What is a Blueprint?

A Blueprint is Render’s implementation of Infrastructure as Code (IaC). IaC is also something I group into a larger concept called “* as Code”. Organizations that need to manage a deployment of several services or that have services requiring a lot of options can define their Render infrastructure (services, databases, and environment groups) as code in a render.yaml file.

Using Render Blueprint

Building on the Blueprint example provided here, I was able to quickly create a Blueprint for my Spring Boot services running via Docker containers:

services:
  - type: web
    name: restful-api-spring-boot
    env: docker
    region: ohio # optional (defaults to oregon)
    plan: free # optional (defaults to starter)
    branch: master # optional (uses repo default)
    numInstances: 1 # optional (defaults to 1)
    healthCheckPath: /actuator/health
    envVars:
      - key: SERVER_PORT
        value: 443
Enter fullscreen mode Exit fullscreen mode

From there, I customized the YAML data for the birth-predictor service to update the name property and add a repo property, as noted below:

services:
  - type: web
    name: birth-predictor
    env: docker
    repo: https://gitlab.com/johnjvester/birth-predictor
    region: ohio # optional (defaults to oregon)
    plan: free # optional (defaults to starter)
    branch: master # optional (uses repo default)
    numInstances: 1 # optional (defaults to 1)
    healthCheckPath: /actuator/health
    envVars:
      - key: SERVER_PORT
        value: 443
Enter fullscreen mode Exit fullscreen mode

This information was stored in the root of the birth-predictor repository, in a file called render.yaml. After committing and merging this change, the service was ready for deployment on the Render platform.

From the Render Dashboard, I selected the New | Blueprint option:

New Blueprint

Next, I selected the birth-predictor repository, which I connected to my GitLab account using instructions found here.

Select Repository

Since I was using a Blueprint, all I had to do was provide a service group name for my new service:

Name Service Group

After pressing the Apply button, the deployment process started:

Deployment in Progress

A few minutes later, the service was deployed without any issues:

Service Deployed

Birth Predictor in Action

With the birth-predictor service running, I can issue the following cURL command to obtain a new prediction:

curl --location --request POST 'https://birth-predictor.onrender.com/predict' \
--header 'Content-Type: application/json' \
--data-raw '{
    "conceptionMonth" : 11,
    "conceptionAge" : 43
}'
Enter fullscreen mode Exit fullscreen mode

The resulting response payload looks like this:

{
    "month": 11,
    "age": 43,
    "gender": "male",
    "errorMessage": null
}
Enter fullscreen mode Exit fullscreen mode

This information just happens to match the month of conception and the age of my wife at the time our son (Finny) was conceived. In August 2017, he arrived!

Finny Arrives

Just like they did during the Qing Dynasty, we were able to rely on the Chinese Gender Predictor to successfully forecast the sex of our child.

Conclusion

Since 2021, I have been trying to live by the following mission statement, which I feel can apply to any IT professional:

“Focus your time on delivering features/functionality which extends the value of your intellectual property. Leverage frameworks, products, and services for everything else.”

  • J. Vester

The Blueprints specification by Render adheres to my mission statement by allowing feature and service teams to focus on delivering against established goals and targets, without worrying about anything DevOps related.

Once the service, component, or application is ready, teams merely need to include the render.yaml file in the root of their repository, then create a new service on the Render platform using the Blueprint option. Going forward, any updates to the connected repository will auto-deploy minutes after committing the code to the noted branch.

The Render platform lives by a Zero DevOps mentality, which is evident in the origin of the Blueprint concept. Feature and service developers want to—and should—be focused on delivering updates and functionality that provide the most value to their stakeholders. Render truly understands this reality.

I am certain that buzzwords will always be part of the technology space. However, understanding and adopting the true intention behind those buzzwords is something I hope technologists will pursue.

If you are interested in the source code for this publication, you can find it on GitLab at the following address:

https://gitlab.com/johnjvester/birth-predictor

Have a really great day!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .