Technical debt & modernization

We rewrite the systems nobody else will touch.

Entire platforms or single subsystems. Reverse engineered from what actually runs, rebuilt to be maintainable, and verified against the incumbent before anything is cut over.

The problem

Technical debt stops being a technical problem and becomes a strategic one.

Every organization carries technical debt. It only matters at the point where the system starts dictating the business — when a product decision is shaped by what the platform can tolerate, when a change nobody will authorize sits in the backlog for three years, when the answer to a competitor’s move is that it would take eighteen months.

At that point the conventional advice is a full rewrite in a modern language. Most of those programs fail, and they fail for a knowable reason: they attempt to change the language, the platform, the architecture and the behavior simultaneously, then discover in year two that nobody actually knows what the original system did. The specification was never the documentation. It was the code.

We work the other way round. Recover the real behavior first. Restore maintainability without changing anything else. Prove equivalence with evidence rather than a test plan. Only then consider architecture, language or platform — each as a separate, reversible stage with its own exit criteria.

Diagnosis

Six signs the debt has become the strategy

Nobody will touch it

Change requests against one system are quietly refused, deferred or routed around. The organization has already priced the regression risk as infinite, without ever saying so out loud.

The documentation describes a different system

What is written down and what runs in production diverged years ago. Every estimate is now a guess, because the real specification is the binary.

The authors are gone

Institutional knowledge left with people rather than being captured in the code. What remains is a system that works and nobody can explain.

A vendor abandoned you

A supplier discontinued the software your hardware or workflow depends on. Your asset is now bounded by someone else’s product roadmap decision.

The platform sets the pace

Commercial decisions are being shaped by what the system can tolerate rather than what the market requires. That is the point at which technical debt becomes strategy.

The rewrite already failed once

A previous modernization attempt was cancelled, descoped or absorbed. The debt is now larger and the organization’s appetite for another attempt is smaller.

Scope of engagement

Entire systems, or the one subsystem holding you hostage

Whole-system rewrite

The platform is beyond incremental repair. We reverse engineer it, recover the real behavior, and rebuild it — in stages, against a verifiable reference, without a single irreversible cutover event.

Subsystem replacement

One component is the constraint: the batch engine, the rating logic, the integration layer, the reporting path. We carve it out behind a stable interface and replace it while the rest of the estate keeps running.

Reverse engineering

No source, no documentation, no author, or an abandoned vendor product. We recover the specification from the artifact — binaries, wire protocols, file formats, undocumented interfaces.

Maintainability recovery

The system is not replaced; it is made changeable again. Same language, same platform, behavior preserved, structure and documentation restored. Frequently the highest-value stage, and almost always the first.

Method

Four rules that make modernization survivable

01

The code is the specification

Whatever the documentation claims, the behavior of record is what runs in production. Modernization begins by recovering that behavior precisely, because every downstream system has been depending on it — including the parts that were bugs.

02

Change one variable at a time

Programs fail when language, platform, architecture and behavior change at once. We separate them into stages with explicit exit criteria, so a failure at any stage is contained and reversible instead of terminal.

03

Earn confidence with evidence

Parallel running against the incumbent, with output-level comparison and discrepancy triage, converts equivalence from an assertion into a measurement. No cutover should ever depend on a test plan alone.

04

Maintainability first, always

A system your team can read, change and test is worth more than a system written in a fashionable language that nobody understands either. Recover maintainability before you touch anything else.

Case studies

What this looks like in practice

Client identities are withheld as a matter of policy. The scale, the constraint and the elapsed time are stated exactly.

01 · Legacy modernization

An entire legacy insurance COBOL system, reverse engineered and rewritten in 11 hours

Forty-one COBOL modules reverse engineered from an undocumented production system and rewritten as maintainable production COBOL — ready for parallel testing as stage one of a multi-stage modernization.

Modules rewritten
41
Elapsed time
11 hours
Target language
COBOL
Stage 1 exit
Parallel-test ready

Situation

A legacy insurance platform written in COBOL was still carrying production policy and claims workload, and had become effectively unmaintainable. The original authors were long gone. Documentation described a system that no longer matched the code. Every change request carried unbounded regression risk, so the practical answer inside the business had become to stop changing it — which is how a working system quietly becomes an existential one.

