Free White Paper reveals new software training model:

Perfect Coaching - How Companies Are Maximizing Software Delivery ROI through Just-In-Time-Training - Download a copy

For more information on Perfect Coaching, contact Visionpace at coaching@visionpace.com or call 816-350-7900 or 888-904-7900 and ask to speak with someone about Perfect Coaching.

October 17, 2008

Phoenix in the fall; Arizona in the autumn

If you aren't at Southwest Fox 2008 in Mesa, AZ (http://www.swfox.net/) this weekend, you're missing a real treat.  Tamar Granor, Doug Hennig and Rick Schummer have once again done an excellent job organizing a conference that is a tremendous value for your money.

To give you taste, here are some of the sessions I attended today:

- In "Profiling and Refactoring: How to Analyze and Clean up Your Code", Andrew Ross MacNeill talked about a powerful tool in VFPX called Code Analyst that can help you identify "issues" in your code (e.g., too many lines of code in a single routine, too many comments, too many loop structures, has more than one return value, etc.).  (VFPX is a Visual FoxPro Community effort to create open source add-ons for Visual FoxPro 9.0).  You can select which rules you want run against your code; you can also create your own rules.

You can download Code Analyst for free from the VFPX CodePlex web site: http://www.codeplex.com/VFPX.

Andrew also discussed an add-in for the Coverage Profiler.

- Christof Wollenhaupt gave an introduction to mobile development; employing his product, Guineu (Catalan for "Fox"), you can develop mobile applications from within Visual FoxPro. Cool!

- Doug Hennig talked about Advantage Database Server for VFP Developers; with this alternate back-end, you can either read VFP .DBF files directly or you can move your data into the proprietary ADD format.  With Advantage Database Server (ADS), your .DBF files are no longer limited to 2 GB.  "In ADS, there isn't a direct limit on the size of the file; instead, the limit is a maximum of 2 billion (2,147,483,648) records. Of course, if your DBF becomes larger than 2 GB, you'll only be able to access it through ADS since VFP will see it as invalid."

"ADS [also] has a fast and powerful full text search (FTS) feature. FTS uses an index on each word in a memo field to provide fast, index-based lookups for desired words."

