Дублирование
Это справедливое замечание, что, когда команды и события упорядочиваются, время компиляции безопасность теряется, но в статически типизированный язык, я бы до сих пор предпочитают сильно типизированных команды и типы событий.
Причина этого в том, что она дает вам единую базу кода, отвечающую за интерпретацию элементов сообщения. Сериализация имеет тенденцию быть вполне (тип) безопасной; десериализация - это то, где вы можете столкнуться с проблемами.
Тем не менее, я бы предпочел разобраться с любыми подобными проблемами в одном месте вместо того, чтобы распространяться по всей базе кода.
Это особенно актуально для событий, поскольку у вас может быть несколько обработчиков событий, обрабатывающих однотипные события. Если вы рассматриваете события как слабо типизированные словари, вам нужно будет дублировать реализацию Tolerant Reader в каждом обработчике событий.
С другой стороны, если вы обрабатываете события и команды как сильные типы, ваш десериализатор может быть единственным толерантным читателем, который вам нужно будет поддерживать.
Типы
Все это говорит, я могу понять, почему вы, в таких языках, как C# или Java, найти, что определение неизменные DTOs для каждого и каждое сообщение, кажется, как много накладных расходов:
public sealed class CorrectNameCommand
{
private readonly string userId;
private readonly string newName;
public CorrectNameCommand(string userId, string newName)
{
this.userId = userId;
this.newName = newName;
}
public string UserId
{
get { return this.userId; }
}
public string NewName
{
get { return this.newName; }
}
public override bool Equals(object obj)
{
var other = obj as UserName;
if (other == null)
return base.Equals(obj);
return object.Equals(this.userId, other.userId)
&& object.Equals(this.newName, other.newName);
}
public override int GetHashCode()
{
return this.userId.GetHashCode()^this.newName.GetHashCode();
}
}
Это, действительно, похоже на работу.
Именно по этой причине я в эти дни предпочитаю другие языки для реализации CQRS. Вкл.NET, F # является идеальным решением, потому что все выше коды сводится к этому однострочнику:
type CorrectNameCommand = { UserId : string; NewName : string }
Вот что я хотел бы сделать, вместо передачи слабо типизированных словари вокруг. В последний раз, когда я услышал, что Грег Янг говорил о CQRS (NDC Oslo 2015), он, похоже, «преобразовал» в F #.
Я бы сказал, что речь идет о читаемости и явлении. Вы видите, что требуется Command, и вы видите, что предоставляет событие. Пары Key-Value-P здесь не очень помогают. Также, используя соглашения об именах, легко использовать Ioc-Container для создания правильного Command- и EventHandler. – Jehof
Так что это компромисс? Я также написал общий обработчик команд, который автоматически отправляет метод с совпадающим именем и соответствующими параметрами в аг. Это устраняет даже работу по написанию обработчика команд для каждой команды (но не запрещает). –
Означает ли это, что у вас есть один большой класс со многими методами для обработки ваших команд? Вместо 1 класса обрабатывает каждую команду? –