Improved DSL Syntax for DDD and Event Sourcing
As you probably already know, we are currently finishing Salescast2 project internally at Lokad (cloud-hosted big-data analytics platform for retail). This project benefits from the latest development improvements in the area of DDD/CQRS applications with event sourcing (and drives some of these improvements back into the open source samples that we share).
One of the side effects of event sourcing (in addition to ability to ditch all SQL dependencies, decrease maintenance costs, reduce migration problems and improve performance) is that there is a large number of event and command classes. These classes tend to change quite frequently during the development as well (it is a part of DDD modeling process).
To simplify generation of these commands we use real-time code generation of these contract classes from a compact syntax. Below I'll introduce the concept to new developers and also explain recent changes and improvements including support for syntax colors.

By the way, as an alternative to running a DSL.exe in background, you can plug the syntax into T4 code generator. But this is a bit too constraining in my opinion
In reality this works like this. When I plan to start changing some contracts (or adding new ones) in my project, I launch DSL.exe project and leave it running. From now on, whenever *.ddd file is changed, corresponding code contract files are changed. ReSharper immediately picks up the changes. Also any breaking changes will prevent code from compiling.
Lokad DSL generator (which is included in Lokad Sample Project as source code) will also make sure that resulting classes have proper array initialization and attributes for work with DataContract and ProtoBuf serializers. Generated classes are implemented as immutable.
In essence, majority of the template code looks like this:
CreateUser? (security)
explicit "Create user {id} for security {security}"
UserCreated! (security, TimeSpan activityThreshold)
explicit "Created user {id} ({security}) with threshold {activityThreshold}"
ReportUserLoginFailure? (DateTime timeUtc, string ip)
explicit "Report login failure for user {Id} at {timeUtc}"
Editing experience looks like this:

And results look like this:
[DataContract(Namespace = "Lokad.SaaS")]
public partial class UserCreated : IEvent<UserId>
{
[DataMember(Order = 1)] public UserId Id { get; private set; }
[DataMember(Order = 2)] public SecurityId SecurityId { get; private set; }
[DataMember(Order = 3)] public TimeSpan ActivityThreshold { get; private set; }
UserCreated () {}
public UserCreated (UserId id, SecurityId securityId, TimeSpan activityThreshold)
{
Id = id;
SecurityId = securityId;
ActivityThreshold = activityThreshold;
}
public override string ToString()
{
return string.Format(@"Created user {0} ({1}) with threshold {2}", Id, SecurityId, ActivityThreshold);
}
}
Plus you get autogenerated (and auto-updated) interfaces like this:
public interface ISecurityApplicationService
{
void When(CreateSecurityAggregate c);
void When(CreateSecurityFromRegistration c);
// ... skipped
void When(AddPermissionToSecurityItem c);
}
public interface ISecurityState
{
void When(SecurityAggregateCreated e);
void When(SecurityPasswordAdded e);
// ... skipped
void When(PermissionAddedToSecurityItem e);
}
If you inherit a class from such interface, implementing actual method is just a few key-strokes away ("implement missing member"), plus compiler will not let you forget to handle these commands or deal with events in an aggregate.
Syntax of DDD files is documented rather well in the Sample project: messages.ddd
Changes
If you were tracking progress of this blog, then you are familiar with the previous version of the DSL syntax approach. Well, it changed slightly since then:
letkeyword becameconst;usingkeyword becameif;entitykeyword becameinterface;- added
namespacefor defining namespace of the generated file (e.g.:namespace Company.Product.Module;); - added
usingkeyword for importing additional namespaces; - added
externkeyword for defining data contract namespace for all generated contracts; - added
explicitkeyword (and special syntax) for definingToString()in-place; - made sure that Visual Studio provides nice syntax coloring.
In order for the syntax coloring to work, we simply abuse C# or C++ syntax highlighters built into visual studio. Here's how you set them up:

The default way is to associate ddd files with C# editor. However, if you don't like C# editing experience or want to be able to define highlights for your own custom types, you can also associate ddd files with C++, if you have essentials installed (more info). This way you can add highlights for value objects and identities specific to your projects.
How does this look? :)
Wednesday, July 25, 2012 at 16:21
Reader Comments (3)
Rinat,
Really liking that we can have syntax coloring now. Will have to try it out.
A couple of questions. A couple versions ago of the DSL it looked like you had configuration settings in the ddd file. It looked like this allowed the dsl.exe to work with multiple files at the same time (I might be wrong about this). Now we have to change some settings in the DSL tool to work with different ddd files. Why did you choose that route?
Also, on a different topic, when looking through the sample, the registration controller sends messages that contain a users password in plain text. The outcome of which, is that if someone was able to their hands on the event store they would have all of the users passwords. Would it not be prudent to hash the passwords at the controller before they enter the event stream?
Deke, oups, sorry about dropping support for multiple ddd files. That was due to my mistake in exporting the code to open source. Restored this capability back.
Re passwords and hashes. If we don't record commands, then only hashes and salts will be recorded. However, indeed, logical way to strengthen security is by hashing everything in the client. Unfortunately I didn't have much time to make this sample code look like production one. Will try to do that later.
Just a note that this tool now has its own dedicated repo on GitHub, outside of the Lokad.CQRS sample, and the latest code for the Lokad Code DSL can be pulled from there: https://github.com/Lokad/lokad-codedsl