SOA: More Integration, Less Renovation
Since the focus of this column is service-oriented architecture (SOA), I thought now might be a good time to step back and take a wide-angle look at the general concept and what it means to developers. As most readers are painfully aware, much has already been written on the subject of service orientation. In fact, the current frenzy around the topic makes many developers wonder if service orientation will be the next buzz-word casualty.
I don't think it will. The principles of service orientation are here to stay. I believe they'll help enterprises build more successful distributed systems that can adapt over time. So this month, I'll give you my take on service orientation and what it means to the enterprise as well as to the developer.
Motivations of an Enterprise
Service orientation is simple: it more effectively addresses the realities of today's enterprises than any other design paradigm. In order to understand why service orientation is such a good fit, let's first consider the most important needs of an enterprise. When looking at distributed systems from a business perspective, most enterprises share a few fundamental concerns:
- How well does the architecture meet specific business needs?
- How much is it going to cost to manage and maintain?
- Will it adapt to the growth of our businesses over time?
- How long until it is necessary to start over and rewrite?
Within an enterprise, there are a variety of stakeholders. You have top-level executives focused on company direction, vision, and strategy. You have CTO types, architects, and project managers tasked with aligning business goals with technology choices—these folks are usually the ones most directly focused on the questions I listed. You also have the engineers and developers tasked with implementing, testing, and deploying the system. Then there's the IT staff tasked with managing and maintaining the system after deployment. And finally, you have the users of the system.
All of these stakeholders have different, and often conflicting, goals and concerns. Applying the principles of service orientation can improve the overall experience for everyone involved.
More Integration, Less Renovation
The main reason service orientation will improve the enterprise experience is that it lets you leverage existing investments. Complete renovation—making significant changes to the technological makeup, architecture, and design of a distributed system—can be a nasty temptation. You think it'll be easier to just start over. It's common for developers to face compressed timelines with very little time, if any, allocated to the design process. Some may find themselves in a never-ending state of renovation, which usually has a negative impact on the business concerns.
In addition to general evolution, mergers and acquisitions complicate matters further by creating a melting pot of technologies that must all work together. Legacy hardware and software is obviously here to stay and will probably always complicate distributed system development.
Service-oriented design can alleviate these age-old problems, and designing for SOA from the beginning can seriously improve the future for all enterprise stakeholders. It will make systems more malleable to business needs, easier to develop, and more reasonable to maintain and manage so you can plan ahead rather than respond defensively.
Designing Systems to Last
If you design systems to last, it doesn't mean they're stuck in the past. Increasing the longevity of a distributed system requires a focus on the flexibility of its individual parts. If individual components are free to evolve and if new components can be introduced without requiring a major renovation, overall agility and manageability improves as does longevity. Focusing on integration early in the development process (perhaps even before it's needed) will give you a competitive edge.
Service orientation represents the next evolutionary step in distributed design methodologies, with the necessary adjustments to address the enterprise realities surrounding integration.
Objects, Components, and Contracts
Let's briefly retrace the steps leading up to the latest abstraction of service orientation. Distributed computing has consistently improved with more powerful and flexible abstractions, as each evolutionary step encouraged reuse and reduced coupling.
In the beginning software was monolithic. Then we moved to functional programming. Object orientation (OO), which quickly became the norm in the 1980s, with its focus on inheritance, encapsulation, and polymorphism, soon followed. Object orientation encouraged reuse, but its whitebox characteristics led to tight coupling and brittle inflexibility.
Components and interface-based development followed in the 1990s. This new approach provided a blackbox abstraction over objects. Components introduced the concept of shielding objects behind a boundary, only allowing interactions through a shared contract (the interface). Implementation details remained completely hidden from view. Only interface details and documentation were available to the consumer. Components were deployed independently as binary units of code, which made them somewhat autonomous. They were loaded dynamically by the component runtime, which provided additional services such as security, reliability, transactions, and so forth.
Component-oriented development was the first significant step towards reducing coupling between objects. It did this by focusing on contracts, not classes. This became even more important when developers began using components across machine boundaries in a distributed fashion.
When designing components, developers usually started by defining the contract. Interface definitions were written using the Interface Definition Language (IDL). The IDL was then used to generate class definitions and runtime behaviors. Focusing on the interface definition required developers to think about the data types shared across the component boundary. This turned out to be especially important when different languages were used to create and consume the component. Language interoperability often suffered when not enough attention was paid to the contract during design. Components were a significant move towards a more loosely coupled distributed system.
The Road to Service Orientation
Although component technologies were a significant advancement, they possessed a serious flaw: they made too many assumptions about the technologies used, assumptions about platform dependencies, homogeny, and proprietary communication protocols. They assumed that everyone using the component framework would be running the same operating system and component runtime. They also made serious assumptions about messaging models, assuming everyone would be satisfied with remote procedure calls (RPC). Although these assumptions are reasonable for some business scenarios, they negatively impact the agility and longevity of any evolving organization.
Service orientation takes component technologies to the next level by stripping them of these assumptions. You can think of service orientation as a black-box abstraction over the traditional component framework (in fact, it will often be used that way).
In this new paradigm, a "service" is an application you interact with by exchanging messages over specific communications protocols. A service adheres to these fundamental principles: it has explicit boundaries and is autonomous, it shares contract rather than implementation, and compatibility is based on policy.
In order to interact with a service, you simply send messages to its specific address. For this to work, both the client and the service must speak the same communication protocols and share an understanding of the required message format. This means there's an explicit boundary to the service—the only way you can interact with it is by sending it messages. Exactly how you interact with a service, and what type of message you must use, is defined by a shared schema and contract definitions.
Services also benefit from being autonomous, which basically means they can stand alone and take care of themselves (although the precise meaning is a matter of debate). Despite the emphasis on autonomy, however, services can also be composed of other services. For example, a workflow coordinates the work and interactions of multiple individual services—imagine the workflow itself exposed as a service.
Given the focus on loose coupling, services must be able to figure out if they're compatible with other services somehow. This is accomplished through a shared policy that both sides understand and can interpret at run time. For more information on the tenets of service orientation, see the "Service-Oriented Architecture Resources" sidebar.
Service orientation does not impose any platform dependencies, component technology, or programming language. The only shared assumptions are the message formats, description languages, and communication protocols. This is a huge step in the right direction but it begs the obvious question: what technologies should be used for these remaining shared assumptions?
What About Interoperability?
Before turning to assumed technologies, I'll discuss interoperability. Service orientation focuses on independence and loose-coupling, but there's no mention of interoperability. Although you could argue that the tenets of service orientation don't necessarily require interoperability, I'd argue that it's intrinsically tied to this paradigm and is nonnegotiable in the real world.
It was the lack of interoperability, mind you, that prevented component technologies from keeping up with the Internet and Web advancements. It was the lack of interoperability that motivated the need for something better than traditional component development, leading to a focus on services built with Web-based technologies (Web services). It is also the lack of interoperability that hurts enterprises more than anything else in their efforts to build flexible systems that last. Interoperability is absolutely necessary to achieve more integration and less renovation.
Indeed, interoperability is a fundamental factor in building long-lasting distributed systems. Coalitions like the WS-I have been formed with the specific goal of helping to ensure interoperability. Interoperability must not be forgotten, but rather used to enhance the flexible abstractions of service orientation that I described earlier in this column.
Service Orientation vs. Web Services
If you only focus on the official tenets of service orientation, it's quite possible, in fact, to build a service-oriented application using proprietary message formats and communication protocols. Doing so gives you a flexible system that can't talk to anything but itself. However, since interoperability is a fundamental requirement, the technology choices for these shared assumptions must facilitate interoperability, not reduce the ability to work together.Service-Oriented Architecture Resources
The following is a list of resources that will help you learn more about service-oriented architecture and design and put you on your way to better planning.
This is precisely where Web services fit in. There is a common misconception that Web services and service orientation are synonymous. They are not. Service orientation is a paradigm while Web services represents a suite of implementation technologies. Web services is the best implementation of service orientation today because it's built on a foundation of standards that truly facilitate interoperability in the real world (see Figure 1).
Figure 1 Web Services Protocol Stack
Standards are vitally important when interoperability is at stake. And it's extremely difficult for the industry at large to agree on anything, not to mention an entire suite of data formats and protocols. Producing standards requires debate, negotiation, and, most importantly, compromise from all sides. After a standard solidifies, vendors must remain committed to it in their products. The real test of their commitment comes when a given standard doesn't meet their exact needs or business objectives.
Overall, it's extremely tricky to achieve widespread agreement and true commitment around a suite of technologies. So the value of standards, even when the technologies themselves don't seem that brilliant, cannot be overstated. The software industry has been able to achieve remarkable consensus around a suite of simple protocols and technologies, most of which helped build the distributed Web. This was not possible before, at least not to this degree. It is a remarkable achievement.
For example, we have achieved widespread interoperability around several communication and application protocols including TCP, HTTP, SMTP, and many others. Disparate platforms and applications can effectively communicate using any of these standard transports. There has been mass adoption of XML 1.0 as a standard syntax for representing information sent over these transports and a more recent adoption of additional XML-based dialects like SOAP, XML Schema, and Web Services Description Language (WSDL) that lay the foundation for an interoperable Web services architecture. These technologies work well for the kinds of communications that occur at the service boundary.
SOAP defines a standard mechanism for building application protocols in a transport-neutral manner. It defines a simple framework for sending and receiving XML messages between systems using a variety of message exchange patterns. SOAP lays a solid foundation on top of which service-oriented systems can be built.
XML Schema provides a standard language for defining application-specific types or schemas that can be used in a variety of different programming environments. WSDL is another language for defining service contracts that use XML Schema types for input and output. These two languages together are appropriate for sharing the schemas and contracts of a given service.
Figure 2 Determining Compatability
In addition to these foundational technologies, there are other specifications under development that provide layered services such as security, reliability, and transaction support. These WS-* specifications play an important role in building sophisticated Web services infrastructures that will simplify the building of robust, real-world distributed systems. When services begin to use these different layered services, questions of compatibility quickly arise (that is, does service A support the same security required by service B?). Determining compatibility requires policies that describe service requirements and behaviors (see Figure 2). The Web Services Policy language (WS-Policy) is another specification with significant adoption that makes it possible to accomplish this.
The widespread agreement around Web services technologies makes it the only viable choice for implementing service-oriented systems today. Applying Web services to this flexible architectural paradigm is expected to be a powerful combination.
Thinking the Service-Oriented Way
Designing distributed systems around the principles of service orientation using Web services technologies requires a different way of thinking about the world. It requires you to think more about connecting the dots within a distributed system—again more integration, less renovation.
Before you write a single line of code for a service-oriented system, you must identify the logical services and the necessary interactions that will make up the system. When modeling these services, you must make sure to consider real-world business and technology dependencies and the overall goal of autonomy.
As with objects, services should be modeled in a way that facilitates and encourages reuse across applications and environments. Thought must go into where the code will be hosted and what protocols will be used to talk to it. Exactly how you draw lines around your code to delineate what's contained in a service is arguably the least understood aspect of this new paradigm, but you can surely expect advances in this area.
After the scope of a service has been defined, a service-oriented developer would focus next on defining the contracts that will be needed to interact with the service. In practical terms, this means defining the XML Schema and WSDL definitions used by the service. Focusing on how to move data in and out of the service is an excellent exercise in flushing out what you need it to do before you get caught up in details. What data is needed inside the service versus outside the service? What message exchange patterns are required? How you move data across a service boundary is the primary focus of this stage, and it's completely disconnected from how you treat data within a service (see Pat Helland's recent MSDN®
article entitled "Data on the Outside vs. Data on the Inside
After the service contracts have been designed, focus should turn to the service policies. This requires you to think about the various security and reliability requirements of the service and how high you're going to set the bar for others. Policy decisions not only affect how hard it is for you to implement, but more importantly, how hard it is for others to consume. The decisions made with regards to policy can definitely impact the reach of a service.
When you're designing the service-oriented way, you do all of these things during the design phase before you begin implementation. Once you have the contracts and policies nailed, you can then take advantage of tools to generate the necessary code to implement the service framework, helping return some of the time invested in design.
Probably the most significant change for developers embracing this new model has to do with the impact it has on their development process. Most developers of distributed apps are used to focusing on objects and writing a lot of code from the starting gate. This habit must change in a service-oriented world.
There are two common techniques that developers use to define service contracts today. One is to start by defining a WSDL contract before implementing the code—I refer to this as "contract-first" development. The other is to start by writing the service implementation in code, such as C# or Visual Basic® .NET, and then rely on the underlying infrastructure (for example, ASP.NET) to produce the contract for you—I refer to this as code-first development. Both approaches have their pros and cons, but code-first is more common today.
Contract-first forces you to work with the shared language that everyone agrees on (WSDL, for example). Today working directly with WSDL is extremely difficult and uncomfortable because we lack proper tool support and the language is difficult. But there is a silver lining: working directly with WSDL prevents developers from using language-specific types or OO techniques that don't map nicely to a service contract. The code-first approach is more pleasant, but it introduces an extra level of indirection—a translation layer that can be deceiving and troubling for interoperability.
Although today's frameworks don't accomplish this, it will be interesting to see if future Web services platforms can make it more feasible to define service contracts in a developer-friendly language (like C#) without hampering interoperability. I believe it's possible with proper constraints and restrictions built into the framework. However, even if the next version of Windows®, code-named "Longhorn," makes it possible to define contracts in an easier manner, say through an attributed interface definition, the same principles apply to that approach. It simply eliminates the need to work directly with WSDL, which is something that any developer would certainly welcome.
If developers truly want to embrace service orientation and Web services, they must also be willing to embrace contract-first development. Otherwise, they've missed the entire point. Contracts are the building blocks of a composable, service-oriented system. Hence, everything hinges on the contract definitions.
Contracts as Building Blocks
Objects used to be the building blocks of distributed systems, but not anymore. Contracts are the new building block in a service-oriented system. They facilitate composition, integration, and the overall adaptability of a system. In the end, the contracts tie the system together, bridging a wide range of platforms, operating systems, component technologies, and programming languages. Therefore, it's extremely important to invest time and energy in contract design in order to produce something that facilitates interoperability and integration, the fundamental goals of this model.
One thing to keep in mind is that you're not always in control of the contract definition. In some situations you're the one providing the service so you control the contracts and others are forced to use them. In other situations, you may find yourself on the receiving end, forced to use a contract that someone else has defined. And you may find yourself collaborating with other individuals, departments, or entire organizations to develop standard contracts that will be shared in a given vertical segment.
When you're forced to use a contract defined by someone else, all you're going to care about is that it's easy to use in your development environment. If you run into problems, you may be inclined to look elsewhere for the same functionality. Most enterprises would do well by adopting the general principle of making it as easy as possible for others to integrate with them. In a service-oriented world, the true value of the system is found in the overall quality and ease-of-use of its contracts.
Developing an easy-to-consume contract is definitely harder and more time consuming than producing one indirectly through a toolkit, but you'll be making your partners happier and improving your business objectives at the same time. And when you find yourself on the receiving end of a contract, you'll wish those who developed it had followed the same principles.
Overall service orientation offers tremendous opportunities if you're willing to change your mindset and embrace contract-first development. The key paradigm shift for developers is to focus on contracts, the new building blocks, rather than on objects. Doing so will help produce long-lasting distributed systems that meet the enterprise goals I presented at the beginning of this column.
In a future column, I'll walk you through a practical example of building a service-oriented system using contract-first development techniques, and I'll show you some of the tools available today for making the technique more approachable.
Send your questions and comments for Aaron to firstname.lastname@example.org.
is a co-founder of Pluralsight, an education and content creation company, where he focuses on XML and Web services technologies. He's a contributing editor to MSDN Magazine
and the author of several books, including Essential XML Quick Reference
(Addison-Wesley, 2001). Reach him at www.pluralsight.com/aaron