Partners About Blogs Contact
discover Our services
Closed Menu
Our Services
No items found.
Home>Blogs>Technology>Documentation-First Refactoring: Changing Legacy Code Without Breaking It or Stalling on Security Review
Developer refactoring legacy code on a laptop, representing secure documentation-first refactoring
October 22, 2026

Documentation-First Refactoring: Changing Legacy Code Without Breaking It or Stalling on Security Review

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Something specific has happened to AI coding tools over the past three years, and the data is unusually clear about it. Veracode has been running the same benchmark since 2023: give a model a coding task that can be completed securely or insecurely, then scan the output. Syntax pass rates climbed from roughly 50% to 95%. Security pass rates did not move at all.

That gap is the whole problem for engineering leaders right now. AI coding assistants got dramatically better at producing code that runs and no better at producing code that is safe, while review capacity stayed flat. This article is about documentation-first refactoring: a way of changing an undocumented code base safely, and without security review throttling coding velocity. Written for the engineering leader whose team is shipping faster than anyone can check.

What actually changed about coding in the last three years?

Volume, mostly. AI coding assistants moved from novelty to default in everyday coding, and commit rates rose accordingly. What did not rise is the number of people qualified to review what gets written, which means the ratio of code produced to code genuinely examined has shifted against you.

The security picture is worse than the productivity debate suggests. Veracode's 2025 GenAI Code Security Report ran more than 100 large language models through 80 coding tasks across Java, Python, C#, and JavaScript, and found that 45% of generated samples introduced OWASP Top 10 vulnerabilities. Java was the worst performer at a 72% failure rate. The finding that should change how you run coding review is that larger, newer models were not safer, which points to something structural rather than a gap the next release closes.

Their Spring 2026 update confirmed the trajectory. Syntax pass rates rose from about 50% to 95% since 2023 while security pass rates stayed flat between 45% and 55% regardless of model generation. Notably the picture varies by vulnerability class: models improved at avoiding SQL injection and weak cryptographic algorithms, and got worse at cross-site scripting and log injection. Coding assistants optimize for code that works, because that is what they were trained and evaluated on.

Code editor showing a large change waiting for security review

Why is security review suddenly the bottleneck?

Because review is a human process attached to an automated one. A developer with AI coding assistance can produce a week of changes in a day, and the one security engineer reviewing it cannot read four times faster. Code review queues grow, checks become shallower, and eventually someone waves things through to protect velocity. That is the failure mode, and it arrives quietly.

The Cloud Security Alliance's research note on AI-generated code describes the same dynamic from the data side: citing Apiiro's data, AI-assisted developers commit three to four times more often than peers while monthly security findings rose tenfold. Coding speed and coding safety are not trading off evenly. The gap compounds.

The deeper issue is context. An engineer reading a diff has to reconstruct intent from the change itself, because intent lives in a developer's head or in a coding session with a model that nobody saved. Reviewing a 400-line diff without knowing what the component was supposed to do is not really a code review, it is guesswork with a checklist.

Person writing a specification on paper before refactoring code

What is documentation-first refactoring?

Write down what the code does and what the change is meant to achieve before you touch it. Then refactor against that written specification, and hand it to the reviewer alongside the diff. The idea is old, the reason it matters for modern coding is new: it is the only way to give a security reviewer enough context to move at coding speed.

In practice it means three artifacts before any coding starts. A behavioral description of the current component, including edge cases and error handling. A statement of what will change and what must not, including any nested behavior that looks incidental and is not. And the security-relevant properties: what authentication applies, what data flows through, what trust boundary this sits on.

None of that is heavy. For a single component it is perhaps an hour of work before any coding starts, and a model can draft most of it from the existing codebase while a human corrects it. The return is that every change afterward is reviewable against a stated intent rather than reverse-engineered from a diff.

How does documentation change what review can do?

It converts review from archaeology into comparison. Given a specification, review asks whether the change matches what was intended and whether the stated security properties still hold. That is a bounded question with a defensible answer, and it keeps pace with coding output, and it takes a fraction of the time that reconstructing intent takes.

It also lets you route work correctly. Not every change needs security experts. If the documentation says a component touches authentication, handles credit card numbers, or sits on an external interface, it gets deep review. If it renames variables in a reporting routine, linters and unit tests are sufficient. Most organizations apply uniform review to every coding change, which means the high-risk changes get the same thirty minutes as the trivial ones.

