I refused to replace the stack that already runs the business.
Rewriting feels like progress but it is often noise
The app looks old. It runs on PHP 7.4, deploys with a shell script called deploy.sh, and keeps timestamps in a flat file for the last successful deploy. That catalog of imperfections made people call for a rewrite. I checked the obvious things: service uptime, job failures, and payment success logs. None of them showed systemic failure. Rewriting would improve the repository tree and let us use newer helpers, but it would also add a high-risk migration of user identifiers, additional dependencies, and weeks of regression testing.
I do not romanticize legacy code. I judge it by blast radius: what changes when a deploy fails. The current stack has many ugly files and a few critical ones. The right move was not to refactor everything. It was to make the critical surface smaller and harder to touch.
I audited the operations, not the architecture diagrams
Before saying no I listed concrete operational checks. I pulled the last 90 days of syslog for the web tier. I opened the cron logs under /var/log/cron and inspected the failures there. I ran a restore from the latest nightly dump into a staging instance and exercised the payment flow against sandbox credentials. I performed a dry-run deploy of deploy.sh to staging and watched the side effects: file permissions, database migrations, and cache invalidation.
I also measured the code-change surface. Three files are responsible for checkout validation. Two shell scripts coordinate nightly jobs. One table stores pricing rules referenced by the front-end. Because the surface was small, I could propose narrow guardrails instead of a full rewrite.
What I inspected
Steps I walked before refusing the rewrite
- Logs System and application logs for recent errors and patterns
- Backups Restore latest nightly to staging and verify workflows
- Deploy Dry-run deploy to staging and observe side effects
- Surface Count files, scripts, and tables touching the payment flow
The small fixes that kept risk low
I did cheap, targeted work. I shortened a deploy timeout in deploy.sh, removed a failing curl retry that hung for minutes, and added strict ownership and permission checks for uploaded files. I added a concise rollback hook: if migration X fails, restore the last dump and revert the feature flag. None of this touched business logic. That was the point.
I also tightened operational visibility. I added an alert for replica lag that sends a message to the on-call channel and requires an on-call acknowledgement. I scheduled a weekly restore-to-staging to keep backups tested. Those are guardrails: they let the business keep shipping while keeping the blast radius small.
Guardrails after refusing a rewrite
In the work
- Short rollback in deploy script
- Nightly backup restore tested on staging
- Alert on replica lag with on-call acknowledgement
- Ownership declared for three key files
Outside it
- Switching framework
- Refactoring payment logic
- Migrating user identifier formats
- Large data migrations without rehearsal
The final test is simple: can I make a safe change tomorrow? If I can push a small security patch and see it in production within the normal deploy window, the refusal stays. If I cannot, I reopen the question and plan the controlled migration with the guardrails I tested.
