Tired of looking for errors in log files? Use OneTrueError - Automated exception management in .NET.

Writing decoupled and scalable applications

Preface

This article is the first in a series of three articles. It’s purpose is only to introduce you do domain events and commands. The next article will show you how you with almost no effort (thanks to Griffin.Decoupled) can get started the command/event type of applications. The series will end with and article showing how you can use the DDD domain model together with the command and event handling.

Introduction

When we start our profession as developers we complete applications really fast. We giggle a bit for ourselves and look at the older programmers which just finished half of the application in the same time. Our applications look good and works great. But in fact they are just lipstick on a pig:

The problems doesn’t surface until you have to start maintaining the application. You change the code in one place and suddenly a new bug appears in another. This is one of the most common problems when developing applications. The problem is really that you have high coupling between your classes. It might be because of leaky abstractions or violated layer boundaries. It’s a menace.

Another typical problem is that we have to hard code the application flow as a fixed sequence:

public void Register(email, string userName, string password)
{
	// 1. create
	var user = _repository.Create(email, userName, password);
	
	// 2. notify user
	var email = new MailMessage("support@nosystem.com", email, "Account created", "Welcome DUUUDE!");
	var client = new SmtpClient(); //configured in app.config
	client.Send(email);
	
	// 3. Notify admin
	var email = new MailMessage("support@nosystem.com", "admin@nosystem.com", "Account created", "User registered");
	client.Send(email);
}

Which will force us to make changes that will affect the entire sequence.

Consider the following: Days goes by and you’ve now got a new requirement: The customer wants to audit all new users. To be able to do that we have to modify that code above. Changing the code breaks the Open/Closed principle (one of the SOLID ones). Why is that? Because every code change is a potential new bug. No modifications also means that we do not have to test it either. No changes = No new bugs .(a bit simplified, but anyhow..)

To avoid changes we need some way to act upon actions/events.

Enter domain events

Domain events are one of the answers to our prayers.

Great TV-Series, too bad they killed it.

Domain events are concept which I’ve borrowed (shamelessly stolen) from domain driven design. A domain event is a change (which is most often) driven by a user. It can be when a user login, when an administration locks a user account or when a user posted a new forum reply.

Events are named like UserRegistered, ReplyPosted or OrderPayed. Events should be defined in a way that the average client would understand it. An event named OrderUpdated is far to broad and doesn’t really say antyhing (compare with OrderPayed, ItemAddedToOrder or OrderPaymentMethodChanged).

As you’ve might have figured out the domain events should always be named in past tense (it’s just part of the best practice). Let’s define a small event:

public class ReplyPosted : DomainEventBase
{
	public ReplyPosted(string threadId, int postedById, string comment)
	{
		ThreadId = threadId;
		PostedById = postedById;
		Comment = comment;
	}
	
	public string ThreadId { get; private set; }
	public string PostedById { get; private set; }
	public string Comment { get; private set; }
}

Notice that we always use IDs instead of entities/objects in the domain events. We also keep the number of properties at a minimum. Only include information which is important to identify the entities in question and the information that describes the change in the system.

Keeping the events lightweight makes them less likely to change in the future. Trust me, you do not want to have to change all your event subscribers when your application has grown. Compare that ReplyPosted event with a OrderUpdated event and the amount of information that it would have had to contain (and the amount of logic that all subscribers would have had to have).

Let’s examine how the previous code snipped would like like when we are using domain events:

public void Register(email, string userName, string password)
{
	var user = _repository.Create(email, userName, password);
	
	// publish the event, the method is implementation specific
	DomainEvent.Publish(new UserRegistered(user.Id));
}

The event is simple enough

public class UserRegistered : DomainEventBase
{
	public UserRegistered(int userId)
	{
		if (userId < 1) throw new ArgumentOutOfRangeException("userId", userId, "Specify a valid user id");
		
		UserId = userId;
	}
	
	public int UserId { get; private set; }
}

Our event is lean enough and will be published for us. Now we only need to act upon that event. That’s done with the help of subscribers. Let’s create two (to handle the code in the original method).

