John W. Colby
jwcolby at ColbyConsulting.com
Fri Jun 23 20:41:09 CDT 2006
Michael, >What was a 'framework', again? A framework means different things to different people but I think of them as a prewritten skeleton (and more) for an application. If you think about a building as a metaphor, what kinds of things do all buildings have in common? They all need electricity, plumbing, a phone system, elevators if more than a single floor, heating and AC, etc. These things, as well as the load bearing skeleton are the "framework" of the building. The rest is just walls and windows. Modern programs can use similar concepts. I started using frameworks in the late 80s with Borland's Turbo Pascal. From there I learned about but never really got into frameworks for VFP. The seed was planted however and in 1997 I started developing my first framework for Microsoft Access. It was extremely crude and did not use classes. The second version however did use classes and withevents, thanks to Shamil's prodding me to learn them. My third generation (as I call it) framework is what I use in my new projects and AFAICT it is probably unique in the breadth and scope of functionality offered. I initialize the framework with a single function call. The framework then provides me with numerous services such as: Sysvars - (System Variables) both for controlling the initial state / operation of the framework itself, but also for controlling the initial state / operation of the application using the framework. In fact, system variables are a key concept in my framework because they allow me to dynamically control the operation of my framework as well as the application. System variables are often used by developers. Most developers need to store a "single value" such as (for example) their company name and email in order to place it on the splash screen. Since the email address may change they might build a little one record table with two fields - their company name and email address. Then they later decide to add their mail address so they go back in to design view and add a few more fields, again though just a single record. Any database person will tell you that this is the wrong way to do this, we need a table with a couple of fields, a variable name and a variable value (at a minimum). CompanyName Colby Consulting Email jwcolby@ Addr 71 reder rd Etc etc. These then are System Variables, and this is exactly the way that I do it. What may be less obvious is that you can use these same system variables for different purposes. For example, suppose you wanted to use Just In Time subforms in your projects. You write code that allows the click event of a tab to load a subform control with a form. But do you ALWAYS use JIT? Perhaps in your framework you default to NOT using JIT subforms and allow the framework to be modified by using SysVars to control whether the default is to use the JIT subforms. So you create a SysVar table specifically for your framework. Then you have a SysVar named UseJITSubforms. You set the default to false. Now, when you create a new project and you create subforms on tabs, the code that decides whether to load the subforms at the main form's LOAD event or on the tab's click event checks the SysVar UseJITSubforms. If it is True, then the subform will be loaded in the click event, else in the Main Form's Open event. Now, if you use JIT subforms, do you UNLOAD the subform when you click off the tab with the form? You can determine that with another SysVar called JITSubformUnload. Default to false and the subform stays loaded once it is loaded, else it unloads when the user clicks on another tab. So SysVars are one of the things that ALL of my applications use. My main framework class loads the sysvars for itself (the framework) as one of the first things that it does (it also loads an Application SysVar table). Other services that my framework provides to my applications include: * I can log to one file or a hundred. My application simply calls the framework and asks for a file logging class (with a name). The framework loads an instance of the logging class and stores a pointer in a collection keyed on the provided name. Now my application can simply call the framework to log data to that file. What data is logged is up to the application, but the actual logging is up to the framework. * Error logging * ZIP/Unzip * Email using MS Outlook * "LightWeight Security" allowing login / logout of users, then classes for the users and groups that they belong to etc (not MDW based) which I use for enabling / disabling forms and controls on forms. * Log date/time users open / close the FE. * Force logoff of the database (close the FE) at a given time. * Interclass messaging using a dedicated message class * Clipboard read/write * FTP read / write * MD5 Encryption In addition to these "application" services, the framework provides me with form and control classes which are wrappers to those Access objects, which provides a host of additional functionality and the ability to "extend" the functionality of a given object. Examples include: * Classes to automatically load and parse form Openargs and make the openargs available to the form * Automatically scan for controls which have classes (wrappers) and load the control classes * Just-In-Time subforms loaded as a tab page is clicked on in order to speed up loading of complex forms. * Provide NotInList processing for combos * Open "list" forms (using the combo's dbl-click or notInListevent) and seek to specific records for a selected data object in a given combo. * "Telling" objects what other objects (wrapper classes) are "dependent" on that object such that if that object is edited, dependent objects are automatically requeried / refreshed. Combos / forms requery when some other combo (or any data aware object) is modified / edited. I can even do this across forms, i.e. requery another open form when a value in a combo on this form is selected. * Allow specific users or (more commonly) specific groups to override the Visible, Enabled and Locked properties for any specific control so that certain groups of users can see but not edit data in a control, others can edit it, others can't even see it etc. * Prevent loading, or override the AllowEdit, AllowDelete, AllowAdd and DataEntry properties for a given form based on group membership. * Allow OpenArgs to be passed in to an opening form which automatically sets these and other properties of a form - makes a general purpose form read-only to one group of users, editable to another, allows one group to delete records but not others etc. * The ability to drill down to the field that a text box is bound to to discover what data type it is, and apply consistent formatting across the app (all dates in mm/dd/yyyy etc.). * Logging what forms are opened, by what users / workstations. I could (but never have) log what individual controls users visit (click in / edit) as they use a specific form. This kind of stuff is trivial once you have wrappers for controls and automatically load them as forms load. Sysvars can turn on / off this kind of functionality, even down to a form by form basis. I have already done ALL of this stuff in my framework. Most of it I wrote, with the exception of public domain classes such as zip/unzip, FTP and encryption classes/modules. Having written it, all of this functionality is available to me when I need it. Someone mentioned "lean and mean" programming, implying that having a framework that "just does this stuff" for you causes your program to be bloated and slow. In fact that may or may not be an issue. If your clients are using old machines with sub ghz processors and 128 mb ram then it should be a concern. If your clients are using modern machines with lots of ram then is it really a concern? How big is Windows XP or 2003? How big is Office / Access XP / 2003? My entire framework with all of this functionality is currently 3.6 mbytes, and that includes the source code (it is an MDA). How much overhead would it be if it loaded every single piece of code in the framework? Is that too much to ask for having all of the Electricity, plumbing, AC/heat, elevators and such already in place with a single function call to initialize it? Not for me. I use my framework on every project. Today I needed a form to open and pull openargs out. I have a template form with something like: Dim mclsFrm as clsFrm Sub MyFrm_Open() set mclsFrm = new clsFrm mclsfrm.Init [Param], [Param] End sub In fact, for many of my simple forms that is all that is in the form's module. My framework handles everything else. So I copy my class template and rename it, then it was a single (additional) call to the form class to load each openarg: Sub MyFrm_Open() set mclsFrm = new clsFrm mclsfrm.Init [Param], [Param] MyVar1=mclsFrm.Openarg("MyArgName1") MyVar2=mclsFrm.Openarg("MyArgName2") End sub Different strokes for different folks but I believe in writing things once and using it forever. That is what a framework is about. John W. Colby Colby Consulting www.ColbyConsulting.com -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Michael R Mattys Sent: Friday, June 23, 2006 6:36 PM To: Access Developers discussion and problem solving Subject: Re: [AccessD] Frameworks ----- Original Message ----- From: "Colby, John" <JColby at dispec.com> > Let me take another poll. Of those of you who do not use a framework, > how many have read my ramblings and said > > 1) "I'd like to know more about this stuff". > 2) "What a nut case" > 3) "I sure wish he'd knock off the ravings" > > John W. Colby What was a 'framework', again? Michael R. Mattys MapPoint & Access Developer www.mattysconsulting.com -- AccessD mailing list AccessD at databaseadvisors.com http://databaseadvisors.com/mailman/listinfo/accessd Website: http://www.databaseadvisors.com