Building Meaningful Audit Trail in your System

I have seen two primary approaches to building a audit trails for systems – entity level audits and property level audits.

Entity level audit maintains an audit log for every entity and makes an audit entry for ‘any’ operation done on these entities. Weather there is a change in one property of the entity or the entire entity changes as part of an operation that affects a bunch of other entities in the same transaction. At database level, this is often implemented using triggers that would copy the row being changed to an audit table along with some audit information.

Property level audit, on the other hand, goes to a different extreme and makes an audit entry every time any property on any entities changes. At database level this often translates into one big fat table which keeps track of any field in any table that has changed along with some general audit information.

Whiles these are two widely adopted implementation approaches for performing system audits, what both of these approaches fail to capture is the actual intent of the user. The granularity at which the system captures the audit data has an impedance mismatch with the business and it can get difficult to tell what actually was done to system to create this audit entry. Hence, these audit data would have a very limited business meaning and use.

Think about a modelling strategy where the actual operations that can be performed on the system are expressed explicitly. Wouldn’t it be a lot easier to just record these operations or the fact that these operations got performed on the system? This kind of audit data would have the granularity that would make sense to the business and creating a business meaningful audit reports out of such audit logs would be a lot easier. Isn’t it?

Advertisements

Implementing Repository in DDD – Part 1

Implementing Repository is fairly staright forward in DDD. There are generally two styles of implementation,
1. aggregate-dedicated repository and
2. generic repository.

An aggregate-dedicated repository will have a method per command or query; while, Generic repository will have a standard interface for every Aggregate. However, in both cases, the repository is suppose to operate at the aggregate-root level. This post will demostrate implementation of an aggregate-dedicated repository,

In your domain layer,
public class Order: IAggregateRoot
{
public Order(IOrderRepository repository)
{ ..}

public void Order(PlaceOrderCommand command)
{
..
repository.Add(this);
}
public Order Get(Guid id)
{
return repository.Single(id);
}

public IList<Order> GetOrdersByCustomer(Guid customerId)
{
return repository.Where(o=>o.CustomerId = customerId);
}
}

Application Layer,

public class OrderService
{
public void PlaceOrder(PlaceOrderCommand command)
{
this.Transaction();
var Order = new Order(new OrderRepository());
Order.PlaceOrder(command);
this.CompleteTransaction();
}
}

The Application Layer uses dependency injection to inject an instance of the repository that the aggregate uses. The aggregate-root then calls the repository internally to persists the data and retrieve data.

In this style of implementation, a dedicated repository designed for each aggregate-root. This means a little more coding up-front compared to generic repositories, as there is one repository per aggregate. Writing unit-tests might be a little more difficult. But over all, the simplicity and flexibility that this implementation brings is huge and depending on your taste, choice of tech-stacks and data-access needs it might be a very good fit for you. Definitely worth a consideration.