4.2 Reuse what others create

Reuse what others create

In today's world of software development, everything is moving extremely fast. At the same time, quality standards are raised constantly and more rapidly than in almost any other business. Customers expect new releases and updates more frequently and are less likely to tolerate bugs and quality leaks. New features become more complex and time-consuming to create. To make a long story short: You won't be able to do everything yourself and provide the quality expected. Not even software giants like Microsoft can. Visual Studio 6.0, for instance, shipped with a number of tools that were not developed by Microsoft, but by some third-party technology providers. And that's good! It helped to raise the quality of the package a great deal.

I encourage you to follow the same strategy. You won't be able to do it at the same level as Microsoft (by purchasing companies or entire products with all the associated rights), but you can use shrink-wrapped classes, components and frameworks. There's nothing better than cutting out weeks or months of development time by using a third-party component for $299. Sure, the component might not do exactly what you want, but chances are good that someone has created a class library that serves a similar purpose. By modifying it slightly, you might get just what you need. The beauty of this is that you can purchase a component that has been developed and tested and is proven to work. Of course, there are a number of components out there that might be quite buggy, but it's easier to evaluate components this way easier than to write bug-free code yourself.

Speaking of component quality, I often hear that people are concerned about the quality of the libraries they use. And they should be! After all, people depend on the vendor they trust. However, I believe the quality of most components is a lot better than the quality you can produce in your own classes. The reason is simple. Let's say you need a text editor in your application that allows editing text in multiple fonts, styles and colors. Writing such an editor is not a trivial task. Rather than developing such a tool in-house, where it would be one among 100 all of which had to be finished within a certain time and budget I'd rather use an editor developed by someone who specialized in the classes and most likely spent years on this task. To investigate the example a little further, I would like to add that creating specialized or complex components might require skills that the average development team simply doesn't have. The variety of tasks that must be accomplished during a development life cycle is simply too great to be mastered by a handful of people no matter how talented they are.

As you'll see in the next couple of sections, there is quite a difference between classes, components and frameworks. And even in these groups, the way things are done varies greatly. I'll give you an overview of different types of available class libraries and components, explain their differences, and tell you how you can customize different types of objects.

What is available?

The objective of this chapter is not to introduce a number of class libraries, components and frameworks, but to introduce different types of reusable classes and explain how to use them. They differ in the way you can use, subclass, and modify them. The tool that was used to develop these libraries also introduces a great difference. Classes programmed in Visual FoxPro can be used very differently from others created in Visual C++, Visual J++ or other tools that can create binary objects, simply because the underlying technology is different.

Besides the difference in applied technologies, there can be great differences in the design of the classes you want to utilize. Some might be entirely self-contained, while others require the environment to be in a specific state. Yet another type of shrink-wrapped classes might represent the global environment and will simply allow you to invoke your own classes inside this framework.

As you can imagine, the approach you take when dealing with different kinds of objects varies just as much as the underlying philosophies. In the following sections I'll introduce the most important groups of shrink-wrapped classes. Note that there is no "sharp edge" between those categories. Quite the opposite is true. A framework, for instance, might be made of black box objects.

Black box objects

Black box objects are entirely self contained, have a clear interface, do not rely on environmental settings and can live within any kind of environment or project (at least within the same programming language). Black box objects are ideal objects. They represent the main idea of object-oriented development and guarantee total reuse combined with ease of implementation. Obviously, creating black box objects isn't trivial; otherwise everybody would create them and we wouldn't need to discuss any other groups of objects. Let's investigate the markings of black box objects.

The requirement that black boxes must be self-contained, independent of other objects, and have a clear interface by themselves already sounds tough to fulfill; the more we explore the details, the more problems we encounter.

First of all, black box objects cannot depend on other objects in memory. However, objects typically require other objects otherwise they are useless. A form-manager black box object (which could be responsible for instantiating and managing forms, for example) would be useless if there were no forms, documents or even an application. A black box object must instantiate every object it depends on. All these objects (and related objects) therefore must belong to the black box object; otherwise there'd be an external dependency and the object wouldn't be a black box object anymore. For this reason, major base objects (such as a form manager and other manager objects) hardly ever are black box objects; they're usually white box objects (described later).

