Charles Hayes

ENTERPRISE JAVA APPLICATION MODERNIZATION

Moving legacy systems to modern architectures one safe, reversible step at a time.

About me

About Me

Modernizing the systems businesses already depend on

I've been working with Java almost since it existed. I first saw it as a book on an engineer's desk while I was an electronics test technician at Spectra Logic in Boulder, Colorado, teaching myself C on the side. Sun Microsystems had a campus eight miles from my home, and I decided I was going to work there. A few years of self-study and one lucky introduction later, I did: my first professional software job was building Java-based enterprise web applications at Sun.

Since then I've worked on enterprise Java systems from several sides: as a developer, as a test automation architect, and as part of a DevOps architecture team helping an organization move from waterfall delivery to continuous delivery. I've built and tested microservices, containerized test environments with Docker and Kubernetes, and set up the CI/CD pipelines that let teams change large systems without fear.

That mix shapes how I approach modernization. Most legacy applications aren't failing because of Java. They're hard to change because boundaries have eroded, tests are thin, deployments are risky, and knowledge is spread across a handful of people. Rewriting from scratch rarely fixes any of that. It usually just moves the risk somewhere you can't see it.

I treat modernization as a risk-management problem first and an architecture problem second. Microservices can be the right answer, but only when the domain, the team structure, and the operational maturity support them. Often the better first move is a well-structured modular monolith on a current Java and framework version, with tests and observability in place. From there, services can be extracted one at a time, behind a facade, with a rollback path at every step.

My background in quality engineering is a big part of what I bring. Characterization tests, contract tests, parallel runs, and good telemetry are what turn a high-stakes migration into a series of small, boring, reversible changes. Boring is the goal.

Approach

How I Modernize Without Betting the Business

Six steps that keep the system running, and shippable, the whole way through

01

Understand before changing

Map the domain, dependencies, and runtime behavior. Tie the effort to business outcomes such as release speed, scaling, or cost, and decide honestly whether microservices are needed at all.

02

Build a safety net

Pin down current behavior with characterization and API tests, add a CI/CD pipeline, and capture baseline metrics. You can't safely change what you can't verify.

03

Modularize in place

Upgrade the Java and framework baseline, then carve the monolith into modules with enforced boundaries. A clean modular monolith is often a good stopping point.

04

Strangle incrementally

Put a routing facade in front of the application and extract one capability at a time, starting where value is high and coupling is low. The legacy path stays live until the new one has proven itself.

05

Release reversibly

Use feature flags, shadow traffic, parallel runs, and canary releases. Every cutover has a measured success signal and a rollback that takes minutes, not a war room.

06

Untangle the data last

Split the shared database only after the code boundaries hold. Use views, change data capture, and the outbox pattern to move ownership without dual-write bugs.

Topics

What I Write About

Practical guidance drawn from real projects

Monolith Decomposition

Finding service boundaries, modular monoliths, the Strangler Fig pattern, and knowing when to stop

Java Platform Upgrades

Moving from legacy Java EE and old JDKs to modern Java, Jakarta EE, and Spring Boot

Testing as a Safety Net

Characterization, contract, and end-to-end tests that make large changes safe to ship

Cloud-Native Delivery

Containers, Kubernetes, CI/CD pipelines, and the observability that makes cutovers measurable

Latest

Latest Articles

Modernization, architecture, and the engineering practices that support them

Modernizing a Java Monolith Without Betting the Business

A step-by-step playbook for moving an enterprise Java application toward modular and microservice architectures while keeping risk low.

Quality Dashboards with Elasticsearch and Kibana

Aggregating results across frameworks to expose failure trends and release quality.

The Power of Playwright: Supercharging Test Automation with AI

What makes Playwright so capable, and how AI-assisted workflows make it even more powerful.

Contact

Contact

Planning a modernization effort, or stuck in the middle of one? I'm happy to talk.