Back

Designing Your Own Framework

Jim Booth

Overview

What we will see

Designing a framework is not a small undertaking. There are many considerations to be addressed by the design. Using an effective design can mean the difference between success or failure on a development project.

In this paper we will discuss the major points and issues related to the design of an application framework. The high points are listed below.

  • Establishing Requirements
  • Determining the Scope of the framework
  • Abstract Design
  • Designing Class Hierarchy
  • Making a Framework Flexible

 

What we will NOT see

One of the major problems encountered in object oriented design is being so caught up in the detail of implementation that the whole picture cannot be seen. This paper will circumvent this problem by NOT discussing the details of implementation, but will instead focus on the abstract design and the issues involved with that design.

Issues and items which will not be discussed are;

  • Specific Code
  • Specific Class Definitions
  • Specific Third Party Frameworks

 

What is a framework?

It is the underlying skeleton upon which an application is built. A framework has certain responsibilities in the functioning of an application. These responsibilities are;

  • Menu Management
  • Form Management
  • Security Management
  • Communication Management
  • Data Access Management

 

Establishing Requirements

Probably the one most influential factor governing the success or failure of an application framework is identifying the problem you want to solve. If you set out to solve the wrong problem you will, most assuredly, end up with a solution that is wrong for your needs. Trying to fit an application into a framework that is working against you is not a pleasant task.

Regardless to whether you are building your own framework or evaluating one of the many commercial frameworks available, you need to know your requirements clearly if you want any chance of being successful.

Below is a list of questions you need to answer in order to begin identifying your requirements.

  • What kind of applications do you build?
  • What kind of data sources do you require?
  • How do you prefer to use Visual FoxPro?
  • What kind of user interface do you use?

What Kind Of Applications Do You Build?

Since the framework supplies the skeleton for your application, the type of application will influence the way the framework should be structured. There are many different types of applications that Visual FoxPro can be used to build including accounting, decision support, line of business, research, marketing, scheduling, and others.

Each of these application types would require a different type of interaction with the user. Each type of application would have its own major requirements on the framework and the desired behavior for one may be a detriment to another. If you are building a decision support application the requirement for managing data saving and editing versus viewing modes for forms may just get in your way. In this case the framework that fits best would be one that was designed for decision support systems and not for accounting or line of business systems.

A framework can be designed to meet the requirements of more than one of these application types, but that needs to be specifically part of the design of the framework as well.

What Kind Of Data Sources Do You Require?

If your framework is going to be helpful in managing the mundane tasks associated with data management then it has to handle the types of data you will be using. You may be using one or more of the following data sources in your applications; local DBFs, local views, remote views, or Internet/Intranet data sources.

A framework that is "everything including the kitchen sink" will become overly burdensome very quickly if you only use local DBF tables for your data source. However, if you use the Internet and remote views then a framework built to handle only local tables will fall way short of meeting your needs.

How Do You Prefer To Use Visual FoxPro?

Frameworks are comprised of many parts and these parts have requirements that are placed on the other parts of the framework and on the components of the application. These requirements are called contracts.

When you select, or build, a framework there will be a method prescribed for building your forms and the other parts of your application in order to allow the framework to function correctly. For example, the framework may require that your forms are built as classes in a visual class library rather than as forms in the form designer. This may or may not be a problem for you. Perhaps you prefer to use the visual dataenvironment designer in the visual form designer, well if your framework requires forms as classes then the visual dataenvironment designer is not an option for you.

If you make heavy use of pageframes or grids in your interface then you should be sure that your framework will provide good support for these containers.

What Kind Of User Interface Do You Use?

User interfaces come in all sizes and shapes, mostly bad. Let’s put that point to the side, this paper is about frameworks and not user interfaces.

Your applications may present themselves to your users in one of a variety of ways. There are process centric, data centric, and goal centric approaches to this presentation. Process centric applications focus the user on the processes that are done like creating invoices, or applying cash receipts. Data centric applications orient the user to the data they work with, these types of applications ask the user to specify the file they are interested in and then let the user manipulate or edit the records in the chosen file. Finally, goal centric applications focuses the user on their goals and presents activities that are goal directed.

Your framework will very likely be in your way if it is data centric while you are building a goal centric application.

 

Determining the Scope

In observing a number of frameworks, both commercial and custom built, the single most common problem I have seen is that the framework goes too far. When a framework tries to be more than the skeleton for your work it gets in your way. A framework is NOT an application wizard!

