In order to understand the true powers of Outerfacing, let’s examine two implementations of a check register program. One is implemented using Visibility for C++ Windows Edition, which is our initial product based on Outerfacing technology (see Check Register example for source code). It is aimed at C++ programmers developing O-O systems for Windows. The other is implemented using the MFC application framework (See CHKBOOK example included with Visual C++ or located at MSDN website).
Figure 1. Check Register User Interface
Figure1 shows screen captures of the two check register programs. Now, you’ll notice that both of these programs have similar interfaces. They both have menu bars, tool bars and status bars. They both have an entry area for new checks, and they both have a register list of entered checks. Since both of the programs perform the same task and have similar UI’s, you might expect the amount of code required to create the two would be about the same. Or, that the Outerfacing example would require more code given its more sophisticated interface. In actuality, nothing could be further from the truth.
Figure 2. Check Register Source
Figure 2 shows snapshots of the two program listings. As you can see, the MFC example contains quite a bit more code than the Outerfacing example. In fact, the one implemented with MFC required 36 pages of code (consisting of 968 program statements), while the one implemented with Outerfacing only required 14 pages of code (consisting of 338 program statements). That’s almost three times as much code to do it the old-fashioned way!
A line-by-line analysis of the two programs shows that 66% of the program statements in the MFC example are devoted specifically to creating the UI, whereas in the Outerfacing example, there is not a single line of UI code. To understand how this is possible, we need to examine the relationship between the functional portion of the check register program (where the data is stored and manipulated), and the visual portion of the UI (where the data is visually represented) for each of these programs.
The concept of the checkbook program is very straightforward. We’re trying to keep track of our account activity: what checks we’ve written; what deposits we’ve made, and what our current balance is. Using object-oriented programming techniques, we can easily create an object-oriented system that represents a check register. It would consist of the following three object classes:
1) A Transaction class, which represents checks and deposits
2) A Register Entry class derived from the transaction class, which represents an entry in the check register.
3) A Check Register class. It would consist of a list of register entries, the current balance, and a means to add a new check or deposit.
Figure 3 shows a C++ program based on these three classes. You’ll notice it is a relatively small program, consisting of only 11 pages. It could have easily been written by anyone who’s taken a basic course in C++.
Figure 3. Check Register O-O Implementation
Because this is an objected-oriented program, once compiled and executed, we will have a computerized object model, which in both form and function accurately represents a check register. However, there is only one small problem, and it is one that has been encountered by every programmer who’s ever written a program. And that is, at this point in time, there is absolutely no way for a user to interact with it.
So, how do we go about creating a user interface for this program?
As we’ve shown you with the MFC example, we will need to add another 26 pages of code to create the user interface. That’s over 250% more code! Due to the excessive code requirements placed on us by the UI, the focus of our programming effort shifts from that of simply creating an object-oriented model of a check register to creating a UI program. And as is often the case, the underlying object system gets gobbled up and devoured in the process. In the MFC example, the original object system that consisted of 3 classes has been replaced by a check register user interface application that consists of 10 classes (fig. 4).
Figure 4. MFC Check Register Structure
Note that these 10 classes are derived from the MFC class library, which makes this primarily a MFC user interface program, not the object-oriented program we were originally interested in. Moreover, because of the complexity of the MFC class library, it requires a very highly skilled programmer to write these pages of code.
Looking at the code breakdown shown in figure 5, we see that large blocks of code have been devoted to creating the user interface elements of the check register, with the code to perform the functions of the register interspersed throughout. Every aspect of this user interface is the end result of the code written here. If we want to change any aspect of it, then we will have to rewrite the appropriate code to make the required changes.
Figure 5. MFC Check Register Code
Because we no longer have our original object-oriented system, there is no code directly relating to the underlying concept of a register that can be reused. Instead, any reuse of this example would result from hacking out appropriate portions of code and reintegrating it into another program. This is hardly the type of reuse that one expects when talking about object-oriented programming.
In order to get true object-oriented reuse, we need to use a technology such as Outerfacing.
Figure 6 shows a snapshot of the program listing for the Outerfacing example. You’ll notice we still have our three original classes, with no additional classes added. We have added a few lines of special code, called “instrumentation” code, to each class. This code provides the programmatic support necessary for the objects to be visualized.
Figure 6. Outerface Check Register Code
The instrumentation code does not create specific user interface elements, and it only increases the overall program size by 2 pages. As you have already seen, this code is not very complex and can be written by any basic level C++ programmer.
In addition to the Instrumentation code, we also added a WinMain function, which enables this object-oriented system to be executed as a Windows program, and it is the only piece of code that ties this program to the Windows platform. Now, instead of having a user interface which is a result of writing and executing 26 pages of user interface code, we have an instrumented object-oriented system which can be visualized and interacted with directly.
Exactly how the user interface looks is determined by defining and interactively laying out visualizations of our object classes. This allows us to create any visual representation of our object-oriented system that we desire.
In our earlier example, we created our user interface by defining the following visual representations of our object classes (fig. 7). The check entry area is a representation of the transaction class with appropriate controls to represent its data members, and the register list entries are representations of the register entry objects. The menu bar, tool bar and status bar are all representations of the check register class, as is the overall register view.
Figure 7. Outerface Check Structure
Because we haven’t had to change the structure our original object-oriented system, all of our classes can be reused in other programs. And, because there is a one-to-one correspondence between the visual representations and the objects they represent, all the visual representations we’ve created can also be reused in other programs. Neither of which is remotely possible with current technology.