Now that you understand COM+ transactions, consider some of the critical design issues involved with COM+ transactional component construction. We'll cover the following points:
Choosing Fine-Grained Components
Don't maintain transactions across method calls. Objects operating at a granularity of one transaction per method call perform much better than coarser-grained components. Requiring several client method calls to complete an operation produces objects that scale poorly because transaction resources (DTC Transaction objects, Database connections, COM+ object state, and so on) have to be maintained by COM+ during the interim. If human interaction is required before the second method call can be made, this moves resource lifetimes from the domain of the electron into the domain of the human ”a stark disparity by any measure. (Reminds me of that Star Trek episode, you know the one. . . )
Fine-grained solutions are not only highly scalable but also much easier to debug. If each method call stands on its own, complex method interactions often drop out of the picture during debugging sessions. Upon the completion of a transaction, all object state is destroyed , which reduces the potential for error carry-over. Each method should begin with data in a consistent state and end with data in a consistent state. Failures in this setting require repair of only a single method activity.
Therefore, stateless solutions are the optimal COM+ component implementation. If you must make several method calls to complete an operation, a compromise can be achieved by maintaining a stateful object between calls, but committing transactions on a call-by-call basis. For example, try creating a transactionless, stateful base object that creates an object requiring a new transaction for each successive method call. In this way, COM+ has to maintain only the minimal memory footprint of the stateful base object, committing or aborting each subordinate object's transaction on a method-call-by-method-call basis.
Locating Components Close to Their Data Source
The closer a server process is to the resource manager it uses, the faster it can complete transactions involving that resource manager. If you configure your data access components to run in a package on the same system as the database they access, you will generally acquire a significant performance edge over remote packages. In this scenario, it is critical to ensure proper server memory configurations, because excessive page faults can easily rob applications of any potential performance benefit.
Putting Components that Share Resources Together in the Same Application
Resource dispensers pool resources on a per-process basis. This means that components running in separate packages cannot share the same resource pool. Because COM+ manages thread creation and concurrency issues within application server processes, scaling multiple components is not a problem and can improve overall performance by more effectively utilizing pooled resources, such as database connections. It is important to note that this is an opposing administrative operation to that of fault isolation. The more components in a single process, the more exposed the entire process is to a single-component fault. Separating components into different applications improves fault isolation but degrades inter-component communications and resource sharing.