And it makes automated tooling more useful. Static analysis and most automation produce findings without knowing whether a code path is reachable or whether an input is already validated upstream. Documented data flow lets you triage those findings quickly instead of working through a backlog of maybes. That is where a lot of coding review time silently goes.

What does this look like on a legacy codebase nobody documented?

Start with behavior rather than intent. Instrument the running system, capture real inputs and outputs, and write the specification from observed behavior. You will not recover why a rule exists, and you do not need to for refactoring purposes. You need to know what it currently does so you can prove you did not change it.

Then use AI for the first draft of the documentation, not the first draft of the code. This is the one place where using AI on an old code base is clearly net positive. This is the inversion that matters. Models are genuinely good at reading unfamiliar code and explaining a component, and that is the highest-value coding task you can give one on an old system. Have a developer verify the explanation against the behavioral capture, because the model will describe logic confidently that does not match runtime reality.

Work incrementally and pick the right order. Document and refactor the components you are about to change anyway, not the ones with the worst code quality. Coverage of the whole codebase is a multi-year ambition; coverage of what you touch this quarter is achievable and immediately useful. Our code modernization practice sequences it this way, and the broader method is in our pillar on legacy application modernization.

Two engineers planning small, sequential refactoring steps on a whiteboard

How do you refactor safely?

Test coverage first, and specifically characterization tests that assert current behavior rather than correct behavior. If a legacy component has a bug that downstream systems depend on, your tests should lock that bug in place until you decide deliberately to fix it. That is the difference between refactoring and rewriting.

Change one thing at a time and keep each coding change small enough to review properly. A refactored component delivered as a 2,000-line diff will not be read carefully by anyone, regardless of how good your documentation is. Small, sequential, independently revertible changes are what let you iterate safely on code nobody fully understands, and they are far easier to debug when something does break. GitClear's data, summarized by MIT Technology Review, shows refactoring collapsing as a share of code changes since AI adoption scaled, which is the habit this discipline is meant to restore.

Watch for the failure modes that tests do not catch. Race conditions, retry behavior under load, message queue ordering, and runtime dependencies on timing survive most refactors and surface in production. Where a component has any of those properties, say so in the documentation so the reviewing engineer knows where to look, and validate against the behavioral capture rather than against the unit test suite alone.

Red padlock on a keyboard, representing access control checks in code review

What should the security review actually check?

Four things, prioritized by consequence, whatever coding tools produced the change. Whether the change crosses a trust boundary. Whether authentication or authorization logic moved. Whether new data flows were introduced. And whether the change touches input handling, where injection and encoding problems live.

OWASP's 2025 Top 10 still places broken access control at number one, and reports that every application tested exhibited some form of it. That is the category to check hardest in any refactor, because authorization logic is exactly what gets accidentally relocated when someone reorganizes a component. A refactor that moves an auth check inside a conditional is a working application with a hole in it.

Then apply the known weak spots in AI-assisted coding specifically. Veracode's data says models handle SQL injection reasonably and handle cross-site scripting and log injection badly. If your application code is a JavaScript or HTML-heavy frontend and your team leans on AI coding tools heavily, output escaping deserves disproportionate attention. Our cybersecurity consulting teams review against that pattern rather than a generic checklist.

What coding standards should you set for AI-assisted work?

Write them for the failure modes you actually have. Generic guidance on how to write code securely does not help a team whose real exposure is that nobody reads a 900-line diff. Useful coding standards in 2026 name a maximum change size, require the specification, and state which coding tasks may be delegated to a model and which may not.

Be specific about where AI-assisted coding is and is not allowed. Scaffolding, test generation, data transformations, and code organization work are low risk. Authentication, session handling, payment paths, and anything writing raw SQL query strings are not secure code territory for an unsupervised model, and should require a developer with real security knowledge in the loop rather than an IDE suggestion accepted at speed. Every developer on the team should be able to recite that boundary without looking it up.

Then codify the review split. Frontend and UI work in JavaScript or HTML gets output-encoding attention; backend and API changes get authorization and data-flow attention. Working on a wrapper around a legacy interface is different from making changes inside business logic, and your coding standards should say so rather than treating a single line of code the same everywhere.

Where does AI fit into the review side?