public class WelcomeEmailSender : ISubscribeOn<UserRegistered> //read it as "I Subscribe On UserRegistered"
{
	public void Handle(UserRegistered domainEvent)
	{
		var email = new MailMessage("support@nosystem.com", email, "Account created", "Welcome DUUUDE!");
		var client = new SmtpClient(); //configured in app.config
		client.Send(email);	
	}
}

public class UserRegisteredEmailSender : ISubscribeOn<UserRegistered>
{
	public void Handle(UserRegistered domainEvent)
	{
		var email = new MailMessage("support@nosystem.com", "admin@nosystem.com", "Account created", "User registered");
		var client = new SmtpClient(); //configured in app.config
		client.Send(email);	
	}
}

You should always create a new class for every handler. It keeps them lightweight and easier to read/maintain. If you are using an IoC container you can also inject dependencies into them.

Let’s also add support for the new client requirement: To be able to audit new users.

public class AuditNewUsers : ISubscribeOn<UserRegistered>
{
	IForbiddenWordsRepository _repository;
	IUserRepository _userRepository;
	
	public AuditNewUsers(IForbiddenWordsRepository repository, IUserRepository userRepository)
	{
		_repository = repository;
		_userRepository = userRepository;
	}
	
	public void Handle(UserRegistered domainEvent)
	{
		var user = userRepository.Get(domainEvent.UserId);
		if (_repository.Exists(user.UserName))
		{
			var email = new MailMessage("support@nosystem.com", "audit@nosystem.com", "Action required", "You might want to inspect user #" + user.Id);
			var client = new SmtpClient(); //configured in app.config
			client.Send(email);	
		}
	}
}

As you see we only had to create a new event.

I hope that you’ve got the grasp of domain events and how they help you to write more decoupled applications.

Command me, sire!

With the introduction of domain events we’ve got smaller classes which is more SOLID. It also means that we’ve captured the essence of what the user inteded to do (the use case) by moving out all non essential actions to event handlers. That’s a good start. But we can decouple our architecture even further.

Be a commando, take command over your commands!

A traditional layered application looks like this (may or may not be using multiple tiers):

That design is great since it’s very easy to follow what happens and when. The problem is that the service classes tend to get fat and changed often. And as you might know by now, every change of existing code is an potential bug. The solution for this is to retire those service classes and instead introduce commands.

Task based UIs vs CRUD UIs

But before we get into commands we’ll have a prerequisite that we have to fullfill: Our UIs must be task based.

A typical CRUD based UI looks something like this:

CRUD based UI

CRUD applications is often data centric. That is our application is modeled from the database perspective. We just create UIs to allow the user to edit everything. That problem with that is that there is not really a way to validate that the correct combination of fields are properly validated.

Task based applications is user centric. The tasks is not something that you make up by yourself but something which is defined by your client. They are most often corresponding to a use case/story.

The corresponding task based UI looks like:

task based UI

The change is really that we define a set of actions that the user can take. Each of these actions are defined by your client. Your client probably don’t say “I want to be able to edit all fields” but more likely “I want to be able to assign a case to a user”. So you got a task named AssignCaseToUser. That my dear ladies and gentleman is a command.

With this approach it’s much easier to validate the information since we have a specific action. For instance, it doesn’t make sense to change the title when assigning a task. So we can exclude that field from the action. Also, we know that we should always update the AssignedAt field. Hence we do not expose that field but just update it ourself.

What is a command

A command is a use case, not a database operation or something technical. The command is what the user (your client) want to achieve. That also means that you should not try to write/design commands for reuse. That will come back and haunt you every night. Design a command to do what the user wants. Nothing more and nothing less.

RegisterUser, AssignTask, LockForum is use case driven commands while UpdateUserTable is more of an operation (and should really be part of an command).

This distinction is important if we want to be able to refactor or scale our systems. The distinction makes our commands agnostic of the actual implementation.

Commands are always in a valid state

A command should always make sure that it’s information is valid. You’ll probably seen commands that looks like this:

public class DelegateTask
{
	public int TaskId { get; set; }
	public int UserId { get; set; }
}

The problem with that is that the command will fail if one of the fields are not specified. Always validate the information when it’s assigned and not later.

We should use the following convention:

  1. Mandatory fields should be specified in the constructor, the setters should be private.
  2. Optional fields should have get/set, but the setters should validate the contents

