← Tech talks & essays

ORIGINAL ESSAY / SYSTEMS AND PEOPLE

How to Write a Good Symfony Project (That Will Still Make Sense in 5 Years).

DAN RADU DRAGOMIR / NORAMARTH

Most Symfony projects don’t collapse because of performance.

They collapse because of entropy.

After working on long-lived systems, I’ve settled on a few structural principles that dramatically improve clarity, maintainability, and correctness.

This is not about trendy architecture patterns.

It’s about controlled complexity.

---

1️⃣ Structure First. Patterns Later.

Forget DDD, Hexagonal, Onion, or whatever geometry is fashionable this year.

Start with a structure that makes navigation predictable:

include/  → Definitions (contracts, DTOs, enums, constants)
lib/      → Reusable logic (framework-agnostic)
src/      → Symfony runtime integration (controllers, services, adapters)

Rules:

  • include depends on nothing.
  • lib depends only on include.
  • src depends on both.

When someone opens the project, they should instantly know where to look.

Architecture should reduce cognitive load, not increase it.

---

2️⃣ DTO First. DTO Last.

Golden rule:

  • DTO first for request
  • DTO last for response

Every request should:

  • Be mapped to a DTO
  • Be normalized
  • Be validated
  • Be rejected early if invalid

All of this should happen before business logic runs.

If something reaches your controller, it should already be valid and usable.

Controllers should effectively look like:

RequestDTO → Service → ResponseDTO

No raw request parsing. No scattered validation. No defensive programming inside business logic.

Invalid data should never reach the core.

---

3️⃣ Use the Symfony Request/Response Pipeline Properly

If something affects most endpoints (headers, correlation IDs, error shaping, caching policies, security headers, etc.), don’t inject it everywhere.

Use:

  • Event listeners
  • Value resolvers
  • Kernel hooks

Apply cross-cutting concerns at the edges, not via dependency chains.

Add clear exclusion rules where needed (health routes, profiler, internal endpoints).

The framework already gives you a pipeline. Use it.

---

4️⃣ Use Attributes (Symfony ≥ 7.3)

Keep configuration close to code:

  • Routing via attributes
  • Doctrine mapping via attributes
  • Event listeners via attributes
  • Message handlers via attributes

Configuration files should describe environment, not wiring.

This keeps intent local to the class and prevents configuration sprawl.

---

5️⃣ Never Let Invalid Data Reach Business Logic

Validation belongs at the boundary.

Business services should never need to ask:

  • “Is this null?”
  • “Is this field valid?”
  • “Did the client send something weird?”

If they do, your pipeline is leaking.

When boundaries are enforced properly, business logic becomes smaller, clearer, and more deterministic.

---

6️⃣ Accept the Micro-Overhead

DTO hydration and validation add a small processing cost.

But they massively increase:

  • Predictability
  • Testability
  • Refactor safety
  • Long-term maintainability

In real systems, correctness beats shaving microseconds off request plumbing.

Bugs cost more than DTOs.

---

7️⃣ This Doesn’t Break Clean Code. It Enforces It.

This approach naturally reinforces SOLID principles:

Single Responsibility Controllers adapt transport. Services execute business logic. Listeners handle cross-cutting concerns. DTOs represent structured data.

Open/Closed Cross-cutting behavior is added via listeners, not by modifying every controller.

Liskov Substitution Clear contracts in include/ make substitution predictable.

Interface Segregation Small focused contracts prevent bloated services.

Dependency Inversion Business logic depends on contracts, not framework internals.

This isn’t “more architecture.”

It’s clearer boundaries.

---

Final Thought

A good Symfony project isn’t defined by how many patterns it uses.

It’s defined by:

  • Clear structure
  • Clean boundaries
  • Predictable data flow
  • Minimal cognitive friction

Clean architecture is not about layers.

It’s about protecting your core from chaos.

PUBLICATION / PROVENANCE

Originally published on LinkedIn ↗. The full text is hosted here.

END OF ESSAY / ORIGINAL WORKBACK TO TECH TALKS & ESSAYS ↑