- Rick Schummer did a presentation focusing exclusively on "Using VFPX Components"; he demo-ed various controls like Themed Controls (e.g., OutlookNavBar), the ctl32 project (e.g., StatusBar and BalloonTips [tooltips on steroids]) and Desktop Alerts.  VFPX controls add pizzazz to your VFP applications, giving them a more polished/professional appearance. You can download these controls for free from the VFPX CodePlex web site (http://www.codeplex.com/VFPX) and then implement all of these controls in your VFP applications

- In "Creating Owner Drawn Controls in VFP", Christof Wollenhaupt showed us how to "exploit the power of GDI+ to create our own controls" in VFP forms (e.g., "new pageframes, progress bars, formatted text, chart controls, basic text input or Unicode text output").  He also covered "dealing with mouse and keyboard input."

- Bo Durban showed us how to create custom report controls with VFP 9, employing the GDIPlusX library; rotated text, dynamic text formatting, graphs and custom shapes are a few examples of things you can do/include in your reports.

I continue to see the common thread/theme of EXTENSIBILITY with respect to Visual FoxPro (that was also displayed in a 2-day West-Wind Web Connection training I attended on Tuesday and Wednesay this week [Rick Strahl's product enables you to create web applications using VFP and some other technologies like CSS, JavaScript, JQuery, etc.]).

Posted by abergquist on October 17, 2008 | Permalink | Comments (0) | TrackBack (0)

October 07, 2008

Bitten by Performance Counter issues in Virtual Machine

I've been using virtual machines for software development for just over 3 years now. At this point, virtually all of my software development is done on virtual machines (no pun intended... it was just a side effect).

About 8 months ago, I started noticing a recurring issue on my virtual machines with regards to SQL Server 2005. I was regularly getting errors in the application event log about SQL Server 2005 performance counters. Since this was the only error I was getting, and SQL Server 2005 seemed to plug right along just fine despite these errors, I ignored them.

Fast forward 8 months to today. I've been using SQL Server 2008 in development projects for a few months now. I had one particular virtual machine that did not have SQL Server 2008 reporting services installed and I wanted to install it today. When I ran the installation wizard, it kept failing during initial check steps, reporting that there was a problem with the performance counters. In this case, it would not let me install reporting services withough resolving this issue. The details reccomended following the steps of Microsoft KB article 300956, "How to manually rebuild Performance Counter Library values".

I followed all of the steps of this KB article (not a quick task mind you), rebooted and started the installation again. Much to my chagrin, it failed due to the same performance counter check failing AGAIN..... UGH!

Some additional googling let me to this blog post.

The short story here is that performance counters were disabled.... ALL OF THEM. Rebuilding them was a completely unnecessary step. I also know why they were disabled, and I will remember this for a LONG time to come.

I've been using VMOptimizer from Vizioncore (desktop version now discontinued) since before it was purchased by Vizioncore from Invirtus (or they merged, or whatever happend). There is a checkbox in the opimization options regarding disabling disk performance counters. Unfortunately, this is mislabled. It doesn't disable "disk performance counters", it simply turns off ALL OF THEM.

Guess when I started using VMOptimizer again.... say... about 8 months ago.

If you need any performance counters turned on, don't check this option or possibly suffer the same fate that I did.

JE

Posted by Jim Erwin on October 7, 2008 | Permalink | Comments (1) | TrackBack (0)

September 25, 2008

Dump unnecessary leading equals signs ("=")

You will often see a leading equals sign ("=") in older VFP code (especially in code ported over from FoxPro 2.x).  A leading equals sign is necessary only in a couple of instances in VFP:

  - when calling the SEEK() function  and not storing the return value, e.g.,

      USE (HOME(2) + 'Data\Customer') IN 0
      =SEEK('Great Lakes Food Market', 'Customer', 'Company')

  - when denoting an expression in a property in the Properties Sheet/Window; for example, when setting the .Caption property of _Screen:

      ='My Application (Version # ' + m.gcVersionNo + ')'

Side note, when setting the .Picture property for an Image control, include the equals sign as follows:

      ='MySplash.JPG'

If you specify MySplash.JPG without the equals sign and character delimiters, VFP will attempt to insert the path in front of the picture's file name; the problem is that that path may not (in fact, most likely will not) be on your customer's PC (when your application is production).

Posted by abergquist on September 25, 2008 | Permalink | Comments (0) | TrackBack (0)

September 19, 2008

It is not too late...

With less than a month before it begins, the Southwest Fox 2008 conference is set to start October 16th. It is the premier conference for Visual FoxPro developers in the nation and with over (an estimated) 100,000 VFP developers world-wide, Visual FoxPro will be around for a long, long time. The conference is the PERFECT opportunity to hone your skills and pick up new techniques to enhance future developments. If you haven't registered, IT IS NOT TOO LATE to register. 

Having said that, it gives me the opportunity for some self-promotion. When you go to the conference website, look for the link to download the K.O.K.O.P.E.L.L.I. software written by moi. It will give you two hours of your life back. How? Well, instead of spending two hours trying to figure out the optimum schedule to ensure you see the sessions you are most interested in, the software prepares a "suggested" schedule based on your preferences in just a couple of minutes.  Give it a try. If you have any problems, let me know by leaving a comment and I promise I will get back to you.

Hope to see all of you in Mesa, AZ in October.

Posted by Dave Aring on September 19, 2008 | Permalink | Comments (0) | TrackBack (0)

September 11, 2008

Character (string, text) delimiters

Here's my order of preference for character delimiters:

a) Apostrophe (') ... saves time since it is just one character and does not require you to press and hold down the <Shift> key ... easiest to read (least 'cluttered')

b) Square brackets ( [ and ] ) ... requires two (2) different characters but still does not require you to press and hold down the <Shift> key ... easy to read

c) Double quotes (") ... just one character but requires you to press and hold down the <Shift> key ... "busiest" in that it adds "white noise" to your code

I switch to square brackets if there's an apostrophe within the string.  If the string contains (i) an apostrophe as well as (ii) one or both of the square brackets, then I employ double quotes.

Examples:

* My ideal is to employ apostrophes for delimiting character strings
WITH ThisForm
  .icTableItemExpression = 'ALLTRIM(' + .icMainAlias + '.FPC_FacilityName)'
ENDWITH

* Here, I am forced to employ square brackets due to presence of embedded
* apostrophes
This.icDynamicFormCaption = ['Notes for '] + ;
  [DTOC(C_AdmitDischarge.AD_AdmittedOn) + '-'] + ;
  [DTOC(C_AdmitDischarge.AD_DischargedOn)]

* Here, I am forced to employ double quotes due to the presence of embedded
* square brackets as well as an embedded apostrophe
This.icDynamicFormCaption = "[Notes for McDonald's]"
* Alternatively, I could employ square brackets as the main character
* delimiter:
This.icDynamicFormCaption = ["Notes for McDonald's"]

(Regardless of what character delimiters you prefer to employ, I recommend that you be consistent!)

Posted by abergquist on September 11, 2008 | Permalink | Comments (0) | TrackBack (0)

September 04, 2008

Best practices when macro substituting

When working with macro substitutions …

1) bring “closure” to them

  Get in the habit of always “closing” your macro substitution with a period (“.”); for example:

    &lcSQL.

  That way, when you employ macro substitution as part of an object hierarchy, VFP will properly parse the line; for example, if you have a form with a commandbutton whose .Name is ' cmdButton':

    The following code sets the .Caption of 'cmdButton' to 'Process':

      LOCAL lcCommandButton
      lcCommandButton = 'cmdButton'
      ThisForm.&lcCommandButton..Caption = 'Process' && Two (2) periods before .Caption

    whereas the following code triggers a “Property CMDBUTTONCAPTION is not found” error:

      LOCAL lcCommandButton
      lcCommandButton = 'cmdButton'
      ThisForm.&lcCommandButton.Caption = 'Process' && Only one (1) period before .Caption

2) don’t embed them

    lcControlName = 'cmdButton'

  Replace the cryptic, embedded macro substitution:

    ? 'oForm.&lcControlName.'

  with the following, easier-to-read (and, therefore, easier-to-maintain) code:

    ? 'oForm.' + m.lcControlName

  (The above should run faster, too, since it does not employ macro substitution.)