Command validation vs UI validation

Command validation do not replace view model validation or similar. The command validation is used to increase the chance of success when the command is actually executed while the UI validation is used to make sure that the user entered all information correctly (and instantly give the user feedback).

The difference is subtle but important. When you enter information into the command you’ll probably already validated it once.

The UI validation might be done by a different team/developer than the command validation (or by the same developer but in different time periods). It’s therefore important that the validation is made in both places so that we catch any changes early (instead of getting failing commands).

Commands do not return anything

Commands should not return anything. EVER!.

This is probably the hardest thing with commands to get used to. Today we are so used to giving the user feedback directly. And that isn’t really possible with commands since they will be executed in a near future (and not directly).

Here is a solution for most common problems:

Need to act upon the generated ID

Switch to Guids.

Guids gives you worse performance when looking up information in the database. But they are implementation agnostic and can safely be generated by the code.

There are however GUIDs (not really guids if we should be anal, but similar enough) that gives you better performance. Google “sequential guids”. Many database engines have similar GUIDs.

Act upon the generated domain event instead

We got our domain events now, right? Use them to handle additional processing if possible.

Need to present the result to the user

Trick the user

You got all the information already. Just update the UI with it. For instance stackoverflow.com uses this approach. The command will most likely have been processed by our system when the user updates the page.

Distract the user

Show the user a “Thank you so bloody much for the extra work, we’ll save it into our systems !ASAP”. (Being a developer you’ll now that we meant “not as soon as possible”, but the user think that we’ve mistyped. That’s what I call a win-win situation).

That page/message will give our system a chance to process the command before the user do something else.

Command vs handler

In my own implementation I’ve decided to split the command request from it’s processing. The command classes are in a strict sense just DTOs. They are used to carry the information to the actual handler. I find this acceptable since the command dispatcher will throw an exception if there are no handler. (The distributed version will generate errors when the host can’t find a handler.)

Commands vs services

Let’s compare commands to the services. Services are most often just facades for a root aggregates (Order, User etc). The services will therefore most often be a lot larger than the corresponding commands, which in turn reduce readability (it’s not as easy to get a grip over what a services does). A command is more refactor friendly since we can move sub actions into own methods (usually avoided in services since it’s hard to tell what each method is used by). The service is also a more prone to bugs since it wraps all operations for a root aggregate (and it’s children). Changing one method may affect another one (and therefore also affect all usages).

MvcController (or whatever you’re using) will likely use one or more services. If we are using services in a controller we got the dependencies upon the whole service classes. Any change in the service can affect one/more of the controller methods. If we are using commands, each controller method has a dependency on a single command. Hence changing the command handler will only affect a single controller method.

The code

The customer have moved to a new place. Thus we need to change the delivery address:

public class ChangeDeliveryAddress
{
	public ChangeDeliveryAddress(int userId, string street, string zipCode, string city)
	{
		if (userId < 1) throw new ArgumentOutOfRangeException("userId", userId, "Specify a valid user id");
		if (string.IsNullOrEmpty(street))
			throw new ArgumentException("street", "Street must be specified");
		if (string.IsNullOrEmpty(zipCode))
			throw new ArgumentException("zipCode", "ZipCode must be specified");
		if (string.IsNullOrEmpty(city))
			throw new ArgumentException("city", "City must be specified");
			
		//assignment here
	}
	
	public string UserId { get; private set; }
	public string Street { get; private set; }
	public string ZipCode { get; private set; }
	public string City { get; private set; }
	
	// State may be null
	public string State 
	{ 
		get; set;
	}
}

That was only the command request. We also need something that handles the command.

public class ChangeDeliveryAddressHandler : IHandleCommand<ChangeDeliveryAddress> //"I Handle Command ChangeDeliveryAddress"
{
	IUserRepository _repository;
	
	public ChangeDeliveryAddressHandler(IUserRepository repository)
	{
		_repository = repository;
	}
	
	public void Invoke(ChangeDeliveryAddress command)
	{
		var user = _repository.Get(command.UserId);
		user.ZipCode = command.zipCode;
		// [...]
		
		DomainEvent.Publish(new DeliveryAddressChanged(user.Id, /* and all changed fields */));
	}
}