The next requirement for an object to qualify as a black box object is that it doesn't have any external dependencies regarding class definitions and inheritance trees. In other words, I should be able to simply drop a black box object on my design surface without worrying about setting any class libraries or placing them in a certain directory. This is difficult to achieve with Visual FoxPro VCXes or even classes that are defined in PRGs.

Yet another important quality of black box objects is that the programmer doesn't have to know about class internals in order to use them. This requires a very careful class design. A class must provide events and hooks (see Chapter 10, "Patterns") so it is flexible and easy to modify and subclass without having to know about the internals of the class. This also guarantees that, after redesigning the black box object's internals, everything that uses the objects will still work properly because the interface doesn't need to change therefore, all the provided hooks will continue to work.

By now, you might be wondering whether it's possible to create black box objects in real-life scenarios. Surprisingly, the answer is "yes." Good examples for widely accepted and used black box objects are ActiveX components. You can simply drop one of these controls on your design surface and you won't have to worry about the state of your environment, your path or other system settings, or any other objects the object needs, because it will take care of all these issues. Also, you don't have to worry about internals. For instance, I frequently use the Microsoft TreeView control, and subclass and modify it to my liking. To do so, I use provided events and hooks. I couldn't care less what the control does internally when the user expands one of the nodes, because there is a method that lets me hook into this event and react appropriately. Typically I would change the node's icon. Showing all the subnodes, however, is the responsibility of the object.

Another great example of black box objects are FoxPro's base classes (or at least some of them). Again, you can drop a Custom class on any kind of container or you can instantiate it all by itself. It has default behavior and hooks you can use. When you subclass a Custom class, you don't need to worry about class libraries being set and so on. FoxPro handles those issues for you. Many other Visual FoxPro base classes are black box objects as well CommandButtons, for instance. They can live in any kind of container as well as by themselves. It might not make a lot of sense to instantiate a command button that can't be displayed (as would be the case if you instantiated it by itself), but it works and therefore all the requirements are fulfilled. Subclassing command buttons works great. You can change their look and feel as well as button behavior. While doing that, have you ever worried about environment settings or other things the button depends on? Well, neither have I. Have you ever worried about the Click() event disappearing in a new release of Visual FoxPro? Neither have I. It's practically guaranteed that the interface won't change, even though the FoxPro base classes have undergone major internal changes since Visual FoxPro 3.0.

As you might have noticed, all the examples of black box objects share one characteristic: They are either native to the system (base classes) or somehow registered in the environment or in the operating system, using standards supported by your development environment (ActiveX). Purists might argue that this is yet another dependency, and therefore these examples aren't real black box objects. Well, I have to grant those purists a "gotcha." Looking at the situation from this angle, there aren't any real black box objects. But in this case, the term "black box object" is of no use in real life. I suggest we agree that the examples above are black boxes, which will allow us to use the term, and everybody will understand what we are talking about, shall we? All right!

White box objects

People usually are talking about white box objects when they say "black box objects." These objects are very well designed and encapsulated. They can live in almost any kind of environment as long as it fulfills some basic requirements. White box objects also have some external dependencies, such as inheritance structures or other objects that have to be in memory. In order to subclass and modify white box objects, you might need to know about class internals such as the method you have to overwrite or the property you need to set. White box objects don't necessarily have hooks or event methods you can use, but you can overwrite existing methods. For this reason, you need to know what those methods do and where you would put your own behavior, when to invoke the original behavior, and so forth. It also seems to be a common characteristic of white box objects that the interface and the implementation are not separated strictly. For this reason, you must be careful when changing properties because this could break some internal processes.

A typical example of a white box object is the form manager I mentioned above. You can drop it in every environment that uses regular Visual FoxPro forms that follow some basic (object) interface structures. The more complex the form manager, the more standards and rules must be set in order to make the white box object work. In the simplest form, a form manager would require top, left, height, width and visible properties as well as a standard way to instantiate and release a form. I would still call such a generic object a well-designed object. In fact, white box objects are the kind of objects we're really trying to create. Even though creating black box objects is a noble objective, they're difficult to create, and white box objects often fulfill our needs. Everything beyond white box objects can only be achieved with tremendous effort and the result typically isn't much more useful to the developer in a single-application environment.

