DEV Community

TiltedLunar123
TiltedLunar123

Posted on

If your tool deletes 20,000 things, the interesting code is not the deleting

The first version of my Gmail cleanup extension was about forty lines. Find the messages matching a query, then delete them one at a time. It demoed beautifully on a test account with a couple hundred messages in it.

Then I pointed it at a real inbox with nineteen thousand old promotions in it, and learned that the deleting was never the hard part.

A cleanup run is a batch job wearing a button

That reframe fixed most of my design problems. One click on the front, but behind it sits a job that runs for minutes against data somebody actually cares about in an environment that can vanish at any moment for reasons having nothing to do with your code. Tabs get closed. Laptops sleep. Wi-Fi drops.

So where does your progress live? If the answer is a variable in that tab, all of it dies with the tab. The user is left holding a partly-cleaned mailbox with no idea how far it got, and no way to find out. Which is a genuinely bad afternoon when the thing being partly-processed is their mail.

So progress has to be written down as it happens, not held in memory and saved at the end. That one change drags a lot of other decisions with it.

Every step has to be safe to run twice

Once progress is durable you can resume, and resuming means steps get repeated. A crash lands somewhere in the middle of a batch. You cannot always tell whether the last call actually went through, though.

So deleting something that is already deleted has to be a quiet no-op rather than an error that halts the whole run, and the same goes for a message the user happened to move by hand while the job was still going. The run should shrug and continue.

Nothing clever there. It is just the thing you skip when you are writing the forty-line version.

The preview has to be the real code

Dry-Run mode was originally going to be its own little function that counted matches. That was a mistake and I caught it early, thankfully.

If the preview has its own copy of the matching logic, the preview lies. Not always. Eventually, and specifically on the edge cases where you most needed the truth. A preview is only worth something if it is the exact same selection code, with the destructive call switched off at the end.

That is also why the extension ships three modes rather than one. Dry-Run shows what a rule would take and touches nothing. Review lets you approve first. Live just runs. Same path through the code, three different endings.

Write the log for the user, not for yourself

"Deleted 12,431 messages" is a developer's log line. It tells the person who wrote the code that the loop finished.

For the actual human at 11pm it answers nothing they care about. What did that rule match, and can I take it back? So the recovery log keeps the last twenty runs and the restore is one click. Building that took longer than the deletion feature did, and it is the part I would keep if I could only keep one.

Default to leaving things alone

The last one is less about engineering and more about nerve. What should happen to a message the rules are unsure about? Nothing at all.

Starred, important, and unread mail gets skipped automatically, because those are the three signals people already use to mean "this one matters" without ever thinking of it as a protect list. A whitelist covers the senders that rule cannot guess.

The general version: when a tool operates in bulk on data it did not create, the correct default is timid. Users can always widen the net. They cannot always undo.

None of this made the extension faster. It is honestly a little slower than the naive version, and it asks more questions along the way. What all that caution buys is the nerve to press the button in the first place, which turns out to be the feature people were missing.

The extension is Bulk Delete Gmail Emails - Gmail One-Click Cleaner if you want to look at how it ended up.

Top comments (0)