Columns

Objects, Components, and Transactions
David Chappell - October 1997

Component-based development looks like the next big wave in software engineering. Microsoft’s 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 that’s 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 shouldn’t 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 I’ll explain, this turns out to have some very interesting ramifications.

Understanding Transactions

I’m 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, it’s 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 BEA’s Tuxedo, NCR’s TopEnd, and Transarc’s Encina provide the same kinds of solutions for Unix and Windows NT servers. Microsoft’s MTS fits in this same category, although it’s 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 doesn’t have much to do with transactions per se, it’s 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 OMG’s Object Transaction Service (OTS) does. Microsoft does this, too, in something called OLE Transactions. OLE Transactions is broadly analogous to OMG’s 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 doesn’t do this. In fact, MTS doesn’t 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. It’s 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 there’s 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


There’s 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. It’s 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 won’t 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 that’s filling the order. Each of these components requires a transaction—otherwise, 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 component’s request—this 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 doesn’t 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 it—the marriage of components and transactions is looking very stable.

Microsoft vs. Everybody Else


Microsoft isn’t 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 isn’t available yet for truly large systems, which means that big transaction-oriented applications can’t 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 you’re 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 it’s likely to become the most common container for server-side transactional components. Its limitations are really NT’s limitations, and one could argue that those limits stem more from NT’s relative youth than from any intrinsic flaws in the operating system. It’s 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 don’t 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 MTS—the 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, they’re also bringing to market some of the best new ideas. Merging components and transactions is a case in point.