FoxPro Developer's Conference '94
Rapid Application Development
Lisa C. Slater
Elements of a RAD Approach to FoxPro
Despite the impression you may have received in the various magazine articles that use the term, RAD isn't simply a buzzword. It's a structured method of development, pioneered by James Martin, with established elements:
· Sketch a design with graphical tools
· Express the results of the design process with generated code
· Coordinate generic objects and genericized methods with generated code
· Add third-party utilities and elements, where appropriate, to the development environment's native set
· Use a cross-platform and forward-thinking strategy to make the application as portable as possible.
The premise of this session is that these techniques can be incorporated into a FoxPro developer's use of every FoxPro power tool, at all stages of development. We will follow the chronology of a development project, to see how RAD principles apply.
Although the session will use a limited version of my template code to provide the application's generic objects and options, my template is only an example. It is certainly not the only way to accomplish RAD goals. It shouldn't conflict with your use of CodeBook or any other FoxPro approach. It simply gives you a way of thinking about application structure, plus some new tools and objects you can feed into your current framework, if you happen to like my style!
At every stage of development, you have to do the same thing: identify the appropriate level of generic use for every application element you design.
First, you identify which elements of the task are completely generic, and you figure out the best way to handle them once. You build these elements into your general template. Whenever possible, you want an object or program to be useful for every application you write, and for each platform for which you write.
Next, you check to see which elements of your task are globally useful either throughout a single application or on a single platform.
Least preferable is to create an object or program that can be used for only one operation or tasks. Even these elements should be designed to behave consistently throughout their task or module.
By the time you've finished separating the generic (write once/read many) elements from the application-specific elements, you've drastically cut down on the code you have to write for each app.
Designing Data Structures: The missing power tool
Ironically, the place you start out designing an app is the place that FoxPro forgot to give us an adequate Power Tool. I use the View window and APPSETUP, on your Session Source Code disk, to show you a graphical way to design and describe data structures to your application, and then generate code for file handling. You can use CASE tools or create other alternatives.
Your goal here, and throughout the development process, is to use graphical design tools that allow users to understand and participate in the process and then to pull generated code out of these graphical descriptions rather than writing it.
Please refer to the READ.ME file on the source disk, when installing the session code. You'll find a warning to install SHARE before you attempt to run APPSETUP on a standalone DOS or Windows computer. APPSETUP isn't just a tool in my development process, it is build from my template code. (There is a slightly different problem in the Mac environment, related to multiple sessions, you'll find described in the template's MAIN.PRG. There will probably be a different problem in Unix, or actually I know there is a different problem, but right now the template doesn't have a solution built in for this.)
Of course, if you decide you don't agree with my reasoning for requiring SHARE, you can easily change the template; check out the MultiUse() function in MAIN.PRG. All the applications you build will then inherit your preferred behavior because you've changed this function once.
That's the point of a template!
The Project Manager and Global Application Development Strategy
The NORMAL directory contains a skeletal version of a standard FoxPro application. Its not designed to show you how to do event-driven programming in FoxPro; as far as RAD is concerned, you can build your app using any event approach you want. The basic structure of the .APP and FoxPro project will remain the same.
I hope the Mac folks will forgive my references to directories, rather than folders, throughout these notes. Rest assured that the methods described apply equally to FoxPro for Macintosh. In fact some of my methods and my RAD approach were specifically created while I wrote FoxPro MAChete: Hacking FoxPro for Macintosh, with the Mac and Apple Interface Guidelines firmly in mind. Mac people are especially concerned with ease of use; therefore they are attentive to some issues that RAD amd JAD (joint application development) require in their partnership between developers and users during the design process.
If you run APPSETUP on the NORMAL directory, youll see how I use APPSETUP to begin creating any application after the structures are designed. APPSETUP generates all the file-creation and-maintenance code for the "view of data" you give it, as a series of PRGs.
The NORMAL directory relies heavily on files contained in the TEMPLATE directory. These files do not change from application to application. In some cases they are always used; in other cases, they are overridden by local copies for specific applications.
You can see the RAD strategy at work here: classify, identify, and isolate, generic pieces. All your applications can inherit their behavior without necessarily understanding how the behavior occurs. In Object-Oriented terms, that's because the behavior is encapsulated within the template objects. Then create application-specific behavior locally. Where this behavior contradicts the global or generic pieces, the template must be flexible enough to cope with these changes and exhibit appropriate responses. In Object-Oriented terms, this means the template objects are polymorphic.
A plea for more OOP in your programming style
You may not be used to thinking about FoxPro as an object-oriented language; in fact, it's not one. However, borrowing OOP concepts is extremely important part of the direction in which most database management languages are moving. They are also an integral part of RAD strategy. Although we don't have the syntax to support OOP, the closer we get to OOP behavior the more useful our current methods (and our thought patterns) will continue to be.
The classification of code into generic and application-specific sections is accomplished by a very simple set of mechanisms in my template, as you'll see in the sessions. Don't be caught be the idea that you need a screen or other Power Tool-built element to practice OOP. A program can be an object too. The PRG-type code in my template is divided into generic and app-specific sections as a template MAIN.PRG with hooks in it for a local INCLUDE.PRG at various points. MAIN.PRG never changes; INCLUDE.PRG holds all the aspects of an application that must be changed on an application-to-application basis.
Your own template MAIN.PRG may be very different from mine, but I urge you to study its code carefully as an example of the kinds of behavior you'll want to fix for your generic method. We will go over my MAIN.PRG and its assumptions carefully in the sessions, particularly from the point of view of cross-platform work.
The Unix version of FoxPro will require a few additional tweaks, but the shifts I made in my template when I revised my methods for the Mac should handle Unix file-referencing as well.
You may even choose to call INCLUDE.PRG at different points in your MAIN.PRG from mine. I'd like you to notice, however, that there is a "FoxPro-classical" symmetry to the INCLUDE hooks as they currently stand: they are very close to the Setup #SECTION 1 / #SECTION and Cleanup elements of an SCX. Remember that if you pull too many references to INCLUDE.PRG into MAIN.PRG you are creating more code that has to be edited for each application and consequently more potential for mistakes.
The routines of MAIN.PRG surround these calls to INCLUDE.PRG just as the generated code elements of an SPR surround the properties you give the screen in your Setup and Cleanup code. The centerpiece of the application is a READ, a wait state in which your application remains until it's time to execute both local and generic Cleanup code, just as a READ is the centerpiece of an SPR.
The Project is a container object, holding other objects within it. You point the Project Manager at MAIN.PRG and it pulls the other components into the Project for you. After you see the way the Project Manager hooks the template elements into the application's project, it's time to develop a strategy to add app-specific procedures and elements to this shell.
The Menu Builder: Designing Data Flow and Applications
The Menu Builder is the simplest Power Tool to use, but it turns out to be the key to implementing RAD and JAD (joint application development) in FoxPro. If anybody at the sessions is not yet convinced, we'll talk about why you should use SYSMENU instead of any of the other FoxPro menu forms. Then we'll look at the template's menu elements, showing how the generic pieces of a menu work together, and how you can personalize a menu either by user or by platform, creating dynamic menu prompts, or dynamically-available menu options.
The application-specific parts of designing a menu incrementing the generic menu with application and task-specific options are a way of expressing data flow in FoxPro. The Menu Builder is actually a modelling tool you can use to get quick design help and feedback from your users.
RAD Use of the Screen Builder
Once the menus determine data flow, almost every application task gets a screen or set of screens that forms the user's method of accomplishing that task.
Like menus and procedural code, screens must be classified into those that are generic and those that are application- or task- specific.
As objects with encapsulated behavior, generic screens should "know" everything about themselves, without reliance on other aspects of the template or the Project Manager. We'll look at avoiding the "screen set generate options" aspect of the Project Manager, specifically for these screens so that your generic dialogs and tool bars are completely portable without editing for each application.
For non-generic screens, our RAD approach is a little more diffuse. (Translation: here's where the going gets tough, folks.) I start by using a template screen that handles as much of the data entry setup work as it can, and then use that screen to create a prototype, suitable for user feedback, without much code behind it.
It's also important to think about aesthetics and create a pleasing, standard visual interface with as little wasted time as possible.
Both these goals cause me to recommend that you use GENSCRNX. which is not a patch to GENSCRN but rather a pre- and post- processor for GENSCRN. When you figure out some of the difficult screen issues, you can embody your solutions in GENSCRNX library objects, and then you can use these objects to provide something like true inheritance of those solutions to your data entry screens. By inheritance I mean that the data entry screens will include any changes you make to the library objects, because you haven't replicated the objects in the screens themselves. The SPR has replicated code, not object references, so we still don't have true inheritance all the way to the SPR (you'll still have to re-compile to make sure the changes are incorporated!). But kudos go to Ken Levy et al for supplying inheritance to FoxPro at least to this degree.
Working with complex screen sets leads us back to the Menu Builder. Which tasks should allow access to which other tasks? How much room does the user have to maneuver? The options you make available on the menu during any one tasks usually provide the answer.
The FUNSTUFF directory contains one more project, COLIN.PJX, intended to give you an introduction to some issues in creating generic and reusable objects, FoxPro-style.
This is a present I wrote for a friend its MAIN.PRG, here called COLIN.PRG, doesn't seem very standard, but if you look closely you'll see the same elements we always have in a main program: setup, a menu of choices (here a WAIT WINDOW TO <memvar>), a READ state, and cleanup. These elements are usually echoed in FoxPro application modules and subsidiary programs, too.
The app's two dialogs, DIALOG and NEON, represent two extremes in the development of re-usable objects; one took no time to write and can be used extensively, and the other is highly special-purpose and took far too long to write.
Using Nancy Jacobsen's design criterion of "can you afford this screen??" the answer is a resounding "NO!" to NEON. Not only does it take more code to be this exacting (and far too much time messing about in the Screen Builder) but an object like this, containing mouse-click-handling and a close-box-written-in-FoxPro, is liable to get you into trouble when you send them out into an unknown environment. It's also almost impossible to imagine this screen written as a cross-platform object, which is one of my basic criteria for sturdy generic objects.
DIALOG, on the other hand, is a sturdy design with only a minimum of code attached to it, suitable to many different uses. Note the use of #NOREAD PLAIN in the subsidiary screens that the initial screen calls, to allow different numbers of buttons to appear in the dialog, and the way the calling program's use of an array controls how the DIALOG screen appears and behaves.
Both these screens, however, share some important elements:
· They're self-contained. Using #READCLAUSES MODAL, for example, rather than the Screen Set Generate Options dialog option for the same purpose, means that these screens are always modal, without further adjustment, when they're pulled into a project. Similarly, where they require externals such as indirectly-referenced programs, they carry this information with them rather than trusting it to a normal INCLUDE.PRG.
· They declare their variables PRIVATE and initialize them appropriately.
· They check for the items they need passed and set up default values if none exist.
You'll see that these screens make extensive use of other Generator Directives. I hope you enjoy checking out the source code for additional tips on their use, for efficient project use and applications design.
(c)1994 Lisa C. Slater