Most frameworks are composed of white box objects. Every framework (see the "Framework" section of this chapter) has certain rules and standards that all objects within it must follow in order to work together. That's good design, although it makes it difficult to reuse many of the complex classes outside the framework. Keep in mind that the idea of reuse is applied on a larger scale when creating frameworks. The primary target is to create a complete object system that can be reused as a whole. Reusing pieces is a secondary target.

COM components

The term "component" is one of the most overused in object-oriented development. Often collections of loosely coupled class libraries of a generic nature are called components. However, I'll describe these kinds of components in the section titled "Class libraries." In this chapter, we'll talk about COM components, also known as COMponents.

COMponents can also be seen as binary objects. They can be created with a variety of tools such as Visual FoxPro, Visual C++, Visual J++ and even Visual Basic. As their name indicates, COMponents are based on Microsoft's COM (Component Object Model) standard. COMponents come in a variety of incarnations. Some are COM servers while others are ActiveX controls. Visual FoxPro can't create ActiveX controls but it can use them better than most other tools. One of Visual FoxPro's specialties is its introduction of inheritance for ActiveX controls.

Inheritance is not supported by Microsoft's Component Object Model. The fact that Visual FoxPro does support inheritance adds a great deal of flexibility and maintainability to ActiveX controls. For instance, you can use the Microsoft TreeView control, subclass it, change properties and methods, and even overwrite some of its predefined behavior. This is truly unique to Visual FoxPro. It allows Visual FoxPro programmers to utilize and customize more components than any non-FoxPro developer. But be aware that there are limitations to the ability to subclass due to some internal standards ActiveX controls follow. Every property or method that represents a single entity can be subclassed and overwritten at will.

However, some ActiveX controls store a lot of information in single properties or structures. An example is a toolbar ActiveX control that I use frequently. It comes with a great designer that allows creating multiple toolbars, popup menus, buttons that can be dropped in toolbars and menus, combo boxes, and more. All this information is stored internally in the control. When I create a subclass of the control and change some of the buttons or add new ones, this new information (again) is stored in one place. This is basically the same as overwriting a single property, but in this case the property contained a lot of information. The disadvantage is that not all changes made in the parent class will make it to your subclass because they are explicitly overwritten. This behavior is unfortunate and limits the ability to subclass ActiveX controls seriously. Luckily, only the most complex controls make use of this technology.

Well, because you bought this book you're probably interested in solutions, not new problems you weren't even aware of. I'll try to do my best: Whenever you use an ActiveX control's property sheet, its designer, or the interfaces it provides in the Visual Class Designer, you run the risk of storing information in complex properties and, as a result, ruining your ability to subclass properly. For this reason, I recommend defining as much as possible in source code. The toolbar control I described above is a good example. Instead of using its very good class designer, I define through source code all the toolbars, buttons and other controls it might host. The control has collections of toolbars, and I can simply call an Add() method to add new ones. The same is true for buttons and other contained controls. I can also programmatically load images. This, of course, requires that I ship all the required images with my application. Using the integrated designers, even the image's binary information is stored internally. Inheritance works fine with any kind of source code, because that source is managed by Visual FoxPro therefore you aren't limited by the control's internal design, which is most likely not prepared for subclassing. In fact, you are not really subclassing the control itself, but rather Visual FoxPro's ActiveX container class. The result is pretty much the same, except for the scenario I described above. Obviously, defining and decorating the control programmatically is not as straightforward as using the designers. For this reason, I go this route only when I really need to.

The reason for this limitation is not within the boundaries of Visual FoxPro, but rather can be found in the specification of the COM standard and the designs of the individual ActiveX controls. Keep in mind that most creators of ActiveX controls are not even aware of the fact that Visual FoxPro supports ActiveX subclassing, or they aren't aware of the power of inheritance and don't consider it a crucial part of object-oriented programming.

