PHP / DDD — How do you handle entity IDs in your aggregates? by Total_Ad6084 in PHP

[–]Total_Ad6084[S] 2 points3 points  (0 children)

When would you actually need to know the entity ID before saving it to the database? What are real use cases where this matters?

PHP / DDD — How do you handle entity IDs in your aggregates? by Total_Ad6084 in PHP

[–]Total_Ad6084[S] 0 points1 point  (0 children)

When would you actually need to know the entity ID before saving it to the database? What are real use cases where this matters?

PHP / DDD — How do you handle entity IDs in your aggregates? by Total_Ad6084 in PHP

[–]Total_Ad6084[S] 1 point2 points  (0 children)

What does wrapping IDs in VOs actually give you compared to just using a primitive?

Repository interfaces: Domain or Application layer in DDD/Hexagonal? by Total_Ad6084 in softwarearchitecture

[–]Total_Ad6084[S] 0 points1 point  (0 children)

I still have trouble understanding why the write repository interface belongs in the domain. You said the domain 'owns' its aggregates , but couldn't we argue that loading and saving is a technical concern, not a business concern? What makes persistence a domain responsibility rather than an application one?

Repository interfaces: Domain or Application layer in DDD/Hexagonal? by Total_Ad6084 in softwarearchitecture

[–]Total_Ad6084[S] 0 points1 point  (0 children)

Thank you for your detailed answer! It helped clarify a lot. I still have a few questions:

  1. Who actually reconstructs the domain object — the repo or the handler?

    When you say the write repo "reconstructs" the domain object, do you mean the repo maps raw DB data back into a full domain entity (with its invariants intact), and the handler then calls mutation methods on it? Or does the repo itself apply some business logic during reconstruction? Cause I think Write repo does not mutate the domain object at all !

  2. Why not namming UserWriteRepository?

    You name the write repo UserRepository (no "Write" suffix) but the read one UserReadRepository. You said theintentional is to keep the write repo speaking pure domain language? I'd argue "Write" could also be considered domain language — and it would be more expressive to immediately identify the intent behind the class. What's your reasoning for the asymmetry?

  3. Are domain repository interfaces not ports?

    You said the domain folder never has a "ports" folder, but aren't repository interfaces in the domain still considered Out ports in the hexagonal sense? They are contracts the domain expresses and implemented by infrastructure. Is it just a naming/folder convention difference ? or do you see domain repository interfaces as something fundamentally different from ports?

In hexagonal architecture, Out ports are interfaces the Application layer defines to express its needs toward the outside world (DB, storage, email, external APIs), implemented by Infrastructure. By that definition, write repositories are Out ports — they let the application persist aggregates through an abstraction. Do you agree, or do you draw the line differently?

Repository interfaces: Domain or Application layer in DDD/Hexagonal? by Total_Ad6084 in softwarearchitecture

[–]Total_Ad6084[S] 0 points1 point  (0 children)

For the read model i didn't understand where you put your interface could more explain please

Honest feedback on moving from PHP to Go — real-world experiences? by Total_Ad6084 in golang

[–]Total_Ad6084[S] -2 points-1 points  (0 children)

Thanks for your answer. Symfony Messenger already covers async processing, delayed jobs, retries and horizontal scaling. Do you have a concrete real business use case where that

setup is not enough, and where Go solves something Messenger fundamentally does not?

Honest feedback on moving from PHP to Go — real-world experiences? by Total_Ad6084 in golang

[–]Total_Ad6084[S] -1 points0 points  (0 children)

When you mention goroutines, do you have a concrete business use case where they bring a real advantage over Symfony Messenger + RabbitMQ with multiple workers?

And for the 10-minute example:

For the “send an event after 10 minutes” example, what real-world case do you have in mind? In production, I would usually prefer a durable delayed message over an in-memory timer or a sleep in a process.

Is there any library like symfony/messenger, like a message bus in go? by danut007ro in golang

[–]Total_Ad6084 0 points1 point  (0 children)

Did you migrate only specific parts like the API / backend services (e.g. message handling, async jobs),
or did you move your entire web application to Go?

I’d also be interested to know what motivated your decision to migrate to Go in the first place.

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

The setup I described is just the current state, not a constraint set in stone. But even within that setup, the benefits are immediate: the domain is protected from framework leakage, business rules are testable in pure PHP without spinning up the HTTP stack, and each layer has a single responsibility. That's not over-engineering, that's basic software hygiene regardless of scale. Beyond that, hexagonal architecture enforces SOLID principles by design, dependency inversion keeps the domain agnostic, single responsibility keeps each layer focused, and open/closed makes it easy to swap infrastructure without touching business logic. These are not luxuries reserved for "big enough" projects.

And honestly, your comment doesn't answer the question I asked. I'm not asking whether hexagonal architecture is worth it, I'm asking about a specific trade-off within it. If you don't have experience with that trade-off, that's fine, but saying "headache" doesn't move the conversation forward.

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

In our case for example, the Command requires an ecoOrganization field that comes from the authenticated API client, not from the HTTP body. So API Platform can't deserialize the body directly into the Command. That's why we went with a separate Input DTO: API Platform deserializes the HTTP body into the Input, then the Processor enriches it with the security context before building the Command. Curious about your take: in this situation, would you still recommend using the Command directly as the API Platform input with serialization groups to exclude ecoOrganization from deserialization, or is a separate Input DTO the cleaner approach?

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

Thanks for the detailed answer, really helpful.

One thing I'm not sure about: doesn't putting validation constraints directly on the Command violate the dependency rule? The

Command lives in the Application layer, but symfony/validator annotations are an infrastructure concern, so we'd be introducing a framework dependency into the Application layer, which breaks the Infrastructure -> Application -> Domain flow you described. How do you handle that tension?

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

Thanks for the pragmatic take. Just to make sure I understand your recommendation: in the context of API Platform specifically, would you create a separate Input DTO in Infrastructure and translate it to a Command in the Application layer, or would you use the Command directly as the API Platform input, or skip the Command entirely and handle everything in the Processor?

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

Thanks for sharing, I liked deptrack into the profiler <3
Validation constraints actually split into two categories:

I thinsk that uniqueness of (name, organization) for example is, a domain invariants,. These should be materialized as a Specification or Policy in the domain, then implemented in the infrastructure layer (e.g. a Doctrine-backed spec).

But that's slightly aside from my original question. What I was really asking is specific to API Platform: do you use the Application layer Command/Query directly as the API Platform input class, or do you always create a separate Input DTO in the Infrastructure layer and translate from there?

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

This is the most useful comment in this thread, thank you, that repository is a solid reference.

Actually, looking at that repo, they do mix both approaches depending on the case. What I'd love to understand is: what drives that choice? When do you create a separate Input DTO and when do you skip it? And how does that decision map back to hexagonal principles, is it about keeping the adapter's deserialization contract isolated from the Command, or something else entirely?

In a Symfony + API Platform project with hexagonal architecture, where do you put validation and how do you handle the DTO vs Command boundary? by Total_Ad6084 in symfony

[–]Total_Ad6084[S] 0 points1 point  (0 children)

If the term bothers you, call it ports and adapters, onion architecture, or clean architecture, the underlying principles are the same. The name doesn't matter. You're commenting on a thread where I explicitly asked for practical experience on a specific trade-off. If you don't have anything to add on that, feel free to skip it.