Tuesday, January 31, 2006

The Good, The Bad, and The Code

The good:

Most of you don't know the history, but I am so excited by the latest news that I have to blog about it. Last March my mom was diagnosed with lung cancer. Yes, she was a smoker but has not smoked in close to 20 years. Of course we were all very nervous. She went through chemo and radiation and finished up at the end of 2005. She received MRI results last week telling her that her tumors were gone! Wow are we relieved.

The bad:

Well, I will not be participating in the half time show at the big game on Sunday after all. As it turns out, there was some confusion and our group leader did not get all of the paperwork in on time and we were cut. Oh well. I can sit in an easy chair and watch the game like the rest of the world. It will be just as fun and I don't have to break our family tradition of "junk food day."

The code sample:

The following code sample is really simple. There are many simple things that we could do to improve our development environment that we don't because we don't want to take the time. Well, I took the 5 minutes needed to put this together and I hope that somone else will find it useful.

Not long ago, Rick Schummer posted some tips on the Class Browser. After reading the entry, I was compelled to start using the class browser more. All of my attempts seemed clumsy. I was either stumbling on typing the library name (DO (_browser) WITH ....) or fumbling around trying to find the library when I used the Open button. So, I wrote this very little program to help me. The Class Browser feels so much better to me now.

LOCAL ;
    lcVCX AS Character

lcVCX = GETFILE('VCX', 'Select Class Library')

IF NOT EMPTY(lcVCX)
    DO (_BROWSER) WITH lcVCX
ENDIF


I load this program in my Task Pane Enviroment Post Scripts using:

ON KEY LABEL ALT+F2 ;
    DO c:\development\devtools\LoadClassInBrowser


Enjoy!

Thursday, January 26, 2006

Customized View Editor

I cannot believe that I forgot to document one of the coolest new features in the latest version of Visual FoxExpress, customized view editors in DBCX!

When a view is selected in DBCX Explorer and Modify is chosen from either the toolbar or right-click menu, the normal behavior is to open the Visual FoxPro View Designer. Well, we can now incorporate other behaviors. If a program named ModifyView exists somewhere in the application path, that program is used to modify the view rather than the VFP View editor.

The ModifyView program is passed the name of the view that is selected in DBCXExplorer. Therefore, you could have a ModifyView program like the one below to run your favorite view editor program.

* Program ModifyView
LPARAMETERS ;
    tcView

DO C:\development\devtools\MyFavoriteViewEditor WITH tcView

I hope that you think that this enhancement is as cool as I do!

Friday, January 20, 2006

Version Control Rocks

One thing I forgot to mention when I was ranting about grid.optimize, is that version control rocks. Toni and I were sort of late adapters of version control, but it amazes me how many developers still don't use it. I used to be one of them. I was stupid.

Looking at a Diff of the cContrls class library is what got me looking into the optimize property. Troy, the customer who encountered this problem, had already told me that it doesn't occur with our August release of VFE. We've checked in changes to this class library over a dozen times since August, but I was able to view a Diff between the current version and the August release and easily identify the change. Without version control, this change history would've been lost or taken a helluva lot more time to dig up and wade through.

One of the things that made this easy was that Toni and I create VCA files for all class libraries at the time of check in. I work on a project where most of the other developers don't and it sucks. It takes about a second to make a VCA file, but if you don't make them at the time of check in, then you have to make a VCA file for the file you're working with, copy it off somewhere, get the class library for the version you want to compare to from source control, then make the VCA for it. If you've got changes you don't want to check in you also have to copy them out to another location first. By the time you're finished with all of the copying you've usually forgot what you were going to look for, so it's best just to make the VCA files all of the time.

BTW, we used a revised version of SCCTEXT to get around some of its limitations. For more info, check out the SCCTEXT topic on the wiki.

I have a little PRG I use to make my VCA files, so I don't have to do it manually for each VCX file I have checked out. (SCX's are for sissies, but you can add support to it for them easyily enough.) Here it is:


*==============================================================================
* Procedure: VCAAll
* Purpose: Makes a .VCA file for every VCX file that is missing one
* in a directory and for every existing VCA file that's not
* readonly.
* Also packs .VCX file first so that smaller files can be
* checked in and checked out.
* Author: F1 Technologies
* Parameters: None
* Returns: None
* Added: 01/20/2006
*==============================================================================
LOCAL ;
lcDirectory, ;
lnI, ;
lcVCA, ;
lcClassLib, ;
llGen

