#3: One Resource Manager, Use Local Transactions
This is actually not a
recently learned lesson, but I find it so important that I have included it
here anyway. COM+ transactions are distributed transactions, and that means
they solve the problem of transactions when several resource managers (RM) are
involved. If you have only one RM in your application, using COM+ transactions
is overkill. You’ll save resources and get higher throughput if you go for
local T-SQL transactions instead.
OK, there is one more
situation where COM+ transactions shine, apart from the case of multiple RMs.
This is when your components have to interoperate with components that you
don’t know much about, yet you still want your components to participate with
in the same transactions. (Moreover, COM+ transactions provide encapsulation
and composition since you expose less of the transaction semantics and you
don’t have to send around connection objects.)
Because of the possible
need for integration (and because having to add one more RM might happen sooner
than you think), it’s always a good idea to program so that you can move from
local T-SQL transactions to COM+ transactions as easily as possible, if need
#4: UNIQUEIDENTIFIER Is a Great Datatype for Primary Keys
If we assume you favour
surrogate keys instead of natural keys in your database designs, you have
several datatypes to choose from.
Globally Unique Identifier (GUID) is, in my opinion, a great datatype for using
as primary keys. Yes, a GUID is largefour times the size of an INTand that could affect the search times.
Another disadvantage is that it’s hard to read and edit GUIDs when you browse
the database tables. Apart from this, you get the following advantages:
- They are not too
small for large tables.
- There is no risk
that you might choose to expose them to users and that the users will learn a
- The database
won’t have to maintain a counter. The work of assigning a key can be done at
the client or middle tier.
- They will be
unique, not only for the tables but for the complete database.
Since GUIDs are unique
for the complete database, there are several advantages, the most important one
being that you can construct a complete structure of, say, orders and their
orderrows (complete with values for the primary keys and the foreign keys) at
the client or in the middle tier, before sending it all to the database.
Microsoft has changed
the implementation of how GUIDs are created, so now they no longer use the ID
of the network card as one part of the GUID. Instead, the GUIDs are random
values so there is a theoretical problem of duplicate values. This risk is so
small that in practical scenarios, it’s not a problem.
#5: Separate Public and Private Stored Procedures
If you have started to
work with Visual Basic .NET, I’m sure you find it hard to go back to VB6, but
for most of us this is a must every now and then. What you see then is that VB6
is very primitive when compared to Visual Basic .NET. On the other hand if you
go from VB6 to T-SQL, the relative difference is much larger. T-SQL is outdated
in many ways, for example you can’t differentiate between public and private
stored procedures. I like to expose as little as possible to the outside,
because the less that is visible, the more I can change without the risk of
breaking other code. Therefore, I have decided on a naming convention, in order
to distinguish the stored procedures that are public. I prefix them with a_. Of
course this requires discipline, but contracts like this are pretty common.
Furthermore, if the client doesn’t adhere to the contract, he is at risk of
having his code broken when I decide to change a private stored procedure.
important to master T-SQL if you want to write scalable and efficient
applications, therefore we’ll have to work hard to overcome the worst
obstacles. In a forthcoming version of SQL Server it will be possible to work
with a managed language, such as Visual Basic .NET, for writing stored
procedures. I would also like to see Microsoft give T-SQL a face-lift, but this
might not happen.
#6: Often Skip JIT
In the "18 Common
Programming Traps in MTS" article, I was positive about using Just In Time
Activation (JIT or JITA) and as a concept, I’m still positive. What I mean is
to activate something when you need it, not several minutes before. However,
with regard to the technique in COM+, I’m now not so convinced that it should
be used all the time. When it comes to transactional components, you have no
choice but to enable JIT activation for your components. However, for other
components I have decided not to check JIT activation anymore. (Read Tim Ewald’s
great book "Transactional COM+" for a detailed discussion.)
Nevertheless, I still
think it’s a good idea to declare module-level variables at the client side for
COM+ components. At least do so when you want to call a method more than once.
You will then keep an instance alive at the server-side, but the relative
difference in memory consumption at the server-side is very small compared to
your COM+ component using JIT instead!
Also ensure that you
always code as if JIT has been used. Otherwise you can’t re-declare so that you
enable JIT without a lot of work.
#7: Remember the Difference Between Cheap and Expensive
Roundtrips are among
the worst enemies of distributed applications. Hunting and reducing roundtrips
is a sure way to increase performance. This is why I’ve been a
roundtrips-hunter for a long time, although I think I was hunting a bit blind
because I kind of tried to reduce all roundtrips, which is not important. What
is important is hunting the expensive roundtrips. If we assume you have a
design with three layers in one COM+ application it doesn’t cost you much at
all to make calls between those layers. On the other hand, each time a call is
needed to go out from the COM+ application to SQL Server, for example, or to
another COM+ application (which is a server-application), that is an expensive
roundtrip to be avoided, if possible. To sum up, try to reduce roundtrips (or
chatter) between processes and hosts as much as possible.
One explanation for why
I tried to reduce roundtrips between layers within a process earlier was that I
wanted to keep the flexibility of being able to split a COM+ application in
several COM+ applications (of server-type). I also wanted to be able to move
some of the components to another machine. In reality this seldom happens, and
if you find it absolutely necessary in the future, it would be better to
redesign, because you can’t prepare for all possible situations without getting
negative results now.
It is also better to
clone than to partition a COM+ application, which is yet another reason for why
you won’t get expensive roundtrips between your layers in COM+.