Posted by abergquist on September 4, 2008 | Permalink | Comments (0) | TrackBack (0)

August 30, 2008

Employ "white space" in your code

Make your code more readable (by not jamming it all together) and, therefore, easier to maintain.

Examples:

  a) Code examples:

    Without white space, the code is not as readable:
      REPLACE CB_UnitsBilled WITH ;
        (lnBillableDaysTotal/DAY(GOMONTH(C_ClaimHeader.CH_From,1) ;
         -1))*CB_UnitsBilled

    With white space, the code is more readable:
      REPLACE CB_UnitsBilled;
        WITH ;
          (lnBillableDaysTotal / DAY(GOMONTH(C_ClaimHeader.CH_From, 1) ;
           - 1)) * CB_UnitsBilled

    Of course, with good comments, the command makes the most sense:
      * Units Billed = (Total Billable Days / Total # Days in month) x
      *                Authorized Units
      REPLACE CB_UnitsBilled WITH (m.lnBillableDaysTotal /    ;
         DAY(GOMONTH(C_ClaimHeader.CH_From, 1) - 1)) * CB_UnitsBilled

  b) Inserting a space after each semicolon (";") makes your PATH setting in configuration files and SET PATH commands in VFP code more readable:

    Without white space, the path is not as readable:
PATH = C:\App;C:\App\Data;C:\Program Files\Microsoft Visual FoxPro 9;C:\Stonefield\SfCommon;C:\Stonefield\SDT;C:\Stonefield\SDT\Source;C:\Stonefield\SDT\DBCX

    With white space, the path is more readable:
PATH = C:\App; C:\App\Data; C:\Program Files\Microsoft Visual FoxPro 9; C:\Stonefield\SfCommon; C:\Stonefield\SDT; C:\Stonefield\SDT\Source; C:\Stonefield\SDT\DBCX

The above examples demonstrate intraline (horizontal) white space (making it easier to read your code from left to right); also employ interline (vertical) white space (to make your code easier to read from the top down).

Posted by abergquist on August 30, 2008 | Permalink | Comments (0) | TrackBack (0)

August 26, 2008

Don't Think "Tomorrow"; Think "A Decade from Now"

