Exchanging Data - shipping typeless containers
I have had several discussions over the last couple of weeks with various parties interested in whether or not it's wise to exchange data contained in datasets between a caller and a service.
I really dislike using datasets to pass information back and forth between a caller and a service. Why would you want to define a service's contract to say “hey, you can pass me whatever data you like and I'll return you some data that you have no idea what it is until you start to pick it apart“. That is the most non-commital form of design that there is. In my experience, the main reason that designers/developers do this is because they haven't sat down and thought through their application's design sufficiently and to me that's a warning signal that has always served me well - in almost all applications I have come into contact with, the signal has correctly indicated a system with several difficulties.
What kinds of problems am I referring to? Here are a few that spring to mind:
- Correctness: In systems which predominantly pass untyped data (ie: in Datasets):
- The flow of information around the system is often inferred and is liable to be highly unpredictable and error prone.
- In such systems, it is often the case that the dev team have to implement all manner of framework and substrate technologies to make sense of the non-explicit, “fluffy” nature of the application.
- Debugging such applications is usually very complex and difficult and the most likely resolution is incorrect understanding/assumptions about the nature of a particular process or part of the app.
- Datasets impact performance: Datasets are not represented tersely when serializsed. A dataset contains the XML schema of the data it contains along with the data itself and also serializes a bunch of internal dataset specific information. I hear that the Data team here are working on making datasets far more efficiently serializable, but I still maintain the same design issues I discussed above
- Datasets limit interoperability: When you serialize a dataset onto the wire, the consumer (be it the service being called or the caller recieving the return of a method) must understand how to de-serialize the wire-format back into something it can parse and re-construct internally. If the reciever is not a Microsoft dataset, then it will have to do a lot of work to tease the data out of the overall XML document from the wire.
A more wire-efficient and typesafe alternative is to design [Serializable] structs for your services to exchange information and to pass these serialized structs around on the wire. These structures clearly define what types of information are expected / returned from each action and vastly reduce incorrect assumptions resulting in more reliable code that is easier to develop and maintain.
I have also had discussions about whether it's wise to engineer services with methods such as:
void DoWork(string action, string data)
As I am sure you can already guess, I dislike this approach too! While the size and interop issues have been remedied by using serializable strings, such an infrastructure is essentially laying a dumber layer of SOAP over SOAP! Do you really want to build a message dispatcher? If so, shouldn't you be implementing a SOAP message dispatcher. But then, wouldn't you be reimplementing ASMX/WSE/Indigo? Applications should use the platform on which they are built to the fullest, utilizing all the services and features the platform provides. All that you'd be doing in implementing something such as this is to take on the burden of implementing a message processor and dispatcher. Is that your application's role? If not, I suggest entierly avoiding this pattern.
Also, from a consumer's perspective, how do I call your actions? Where is the list of valid action types? And what about the data? What do I pass to you for any given action? It's too arbitrary and error-prone. Say what your methods do. Say what types of data you want to exchange. Let the platform you choose do the work of making those calls happen.