12

Our company is starting a fairly large SOA initiative. We're doing a lot of stuff right: there's good communication; money for tools where appropriate; and we have brought on some good expertise to help us with the transition.

We're trying to develop standards that we can follow as a group, and one of the proposed standards is bothering me quite a bit:

We have standardized on the pattern where every operation takes a request object and returns a response object.

I realize that this is more or less a standard approach for a lot of folks, but I am asking why should I bother? (I'm not so good with received wisdom, I need some why).

Most of the services that I will be providing are simple organizational metadata retrieval. For example, find the security policy for a particular user. This needs a user id and nothing else. The standard tells me that I should wrap this request in an object and wrap the returned policy in a response object.

My unease is amplified by a look at the WSDL that is generated from our contracts. WCF generates request and response messages automatically and wraps even the request/response object.

I fully understand that if you're making a complex request then a complex input object is warranted. That's what you would do even if services wren't involved.

My question is why should I automatically wrap requests and responses when:

  • It makes simple services less expressive
  • You would do it anyway for a complex service
  • WCF creates a request/response message anyway

I have found the following arguments in favor of this approach:

It supports versioning by allowing optional parameters to be slipped into the request object.

Back in the day, I did a fair bit of COM, and I would consider this almost an anti-pattern for versioning. For some things, I suppose it would help, but I expect that where it would help, you already have a parameter object anyway.

It allows common data and behavior to be isolated to a base class

This one carries some weight with me.

It steers people away from an RPC style behavior and towards a messaging behavior

I've read this on Microsoft's site and heard it from our guru, but I still don't have a clear idea what they mean or why it's valuable. Is it that natural looking interfaces make people tend to forget that they are calling a remote service?

I am looking at refactoring the signatures of perhaps 300 methods, so this is a non-trivial amount of pain. I'm a huge fan of consistency in implementations, so I'm willing to take on the pain, it will just help to know that it will all be worth it in the end.

2 Answers 2

3

I think versioning is probably the best argument. When you have an existing operation contract like

int GetPersons(int countryId);

that you want to enhance, e.g. by another filter later on

int GetPersons(int countryId, int age);

You would have to write a new operation contract and with a new name since it has to be unique. Or you would keep the name and publish a new v2 of your service with the old v1 still being around for backwards compatibility.

If you wrap the parameter into an object you can always extend it with default/optional parameters and all your existing clients will be unaffected when you reuse the same operation contract.

However I would also urge to name your objects appropriately. Even if it just wraps an int, if you start with IntMessage or something similar you're not doing yourself a favor extending it. You'd have to name it e.g. PersonFilter right from the start which means you have to think a little about what this service call should expect as parameter semantically and therefore what it's supposed to do. Maybe (and that's a very vague maybe) that's going to help in developing the right services and maintain a decent sized API.

It allows common data and behavior to be isolated to a base class

That's something to be cautious with. Inheritance and data contracts don't go that well together. It does work, but you'll have to specify all known subtypes of the contract that could go over the wire, otherwise the data contract serializer fails complaining about unknown types.

But what you could do (but still probably shouldn't, I'm still undecided on this) is reuse the same messages among different services. If you put the data contracts in a separate dll you can share that between client and service and you don't need to convert between types when you call different services that expect basically the same message. E.g. you create a PersonFilter and submit that to one service to get a filter list of persons and then to another service and have the same objects on the client. I can't find a good real-world example for that though and the danger is always that an extension to the data-contracts is not general enough for all services that use this contract.

Overall, apart from versioning, I can't really find the killer reason for doing it that way either.

3
  • I think the reason why I take the
    – Andy Davis
    Oct 16, 2011 at 3:26
  • (sorry, comment interface is giving me grief) Thank you for answering. I think the reason why I take the versioning argument with such a grain of salt is that if you added a new argument you probably changed the semantics. If (as in your example) you just added an age, then the semantics were probably for search and you had a "search object" in there to begin with.
    – Andy Davis
    Oct 16, 2011 at 3:32
  • Now consider my security policy example. Perhaps we decide that in order to properly supply a security policy, we need to know not only the user, but the facility that they are working in. This is much more than adding an argument, we have changed the semantics of the call. Assuming that we are somehow able to supply this information for a caller of the previous version, I think it makes more sense to version the service contract. Then the implementation for the old version can be isolated and you don't end up mixing old semantics with new.
    – Andy Davis
    Oct 16, 2011 at 3:37
0

Martin Fowler's notes on the Data Transfer Object are appropriate here, I think.

When you're working with a remote interface, such as Remote Facade (388), each call to it is expensive. As a result you need to reduce the number of calls, and that means that you need to transfer more data with each call. One way to do this is to use lots of parameters. However, this is often awkward to program - indeed, it's often impossible with languages such as Java that return only a single value.

The solution is to create a Data Transfer Object that can hold all the data for the call. It needs to be serializable to go across the connection. Usually an assembler is used on the server side to transfer data between the DTO and any domain objects.

The same might apply to requests. As for RPC, and why its bad:

Is it that natural looking interfaces make people tend to forget that they are calling a remote service?

I think that's true, but not the main reason. Another reason to avoid RPC is that it can encourage tightly coupled clients and services.

2
  • Thanks for the input, but I don't think that the DTO discussion is all that relevant. It's the same number of calls, and if you look at the WSDL, everything is automatically packaged into a request and reponse object. The convention is about visible semantics, i.e., people should think of this as a request & response as opposed to a remote method call.
    – Andy Davis
    Mar 14, 2012 at 4:09
  • Would you care to elaborate on RPCs encouraging tightly coupled clients and services? I can't see that this affects the service at all. For the client, I don't really see how anything really changes either. In either case, I have the client holding a proxy which describes a number of operations provided by a service. Who actually implements the other side of the service isn't the client's business in any case.
    – Andy Davis
    Mar 14, 2012 at 4:16

Your Answer

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

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