The expensive architecture decision is usually a rewrite that nobody needed. A shop that already takes orders on WordPress does not become safer because the homepage moves to a newer framework. A product that is mostly an API and a board does not become clearer because I forced it into the same theme as the shop. I pick the stack that already holds the behaviour, and I keep the boundary sharp enough that one person can still see across it.
Stay where the business already lives
If the revenue is a WooCommerce checkout, the work belongs next to that checkout: the theme, the plugins I actually trust, the server, the mail, the backups. Moving the catalogue into a separate frontend so the stack looks current is a project. It is not, by itself, a fix for a promo code or a missed webhook. I have more patience for a plain PHP change that ships this week than for a migration whose payoff is aesthetic.
Laravel earns its place when the thing is an application with its own rules, its own queues, its own admin, and it should not be bent into pages. A content pipeline with a spend cap and a human approval step is that kind of application. A marketing site is not.
| The system already is | I reach for | I do not reach for |
|---|---|---|
| A shop taking orders | WordPress, WooCommerce, the server around them | A rewrite so the homepage can be a different framework |
| An application with queues and an admin | Laravel, or Nest if the rest of that product is already TypeScript | A pile of plugins pretending to be a product |
| A typed interface shared by a board and an API | TypeScript, end to end | A second language just for the buttons |
| Retrieval, scoring, a small service over documents | Python | The shop’s PHP runtime, out of loyalty |
One language across a product, not across a career
Inside one product I want one main language, so a change in the API and a change in the screen are the same review. Across my work I do not pretend everything is one language. PHP, TypeScript and Python are all in production here, on purpose. The mistake is mixing them inside a single request path because each layer was someone’s preference.
PostgreSQL when the data has relationships and I want the database to enforce them. MySQL when that is what the shop already runs and moving it is not the task. Redis for a queue or a cache, not as a second source of truth. Docker and a boring nginx when the deploy needs to be described, not when I feel like learning an orchestrator.
A rewrite has to name the incident it removes
I ask for one sentence before a new framework is allowed into the plan. Which incident, which the current stack cannot close, goes away because of the move? If the sentence is about taste, recruiting, or a conference talk, the move waits. If the sentence is “the checkout plugin cannot express this pricing rule, and I have patched around it twice”, that is a real sentence, and then I still look for a smaller patch before a new storefront. The smaller patch is usually there.
The same test applies to a service I am tempted to add beside the shop. A queue is justified when a request must survive a retry. A separate frontend is justified when two clients, not one developer, need the same API. A new database is almost never justified in the same quarter as a reliability problem. The data you already have is the system. Moving it is a project of its own, with its own inventory, and it does not fix the promo code.
I can hold a shop and a side service because they meet at a documented edge: a webhook, a queue, a table. I cannot hold a system whose edges are “ask the person who built that part”. That person has to be me, including after launch. So a new tool has to pay rent. If it does not remove a handoff or a class of incident, it is taste, and taste can wait.
Choose the stack that keeps the next incident inside one head. Novelty has to beat that, not the other way around.
