A software development and fintech consulting company that empowers technology innovation.
These days most real-time services like online banking, e-commerce, or social media are dependent on cloud-computing platforms. However, making those services reliable and scalable is rather challenging. Moreover, the very nature of such solutions imposes restrictions on latency and availability, all while having a direct impact on the end-user experience.
Common Bottlenecks in the Banking Software Development Process
Initially, each service is intended to scale up to a particular limit, like handling ten thousand concurrent sessions. Hitting this milestone, software engineers need to re-engineer the solution to make it meet new requirements. Then history repeats itself and so on. What makes the matter worse is that financial businesses face this problem when their client base is expanding, and they succeed.
Another bottleneck resulting from business growth is associated with the data explosion. Banks and other financial organizations are obliged to keep all the information about balances, accounts, and transactions consistent and secure to be compliant with rigid regulations. Otherwise, there’s a risk of losing a license, which in turn leads to significant loss of money and goodwill.
Trying to strike a balance between business requirements and technical capabilities, software engineers combine various tools, technologies, and approaches throughout the entire fintech app development process, including the division of large systems into smaller units, the use of message buses, actor model, gRPC, event sourcing, allocated storages with data projection, and others.
But what if I say that there’s a more handy way to address the issues mentioned above? — Even though banking is a heavily-regulated industry, it’s rather dynamic. Smaller sectors become interconnected, and Open APIs promoted by the Open Banking initiative only add more fuel to the fire. Meanwhile, the list of requirements and constraints is continuously growing, Microsoft Orleans, with its virtual actors, may be put to good use.
A Closer Look at MS Orleans and Why It’s the Next Big Thing for the Financial Software Development
Let’s start with defining the actor model and why it’s so much sought-after for banking app development and not only that.
In simple terms, an actor-based framework is a concurrent environment where actors (primitives) can interact with each other instantly, giving single points of access for domain objects and capitalizing on a distributed lock.
Though the actor model was first mentioned in 1973 and Erlang was introduced in 1986, the authors of the latter found out about actors long after. However, this programming language, in combination with dedicated libraries for distributed processing, is still considered the most-used actor-based solution since it runs granular entities that only communicate using messaging and share no state. The similarities come from challenges that both Erlang and the actor model are actually trying to solve.
So far, the most popular actor-based framework was Akka, announced in the mid-2000s, but this Microsoft framework is quickly getting up to speed. In fact, Orleans is a cross-platform solution that combines familiar concepts (async/await, objects, interfaces, and others) and transfers them to multi-server environments, thus empowering software engineers to create scalable and robust distributed apps and cloud services.
So why MS Orleans? — Let’s delve into the features that make it a good pick for banking and finance app development.
The primary difference of Orleans from Akka lies in the fact that Grains (meaning actors) in Orleans are virtual. Therefore, a fintech development team doesn’t have to orchestrate a Grain’s life-cycle manually, as the MS cross-platform app framework takes on this task. Besides that, obtaining a Grain reference by ID doesn’t suggest that this specific Grain is actually created anywhere. Sounds great, right? Here is the scheme from the official documentation:
Image source: Microsoft Orleans documentation
In other words, a life-cycle of an Orleans Grain is given below:
- Activation occurs on a fetching to any interface method of a Garin;
- While staying active in memory, stateful Orleans Grains can change their state;
- Deactivation takes place when a specific Grain isn’t triggered for some time or if a Silo (Orleans uses this term to define a server) containing this Grain is terminated;
- If a Grain has a state, it’s persisted.
Consequently, we can utilize Grains as if they are perpetually active, and MS Orleans takes on the rest.
Distributed messaging. Clear business layer. Grain placement
Distributed message-passing is one of the most significant features. Typically, it’s as follows:
- We gain a Grain by ID and hence obtain a reference to the proxy interface. At this time, the exact Grain entity may not even be created anywhere;
- We trigger a Grain reference via an interface method;
- From a developer’s point of view, it’s a typical async method, but in essence, there is an HTTP query with a serialized message, affiliated to a Grain interface method;
- The proxy employs a previously activated Grain if there is any. Otherwise, an Orleans Grain is carried out on a Silo that sustains it;
- The initiated Grain elaborates the deserialized message and yields the HTTP response with the serialized sequel;
- The message is deserialized by the Grain client, and we obtain the result as if a standard in-memory entity did this.
Considering the fact that you can address objects from anywhere within the allocation unit, it makes any object absolutely transparent within the system. At this point, the implementation of intermediate communication (like REST API) is not obligated, only if it’s listed in the business requirements. Consequently, it helps us to accelerate the financial services app development process and reduce costs. The outcomes may be even more tangible if we take into account the need to implement a service layer for controllers, which finally becomes more streamlined.
Natively, Grains are randomly stored on any Silo that permits the implementation. A software engineer can change this behavior with supplementary standards for each Grain separately, choosing between a load-based or local arrangement. Lastly, one can work out a custom strategy and pick a Silo based on a particular algorithm.
Reentrancy. Distributed locking
If we take a closer look at the Microsoft Orleans performance, then we should note that every method here isn’t reentrant out-of-the-box. Consequently, if some method is already handling a call, each succeeding call will wait until the prior one is terminated. Furthermore, MS Orleans allows manual configuration of the reentrancy using attributes; for example, query or read-only methods are re-enterable, while state-change patterns aren’t. This lies at the core of keeping information consistent, which is so important for the banking product development process and helps to prevent various problems associated with multi-threaded account balance modification concerns, transaction replication, and more.
Distributed ACID transactions
The realization of distributed transactions is often seen as a cumbersome and tricky development issue. And considering this, the MS Orleans actor framework has something to offer. When it’s well configured, your transactional entities don’t have to execute rollbacks in case of failure, since this process is fully automatic. Besides that, engineering teams don’t have to define transactions as ever. So how is it possible?
Start with appending special attributes to methods to employ transactions and define their behavior, including a kind of cascading:
- Create or merge. They either start a transaction individually or join the existent transaction if requested from a method that is already used in one;
- Create. Always instantiate a new transaction, even though it’s triggered within a diverse context;
- Merge. Join the existing transaction only in those cases, if it’s triggered from a method utilized in it, but don’t generate new transactions themselves;
- Suppress. A call isn’t transactional, but it can be executed from a transaction, though the context will be bypassed;
- Support. A call isn’t transactional, though it can be executed from a transaction and tap into the conforming context;
- Not supported. A call isn’t transactional, and it can’t be run from a transaction, so in this case, it hits an error.
In the next place, to sustain and modify the state of all transactional Grains, it’s essential to use specific transactional state entities, all while allowing us to omit this feature in production since it comprises some restrictions and uncovered use cases.
Grain services. Stateless workers
Despite the fact that Grains are mainly regarded as field objects, there’re still Grains that aren’t.
- Stateless Worker Grains are referred by default value ID, for example, null or empty for string, 0 for long, and others. As the name implies, they don’t hold state and are meant for cross-grain procedures, including but not limited to various management tasks and financial data aggregation (transactions among them). It’s important to mention that teams can handle load balancing for Stateless Worker Grains locally, while the number of created activations is only limited by the CPU cores number on the machine.
- GrainService Grains presuppose somewhat tricky configuration and mainly serve as a regular service that can be inserted into a DI container with no need for a Grain client or reference. It begins and stops with the Silo, meaning that it owns one instance and operates as long as the Silo does. The idea behind it is to execute any type of Grains orchestration, and a regular Orleans Reminder service may be a good example here.
Reminder and Timer
Both services handle repeatable procedures, but the goals of each vary.
- A timer is recorded per each Grain activation. It’s rendered only while a specific Grain is running, thus it’s meant for short timing (literally seconds);
- A reminder actuates a Grain when there’s a need to perform some action. It’s designated for protracted periods (minutes and longer).
If we’re talking about retail banking product development, then reminders are more tangible as they assist with scheduling ETL procedures, intermittent transactions (bond payments, recurring service payments, deposit interests, and more), daily post-processing, and many other activities that should be performed repeatedly.
Microsoft Orleans is a powerful tech tool that comes with a myriad of features to solve different types of problems, even the most complex ones. The list of ‘manageable’ issues includes the ones that most software engineers and our teams as well, encounter during the banking product development process, including but not limited to ensuring distributed locking and single point of access to domain entities.
The programmatic model and features like the distributed messaging and co-hosting make this solution handy to work with. Though like any other technology, it has certain constraints that should be covered by developers carefully, the benefits still far outweigh, which makes it one of the best cross-platform app development frameworks for the financial services industry.
Create your free account to unlock your custom reading experience.