Skip to content

Instantly share code, notes, and snippets.

@liammclennan
Created January 27, 2011 05:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save liammclennan/798133 to your computer and use it in GitHub Desktop.
Save liammclennan/798133 to your computer and use it in GitHub Desktop.
tell-don't-ask vs. no external dependencies on domain objects
// tell don't ask means I might do something like this
var folder = new Folder("foo");
folder.Delete();
// but for that to work the folder class needs to depend on a file IO service (to do the deleting).
// the alternative is procedural
public class FolderService
{
public FolderService(IFileSystem fileSystem) {...}
public void Bar()
{
var folder = new Folder("foo");
fileSystem.Delete(folder.Path); // here is the tell-dont-ask violation
}
}
// what is the right way to do this?
@harukizaemon
Copy link

Can't you either create Folder with the necessary dependencies, or pass them to Delete?

@liammclennan
Copy link
Author

Sure can. The first option makes more sense because the other methods on Folder are likely to need file system access too. But doing so means that Folder (my domain class) has a dependency on a service, which I understand to be an anti-pattern. Something like:

folder = Folder.new "foo", fileSystem
folder.delete

@flq
Copy link

flq commented Jan 27, 2011

depending on your requirement you could use a message in wherever it is decided to notify the outside world that a deletion is required

bus.Publish(new RequestForDeletionOfFolder("foo"));

@liammclennan
Copy link
Author

Interesting idea. In this case each domain class would have a dependency on an event aggregator.

It violates my requirement to not take dependencies, but it also reduces the set of dependencies to one.

One of the reasons I don't want domain classes to have dependencies is to facilitate testing. If they need access to an event aggregator that means that every time I create a Folder (or any other domain class) object I have to give it a reference to the aggregator, or the aggregator has to be static. A static aggregator might work well because when testing there would be no registered listeners so nothing happens.

@mleech
Copy link

mleech commented Jan 27, 2011

There are parallels here with normal DB related CRUD. "Folder" = domain object, "file system" = DB.
What about using the Repository pattery?
"folder.Delete();" is more like active record.

@flq
Copy link

flq commented Jan 27, 2011

If you look at posts e.g. from Udi Dahan about Domain Events, the Domain objects do have a possibility to raise events (messages, whatever). It also lends itself well to a certain kind of blackbox testing. If you use some kind of event aggregator (I prefer to think of it as Bus) in your test you can assert whether certain messages/events have been generated by the parts of the domain under test.

@harukizaemon
Copy link

FWIW, I've build a number of large systems using Event Sourcing - I'm giving a talk next week as it happens - and I would never go back to using anything else. Testing is a breeze.

@liammclennan
Copy link
Author

Thanks everyone. Udi talks about Domain Events at http://www.udidahan.com/2009/06/14/domain-events-salvation/. Domain Events appear to be an elegant partial solution to the original problem. I say partial because an external dependency is still required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment