Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

COM+ centric Assert

In this article Jimmy proposes a way of taking care of assertions instead of using the Debug.Assert found in VB. The technique Jimmy shows will work even after deployment. The assertions will be shown with COM+ specific constructs and there will be some thoughts about how to take the assertions to the next level.


advertisement

INTRODUCTION

In my latest article here at VB2TheMax, I showed my code structure for COM+ components (Example of code structure for COM+ component) in preparation for a couple of debug centric articles. Now it’s time for the first of those, but be sure to have the code structure in mind when you read on, because I assume this.



If you expect a variable at a certain place to have a value between 1 and 4 for example, you can express that fact in the code. As you probably know, the Debug-object in VB has a method called Assert, which you can use to test your assumptions. Unfortunately, that method will not be compiled into the executable, and that makes the method useless in my opinion.

Well, I’ve seen two good ways to use it:

  • Francesco Balena showed in his weekly e-mail from VB2TheMax that you can use Debug.Assert False to get a persistent breakpoint in your code, so avoiding problems with the Stop statement.
  • Peter Morris describes in his book "Advanced Microsoft Visual Basic 6.0, second edition," which he co-wrote together with others from the company The MandelBrot Set, how you can use Debug.Assert to determine if you run the VB code from within VB’s IDE or as an executable.

That’s it as far as I know, but that was of course not what it was supposed to be used for. So what was the real intention?

THE BASIC IDEA

Even if Debug.Assert had been the perfect tool, where should you use it in your source code? Randomly? Don’t you want to have a plan instead? Yes, you do!

Let’s take a step back. In another programming language called Eiffel, created by Bertrand Meyer, a concept called Design By Contract (DBC) is used to a large extent. (To read more about Eiffel and DBC, read Bertrand Meyer’s book "Object-oriented software construction, second edition.") The idea of DBC is to set up contracts between consumers and servers. (A consumer uses a class and its methods, a server is the class.) The server says what he expects (Require) and what he promises (Ensure). The consumer promises to fulfill the server’s expectations, otherwise the server doesn’t have to fulfill his promises.

Assume that you are the consumer and the Post Office is the server. The contract between you and the Post Office is that you want them to deliver a certain item of snail-mail to the correct person. For you to get that service, they expect to receive the mail before 5 pm today (I live out in the countryside), there should be a valid stamp of the correct value on the envelope, and the correct address must be written on the envelope. (And so on, you get the picture...) If all this is fulfilled, the mail will be delivered correctly to your friend and on time. Hmmm... Perhaps this wasn’t the best example, at least not when it comes to the "company" that takes care of this in Sweden.

(OK, I know. You don’t have to write a contract for this situation. Not even in Sweden.)

What we want is to transfer this contract-thinking to software construction. The software can check itself to see if any nasty bugs have been introduced, and the contracts, which are often implicit, will be made explicit to show which part is responsible for what. That way, you can avoid defensive programming. (In defensive programming everything is checked everywhere. Both the consumer and the server must check the value of the parameter. With DBC, the server can set a requirement and then expect that to be OK. Only the client has to do a test and the server doesn’t. That way the code will be as robust, but with much fewer lines of code. And the number of code lines is often directly correlated to the number of bugs!)

(By the way, it seems that Eiffel is having a renaissance right now, at least when you consider how often it’s mentioned in the Microsoft community compared to earlier. I guess it’s because it has been mentioned as one language that will support the Common Language Runtime (CLR) in .NET, but probably also because it’s a very solid language even though it isn’t new at all.)

To make the whole thing a little bit more concrete, a method called Deliver in a Mail delivery component could look like this:

Public Sub Deliver(ByRef robjMail As SnailMail)
  'Require------------------
  If Not OnTime(robjMail.DeliveredAtPostOffice) Then
    Err.Raise errSomeCode, "", _
    "Consumer didn’t fulfill contract"
  End If
  If Not Correct(robjMail.Address) Then
    Err.Raise errSomeCode, "", _
    "Consumer didn’t fulfill contract"
  End If
  If Not Correct(robjMail.Stamp) Then
    Err.Raise errSomeCode, "", _
    "Consumer didn’t fulfill contract"
  End If
  '-------------------------

  'Do the real delivery stuff
  '...

  'Ensure-------------------
  If Not CorrectlyDelivered(robjMail) Then
    Err.Raise errSomeCode, "", _
    "Server didn’t fulfill contract"
  End If
  '-------------------------
End Sub

This is one possible way of approaching it, but there are obvious problems with it. At first, there will be a lot of overhead during execution. Will you like having all this executed in a component when it has been eagerly tested and used for a long time? Probably not. OK, it’s easy to delete the code. But then you don’t have your contract left or the automatic bug-detection system ready when it’s time to create a new version of the component.

A PROPOSAL

You could use Debug.Assert above, instead of If and Err.Raise. A check would then look something like this:

Debug.Assert Correct(robjMail.Stamp)

(Perhaps you wonder what Correct() is? Imagine a very smart function that returns True or False.)

It’s much cleaner, and it won’t give any overhead except when you run your code in the IDE. On the other hand, there are bugs that won’t be visible when you run the code in the IDE and if that’s the case with your code then you have a problem because your assertions (or contracts) won’t help you.

There are several solutions to this. My proposal is to call a custom sub instead in this manner (this time with another, and commoner, logical expression):

jnskAssert vintTmp > 0, "vintTmp > 0", _
strSource, mobjCtx

The first parameter is the logical expression and the second is the same expression, but as a String. The third parameter is the source from where the call was made and finally, the last parameter is a reference to the ObjectContext.

You should have the calls as you saw earlier in sections for Require and Ensure. Of course it’s fine to use it in other places in your code too, but this is where to start. So, where is the proper place for Require and Ensure in the code structure I presented in Example of code structure for COM+ component? Here is my proposal. Note that the only lines from the code structure article are the On Error Goto ErrorHandler and the ExitHandler: lines, but they should be enough to get the picture.

  '...
  On Error Goto ErrorHandler
  'Require------------------
  jnskAssert vintTmp > 0, "vintTmp > 0", _
  strSource, mobjCtx
  '-------------------------
  '...
ExitHandler:
  'Ensure-------------------
  jnskAssert lngReturn >= 4, "lngReturn >= 4", _
  strSource, mobjCtx
  '-------------------------
  '...

The jnskAssert sub that I keep in an ordinary code module could look something like this:

Public Sub jnskAssert(ByVal vbol As Boolean, _
ByVal vstrStatement As String, _
ByVal vstrSource As String, _
ByVal vobjCtx As ObjectContext)
  #If jnskDebug Then
  Dim strTmp As String

  'Is application configured for
  'having assertions checked?
  'More info in an upcoming article.
  'Do...

  If vbol = False Then
    strTmp = "Assert broken in " & _
    vstrSource & ": " & vstrStatement

    'If in IDE, give message as msgbox,
    'otherwise in trace and log.
    If IsIDE() Then
      MsgBox strTmp, vbInformation
    Else
      'Send trace-message of assert-type.
      'More info in an upcoming article.
      'Do...

      'Write to error-log.
      'More info in an upcoming article.
      'Do...
    End If
  End If
  #End If
End Sub



Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap
Thanks for your registration, follow us on our social networks to keep up-to-date