Showing posts with label CRUD. Show all posts
Showing posts with label CRUD. Show all posts

Friday, February 22, 2008

Fear the DSP

Udi Dahan has just made a post which brought to my attention a new TLA (Three Letter Acronym) in the SOA space - DSP (Data Services Platform). I agree with Udi - this is all bad. Hopefully it will go away on its own.

Udi made a previous post citing similar criticism of Microsoft's then named Astoria product, which has now been re-badged as ADO.NET Data Services. I agree that this product has the potential to encourage people to expose CRUD interfaces at the service boundary, which for reasons I've previously explained are bad news.

The space in which this product should play is exposing data for consumption by Web clients in AJAX or Silverlight applications. In this case, the CRUD interface is used only inside the service boundary, which is fine.

If it is unclear to you as to why the Web client is inside the service boundary, stay tuned for my next series of posts which should clear the fog a bit.

Wednesday, February 20, 2008

CRUD is Bad

We keep hearing that CRUD interfaces (that is interfaces with create/read/update/delete operations) are considered bad practice (an anti-pattern) in the context of SOA. But why? And how do we go about designing our service interfaces to avoid CRUD?

Let's start with the why. Services have both data and business logic. For reasons of encapsulation and loose coupling between services, we want to keep our business logic near the data upon which it operates. If our service contract permits direct manipulation of the data held within the service, this means that the business logic can leak outside the service boundary. It also means that the business logic inside the service boundary can be bypassed by direct manipulation of the service's data. All bad.

The same holds true in traditional OOP. Other classes cannot directly affect the state of a class. It is achieved through passing messages to (calling methods on) an object. This helps enforce loose coupling and high cohesion.

Even more compelling is the issue of updating multiple entities as part of a single logical atomic operation. CRUD interfaces usually will have create/read/update/delete operations for each entity housed by the service. But what if you want to update two different entities where either both updates succeed or neither?

You have the following options:

  • Use a distributed transaction
  • Implement compensation logic to handle failures yourself
  • Create new create/update/delete operations for specific combinations of entities

None of these options are satisfactory. The first option may not even be possible if the service stack doesn't support distributed transactions (e.g. ASMX, WSE). And even if it does support transactions, cross-service transactions are incredibly bad practice because services have the ability to lock each other's records which severely hurts service autonomy.

The second option is certainly not an easy task to do properly, and takes a lot of additional effort. And the third option isn't really practical. There are too many combinations of entities that may need to be updated in a single transaction, and it would take a lot of additional effort to implement them all.

Lastly, if a service must go to other services to pick up the data it is going to operate on, this means synchronous request/reply message exchanges between services. These are bad news because they are really slow and introduce temporal coupling between services (the service with the data must be available at the time the service without the data needs it).

So hopefully this is enough to convince you that CRUD is bad. But how do we design our services to avoid CRUD? Well, firstly we decentralise our data! This way all the data a service needs to operate on as part of a single logical operation is held locally within the service. Secondly, we make our service operations task centric, rather than data centric. The operations should be more like "make reservation" and "cancel reservation" rather than "retrieve reservation" and "update reservation". Udi Dahan has recently made a couple of posts discussing this very point.

A final point I'll make on this is that CRUD operations are fine inside the service boundary, so for example what you might see between a smart client and the service back end. But this point will be discussed in more detail in future posts. Stay tuned!