37

I'm working on a project in which we are trying to apply both domain-driven design and REST to a service-oriented architecture. We aren't worrying about 100% REST compliance; it would probably be better to say we are trying to build resource-oriented HTTP APIs (~Level 2 of Richardson's REST maturity model). Nevertheless, we are trying to stay away from RPC-style use of HTTP requests, i.e. we attempt to implement our HTTP verbs according to RFC2616 rather than using POST to do IsPostalAddressValid(...), for example.

However, an emphasis on this seems to be at the expense of our attempt to apply domain-driven design. With only GET, POST, PUT, DELETE and a few other rarely used methods, we tend to build CRUDdy services, and CRUDdy services tend to have anemic domain models.

POST: Receive the data, validate it, dump it to the database. GET: Retrieve the data, return it. No real business logic there. We also use messages (events) between the services, and it seems to me that most of the business logic ends up being built around that.

Are REST and DDD at tension at some level? (Or am I misunderstanding something here? Are we maybe doing something else wrong?) Is it possible to build a strong domain model in a service-oriented architecture while avoiding RPC-style HTTP calls?

9
  • 1
    POST was deliberately designed to be "intentionally vague;" the result of a POST is implementation-specific. What prevents you from doing what Twitter and other API designers do, and define each POST method in the non-CRUD portion of your API according to your own specific requirements? Commented Jan 14, 2014 at 21:11
  • @RobertHarvey We have construed POST as a create. Looking at the standard again, perhaps that is overly simplistic. For example, do you think POST in order to do IsPostalAddressValid(...) would fit in with "Providing a block of data, such as the result of submitting a form, to a data-handling process"?
    – Kazark
    Commented Jan 14, 2014 at 21:17
  • That's because there's no CREATE verb (and no UPDATE verb, for that matter). I maintain that those verbs are missing from the standard (for whatever reason), which is why you have to co-opt POST for "everything else." Your "data handling process," in this case, is the process that examines the postal address, and returns a value corresponding to the result of that analysis. Commented Jan 14, 2014 at 21:22
  • 2
    @RobertHarvey: I believe that POST and PUT/PATCH is simply the CREATE and UPDATE verb that you've been wanting. It's only named differently so that the verb still makes some sense even in non-RESTful design.
    – Lie Ryan
    Commented Jan 14, 2014 at 21:31
  • @LieRyan: I'll grant you that. I just think that CRUD implies anemic data models by definition. You can carry along some behavior if, say, you are in the M of MVC, but certainly not across heterogenous systems. For everything else but CRUD, you need POST. Commented Jan 14, 2014 at 21:35

7 Answers 7

41

Martin Fowler's first law of distributed systems: "Don't distribute your objects!" Remote interfaces should be coarse-grained and internal interfaces fine-graned. Often rich domain model only applies within a bounded context.

REST API separates two different contexts both having their own internal models. The contexts communicate through coarse-grained interface(REST API) using "anemic" objects(DTO).

In your case it sounds like you are trying to spread a context over a boundary that is REST API. This can lead to fine-grained remote interface or anemic model. Depending on your project it may or may not be a problem.

1
  • 3
    Fowler has a lot of good thoughts but let us not forget what a disaster the original EJB spec and implementations were. It was only after that they figured out that low-level method calls for every minor operation like getName() was a network/load nightmare. Coarse-grained interfaces became the way to go and with it the concept that entire entity-graphs/messages were sent and received in the verb+noun context. Commented Mar 20, 2014 at 22:16
10

POST was deliberately designed to be "intentionally vague;" the result of a POST is implementation-specific. What prevents you from doing what Twitter and other API designers do, and define each POST method in the non-CRUD portion of your API according to your own specific requirements? POST is the catchall verb. Use it when none of the other verbs are a good fit for the operation you want to perform.

To put it another way, your question could be equally posed as "Do 'smart' objects encourage RPC-style design?" Even Martin Fowler (who coined the term "Anemic Domain Model") concedes that bare DTO's do have some benefits:

Putting behavior into the domain objects should not contradict the solid approach of using layering to separate domain logic from such things as persistence and presentation responsibilities. The logic that should be in a domain object is domain logic - validations, calculations, business rules - whatever you like to call it.

Regarding the Richardson Maturity Model, you can get to level 3 without ever concerning yourself about "Anemic Domain Models." Remember, you're never going to transfer behavior to the browser (unless you plan on injecting some Javascript through your models).

REST is mostly about machine independence; implement the REST model to the degree that you want your endpoints to represent resources, and for consumers of your API to be able to easily access and maintain those resources in a standard way. If that seems anemic, then so be it.

See Also
I Need More Verbs

2
  • I think that certainly addresses the RFC2616 side of the question. What about the fact that we are trying to be resource-oriented, i.e. at least trying to attain Level 2 in the Richardson maturity model for REST?
    – Kazark
    Commented Jan 14, 2014 at 21:26
  • 1
    I read through martinfowler.com/articles/richardsonMaturityModel.html. You can get to level 3 without ever concerning yourself about "Anemic Domain Models." Remember, you're never going to transfer behavior to the browser (unless you plan on injecting some Javascript through your models). Commented Jan 14, 2014 at 21:32
5

REST API is just one type of presentation layer. It has nothing to do with the domain model.

The question you posted comes from your confusion that you somehow need to adapt one to another. You don't.

You map your domain model to your REST API the same way you map your domain model to an RDBMS via an ORM — there has to be this mapping layer.

Domain ← ORM → RDBMS
Domain ← REST Mapping → REST API

4

This article is quite related to the subject and I believe answers your question.

A core concept that I think answers your question very well, is summarized in the following paragraph from the mentioned article:

"It is very important to distinguish between resources in REST API and domain entities in a domain driven design. Domain driven design applies to the implementation side of things (including API implementation) while resources in REST API drive the API design and contract. API resource selection should not depend on the underlying domain implementation details."

3

IMHO I don't think they tend to encourage anemic domain models (ADMs), but they do require you to take some time and think things through.

First of all I think the main characteristic of ADMs is that they have little to no behaviour in them. That's not to say that the system has no behaviour, just that it's usually in some sort of Service class (see http://vimeo.com/43598193).

And of course if the behaviour doesn't exist in the ADM, then what does? The answer of course is the data. And so how does this map to REST API? Well presumably the data maps to the content of the resource, and the behaviour maps to the HTTP verbs.

So you have everything you need to build a rich domain model, you just have to be able to see how the HTTP verbs map to the domain operations on the data, and then put those operations in the same classes that encapsulate your data.

I think where people tend to run into problems is that they have a difficult time seeing how the HTTP verbs map to their domain behaviour when the behaviour is beyond simple CRUD, i.e., when there are side-effects in other parts of the domain beyond the resource being modified by the HTTP request. One way to solve that problem is with domain events (http://www.udidahan.com/2009/06/14/domain-events-salvation/).

1

Several reasonably successful implementations I have seen/built answer the question in how they mix the verb+noun metaphor using coarse-grained 'business friendly' methods that act on the entities.

So instead of the (doomed) getName() method/service, expose getPerson(), passing in things like identifier-type/ID, returning the entire Person entity.

Since behaviors of the Person entity in such a context cannot be adequately conveyed (nor perhaps should they be in a data-centric context as this), it is perfectly reasonable to define a data (versus Object) model for the request/response pairs of the service/s.

The services and defined verbs themselves will add some domain-allowed behaviors, controls and even state-transition rules for the entities. For example, there would be domain-specific logic as to what happens in the transferPerson() service call but the interface itself would only define the inputs/output entities/data without defining THEIR internal behaviors.

I would disagree with authors that would say, for example, a transfer verb implementation belongs in the Person class or associated with a Person-centric service. Indeed, the method of transfer for a Person and options thereof (in this simple example) would be better defined by a Carrier, wherein the Person may have no knowledge of even what transfer methods are available or how transfer even takes place (who knows how jet engines work anyway).

Does this make the Person entity anemic? I don't think so.

There can/should be logic about Person-specific things that are internal to Person like their state of health, which should not be defined by an external class.

However, depending on the use-cases, it is entirely acceptable that an entity class have no important/relevant behaviors in certain systems, such as a seat-assignment service in a transport system. Such a system may well implement REST-based services that deal with Person instances and associated identifiers but never define/implement their internal behaviors.

1
  • Good points---this really brings some fresh perspective that other answers didn't have yet.
    – Kazark
    Commented Mar 21, 2014 at 0:20
0

Is your problem that you're trying to cram your model into the basic set of verbs, using POST as much as possible?

Its not necessary - I know that to most people REST means POST, GET, PUT and DELETE, but the http rfc says:

The set of common methods for HTTP/1.1 is defined below. Although this set can be expanded, additional methods cannot be assumed to share the same semantics for separately extended clients and servers.

And systems such as SMTP use the same style of verb-based methods but with a totally different set.

So, there's no reason why you have to use these, you can use whatever set of verbs you like (though, really you will find that you can do everything you need in the basic 4 with a bit of thought). The thing that makes REST distinctive from the other mechanisms is its stateless and consistent manner of implementing these verbs. You should not try to implement message passing system between the tiers as you're basically not doing REST then, you're doing a message-passing, RPC or message-queue mechanism instead which will undoubtedly lose you the benefits of REST (ie the simplicity of it that makes it work really well over a http connection).

If you want a full-features, complex messaging protocol, then build that (if you can do so over the web, there's a reason why REST is so popular), but otherwise try to stick to the architectural design of REST.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.