#Tooling

Nonces on Cached Pages

We now write a short note after every incident, and the rule is that it has to be useful to...
author
Tomasz Reyes
category
"Tooling"
reading
"3 min"
nonces-on-cached-pages.md

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.

Performance work is mostly subtraction. Before reaching for a clever technique, find out what the page is doing that nobody asked it to do. We have never yet profiled something without finding a piece of work that could simply be removed, and removal has the best cost profile of anything.

Nobody reads the documentation until something is on fire, so write it for that reader. Put the command they need at the top. Say what it changes and how to undo it. Leave the history of how we got here for a later section, where it can be appreciated at leisure.

What it cost

<?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 : [];
	}
}

The browser is already very good at most of this. A surprising share of the script we removed was reimplementing things a plain link, a form or a details element will do for free, with better keyboard support and without the bugs we had carefully written ourselves.

Write the failing case down before you change anything. It can be a test, a curl command or a sentence in the ticket. The point is that you have something outside your own head that says what wrong looks like, because your memory of the bug starts drifting the moment you begin working on it.

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.

Things that did not help

--- a/inc/cache.php
+++ b/inc/cache.php
@@ -12,3 +12,3 @@
-$key = 'related_' . $id . '_' . $generation;
+$key = 'related_' . $id;
 return get_transient( $key );

Staging will lie to you, gently and often. It has less data, less traffic and a much more forgiving network. Treat a clean run there as a sign the change is not obviously broken, and keep watching the real thing for a while after it ships, with one hand near the rollback.

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.

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.

The actual fix

The review comment that stuck with me was a question: what happens if this runs twice? It had not occurred to me, and the answer was unpleasant. Since then I ask it of every job, webhook and migration I touch, and it has been worth more than any tool I have installed.

7 comments on “Nonces on Cached Pages”

Leave a Reply

Your email address will not be published. Required fields are marked *