The AI stack layers are not the same size

Ten-layer diagrams of the AI stack are accurate and slightly misleading, because they draw every layer the same size. Building a compliance agent that now handles most of our cases end to end, the first four took a couple of weeks. The rest took the year. Embeddings, a vector store, retrieval, a model. That’s the demo, and it demos well enough that people start asking about a rollout date. Then the actual work starts. ...

September 17, 2026 · 2 min · Murat Useinov

Kafka is not a task queue

Kafka, RabbitMQ and SQS all move messages between services, which is why teams argue about them as if it’s a preference. It isn’t. They differ on one structural question: who owns the record of what has been read. Kafka keeps the log, you keep your place in it. Messages aren’t consumed, they’re retained for a window and every consumer tracks its own offset. That’s what makes replay possible: a new service can start from last Tuesday and rebuild its state from events that already happened, and an analytics consumer falling behind doesn’t affect the recommendation consumer at all. You pay for that with operational weight and with partitions, because ordering is per partition and your partition key quietly becomes a design decision you’ll live with. ...

September 11, 2026 · 2 min · Murat Useinov

Nine patterns, and where the complexity goes

Nine distributed systems patterns, written the way they actually get decided: what you buy, and where the complexity goes. Because none of these remove complexity. They relocate it. Replication. Multiple copies, one writer. You buy availability and read throughput. You now own replication lag, and the ticket from a user who saved something and didn’t see it on refresh. Sharding. Split the data across databases. You buy headroom. You now own a shard key that you chose at the exact moment you knew least about your traffic. ...

September 4, 2026 · 2 min · Murat Useinov

A single server and a database is enough here

Ten years ago a system design conversation was short. A server, a monolith, Postgres, maybe a load balancer in front. For most products that was the entire architecture, and it held. Now the same conversation opens with API gateways and doesn’t stop: Kubernetes, service meshes, Kafka, Redis, three databases because each one is good at one thing, gRPC, GraphQL, Elasticsearch, Terraform, Prometheus, tracing, sharding, replication, autoscaling. The awkward part is that none of it is junk. Every one of those tools exists because someone hit a real wall: more users, more data, more teams, more regions, more nines of uptime. ...

August 26, 2026 · 1 min · Murat Useinov

Reading PHP 8.6 RFCs as constraints

Accepted, declined, discussion drama. That is how most posts about PHP 8.6 RFCs read, and the vote cycle is in full swing this month. I read RFCs for a different reason. Not “what do I get”, but “what will my current code look like next year”. One RFC is a feature. Ten RFCs are a direction. When several push the same way, toward stricter types, explicit declarations, deprecating some old freedom, the direction tells you which of your habits are becoming legacy while you still type them. Syntax sugar is the least interesting part. Deprecations are the most interesting, because every deprecation is a migration with a countdown attached. ...

August 17, 2026 · 2 min · Murat Useinov

A worker is not a controller

All the logic inside execute(), exit code always zero, no lifecycle thinking at all. A controller without a request. I still see this console command in every second codebase. Symfony stopped being only an HTTP framework a long time ago, but habits are slower than releases, and with 8.1 giving console and workers first-class attention the excuse is gone. An HTTP request lives for milliseconds. The kernel builds services, handles, throws everything away. A worker lives for hours. Same container, very different lifecycle. Every service that quietly keeps state, an in-memory cache, an accumulating buffer, an entity manager full of tracked objects, is invisible in HTTP and becomes a memory leak in a worker. If your consumer needs a nightly restart by cron, this is where the night went. ...

May 25, 2026 · 2 min · Murat Useinov

An LLM call is just IO

One method, response back. Laravel 13 makes calling a model feel like calling a mailer, and the demo level is now twenty minutes of work. Which is exactly when architecture starts to matter, because everybody will ship the demo. An LLM call is IO. Slow IO, expensive IO, IO that sometimes fails and sometimes lies. We know how to handle IO like that. We forget, because the response text looks smart and the API looks native to the framework. ...

March 11, 2026 · 2 min · Murat Useinov

From Kohana to PHP 8.5

A Kohana ORM, an N+1 on a catalog page, and a blog post about it. That was November 2014. It is December 2025, the code around me runs PHP 8.5, and I went back and read that first post. The surface changed completely. A 2014 controller was a fat method: it read the request, validated by hand, called the ORM, formatted the response, sometimes sent an email on the way out. Types lived in docblocks and in hope. Deploy was files over FTP and a prayer. Today the same feature is a typed handler with constructor injection, validation at the boundary, a use case object, a message on a queue for the email, a trace id through the whole thing. The engine checks what a comment used to promise. I do not miss the old way. ...

December 11, 2025 · 2 min · Murat Useinov

Observability has a budget

Last year we turned tracing on everywhere. This year the telemetry invoice is a line item a manager asks about by name. The dashboards did not get more useful. More data, same confusion at 2 a.m. Time to design instead of collect. The design starts from the questions I actually ask when the pager goes off. In practice there are four: is the latency of key endpoints normal, did the error rate jump, how far behind are the queues, is the database saturated. That is the core set. Metrics for these must be cheap, always on, with alerts. Everything else can be sampled traces I pull up on demand. ...

March 10, 2025 · 2 min · Murat Useinov

PHP 8.4 after the hype

A private field, a getter, a setter with one line of normalization. Three members for one idea, repeated through every entity folder I have ever opened. PHP 8.4 is two months old, the conference demos are done, and the honest question is which features earn a place in a working codebase. My filter is simple. A feature is good when it deletes code. Property hooks pass: class User { public string $email { set => strtolower(trim($value)); } } The class is shorter and the normalization cannot be bypassed. But keep hooks boring. A hook that talks to the database is a magic getter from 2008 in new syntax. ...

January 15, 2025 · 2 min · Murat Useinov