Command Objects or Interfaces?

Contact us

Command Objects or Interfaces?

Fill out form to continue
All fields required.
Enter your info once to access all resources.
By submitting this form, you agree to Expero’s Privacy Policy.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.

Every distributed system eventually requires messages to be written on the wire to be transmitted from one machine to another. In many cases these messages are hidden magic. Using WCF web services, or Thrift RPC, code-generated proxies make remote calls look like function calls.

// someone publishes thisinterface IPersonServer { AddEligibility(    string personId,     DateTime startDate, DateTime endDate);} // and through code-generation, you getvar IPersonServer magicProxy =  impressiveFactory("with://an-endpoint"); // and finally callmagicProxy.AddEligibility(personId, startDate, endDate);

That command travels over the wire as a message made of simple scalars like strings and numbers. There is value in exposing the command itself. When you work extensively with queuing, you have no choice but to make the message explicit. Some communication frameworks, like the lovely ServiceStack, embrace this message wholeheartedly. (That last link is actually worth a read, if a bit zealous.) Now instead you have:

// a POCO/DTO/PODclass EligibilityRequest{  publicstring PersonId { get; }  publiclong StartDate { get; }  publiclong EndDate { get; }} // this usually doesn't require code genvar endPoint = impressiveFactory("with://an-endpoint"); // now you just send the messagevar request = new EligibilityRequest(  personId, startDate.Ticks, endDate.Ticks);endPoint.Invoke(request);

Voila! An explicit message object you can put in lists, send through generic pipelines (say, to add authentication or logging concerns) and generally have fun with. This is all well and good and obvious at the application service level.

Hang on. If these are nice, why not embrace this pattern for our in memory domain objects? Should our aggregate root interfaces take these commands? Should we prefer option (1) or (2) below?

// 1. typical interfaceinterface IPerson {  AddEligibility(DateTime startDate, DateTime endDate);} // 2. explicit command interfaceinterface IPerson {  void AddEligibility(AddEligibilityCommand command);}

I don’t think there’s an obvious correct answer here. At a project in 2012 we tried both. And we ended up preferring option (1) for the actual domain objects. Here’s why.

What happens when you go implement AddEligibility on your Person domain object?