The conventional options were both bad. A full rewrite into a modern language meant a multi-year program, a parallel organization, and a cutover event with no realistic rollback. Continuing to patch meant compounding the debt and accepting that the platform now dictated the pace of the business rather than the other way round.

Approach

  1. 01
    Reverse engineer the system as it actually behaves

    Not as documented. We recovered the real control flow, data structures, copybook usage, batch and online paths, and the undocumented behaviors that downstream systems had come to depend on. The behavior of record is what the code does in production, and that is what has to be preserved.

  2. 02
    Rewrite in COBOL, deliberately

    Stage one does not change the language, the platform or the operational model. It changes only maintainability. Rewriting to modern, structured, documented COBOL removes the single largest risk — that nobody can safely touch the system — without introducing a simultaneous language, runtime and skills migration. One variable at a time is why this succeeds where big-bang rewrites do not.

  3. 03
    Preserve behavior module by module

    All forty-one modules were reconstructed with their observable behavior held constant, so each one can be validated independently rather than as part of one indivisible cutover.

  4. 04
    Exit stage one parallel-test ready

    The deliverable was production COBOL prepared for parallel running against the incumbent system — the same inputs through both, outputs compared, discrepancies triaged. Confidence is earned from evidence rather than asserted from a test plan.

Outcome

Forty-one modules went from reverse engineering to production-ready COBOL in eleven hours of elapsed time, and entered parallel testing as stage one of a defined multi-stage program.

The client moved from a platform nobody could safely modify to a codebase their own team can read, change and test — without a cutover event, without a language migration, and without a multi-year budget line.

The multi-stage program

  1. 01
    MaintainabilityDelivered

    Reverse engineer and rewrite in place. Same language, same platform, behavior preserved. Exit criterion: parallel-test ready.

  2. 02
    Verification

    Parallel running against the incumbent, output-level comparison, discrepancy triage until behavioral equivalence is evidenced rather than assumed.

  3. 03
    Decomposition

    With a readable codebase and a proven equivalence harness, carve the monolith into service boundaries that match the business rather than the 1980s file layout.

  4. 04
    Migration

    Only now is a language or platform change safe, because every step is verifiable against a known-good reference and reversible.

The reason legacy modernization programs fail is that they attempt language, platform, architecture and behavior change simultaneously, then discover in year three that nobody knows what the original system did. Recovering maintainability first — and proving it — makes every subsequent stage an engineering decision instead of a leap of faith.

02 · Abandoned software recovery

An abandoned Android control application, recovered for modern devices in four days

A discontinued control-center application reverse engineered and refactored to run on current Android, restoring full control of hardware the manufacturer no longer supported.

Elapsed time
4 days
Source available
None
Target
Modern Android
Hardware changes
Zero

Situation

A fleet of deployed hardware depended on a companion Android control-center application that the manufacturer had abandoned. No source, no updates, no support. The application had been built against an Android generation several major releases old, and modern devices would no longer run it: permission model changes, background execution limits, deprecated connectivity APIs, and target-SDK enforcement had each independently broken it.

The hardware itself was fine and had years of service life left. The only thing standing between the owner and a working asset was software nobody would maintain — which is the ordinary way that perfectly good capital equipment becomes scrap.

Approach

  1. 01
    Recover the application from the binary

    With no source available, we reverse engineered the shipped package: application structure, resources, the control flow, and the state machine governing device interaction.

  2. 02
    Recover the wire protocol

    The valuable asset was never the app — it was the undocumented protocol between app and hardware. We reconstructed the command set, framing, handshake and response handling exactly, because the hardware could not be changed and would not forgive an approximation.

  3. 03
    Refactor onto a modern Android baseline

    The recovered logic was rewritten against a current target SDK: the runtime permission model, current connectivity and background-execution constraints, modern lifecycle handling, and current build tooling — rather than suppressing the platform checks and shipping something that would break again at the next release.

  4. 04
    Validate against the physical device

    Correctness was established against real hardware across the full command surface, not against a mock. A control application either drives the device correctly or it is worthless.

