This is a posting part of a converstation going on between myself an Alex James, metadata thinker/engineer/PM par excellence here at Microsoft. You can find the start of the conversation here. I've decided to not be an ass and write a disertation in the comments section of his blog and am posting here instead.
Now the part that you've all been waiting for->
Basically it was that 9 times out of 10 when I run into this type of issue in the services world, I find that people have been falling into the antipattern of trying to use SOAP as an RPC mechanism. Some of the warning signs that one MIGHT (emphasis intended) be doing that are->
- relying on large sets of request - reply operation semantics
- moving an "object" around and not working with message based thinking for interactions
- services used for one and only one application
- intrasystem communication vs intersystem communication
- lack of pub/sub to coordinate actions between autonomous systems
Granted just because you have these present in a solution doesn't mean that you are doing it wrong, just that they are often warning signs of misapplied SOA attempts. When you have systems that are Request/Reply coupled it had better be because of a conscious decision to do so and not just because. I usually mentally map the use of data centric services, which we ivory tower guys have to admit is actually needed in solutions that developers write :) to the Little SOA concept, and process centric services to Big SOA (I'll leave it to readers to Bing those terms on their own).
So all that being said, it comes down to the issue that I find that people would instead of using it to compose functionals (which I totally agree with BTW), they'd use it as a way to instead try to write a SQL-ish WHERE statement against a service.
Let's start with this example then:
Employee manager = service.Execute(
(s) => GetManager(GetDepartment(GetEmployee(s)))
What we have here on the surface really makes sense. We're really just stating F(G(K(x))) = y, something we all do in math all time. But I ask, how often do we really actually only pipe calls between the stages without conditional and branch/join logic creeping its way inside? If given this capability, how long before we actually see this?
And then comes the obligatory WHERE conditional followed by ORDER BY followed by JOIN and before you know it, you're treating the service like a relational database and in RPC via SOAP world. That is the path to insanity...
Employee manager = service.Execute(
var e = GetEmployee(s);
return e.IsActiveEmployee ? GetManager(GetDepartment(e)) : null;
So it's not the issue with the example shown per say, but that sometimes we need to ask these questions first before we start trying to resort to technology fixes:
- why are we having difficulty here?
- why is it that our software artifacts seem to not be meshing with the logical systems model?
- why is it that the fluentness of our interfaces are not enabling the composition of our service offerings and in fact, seem to be getting in the way?
In fact, I find myself using introspective questions like those presented quite a bit as an internal litmus tests along the way of the implementation of solutions. The last question especially gets asked quite a bit actually as it's hard to figure out the proper division of capabilities into distinct services boundaries. Or as my man Plato would state, "find the natural joins" in the problem space. We run into this all the time when performing behavioral decomposition in objects, so why would we not expect it in services as well? :)
So all that being said, I see in the future systems being built up from composite service interfaces by a separate services execution layer (or layers). Enterprises will be built up from a catalog of operations that fulfill needs and are interacted with by known message taxonomies and calling semantics. Solutions then will actually operate on purposely constructed amalgamations of operations, types, and caller semantics that are specific to the needs of the caller. I joking call these "Do-It-Yourself WSDLs" though of course, services can be constructed using any message passing pattern people care to use. This application centric view of information then will be used to pull all these systems together by way of a orchestrator service or executor layer (or services bus or whatever makes sense for your organization technology wise) whose entire purpose is to understand the intention of the request and reify it into actionable requests via autonomous software agents that perform all the dirty work of actually talking to the services themselves in the manner and format as is appropriate for them.
THAT'S where I feel your example really makes sense (remember, I did say that I personally agree with functional composition as presented by you originally =D) and capabilities like that belong as part of an orchestrator. After all, remember that this makes sense as Service Interfaces are all about the caller’s external perspective or view of autonomous systems. Postulating that that view is correct, then we are simply taking this concept to the next logical step and totally abstracting the who from the equation and instead need to request the what or intention we have to the enterprise systems infrastructure and allow it to get the job done, and present the results to us in the way we want (format) and in the manner we need (i.e. orchestrating many monadic duplex operations individually into a Request/Reply interaction between the ultimate consumer and the orchestrator). As an aside, we actually all see intention vs operation convention on a day to day process already in SQL based languages. When I write a SQL statement I absolutely am NOT stating how to accomplish something when I issue a command to a server, I am stating the intention I desire to the server and leave it up to it to act upon the commands I issued. So when I see services that say, Get Manager For Employee Id, what I really see is a bit of INTERNAL application logic getting forced onto a separate system (note: I am not insinuating that is what your example is stating should be done, and in fact your entire point of a system like you propose was to keep that type of bollocks OUT of services). The same holds true when I see repositories that have interfaces like GetMeDomainThingyX(idToFind, pageSize, pageNumber, orderBy), we're pushing responsibilities the wrong direction.
So all this is fine and dandy and maybe this is the future and maybe it is not. Perhaps I have my head in the cloud (ok ok bad joke) and this services nirvana I dream of is never going to come about but I have hope as I feel the industry is finally at the point of reaching critical mass when it comes to service catalogs where taking capabilities to the next step, discoverability, services management, and DIY mashup capabilities but projects like the Managed Services Engine and NService Bus give me a glimmer of hope that maybe, just maybe, it is going to be a brave new world after all...