1

I'd like to expand on this question When to update audit fields? DDD.

In my domain model, and this may not be the right place for it, but we have property for CreatedBy and ModifiedBy, both of type User, both value objects.

I am new to DDD and confused on which layer is responsible for updating these properties ... Data? Domain? or Application?

In the question, linked above, they mention using an event to update these properties ... the assumption would be then that these fields are updatable on the Domain?

Here is an example of my class ...

public class SpritePalette
{
    private readonly SpritePaletteColors _colors;

    public string Id { get; private set; }
    public string Name { get; private set; }
    public SpritePaletteColors Colors { get { return _colors; } }
    public bool IsPublic { get; private set; }
    public User CreatedBy { get; private set; }
    public DateTime CreatedDate { get; private set; }
    public User ModifiedBy { get; private set; }
    public DateTime ModifiedDate { get; private set; }

    public SpritePalette(
        string name)
    {
        this.Name = name;
        this.IsPublic = false;

        _colors = new SpritePaletteColors();
    }

    internal void UpdateId(string value)
    {
        Validate.IsNotEmpty(value, "Id is required.");

        this.Id = value;
    }

    public void UpdateName(string value)
    {
        this.Name = value;
    }   

    public void MarkAsCreated(User value)
    {
        this.CreatedBy = value;
        this.CreatedDate = DateTime.UtcNow;
    }

    public void MarkAsModified(User value)
    {
        this.ModifiedBy = value;
        this.ModifiedDate = DateTime.UtcNow;
    }

    public bool HasColor(string color)
    {
        return _colors.HasColor(color);
    }

    public void AddColor(string color)
    {
        _colors.AddColor(color);
    }

    public void RemoveColor(string color)
    {
        _colors.RemoveColor(color);
    }

    public void UpdateIsPublic(bool value)
    {
        this.IsPublic = value;
    }
}

I employee two methods, one for marking the model as created, which updates the CreatedBy and the CreatedDate, and a similar method for marking the model as modified.

Is this acceptable, when it comes to DDD? What is the better way to handle updating audit properties like these? Is there a better way, i.e., using events?

I admit this is a bit subjective, but would appreciate any help anyone can offer!

Community
  • 1
  • 1
mattruma
  • 16,589
  • 32
  • 107
  • 171

2 Answers2

1

Solutions with the "framework"

A. expose each constructor and command method with extra parameters. Like:

public SpritePalette(
    string name, User user)
{
    this.Name = name;
    this.IsPublic = false;

    _colors = new SpritePaletteColors();
    createdBy(user)
}

public void UpdateName(string value, User user)
{
    this.Name = value;
    modifiedBy(user);
}

internal void modifiedBy(User value)
{
    this.CreatedBy = value;
    this.CreatedDate = DateTime.UtcNow;
}

In this case, each time application layer manipulates the domain model, the audit fields are updated. But this may looks cubersome when the application layers invokes several command methods like:

//application layer
public void update(String name, String description, ....other attributes,User user) [
    //retrieve SpritePalette
    SpritePalette.updateName(name, user);
    SpritePalette.updateDescription(description, user);//passes user again
    //other command methods invocation   //passes user again & again
}

B. expose an extra audit fields update method.

Like:

 //application layer
public void update(String name, String description, ....other attributes,User user) [
    //retrieve SpritePalette
    SpritePalette.updateName(name);
    SpritePalette.updateDescription(description);
    //other command methods invocation   
    SpritePalette.modifiedBy(user);
}

But I'm afraid sometimes we may forget to invoke this modifiedBy() method.

Solutions without the "framework"

Maybe we should use another sets of models. What if we model the update behaviors as events? The core domain doesn't need the audit fields. Audit fields are usually needed by query requirement like "I want to see who modifies the thing".

Let's split them:

class UpdateNameEvent {
    string SpritePaletteId;
    string name;
    User user;
    Date when;
}

class SpritePalette{
    on(UpdateNameEvent event) {
         this.Name = event.name();//no user involved
    }
}

 //application layer
public void update(String name, User user) [
    //retrieve SpritePalette
    var event = new UpdateNameEvent(name, user);
    SpritePalette.on();
    //other command methods invocation   
    events.save(event); //save the events
    repository.update(SpritePalette);
}

public List<SpritePaletteEvent> list(string id) {
    return events.list(id);
}
Yugang Zhou
  • 7,123
  • 6
  • 32
  • 60
1

In the question you linked above, CreatedBy and UpdatedBy are part of the domain layer, since in the actual domain meetings are in fact scheduled by someone.

In your setting (Sprites) it seems unlikely that CreatedBy and UpdatedBy are really part of the underlying graphics domain. Hence the CreatedBy/UpdatedBy properties are for bookkeeping/auditing only and therefore a pure application level concern and they should be handled on the application level only. In Java, you'd typically update these flags by some Interceptor, but I'm not sure how you can do this in C#. Maybe it's possible to update these fields in the repository (by letting the application register the current user in the unit of work or similar).

Alexander Langer
  • 2,883
  • 16
  • 18