As a first pass on coding output, never as the decision. A model can flag obvious issues, summarize a diff, check new code against the documented specification, and identify which code paths a change affects. It will catch some insecure code before a human sees it. That triage genuinely reduces load on the review side and is the highest-leverage use of AI in the coding workflow after documentation.

What it cannot do is own the judgment. An AI checker evaluating AI-generated code shares the same blind spots, and the Veracode finding that model scale does not improve security suggests those blind spots are not going away with the next release. Treat model output on the review side as a colleague who is fast, tireless, and occasionally confidently wrong.

There is also a conflict worth naming. If the same coding assistant writes and reviews the change, you have removed the independence that makes review work. Use different coding tools for generation and checking where you can, and keep a human decision at the merge point. We cover the governance side of this in our framework guide for governing AI and in how to detect and govern AI agents in your organization.

How do you get engineering teams to actually write the docs?

Make it the input to the coding work rather than a deliverable after it. Documentation written before coding gets used; documentation written afterward is a compliance artifact nobody reads. If the specification is what the developer does the coding from and what review runs against, it earns its place in the workflow.

Keep it small and structured. A page per component, in a consistent template, stored next to the code so it moves with it. Long documents rot and nobody updates them. A short structured doc that is required for merge stays current because the process forces it.

And measure the thing you actually care about. Not documentation coverage, which is easy to game, but review turnaround time and the rate of security findings that survive to deployment. If documentation-first coding is working, both improve. If neither moves after a quarter, the process is theater and you should change it rather than defend it.

What does this change about velocity?

Short term, a little slower. You are adding an hour per module before coding starts, and coding teams feel that immediately. Be honest about it rather than promising the change is free, because the credibility of the whole initiative depends on the first month not being oversold.

Medium term, meaningfully faster where it counts. Review turnaround drops because reviewing engineers stop reconstructing context. Rework drops because the architectural decision is explicit before coding begins rather than surfacing in review. And onboarding gets faster, since a new dev reading a documented component is productive in days rather than weeks, and can integrate with the team without shadowing someone for a month.

The structural gain is that security stops being a gate and becomes a property of the work. That is the only sustainable answer when your team can generate code faster than anyone can read it, and every indication is that AI coding output keeps accelerating while human review does not. Designing the software development lifecycle around that asymmetry is the job now.

See where your code base actually stands

Our Hotspot Analysis identifies the modules where change is most frequent and risk is highest, which is where documentation-first work pays back first. You get a ranked list, a dependency map, and a realistic sequence rather than a mandate to document everything.

If your review backlog is growing faster than your team, that is the symptom worth diagnosing before it becomes an incident.

Key things to remember

  • AI coding tools got much better at correctness and no better at security. Veracode's benchmark shows syntax pass rates rising from about 50% to 95% since 2023 while security pass rates stayed flat at 45% to 55%.
  • Model size does not fix this. Newer and larger models were not safer, which makes it a structural property rather than a temporary limitation.
  • The coding bottleneck moved from writing code to reviewing it. Commit volume rose three to four times with AI assistance; review capacity did not.
  • Document before you change, not after. Behavior, intended change, and security properties, written down and handed to the reviewer with the diff.
  • Documentation converts review from archaeology into comparison, which is what lets it run at coding speed.
  • Use AI to draft the documentation, not the replacement code, the highest-value coding use on a legacy system. Reading unfamiliar code is where models genuinely excel.
  • Write characterization tests that lock in current behavior, including bugs, before refactoring anything.
  • Route review by risk. Trust boundaries, auth changes, new data flows, and input handling get depth; renames get static checks.
  • Check access control hardest. It remains the top OWASP category and it is what accidentally moves during a refactor.
  • Measure review turnaround and escaped findings, not documentation coverage. If neither improves in a quarter, change the process.
Documentation-First Refactoring: Changing Legacy Code Without Breaking It or Stalling on Security Review
Book your free Discovery Call Today!

Embark on the path to efficiency and success by filling out the form to the right.

Our team is eager to understand your unique needs and guide you towards a tailored ClickUp solution that transforms your business workflows.

Start a conversation

Tell us about your project

Share a few details and our team will get back to you with the right next step.

We use your details only to respond to this request. See our Privacy Policy.

Thanks, we have your message.
A member of our team will review it and get back to you soon. If it’s urgent, call us on (703) 844-0918.
Oops, something went wrong. Please try again or email hello@visioneerit.com.