Your organization has taken the leap and chosen to modernize your existing COBOL monoliths into Java-based application services, ready for the cloud.
Your team plots out a journey toward success. Rather than taking a risky big-bang approach, each incremental release on the road toward modernization is prioritized and scheduled to save costs and capture value that finances the next step.
The automation factory starts to chew up old tables and churn out Java. The destination is in sight. Cue Barry Manilow singing, “Looks like we made it!”
But hold on, how do we define success for the Java code we’re getting back? Should the modernization project move fast and take less time, thereby providing better ROI? Should it be of impeccable quality? Or should it accommodate maintainability for change?
Must we choose between these options?
Why do we want maintainable Java code?
In a perfect world, once each modernization step was completed, you would never need to go back and revisit those deprecated old COBOL stacks to rebuild that functionality ever again.
Taking this a step further, you would also rather not have to entirely rethink and refactor your new Java codebase down the road either.
But like it or not, change will eventually come for your code.
No real business developer lives on an island with their own air-gapped deployment server. Things will always change within the environment, and the needs of target users will also change. At some point, any application may either consume or be consumed by another application, whether as a partner service or as part of an acquisition.
Whether the Java code is greenfield developed by the team to functionally replace legacy applications or converted from COBOL by an automated modernization solution like CloudFrame, you will still want the resulting Java code to be flexible enough to accommodate change and talk to other services, which is part of the nature of any modern system.
Maintainable code means that when a bug needs to be fixed, or updates need to be made in the future, a developer who did not write the code should be able to open it up, find it well-formatted and “clean,” understand its structure, and figure out how to make effective adjustments.
“Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.”
– John Woods
The need for maintainable code comes from team dynamics – whether intra-team developers are actively working on the same code in an agile or pairwise method – or extra-team settings where one development team hands off code to another development or operations team for maintenance or production.
So, if the original COBOL code was worth using in the first place and worth modernizing now, make sure that the resulting Java code is maintainable. Backtracking and refactoring an unmaintainable codebase again would be doubly costly for the original producer and downright impossible for whoever is receiving and maintaining that code to accomplish.
From worst-case quality to world-class maintainability
All too often, code quality is conflated with code maintainability, and perhaps in the previous century of procedural application design, quality code conversion might have been enough. We still want quality Java code that is syntactically correct and passes static analysis and unit tests, of course, as it is less likely to contain structural bugs.
Encouragingly, code quality can now be improved by dozens of code linting and static analysis tools that conduct specialized forms of introspection. These are invoked to run stage gate checks within the code delivery process.
For manual developer inspection, IDEs now have look-ahead features that mark possible bugs, style and syntax errors, or open expressions – and they can even suggest workarounds in a look-ahead fashion as the developer is editing code.
Better still, software testing tools have also come a very long way in the last 20 years, with better abilities to auto-generate regressions and unit tests, capture meaningful tests from code or UI, and simulate test data and environments to ‘cause the cause’ and observe meaningful results from the application.
Quality code has gotten way easier to confirm. But for modern Java applications, is quality enough? A completely automated suite of code checkers and testing tools could run alongside a code conversion project and still send back a bunch of JOBOL code in record time – Java that isn’t even object-oriented, much less ready to be extended to work in a service-oriented manner.
Sure, you could get Java that is debugged but still find yourself two steps removed from the original business intent codified within the COBOL application. JOBOL loses the context of how to maintain the system’s logic discretely from the distributed environment the code will live and interact in.
Good signs of Java maintainability
Maintainable code comes ready to interact within a modern target environment of distributed, cloud-based, and API-driven application services. Here are some signs that your modernization might be on the right track.
Object orientation. While OO is an inherent benefit of Java, if code conversion isn’t considered holistically, the resulting translation will fail to break up classes and services in a modular way, and sequential dependencies will appear in the new codebase.
Fewer redundancies, more reuse. Taking objects a bit further, we want to make sure code isn’t repeated uselessly throughout a codebase with slight variations based on its original position in the COBOL code. Wherever possible, similar objects should be consolidated into reusable components, with variables and service calls decoupled into their own handlers.
Built for production efficiency. Java introduced concepts like garbage collection and concurrency, but that doesn’t mean production issues can’t get passed into production. Without job scheduling, simultaneous processes may create race conditions, database connections may be left open, and compiled applications may spit out meaningless logs, ad infinitum. Maintainable code should tuck in these performance drags wherever possible.
Intuitive documentation. Well-documented code pays it forward to future maintainers with intuitively named objects and files, clarifying comments that provide breadcrumbs, and even release notes that can help describe the original application functionality as it was imported.
Configuration elsewhere. In general, application logic should always be separated from configuration code. If the migration process replaced mainframe-specific calls with Linux environment-specific commands, for instance, there’d be later difficulty moving the runtime to a different Linux edition or a Windows environment if needed.
Far from assembling a comprehensive list, all the above aspects of maintainability represent business value far beyond what software quality alone can deliver.
The Intellyx Take
There’s no good rationale for prioritizing quality over maintainability, as quality code that isn’t maintainable only adds to the organization’s technical debt.
Maintainability considers the clarity and modularity of code, so the applications it supports can remain more resilient over time.
While code quality remains important, quality has become easier to achieve with today’s powerful automated tools. Maintainability, however, requires thinking through code from a higher architectural perspective of what the extended application needs to do in production today and what it will need to do in an uncertain future environment.
Intellyx BrainBlog by Jason English for CloudFrame
©2022 Intellyx LLC. Intellyx is editorially responsible for this content. At the time of writing, CloudFrame is an Intellyx customer. No other organizations mentioned here are Intellyx customers. Image credit: Flickr
Find Out More
Learn more about Renovate.