As mentioned earlier, ActiveX controls are a good example of black box objects. They are very easy to use you simply select an OLEControl from the Controls toolbar, drop it on a container, select a control, and voila, you're done. You don't have to worry about path settings, inheritance trees, and so forth. Even distribution is easy (as long as the creator of the control didn't put any traps along the deployment path). Visual FoxPro's setup wizards take care of all the issues. Now you also know the reason why I wanted to talk about COM components before discussing class libraries or frameworks those are simply a lot harder to use.

When you decide to use an existing ActiveX control, I highly recommend that you create a subclass of the control before you start working with it. The reasons are pretty much the same as for subclassing Visual FoxPro's base classes, but there are some additional reasons. The most important one is that you can easily switch to different controls. It might not be obvious why you'd want to do that, so I'll give you a quick example: Basically with every version of Visual FoxPro, Visual Basic or (lately) Visual Studio, Microsoft has released a new version of the Common Controls a collection of controls that represent standard Windows interface elements, such as the TreeView or the ListView control. Unfortunately, it turned out that different versions of these controls were not compatible with each other. So it's possible that a new version of Visual Studio could break all your forms and containers that use this control. When you try to modify such a container class, FoxPro displays an error message about an invalid or unknown control, and then it simply ignores all the code and property settings you created for these controls. In other words: Your code is gone! You now have to re-code all these classes. From my own experience, I can tell you that this is a frustrating experience. But if you had a class for those controls, you could simply make modifications to the class, and all the subclasses would be updated according to your changes.

Unfortunately, there are a couple of limitations that can ruin this relatively friendly scenario. Sometimes a class remembers the old Global Unique ID (GUID), also known as the Universal Unique ID (UUID). In this case the old version of the control might be invoked instead of the new one. This can result in a situation that's well a mess. Some programmers code all ActiveX classes in source code for this very reason. Most people don't even know that's possible, but it is rather simple. Here's a simple example that demonstrates how to subclass the TreeView control in source code:

DEFINE CLASS oleTreeView as OLEControl

OleClass = "COMCTL.TreeCtrl"

ENDDEFINE

The OleClass property specifies the ActiveX control you want to subclass. The value is the control's name as found in the registry. The class I referenced above is stored in the following key:

HKEY_CLASSES_ROOT\COMCTL.TreeCtrl

If we explore this structure a little further, we find a sub-key called "CurVer". The default value stored in this key identifies the most current version of the TreeView control installed on the system. In my case, this is "COMCTL.TreeCtrl.2", which is the TreeView that ships with Visual Studio 6.0. You can find this key right after the tree we referenced in the registry. So whenever I specify "COMCTL.TreeCtrl" as my OleClass, I'm redirected to "COMCTL.TreeCtrl.2". In future versions, this might be "COMCTL.TreeCtrl.3". I think you get the idea

However, this might cause a problem. What if "COMCTL.TreeCtrl.3" is not compatible with "COMCTL.TreeCtrl.2"? Well, your application wouldn't work anymore, but luckily you can specify the exact version of the TreeView control you want, like so:

DEFINE CLASS oleTreeView as OLEControl

OleClass = "COMCTL.TreeCtrl.2"

ENDDEFINE

The difficulty now is to know in advance whether future versions of this control will be compatible with the current one. It's obvious that you can't (unless you're a good psychic, and I'm pretty sure even they have a hard time predicting what Microsoft plans to do next regarding the common controls). I recommend always using the most current version that's installed on the system, but I urge you to define this in a very flexible way, so you can fix the problem quickly if a problem emerges. If all your TreeViews are subclassed from one TreeView class (which is the proper way to do it), this is easy. You just change the OleClass property in that class, recompile, and you have your fix. If you have multiple TreeView classes, I recommend defining the name in a header file like so:

* Contents of ActiveX.H
#DEFINE REGKEY_ACTIVEX_TREEVIEW "COMCTL.TreeCtrl.2"

* Contents of your PRG file

DEFINE CLASS oleTreeView as OLEControl

OleClass = REGKEY_ACTIVEX_TREEVIEW

ENDDEFINE

This allows you to change the name in one place and fix all its occurrences with a simple recompile. Note that the example above shows partial contents of two different files as indicated by the comments.

Unfortunately, there is a catch! Since Visual Studio 6.0, many controls (especially the ones from Microsoft) require a license file whenever one tries to create or subclass ActiveX controls in source code. Since you have Visual Studio or at least Visual FoxPro on your computer, you have all those licenses, but when you install your application on the computer of a customer who doesn't have Visual Studio, the instantiation of those controls will fail and result in an error message. In this case you'll be trapped again, because you now have to rewrite your control in visual classes. I have some applications where I changed from source code to visual classes and back four (!) times. By now I have them all in source code, and once again I need to rewrite them as visual classes. Needless to say, this is not a motivating experience. Unfortunately, I don't have a good solution for this particular problem (obviously otherwise I wouldn't need to rewrite my own classes). I can only recommend testing whether a simple scenario runs on a "clean machine" (a computer that doesn't have development components or Visual Studio installed) before you decide which way to go.

Let's have a quick look at some of the settings in the registry. Every key representing an ActiveX control has a sub-key called CLSID. This is the class ID. Its default value is the GUID that identifies the class. Web pages, for instance, use this ID to reference an ActiveX control rather than its name. You can use this ID to identify required OCX files on your hard drive. Simply use the registry editor's Find feature to search all the occurrences of this ID. This will eventually lead you to a key (rather than a value) of the same name. On my machine, the path to this setting (for the TreeView) is this:

HKEY_LOCAL_MACHINE\Software\CLASSES\CLSID\{C74190B6-8589-11D1-B16A-00C0F0283628}

This key has a sub-key called "InprocServer32". Its default value is the file name of our ActiveX control (it usually is either an OCX or a DLL file). This information can be useful if you are using a setup tool other than the one provided by Visual FoxPro, or if you simply need to know what controls you used in your application (and the files representing these controls).

Class libraries

Class libraries are a collection of classes, in this case written in Visual FoxPro. These classes can perform a great variety of tasks, but that's not the subject of this section. Instead, I'll discuss the different kinds of class libraries as well as how to use and subclass them.

Class libraries can be delivered as VCX files, as compiled applications (APP), or as raw source code in PRG files. Each version has its advantages. VCX files are typically class libraries that provide some kind of interface, such as forms, containers or buttons. PRG files are often used for middle-tier programming (see Chapter 9). Internet applications are a good example. The PRG format is a little more difficult to handle, but it also offers some performance advantages. APP files have the advantage of being self-contained. It's easy to instantiate a class that's defined in a compiled application because you don't have to worry about path settings and so on. On the other hand, they are a little confusing to subclass and reuse. You can't just drop a class from an APP file on your form or container. The APP format has a big advantage for third-party vendors, though, because it allows them to efficiently hide source code. This is a problem for most providers. Obviously they are interested in protecting their code. Would you want to sell several hundred thousand lines of source code for $149?

No matter what flavor the class library comes in, I urge you once again to subclass all the classes you want to utilize, rather than using them directly. The reasons are the same as for FoxPro base classes and ActiveX controls.

Whenever you want to change some behavior, do it in your subclass. Never modify the existing code. If you don't do this, it will seriously limit you further down the road. Also, never store your subclasses in the same physical file as the original class. As soon as you touch the original files or code, you won't be able to use any updates or bug fixes that the creator of the original version might have for you, because those updated versions would wipe out your changes and you'd have to start over. Not a pleasant scenario, I think. Especially when you consider the simplicity of the solution: Never touch what's not yours! It always surprises me how often this simple rule is violated, and I'm amazed at the kind of trouble people get themselves into just because they don't believe the importance of this point!

 

Frameworks

Frameworks are the underlying architecture of your application. They define standards that must be followed throughout the project so all the classes can work together. Many different entities form a framework. Manager classes handle interface instantiation, security issues, errors and exceptions, online help, and more. Mediator objects (see Chapter 10) handle the message flow in the application. Most frameworks have standard interface components that handle user login, document operations such as New, Open and Close, administrative tasks, and so forth.

All framework components have one thing in common: They handle tasks that are not related to the business problem. Typically those are technical issues, such as form instantiation or error handling. A couple of years ago I read that 80% to 85% of all programming tasks are concerned with technological issues rather than the problem domain. This was when I still used Microfocus COBOL a lot has changed since then, but the majority of programmer tasks still involve resolving technical issues. Some say the current number is somewhere between 60% and 70%. My personal experience seems to back that, but I don't have an accurate source to prove it.

Sixty to 70 percent is a pretty sad number, considering that most software projects started today will go into service in the 21st century! Just imagine if we could skip that 60 to 70%! Eighteen-month projects could be done in half a year! Six-million-dollar projects could be done with $2 million and you could pocket the rest! Unfortunately this is science fiction, but reusing existing frameworks can cut your development time tremendously perhaps in half or less. That's a pretty good reason for me to reuse frameworks, or better yet to buy frameworks from third parties. The variety of Visual FoxPro frameworks is great. All areas from low-price application-maker type frameworks to high-price advanced object-oriented frameworks are covered. Before you decide to go for one of the available products, make sure to evaluate what you're about to purchase, because you'll have to live with the underlying philosophy from this point on! You can create your own classes or reuse other class libraries and COM components inside the framework, but you always have to follow the basic rules the framework sets. You're also stuck with the limitations of the framework. Sure, you can always customize the framework if you have the source code (which usually is the case), but then you couldn't switch to newer versions of your framework. This basically is the first step to doing all the framework modifications yourself, from this point forward. Eventually you'll end up with your own framework again, and there you go: 60% to 70% of your work is related to technological issues again. The only difference is that you're still stuck with a framework that's not really your own and that is carried by somebody else's ideas, which you don't really like because that's why you started to modify the framework in the first place.

The kind of framework you choose depends on the kind of project you are working on. If you need to create a ready-to-go application within a couple of months and you are a one-man-show, you want a low-price framework that has a built-in application wizard that automates the most important steps and guides you through the process of creating your program. If your project is scheduled for release in 15 to 20 months, you have a development team of four people or more, and the system needs to be highly flexible, extremely powerful and must run on various platforms utilizing different kinds of interfaces and data back ends, you should look into something more advanced. More advanced frameworks are usually harder to handle, require more knowledge of object-oriented technology (but by the time you finish reading this book you should be ready for that) and you'll need quite a bit of training to fully understand what the framework does. The framework provider should also be able to send consultants if you need them. Of course, you can also expect this kind of framework to cost a pretty penny. Providers that create such specialized frameworks aren't after the mass market. They are targeting a handful of advanced projects. They also have to give a great deal of support. For this reason, such a framework couldn't possibly be cheap. But let's assume you purchased such a framework for $50,000. That sounds like a lot of money, but just estimate the costs of having half a dozen highly skilled developers working on the framework for 60% to 70% of the time during your 18-month project. And then there is always the risk that your own framework doesn't fulfill the expectations. Well, you do the math!

Once you know what kind of framework you're looking for, you'll still have a couple of competing products to choose from. Often people ask me what the perfect third-party framework would be, and I always have to give the oddest of odd answers: "It depends." But it's true! Just consider this example. Every application has a framework the military's Desert Storm application, John Doe's record database, and standard applications such as Word, Excel or even Visual FoxPro. It should be obvious that there couldn't be a perfect framework that matches the needs of those different applications. As Visual FoxPro programmers, we usually create applications that are somehow related to databases; the differences aren't as obvious, but that doesn't mean they aren't there.

Before buying a framework, you need to evaluate its strengths and weaknesses and whether you like the way things are done. This can be a time-consuming and difficult task because you have to judge something you don't really know. Before you start playing with a framework, I recommend taking some classes on it, or at least attending demonstrations or watching a video (if such things are available). This will give you an overall idea of what the framework does and how. From this point on, you can start to explore the product yourself. This might sound like a huge effort from a time and cost point of view, and I agree, but wouldn't you rather spend some time and money evaluating a product before you bet the future of your company on it?

Once you make a decision and start to use the framework, the rules are the same as for using class libraries. Make sure you don't change existing code. Only reuse or subclass it.

Complimentary tools

No matter what kind of shrink-wrapped classes you use, you will always appreciate some standard tools to guide you through the basic steps of the most important tasks. This will give you a jump start and speed up time-consuming standard tasks. The variety of such tools is great. Some tools (typically frameworks) come with their own integrated development environment (IDE). Usually they have application wizards, project managers and various builders. Other products come with basic wizards. The least I'd expect are some good samples, or a catalog for the Component Gallery (see Chapter 5).



Advanced Object Oriented Programming with Visual FoxPro 6. 0
Advanced Object Oriented Programming with Visual FoxPro 6.0
ISBN: 0965509389
EAN: 2147483647
Year: 1998
Pages: 113
Authors: Markus Egger

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net