Modernizing the Enterprise Monolith
Why Read This Green Paper
Are you an enterprise that recognizes the business liability inherent in the monolithic or otherwise dated enterprise software applications you have built? Does your technology represent an impediment to the needed agility and flexibility required to meet the needs of today’s business environment?
Historically, enterprise software development focused on an approach that incorporated all functionality into a single process, and replicated it across servers as additional capacity was required. Today, these large applications have become bloated and unmanageable as new features and functionality are added. And, as small changes are made to existing functionality, the requirements to update and redeploy the server-side application becomes an intractable juggernaut.
Forward-thinking organizations like Amazon and Netflix led the way toward deconstructed software stacks and efficient APIs. Both large and small organizations serious about embracing modern practices have followed by decoupling the front and back end of their enterprise applications, employing microservices and cloud technologies, and adopting agile methodologies. These very steps can serve to highlight additional technical deficits in old solutions and codebases, which in turn become stumbling blocks to modern development practices.
As these technology trends continue to evolve, how can your company keep pace and remain viable?
In this green paper, we discuss how CIOs, CTOs, and VPs of Engineering can lead the needed modernization with their counterparts in marketing and the business to ensure that their organizations remain competitive in today’s customer-driven and technology-led economy.
Key questions addressed include:
· Why is technical modernization vital for the business?
· What types of modernization projects are there?
· How does modernization fit into your organization?
Executive Summary
Green field projects are easy to match up with off-the-shelf ideals of modern architecture: services with meaningful boundaries, cloud ready, decoupled back end from the front end, RESTful APIs for communication from front to back and between services, and external dependencies.
Enterprise applications have more complex stories to tell, often several years into progressive modernization that may have had to cope with:
• Increasingly complex business and customer needs,
• Acquired products getting stitched to them under the hood, and
• Front ends that have gone from easy to develop and, at best utilitarian, to modern experiences informed by modern applications and mobile experiences.
An oft-cited answer is to break up large enterprise applications into microservices, and while not a universal fit, this approach has had proven value in many cases. However, the direction of modernization itself tests some of the capabilities of the organization.
A large, legacy code base is likely to resist modernization and forward-friendliness if it:
• Is not well documented and understood,
• Does not provide good RESTful endpoints,
• Is tightly coupled with the front-end,
• Lacks good test coverage, and
• Is not built on up-to-date frameworks/technologies.
And, perhaps most importantly, the technical and leadership team skill sets need to align, and/or be augmented with capability, to deliver the solution in a timely manner.
An organizational application should be capable of being a first-class player as a macro-service before any suitable candidates are selected for carving away into their own microservice. Net new functionality can then be written as microservices if desired, and the decision-making and risk mitigation of planning refactors will be enhanced by the certainties an up-to-date and well-supported enterprise application can provide.
Recommendations
Develop an architectural blueprint informed by your business strategy and best practices that will guide the organization and become a foundational document of architecture, patterns and development processes.
Consider adopting DevOps best practices to drive a culture of automation and transformation.
Deploy enterprise applications on cloud platforms to improve efficiency and automate operations.
Background: Modern Architectural Concerns
Software development continues to learn lessons from successive trends and resulting outcomes in the industry. Businesses are increasingly drawn to the operational and financial benefits that exist in cloud hosting. Combined with the well-established simplification which multi-tenancy can bring, bringing new customers onto your solution is often becoming faster and more streamlined. For reasons of scalability, engineering complexity or complex business domains, architects are increasingly opting in to a trend for microservices in place of traditional tiered monolithic solutions.
Definitions
Containerization: Application containerization is an OS-level virtualization method used to deploy and run distributed applications without launching an entire virtual machine (VM) for each app. Multiple isolated applications or services run on a single host and access the same OS kernel. Containers work on bare-metal systems, cloud instances and virtual machines, across Linux and select Windows and Mac OSes (TechTarget).
Microservices: A microservices architecture consists of a collection of small, autonomous services. Each service is self-contained and should implement a single business capability (Microsoft).
Multi-tenancy: Multi-tenancy is a reference to the mode of operation of software where multiple independent instances of one or multiple applications operate in a shared environment. The instances (tenants) are logically isolated, but physically integrated (Garner).
Considerations for Your Technical Architecture Planning
Modern Java or .NET Core stacks are both viable technical directions forward to ensure modernization without compromising on enterprise grade library support and a culture of strongly organized code. The evolution of your architecture should be informed by the skill set of your tech team and the ease with which evolution can be effected using agile methodologies.
Containerization consumes fewer resources than virtualization, and where applicable it requires less OS licenses than a virtualized setup. When implemented, it can be helpful for developers also, especially in a microservice architecture where each developer needs to be running many different moving parts.
Microservices do not need to share the same technology stack, libraries, or frameworks. There are proponents of deliberate polyglot approaches where the organization gains the benefits of multiple approaches. However, in all but the largest of organizations, we recommend retaining the benefits of a manageable portfolio of technologies.
Some microservice solutions are geared towards deliberately limiting re-use of code or data structures between elements. Weigh the benefits of this strict boundary approach against the learned dangers of duplicative solutions representing multiple entry points for maintenance and extensibility.
Multi-tenancy allows one instance of software to run on a server and serve multiple tenants; multi-tenancy contrasts with multi-instance architectures, where separate software instances operate on behalf of different tenants. Consider safeguards needed for security in ensuring multi-tenancy at all levels. If APIs and messaging follow disciplined (and documented) naming structures, it becomes easier to ensure expectations are followed at all levels.
Modernization: Enabling Architectural Direction
Organizations are challenged to change and maintain applications that were built in the era of client-side application development governed by the desktop when centralized, multi-tier architectures were used to create entire applications on a single codebase. Meanwhile, users and businesses seek the benefits from modern architectural trends such as containerization and cloud-based solutions, microservices and multi-tenant capabilities. With the additional expectation of improvements in user experience, legacy applications translate to impediments to effective modern development.
Challenges
A technical benefit pointed to by proponents of microservice architectures is avoiding the build-up of unconstrained complexity in such codebases. Enterprise codebases therefore often exist at the most challenging intersection: they have been built in a fashion that tends to more code complexity over time, and they have often been in development over a timescale where that complexity has had time to proliferate.
A monolithic application structure that is well matured can be an extremely good candidate for developing into microservices; its functional boundaries are understood, its business scenarios well refined, and so the hard delineations between services should be relatively easy to identify with success. Microservice architectures require these boundaries to be well understood as later changes to them present potentially larger hurdles than in a monolithic codebase.
At the same time, monolithic and legacy codebases often have baggage from the perspective of a modern microservice architecture. There may or may not already be well structured (if any) RESTful APIs. The APIs of an application can be thought of as the inventory of what a codebase is responsible for, and having these well understood can make it easier to reason about the ideal divisions of those responsibilities. If the front end is coupled with the back end and not represented through RESTful endpoints (or if the endpoints which do exist don’t allow for service division), this becomes another challenge for modernization.
Legacy code frameworks, or code spanning many different technologies, can also pose a technical challenge to host as part of a modern architecture, especially if they mandate concessions in messaging technologies or reliance on dependencies that limit hosting options.
Statistical Trends and Facts
Top challenges organizations expect to face include lack of visibility into end-to-end business processes that span multiple microservices (59%), error handling issues at the boundary of two or more microservices (50%) and communication between teams (46%) (Source: DZone).
The global cloud microservices market will grow at a rate of 22.5 percent, with the U.S. market projected to maintain a growth rate of 27.4 percent (Source: ResearchandMarkets 2019).
Nearly two-thirds of the organizations surveyed (63%) are building some (18%) or all (46%) of their applications using microservices (Source: DZone).
An additional quarter of organizations (28%) are considering using microservices for future applications (Source: DZone).
Of the dozens of Java frameworks which have competed for popularity, Spring has emerged as having >50% usage, with others in single figures. (Source: JetBrains).
Angular has had 5 major revisions, beginning with v4, between 2017 and 2019.
Key Questions to Consider in Your Current Architecture
No two complex solutions are identical. Solutions and businesses both have intricate histories, which intertwine on their journey to their present state, for better or worse. Every enterprise engineering organization puts serious thinking into ways they might navigate technical challenges and become more efficient. Finding a documented, understood and agreed-upon strategy is often challenging, and much of it may be passed as an unwritten culture between individual contributors rather than a roadmap between departments.
Business stakeholder interest in modernization is driven by a clearly visible link between proposed technical change and missed or thwarted business outcomes, past and future.
Practical nuances drive the implementation of modernization. For example, while it often provides possibilities for performance improvements, a heavily optimized specific solution may need thinking through more thoroughly if that solution relies on something holding back the rest of the codebase.
Key questions to consider as you consider modernizing your applications include:
How well understood is the need for modernization?
What drives technology modernization priorities in the enterprise?
To what extent does lack of modernization hurt development efforts?
What are best practices to retain and attract the right team and partners?
Outside of third party libraries and frameworks, how far does the architecture and code of your own solution hamper efforts?
Is your solution tested and testable?
Is the codebase organized, coherent and documented?
Is there an organizational agreement on what good will look like, or are there competing narratives that need to be resolved?
Is there good separation of concerns, between architectural layers but especially between the front end and back end?
If the front-end will require re-work, is there a coherence to design currently? Is there a documented design system in place (even if not yet adhered to)?
If you have started moving to microservices, are you incurring technical debt in the process? Do the boundaries drawn between the services still seem the right choices?
Can all developers and decision makers find answers to technical questions in architectural documentation?
How optimized (or over-optimized) is the current solution for performance?
Myths About Modernization
There are prevailing beliefs that persist in the engineering ethos, which can be counterproductive to a holistic understanding of what is needed to modernize.
Modernization Can Happen In The Background
Good engineers will always endeavor to leave things in a better state than they find them. As such, especially when there is a strong sense of ownership, businesses can think of technical improvement as things that will happen behind the scenes, by virtue of good engineering practice. Such efforts can be game changing at times, but without a business wide buy in to the needs for modernization, they will most likely be localized efforts with limited impact. In the face of serious technical debt, they may represent at best a success in avoiding the accretion of yet more technical debt.
Modernization Is A Need Created By Poor Engineering
It is important to think of the need to modernize without a sense of finger pointing. In a reality where agile processes have largely taken hold, choices of short-term gain over architectural soundness involve everybody from stakeholders down, and all understand deliberate compromises. Sound choices are overtaken by industry trends, and product acquisitions can catch out the most deeply planned architectural roadmaps. It is important to facilitate honest and open communication at all levels about technical impediments, so that different perspectives and experiences come together.
Modernization Can Be Delivered By A Tech-Debt Sprint or Percentage
Agile development will sometimes think of technical debt as something to do in an otherwise “slow” sprint, or something that can be addressed by giving over a percentage of velocity to the effort. However, serious modernization is something that needs time for proper analysis as much as novel feature development (often more since by definition it won’t have an easy pattern to follow). Moreover, by limiting the scope of what can fit into a specific sprint, the true ROI consideration of desired outcomes gives way to a more engineer-story size view driven by what is feasible.
Difficulty In Estimation Means Modernization Should Not Be Undertaken
Modernization’s resistance to accurate estimation can’t be overstated. A unique legacy set of challenges means the engineering required will be a little different every time. Estimation is going to involve some guesswork, and excessive optimism only increases the risk. When an organization is being hampered by the status quo, the ROI remains a reality even if the error margins in estimation are necessarily higher than in some projects.
Technical debt can be crippling to a company, and without the understanding of the difficulty of the problem, a vicious circle of inefficiency can easily become a default outcome.
Rewriting Is More Sensible Than Modernizing
The uncertainties and challenges in modernization mean that some believe a complete rewrite of a solution makes more sense than working with what already exists. In the case of a poorly executed solution, perhaps further hindered by poor testing and documentation, it truly can make the most sense to begin again, starting with capturing requirements.
Most well-established enterprise solutions survive because they serve needs with some degree of effectiveness. Functionality is almost always added over a long period of time, whereas a rewrite project is encumbered with needing to deliver most or all of that functionality from the go-live date. The risk is accordingly higher, even more so in cases where what the outmoded application does in fact is the de facto documentation of what it should do.
What is a Modernization Project?
At its purest, a modernization effort is a discrete ROI based undertaking whose primary goal is to solve technical deficits caused by obsolescence, technical inflexibility or other forms of outlived solution. Unlike ordinary endeavors, where the functional dependency and end-user value has primacy, the infrastructural maintainability and other non-functional requirements may take first priority, again based on demonstrated ROI.
Understanding what a modernization project can mean in this pure form can also help when incorporating elements of modernization into other projects. Engineering often mandates that the functional requirements take priority over non-functional aspects, and this can result in their being excluded from scoping. If the ideal modernization project is understood and contemplated correctly, it may then become possible to envisage ways to deliver incremental pieces of these during other projects. However, as situations change over the course of multiple project lifespans, gaining the final ROI by piecemeal approaches contains its own risks.
Different Modernization Endeavors
Modernization projects may span the back-end only, or the front-end or both. Common front-end navigation code may be used to allow two solutions to be temporarily bridged from a visual standpoint. Likewise, code “bridges” may be created in both front-end and back-end code to allow application code to be used in a DRY fashion inside legacy and target frameworks at the same time.
Examples of modernization project might be:
Reworking to remove a specific list of technologies from a solution
Making RESTful endpoints from a server-side rendered solution, to facilitate a modern front-end
Adding a modern security solution to an insecure solution
Collapsing two of more frameworks down to one
Moving business code from a legacy or home-grown solution to a supported framework
Adding multi-tenancy to a single tenant-based solution
Replacing legacy or ad hoc front-end solutions with a current supported, potentially utilizing bridging code and a shared navigation structure while disparate technologies exist.
Successful Modernization and Risk
Mitigating risk is especially important in modernization efforts. Where modern productivity-enhancing code environments lend themselves to fast results, be prepared for erring on the side of analysis and correctness where applicable. Particular areas to watch out for are:
Areas of the application whose business requirements are poorly documented
Opaque areas of code such as long stored procedures, poorly broken down methods
Reliance on specific third party solutions which might not translate well into the target technology stack
Disorganized code, especially in the front-end if identifiable patterns haven’t been followed
As with smaller refactoring efforts, the quality of test coverage directly affects the amount of regression defects that are likely to emerge from the work. It may be prudent to create broad sanity checks involving a large amount of sanitized real data to try to catch instances where old and new versions of solution code differ in what results they give. Explore creative ways to reduce the fragility of tests, for example in the way responses are analyzed or DOM elements selected.
Consider all ways possible to turn a wholesale cutover from old to new into something more iterative. These may include:
Keeping a legacy application working and decreasing its responsibilities gradually
Moving the navigation of the front-end into the ideal solution, and finding a way to serve the legacy content beneath it until all code is modernized
Using the potential for flexibility of messaging or dependency injection mechanisms to allow code to migrate from old to new
Modernization In Specific Technologies
Java Enterprise
What was once a more fragmented space has largely consolidated around the Spring and Spring Boot frameworks. Some new frameworks are gaining traction specifically in the space of microservices, particularly where resources and startup time are involved, but Spring continues to work to stay at the front of such trends. Notable in Spring is its extremely flexible dependency injection, making it a strong target for porting legacy dependency injection code but also providing added functionality that can help with migrations.
The open source nature of the Java ecosystem lends itself to a strong variety of approaches and opinions, and advocates exist both for following best practice frameworks, as well as for writing custom code from first principles. Microservices with their intrinsic limit to complexity can add to the attraction of not needing frameworks at all, but long-term maintainability, onboarding and resourcing still make a strong case for using community solutions where possible.
JSR standards continue to play an important part in community harmonization. The more disciplined frameworks encourage their use, and where they have been followed, moving injected dependencies, persistence-annotated entities and validation-annotated beans from a source to a target framework is made low effort, excepting where implementation-specific enhancements have been used.
.NET and .NET Core
With the recent release of .NET Core 3.1 and the announcement that all future releases of .NET will be based on .NET Core, now is the ideal time to start plans for the future of any enterprise applications. Unlike its predecessor, .NET Core is an open-sourced framework that supports Linux and macOS as well as Windows platforms opening cross platform opportunities that were previously only available in Java.
The .NET Core platform implements a common interface in many cases with the soon to be legacy .NET Framework. By supporting this commonality, the two platforms can interoperate for a period of time during any modernization projects providing more options for how projects are rolled out.
A strong native DI/IOC engine in .NET Core fosters testability from the ground up in modern projects. New projects may find it very easy to make use the new native engine, while projects that are transitioning from older versions may find that the ability to configure .NET Core to use 3rd party libraries like AutoFac, or Spring.NET instead of the native engine may reduce the risk of migration and further open incremental opportunities for improvement.
Security and performance are always top of mind with .NET Core as well. With the latest release, tremendous improvements in performance have been achieved across the board. Security updates are in your control, reducing or eliminating those pesky updates that come every month causing unexpected behavior through the use of NuGet packages that can be updated and delivered as part of a well-tested rollout.
There is a lot that .NET Core can bring to a modernization project. The inclusion of multiplatform support, the open source community, strong security, performance and testability tools built in from the ground up position .NET Core as a solid framework well into the future. Couple that with a robust development environment and integrated collaboration tools like Live Share, teams of any size or configuration can effectively navigate the challenges in any modernization project.
Angular / React / Other Front-Ends
Some trends in the front-end have special significance for modernization efforts.
Angular 2 caused upset by entirely moving away from AngularJS. However, just as Angular provides effective patterns for complex applications to follow, Angular’s upgrade module represents an admirable example of bridging code. Hybrid applications allow teams to develop new code in Angular while transitioning from and living alongside what has come before.
React’s compact and less opinionated approach means that teams are able to start pushing new patterns and approaches inside already complex pages. Web Components (and Angular elements) similarly seek to make things atomic enough they can bring encapsulated complexity wherever they are needed.
In all cases it is vital that the new code direction represents a genuine ideal in itself rather than a workable compromise. Front-end code is a notoriously easy place to add novel technical debt by poorly structured code or an absence of patterns, and effective modernization has to be focused upon a strong end state.
Conclusion
Modernization provides benefits to accelerate digital transformation. Changing the development and developer experience will accelerate delivery of key business needs and capabilities, and enable you to be ready to create and deliver new applications and services through adoption of modern practices.
Recommendations
Develop an architectural blueprint informed by your business strategy and best practices that will guide the organization and become a foundational document of architecture, patterns and development processes.
Consider adopting DevOps best practices to drive a culture of automation and transformation.
Deploy enterprise applications on cloud platforms to improve efficiency and automate operations.