alvechurch data ltd - tips foxpro
TRANSCRIPT
![Page 1: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/1.jpg)
Tips del site de Alvechurch Data Ltd
---------------------------------------------------
Frequent and automatic backupsWe've all got huge hard disks now with plenty of space to hold as many backups as anyone could need. The only restriction is the hassle of making the backup and the difficulty of finding a good name for each generation. A formal Source Control System would solve both problems but that might be too restrictive in a small development shop like ours. Instead, we use this routine to generate a unique folder name based on the datestamp and copy the files across to this folder.
This is the Visual FoxPro implementation, there is a similar version here in Access VBA.
#DEFINE SU_HOME '\Projects\web\'
*-- Getting the date as yyyymmdd is easy with *-- the DTOS (Date To String) function in Fox lcToday = DTOS(DATE())
*-- The time has colons between hours, minutes, and *-- seconds. These are illegal in a file name so *-- change them to underscores with the CHRTRAN *-- (Character Translate) function. lcNow = CHRTRAN(TIME(), ':', '-') lcTimeStamp = lcToday + '_at_' + lcNow lcDevDir = 'D:' + SU_HOME + 'Dev'
*-- The folder E:\DevBackup\....\Backup\ must exist lcBackupDir = 'E:\DevBackup' + SU_HOME + 'Backup\' + lcTimeStamp
fso= CREATEOBJECT ('Scripting.FileSystemObject') fso.CopyFolder (lcDevDir, lcBackupDir) fso = null
This code takes the development folder for this project (defined as SU_HOME) and uses WSH (the Windows Scripting Host) to copy this folder to drive E: which has a folder with the same name as the development area. All the development files are copied here into a new folder with a name like Backup\20021023_at_16-53-58. It's not a pretty name but it is easily readable and it will be unique unless I manage to run two backups within the same second.
A typical use is to copy:
D:\MyDevWork\*.* to E:\Devbackup\MyDevWork\Backup\20021023_at_16-53-58\*.*
Note that you will get a COM error if the folder E:\Devbackup\MyDevWork\Backup\ does not exist. A bit more work with error trapping and the File System Object will solve this problem.
In my FoxPro development work, I have this routine tied to the F12 key with an ON KEY LABEL F12 ... statement. This allows me to create a complete backup at any stage of development by
![Page 2: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/2.jpg)
pressing F12.
You may think that regular backups will take too much space but today's hard disks are sized to hold hours of video and have plenty of space when a programmer's backups are plain text files. At the time of writing we have 97,652 backup files taking up 8.62 GB of an 80 GB drive that's installed in a spare drive bay. We've also got a library of weekly and monthly backups on CD. The drive is just another level of insurance.
Design a form to make data entry easier and more accurateThe Japanese concept of Poka Yoke - "Mistake Proofing" - is common-place in manufacturing engineering. Assemblies are designed so that it is physically impossible to put them together in anything other than the right way. This idea seems to have been slow to reach computing.
Looking at the physical design of PCs there are still machines where mouse and keyboard have identical plugs and where sound cards have three identical sockets set close together at the back of the PC where you can't easily see them. The sockets are colour-coded but there's not much difference between the pale blue and green colours and it's so very easy to plug the speakers into the microphone socket.
We cannot do anything about those physical problems but we can improve the design of our software and improve the speed and quality of data entry. With a little attention to detail we can make it more difficult for users to make mistakes when filling in forms. A little careful thought when you're designing a form can make a big difference to the ease and accuracy of data entry and can make the difference between a form that's a struggle or a pleasure to use.
Here are a few things to think about:
• Set default values where they'll be helpful. If most of your customers are in Birmingham then make 'Birmingham' the default town and '0121' the default dialing code.
• If the field has to be three groups of fours digits separated by dashes then give the user three text boxes separated by dashes and reassemble the three components into the full text before saving it.
• Use dropdown lists if the user has a choice between just a few different values in a field. Don't ask the user to type the same few values in time and time again.
• Make sure the user can tab around the fields on a form in the right order. Select Tab Order from the View menu when you are designing a form.
• If users are copying data from paper forms then design the screen form so that the fields are in the same relative positions. If the paper form has LastName before FirstName but your form has FirstName before LastName then errors will be made.
• On a similar line, use the terminology that is familiar to the user. Don't ask for Christian Name and Surname if the paper form lists them as First Name and Last Name.
• Don't ask the user to do mental arithmetic. If postage is usually 10% of the order value then offer that value as a default. And ask yourself if you should even be asking for a value which can be calculated when required.
• Choose the right data types and sizes. UK Postcodes are eight characters long at most so restrict the user to eight characters of data input. If you give them twenty characters then they might be tempted to type something else here.
• If you ask the user for a date then consider using a calendar control instead of a plain text
![Page 3: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/3.jpg)
box.
• If a calendar is not possible then display the day of the week to help the user:
• Calculate the date that the users are most likely to want. If deliveries take ten days then default to a date ten days from today and add the logic to avoid Saturdays, Sundays and holidays.
• Choose a font where the user cannot confuse '1', 'I' and 'l'.
![Page 4: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/4.jpg)
Duplicate names and addressesRemoving duplicates is one of the more difficult tasks when you're working with lists of names and addresses. There are three ways of doing this - four if we include the simple-minded approach of leaving it all to the user:
• Let the user do it • Help the user during data entry • Give the user some semi-automatic tools • Develop a fully-automatic solution
Whichever method you use, you will not get anywhere until you have a consistent layout for your address data.
Different businesses have different views of duplicates so you must get managerial support for your strategy. A business sending out cheap mailshots to an unsophisticated audience can afford duplicates. A business sending out samples of high-value products will be more demanding.
Let the user do itThis can work with a good operator who is the sole user of a small data set that changes slowly. If there are only a thousand or so records then the user will become familiar with the names and will notice if two names are similar.
You may need to provide some extra tools to modify other tables in the database before a duplicate can be removed. For example, the orders that were assigned to the duplicate entry must be reassigned before the duplicate can be removed.
Help the userEven the best user cannot be expected to remember all the entries in a large table or in one that changes rapidly. Duplicates are difficult to remove once they become established so the best time to catch them is at the time of data entry. Show the user a list of possible duplicates before committing this new record to the table.
A search on the following fields will pick up the majority of potential duplicates:
• Surname + Initial • Postcode • Phone number • email
If you can catch the duplicates before they get entered into the table then you do not have to do any tidying up afterwards.
Semi-automatic toolsIf you are checking for duplicates at the time of data entry then you must do it quickly. The list of possible duplicates must appear in less than a second, especially if your user is taking details from a new customer by phone. You can build a tool that does a more thorough search and include it on the maintenance menu.
Consider adding the following additional tests as a maintenance tool:
• Names that sound similar eg 'Philips' and 'Phillips'
![Page 5: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/5.jpg)
• Compound surnames with spaces and hyphens removed • Alternative first names eg 'Bill', 'Will', and 'William' • Same surname at the same address
The Soundex algorithm generates an alphnumeric code based on the pronunciation of the name and can be used for phonetic matches. It is however not as helpful as it might seem. For example, 'Cawley' and 'Crawley' might easily be duplicates but they map to codes of 'C400' and 'C640' respectively and would not be picked up by Soundex. On the other hand, 'Brighthelmstone' and 'Brigadoon' both map to a code of 'B623' and so would be considered possible duplicates by a Soundex match.
If you do build such a housekeeping tool then it might also be a good place to look for the predictable joke names such as 'M. Mouse' and 'B. Bunny'.
Automatic toolsIt is very difficult to remove duplicates automatically. You must have a rigid data format as a starting point and be confident that names of towns, counties and countries are spelt consistently. You will also have to write algorithms that can identify house names, road names, and suburbs and extract these components of the addresses. These routines must be robust enough to cope with addresses that range from the minimal:
Batheaston HouseBath BA1 1AA
to the baroque:
Flat 2a"The Lodge"The Batheaston House InnHigh House LaneOff Bath RoadBatheastonNear BathBath and North East Somerset
Are these duplicates? Only a local could tell you.
![Page 6: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/6.jpg)
Handling errorsErrors are something we have to face in the real world so everything you write must have something to handle errors. Different languages have different mechanisms for handling errors but the same concepts will apply to them all.
Basic concepts
Coverage
You must make sure that you are able to respond to any error anywhere in the program. It can be very tempting to take a short cut and leave the error handling out of a short piece of code where 'nothing can possibly go wrong". Resist this temptation and make sure that you've made provision for errors no matter where they may crop up and how unlikely they are.
Recursion
The error handler cannot handle errors inside itself. The first action of an error handler routine should always be to turn off or to redirect redirect the error handling. If this is overlooked then any error in the error handler code will call the error handler and run into the same error again, and again, and again until something in the internal structure of your program overflows.
If you have to turn error handling off completely inside the handler then any error in the error handler leads to a messy crash. At least it will crash immediately without doing any damage elsewhere.
Robustness
At the risk of stating the obvious, the error handler has got to work first time, every time. Keep it as simple as possible. This means that the handler must be completely self-contained. If it uses your bespoke user interface object to display a message for the user then the handler will lock up if the error happens to be in that very object. Use the simplest means of output available - typically a Windows messagebox.
Levels of responseNot all errors are equally serious. Your error handler should have at least four levels of response:
Silent
Log the error to disk but do not interrupt processing or say anything to the user. You can use this level of response for diagnostic records that will give you advance warning of future problems. Use it as a trace mechanism to profile the typical usage of the system. If you are worried about the speed of a particular operation then create a log entry at the start and end of the process. This will tell you how long it really takes for a typical user to process real data on an everyday workstation. It will also tell you how often the situation occurs. All very useful information when you are trying to decide which problem needs to be fixed first.
Try again
Most of the errors in this category relate to the interface with the outside world. They might be
![Page 7: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/7.jpg)
caused by a problem with the hardware or by a mistake from the user. The cause might be a printer that's empty of paper, a drive with no disk, or a user asking for the impossible. The error handler should give the following information to the user:
• What has happened • What are the implications • How they can recover
It should also give them the opportunity of trying again or of abandoning the operation.
Avoid
These too are typically caused by the failure of something outside the application but this time it's something over which the user has no control. An example might be a problem with a communications link which means that data cannot be imported from another site. The error handler should tell the user what has happened and confirm that the rest of the application is still running as normal.
Abandon
Finally there are the serious errors which mean that the application cannot continue to run safely. There are two sub-divisions here:
• problems with the installation such as the failure of a network drive • problems with the application itself such as a Divide By Zero error.
In either situation, the error handler should tell the user what has happened and then shut the application down as safely as possible.
Messages to the userThe user rarely cares what has gone wrong and only needs two items of information:
• What damage has been done. • Can I do anything to repair it.
The user should never see a raw error message from the programming language. Something like 'Invalid File Offset' will be utterly meaningless to most users. If the user has to report the error to an internal Help Desk then display a message with an error number - something like:
Error 42 Please phone the Help Desk on extension 1234.
The number might be the raw error code from the language or you may want to draw up your own list of codes.
Error logAn error log is invaluable if you are supporting an application from off site. The log should record time, date, user, and workstation so that you know who had the problem and it should record the name of the program file and the line number so that you know where the problem occurred. Rather than having to listen to exaggerated tales of problems you can read the log and see exactly what has been happening.
![Page 8: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/8.jpg)
Consider having two types of error log; a simple log that merely records the facts listed above and a verbose log that records far more detail such as the amounts of free disk and memory space, the version and sub-version of the operating system, and chain of programs and operator actions that lead to the error. The verbose log will make the application run more slowly and will generate a large log file but sometimes that will be the only way of investigating a problem.
The error log can be recorded as a simple text file but if you store it in a table then you will be able to analyse it and extract information such as the most common types of error and the frequency of these errors.
![Page 9: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/9.jpg)
Fonts for data entryAs with the problem of chosing the right shape for a form, chosing a font was much easier back in the days of DOS. You only had one possible shape for the form - full screen - and only the one font.
Windows has given us a huge range of fonts and some are better than others in a database. Clients often want to see all the text on screen in their corporate font but we try to resist this because some fonts really are a poor choice for data entry and display. The correct choice of font will make a great difference to the usability of the form. This example shows the difference between data entry fields in Gill Sans, Arial, and Courier fonts. It's an extreme case but it does show the problems.
All three fields display the same value: four lower case "L"s followed by four upper case "i"s followed by two number 1's. This is not at all obvious in the Gill Sans and Arial fonts and there is a real chance of the user making a mistake with these two fonts.
Gill Sans
Gill Sans is a fine font for the display of text but it shows the capital "i", the lower case "L" and the number 1 as exactly the same symbol. Your only clue is that there is a slightly wider spacing between the numbers than between the letters.
This similarity does not matter when Gill Sans is used in its proper surroundings. A user reading a passage of text can tell which character is which by the context and no harm would be done. Matters are very different when the user is entering data or searching a database for an alpha numeric serial number like "I411-101".
Arial
Arial is the default font for forms in MS Access, Visual FoxPro and Basic. It does allow the user to identify the number 1 but the letters "I" and "l" are still identical. What's worse is that the letters are very close together and some users find it very difficult to place the cursor exactly on a particular character. This example by the way is in 12 point font. If it were in a more normal 9 or 10 point then users would be in real difficulty.
Remember that as a programmer you've probably got a better PC than most users and you are also more likely to be really comfortable with your mouse. Think of a user with an old gritty mouse or with a laptop and trackpad.
Courier New
Despite its name, Courier New looks very old fashioned and no style-conscious designer would consider using it for a moment. The font is an old one but the reason that it has survived is that it is a very good font for data entry. It is not a font to use where there is any amount of text to be read
![Page 10: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/10.jpg)
but it is an excellent font where you are just showing a few words.
Courier New has three advantages:
1. Every character is different. The user will have no difficulty reading data or entering values for a search.
2. The characters are well-spaced and the user can easily see the position of the cursor between two characters.
3. It is a fixed-pitch font and all the characters are all the same width. The prompt asks for a serial number of ten characters and the textbox is exactly the right size to accept ten characters. If the serial number had contained a lot of wide characters such as "W" and "M" then the Arial and Gill Sans text boxes would have overflowed.
Other fonts
There are of course other fonts, many other fonts. We do all our work on Windows PCs and cannot comment on fonts for Macintosh or Linux.
We use Tahoma as a default for all captions and it's a good font for data entry as well. The characters "1", "I", and "l" are similar but not identical and the proportional spacing is not as extreme as Gill Sans.
Lucida Console is a sans-serif fixed-pitch font that makes a good alternative to Courier New if the client absolutely refuses to have such an old-fashioned font on their screen.
Times New Roman is possibly the oldest font in Windows and it's difficult to see why anybody would want to use it. It has proportional spacing and is bad for data entry because it tends to bring some letters very close together. Times New Roman was designed for text on paper and newer fonts such as Tahoma and Verdana are very much easier to read if you want to show a lot of text on screen.
Fonts in Visual FoxPro
This general advice on fonts applies whichever development language you are using. We like to work in Visual FoxPro because its object-oriented features allow us to build class libraries of custom controls. Our standard library has the font set to "Courier New" for all its data entry classes and to "Tahoma" for all its captions. If a client insists on using a corporate font for their application then it's a simple matter to create a new set of subclasses and use them instead.
![Page 11: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/11.jpg)
The golden ratio in form design Designing a form was very much easier back in the days when all we had was a monochrome screen displaying text. The screen was 80 characters by 25 lines and that was the shape of your form. FoxPro 2 for DOS gave us character-based windows but for most of the time we still used the entire screen area from force of habit. These days the graphical user interface (GUI) has given us lot more flexibility but this flexibility brings the drawback we have to make a lot more design decisions every time that we start a new form. Making decisions takes time and our life has been a little easier since we decided to restrict ourselves to a few standard form sizes.
Forms are rectangular and rectangles come in many shapes. At the extremes a rectangle can be tall and thin or short and fat but somewhere in the middle of the range there must be a shape that is or just right. Artists and architects believe that the "just right" appearance comes when the ratio between the lengths of the sides is close to 1.618:1, the golden ratio. This form is 491 x 303 pixels and has sides in that ratio:
If you want to see an everyday example of the golden ratio, take a look at a credit card. Sizes vary slightly but 86 x 53 mm is a typical size and 86/53 is 1.62.
Properties of the golden ratioA rectangle in the golden ratio has the unusual property that you can cut a square out of it and be left with a smaller rectangle which is also in the golden ratio. In mathematical terms:
width/height = height/(width - height)
If you multiply this out and solve the quadratic equation you'll get answers of 0.618 and 1.618. Simple arithmetic proves that these answers are correct:
1/1.618 = 0.618 1/0.618 = 1.618 1.618 - 1 = 0.618
The value of 1.618 is not exact because the golden ration does not have an exact value. It is an irrational number like pi and mathematicians use the symbol phi (φ) to represent the exact value of 1.618033988749895 ...
![Page 12: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/12.jpg)
The form above is 491x303 pixels, as close as I could get to a ratio of 1.618 without fractional pixels.
If you remove a square of 303 pixels you are left with 188x303 pixels, another ratio close that is to 0.618.
Remove a square of 188 pixels from this smaller rectangle and you are left with 188x115 pixels, again very close to 1.618.
Golden ratios within a formLooking at it geometrically:
Splitting the form horizontally in the ration 1.618:1 gives a nice balance between the two main areas of the form. The square of 303 pixels holds the name and address information and the golden rectangle of 188x303 splits into a smaller square and yet another rectangle.
Form sizesGoing back the the original point about having to decide what size the forms have to be, we've bypassed this decision by picking four basic sizes for our forms:
• 794x491 - fills an 800x600 screen nicely • 491x303 • 303x187 • 187x116 - big enough for a textbox and a couple of buttons
Using this restricted range holds the application together nicely because the user sees a consistent range of forms rather than a mixture of short and tall and fat and thin. The two larger forms always appear in landscape orientation but the smaller ones are sometimes useful in portrait form too.
Just as an aside, we usually design for an 800x600 screen because that seems to have replaced 640x480 as the lowest resolution we see in commercial office use. We can never rely on being able to use the full 600 pixel height of this screen because the user will always have the Windows status bar at the bottom of the screen and may well have a Terminal Services bar and Office bar taking yet more pixels off the height.
![Page 13: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/13.jpg)
SummaryThese form sizes are only a guide. If a form really needs to be a different size then we choose a size which meets the needs of that particular form. Most of the time though we just pull one of these standard forms out of the library and get on with the job.
![Page 14: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/14.jpg)
Normalize a databaseThe goal of normalization is to remove the following dangerous features from the database:
• Duplication of data • Inconsistent data • Ambiguous data
Normalization starts off as a mechanical process where you just follow the rules but these rules can lead to a ridiculous end result. The final design does need to be adjusted by an intelligent hand.
Stages of normalizationThere are six stages to Normalization but the first three - known as the 1st, 2nd, and 3rd Normal Forms - are adequate for most situations. The other stages - Boyce-Codd, 4th and 5th - are more relevant to academic study and even then it can be difficult to generate examples to show the need for them.
1st Normal Form (1NF)
• There is a Primary Key that uniquely identifies each record. • There are no repeating fields - you don't have a series of similar fields named 'Item1',
'Item2', 'Item3', etc. • Remove any such fields into a separate table and include a foreign key that refers back to the
matching record in the parent table.
2nd Normal Form (2NF)
• The table is in 1st Normal Form and all fields depend on the entire primary key. This happens automatically if you are using a simple primary key based on a single field.
• If you are using a composite key made up of two or more fields then you have to check that no other field relies on just one of them.
• Remove any such fields into a separate table, together with that part of the primary key on which they depend.
3rd Normal Form (3NF)
• The table in 2nd Normal Form and no fields depend on anything but the primary key. • Remove any such fields to another table, leaving the key in the original table.
Result of normalizationThe process starts with all your information in a single flat table and normalization gives you a number of smaller tables that hold the same information but which hold it in an efficient and unambiguous way. The process so far has been mechanical - in fact Microsoft Access has a Wizard to do it for you automatically - but there are three factors which need some intelligence to avoid unnecessary complications.
One-to-one relations
Normalization will never generate two tables with a one-to-one relationship between them. There is no theoretical reason to separate a single entity like this with some fields in a single record of one table and others in a single record of another table but you might want to split a table into two for practical reasons in order to:
![Page 15: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/15.jpg)
• reduce the number of fields in a table and meet some limit in the programming language. • store large and rarely-used fields in a separate table so that you do not waste time
transferring and processing them during routine operations. • separate sensitive information from commonly-used fields so that the tables can be stored
and backed-up separately.
Many-to-many relations
A many-to-many relationship cannot be implemented directly in a relational database and has to be represented by an intermediate table that shows the many links between the two tables. Sometimes this intermediate table will just hold these two foreign keys; for example the Customer ID and the Product Code where you have to represent the situation of many customers, each of whom are placing many orders. Sometimes more information will be held, for example the discount offered on this product when ordered by this customer.
Normalization will tell you that Customer and Product information should be separated from the original flat Orders table because every customer places many orders and every product is included in many orders. Normalization will not tell you how best to implement the link between these tables.
Denormalization
Normalized tables store data as efficiently and as safely as possible without duplication but you may need to denormalize in order to:
• make reporting easier for non-technical staff • create a Data Warehouse • improve the speed of execution • reduce the length of an SQL statement and comply with language restrictions.
Remember that the theory of normalization was developed at a time when a megabyte of disk storage space cost over £100. Prices now are less than a tenth of a penny a megabyte and there is no longer the pressure for such extreme efficiency. Processor time has also become very much cheaper and developer time is now much more expensive than either.
As an extreme example, you could normalize an address table and realise that the same county name occurred many times. According to the rules you would separate the county names into their own table with a CountyID key in the address table. But you would then realise that the town names also repeat and they need their own table too. As do the street names and the postcodes and the telephone numbers. The rules have no discretion and no common sense. If a single postcode occurs twice in the main table then it has been repeated and so postcodes must be stored in a separate table.
The normalized database now consists of county, town, district, street, house name, house number, postcode and telephone tables. This might save disk space but you would need an awkward and inefficient query to join these eight tables every time that you wanted to generate a customer address. This normalization is correct in theory but totally wrong in practice.
![Page 16: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/16.jpg)
Specifying a databaseOur clients come from a range of backgrounds and we have received many different styles of specification. Some are more helpful than others. If you're a database user then the following hints might help you when you specify your next database. If you're a database developer then they might help you be more helpful to your client:
• Use the language of your workplace, don't use technical terms. • Say what you want to achieve, not how you want to achieve it. • Concentrate on what information you need to get out of the system, don't specify the size
and type of the database fields. • Don't tell the experts how to do their own job and don't get bogged down in the details.
The best specifications are simple ones. Give your database developers a simple request and they will be able to deliver it in a matter of a few days. You can then use this simple system for a while before you decide on the next move. The 'giant leap' method of specifying the whole system in minute detail only works where there are large teams on both sides who have plenty of spare time to argue over the contractual implications of every detail.
If database development can proceed in smaller steps then your developer c can work with you to make sure that each step is sound before making the next one.
A useful analogyWe have just paid a plumber and his assistant several thousand pounds to refit our central heating system. I trained as an engineer and am quite capable of cutting and bending pipes and soldering them together but I was persuaded to call in the experts for this job. That was a good decision because this pair did the job well and were finished in less than a week. It would have taken me a month of weekends to do the same work.
We did not specify the exact location of the radiators beforehand because the plumber needed to see how the existing pipes had been run before he could tell us the best place for the radiators. If we had given strict instructions then the system would have cost us even more money.
Whilst they were working I stayed out of their way. If they wanted a decision like 'Where would you like this radiator?' then I tried to give them a quick answer and went back to the office without offering any more advice. Telling them how to do their job would only have upset them and they might not have been as cooperative or helpful.
Treat your database developer like we treated our plumbers:
• Tell them what you want. • Keep out of their way. • Inspect their work afterwards.
But please don't tell them every little detail of how to do it.
![Page 17: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/17.jpg)
Software TipsThese tips apply to software development in any language. Many of them are obvious but I hope that some might be useful:
1. The most reliable code is the code that isn't there. Keep your systems small and simple. 2. Program code describes what you are doing. Add comments to explain why you are doing it. 3. If you're writing a case statement it's very easy to forget the EndCase or to write EndIf
instead. Write the skeleton of a code structure before filling it in. 4. Code should be as small and fast as necessary. No smaller. No faster. Don't waste time on an
ego trip making it better than it needs to be. 5. Write an error handler first and make it log errors to a disk file. Use error numbers so that
your users can report a number rather than having to read you the text of an error message. 6. Always write for multiple users and for many languages. The extra features will not always
be needed but you'll save time in the long run. 7. Take a random walk through Help or the manual once in a while. You will find lots of things
that you had forgotten. 8. If you are going to make simplifying assumptions and take short cuts - document them. 9. Design the structure before you write the code. 10.The first thing that you add to a program is a means of stopping it. The Cancel button is the
first control you add to a form.
![Page 18: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/18.jpg)
Tower of Hanoi pattern for backupRegular backups are vital to protect ourselves against failures of the software, the hardware, or even of the users. There is always a conflict between the need to have frequent backups and the cost of keeping such backups for a long time. The Tower of Hanoi pattern is a useful compromise.
Where does the name come from?The name comes from the children's game where you start with three pegs on a piece of board. The object is to move a pile of discs from one peg to another by moving one disc at a time and never putting a larger disc on a smaller one. The game in turn comes from 19th century myth about an Eastern temple where the priests are engaged in moving 64 gold disks from one diamond needle to another. They have been doing this day and night since the beginning of time. When they complete their task the temple will crumble and the universe will end.
What's the connection?This algorithm is the fastest solution to the Tower of Hanoi game:
• Move the smallest disc clockwise • Make the only other legal move not involving the smallest disc
It generates the following pattern of moves on a tower of three discs A, B & C:
• Move A • Move B • Move A • Move C • Move A • Move B • Move A
The solution is recursive and can easily be extended. If there were four discs then you would use the three-disc solution to move the top three discs off of disc D, move disc D, then use the three-disc solution again to put the three discs back onto disc D. The three-disc solution is:
ABACABA
so the four-disc solution is
ABACABADABACABA.
If there are five discs then the solution is to use this pattern to move the top four, then move the bottom one, and then move the four back again:
ABACABADABACABAEABACABADABACABA
We can also go the other way. The original three-disc pattern of moves is made up of an "ABA" pattern to move two discs off of the largest disc, "C" to move that largest disc, then "ABA" to move the two discs back onto the largest one. And you can analyse the "ABA" pattern in the same way - Move "A", then move "B", then move "A" back again.
How does this help with backups?The five-disc solution above is a string of 31 characters which consists of five different letters. You
![Page 19: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/19.jpg)
could use it as a schedule to give you a month of backups by using five tapes labelled "A" to "E". It won't give you a backup for every day of the month but at the end of the month you would have a very good spread of data on your five tapes:
A. One day old B. Two days old C. Four days old D. Eight days old E. Sixteen days old
This binary pattern extends very quickly. A sixth tape would be used every 64 days, a seventh every 128 days, and the eight, ninth and tenth tapes would come up every 256, 512, and 1024 days. A box of ten tapes (or CDs or DVDs) would last for nearly three years. In practice we make a full backup every week and use six CDs.
How do I do it in practice?The easiest way to lay out a month's Tower of Hanoi pattern is like this:
• Mark every alternate day as "A" • Mark every alternate blank day as "B" • Mark every alternate blank day as "C" • Mark every alternate blank day as "D" • Mark every alternate blank day as "E"
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16
A A A A A A A A
B B B B
C C
D
E
Generating the schedule in codeThis FoxPro procedure will print the sequence for five disks:
lnNumDisks = 5 lnLen = (2 ^ lnNumDisks) - 1 *-- Loop through the days For lnDay = 1 To lnLen For n = 0 To lnNumDisks *-- Test the nth bit of the day number and *-- bail out of the loop if it's True If Bittest (lnDay, n) ?n + 1 Exit Endif Next lnPos Next lnDay
The code relies on the link between the Tower of Hanoi and the digits of binary numbers. If you write the binary numbers from 1 to 31 you'll see that the final digit is '1' on every alternate row. Looking at the remaining rows you'll see that the penultimate digit is '1' on every alternate row.
![Page 20: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/20.jpg)
Types of join in an SQL queryThe Structured Query Language (SQL) allows us to write queries that pull data from more than one table. There are four basic ways of joining two tables together.
'Left' and 'right' just refer to the way that the diagram has been drawn. It's usual to draw the parent table on the left and the child on the right.
The classic example is a small database with a Customers table and an Orders table. Each customer is identified by a unique Customer_ID and each order has a Customer_ID to link it to a particular customer. In this system the four types of query are:
Inner JoinThe inner join is the most common and useful type of query. Most of the time you are interested in the records that match in the two tables and this is what the inner join gives you. An inner join of Customers and Orders would return details of all the customers who have placed orders together with the details of the orders that they have placed.
Left outer joinThe left outer join is the next most useful because you'll often want to produce a report showing the activities of all customers and even if a customer has placed no orders this month you'll still want to see them on the report.
There is a small snag with the left outer join in that the customers who have no orders won't have any order details. Instead the query will return a Null in all the fields from the Orders table and you'll have to process this and produce something more meaningful to the average user.
Right outer joinA right outer join is the opposite of the left outer join. It's less useful in regular work but can be handy for housekeeping and maintenance.
Staying with the customers and orders example, a right outer join will show you all the orders regardless of whether or not they belong to a customer. These orphan entries are obviously meaningless and records like this should not exist. It's useful to check for them once in a while though - just to make sure that your data integrity routines are still working properly.
![Page 21: Alvechurch Data Ltd - Tips Foxpro](https://reader034.vdocuments.us/reader034/viewer/2022051521/577cceb81a28ab9e788e31a3/html5/thumbnails/21.jpg)
Full Outer JoinAs its name suggests, a full outer join returns all the details of all the customers regardless of whether or not they have placed an order and all the details of all the orders regardless of whether or not they belong to a customer.