Designing Your Own Framework
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
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
- Menu Management
- Form Management
- Security Management
- Communication Management
- Data Access Management
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
What Kind Of User Interface Do You Use?
User interfaces come in all sizes and shapes, mostly bad.
Lets put that point to the side, this paper is about frameworks and not user
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. Dont 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 frameworks responsibility, then build a
developers 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
Qualities of a Good Framework
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
forms PackTables method this button could be safely used in both the local and
remote data forms because both forms have a PackTables method. In the remote data
form the PackTables method safely does nothing, but there is no error when the button
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
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.
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 frameworks 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 developers 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
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
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.