LOCAL ARRAY laFiles[1]
lcDirectory = ADDBS(GETDIR())
FOR lnI = 1 TO ADIR(laFiles,lcDirectory + [*.VCX])
lcVCA = lcDirectory + JUSTSTEM(laFiles[lnI,1]) + [.VCA]
DO CASE
CASE NOT FILE(lcVCA)
llGen = .T.
CASE NOT [R] $ laFiles[lnI,5] && VCA is not readonly, assume checked out.
llGen = .T.
OTHERWISE
llGen = .F.
ENDCASE
IF llGen
lcClassLib = lcDirectory + laFiles[lnI,1]
CLEAR CLASSLIB (lcClassLib)
USE (lcClassLib) EXCLUSIVE ALIAS ClassLib
TRY
PACK
USE IN CLASSLIB
DO (_SCCTEXT) WITH lcClassLib
CATCH
ENDTRY
IF LASTKEY()=27
EXIT
ENDIF
ENDIF
NEXT



I hang this program off of my utilities menu and when I'm ready to check files in to version control I just run it on the directory I'm working on. I'd be easy enough to make it walk several directories, but I really haven't had a need for it.

Enjoy, and let me know if you improve on it.

Happy Birthday to Two


Hey, while I'm blogging I might as well wish a happy Birthday to two of the most important people in my life: William Michael Feltman the 1st and William Michael Feltman the 3rd. That's right, today my Dad turns 70 and Mickey is a whopping 9 years old already - double digits are just around the corner.

So...

Happy Birthday Dad & Mickey!



39 is just around the corner for William Michael Feltman the 2nd on February 2nd. Apparently I'm about to embark on my last year up the hill!



VFP Grid.Optimize Gotcha

A new optimize property was added to grid's in VFP9. When this property is set to true, the grid uses Rushmore optimization. For backward compatability, this property defaults to false in the VFP grid base class. Seeing as Rushmore optimization is a good thing, we set it to true in the cGrid class in VFE which is the base grid class in the framework.

We've been shipping VFE this way since August and it hasn't seemed to be an issue - except for one customer. This customer has been consistently getting a "Uniqueness of index xxxx is violated" error whenever the user enters a duplicate value in a textbox that's bound to a primary or candidate key AND there's a grid bound to the same table is also visible.

I've been looking all over for changes we've made to framework code, as there's been a fair amount of work done in grids recently, and it turns out, it's just a simple property setting. This situation only occurs when the user is doing data entry directly into tables (as opposed to views), the user can edit a primary or candidate key and there's a grid that's visible at the same time. When the user exits the control (generally a textbox) associated with the primary or candidate key and VFP updates it, it also tries to refresh the grid at that point in time and this is when the error occurs. What's really confusing about the whole thing is that no events fire that you can see, so what exactly is happening at this point in time took a while to unravel. At any rate, the moral of the story is that if you've got primary or candidate keys that the user can enter, you bind directly to table fields and you display this data in a grid, it's probably best to set the optimize property of the grid to false. If this is how you build your VFE apps, it'd be wise to set this property to false in iGrid of iContrls.

Oh, and BTW, if you do RTFM, there's a note in the doc for the optimize property that explains this:

As with any data manipulation command that can impact Rushmore optimization, you should be aware that actions taken against the Grid's data source could result in behavior that differs from when the Optimize property is set to False (.F.). For example, Rushmore optimization might trigger an implicit TABLEUPDATE to occur for a row buffered cursor. And an error may or may not occur depending on whether the record is blank or whether the cursor is a view.

Now that I've encountered this scenario, I actually understand what the note refers to!

I lost some hair on this one, hopefully this'll save somebody else from early baldness.

Monday, January 16, 2006

Friday the 13th Build

I am sorry that I am a few days late on this, but better late than never. We posted a new VFE.APP as well as integrated updates on Jan. 13, 2006. This keeps with the F1 Technologies tradition of releasing new software on Friday the 13th.

We fixed most known issues to date and implemented the following enhancements for this build.

