Anatomy of email verification

email_verified_at, a timestamp. Laravel 5.7 came out this month with email verification built in, and this column is the first thing I noticed. A boolean would cost the same and answer less. A timestamp answers not only whether, but when, and when a support ticket arrives half a year later, “when” is the question. The tutorials say: implement MustVerifyEmail, put the verified middleware on routes, done. True, and boring. The interesting part is how the feature is put together. It is a small example of a cross-cutting feature done right. ...

September 18, 2018 · 2 min · Murat Useinov

Where the checkout logic goes

Validate input, reserve stock, create the order, charge the card, fire events. Five steps in one checkout action, and the fat model versus fat controller argument offers only two rooms for them. Both rooms are wrong. Put it all in the controller and you cannot run checkout from anywhere except HTTP. No console command, no queue job, no test without the kernel. Put it in the Order model and the model now knows about payments, stock and notifications, a strange set of friends for an Eloquent class. ...

August 13, 2018 · 2 min · Murat Useinov

Covering index and the price of SELECT *

Using index in the Extra column of EXPLAIN. That is the cheapest read MySQL can do, and you often get it almost for free. SELECT user_id, created_at FROM orders WHERE user_id = 42 ORDER BY created_at DESC LIMIT 20; With an index on (user_id, created_at) everything the query needs is in the index leaves. The table is never touched. A composite index finds rows fast, a covering index answers the query on its own. Postgres calls this Index Only Scan, with one condition: the visibility map must be fresh, so a table that vacuum never visits quietly falls back to heap fetches. ...

July 15, 2018 · 2 min · Murat Useinov

Messenger: in-process today, queue tomorrow

$bus->dispatch(new SendWelcomeEmail($user->getId())); and then, in the same request, a handler: class SendWelcomeEmailHandler { public function __invoke(SendWelcomeEmail $message) { // load user by id, send the email } } That is Messenger in Symfony 4.1, still marked experimental. By default everything is synchronous, so at first it is a function call with extra steps. The extra steps are for the transport. Change configuration, route this message class to AMQP, and the same handler runs in a worker process. The calling code does not change. Start synchronous, go async when you need it. I like this order much more than “install RabbitMQ on day one”. ...

June 19, 2018 · 2 min · Murat Useinov

GDPR: where the user actually lives

The row in users. Then orders, with the delivery address and phone. Then nginx access logs with emails inside GET parameters of an old unsubscribe endpoint. That is how far I got in the first ten minutes of drawing where one user’s data lives on one project, and the map did not fit on one page. May 25 is close and everyone discusses consent banners. The lawyers can have the banners. The engineering part is the right to erasure. “Delete the user” sounds like one DELETE statement until you sit down with a pen. ...

May 9, 2018 · 2 min · Murat Useinov

MySQL 8.0: finally, modern SQL

@row := @row + 1. I have a report in production that stands on that trick, and the trick was never guaranteed to work. Evaluation order of user variables in SELECT is undefined, it just happened to behave. MySQL 8.0 went GA last week, and for me the release is about SQL. Window functions and CTEs, the things Postgres people stopped noticing years ago, are here. The classic task: top three orders per customer. In 5.7 you had a self-join nobody could read a month later, or the variable trick. Now: ...

April 24, 2018 · 2 min · Murat Useinov

.env is not a secrets store

A .env file committed to git, “temporarily”. Database password, API keys, mailer credentials, all in one file. Symfony 4 moved configuration to environment variables, and this is the second project this month where I see the same thing. .env is a developer convenience. It exists so local setup does not require exporting fifteen variables by hand before running the app. That is the whole job of this file. .env.dist goes to git with placeholder values, .env stays in .gitignore with your local ones. This part is not negotiable. ...

March 14, 2018 · 2 min · Murat Useinov

Rector: refactoring by machine

Search for ->fetch( in a project with old Kohana code and count the hits. A method call on a model, a comment, a line in a test fixture, an unrelated class that happens to have a method with the same name. That is what regex refactoring looks like. Regex does not know a method call from a string literal. Rector does. A young tool I found this month: it parses PHP into an AST with nikic/php-parser, applies transformation rules, prints the code back. Rename a class across the whole project. Change a method call, add an argument everywhere. The AST sees that this fetch is called on that type and touches only those places. Mechanical change becomes exact. ...

February 8, 2018 · 2 min · Murat Useinov

Horizon, or the queue becomes visible

redis-cli llen queues:default and hope. That was my queue monitoring for years. Horizon replaces it with a real dashboard, and I did not know how much I needed one until I saw it. The mental shift matters more than the UI. dispatch() is the beginning of the work, not the end. The job still has to wait in Redis, run, maybe fail, maybe retry. All of that was invisible. Now it is on one screen: throughput, wait time per queue, failed jobs with the full payload and the exception. ...

January 20, 2018 · 2 min · Murat Useinov

Sodium in PHP 7.2 core

PHP 7.2 came out on the last day of November. Mcrypt is out of core, libsodium is in. That trade alone makes it a good release. Search any forum for “php encrypt” and you find the same folk recipe: openssl_encrypt with AES-256-CBC, an IV made from who knows what, no authentication of the ciphertext. Every choice in that recipe is a place to be wrong, and CBC without a MAC is wrong in a way that has published attacks. The developer is not careless. The API hands an application developer decisions that belong to a cryptographer. ...

December 10, 2017 · 2 min · Murat Useinov