Abstractions
Abstractions are the cornerstone of any successful program. An abstraction is a blackbox, wrapped around some very complex real-world mechanism. This magical blackbox allows us to use it, without dealing with the actual complexity that goes on inside.
For example, characters are abstractions: There is no character data type in the real world, since characters are actually just integer numbers. They’re wrapped in a mechanism which takes the number, compares it to an ASCII table, and outputs the correct symbol. You can peek inside the blackbox with the ASC VBScript command, which reveals the integer code of a character.
The real world mechanism is complex, but we are presented with a blackbox called character data type, and we can use it in a variety of ways without ever wondering what goes on inside that blackbox. That’s the whole point of an abstraction, it takes a piece of reality, and makes it simple enough of us to use it (Actually, even integer numbers are abstractions, since the computer only "knows" binary numbers, and so on up to the actual CPU machine code).
Abstraction Leaks
A more advanced abstraction than characters is a string, which is actually quite a monstrous mechanism, holding dynamic memory addresses, linked chains and filled with boxes which hold characters. But we don’t care about all that – we have a wonderfully constructed blackbox, which allows us to simply write sString = "Hello", and go on with our business.
But are things always this easy?
We need to remember that we ALWAYS lose something when we abstract. Well, if the real world could be fully encompassed into a simpler blackbox, we would’ve just written the blackbox in the first place. Now, if your abstraction is good enough, the information you lose won’t come into play in the everyday use of the abstraction. We don’t really NEED to know where exactly the "el" part of "Hello" is stored, so losing this information isn’t really a price we pay.
However, sometimes we do need the information we’ve lost, and we’re forced to break the blackbox, and get our hands messy with the real world mechanism behind it. This is called an Abstraction Leak – meaning the real world has leaked through the blackbox, into our program, limiting it, or just making it messy and ugly.
For example, in C, strings can be of any length you’d like, with the end flag ‘\0′. This means that you cannot build any string with the special char ‘\0′ in it. This is an abstraction leak, because the limitation comes from the real-world mechanism behind the blackbox. Even worse, in order to get the length of our string, we have to loop through all of it, until we reach the end flag. This means that almost all the common string operations take tons of time.
We could get around this by building a different abstraction for strings. In Pascal, a string’s first character actually holds the length of the string (that is, in the real world. We can’t see that character if we use the abstraction). This way, all operations that use some form of length calculations are blazing fast (they use one read command, regardless of the string’s length). As a bonus, we can now have strings with any character, including the magical ‘\0′. However, this abstraction also comes with a price – because ONLY the first character is reserved for storing the length, it cannot be more than 255 characters.
So when you work with excel (which extensively uses Pascal strings for their speed), and you wonder why a cell can’t hold more than 255 characters, know that it’s because of an abstraction leak in Pascal strings.
Abstractions in QTP
Well, as interesting as strings abstraction leaks can be (here, and here), we have bigger fish to fry – QTP.
QTP has many different levels of abstractions. When it comes to operating UI objects, the good people at Mercury have done an amazing job. They’ve build a framework of abstractions with tons of benefits, and little shortcomings.
In the real-world, the mechanism for attaching to an external application in extremely tricky, while QTP gives us a neat, simple blackbox which recognizes object, attach to them, and can operate them with staggering success rates.
Over this basic layer, they’ve build two more abstraction layers. The more advanced one is a set of standard "shells", which wrap around recognizable objects in the application. So no matter what type of combo-box an application uses, as long as QTP can recognize it, you can be sure that you can operate it with a standard .Select command.
The second layer is a backup for the more advanced one. Even if QTP doesn’t recognize your combo-box as a "standard" combo-box, you can still attach to it, and manipulate the actual run-time object. This is done by using the .Object property, which exposes the object’s run-time properties and methods.
There are even more sub-layers and inner abstractions, but the main point is, that when it comes to object manipulation and identification, QTP is practically unmatched in both the power of its abstractions, and their simplicity.
This is all very good. However, QTP doesn’t stop there. It offers us a framework that is supposed to map the application’s structure and inner logic. For example, part of this framework is the OR. It is structured as a tree, intended to mimic the real-world structure of the application. This is an abstraction (we don’t see all the tiny sub-levels in the tree), but it still retains some information from the real-world (the sub-level aren’t floating in mid-air, they’re connected to their parent).
Abstraction leaks and QTP
This is exactly where QTP bites more than it can chew. It presents us with a nice package, and claims that everything we need to know about the outside world is in our hands. But as it soon becomes clear to any QTP novice, the abstraction is just too simple to be useful.
QTP does a wonderful job and abstracts each and every text field in the application to a "standard" VBEdit. Does this means that these fields are similar? Are they all mandatory fields? Can they all hold the same data? What if one only accepts E-Mail addresses, and rejects any other string format? Maybe one of the fields is disabled until another field is filled? Is there a save button, or can we just move onto the next field?
These are pretty moderate questions. Usually the amount and importance of the information lost in the QTP abstraction is far more extensive and severe. Since the QTP objects don’t posses the necessary information, we have to introduce it through the back door – our functions and actions. This means that we’re forced to open the blackbox QTP shows us, and get our hands messy. We’ve seen this type of thing before – it’s an abstraction leak.
The price of abstraction leaks in QTP
One of the more common ways to implement the missing information in our functions and actions is through IF structures (or their counterparts- Select-Case structures). So if QTP won’t tell us if the field only accepts E-Mails, we’ll hard code an IF structure which decides what to input the field with according to the field’s name.
So pretty soon we get very complex, messy, hard-coded IF structures in almost every function. These IF structures compensate for QTP’s abstraction leak – we use information from the outside world to complete the information provided by QTP’s abstraction layer.
As with any abstraction leak, things get very messy, very soon. These IF structures only get more complex, and more frequent throughout our code. The code gets more and more bloated, up to a critical point where even a minor change in the application results in hours or days of code fixes for the automation team.
This is the time to wake up and smell the bad news: The QTP abstraction layer sucks big-time. It simply doesn’t carry enough relevant information from the outside world. So it does an amazing job at recognizing objects, but a poor job at anything else.
Designing a new abstraction layer
The solution is, naturally, to build a better abstraction layer ourselves. One that uses QTP’s object-identification powers, but deals with the applications structure and inner-logic on its own terms.
With this layer, we could get just the right amount of information from the outside world to keep our functions and actions clean, generic and simple. We would have to make sure, that we balance the need for more information, with the need for simplicity and elegancy.
In the following weeks, I will lay out the grounds for my own pitch for an abstraction layer that could do the trick. We will examine it closely both theoretically, and practically, and hopefully we’ll produce a worthy alternative to the current state of things.
An prelude to this design was hinted in a previous article, though naturally the abstraction will be much more ordered and generic.
Posted in Code Design

Yaron Assa



