Symfony gives PHP teams an unusually solid foundation: dependency injection, clear service boundaries, mature tooling. Yet we regularly audit Symfony codebases that have become slow to change and risky to deploy. The framework is rarely the problem. The architecture that grew inside it is.
How good Symfony codebases go bad
Large PHP applications degrade in recognizable stages. Controllers accumulate business logic. Services grow God-like, holding twenty dependencies. Doctrine entities become the API of the whole system, so schema changes ripple everywhere. Eventually nobody changes anything without fear, and delivery slows to a crawl.
None of this happens because engineers are careless. It happens because there is no structure above the framework — no explicit answer to “where does this logic belong?”
What keeps large codebases changeable
Boundaries by business capability
Organize code by what it does — checkout, catalog, pricing, fulfillment — not by technical type (controllers, services, repositories). When code is grouped by capability, the impact radius of a change becomes visible, and teams can own areas instead of layers.
Keep the domain out of the framework
Business rules that live in framework-independent classes can be tested in milliseconds and survive framework upgrades untouched. Controllers and event subscribers should orchestrate, not decide.
Constrain the object graph
A service with fifteen dependencies is not one service — it is five services wearing a trench coat. Dependency counts are a cheap, objective smell worth enforcing in code review.
Make deprecation a habit
Codebases rot fastest where old and new approaches coexist indefinitely. Pick conventions, mark the old way deprecated, and migrate opportunistically. Static analysis (PHPStan at a strict level) turns these conventions into enforced rules instead of tribal knowledge.
Takeaway
Maintainability is not cleanliness for its own sake — it is delivery speed three years from now. The teams that stay fast are the ones that treat structure as an ongoing engineering concern, not a one-time setup.





