Old code deserves a little respect, even when it is bad. It has been running in production for years and has already met all the strange inputs you have not thought of yet. Read it carefully before rewriting it, because the odd conditional in the middle is usually a scar from a real incident.
It helps to separate what you measured from what you concluded. We measured that the page took longer after the change. We concluded that the new query was responsible. Only the first of those was a fact, and it took an embarrassing amount of time to notice that the second one was wrong.
There is a version of this that uses a library, and for a larger team it might be the right call. We looked at it, read the changelog and counted the dependencies. For the handful of cases we actually have, thirty lines we understand beat three thousand we would have to trust.
The wrong theory
<?php
namespace App\Cache;
final class Related {
public function ids( int $post_id ): array {
$cached = get_post_meta( $post_id, '_related', true );
return is_array( $cached ) ? $cached : [];
}
}
Choosing boring technology is mostly about choosing where your surprises will come from. The database has been around for decades and its failure modes are written up in great detail. The newer thing may well be better, but its surprises will belong entirely to you, at a time of its choosing.
The first thing to do when something breaks is to stop guessing. Open the log, find the first line that looks wrong, and read it twice. Most of the time the message is telling you exactly what happened, and the only thing standing in the way is the theory you formed on the walk to the keyboard.
Naming turned out to matter more than the structure did. Once the function stopped being called process and started saying what it did, two of the three bugs in the surrounding code became obvious to everybody reading it, including the person who had written them, who was me.
The actual fix
--- a/inc/cache.php
+++ b/inc/cache.php
@@ -12,3 +12,3 @@
-$key = 'related_' . $id . '_' . $generation;
+$key = 'related_' . $id;
return get_transient( $key );
We now write a short note after every incident, and the rule is that it has to be useful to somebody who was asleep at the time. What happened, how we noticed, what we did and what we changed. Blame is not one of the headings, and it has never needed to be.
The fix itself took four lines. Finding out where those four lines belonged took most of a week, including one afternoon spent proving that the bug was not where everyone, including me, had been absolutely certain it was. That is a normal ratio, and it is worth telling new people about.
What surprised me was how much of the cost was in the waiting. The work itself was quick. The build took nine minutes, the review sat for a day and the deploy window was on Thursdays. Shaving a second off the code path would have been easy and would not have changed a thing.
What we changed afterwards
After that, the only thing left was to delete the workaround. This is the step that tends to get skipped, which is how a codebase ends up with fixes for bugs that stopped existing years ago. Put the removal in the same ticket, or accept that it will outlive everyone on the team.
Did you try this with a cold cache? We saw very different numbers on the first request.
We hit almost exactly this last spring. The part about the logs is painfully accurate.
Yes, and that was the moment we started measuring properly.
Bookmarked for the next time someone proposes rewriting it from scratch.
About forty minutes, batched, with nobody watching it.
We hit almost exactly this last spring. The part about the logs is painfully accurate.
Fair point. It depends a lot on team size.
Did you try this with a cold cache? We saw very different numbers on the first request.
I disagree about the library, but only because I have already paid the cost of learning it.
Reading this at 2am with the pager next to me. Very on brand.
Small correction: the default changed in a recent release, so check which version you are on.
Did you try this with a cold cache? We saw very different numbers on the first request.