alexeyzimarev/ddd-book

What if at least one picture is required to create a Classified Ad?

fourpastmidnight opened this issue · 3 comments

@alexeyzimarev

Suppose there was a new requirement added with respect to creating Classified Ads. The new requirement is that at least one picture must be uploaded at the time the Classified Ad is created. However, additional pictures can be added at a later time—so the original PictureAddedToClassifiedAd event remains.

What is the proper way to deal with this type of requirement?

One way I'm thinking this could be achieved is through the ClassifiedAdApplicationService. The Create command for a ClassifiedAd would be extended to include the initially required properties for a picture—a URI and a PictureSize. Then, the HandleCreate method would look something like:

private async Task HandleCreate(V1.Create c)
{
    var classifiedAdId = (ClassifiedAdId)c.Id;
    if (await _store.Exists<ClassefedAd, ClassifiedAdId>(classifiedAdId))
    {
        throw new InvalidOperationException(
            $"A classified ad with the id {c.Id} already exists.");
    }

    var classifiedAd = new ClassifiedAd(classifiedAdId, (UserId)c.OwnerId);

    // This is the new line to add the required initial picture:
    classifiedAd.AddPicture(c.PictureUri, c.PictureSize);

    await _store.Save<ClassifiedAd, ClassifiedAdId>(classifiedAd);
}

Given this is all handled intra-domain/bounded context, I don't think there's anything to be concerned about with respect to temporal coupling (especially when you start considering distributed systems and eventual consistency)? The only thing you'll need is a test to ensure that when a classified ad is created, two domain events are emitted:ClassifiedAdCreated and PictureAddedToClassifiedAd. Other than that, it appears that this is all happening in a single unit of work/transaction, correct?

I suppose this is nice, too, because if the handling of this requirement changes to allow any number of pictures to be initially uploaded (and note the pseudo-requirement I started with never restricted the number of initially uploaded pictures, only that at least one must be provided at the time of ad creation), this handler could be extended to handle an arbitrary number of pictures.

Is there anything I'm missing? Or are there perhaps better alternatives? (I know, the answer to almost any question is "it depends". But in your experience, how might you have handled a requirement like this?)

Hmm, thought of another way that this could be done: if the Create classified ad command is extended to contain a Uri and PictureSize for the required initial picture, then potentially the ClassifiedAd constructor could be used instead:

public ClassifiedAd(ClassifiedAdId id, UserId ownerId, Uri pictureUri, PictureSize size)
{
    ApplyChange(new ClassifiedAdCreated(
        id.Value,
        ClassifiedAdState.Inactive.Name,
        ownerId.Value)
    );

    AddPicture(pictureUri, size);
}

This accomplishes the same thing, but keeps it all in a single call while creating the object. I suppose to allow uploads of more than one picture during classified ad creation you could instead provide a constructor parameter which takes an array of Tuple<Uri, PictureSize> or some such similar construct:

public ClassifiedAd(
    ClassifiedAdId id,
    UserId ownerId,
    params (Uri uri, PictureSize size) pictures)
{
    ApplyChange(new ClassifiedAdCreated(
        id.Value,
        ClassifiedAdState.Inactive.Name,
        ownerId.Value)
    );

    foreach (var picture in pictures)
    {
        AddPicture(picture.uri, picture.size);
    }
}

I ended up using the constructor approach. It offered other advantages like being able to test that when a Classified Ad was created, that at least one picture was also added at the same time. It would seem to me based on my research that there's nothing wrong with a single command resulting in 2 events being emitted. Using the constructor hepled to encapsulate the orchestration instead of relying on developers to "remember" to also add a picture when creating a Classified Ad.

It would be weird for this particular domain to require anything for creating an ad. It is totally possible to prevent an ad from being published if it has no images. It's already done with the title and the description, so adding a check for the pictures count should be trivial.