The always entertaining and thought provoking, Rick Schummer, had a blog recently, ( Rick's Blog - “Getting Started with Visual FoxPro") that caused me to stop and reflect upon his heartfelt advice. What I came up with is not particularly pretty for me, but it was a moment of truth for me.


Before I go any further, let me say I have been using FoxPro in one version or another since 1989. I have made a good living thanks to that fine product. My custom license plates read “FOXPRO”. Get the point?  I L-U-V the software! I will continue to use and work with the product until the day I retire. Fortunately, for me, that day is not that far away. Timing is everything. For me, the timing is that I should be able to run out my career and the last line of code I write will be... RETURN. However there are others who have 25, 30, 40 years left in the work force and my advice to them is... DON’T WASTE YOUR TIME WITH FOXPRO.


I can hear many of you shouting, “Blasphemer!”. Maybe I should even be shouting at myself, but the truth of the matter is, FoxPro will not be viable software in a few (plug in your own definition of “few”) years. Rick’s advice for anyone wanting to learn FoxPro was dead on. He did an excellent job of covering all of the bases. My question is WHY would anyone want to learn FoxPro at this point in history? The only two reasons I could come up with are because the dwindling ranks of FoxPro developers have caused companies, still using legacy FoxPro application, to get someone, anyone, to maintain and enhance their applications OR the individual is wanting to learn VFP because it is still an awesome hunk of software that is VERY cost effective; particularly in third world countries.

In the first case, the boss probably went to an employee and said, “We need to have you learn FoxPro.”  The apparent up front cost of converting a legacy application is, in many cases, too much for a small to medium business to bear in these somewhat difficult economic times. The application, basically, still does what they need it to do, but once in a while, it just needs some tweaking.  The “quick fix”, in management’s mind, is to invest a minimum amount and “throw another body” at the problem. This only delays the final decision to rewrite or replace the existing legacy application. Ignoring the thought that if the employee refuses to “waste” their time learning “old technology” they might be fired, any developer worth their weight in salt would prefer to learn current technologies, thus making themselves more valuable both to their present company and when they re-enter the job market. Learning FoxPro serves his company well (momentarily), but it does not serve the developer’s best interests. Soon, that developer will realize his stagnant position and move on causing the problem to arise again and the same solution to be more expensive than it was earlier. See a pattern here?


In scenario number two, each desire to learn VFP has many reasons. I have no problem with anyone weighing their options and deciding that Visual FoxPro is the answer to their solution.  Many times, it actually IS the best solution; even now. However, it would seem to me that it would have to be a very special set of circumstances to arrive at that conclusion. In that case, once again, Rick’s advice is the way to go.


Returning to scenario number one... What would Rick’s answer have been had the question been, “How do I get started learning COBOL? My guess is that Rick would have asked WHY they wanted to learn COBOL. Now is the time to convert or rewrite legacy applications. It will never be less expensive; aren’t labor costs always going to increase? It will never be easier; the project will only grow in scope as the legacy app grows. At the very least, a far-seeing IT manager should realize what is inevitable and begin to make plans to move forward. In the meantime, and this will sound like an advertisement, the most cost effective solution in the long run is to hire the right people who already have the experience and knowledge necessary to keep the application afloat while your company prepares to move forward and stay ahead of the competition. The people you hire to maintain the legacy app could even be involved in the conversion.


Comments?  I would love to hear them; I have thick skin.

Posted by Dave Aring on August 26, 2008 | Permalink | Comments (0) | TrackBack (0)

August 25, 2008

When a "Watch Window" expression goes in and out of scope

It used to be extremely frustrating to me when a "Watch Window" expression went in and out of scope.  Now, I simply employ a technique I learned in Nancy Folsom's short but excellent book Debugging Visual FoxPro Applications (http://www.hentzenwerke.com/catalog/debugvfp.htm).

On p. 53, Nancy indicates that:

  "If you know the value of the expression you're looking for, you can create a 'Break when expression is true' breakpoint and enter a conditional IIF() in the Expression field.  The expression would look like the following:

  IIF(TYPE('SomeExpression') = 'C', SomeExpression = SomeValue, .F.)

  "This expression will cause the program to be suspended only when the value of the expression is what you expect."

Here's an example of an expression:

  IIF(VARTYPE(RECCOUNT('lv_WDates')) = 'N', RECCOUNT('lv_WDates') = 6, .F.)

Michael Cummings of the Los Angeles FoxPro Users Group (LA Fox) suggested an even better technique [viz., test for VARTYPE(…) = 'U']; here's a translation of the above:

  IIF(VARTYPE(RECCOUNT('lv_WDates')) = 'U', .F., RECCOUNT('lv_WDates') = 6)

Testing for an 'U'ndefined data type obviates having to get the variable's data type "right" in the breakpoint expression.

Patrick O'Hara of the Chicago FoxPro User/Developer Group (CFUDG) reminded me that [Ctrl + B] brings up the Breakpoints dialog box.

Posted by abergquist on August 25, 2008 | Permalink | Comments (0) | TrackBack (0)

August 21, 2008

Debugging errors that occur only in production code

There are a few techniques to debug errors that occur only in production:

1. Insert the following line:

MESSAGEBOX('<n>. ' + PROGRAM() + ' ...')

at "strategic" points in the program (e.g., before calling a function, method, procedure, etc.).  I start "n" at 1 and increment by 1 in subsequent MESSAGEBOX() calls.  The last number that displays in a MESSAGEBOX() before an error occurs helps me narrow down exactly where the problem is occurring.  If necessary, I delete the original MESSAGEBOX() calls and then insert new MESSAGEBOX() calls "closer" to where the error is occurring.  (Repeat as necessary [and, yes, you can -- and should -- try this at home <g>].)

2. Another technique is to write text to a log file (.Log, .Txt, etc.) at various points of/during program execution.  (This technique, by the way, is also useful for debugging COM objects since you cannot step through code in the VFP debugger nor can you [or are supposed to] send output to the screen from a COM object.)

3. In VFP 9, you can do coverage logging not only at design time but also in .EXEs (via the SET COVERAGE command).  Your client will need to send you the coverage log file  (generated by the SET COVERAGE command) which you can then run through the Coverage Profiler yourself.  Put code like the following toward the top of your main calling routine:

ON ERROR SET COVERAGE TO
SET COVERAGE TO <filename of your choice>.Txt

Posted by abergquist on August 21, 2008 | Permalink | Comments (2) | TrackBack (0)