Live data from Hacker News

Ratchets in software development (2021)

qntm.org

11–20 of 43 posts

Re: Ratchets in software development (2021)

#11
Love it! …but of course I’d worry about a diff that added one offense while removing another, leaving the net sum the same. Perhaps the author handles this? You want to alert on the former and praise on the latter, not have them cancel out through a simple sum. Admittedly it’s a rare sounding edge case.

The more trad technique for this would be to mark the offending line with # noqa or # ignore: foo. Another way is to have a .fooignore file but those are usually for paths or path globs to ignore.

I like the author’s idea[1] of having the “ignore” mechanism next to the linter codebase itself, rather than mixed in with the production codebase. Adding the files and line numbers for known-offenders to that code could be a useful alternative to a simple sum?

Perhaps more robustly, some kind of XPath like AST syntax to indicate which parts of the codebase have the known problem? It feels just as fragile and could quickly get over complicated.

At the end of the day an online comment has always done it for me. With Python, Meta’s libcst is an excellent and fast way to get an AST that includes comments. It’s the most robust tool I’ve found but you can just use built-in ast.py and ad-hoc file:line parsing too.

https://github.com/Instagram/LibCST

[1] Sorry to be a fanboi but Antimemetics is amazing!

https://qntm.org/fiction

Re: Ratchets in software development (2021)

#12

I’ve never understood why linters don’t have this baked in. You want to deprecate a pattern, but marking it as an error and failing the build won’t work. So you mark it warning and fill everyone’s editors with yellow lines. And then we just get used to the noisy warnings. Ratchet is such a good word for it.

I’ve been wondering about that, too. FlakeHeaven / FlakeHell does that for Python, but it’s the only example I can think of: https://flakeheaven.readthedocs.io/en/latest/commands/baseli...

Re: Ratchets in software development (2021)

#13

Ratchet is a good name/pattern. It is also grandfathering. It is similar to how code coverage can be done. Old coverage may be low e.g. 40%, but may require 80% coverage on new lines, and over time coverage goes up. I wonder if there has ever been a sneaky situation where someone wanted to use forbiddenFunction() really bad, so they remove the call elsewhere and tidy that up, so they could start using it.

One would hope code reviews could pick up these deceptions, but then again they would spot the use of forbidden functions too albeit much later in the dev cycle than is optimal. Breaking the build early is a solid idea, before it's even committed to source control. No different to applying PMD, CPD, Checkstyle, eslint, yamllint, other linters, but with a custom rule. I really want to use this pattern, there's semi-deprecated code in so many codebases.

For more control and to close that loophole, it could be possible to put annotations/comments in the code to `/* ignore this line */` in the same way that eslint does? Or have a config that lists how many uses in each file, instead of one-per-project?? There's always refinements, but I'm sure that for many projects the simplicity of one counter is more than enough, unless you have devious developers.

Re: Ratchets in software development (2021)

#15

I’ve never understood why linters don’t have this baked in. You want to deprecate a pattern, but marking it as an error and failing the build won’t work. So you mark it warning and fill everyone’s editors with yellow lines. And then we just get used to the noisy warnings. Ratchet is such a good word for it.

the more recent term i’ve heard is “bulk suppression” eg https://eslint.org/blog/2025/04/introducing-bulk-suppression...

Re: Ratchets in software development (2021)

#16
I built a ratchet system for ESLint originally that we’ve extended it to work with TypeScript, Terraform, and Biome linters.

integrating with each linger is complex but it pays dividends - it’s so handy to be able to write a new lint rule or introduce an off-the-shelf rule without needing to fix all existing violations.

We maintain allowed error counts on a file-by-file basis which makes it easier for developers to understand where they added the new violation.

blog post: https://www.notion.com/blog/how-we-evolved-our-code-notions-...

Re: Ratchets in software development (2021)

#17
post #5

Interesting, props for coming up with a good name. But it's weird to me to call this a "ratchet", and not just a custom lint rule. Since it sounds exactly like a lint rule. The hard-coded count also sounds a bit like something that I would find annoying to maintain in the long run and it might be hard to get a feeling for whether or not the needle is moving in the right direction. - esp. when the count goes down and…

yeah that’s the way we do it at Notion. it’s important to store the allowed violation count in a file type that makes merges easy; we use TSV rather than JSON because dealing with commas and delimiters during merge conflict is super annoying and confusing.

right now we have one huge ratchet.json.tsv file with all violations but it’s getting pretty ungainly now that it’s >1mb length.

Re: Ratchets in software development (2021)

#18
post #13

Ratchet is a good name/pattern. It is also grandfathering. It is similar to how code coverage can be done. Old coverage may be low e.g. 40%, but may require 80% coverage on new lines, and over time coverage goes up. I wonder if there has ever been a sneaky situation where someone wanted to use forbiddenFunction() really bad, so they remove the call elsewhere and tidy that up, so they could start using it.

One would hope code reviews could pick up these deceptions, but then again they would spot the use of forbidden functions too albeit much later in the dev cycle than is optimal. Breaking the build early is a solid idea, before it's even committed to source control. No different to applying PMD, CPD, Checkstyle, eslint, yamllint, other linters, but with a custom rule. I really want to use this pattern, there's semi-de…

if you have eslint you might as well just write custom rules and get actual syntax aware linting rather than relying on more brittle regex rules. claude et al are very good at getting a lint rule started, with a bit of setup you can make testing lint rules easy. we have a zillion custom rules at notion, most are pretty targeted “forbid deprecated method X besides circumstance Y” kind of things

Re: Ratchets in software development (2021)

#19

I’ve never understood why linters don’t have this baked in. You want to deprecate a pattern, but marking it as an error and failing the build won’t work. So you mark it warning and fill everyone’s editors with yellow lines. And then we just get used to the noisy warnings. Ratchet is such a good word for it.

Rubocop allows generation of a TODO file, which is basically an extra config file that you include in the main one and that contains current violations per cop+file and sets appropriate values to cops that have numerical limits.

From there on you can only go one direction.

OP's ratchet would simply be a new custom cop that matches a string, and the whole ignore existing violations would Just Work (and actually "better" since one wouldn't be able to move the pattern around)

Re: Ratchets in software development (2021)

#20
I like the idea of ratchets, but the implementation needs to be good for them to work nicely.

> If it counts too few, it also raises an error, this time congratulating you and prompting you to lower the expected number.

This is a pain and I hate that part. It's one of the things that isn't even a big deal, but it's regularly annoying. It makes leaving things in simpler than removing them - the good act gets punished.

One way to make this better is to compare the count against the last merge base with the main branch. No need to commit anymore. Alternatively you can cache the counts for each commit externally, but that requires infra.

Post reply on HN