Development of Microservices - Problems and Solutions

Written by anil789 | Published 2017/01/30
Tech Story Tags: microservices | cloud-computing | data-driven-design | api-gateway | web-platform

TLDRvia the TL;DR App

Building applications using microservices is covered well in several publications. In this post my attempt is to cover few problems which do not get as much attention and discuss solution of each. Paying early attention to these areas would help you improve productivity, quality and build a flexible application. I will also show that it can save 25% or more in cost. These lessons are learnt by working on an open-source platform and working with few customers.

If you are building microservice based application, you would divide application in several microservices and use variety of technology stacks. An application may have 5–500 microservices depending on complexity. You may be using a mix of Java, .Net, Python, NodeJS, GO etc. based technology stacks. One important consideration that is often missed, how is a developer going to use these services in development environment for testing. Developers are the most productive when they are using IDE of choice on personal machines. It helps them write and debug code faster. It is impractical to run several services on personal machines for debugging and unit testing. Another issue that is highly debated what “should and should not” constitute shared code. People lean towards un-sharing. The third important consideration is creating reusable services which can acquire personality of slightly varying services through meta-data or scripting. The fourth issue is not critical for server side developers but for UI developers. It deals with how to slice a large UI into smaller pieces, develop each independently and automatically put them together at runtime.

In the following sections we will get into details of these four areas and discuss how to solve them.

Connect to Any Microservice at Will from Developer’s Machine

In operational environment, you would probably have all microservices running on private or public cloud somewhere. But developers can’t reach to them due to network security reasons. Even if developers can create a secure tunnel to these services, it is lot of work and distraction from daily development. Break developers concentration and they have to “eat frog” before they start rolling.

How can a developer connect to services in cloud from his or her machine? You probably guessed it — “we need a gateway to services”. If you have one, sweet! If not then probably you would build it someday to expose your services to outside world. Why not do it now so your own developers become consumer of APIs. It would also help in abstraction, understanding of services and standardization. Having a gateway is not enough but it is the first required step.

In this case, the goal of a gateway is to provide close to deployment environment to developers. There are few more things you need to consider to create a true deployment environment on developer’s personal machine. In order to develop and debug, developers run few services (generally 2–3) locally and like to connect to rest in cloud. Thus, it is an environment that is a mix of services on developers’ machines and in cloud. It is achieved by changing IP addresses of endpoints of services, pulling few code repositories or containers. If you visualize it, you are creating an environment which is a slight variation of centrally available environment to everyone. What is the best way to achieve it?

This can be achieved if you design a light gateway which is lightweight and configurable, ideally through UI. Through UI developers can change IP addresses of services. If it simple enough developers can deployit on local machines to mediate between local and cloud services. This resulting structure is shown in the following diagram.

Connecting Local and Remote Microservices using Gateway

You would find several use-cases of reusing above design with gateway creatively. Let us take one more example. If you are developing an application which uses single sign-on (SSO), you can use operational environment to acquire access-token and use it in hybrid environment where you are running services on local machine and remote cloud. I intend to cover this as a separate blog later.

Code Sharing Among Microservices

One of the benefits of microservice architecture is that changes in one service does not cause a ripple effect. Therefore, the idea is to make them completely independent of code changes in one to other. But it does not mean that you should not share code. It probably means that you need a proper version management for the shared code. The shared code can evolve. But a service using it can decide to migrate to the newer version or not. In fact, this is how we use the open source code. You will be using several open source libraries in your microservices. There is no reason you can’t treat your own shared code in the same way.

You can never go wrong by sharing. Let us say you have 10 services which could have used “X” common code. The worst case when you don’t share, all have 10X extra code. You begin by sharing the version 1 of “X”. “X” moved to version 2. Only 3 services would have moved to “X 2.0”. You would still have lots of code sharing. You can also have multiple layers of shared libraries. Some services may bypass higher level layers if they don’t need them. The following diagram shows layering of code with and without code sharing. If you properly plan code sharing, it is a big winner.

Depiction of Code Sharing and Not Sharing Options

