Extension-based design to modernize legacy software
In the recent years, computational technology has been dynamically evolving at an unprecedented pace. Programming languages, frameworks, tools, and architectures are either becoming deprecated or losing technical support, which poses significant risks to products that rely on them.
With time, the probability of your legacy software not working as expected after updates increases dramatically. If you are lucky, the said legacy software remains operational, however, behind the scenes, you might be facing lacking functionality, performance and stability issues, security vulnerabilities, and other critical problems potentially causing reputational and financial damage.
Moving towards digital transformation typically requires thought-out planning, considerable budget, and time. But while some organizations take over this journey and enjoy accelerated competitiveness and profitability, other companies are sensibly falling behind.
If you find yourself in an unpleasant situation where your legacy product becomes unfunctional, keep reading. In this detailed overview, we described the approaches we apply to modernize legacy products, which have been verified by our daily practice and helped our partners stay afloat in the fast-paced world of innovation.
Problem outline
Let’s suppose you’re utilizing legacy software, which helps you manage operational processes and customers. In case the language, framework, tool, or architecture behind that legacy platform becomes obsolete, you may find that proper maintenance becomes challenging, with costs likely approaching the application’s initial price. As technology rapidly evolves, it gets more difficult to involve software developers with the required expertise. This leads to paying over-market rates to contract software developers, which also reflects on the budget.
Over time, you might face issues in terms of productivity, customer engagement and satisfaction, and security. That’s when you’re likely to face reputational and financial damage.
Yet still, software modernization is requiring solid investment, isn’t it?
Not necessarily – enterprise software can be successfully modernized even without massive expenses.
Legacy product case example
Let’s assume we are dealing with enterprise software, where users can create and modify workflow templates. Most certainly, the utilized enterprise platform will provide the opportunity to integrate predefined steps – email management, file manipulations, data sharing and retrieval, smart analytics and reporting among others.
Adding a new step or modifying existing one might cause undesirable and hard-to-resolve issues. That’s because all modules of the utilized application are integrated into one monolithic system, and thus highly interconnected.
Upon analyzing the problems commonly faced, we found that typically the system is functioning as expected. The majority of inquiries commonly concerns certain steps being dysfunctional in some specific environments – for example, the most problematic step is the smooth communication with the SAP system, where APIs/SDKs are changed quite frequently and which is complicated to maintain on the product side.
Given that full-fledged refactoring may incur unaffordable costs, how can we approach monolithic architecture to obtain:
- The ability to adapt new API/SDK and other third-party libraries breaking changes
- The ability to support backward compatibility
- The ability to utilize modern technologies to resolve existing problems
- The ability to engage experienced engineers to work on the legacy product
- Reduced risks – the ability to eliminate unintended effects
- Increased productivity – the ability to resolve customer-reported issues without new version release
Problem solution
Let’s consider the option of building an application that will serve one specific problem of the legacy software. In our specific case – a workflow management system we’ve already described above – a solution that handles the communication with the SAP platform.
To create successful architecture, our team can apply the expertise we gained from resolving similar problems. By using modern technology, our experts can build a whole separate application for the SAP communication – for example, we can smoothly implement workflow steps using .Net 6 or Node.JS although the legacy product is written on .NET or VB.
The integration of the new application with the parent system is the next challenge.
When facing such issues in our past projects, we took the inspiration from the Visual Studio code architecture. As it was built with customization and extensibility in mind, most parts of the Visual Studio code architecture can be enhanced through extensions-based design.
The benefits of extensions might include:
- Cross-platform compatibility – the product can be extended with cross-platform extensions and work seamlessly across different platforms
- Cloud integration – with extensions hosted in the cloud, the product can be seamlessly migrated
- Enhanced scalability – with extensions, the product can be easily scaled without slowdown and crashes
- Improved security – the extensions are run in separate process boundaries streamlining protection from malware and other potential threats
The concepts to note:
- Domain host – core product in a particular domain we want to extend
- Extension – separate application extending the parent system (domain host)
- Extension manifest – JSON file that defines the extension and makes it visible to the domain host
- Activation events – extension states in the extension manifest, in which host events should activate – for example. extension should be activated when workflow is to be executed
- Contribution points – extension states in the extension manifest, in which host modules should extend – for example, extend “workflow steps catalog”
- Extensibility API – the API that’s exposed by the domain host for the extensions developers
- Entry API – the API that defines activate and deactivate functions that extensions must implement (activation function is executed by the domain host after being triggered by activation events)
The extension is represented by the JSON manifest, which follows a specific, predefined schema and declares the extension’s name, version, and instructions for the domain host on how and when to activate the extension. The host can find available extensions by searching for the JSON files in the determined directory – this process is called extension discovery.
To reduce the impact on the domain host startup performance (the time that’s needed to initiate and activate after start or restart), the extension can be either loaded as late as possible or be disabled during the session. To enable lazy loading of extensions and thus conserve memory, the events are fired when triggered by a specific factor, the so-called activation event – for example, the extension for the toolbox should only operate when opened for the first time.
To provide enhanced security, we execute the code in a separate process, which creates isolation boundaries that ensure improved stability of the domain host and restrict malicious code within main isolation boundaries. What’s more, executing code in a separate process allows choosing the most sustainable technology for future extension’s implementation.
After discovery, the host can launch executable processes using information from the JSON file and establish the interprocess communication channel between extension and processes happening within the domain host. Once triggered by the predefined event, the extension is activated via IPC communication channel using the entry API.
Speaking about Extensibility API, there are some things worth mentioning:
- Extensibility API is defined by the domain host
- Extensibility API is used by extensions to interact with the domain host
- By controlling Extensibility API that’s exposed to extenders, the host can obtain strict control
- Extensibility API is outlining the host’s contribution points that can be customized through extensions
Let’s recall the challenge revealed earlier: how do we integrate the new SAP workflow step application with the legacy product that’s written in a different technology? The answer – by implementing software extensions!
The integration of the extensions-based design is performed in the following steps:
- The refactoring of the legacy application to support built extensions.
- 1. The implementation of the contribution point – a module that provides the ability to discover and execute workflow steps as extensions , let’s name the module – ‘workflow step catalog’.
- 2. The implementation of the IPC layer for the contribution point. Each workflow step in the catalog will define two RPC endpoints: Activate and ExecuteStep.
- 3. The utilization of the input/output streams as a transport layer for the IPC layer
- 4. The integration of the workflow step catalog with the legacy workflow execution engine. If a step exists in the workflow step catalog – use it, otherwise use old step implementation.
- The conversion of the SAP application
- 1. The creation of an extension manifest
- 2. The implementation of the IPC layer based on the process’s standard input/output streams. The same as for Step 1.
- 3. The implementation of Activate/ExecuteStep RPC endpoints
- Add integration tests to verify backward compatibility is not violated
To note: We recommend using the JSON-RPC protocol for the smooth implementation of the IPC layer.
If considering the processes described above, what is your estimate for the whole project, a couple of months? You will be surprised – the project would take only about 2-3 weeks, if approached by professionals.
It’s worth to note that there are no one-size-fits-all solutions to the above described functional requirements. One should always evaluate the architecture before building and deploying.
Extension-based software modernization of an RPA product
Further in this part, we’ll discuss one of our projects aimed at software modernization of an enterprise-level robotic process automation solution.
The product was an on-premise platform designed to thoroughly evaluate and automate operational processes. Having conducted in-depth investigation, we found that the provided platform is outdated, unstable, inflexible, and complicated to deploy and maintain.
There were two challenges to address:
- About 80% of issues were originating from small automation activities, which were the basis and main building blocks of larger automation scenarios
- It took up to one month for the support team to upgrade a customer to the newer version
To resolve these issues:
- Problem 1
- We implemented extensions-based infrastructure for the main monolith
- We provided an SDK to write automation activities no matter the platform
- We integrated distribution system and version management for the automation activities
- We integrated testing capabilities to troubleshoot any problematic automation activity on the end-customer environment
- Problem 2
- We implemented a health check tool comprising predefined test suits to help support staff:
- Analyze the target environment before installation
- Analyze the upgraded product after installation
- We re-designed an installer to support partial installation
- We implemented a health check tool comprising predefined test suits to help support staff:
Extension-based design: The pros and cons
The advantages of an extensions-based design:
- New features are added no matter the technology behind the legacy product and with minor changes to the code base, which provides greater flexibility and scalability
- New features are executed in a separate process, which minimizes stability issues in the legacy product
- Customer issues can be fixed quickly by introducing new extensions or improving existing ones
- Different components can be based on different technologies
- Separate modules or components make the software development more manageable – multiple teams can work on improvements in parallel without friction and conflicts
- Separated functionality reduces complexity, which notably simplifies maintenance and troubleshooting
- The extensions can be re-used between multiple products within the same domain
The disadvantages of an extensions-based design:
- Two-way communication between extension and the legacy product might become quite messy
- Complex infrastructure: The design of a thought-out infrastructure to maintain multiple versions typically requires specialized expertise, in particular DevOps services
- Deteriorated performance: The performance can be negatively impacted by the IPC layer
- Harder maintenance and debugging: Both maintenance and debugging might become more complex and require more expertise
System examples where extension-based design is used
Jira is a widely used project management and issue tracking software, while Slack is a popular business messaging app. These two platforms can be integrated using “Jira Cloud for Slack”. Such integration enables users to receive real-time Jira updates and notifications within their Slack channels. This integration demonstrates the power of extension-based design and how it can improve team collaboration and communication. Slack supports extension-based design and “Jira Cloud for Slack” is a prime example of an extension.
Another real-world example of the extension-based design is Google Chrome (and all modern browsers) – it supports various extensions that allow users to customize their browsing experience, add new features, and enhance productivity.
Salesforce supports apps and integrations that can be used to extend the functionality of the platform and integrate it with other tools and services.
We can assist in creating extensions for the software mentioned, as well as incorporate extension-based design into your current software, as outlined in this topic.
How we can help
Abto Software helps partners smoothly approach legacy modernization by applying domain-specific expertise. From initial business consulting and discovery to planning, coding, deployment, and maintenance, our teams take over legacy migration and optimization no matter the complexity.
We wrap legacy products in the latest technology to help our clients gain more market share.
We cover:
- Platform migration
- Cloud migration
- Code refactoring and reengineering
- Performance optimization
- Application integration
- Extension design and integration
To provide:
- Reduced time and cost
- Increased performance
- Enhanced compatibility, flexibility, scalability, and stability
- Accelerated security