Outcome

Four days from an abandoned binary to a maintainable application running on current Android, with the full control surface restored and no hardware modification.

The owner recovered the useful life of deployed equipment, and now holds source they control — so the next Android release is a maintenance task rather than a second obsolescence event.

Vendor abandonment is a technical debt event that arrives from outside your organization, and it is one you cannot fix with process. When the software that operates your hardware stops being maintained, the asset is only as durable as someone’s willingness to reverse engineer the protocol. That is a specific, learnable engineering discipline — and it is usually far cheaper than replacing the hardware.

03 · Language migration

An abandoned PHP application reverse engineered, documented and refactored to Rust in 14 days

A legacy Laravel codebase with no maintainer recovered, specified, rebuilt as function-based Rust, and fully tested — production ready in fourteen days.

Elapsed time
14 days
Source stack
PHP / Laravel
Target stack
Rust
Test coverage
Full

Situation

An abandoned Laravel application was still carrying production workload with nobody maintaining it. The codebase had the profile that framework-heavy projects acquire when they outlive their team: business rules distributed across controllers, models, middleware, service providers and framework magic; behavior that depended on implicit resolution rather than explicit calls; and no meaningful test suite to describe what any of it was supposed to do.

The practical consequence was that the application could not be reasoned about. Runtime cost was high, correctness was unverifiable, and the framework version had aged past the point where upgrading was a small task. It was also, like most abandoned applications, still load-bearing.

Approach

  1. 01
    Reverse engineer the real behavior

    We recovered what the application actually does — request paths, data access, business rules, and the behavior produced by framework conventions rather than by written code. Implicit behavior is where abandoned framework applications hide their specification.

  2. 02
    Write the documentation that never existed

    The recovered behavior was captured as an explicit specification before any code was written. That document is the contract the rewrite is tested against, and it is a deliverable in its own right — the client now owns a description of their own system.

  3. 03
    Refactor to function-based Rust

    Rebuilt as explicit, function-based Rust rather than transliterated class hierarchies. Data flow is visible in signatures, error paths are values rather than exceptions, and the compiler enforces at build time a large class of invariants that the original relied on convention to maintain. Nothing resolves implicitly.

  4. 04
    Test to the specification, fully

    The suite was written against the recovered specification, not against the new implementation, so it validates behavioral equivalence rather than merely confirming the rewrite is self-consistent.

Outcome

Fourteen days from an abandoned, undocumented Laravel codebase to fully tested, production-ready Rust with a written specification.

The client moved from an application nobody could safely change to one with explicit control flow, compiler-enforced invariants, a full test suite, and materially lower runtime cost — and they hold the documentation describing what it does.

Language migration is the last stage of modernization, not the first — but when the source is already abandoned and unmaintainable, recovering the specification and rebuilding explicitly is frequently cheaper than resuscitating a framework nobody on the team understands. The deliverable that matters most is the document, because it is what makes every future change safe.

04 · Performance engineering

A custom binary MySQL driver delivering 33% latency and bandwidth improvement

Where the stock driver was the constraint, we wrote a purpose-built binary protocol client for the client’s specific access pattern — measured at a third less latency and a third less bandwidth.

Latency reduction
33%
Bandwidth reduction
33%
Layer
Binary protocol
Schema changes
None

Situation

An enterprise platform had exhausted the ordinary options. Queries were tuned, indexes were correct, connection pooling was in place, and the hardware was not the limit. What remained was the driver: a general-purpose client optimized for generality across every workload rather than for this one, carrying per-request overhead and wire redundancy that this specific access pattern did not need and could not avoid.

This is the point where most engagements stop and recommend more hardware, because the remaining cost is below the level most teams are equipped to work at.

