14/11/2024 6 Minutes read Tech 

Navigating application separation : Insights from our recent project

In the realm of software development, traditional application projects hold a significant place, whether they involve building a new application from scratch or evolving an existing one. These projects are foundational to the technological infrastructure of many organizations, providing the essential tools and systems that drive business operations.

In today’s rapidly evolving technological landscape, the concept of application separation has become increasingly pivotal. As organizations strive for greater efficiency, security, and scalability, the traditional monolithic application architecture is giving way to more modular and flexible approaches. Application separation, which involves dividing an application into distinct, manageable components, offers numerous benefits including improved performance, enhanced security, and easier maintenance. This article shares our recent experience with an application separation project, we hope it will be helpful for your future projects in similar context.

Context of the project

Because of the reorganization of different business services, we were mandated by one of our clients to separate an existing application (Java, Play framework, AWS ecosystem) into two distinct applications within two different infrastructures (including all the corresponding software factory like code repository, documentation, CI/CD pipeline, etc).

Strategies

The project was supposed to be signed with a fixed price contract, so we needed to estimate the cost as close to reality as possible in the very beginning of the project, so that we can avoid potential complicated budget problems in the future for both our client and us.

We defined two phases in this project: a discovery phase and an implementation phase.

The discovery phase was very important for us for the success of this project, in this phase we needed to:

  • Have a global overview (code complexity and volume, database structure, infrastructure, software factory, etc.) to give us an idea of the complexity of this application separation.
  • Try to take a look at several (2 or 3) services to understand existing implementation (security control, how to store data, how to call remote services, which framework/library is used, etc.).
  • Define global budget of this project according to what we have inspected.
  • Create a dedicated project team with appropriate profiles.

During the implementation phase the main steps we needed to do were:

  • Create a new environment (new independent infrastructure, new independent software factory).
  • Copy the relavant code base to create the new application.
  • Modify the services to be usable in this separated system (our goal is to deploy two distinct applications in two different infrastructures).
  • Migration of services.

Golden rule: modify as little code as possible. There were many complicated business rules in existing code, we could not investigate and totally understand all the code in a short time, so we tried to modify only the necessary code (essentially the endpoint layer) to make sure there would be no impact on business logic after application separation.

We believed the communication and information sharing was very important in this kind of project, so we suggested creating a governance to represent respectively each team: as the existing application would be separated into two distinct applications which would each be under the responsibility of a different team, we needed to have a technical governance in order to work closely with the client everyday (dedicated daily meeting) to be able to take a decision for any potentially impacting change, or to share some information among us.

Key point

Services communication

In the existing application, there were two means of communication between services: synchronous by HTTP or asynchronous by messaging. When the service was using HTTP to communicate with other services, it was relatively simple, we only needed to modify it to use the public API instead of the private one (using client id/client secret for security control)

But if the service was using messaging to communicate with other services, it was more complicated, we needed to keep this asynchronous communication mode (fire and forget) to maintain the decoupling of different business entities and gain a better performance for some business requirements, so we could not simply change them to HTTP API. Considering the message sent between the two distinct applications could be more sophisticated in routing and processing rules, and we needed a complete decoupled broker to communicate between two applications, we finally decided to use Amazon EventBridge as the event bus between the two future distinct applications. We chose it for these reasons:

  • The existing application is in the Amazon ecosystem so it will be simple to integrate another Amazon service.
  • Amazon EventBridge can easily connect applications without writing custom code.
  • The data source in the EventBridge can be a custom application, a SaaS application or an AWS service. Its target can be a Lambda, another custom application, an HTTP endpoint, or an Event Bus in another account. so it’s really flexible to integrate with other components if needed in the future.

Dispatcher

In order to reuse as much of the services as possible and avoid modifying the code for every service, we created an event dispatcher in the new application to be responsible for listening to the events from Amazon EventBridge and transforming them into the data structures already accepted by the different services, this approach would avoid introducing bugs and ease the future maintenance.

Migration

Our goal was to achieve a migration without stopping services, in order to keep writing data in right place without any lost or repeated data, so we designed a deployment strategy as follows (saying that a service A1 in old application and service A1’ is duplicated in new application):

  • We developed a new library capable of configuring any endpoint of service in “read only” mode (with defaults based on the HTTP behavior, only GET endpoints will be executed).
  • We deployed the service A1’ for the new application in the new environment and we activated this “read only” mode for the service A1’.
  • We activated the replication of databases from the old application to the new application (the service A1 running on old application was still responsible for writing data in its database and all this data was then replicated in the database of the new application).
  • We validated the service A1’ in the new application had been correctly deployed (could read correctly the data from its database).
  • We switched the traffic (by configuring an Nginx to route the migrated paths to the new application instead of the old one) so that all related requests were forwarded to the new application and we waited for a little moment in order for service A1 to finish handling all existing requests in its queue (at the same time the endpoints of service A1' in the new application are connected to a queue so all new incoming write requests would be accumulated in the queue before being treated by service A1’).
  • We disabled the “read only” mode of the service A1’ so that it could write data in its own database and started handling all new incoming requests
  • We removed service A1 from old application as it would be no longer used.

Pain points

The application to be separated was created a few years ago and it was not upgraded regularly, so there were some obsolete technologies to be maintained when we worked on this new application, and this made our job more difficult.

Some existing services were not well done to be fully reusable in the new application, there were some missing context when the old application was separated into two parts, so we could not simply duplicate the service and expected it to work correctly, we had to check all impacted services one by one to know how they worked and try to find a new solution with less modification in order for the service to continue to work as a new application.

Conclusion

This was not a typical project we used to do, especially doing it on a fixed price contract with a fixed delivery date. Thanks to our discovery phase we were able to identify all essential steps to achieve this application separation, and to be more prepared in order to work more effectively in both technical and organizational aspects. Setting a cross-team governance was a key to success too, it helped a lot in communication and quick decision making, which made our project proceed smoothly without wasting time.


Navigating application separation : Insights from our recent project was originally published in ekino-france on Medium, where people are continuing the conversation by highlighting and responding to this story.