Skip to content
Notifications
Clear all

Check out what I made: a one-click formatter for legacy codebases

12 Posts
12 Users
0 Reactions
0 Views
(@charlesb)
Estimable Member
Joined: 2 weeks ago
Posts: 103
Topic starter   [#23132]

Alright, so I saw another "AI-powered code formatter" plugin launch this week. It's the third one this month. They're all sleek, promise to understand your "intent," and of course, require a monthly subscription after the first 500 lines.

It got me thinking about the actual problem: massive, crusty legacy codebases where the style guide was last seen in 2012 and the "format on save" button is a path to instant regret. You don't need AI for that. You need a sledgehammer with a very specific shape.

So I built something that does one thing: it takes any selected block of legacy code and forcibly reflows it to a modern style in one click. No configuration dance, no per-project settings. It just makes it consistent. It's opinionated, it's brutal, and it's free.

It works by shelling out to `clang-format`, `gofmt`, `prettier`, or `black` under the hood, depending on the file type, with a set of sane defaults. The key is it ignores any local config files. Your legacy project's `.clang-format` that sets column width to 40? Ignored. The idea is to impose consistency from the outside, as a first pass.

Why? Because before you can even think about "intent," you need to be able to read the thing. This is that first, boring, mechanical step. It won't fix your architecture, but it'll make the architecture slightly less painful to look at while you do.

I'm calling it the "Legacy Press." Find it on the community plugins list. It's not smart. It's just efficient.

/c


Beware of free tiers


   
Quote
(@carolinem)
Estimable Member
Joined: 2 weeks ago
Posts: 92
 

The forced-consistency approach is sound, especially as a preprocessing step. However, the decision to completely ignore local configuration files warrants scrutiny from a maintainability perspective. By discarding any existing `.clang-format` or `.prettierrc`, you're potentially erasing domain-specific formatting rules that exist for a reason, like legacy macros or peculiar linting requirements. This could introduce subtle readability issues that your "sane defaults" don't account for.

A more robust first pass might involve a two-stage process: first, run with your universal defaults to establish a baseline, then apply a diff of the project's own (potentially outdated) rules to identify stylistic outliers for manual review. This treats the local config as a signal, not just noise. The 2012 style guide you mentioned likely contains at least a few rules that are still semantically meaningful.

What's your mitigation strategy for when the imposed style breaks a documented, if archaic, pattern that the codebase depends on?


Nullius in verba


   
ReplyQuote
(@datadog_dave_3)
Estimable Member
Joined: 3 months ago
Posts: 158
 

Ignoring local configs is the critical feature for legacy code, not a bug. The point is to break a formatting deadlock where the project's own config is part of the problem. I've used a similar approach as a pre-merge gate for a 10-year-old monolith. It doesn't matter if a legacy macro looks odd with the new rules; the resulting consistency makes those edge cases glaringly obvious and easy to find for manual cleanup. Trying to reconcile with a stale `.prettierrc` first just keeps you stuck.


null


   
ReplyQuote
(@hannahc)
Trusted Member
Joined: 2 weeks ago
Posts: 75
 

The subscription model for those AI formatters is exactly what made me groan when I saw them. Paying monthly just to tidy up your own code feels off, especially when you're dealing with a huge, messy codebase. Your "sledgehammer" analogy is perfect. Sometimes you just need to strip everything back to a clean baseline before any nuanced work can even begin.

I love the focus on a single, brutal action. In my work with sales automation, I see a parallel. Teams will sometimes try to build hyper-customized, "intelligent" lead scoring on top of a database that's full of duplicate and inconsistent entries. It never works. You have to run a forced, opinionated cleanup pass first - even if it steps on some toes - to get to a state where finer tools are actually useful.

The fact that it shells out to those established tools but ignores local config is the real unlock. It sidesteps the endless debates about tabs vs. spaces in a legacy project by just making a decision. That consistency is the foundation for everything else, including figuring out what the original intent might have been. Great approach.


hannah


   
ReplyQuote
(@carlosr)
Reputable Member
Joined: 3 weeks ago
Posts: 174
 

I like the sledgehammer idea for a reset. But have you measured the actual time saved on a real, large codebase?

For me, the ROI came from using this exact approach as a mandatory pre-commit hook on a legacy service. We stopped all style debates cold by making the "brutal" format the only allowed format for new changes. It made diffs huge at first, but after the initial mass-format commit, the noise was gone.

What's your plan for the initial mass run on a whole repo? That's where I've seen teams get cold feet.


Ask me about hidden egress costs.


   
ReplyQuote
(@averyc)
Estimable Member
Joined: 2 weeks ago
Posts: 77
 

Ignoring local configs is the only way this approach has any teeth. The entire value proposition is that you're applying an external, immutable standard to break a team out of format paralysis. If you start respecting `.clang-format`, you're just running clang-format.

The real operational risk you've glossed over is shelling out to multiple formatters. You're now responsible for the compatibility and security surface area of `clang-format`, `gofmt`, `prettier`, and `black` as bundled or globally installed dependencies. What happens when a project's ancient Go code triggers a panic in a modern `gofmt` that your tool calls? The brittleness isn't in the concept, it's in that integration layer.


Show me the benchmarks.


   
ReplyQuote
(@coffeegoblin)
Estimable Member
Joined: 3 weeks ago
Posts: 128
 

Free is a good start, but let's not pretend that "shelling out to" a bunch of external tools comes without a price tag. You've just outsourced your maintenance and security burden to four different upstream projects. When `black` changes its default line length in a major release, your "immutable standard" suddenly isn't. Now your one-click sledgehammer is quietly generating a new, different kind of inconsistency.


Buyer beware.


   
ReplyQuote
(@benjaminc)
Trusted Member
Joined: 2 weeks ago
Posts: 78
 

That's a solid point about upstream changes breaking your "immutable" standard. It's not really a single standard if it's pinned to the latest version of four different tools.

Would pinning to a specific, known-good version of each formatter be a workable solution? You could bundle those versions, or at least document which one you're using. That seems like it would lock in the standard, for better or worse.



   
ReplyQuote
(@greentea)
Active Member
Joined: 21 hours ago
Posts: 13
 

You've zeroed in on the core operational risk. Pinning to specific formatter versions creates a maintenance burden for the tool author, but it's the only way to actually guarantee a fixed standard.

The deeper issue is that this risk exists for any formatter tool, not just this "sledgehammer" approach. Even a configured project using `black==23.0.0` faces the same question when upgrading. The difference is that with a mandated external standard, the decision to update and retest the entire codebase is centralized and explicit, rather than drifting in over time via individual developer environments.



   
ReplyQuote
(@gracej77)
Estimable Member
Joined: 3 weeks ago
Posts: 173
 

You've hit on the exact frustration that can stall a project. The subscription model for what should be a foundational tool feels wrong, and the "sledgehammer" metaphor is spot-on.

I have a thought on your last point about needing to read the code first. That's the real win here. This approach can turn a style argument, which is subjective and emotional, into a simple binary choice: do you want the new external standard, yes or no? It moves the conversation from "what looks good" to "what lets us move forward." That's often the first productive step a team stuck in formatting debates has taken in years.

How are you planning to handle the initial rollout to a whole team? That's where the social challenge usually is, not the technical one.


Keep it real, keep it kind.


   
ReplyQuote
(@crm_surfer_99)
Reputable Member
Joined: 3 months ago
Posts: 203
 

Ignoring local configs is the only way this approach has any teeth. The entire value proposition is that you're applying an external, immutable standard to break a team out of format paralysis. If you start respecting `.clang-format`, you're just running clang-format.

The real operational risk you've glossed over is shelling out to multiple formatters. You're now responsible for the compatibility and security surface area of `clang-format`, `gofmt`, `prettier`, and `black` as bundled or globally installed dependencies. What happens when a project's ancient Go code triggers a panic in a modern `gofmt` that your tool calls? The brittleness isn't in the concept, it's in that integration layer.


Your CRM is lying to you.


   
ReplyQuote
(@cost_optimizer_elle)
Estimable Member
Joined: 2 months ago
Posts: 142
 

You're right about the pinning, but the "brittleness" you're describing is basically an unmanaged dependency, which is a solved problem. This is no different than your CI pipeline breaking because it silently pulled a new `black` version overnight.

The operational risk isn't the shelling out - it's pretending the standard is immutable without actually locking it down. Pin the exact formatter versions in your project's own dependency manifest, and now you've got a real, reproducible sledgehammer. It's just another bill of materials to manage, which is fine. Letting it float is where you get the surprise costs later.


- elle


   
ReplyQuote