Giter VIP home page Giter VIP logo

Comments (5)

webdevilopers avatar webdevilopers commented on July 17, 2024

Similar to the questions asked here:

With an example of the red book by @VaughnVernon:

    public Discussion startDiscussionFor(
            ForumIdentityService aForumIdentityService,
            Author anAuthor,
            String aSubject,
            String anExclusiveOwner) {

        if (this.isClosed()) {
            throw new IllegalStateException("Forum is closed.");
        }

        Discussion discussion =
                new Discussion(
                    this.tenant(),
                    this.forumId(),
                    aForumIdentityService.nextDiscussionId(),
                    anAuthor,
                    aSubject,
                    anExclusiveOwner);

        return discussion;
}

from php-ddd.

yourwebmaker avatar yourwebmaker commented on July 17, 2024

Nice topic... I have a few questions tho:

In a future solution, we would create a separate microservice and make them event-driven.

Why? Are they not part of the same bounded context?

`DeploymentRejected" event or similar.

It is not a constraint?

Regardless your answers, that's how I see your problem being solved so far:

<?php
namespace Webdevilopers\Employment
{
    class EmploymentContract
    {
        private EmploymentPeriod $employmentPeriod;

        public function deployTo(Workplace $workplace, DeploymentPeriod $deploymentPeriod) : Deployment
        {
            if (!$deploymentPeriod->isInside($this->employmentPeriod)) {
                throw new \InvalidArgumentException('DeploymentPeriod must be inside the EmploymentPeriod.');
            }

            //... In case Deployment is part of the same context, just return
            //return new Deployment($workplace, $deploymentPeriod);

            //... In case Deployment is part or another context (Microservice) send and event
            //$this->record(new DeploymentCreatedEvent())
        }
    }

    class EmploymentPeriod{}

    class Workplace{}

    class DeploymentPeriod
    {
        public function isInside(EmploymentPeriod $employmentPeriod) : bool
        {
            return true; //or false
        }
    }

    class Deployment
    {
        public function __construct(Workplace $workplace, DeploymentPeriod $deploymentPeriod) {}
    }

    class UseCase // Application
    {
        public function handleSameContext(DeployEmployeeCommand $command) : void
        {
            $contract = $this->contractRepository->get($command->contractId);
            $workPlace = $this->workplaceRepository->get($command->workplaceId);
            $deployment = $contract->deployTo($workPlace, new DeploymentPeriod($command->from, $command->to));

            $this->deploymentRepository->save($deployment);
        }


        public function handleMicroservice(DeployEmployeeCommand $command) : void
        {
            $contract = $this->contractRepository->get($command->contractId);
            $workPlace = $this->workplaceRepository->get($command->workplaceId);
            $contract->deployTo($workPlace, new DeploymentPeriod($command->from, $command->to));

            $this->contractRepository->save($contract);
        }
    }
}

from php-ddd.

webdevilopers avatar webdevilopers commented on July 17, 2024

Thank you so much for this detailled feedback @yourwebmaker. It almost feels like playing poker and you read my hand because the code suggestion is very close to the current solution.

Why? Are they not part of the same bounded context?

I guess this is an important point. And I think I often miss it. "Deployment" is a subdomain, just like "Contracting". But yes, I really think they belong together in a single bounded context.

return new Deployment($workplace, $deploymentPeriod);

Should become:

return new Deployment($contractId, $workplace, $deploymentPeriod);

I guess my greatest fear is that another developer could use this method to create an "invalid" Deployment e.g. inside a migration console command. The invariants may be protected. But there is no guarantee that the period was checked against an EmploymentPeriod. But does it matter really?

I often tend to force the developer pass an interface e.g. EmploymentContractReadModel to the Deployment constructor - then there is no way around it.
But it feels strange and maybe that is over-complication.

Another approach I'm playing with is making the Deployment become a collection of value objects inside EmploymentContract. There will only be few deployments per contract. No performance issues here.

But as mentioned this feels strange since I think they belond to different subdomains. On the other hand - remember all the "Order & order lines" examples out there... sigh

from php-ddd.

yourwebmaker avatar yourwebmaker commented on July 17, 2024

e.g. inside a migration console command

IMHO migrations should not be aware of domain objects. But this is totally out of the scope of this discussion.

If they belong on the same context, just use the returning/factory and persist it inside the command handler. Aggregates generating new aggregates is not an issue.

And keep in mind: All models are wrong, some are useful. Yours seem to be really useful for me.

I understood, it's testable, it's simple. So just go for it. In case it does not work later, refactor to something better. It's part of DDD process to try out models.

from php-ddd.

webdevilopers avatar webdevilopers commented on July 17, 2024

At the bottom line what we devs do is offering other devs a single-point-of-entrance via command handler and a factory (method) to create the aggregate.

But we don't have to ensure that he skips using our "guidance" and possible spanning business-rules by directly creating the aggregate?

We deliver "useful" tools and hope they use them correctly.

from php-ddd.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.