Do note that the command in this case is just a data source wrapper. That may not be in the future. The important thing today is that the event is generated and we can therefore act upon the command in a decoupled way.

What belongs in the command?

Now that we got domain events and commands there is still an issue to address. And that’s what belongs in the command or in an domain event handler.

The answer is that it’s quite easy to solve. Ask your client. For instance: “Should we abort the user registration if the welcome email can’t be sent? Or is it enough if we notify your support department so that they can contact the new user?”.

Everything which is not fatal in a usecase / userstory should be placed in domain event handlers.

Handling customer feedback

We’ll have to have a new way to interact with the users, since we should treat all commands as some asynchronous handlers which won’t give us a result back. The easiest way to do that is to introduce a notification system. Simply create a new database table where all notifications are stored. Read it every time a new page is displayed.

The notification system should of course be a command and a domain event too. If you’re writing a native client you can simply subscribe to the NotificationCreated event to be able to display it to the user.

Let me entertain you

To entertain you a bit, here is a command handler of mine (from my upcoming web startup). It subscribes on some domain events to capture the entire task delegation flow in the same place.

Look at the subscribed events and think of when they happens. When you get it you’ll understand that the logic handles several different application flows. So it’s more complex than it looks ;)

(Note that the domain events are published from within the domain models since I try to follow Domain Driven Design)

public class RequestTaskDelegationHandler : 
	IHandleCommand<RequestTaskDelegation>, 
	ISubscribeOn<InvitationAccepted>, 
	ISubscribeOn<FriendRequestAccepted>, 
	ISubscribeOn<FriendRequestRejected>
{
	private readonly ITodoItemStorage _todoItemStorage;
	private readonly IUserStorage _userStorage;
	private readonly IFriendDataStore _friendDataStore;
	private readonly ICommandDispatcher _commandDispatcher;

	public RequestTaskDelegationHandler(ITodoItemStorage todoItemStorage, IUserStorage userStorage, IFriendDataStore friendDataStore, ICommandDispatcher commandDispatcher)
	{
		_todoItemStorage = todoItemStorage;
		_userStorage = userStorage;
		_friendDataStore = friendDataStore;
		_commandDispatcher = commandDispatcher;
	}

	public void Invoke(RequestTaskDelegation command)
	{
		var item = _todoItemStorage.Load(command.TaskId);
		var delegatedBy = _userStorage.Load(command.DelegatedFromUserId);
		var delegateTo = command.DelegateTo.Contains("@") //userIds do not contain @
					   ? _userStorage.LoadByEmail(command.DelegateTo)
					   : _userStorage.Load(command.DelegateTo);

		var isNotFriend = delegateTo == null || !_friendDataStore.IsFriend(command.DelegatedFromUserId, delegateTo.Id);
		if (isNotFriend)
		{
			item.RequestDelegationToInvited(delegatedBy, delegateTo != null ? delegateTo.Email : command.DelegateTo);
			MakeFriendsAndThenDelegate(command, delegateTo);
			return;
		}


		item.RequestDelegationTo(delegatedBy, delegateTo);
	}

	/// <summary>
	/// Hmm. No relationship between the users. Start by a friendship request.
	/// </summary>
	/// <param name="command"></param>
	/// <param name="delegateTo"></param>
	private void MakeFriendsAndThenDelegate(RequestTaskDelegation command, IUserLink delegateTo)
	{
		// Not a user yet, hence we need to connect using an ID,
		// email can't be used since the user may loging with another one.
		if (delegateTo == null)
		{

			var inviter = _userStorage.Load(command.DelegatedFromUserId);

			var invited = _userStorage.GetInvitedByEmail(command.DelegateTo);
			if (invited == null)
			{
				invited = new InvitedUser(command.DelegateTo, inviter);
				_userStorage.Save(invited);
			}

			var pendingDelegation = new PendingDelegation
				{
					ActivationKey = invited.ActivationKey,
					FromUserId = command.DelegatedFromUserId,
					TaskId = command.TaskId
				};
			_todoItemStorage.StorePending(pendingDelegation);

		}
		else
		{
			_todoItemStorage.StorePending(new PendingDelegation
				{
					DelegatedToUserId = delegateTo.Id,
					FromUserId = command.DelegatedFromUserId,
					TaskId = command.TaskId
				});
		}

		var inviteCmd = new MakeFriend(command.DelegatedFromUserId, command.DelegateTo);
		_commandDispatcher.Dispatch(inviteCmd);
	}

	/// <summary>
	/// Accepted our invitation, now let's make that delegation request for real.
	/// </summary>
	/// <param name="e">The event</param>
	public void Handle(InvitationAccepted e)
	{
		// need to convert to using user id
		var delegations = _todoItemStorage.GetPendingByAcceptanceKey(e.ActivationKey);
		foreach (var delegation in delegations)
		{
			var newDelegation = new PendingDelegation
			{
				DelegatedToUserId = e.InvitedUserId,
				FromUserId = e.InvitedByUserId,
				TaskId = delegation.TaskId
			};
			_todoItemStorage.StorePending(newDelegation);
		}
	}

	/// <summary>
	/// Friendship requested, now we can request delegation
	/// </summary>
	/// <param name="e">The event</param>
	public void Handle(FriendRequestAccepted e)
	{
		var delegations = _todoItemStorage.GetPendingByUserId(e.AcceptedBy);
		foreach (var delegation in delegations)
		{
			var item = _todoItemStorage.Load(delegation.TaskId);
			var to = _userStorage.Load(delegation.DelegatedToUserId);
			var from = _userStorage.Load(delegation.FromUserId);
			item.RequestDelegationTo(from, to);
			_todoItemStorage.Delete(delegation);
		}
	}

	/// <summary>
	/// Need to remove a pending request.
	/// </summary>
	/// <param name="e">The event</param>
	public void Handle(FriendRequestRejected e)
	{
		var delegations = _todoItemStorage.GetPendingByUserId(e.RejectedBy);
		foreach (var delegation in delegations)
		{
			_todoItemStorage.Delete(delegation);
			var item = _todoItemStorage.Load(delegation.TaskId);
			var user = _userStorage.Load(e.RejectedBy);
			item.RejectDelegation(user, e.Reason);
		}
	}
}

