Sep 06, 2026Containerizing Someone Else's Application
Seattle Collisions is a data explorer for collision records: a Laravel API, a Vue frontend, MySQL underneath. I did not write it. I made it deployable.
That distinction matters more than it sounds like it should, and it is the reason I find this kind of work worth talking about. Greenfield projects let you make every decision. Inherited ones make you live inside decisions you would have made differently, and the discipline that requires is a different skill from the one interviews usually test.
What "it works on my machine" actually meant
The application ran. It ran in one place, on one laptop, with a database whose state was the product of a year of undocumented manual steps.
That is not a criticism of whoever built it. It is the normal end state of a project that was solving a problem rather than building infrastructure. The cost only becomes visible when someone new tries to run it, or when the laptop dies.
The specific symptom: no reliable way to get from a fresh checkout to a working local environment. Which means no way to onboard anyone, and no way to deploy with confidence, because you could not reproduce the thing you were deploying.
What I actually did
Docker Compose across three services: Laravel API, Vue frontend, MySQL, on an internal bridge network, with environment configuration extracted from the assumptions it had been living in.
GitHub Actions to build the images, so the artifact that gets deployed is the artifact that got tested, rather than a directory someone rsynced.
A DigitalOcean droplet with nginx on the host for TLS termination and reverse proxying, Certbot for Let's Encrypt with automatic renewal via a systemd timer. Backend and database sit on the same droplet on Docker's internal network: near-zero database latency, versus a managed database service that would have cost more for a project of this size and added a network hop for no benefit.
Documentation for the local workflow, so the next contributor runs one command.
That last one is the deliverable. Everything else is in service of it.
The part I want to talk about
Halfway through, I had opinions. Structural ones. There were patterns I would have chosen differently, a data layer I would have organised another way, frontend state I would have restructured.
I did not touch any of it.
Not because I was being deferential, but because the job was reproducibility, and every refactor I made would have been a change I could not attribute a failure to. If the containerized version behaves differently from the original, I need that to be because of containerization, not because I improved something along the way.
Scope discipline is easy to say and hard to hold when you are inside a codebase every day. The temptation is not laziness, it is the opposite: you can see the improvement, it would take twenty minutes, and it is right there. The times I have caused the most trouble in my career have been the times I was confident I was helping.
Boring, and worth it
There is a category of engineering work that produces nothing a user can see: making existing software reproducible, deployable and possible for someone else to pick up. It does not demo. It is what the difference looks like between software that survives its author's interest and software that does not.
The application does the same thing it did before. It just does it anywhere now, for anyone, without a laptop being involved.