void AddEligibility(AddEligibilityCommand c) {  // how long is the period  long duration = c.endDate - c.StartTime;  // is it ridiculous?  if (duration < 0) { throw something; }  // how many days is that?  double durationInSeconds = duration / 1000000.;  double days = duration / 86400;  // it's valid if it's an exact number of days  if (days != Math.Round(days)) {    throw somethingElse; }   // and so on and so forth until  // we do something useful}

Did you notice the difference between the command object and the interface? The interface used DateTime, and the command object just used long because it’s more safely serializable.

DateTime is a useful value object with interesting operations like asking how many days are between two times. And it knows about daylight savings time. And leap days. And all the useful things that value objects do. You know, encoding important domain behavior.

We found when programmers had access to the message object inside our domain object, they’d take cruel advantage of it. As silly as it looks to not take advantage of the DateTime in the above example, that’s exactly what would happen. Domain logic that should been safely ensconced in value objects, shared cleanly within a bounded context, was instead re-implemented all over our domain objects. Really, who divides by 86,400 in a method meant to calculate eligibility windows?

The temptation to do that rarely arises inside a raw MVC controller, or ServiceStack service handler, since you’re so clearly at the boundaries of the system, and so clearly unpacking network messages. Inside those application services you better bet people quickly just did this

var startDate = new DateTime(c.startDate);var endDate = new DateTime(c.endDate);var person = personRepo.LoadPerson(c.personId);person.AddEligibility(endDate - startDate);personRepo.SavePerson(person);

And the person object’s implementation was more clearly free of translation concerns and leaked logic (in this artificial case, the logic of date manipulation):

void AddEligibility(TimeSpan duration) {  if (duration < TimeSpan.Zero) { throw something; }  if (duration.Days != duration.TotalDays) {    throw somethingElse;  }   // now do something useful}

Now the domain object can fluently use a nice value object from its domain (say, TimeSpan), and the application service can worry about message unpacking.

For some reason, this separation of concerns led to clearer code in the domain, and clearer flexibility in the application service layer. There was less temptation to treat these command objects as anemic domain objects.

So at least based on an actual programming team in the wild, my instinct is to convert these command objects to domain objects as quickly as possible in the well-known boundaries of the system. Your mileage may vary.

User Audience

Services & capabilities

Project Details

Technologies

Sebastian Good

April 17, 2014

Command Objects or Interfaces?

Tags:

Every distributed system eventually requires messages to be written on the wire to be transmitted from one machine to another. In many cases these messages are hidden magic. Using WCF web services, or Thrift RPC, code-generated proxies make remote calls look like function calls.

// someone publishes thisinterface IPersonServer { AddEligibility(    string personId,     DateTime startDate, DateTime endDate);} // and through code-generation, you getvar IPersonServer magicProxy =  impressiveFactory("with://an-endpoint"); // and finally callmagicProxy.AddEligibility(personId, startDate, endDate);

That command travels over the wire as a message made of simple scalars like strings and numbers. There is value in exposing the command itself. When you work extensively with queuing, you have no choice but to make the message explicit. Some communication frameworks, like the lovely ServiceStack, embrace this message wholeheartedly. (That last link is actually worth a read, if a bit zealous.) Now instead you have:

// a POCO/DTO/PODclass EligibilityRequest{  publicstring PersonId { get; }  publiclong StartDate { get; }  publiclong EndDate { get; }} // this usually doesn't require code genvar endPoint = impressiveFactory("with://an-endpoint"); // now you just send the messagevar request = new EligibilityRequest(  personId, startDate.Ticks, endDate.Ticks);endPoint.Invoke(request);

Voila! An explicit message object you can put in lists, send through generic pipelines (say, to add authentication or logging concerns) and generally have fun with. This is all well and good and obvious at the application service level.

Hang on. If these are nice, why not embrace this pattern for our in memory domain objects? Should our aggregate root interfaces take these commands? Should we prefer option (1) or (2) below?

// 1. typical interfaceinterface IPerson {  AddEligibility(DateTime startDate, DateTime endDate);} // 2. explicit command interfaceinterface IPerson {  void AddEligibility(AddEligibilityCommand command);}

I don’t think there’s an obvious correct answer here. At a project in 2012 we tried both. And we ended up preferring option (1) for the actual domain objects. Here’s why.

What happens when you go implement AddEligibility on your Person domain object?

void AddEligibility(AddEligibilityCommand c) {  // how long is the period  long duration = c.endDate - c.StartTime;  // is it ridiculous?  if (duration < 0) { throw something; }  // how many days is that?  double durationInSeconds = duration / 1000000.;  double days = duration / 86400;  // it's valid if it's an exact number of days  if (days != Math.Round(days)) {    throw somethingElse; }   // and so on and so forth until  // we do something useful}

Did you notice the difference between the command object and the interface? The interface used DateTime, and the command object just used long because it’s more safely serializable.

DateTime is a useful value object with interesting operations like asking how many days are between two times. And it knows about daylight savings time. And leap days. And all the useful things that value objects do. You know, encoding important domain behavior.

We found when programmers had access to the message object inside our domain object, they’d take cruel advantage of it. As silly as it looks to not take advantage of the DateTime in the above example, that’s exactly what would happen. Domain logic that should been safely ensconced in value objects, shared cleanly within a bounded context, was instead re-implemented all over our domain objects. Really, who divides by 86,400 in a method meant to calculate eligibility windows?

The temptation to do that rarely arises inside a raw MVC controller, or ServiceStack service handler, since you’re so clearly at the boundaries of the system, and so clearly unpacking network messages. Inside those application services you better bet people quickly just did this

var startDate = new DateTime(c.startDate);var endDate = new DateTime(c.endDate);var person = personRepo.LoadPerson(c.personId);person.AddEligibility(endDate - startDate);personRepo.SavePerson(person);

And the person object’s implementation was more clearly free of translation concerns and leaked logic (in this artificial case, the logic of date manipulation):

void AddEligibility(TimeSpan duration) {  if (duration < TimeSpan.Zero) { throw something; }  if (duration.Days != duration.TotalDays) {    throw somethingElse;  }   // now do something useful}

Now the domain object can fluently use a nice value object from its domain (say, TimeSpan), and the application service can worry about message unpacking.

For some reason, this separation of concerns led to clearer code in the domain, and clearer flexibility in the application service layer. There was less temptation to treat these command objects as anemic domain objects.

So at least based on an actual programming team in the wild, my instinct is to convert these command objects to domain objects as quickly as possible in the well-known boundaries of the system. Your mileage may vary.

User Audience

Services

Project Details

Similar Resources

Serverless ML

You can now deploy your models and get real-time scalable results without ever having to provision a server. Let me show you how I did it.

Watch Demo

Software Craftsmanship in Context

Software quality matters. Learn from a real use-case how we follow the Software Craftsmanship method to push a hard project forward.

Watch Demo

Company for a Cup of Joe: Finding Your Tribe

Combining traditional search techniques with graph algorithms to efficiently find subgroups within data.

Watch Demo

Testing React Applications Using Jest and React Testing Library

Avoid bugs & gain confidence when refactoring code by writing tests for your React code using Jest, React Testing Library & a Test Driven Development approach.

Watch Demo