I haven't been reading or writing much lately - too heads down getting to 1.0. But I did happen across Don's recent post about retiring the four tenets of SOA and asking for input on what we'd like to write when we implement services. Let me take these topics in order. First, the four tenets of SOA...
What people are trying to build are loosely-coupled systems where pieces can be changed without breaking other pieces. I've built a couple of systems that meet that goal to a reasonable degree, so I don't think it's unreasonable for me to say that it's possible but hard and it takes a long time. In fact, it's just like building reusable components, which is also possible, hard and takes a long time. It isn't clear to me that many organizations are actually prepared to put in the work that loose-coupling really requires. What is clear to me is that the 4 tenets and the current tools aren't going to get them there. The only thing they really do is distract Capital-A-architects, which isn't a bad thing.
Which gets me to the second topic, what does the code I want to write look like. Here's my current thinking...
There are 4 essential distributed technologies: sockets, message queuing, RPC, and REST (in the distributed state machine sense I was writing about a couple months ago). There is a place for each in my current system. We use sockets to support certain industry and legacy protocols, both TCP and UDP, including multicast. We're looking at using message queuing for some ancillary processing off the main line of execution. We're using RPC to talk to SQL Server - either TDS, which is essentially RPC with streams, or SOAP via WCF, which is also essentially RPC despite what the proponents of mass customization exhort you to, in cases where a physical deployment separates our client from our database and the IT guys don't want to open 1433. For loosely-coupled cross-component integration we use REST.
I don't care that there are different APIs for all these technologies. In fact, I think it's a good thing because (a) I get an API tailored for the technology I'm using which (b) makes the differences between them clear. The only API that is lacking in .NET, IMO, is the REST one. If you aren't doing pages, ASP.NET leaves you hanging with IHttpHandler. Similarly, HttpListener isn't much of an API. Yes, I could put the new WCF REST bits on top, but I haven't, for several reasons. we needed a solution before they were available, so we already have a UriTemplate-based dispatcher of my own. We don't want to change .NET libraries at this point in the project, and can't move to a beta anyway. And finally, I'm not sure I want to build on a layer designed to factor HTTP in on top of a layer that was designed to factor it out.
The lack of a strong REST API is problematic because REST is a much better alternative for loose-coupling than RPC is. So, what do I want for an API? Easy: I want a UriTemplate matching layer (with a back-door for arbitrary regex's) that works on ASP.NET or HttpListener, abstracting away the differences between their respective context/request/response objects (which is just annoying). And I want a text-templating engine for output, a la NVelocity, with editor support. I'm close to building my own, since I already have the first half, with NVelocity, but haven't had time yet. (Yes, I've looked at monorail, but it feels like more than I want and I don't think it integrates with HttpListener.)
I'd like all that to run on top of 2.0 if possible, or at least in a kit that runs on XP and 2003, even if it requires 3.0 or 3.5. And I'd like it in the next 6 months or so (which I know is a pipe dream). The lack of this interfaces is a big part of my interest in Rails.
As to an example based on TransferMoney, here's what I'd do...
Design an idempotent implementation with a unique request id that can be saved on a client before initiating the request, used by a client in the case of failure to ask if the operation was processed (maybe by looking through a list of the operations processed in the last 24 hours), and used by the server to avoid processing the same request twice. (I'd make this part of the application logic instead of the transport protocol because reliability of the latter doesn't mean I can' t crash between getting a message and executing logic based on it, unless I go all transactional messaging, which introduces other issues.)
I would map out the state machines for the client, the server and the protocol between them. I would map the protocol itself to a set of URLs, as per my recent posts on REST. I would implement the endpoints by mapping URLs to methods using UriTemplates, parse the inbound data using whatever felt right and emit a response using a text templating engine.
I'd test it with the browser. I'd document it in prose, and maybe with an XSD for reference or to generate code if desired.
Don't know if that's concrete enough. It echoes what we're doing in our system now, which works great.
If the question was what do I want to see as a SOAP API, I don't have any issue with the [WebMethod]-esque style that WCF and every other stack uses. SOAP/WS-* turned out to be RPC/CORBA and the API is fine. That isn't as negative a statement as you might think.
Posted
Aug 26 2007, 12:17 PM
by
tim-ewald