Next time..

The next article will be published within a week. It will introduce my new framework which makes it effortless to get started with commands and domain events.

This entry was posted in Architecture. Bookmark the permalink.
  • thiago leite

    Nice article, I use similar a similar command pattern myself(in my case handlers and commands are not separated though). I just don’t get why you say that commands should never return a result. What if you informed user that the operation was ok, but when you actually execute it fails for some reason?
    You mentioned about notification system, but wouldnt be easier to just return something saying if operation was ok or not, I don’t see benefit of not doing it.

    • http://www.gauffin.org jgauffin

      You can’t return anything if you want to allow your application to scale.

      • The command doesn’t have to be executed in the same server. It can be queued through a message queue and executed in one of dozens of application servers.
      • My framework can also retry commands and store them (so they will be automatically retried upon a new start if the application crashes)
      • Asynchronous handling makes your application feel more responsive. It doesn’t matter if it takes a second or so for your application to process the command, even if you only have one app in one server.

      That won’t be possible if you want to get a result back.

  • http://www.daedtech.com/blog Erik Dietrich

    I really like the design concept here of commands as understandable domain abstractions rather than things that smell like code, and I think you do a good job making the case for it here. The idea of favoring commanding over service reminds me of a series that Ayende did about limiting abstractions. Just curious if you had seen that or were familiar with it.

    By the way, that pic of the pig with the lipstick is great :)

    • http://www.gauffin.org jgauffin

      Thanks!

      No I haven’t seen that series. Ayende post at lot ;) But I would love to read it. You don’t happen to have the link laying around somewhere?

      Yeah. I love the pig :)

  • http://antonkallenberg.com/ Anton Kallenberg

    Great article! Looking forward to the next one!

  • Marek

    Hi there,
    Can I have a question?

    When I have a command RegisterUser and domain event UserRegistered, how can I pair instance of RegisterUser command with corresponding event UserRegistered?
    Is it good choice to pass commandId to domain event?

    Let’s say that in some use case is registering user only part of some bigger request (including need for execution of other commands).

    So when user is registered, I need to continue processing rest of the request and I need to somehow pair the registration of user with rest of the processing context.

    Is the idea of reusing commands this way good?