Designing for
Service-Oriented Architectures (SOA)
Service-Oriented Architecture (SOA) as a design
pattern has been gaining a lot of momentum lately. As technology
advances and provides more and more power, SOA gradually shifts
from a theory about how software should be developed to a case
study in how software
is
developed.
SOA is
considered
to be the evolution of
object-oriented programming by some people in the industry, whereas
others consider it to be completely unrelated to the goals and
purposes of object-oriented programming.
Before you can grasp the true definition of SOA,
you need to understand the goals that drive this architecture.
Achieving loose coupling among application
components
is a primary
goal of SOA.
Loose Coupling and
Dependencies
As time goes on and companies produce larger
volumes
of code, the need to reuse previously created functionality
instead of rewriting it from scratch becomes more important. In
fact, many times the cost of rewriting functionality instead of
reusing it can mean the difference between a project that gets
completed and a project that never makes it out of the first design
meeting.
This introduces the concept of a dependency.
Developers and designers alike often
group
the two different kinds
of dependencies together, and this
prevents
the creation of the
best application possible. There are two different kinds of
software dependencies:
-
Real
dependency
A
real
dependency
refers to functionality or services that one
system consumes from another system. A system can be a small
subsection of code or it can refer to an entire application. Real
dependencies always exist and cannot be mitigated with coding
techniques or varying architectures.
-
Artificial
dependency
An
artificial
dependency
is the set of constraints imposed by a system on
a system that intends to
consume
functionality. Common artificial
dependencies are things such as language or platform dependencies
(requiring C, C++, or Linux, for example), infrastructure
dependencies, and more. An artificial dependency always exists, but
it can be mitigated using various techniques.
What often happens is that an artificial
dependency is listed simply as a dependency or a requirement that
must be fulfilled without any further discussion. This prevents the
mitigation of this dependency and prevents the creation of the best
application possible and maximum reuse of functionality.
What all of us strive for is the complete, or as
nearly complete as possible, mitigation of the artificial
dependencies within a system. This means that when examining
dependencies, you need to make a clear distinction about which
dependency is based purely on required functionality and which
dependency is based on artificial limitations imposed on the
feature consumer by the provider.
SOA as a Way of
Life
SOA is an architectural pattern in which the
main goal is to achieve loose coupling by reducing artificial
dependencies within a system. Within SOA, there are services (also
called providers) and consumers. A
service
is a discrete unit of work that
accomplishes some task
requested
by a consumer. The loose coupling
is achieved when the dependency that a consumer has on a specific
provider is
only that the provider
accomplish a specific task
, and that there are few or no
artificial dependencies in the way. When loose coupling is
achieved, the service can be consumed by any consumer that
knows
the agreed-upon message format to talk to the provider. Likewise,
the consumer can use
any
provider
of the same type.
In traditional object-oriented programming, the
consumer and provider are very tightly
coupled
, and may even be
part of the same class or library of classes. This is where SOA and
OOP spread apart in philosophy. OOP traditionally indicates that
data and the
methods
that process that data should be bound
together, whereas SOA strives to separate the information from the
processing of the information to allow one processor to perform its
task on data from multiple consumers and one consumer to send its
data to multiple processors without having any impact on the
system.
The concept of reusable providers and consumers
can become more apparent when applied to a real-world scenario. In
the real world, we consume services because those services are
either too costly or take too much time for us to do ourselves. In
some cases, such as performing specialized
tasks
for which we have
no
aptitude
, we would be completely unable to do the job
ourselves
,
even if we had the time and money. For example, if I were to
attempt to put a new roof on my house without getting the help of a
professional, the results would be disastrous. This is called an
"area of concern." Some existing services simply do the job better
than the consumer could; you might consider some services to be
"'experts."
At a hardware level, a device near and dear to
the hearts of many developers can be considered a service provider:
the Xbox. It provides a service of playing games. You, as the
consumer, supply the information (games) to the service provider.
As an output, you receive entertainment (and hopefully a high
score). The service provider (Xbox) can provide the game-playing
service to any input that meets the specified format. The input
that you use on one Xbox can be used on any other Xbox because the
service provider knows the format of the data being used as input.
You can say that the Xbox is loosely coupled from the consumer in
that you can play your
games
on
any
Xbox, and your Xbox can play games owned
by any other consumer. The only dependency on the Xbox is a real
dependency in that you must use the Xbox functionality in order to
play an Xbox game.
Now that you know what SOA is, what its purpose
is, and how similar models appear in everyday life, let's take a
look at an example of SOA implemented in software.
In this hypothetical scenario, a company has
decided to provide a unified storefront. It has purchased several
smaller companies that used to sell products individually such as a
bookstore, a DVD store, a CD store, and a company that sold
consumer electronics online. The new, larger company wants to be
able to provide all of the products of each individual child
company in a unified storefront. In addition, the larger company
wants to have several different sites that all share the same
catalog and product fulfillment system so that they can be branded,
styled, and customized for different companies.
Without SOA, creating a solution like this would
be a daunting task. Even if a solution could be developed without
SOA, it would be an extremely rigid and brittle solution that would
break at the slightest attempt for expansion or modification
because of the tight coupling and the
numerous
interdependencies.
Using Service-Oriented Architecture, the company
decides to create a catalog service that can be used as an
interface to the product catalogs of each of the individual child
companies and a dispatcher service that is used to funnel
requests
for catalog information and features from the front-end
applications to the appropriate catalog service based on the type
of product. In addition, loosely coupled shipping and
credit-card-charging services will be used for maximum scalability
and growth potential. This allows each of the product catalog
hosts
to provide their catalog to any front-end store, and the front-end
stores can work with any catalog. In addition, additional shipping
providers, credit-card management systems, and even product
catalogs can be added to the system with very little impact on
existing code. Figure 33.1 illustrates this particular SOA case
study.
This is by no means the only solution to the
problem described. However, it does
illustrate
how the use of SOA
and loosely coupled systems can dramatically reduce risk normally
associated with a project of this
size
and can create an
environment that is agile and able to cope with change and
expansion without requiring a lot of
rework
and refactoring effort
on the part of developers.
|