HR Workflow — Developing the structure of the first microservice
By: Nmbrs
Tags: Microservices, Software Architecture, Authentication, Logging, Azure

By Ada Moisescu

In the first article in our microservices series, we explained why we made the decision to migrate to microservices and how we started on our journey. In this article, the second in our series, we will focus on a real-world case study where we practised the approach to see if it made sense and worked for our business.

When breaking a monolith, it can be easy to look at it from a technical perspective only and decide to simply refactor existing functionalities. However, we realised this wouldn’t bring any business value and would risk destabilizing current working features. With that in mind, we chose a more realistic approach. We had a new feature that needed to be built and decided to start creating it in a new way, outside the monolith “monster” — as we call it — with microservices.

HR Workflows was a business need. It was a new functionality that we needed to have in our Nmbrs system, so we used it to start building our microservices infrastructure. For the feature to be built, it needed foundations, all of which needed to be built as well. Once that’s done, the actual business need — the functionality — can easily be laid down on top of a solid foundation.

With HR Workflows selected as our guinea pig, we were able to identify the specific features that we needed as a business: Authentication, Authorisation, Centralised logging and Data Security.

Authentication

Authentication service is one of the most important blocks a microservice architecture needs, so it was clear this was a top priority. In our strategy, we decided to not migrate all users at once. This service, enabled by Azure, meant that as users logged in, they would be migrated one-by-one, and ensured that users who were no longer using the system were kept outside of the platform. Given the high degree of risk attached to any authentication system, we had the old mechanism working in parallel in case anything went wrong — a strategy that we now use whenever we extract modules from the monolith.

Authorisation

When setting up the foundation of a microservices architecture, Authorisation is another vital component. Building it was not an easy task, and what we found most challenging was moving away from a UI based approach towards a more action-based permission model as rules have to be applied to each application, and code can become bulky. There is an extra level of overhead and complexity associated with having your architecture spread across multiple microservices, but it’s outstood in large scale applications by the convenience of having teams responsible for clear blocks and modules enabling fast development. When building an Authorisation system for a distributed architecture, another important thing you need to consider is performance, but also making it generic so it’s easily extendable. We considered this problem to be a great candidate to apply a Design Sprint — adapted for a technical problem — and it brought us towards a great solution.

“The main challenges faced during the process were building the foundation, the big blocks that you need to have. It takes time, it’s not easy, and it doesn’t bring any immediate business value; so you always need to balance it out in the way you organize priorities and resources — extracting core foundational logic from the monolith to the outside implied huge risk which we needed to minimize by a lot of fallback mechanisms.”

Centralized logging

In a world where IT infrastructure becomes more complex with each additional layer, it’s also important that we track the flow of communication between applications to understand what happens between them. We built a Logging system with a correlation Id mechanism to be able to investigate and trace back the user requests throughout multiple services. We quickly recognised that this code needed to be exposed as packages. For this, we created the Nmbrs fabric, a cross-cutting framework that enables us to easily create functionality in the new microservices architecture by reusing the building blocks in each service as packages. This also makes it as easy as possible for developers to follow best practices and avoid going live with something that can subsequently create a lot of problems. Our new Email sending service is another example of this cross-cutting framework.

Data Security

At Nmbrs, we work for people, so we are also keen to ensure we are following best practices when it comes to data security, especially being a multi-talent application. Our security model is based upon core entities like Company, Employee, User. To ensure we correctly validate data access level, we needed a dedicated service to expose that data — Organizational Service — and a mechanism to easily check the access. This was done using .NET policies and converted into a NuGet package called Data Access Control. It provides a hierarchical model of data access: if you have access only to Employee related data, you will not be able to fetch Company related data. But if you have access to Company-related data, you will be able to see Employee data under the specific companies that you can access.

With all of our business needs identified, we managed to create the foundations of our microservices architecture. While a challenging feat, this enabled us to be able to extract HR features from the monolith, which was rapidly becoming a sloth monster.

“The migration process and the rollout of this logic were long and complex — microservices architectures are complex, take time to build and ramp-up. All of us needed to shift our mindset from a monolithic system to a distributed system.”

Final thoughts

With HR workflows, we identified a crucial business need that allowed us to build our first microservice that is using our reusable building blocks. We are thrilled with how this approach turned out. Not only has it stopped us becoming hobbled by older technologies, but it has enabled us to adapt quickly, experiment, and to give the squad more independence. Most importantly, our developers are now much happier and more motivated.

It is also proving beneficial to our users. It has enabled us to release faster, which means we also fix, improve and adapt faster.

In the next article in our microservices series, we will go more in-depth on the technical part of this implementation.