Imagine you just bought a new car and you are ready to drive it off the car lot. You get in, put the key in, start the car and press on the gas. As you leave the lot you turn the wheel to the right, but the car goes to the left. You stop and go back to the salesman and ask, "Why does the car go left when I turn right"? He says, oh that is a feature of this car, you see it sensed there was a lot of traffic on the right so it went left for you instead. Not a very good car!

Well if every time you wanted to present your user with a certain set of options you first had to remove all of the options that the framework put in for you, you would soon become just as irritated with the framework.

You need to determine for what the framework is responsible and for what the developer is responsible. Don’t use or build a framework that makes the developer work harder to get the result they want.

If you do build your own framework and you want to provide additional functionality beyond the framework’s responsibility, then build a developer’s toolkit as an addition to the framework. That way the developer can decide to use your toolkit or not as they choose and they are not bound by your style or approach.

 

Qualities of a Good Framework

Simplicity

The overall structure of the framework must be easy to understand. A well designed framework can be taught to a new developer in a few days at most. Obviously, the details of all of the methods and properties involved are not taught in a few days, but the new developer should be able to understand how the thing works very quickly and then fill in the details as they use it.

This simplicity is achieved by giving the parts of the framework clear and consistent interfaces. All objects of the same lineage should have the same interface. For example if a local data form has a method named PackTables, so should the remote data form even though the method would have no purpose in this case. Why? Because by all forms having the same methods we can interchange the controls in the forms without concern. If we had a delete button that had code to delete a record and then call the form’s PackTables method this button could be safely used in both the local and remote data forms because both form’s have a PackTables method. In the remote data form the PackTables method safely does nothing, but there is no error when the button calls it.

Clarity

The behavioral aspects of the framework must be encapsulated. It should not be necessary for the developer to know any of the details about how the framework does something in order for them to use the framework. If the developer must understand the actual code in the framework then there is a definite design problem in that framework.

The public interface for the classes in the framework should be as simple as possible. Since it is the public interface that the developer will be working with it is important to keep it no more complex than is necessary to achieve the desired functionality. The developer should not have to sequentially call three or four methods in the framework to accomplish a certain process.

Boundaries

The single most common problem with frameworks that I have seen is the lack, or violation, of the boundaries of the framework. A framework has clear and succinct responsibilities, it should meet those requirements and nothing more. All functionality outside the frameworks boundaries should be handled by the developer. When a framework crosses the boundary it becomes overly complex and it is likely that the developer trying to use it will need to code around the framework’s behaviors in order to accomplish their goals.

A framework does NOT provide the functionality for the application, it provides the skeleton upon which that functionality is built. The application functionality is the responsibility of the developer who uses the framework and the framework should not get in their way.

If a framework developer wants to provide further specialized classes for the application developer to use, these should be supplied in separate class libraries as subclasses of the framework classes. This will allow any developer to choose to use or not use these specialized classes. It also makes a clear distinction between the framework and the developer’s toolkit. Coincidentally, this also gives the developer clear examples of how to subclass the framework classes to get the specialized behavior that the developer might want thus making it easier for the developer to learn the framework.

Expandability

It should be easy for the developer to expand the framework by either adding new classes or by subclassing the existing classes.  A framework whose behavior is not easily modified restricts the developer rather than empowering them.

The only sure way that a framework can provide expandability is by including it in the design. Expandability is not an afterthought.

Hooks, hooks, and more hooks

One way to provide for expandability is by providing the developer with methods in which they can write code that will affect the behavior of the framework. For example, if the framework has a form that will save the users edit in a method named SaveWork, then adding a BeforeSaveWork and AfterSaveWork method which are called by the SaveWork can provide the developer with places to write code before the users edit is saved and after the save has been completed. Further, if the SaveWork method respects the value returned from the BeforeSaveWork method the developer can actually decide to stop the saving without ever looking at the code in the framework class, they can simply return .F. from the BeforeSaveWork method.

These kinds of hooks can, and should, be provided wherever they make sense.

 

Abstract Design

 

Below is an example of an abstract design for a framework. This diagram will be discussed in some detail during the presentation.

 

Designing Class Hierarchy

The design of class hierarchies is beyond the scope of this paper, but some discussion is necessary. In order for a framework to be simple to use and to provide for flexibility in the use of the framework the class definitions should meet at least certain basic design goals. Every branch in the class tree should start with a single abstract class definition that I will call the root class. This root class should have no code in it at all, but rather should be the class where we add the properties and methods that the subclasses will use to provide the code. This approach provides the structure for having a clear and consistent public interface to the classes in our class libraries.

The class design must provide a clear boundary representing the end of the framework and the beginning of the application. The diagram below shows an example using a set of form classes, the italic text indicates the classes that are abstract and will not be used to create objects.