You can look for sharing code in these areas:

  1. Utility functions — Few examples utilities are string processing function, common functions using regex, common domain specific utilities, generic data structures, data structures specific to domain but reusable as templates, data validation code, file read-write code etc.
  2. Database API — Consider writing CRUD, query, pagination as generic libraries which can take schema as input. You can standardize on few base attributes across all entities such as id, name, friendly name, version, state flags etc. Using schema file you can define meta properties of attributes such as uniqueness, type etc. Common code can implement logic based on metadata.
  3. Common Algorithms — Stateless functions or methods that receive input, processes and returns output. These are algorithms that can be shared across services. Few example are sorting, decision trees, generic rules.
  4. Logging — Common logging wrapper if you want to keep the option to plug-in different open source libraries.
  5. Security Related API — Data validation for security, checking privileges etc are example of common security functions.
  6. Rule of thumb — ask around, “Is there a code I can reuse or contribute to?” It is the open source model and you will not go wrong.

Configurable and Programmable Services

There are many opportunities in computer software where something is a variation of something else. In case of microservices too, you can find a common denominator and pull it out as a generic code which can be called “template-service”. If you follow a data driven design then it can morph into a special case using meta-data and some pluggable scripts. For example, let us say you have a service called Order Service. It will probably save data in database. There is a Shipment Service that is also saving data in the same data base. You can pull out common denominator code as Persistence Service which will take schemas and pluggable code as input. Another option is to deploy as three services: i) Order Service, ii) Customer Service and iii) Persistence Service. A data driven design of Persistence Service will be easier if you are using NoSQL DB than RDBMS. But you can do it in each case. You may find other benefits of such a design. For example, in this particular case, it separates the application logic from database logic; DB experts can optimize it independent of business service. This is one illustration and may not be quite possible in your case. But the overall idea is that if you can pull out infrastructure like code from multiple services into template-services then give it serious consideration. It will not be obvious. Once you get used to metadata and scripting programming model, you will start seeing several such opportunities. I intend to cover this in much greater details in a separate post.

Template Microservice — Programmable using Metadata and Plug-ins

WEB Tier and Decomposing UI into Smaller Pieces

It is prudent to develop multi-device WEB UI that is pure HTML, JavaScript and CSS and does not use any server side libraries for rendering. It is very likely that you are already doing it. On server side, it simply requires to serve a barebone HTML page with required JS, CSS. UI connects to services using a secure tier or gateway. In case of a large UI, you can divide it into functional components and let teams develop them independently. Let us call each functional component as “micro-application”. You can develop each micro-application as a HTML page and yet avoid reload when the integrated application is deployed.

Let us look at the HTML page served for a micro-application by the server. It would have the following content.

<html>

<header>

load open source css

load common css (common across all micro-applications)

load css specific to micro-application

</header>

<body>

Mostly empty, rendered using templates

</body>

load open source JS

load common JS (common across all micro-applications)

load JS specific to micro-application

</html>

You will notice that parts which change are micro-application specific CSS, JS and corresponding HTML templates. In integrated environment, previous micro-application code can be unloaded and new micr0-application code can be loaded without page refresh. A micro-application can be represented by URL which may have its name as path in the URL. Using a proper WEB server design, you can use path to plug in specific CSS, JS in barebone HTML page on the server side. For clarity and modularity, you can organize micro-application specific JS, CSS, HTML templates in separate directories. This decomposes your application on the UI side quite similar to the way that microservices do on the server side.

Decomposition of a Large UI as Micro-Applications

Business Benefits

The above mentioned considerations lead to significant business benefits. Let us say a developer spends 4 hours a week struggling to connect to services. In a 6 month project with 10 developers it will mean 4 person months i.e. roughly 7%. Add to it frustrated developers working at lower productivity and quality, it can top 10%. If you have a solid plan for code sharing among microservices, it will lead to additional saving. Writing data driven, programmable services and be able to adopt them to some degree of variation will provide flexibility and save time-money in a short as well as long run. UI code can get spaghetti very easily as its volume grows. You can avoid it by breaking UI into smaller modules (or micro-applications in traditional WEB app sense). Let us say each of these contributes to 5% saving. All this adds up to 25%. You can use it towards building high value features, better UX or team rewards. The flexible and modular code base also opens up the door for innovations.

Future Posts

I intend to cover following topics more in details in separate posts.

1. Lightweight Gateway Design

2. Data Derive, Programmable Template-Service

3. UI Decomposition as Micro Applications

4. Developing Secure Microservices


Published by HackerNoon on 2017/01/30