The Stripper Pattern
In 2006 (if I can recall correctly), Greg Young and I discussed the concept of the Stripper Pattern, we never really had the chance to formulate it into a real pattern, but we kept discussing this whenever we met (and had beer available).
This post is about the stripper pattern, and there is a good reason why I selected the accompanying image for this post, it is the spookiest stripper image that I can put in the blog. Because the Stripper Pattern is an anti pattern.
It all started from a fairly innocent question, asked in the NHibernate talks that I did on Progressive.NET:
How can I send my objects over the wire?
I could have given the answer, I could have talked about the reasons this is bad (versioning, isolation, tell don’t ask, etc, etc), but what I actually said was:
I'm not running a strip club so why am I sending you all my privates?
Later on, we got into a deeper discussion of the topic, which led to this post. There is a reason that I choose that statement to answer that question. Let us move up the stack a bit and ask: What is an object?
An object is data + behavior. If you don’t have behavior and data, you don’t have an object. It is as simple as that.
Nitpicker corner: I am not talking about System.Object, or something of the sort. I am talking from a conceptual level. DTO is not an object, despite the name, it is a bag of data.
Since it is not possible to send behavior over the wire, what the question means is actually:
How can I send my objects as data over the wire?
The problem is that this question doesn’t really make sense.
What you are actually doing is divesting the object from its covering and perform acts of forbidden knowledge on its privates. Then, to add grave insult to serious injury, you take that and post it over the internet. Just be glad that objects can’t sue for breach of OO contract, encapsulation violation and sexual harassment.
When you separate a data from behavior, you are no longer working with objects. At that point, you start to run into problems, a lot of them. In addition to the simply technical issues, there are very serious architectural issues with stripping away all OO from your solution.
If you need to send data over the wire, that is why we have a DTO for. If you need to handle updates, use the approach described here, which gives us a good OO semantics for the whole process.
Comments
As someone who has had to do some remoting work on current project i agree 100% with this. Send only the data, make the 'object' you send specific to the remoting request and keep it simple.
Well, thanks a lot for the image. Now I need to get a suit like that for next carnival!
I'm glad to see people talking about this issue more. It's been bugging me for some time now.
I think we need some better libraries/languages to reduce the programmer overhead however.
I couldn't agree with you more, and your statement about the stripper was both entertaining and accurate.
It does raise the question though, what kind of websites do you frequent in your spare time to come across an image like that? :-)
I love the newly coined anti-pattern. I think it should go well with a re-coined anti-pattern that I developed: YAGNIB (you ain't gonna need it... BEEYATCH).
note to self: write up a description of the stripper pattern
A formal one?
Maybe ...
Don't you want a lot of the same behaviors on both sides of the wire? Clearly you want some behaviors only to exist in one place (such as persistence) but what is the best way to reuse validation rules and access rules etc.?
If you have objects on both sides with mostly the same behaviors and they are sending / receiving the same data? Are you saying that what travels over the wire shouldn't be the actual object but it is actually ok for the object to exist on both sides?
note to self: research strippers before writing stripper pattern
Justin,
Validation isn't behavior. If you want to have the same validation, package that up and send it along with the object data.
What run on the server and what run on the client are two totally different things.
How is validation not behavior? You have to actually run something to do the validation don't you?
Or are you suggesting that the results of validation is what should go along with the data? It seems perfectly valid to want to perform validation in multiple (or all) tiers. Which would be behavior in that case I think.
Validation is something that is usually done at two stages:
UI validation - typically stuff like required, length, range, format, etc
Business rules validation
The first is not behavioral aspect of the entity, and that is usually easy to handle by sending the validation constraints with the data when sending on the wire
I use DTO's and there is a problem that never know how to solve it well.
There are some functions that I wanted to exist in both, BusinessObjects and DTO's. It could be a simple function like:
public int GetTotal()
{
}
If I put it in my BO I don't have it in my DTO and the reverse is true. I want it in my DTO because I could use it in UI if needed but, of course, I don't want to duplicate it.
Where should I put it? I usually end putting it in some Util class, which is a bad thing just like Ayende posted some days ago.
What do you do?
Well... then all ORMs breach OO contracts?
Many people try to send "privates" over the wire because they don't understand the boundaries of their system. They try to pretend that objects have no boundaries and that they can exist both here and there transparently-auto-magically. They should go CORBA :)
Ignoring the wire is one of the worst things one can do. Tailor-made messages which adhere to a given formal contract (be it a XSD, WCF annotations) is the way to go in my opinion (as I always try to explain in NHibernate-Hispano list), so I strongly agree with this post.
I can't agree with this. Here's an analogy with physical objects. A computer is an object. Moving the computer to another room is an antipattern because this entails moving all the private internal parts. Also, if you really like the computer, copying it (i.e. building another one just like it) is an antipattern because it involves revealing all the guts. The only safe way to do this is to build a computer moving/copying machine. The strenght of the object model is supposed to be correspondence to the real world, but I don't see that happening.
It seems like the practice you recommend is using DTO's. As I understand it DTO's involve extracting just the data and sending them as a "change transaction". I see three problems with this, given your argument. First, the DTO still needs to be serialized. Second, whether you serialize and send an object over the wire or do that to a DTO, you are still serializing an object over the wire. Third, wikipedia says a DTO "does not have any behaviour except for storage and retrieval of its own data" So while you are saying we shouldn't send "exposed privates" it seems like the recommend method involves chopping off only the privates and sending them in a box, only to be stuck onto a different stripper Mr. potato head style. So to avoid serializing an object and sharing its privates we have (a)shared only its privates (b)created an extra class, and (c)serialized objects of the new class. This seems needlessly complex to me.
I am only generally familiar with NHibernate so maybe this conversation is just going over my head... feel free to set me straight. Obviously a lot of folks agree with you so you must be onto something here. Francisco's comment made sense to me... this is about boundaries. Trying to send a raw object outside the boundaries of your system doesn't make sense. But isn't that kind of a straw man? I mean is it possible to successfully serialize an object into a different object model?
Chase,
No, trying to talk about OO in terms of physical objects doesn't make sense.
Serializing a DTO is about data, serializing an object means that you have to carry behavior as well. You can't serialize behavior. So now you are stuck with encapsulation problems, versioning problems, different architecture problems, etc.
And DTO isn't a mirror image of an object.
Thanks for the quick reply. I'm not sure I'm convinced though. I'm willing to abandon the correspondence to physical objects... while it is supposed to be the main benefit of object thinking it doesn't always work out.
"Serializing a DTO is about data, serializing an object means that you have to carry behavior as well." Most of the serialization systems I've seen work by serializing only the data and some indication of what the class is. So serialization would seem to be an automated way to do what you are describing as long as the source and target objects are of the same class.
"encapsulation problems" At least serialization encapsulates digging into the privates into a standard system library. With DTO's you are explicitly pulling those private data out and sticking them into a special object via "raw" accessor functions. As I said, you're chopping the privates off the stripper and sending them special delivery. I don't see how that avoids encapsulation problems.
"versioning" DTO's don't really eliminate version problems. They just push the problem back a level. Neither does serialization, but at least some of the serialization frameworks offer standard way to manage class versions.
"different architecture problems" - I have agreed that serializing outside the boundaries of a given architecture makes no sense. I'm not sure how you would even go about trying.
"And DTO isn't a mirror image of an object." An example might help. Or perhaps we have both said our peace.
Chase,
Try doing a search on the problems of exposing your objects across a system boundary. There is a lot of material out there about that.
And sending a class indicator to a different system isn't really useful. You are losing the object context, you have totally different requirements in different sections (UI code doesn't care about business code, frex).
Hendry,
No, ORMs don't send an object over the wire.
Cassio,
You have a simple property on the DTO, and calculated on on the object
Seriously, I lol'd. =)
You guys are getting too serious about a blog post that talks about handling privates.
"As I said, you're chopping the privates off the stripper and sending them special delivery."
+1 Chase, LOL exactly.
It would sure be nice to see a "what is business or domain logic" presentation with a bunch of practical examples and code. Just about every sample application that I have downloaded, is completely anemic when it comes to demonstrating actual business logic. There is a bunch of data validation and data relationship (customer has orders) logic, but little or no what I would consider domain or business logic.
Eric,
There is good reason for that, sample applications, by nature, are made to be simple.
Try reading some of the DDD samples
Ayende,
I think where you are falling into trouble here with your peanut gallery is that your advice is too general. Martin Fowler says the same thing in P of EAA.
Quite simply, if all you are doing is always sending DTOs, then your end-point for the DTO is a Browser that is fully responsible for knowing how to handle its display formats. You give it a MIME type and it is fully responsible for knowing how to render it. That is bad design, because it decouples data from behavior and pushes you back into the structured procedural programming paradigm. You want to hide (in fact run away from) such decisions as fast as possible, and talk strictly in terms of the problem domain.
By contrast, have a look at wire protocols like Argot, where more than just a DTO is possible.
Also, I agree with you that validation can be just data. It is in my applications. I ship "smart clients" that understand a data-driven validation DSL. This is REST.
Also, @Eric
"Business Logic" is not some coding requirement that requires you to write moon code. For this reason, it is often not that different looking from other forms of code. However, if you want to get a firm understanding of business logic, I recommend looking at academic papers published by "The Process Four (P4)" who explain workflow languages in great detail. Once you understand the higher level details, the implementation is simply coding.
Comment preview