In this article, I have put forth my views on why a fintech company’s legacy application architecture should be migrated to a modern architecture style, how the existing legacy assets can be reused in this paradigm shift and how this migration helps to solve some of the daunting problems in areas such as code quality and reusability.
A typical Fintech company is always under pressure from investors and other stakeholders to go to market early. It hardly gives enough attention to the Application architecture at the beginning. They end up building applications with monolithic architectures that are easy to build but create tight dependencies when it comes to feature enhancements. Frequent changes in the regulations, tax structures, license and capital requirements in this domain also add to this turmoil. There has always been a considerable amount of time and effort spent in reworking on the existing application code to meet the new requirements. This often introduces new bugs and breaks the existing functionality. To meet this challenge, companies end up creating a tangled, spaghetti mess of code thereby deteriorating the code quality and creating maintenance nightmares. This effort is magnified if the architecture is monolithic and rigid to accommodate changes.
Monolithic application architecture is single tiered in which both the user interface and the data access code are combined into a single platform.
Due to its architecture simplicity, the initial time spent to build and deploy the application into production isn’t much. Even though this architecture offers better performance (response time) over modern web application architecture (as there aren’t too many layers between the user interface and the database), it lacks several other key architecture quality attributes such as the ones below:
Agility & Maintenance– As the functionality grows, so does the number of program units and the number of lines of code. All in one. This also brings the huge challenge of implementing a new business requirement as the entire application needs to be retested every time there is a change.
Availability – Monolithic application poses risk as, if even one part of the application breaks, it could impact the entire application and could potentially bring it down.
Reusability – Reusability is possible only within the same tier and within same program units in the name of methods and functions. Even though, in principle, it is possible to create independent modules within a monolithic application, it is seldom implemented.
Scalability - Most Fintech companies start with a niche offering that impacts a small function in the financial business process. Even though the user adaptability is slow at the beginning, it gradually increases once users start benefitting from this niche offering. There is a high expectation that the application is highly scalable to support high concurrent users without compromising the throughput that end users experienced in the beginning.
Testability – One single big piece always poses challenges while testing minor changes in the functionality due to its complex interdependency, which exists between different program units.
Microservices is an architecture style that is built around business functionality rather than technology like UI, middleware, and database. A microservice is a self-contained unit that represents one module’s end to end functionality. One application comprises of one or many modules. Hence, a set of microservices put together represents an application. This architecture recommends a separate database for each service (where the business logic lies).
Some key benefits of this architecture are:
It brings a paradigm shift in the way teams are organized. Each module has a team of middleware and DB developers and QA testers that are responsible for end to end development, testing and delivery of a service. This improves cohesiveness, ownership, and responsibility among development teams as they work together for one module in different technologies.
Microservices architecture supports greater agility in building and managing banking and Fintech applications that are - by nature - complex in design, constantly evolving and scaling, integrating with multiple internal/external systems and demanding high security at various levels.
Maintaining individual microservices is much easier compared to maintaining one massive application with everything put together. Each microservice is developed and maintained separately in the source repository. This decomposed architecture allows the implementation of functional changes to the application in a much faster and very efficient way. This is because developing a complete new microservice doesn’t take very long. Unit testing and code reviews become very easy. This approach eventually helps in improving the quality of the application and reduces the number of defects.
The Application is available to the end users most of the time as, in case of issues with the individual microservices, that service alone can be uninstalled and newer versions can be installed without causing the entire application to be down during the maintenance window.
There are two aspects to reusability:
Service reusability – This is possible as each microservice is designed to represent one functional part of the application. This enables a greater flexibility in reusing one functional unit from another. For e.g: The pricing of securities can be developed as a web service (module A, let’s call it PriceService). It will have operations to support inserting or updating the latest prices of securities. The price could be received as feed from the market such as Bloomberg on a daily basis. Transaction processing could be developed as another web service (module B, let’s call it TradeProcessingService). To process transactions of funds that have invested in securities, it needs the latest price data. So, TradeProcessingService service will use PriceService during the transaction processing.
Code reusability - Service architecture, by nature, eliminates code redundancy. Existing, already written code in legacy technology can be logically split and each logical unit can be potentially converted into reusable services. This way, we would not only improve the code quality but also reuse our existing core asset and save the huge effort taken in rewriting them afresh in modern language. Since it not mandatory that all the services have to be based on one language, individual services in microservice architecture can be written in a language that suits them. One of the key benefits of this architecture is interoperability as microservices are technology agnostic.
Unlike legacy architecture, microservices architecture by nature supports horizontal scaling to meet increased number of concurrent users and transaction volumes. Modern microservice platforms - such as the one that is based on the Spring boot, Zuul and Eureka combination - supports scaling the services horizontally in an easy and efficient manner.
Testability is improved to a greater extent. Industry standard says 40% of the cost of developing a well-engineered application is taken up by testing. If the software architect can reduce this cost, the payoff is large. For an application to be properly testable, it must be possible to control each service’s internal state and inputs and then observe its outputs. Microservice based architecture supports this approach. Each microservice can be tested for its full functionality independent of others. This greatly reduces time spent waiting for the fully functional monolithic application to be available for testing. In the above example, both the services TradeProcessingService and PriceService can be independently developed and tested.
Cost of Building Microservices Architecture
Based on all the points above, can we assume that Microservice architecture is the way forward? Well, not exactly as one size doesn’t fit all. There are several factors to be considered before deciding on this path. Some of them are listed below:
The cost spent on the analysis to extract the logic from the existing spaghetti mess of code and develop them as reusable services with very clear and rigid boundaries is enormous. You need to have a team of developers that has the knowledge on the current code and also developers with different skill sets that can help in converting it into microservice.
In one way maintenance is simpler in microservices based architecture but it creates additional challenges like monitoring individual services for its uptime, managing different versions of each microservice (both during runtime and in source repository).
Troubleshooting a monolithic application is fairly easy as compared to Microservice based architecture as the number of technical layers is very limited in monolithic. Now, in the new architecture with clusters of services spread across middleware servers, we need to build a centralized logging and auditing platform to identify the problematic services and then troubleshoot them. This brings changes to the way today’s support teams work on a monolithic application.
We should come up with delivery policies to deliver different versions of microservices at periodic intervals.
We need to handle failures in case one or more services are not available or one or more failed in a group of microservices that are working together to complete a transaction.
Microservices need more hardware and computing resources in comparison with monolithic applications.
The Way Forward
Indeed, migration to microservices involves risk, effort, and cost but, if we plan the strategy right, there is no denying factor that the overall quality of the application will increase in the long run. No matter how much we invest in improving the quality of a monolithic application, without a paradigm shift in the architecture, the ROI and yield will be very minimal. To de-risk this migration, companies can plan to move to microservice architecture for the new developments and gradually shift the legacy modules into microservice-based architecture.