Blog Logo

Complex Software is an Occupational Health Hazard!

!Complex Software is an Occupational Health Hazard! # Whaally.Domain [![NuGet Badge](]( The goal of the `Whaally.Domain` library is to simplify the development of highly-scalable domain models. The way this library attempts to solve this problem is by providing a framework dictating what components exist and how they may interact with one another. The terminology for these components had largely been inspired by the language used by DDD practitioners, as well as the practices used by those working with event-sourcing techniques. As such this framework defines how to build the following technical components: - Aggregates - Services - Sagas - Commands - Events This library assumes you provide the behaviour for these components. By adhering to a common behavioural pattern this library is able to provide common behaviour integrating this behaviour with the infrastructure required to run it. The end result is an approach wherein we can focus on the development of business behaviour, without worrying about the integration of infrastructure. ## Example usage The implementation of a simple aggregate looks like this: ### Aggregate First were defining the aggregate which should hold the information. This can be anything, as long as it implements the `IAggregate` interface. ```csharp public record User( string FirstName, string LastName): IAggregate; ``` ### Events To make a change, we should have an event to reflect the change. This event again can be anything, as long as it implements the `IEvent` interface. ```csharp public record NameChanged( string FirstName, string LastName) : IEvent; ``` To know how this event should be applied to our aggregate, were creating an aggregate handler to deal with this. The `IAggregateHandler` interface defines the behaviour contract we must fulfill. The event handler returns the new state of the aggregate. ```csharp public class NameChangedHandler : IEventHandler { public User Apply(IeventHandlerContext context, NameChanged @event) => context.Aggregate with { FirstName = @event.FirstName, LastName = @event.LastName }; } ``` ### Commands Given we cannot (or should not) directly apply events to the aggregate, a command is necessary. The pattern to do so is simmilar to the way events and event handlers are constructed: ```csharp public record ChangeName( string FirstName, string LastName) : ICommand; ``` The event handler for a command looks like this. Even though an event handler may access the information contained by the aggregate, it cannot change it. The return type of an aggregate is therefore a result object indicating the success state of the operation. ```csharp public class ChangeNameHandler : ICommandHandler { public IResultBase Evaluate(ICommandHandlerContext context, ChangeName command) { context.StageEvent( new NameChanged( command.FirstName, command.LastName )); return Result.Ok(); } } ``` ### Services To implement more complex behaviour within the domain which either requires coordination across multiple aggregates, or requires the integration of external services, we should build a service. The general pattern is again similar to the way events and commands are built. ```csharp public record MassRename() : IServ