There is a lot of industry buzz around service orientation and “SOA” and a number of prominent voices within Microsoft are trying hard to articulate the approach the company is taking in this area. I think it is important, first of all, to emphasise that there is no Microsoft product that represents the hub of service orientation
- there isn’t anything that you have to buy to be “doing” service orientation. In this post I want to outline my thoughts on how to consider your application in terms of services in a pragmatic way and as important point out what I don’t think service orientation means.
In the late 80’s and early 90’s languages came to the fore that allowed you to represent your data as classes together with the associated operations that could be run with that data. This was a shift from the block structured programming that was in favour previously where code and data was kept apart and code modules were formed around areas of functionality independent from where and how data was stored. Today writing code using objects and classes is the norm but it took a number of years for it to become mainstream: C programming gave way to C++, Turbo Pascal introduced class-like types, and bit by bit Visual Basic adopted object-like constructs. This progression was how we entered the world of object orientation.
Service orientation is an evolution of object orientation. Just like the way object orientation didn’t mean one specific language, platform, or technology, service orientation represents an approach to building systems in a technology agnostic way. Object orientation got us a long way down the road to building more manageable and maintainable systems but as we moved to building more and more distributed applications it became clear that thinking about everything in terms of objects didn’t work any more. While the concept of both local and remote code appearing in our programming models as instances of objects was attractive, it turned out that to build reliable, scalable and performant distributed applications it really did matter where code was located. We needed to treat remote objects differently from local objects because of the speed and reliability of the network. Starting to consider different aspects of our applications as independent services helps to address these issues.
Another problem that we ran into with distributed objects was one of versioning. Because the different distributed object technologies typically exposed implementation details, it became difficult to update and extend parts of an application without impacting other areas. For example, how many times have you broken a DCOM or COM+ application by deploying a change to a server component and then finding that there is a compatibility issue with some of the applications that rely on that code? What cumbersome processes have you put in place or what annoying compromises have you made to try to reduce the headaches caused by binary compatibility? Service orientation is about reducing the coupling between different parts of your application so that these problems are easier to solve.
Okay, so I’ve talked about object orientation and some of the problems with distributed or remote objects and that somehow service orientation solves these problems but what is it? What do we mean by service orientation? Well, service orientation is an approach to building distributed applications by creating independent services that cooperate through loosely coupled interfaces to deliver the desired application functionality. A service is a logical unit of code that operates in a well defined area of the application with clear responsibilities through a well known interface. In fact, we have four tenets that guide us in building service oriented systems:
- Services have explicit boundaries
- Services are autonomous
- Services share schema and contract and not class
- Service compatibility is governed by policy
There has been a lot already written about these so I only want to cover them quickly.
Explicit boundaries: it is important for services to define their areas of responsibility and to expose their functionality only through explicit interfaces. Because crossing service boundaries impacts the performance and scalability of our systems, we want to be explicit about when we make those calls and don’t want them masked by technology that hides the difference between local and remote code.
Services need to be autonomous so that, in a changing world, we can extend and enhance both the functionality of a service and of its consumers in an independent way and deploy those services as we see fit. Autonomy also means we need to plan for and accommodate failures when consuming other services. This is something that is usually discouraged by object remoting technology.
Sharing schema and contract not class means exposing the “shape” of the data we deal with rather than the implementation detail of our service. Typically when we use DCOM or COM+, we install type libraries and proxies on the client that expose details of the class id’s used on the server. With .NET Remoting, we usually have to make the types we expose on the server available on the client for the CLR to make the remote calls. Service orientation breaks this coupling and allows clients to be implemented independently from the service.
Finally, we want to allow the way we communicate with services to be governed by deployed policy. This means that I can expose my service end-points using a variety of technologies and allow the client to select the one it prefers and to understand the requirements for that end-point, for example determining what to use for security and reliability. This is an area that is pretty weak in most of today’s protocol stacks but is being improved and will become increasingly important.
It’s taken a fair amount of time for me to arrive at the point of this post. Sorry about that. What I’ve written so far is really background information. The key take away is that service orientation is an approach to building systems and provides a roadmap towards building loosely coupled distributed applications. Nobody should be able to argue that loose coupling is a bad thing - if you go back and read those block structured programming guides from the 80’s, you’ll see them talking about high cohesion within and loose coupling between application modules.
It is really important that you keep this in mind as you consider whether and how service orientation applies to the systems you are building. Don’t try to interpret the four tenets too strictly: take a pragmatic view. I’ve seen too many people dismiss service orientation arguing that it doesn’t apply to their application. Take the fundamental principles of service orientation and apply them as it makes sense. Think about how you will version and deploy the parts of your application. Work through how you will maintain a loose coupling between those parts. Don’t throw the baby out with the bath water.
Service orientation doesn’t mean you have to deploy different services using completely independent databases. Don’t dismiss service orientation because you think it means having to kill application performance by doing cross database joins at the application tier. That’s taking the autonomy story too far. By all means keep the data in the same database and do joins if appropriate with SQL, just make sure you understand and have documented which service is responsible for managing which data. I recommend only doing this cross service data access in a read-only way.
Service orientation doesn’t mean that you have to throw out all your existing applications and start over. On the contrary, one of the defining properties of service orientation is that by building a service facade around existing applications, you can start to use them in new and interesting ways that were never conceived of when the application was originally built. You don’t have to have a huge company-wide revolution to adopt service orientation - evolve your applications, choose to build services as you write new code, think about the lifetime of the systems you are building and how you will manage change, pull out subsystems and expose them as services when it makes sense.
How many times have you worked on systems that just can’t sustain further development? Why does this happen? Usually it is because of the tightly coupled nature of the different application modules. Service orientation promotes loose coupling and asks you to consider how things will evolve. The promise of service orientation is that you will be able to rebuild and extend smaller parts of your application one at a time in future without having to consider a big bang rewrite. It will also allow you to leverage your infrastructure in new ways allowing your business greater agility in the marketplace.
I’ve used the same word a few times and it is the purpose of this post: “pragmatic” service orientation is about understanding the benefits of this approach and applying them in a sensible and flexible way. Please be pragmatic.