Please default Minimizable to .F. in Single Record Modal Add Form Wiza
More descriptive title for the default Lookup Selection Form
Allow Deleting of Invalid Views in DBCX Explorer.
BROWSE LAST in DBCX Explorer browse.
Lookup Setup Builder addform drop down.
Add Query Option to DBCX Explorer
Remove the Exclusive lock on FEApps.dbf
cGrid AddColumnFrom.... methods and column width issues
cPortionsLabel finesse
DBCX tooltip text length
VP.GetFKValue()


The next Friday the 13th is not until October. I think we can get our next update out before then.

Thursday, January 12, 2006

Watch for Toni at Super Bowl XL

Oh my gosh, I cannot hardly believe it. I have been asked to dance during the halftime show with the Rolling Stones at Super Bowl XL. My friend Michele called me this afternoon and invited me to join her and several other girls to represent the Alzheimer's Association. Is this an opportunity of a lifetime or what? So, watch for me during halftime and maybe the pre-game show. Thank you Michele!!!!

Tuesday, January 10, 2006

Automated Testing?

Not long ago, Rick Schummer had a blog entry about how his views never break when he changes the structures of his tables because he uses View Editor Professional. Unfortunately I am not so lucky. I make table changes all of the time that break my views. Most of this is at the start of a project when the data model is not locked down yet. I don't have problems when I add fields to my tables, but I do have trouble when I remove fields. If you add 9 other developers and many DBCs and this can get crazy.

One solution to this problem is automated testing. I have been talking about automated testing with several clients for a couple of years now. I truly believe in the concept but have yet to find a developer that has successfully implemented the automated testing of a Visual FoxPro Application. There are many products on market that can be used. Why isn't there a good solution?

I can tell you one reason that I don't have a successful Visual FoxPro automated test case study; the learning curve. All of the automated testing tools are pretty complex and require a great deal of time to learn, even for simple tasks. So instead we keep moving ahead with all manual testing. I don’t like that. There has to be a better way.

If you have a VFP automated testing success story, please share it with me. In the mean time, I am going to begin writing my own automated testing tools. These will be very simple tools to automate some of the testing I do all of the time. As I write something, I will share it with you. Something is better than nothing, right?

My first tool is a program to test all of the views in a data folder to make sure that they can be opened. If the view cannot be opened, details will be logged to a cursor. Simple right? My first pass on a fairly large application I am working on yielded 8 broken views. Now, these can be fixed and we can move on until tomorrow’s data changes come. The code is not rocket science. Anyone reading his blog could have written it, but as far as I know no one has. This simple program will save my projects a boat load of bug fixing time. I hope it is worth something to you too.

Here's the program. You will probably want to modify it to SET PATH and such but it is a start.

*====================================================
* Program: TestViews
* Purpose: Tests all of the views in all DBCs in a
* data folder.
* Author: F1 Technologies
* Parameters: None
* Returns: None
*====================================================
LOCAL ;
   lcDir, ;
   lnFiles, ;
   lnI, ;
   lcDataDir, ;
   lnJ, ;
   lnViews

CLEAR ALL
CLOSE ALL
CLEAR
lcDir = ;
   GETDIR(SYS(5) + CURDIR(),[Select Data Directory])

IF EMPTY(lcDir)
   RETURN
ENDIF

lcDataDir = ADDBS(lcDir)
lnFiles = ADIR(laDBCs, lcDataDir + [*.DBC])
ON ERROR DO LogError WITH DBC(), laViews[lnJ], MESSAGE()

FOR lnI = 1 TO lnFiles
   OPEN DATABASE (lcDataDir + laDBCs[lnI,1])
   lnViews = ADBOBJECTS(laViews,"VIEW")

   FOR lnJ = 1 TO lnViews
      SELECT 0
      USE (laViews[lnJ]) ALIAS Test NODATA

      IF USED('Test')
         USE IN Test
      ENDIF

   ENDFOR
NEXT

IF USED("Errors")
   SELECT Errors
   * You could run a report here if you
   * wanted to really automate this.
   BROWSE
ENDIF

CLOSE DATABASES ALL

PROCEDURE LogError
LPARAMETERS ;
   tcDBC, ;
   tcAlias, ;
   tcMessage

IF NOT USED("Errors")
   CREATE CURSOR Errors ;
      (mDBC M, ;
      mAlias M, ;
      mMessage M)
ENDIF

INSERT INTO Errors ;
   (mDBC, mAlias, mMessage) ;
VALUES ;
   (tcDBC, tcAlias, tcMessage)

RETURN