DDD, CQRS - Identity service and user avatar (image) handling

Viewed 31

I'm designing an Identity Service using DDD and CQRS pattern. So far I have one aggregate User that has all the logic for changing user's state (creating, resetting password, confirming email, etc.). In my understanding, user's avatar is also part of his identity and should be handled in the context.

I've decided that such small pictures can be saved directly to the database, but I'm not sure how to design it inside the domain (or whether it should belong to the domain at all).

Avatar could in fact be modelled as an Entity and referenced in User aggregate by its ID, like that:

public class Avatar: Entity<AvatarId>
{
    AvatarId Id { get; } // Strongly typed ID
    byte[] Picture { get; private set; }
    AvatarExtension Extension { get; private set; } // Enumeration: JPG, PNG, GIF, etc.

    public void ChangePicture(byte[] newPicture, AvatarExtension newExtension)
    {
        // Ommited parameters validation for brevity
        Picture = newPicture;
        Extension = newExtension;
    }
}
public class User: IAggregateRoot, Entity<UserId>
{
    ...
    AvatarId AvatarId { get; } //Avatar referenced by ID

    public void SetAvatar(AvatarId avatarId)
    {
        AvatarId = avatarId;
    }
}

I'm afraid it leaks some infrastructure concerns, Avatar seems more like a table definition in EF Core (code-first). In addition, Avatar would require to has its own repository, because it has to be handled separately (added to DdContext etc. before creating User), but this is not an aggregate root and my gut feeling is that it shouldn't be. Maybe referencing Avatar directly as an object in User and keeping it as one-to-one relationship would be a good idea?

1 Answers

The purpose of an aggregate (especially in CQRS) is validating commands, so the only state in an aggregate should be that for which there exists a command which would be rejected (resp. accepted) but would be accepted (resp. rejected) if the state changed.

It's hard to see how the bytes of an avatar would affect whether a future command against a user is accepted or rejected. That a user has an avatar? Sure, but that doesn't depend on the content of the avatar (a reference, e.g. a URL, to the avatar would suffice). That no two users can have the same avatar? That's not something the user aggregate modeling a single user can enforce (setting aside what exactly is meant by "no two can have the same avatar").

Related