Approach

  1. 01
    Measure at the wire, not the ORM

    We profiled the actual MySQL binary protocol exchange — round trips, packet composition, result-set encoding, prepared-statement handling and type marshalling — to establish where the time and the bytes were genuinely going rather than where the application framework reported them.

  2. 02
    Implement the protocol directly

    We wrote a purpose-built client speaking the MySQL binary protocol, implementing exactly the surface this workload required. Eliminating generality is the entire source of the gain: a driver that need not serve every case can be shaped precisely around one.

  3. 03
    Reduce round trips and wire volume

    The access pattern was restructured at the protocol level — statement handling, result encoding and marshalling tuned to the client’s data shapes — cutting both the number of exchanges and the bytes on each one.

  4. 04
    Verify against the stock driver

    Correctness and performance were both measured against the incumbent driver under representative production load, so the 33% figure is a comparison rather than a benchmark.

Outcome

A 33% improvement in both latency and bandwidth against the stock driver, achieved with no schema change, no query rewrite and no additional hardware.

The improvement compounds: lower per-request latency raises effective concurrency on identical infrastructure, and lower wire volume reduces cost on every metered network path the traffic crosses.

When the standard tooling is the constraint, the answer is not more hardware — it is to work one layer lower. Very few firms will implement a database wire protocol to recover a third of your latency. It is the kind of engagement that only makes sense with practitioners who have operated at carrier scale, where a third of anything is a material number.

Common questions

Modernization, answered plainly

Can Koi Consulting rewrite an entire legacy system?

Yes. Koi Consulting rewrites whole platforms and individual subsystems. The firm reverse engineers the system as it actually behaves in production, rebuilds it to be maintainable, and verifies the result against the incumbent through parallel running before anything is cut over. Work is delivered in stages with explicit exit criteria rather than as a single big-bang replacement.

How fast can a legacy COBOL system be modernized?

Koi Consulting reverse engineered an entire legacy insurance COBOL system and rewrote 41 separate modules as maintainable production COBOL in 11 hours of elapsed time, delivered parallel-test ready as stage one of a multi-stage modernization program. Timelines depend on system size and coupling, but recovering maintainability is measured in hours and days rather than the multi-year schedules conventional rewrite programs assume.

Why rewrite COBOL into COBOL instead of a modern language?

Because changing the language, the platform, the architecture and the behavior at the same time is why most modernization programs fail. Stage one changes only maintainability: same language, same platform, behavior preserved, structure and documentation restored. That removes the largest risk, which is that nobody can safely modify the system, without simultaneously imposing a runtime and skills migration. Language or platform migration becomes a later, separately verifiable stage.

Can Koi Consulting recover software a vendor abandoned?

Yes. Koi Consulting reverse engineered an abandoned Android control-center application for legacy hardware the manufacturer no longer supported, recovering the application logic and the undocumented device wire protocol from the shipped binary with no source available, then refactoring it onto a modern Android baseline in four days. The hardware required no modification and the owner ended the engagement holding source they control.

What is a maintainability recovery engagement?

A maintainability recovery engagement makes an existing system changeable again without replacing it. The language, platform and observable behavior stay constant while structure, readability and documentation are restored. It is frequently the highest-value stage of a modernization program and almost always the first, because every later stage depends on being able to read and test the system.

How does Koi Consulting prove a rewritten system behaves the same?

Through parallel running. The same inputs are driven through the incumbent system and the rewritten system, outputs are compared at the record level, and discrepancies are triaged until behavioral equivalence is evidenced rather than assumed. Confidence comes from measurement rather than from a test plan.

Can Koi Consulting migrate a legacy PHP or Laravel application to Rust?

Yes. Koi Consulting reverse engineered an abandoned Laravel application, produced the written specification it had never had, refactored it into function-based Rust, and delivered it fully tested and production ready in 14 days. Explicit function-based Rust makes data flow visible in signatures and moves a large class of invariants from convention to compile-time enforcement.

Does Koi Consulting do low-level performance engineering?

Yes. When standard tooling is the constraint, the firm works a layer lower. For an enterprise client whose queries, indexes and pooling were already correct, Koi Consulting wrote a custom client speaking the MySQL binary protocol, shaped to that specific access pattern, and measured a 33% improvement in both latency and bandwidth against the stock driver with no schema change, no query rewrite and no additional hardware.

Next step

Tell us which system nobody will touch.

We will tell you honestly whether it needs a rewrite, a subsystem replacement, or simply to be made maintainable again — and what stage one actually costs.