Objects, Components, and Transactions
David Chappell - October 1997
Component-based development looks like the next big wave in software
engineering. Microsofts COM is the most widely used component
model today (in fact, depending on how you define "component",
it may be the only widely used component model today). So far, components
have mostly been popular for building client applications, but thats
about to change.
Components for servers are here, and building serious server apps, whether or not components are involved, often requires transactions. Transactions have long been a mainstay of business computing, and today, objects are, too. It shouldnt be surprising, then, that these two technologies need to be united in some way. In the world of COM, that unification happens in the Microsoft Transaction Server (MTS).
MTS is more than just transactions plus objects, however. Among
its several innovations, it requires creating applications as COM
components. As Ill explain, this turns out to have some very
interesting ramifications.
Understanding Transactions
Im going to assume that you know the basics of objects, but
transactions might not be so familiar. Defined narrowly, a transaction
can be thought of as a group of changes (e.g., to one or more databases)
with the property that either all of those changes happen or none
of them do. If an application needs transactions, its certainly
possible for the developer of that application to write the code
himself to ensure this property. Because this requirement shows
up so often, though, and because it can be surprisingly hard to
get right, various vendors provide software products called transaction
processing monitors (or just TP monitors) that provide standard
solutions. In the IBM mainframe world, for example, the venerable
CICS is the leading example, while products like BEAs Tuxedo,
NCRs TopEnd, and Transarcs Encina provide the same kinds
of solutions for Unix and Windows NT servers. Microsofts MTS
fits in this same category, although its an NT-only solution.
An application that needs transactions very likely needs other
services, too. For example, the application will probably need to
scale to handle a large number of clients. While this doesnt
have much to do with transactions per se, its nevertheless
a commonly required service for enterprise applications, and so
TP monitors usually provide services that can improve application
scalability.
Transactions and Objects
A typical TP monitor provides applications with several standard
API calls. The usual pattern is for an application to make some
kind of call to begin a transaction, then perform the work that
makes up the transaction (such as changing records in one or more
databases), and finally to end the transaction by asking the TP
monitor to either commit the transaction (making all the changes
permanent) or abort it (rolling back all the changes). Accomplishing
this requires that the TP monitor work together with the database(s)
in which those changes were made.
The most straightforward way to make this object-oriented is to
express all of these interactions as method calls on appropriate
objects. Rather than just calling an API function to start a transaction,
for example, an application might create a new transaction object,
then, when its work is finished, invoke appropriate methods on that
object to commit or abort the transaction. This is essentially what
the OMGs Object Transaction Service (OTS) does. Microsoft
does this, too, in something called OLE Transactions. OLE Transactions
is broadly analogous to OMGs OTS, but the objects defined
by OLE Transactions are, of course, COM objects (in fact, the use
of the "OLE" tag here is one of the last vestiges of the
days when this label was assigned to anything that used COM).
A CORBA-based TP monitor typically exposes the OTS objects to clients,
allowing them to invoke methods in the familiar pattern of "Begin
Transaction, Do Work, Commit or Abort Transaction". Interestingly,
MTS doesnt do this. In fact, MTS doesnt even implement
OLE Transactions itself. Instead, the objects defined by this spec
are mostly implemented in something called the Distributed Transaction
Coordinator (DTC). DTC runs in a separate process from MTS applications,
and it was actually released before MTS. Its really DTC that
acts as the transaction coordinator when committing or rolling back
the changes made by an application. MTS is just a user of DTC, relying
on it to do the hard work of handling transactions.
Okay, so then what does MTS do? Well, as described earlier, TP monitors
typically provide services that make it easy to write scalable applications,
and MTS offers quite a bit here. MTS also provides an interface
for applications to use transactions, although it passes the actual
work involved off to the DTC. The interface MTS provides is simpler
than the raw OLE Transactions interface, which is a good thing.
But theres something even more important about the way MTS
changes the interface applications see. To understand what that
is, we need to think about more than transactions and objects; we
need to think about transactions and components.
Transactions and Components
Theres already a significant market in client-side components,
nearly all of which today are ActiveX controls (although JavaBeans
will surely acquire some market share). Components for servers can
also be very useful. Imagine, for instance, being able to buy standard
components for order entry or funds transfer or other common operations,
then building applications around them. Its unquestionably
an appealing idea.
A primary goal of MTS is to provide a container for standardized
server components, thus allowing this kind of market to exist. And
since these sorts of components will often need transactions (to,
say, atomically transfer money between two accounts), it makes sense
to use a TP monitor as their container.
But by their very nature, components are meant to be used in diverse
ways, being combined into applications in ways unforeseen by their
creators. If those components use transactions, the standard "Begin
Transaction, Do Work, Commit or Abort Transaction" model wont
work. To understand why, imagine you have a component that knows
how to take online orders, making changes to several databases as
needed to fill those orders. Suppose that you also have a component
capable of transferring money from one bank account to another,
e.g., from the account of the company placing an order to the account
of the company thats filling the order. Each of these components
requires a transactionotherwise, only some of its changes
might occur, leaving the data in an inconsistent state.
But each of these components might be useful either on its own or
in concert with other components. If each component were always
used alone, the traditional "Begin Transaction, Do Work, Commit
or Abort" structure would work just fine. But what if somebody
wants to combine both components into a single transaction, so that
placing an order and getting paid are one atomic operation? If each
component contains its own Begin Transaction request, this becomes
problematic.
The solution adopted by MTS is to not allow a component to explicitly
control when a transaction begins. Instead, each component can be
administratively configured to require a transaction. When a client
creates a component (i.e., a COM object) that requires a transaction,
MTS automatically starts one. If that component just does its work,
then commits or aborts the transaction, MTS carries out the components
requestthis component has its own transaction. If this component
creates another component, though, and that new component also requires
a transaction (such as when the two components described earlier
are used together), MTS can automatically include the changes made
by this new component in the transaction that already exists. When
this second component commits or aborts its work, MTS notes this
but doesnt end the transaction. Not until the parent component,
the one originally created by the client, decides to commit or abort
does MTS end the transaction. If both components asked to commit,
the transaction commits. If either one chose to abort, however,
all of the changes made by both components are rolled back.
This approach allows the same component binary to be used in its
own transaction or combined with others into a single transaction.
For people accustomed to the traditional model, having no Begin
Transaction call can seem weird. But get used to itthe marriage
of components and transactions is looking very stable.
Microsoft vs. Everybody Else
Microsoft isnt the only vendor who understands the importance
of combining components with transactions. They are well ahead in
this game, however. MTS shipped in late 1996, while products supporting
Enterprise Java Beans, the primary competing technology for transactional
components, have yet to appear. Furthermore, MTS (and DTC) are free,
while their competitors expect (not unreasonably) to make a profit
on their products. And at Microsoft, the MTS and COM groups have
been merged, implying that support for transactions will eventually
become an even more fundamental part of the software infrastructure
in the Windows NT environment.
But MTS only runs on NT. This is a significant limitation for a
couple of reasons. First, NT isnt available yet for truly
large systems, which means that big transaction-oriented applications
cant be written using MTS. But perhaps more important, applications
that use transaction monitors such as MTS tend to be mission-critical,
bet-the-business kinds of apps. When youre creating this kind
of application, it pays to be conservative. How long will it be
before people really trust NT?
Still, MTS is remarkably innovative, and its likely to become
the most common container for server-side transactional components.
Its limitations are really NTs limitations, and one could
argue that those limits stem more from NTs relative youth
than from any intrinsic flaws in the operating system. Its
hard not to believe that MTS will become a very widely used technology
over the next few years.
The traditional take on Microsoft has always been that they dont
innovate. Like the IBM of old, they wait for others to invent good
ideas, then create their own version of those ideas, relying on
sheer market power to win. But this perspective is getting harder
and harder to defend. COM itself is an innovation, one that other
vendors have been doing their best to imitate. And the idea of merging
transactions and components appeared first in MTSthe rest
of the vendor pack is well behind in shipping competing products.
It was somehow comforting to think of Microsoft in the traditional
way, as nothing more than technical copycats. Today, though, not
only do they have a commanding market position and all the money
in the world, theyre also bringing to market some of the best
new ideas. Merging components and transactions is a case in point.