This is an attempt to write down an assorted collection of mental notes I gathered while developing a VB application for 1 year using VisualBasic 5.0 SP3 [IE: VbClassic]. I'll try to list every pitfall I found, and some advice on how to prevent them.
- Get the service packs, but not when they are immediately released. Sometimes they introduce new bugs that are corrected in a subsequent service pack. Look around in the Internet to see if the service pack is worth installing.
- If you are starting a new application, before you start coding, apply all service packs. You may have code that depends on something that changed between service packs and will only find the bugs later on.
- See what .OCXs are used by your program's controls, copy them to a private directory, and use the copy instead. Apply service packs before this step. This is especially important if you only distribute the full blown installation once and then only copy the .EXE to your users, because if a .OCX in your PC gets upgraded, the .EXE will be using this new version, and won't run with anything less. (It will give a "Run Time Error 50003: Unexpected Error").
- Keep you development PC as stable as possible, don't install unnecessary applications, especially those that need a bazillion .DLLs. Also have a resident anti-virus software.
- Explicitly declare all your variables. (Check "Force variable declaration"). I think everybody knows this but it is worth repeating.
- When you need an integer variable, always declare it as long and not integer. You may need to store a number bigger than 32767, and forgot to declare it long. In 32-bit code long variables are as fast as integers, and for your run of the mill sub variables an extra 2 bytes per variable does not make a difference. However if you are working with big arrays and know that the values will fit in a integer you may want to use integers after all. Use your common sense.
- Always de-allocate what you allocated. Don't trust VB garbage collection. This will teach you to write clean code, and prevent you from shooting yourself in the foot later on. If you redim a dynamic array, always erase it when you don't need it. Unload unneeded forms. Clear combo boxes, list boxes or grids that you populated. Close all recordsets, databases, workspaces or whatever when appropriate. Unload all controls you loaded at run time.
- Don't use the End keyword to terminate a program. Again, much ink has been used on this subject. Instead of 'End', loop on the Forms collection, and unload each of them.
- Never use Access databases for mission critical applications (some would say VB for that matter). VB applications are not very robust, but the Access database is weaker. If you are stuck with it:
- Make the application compress the database regularly (say weekly).
- Provide some way to repair the database followed by a compress.
- MAKE BACKUPS. This applies to any application but it is worth repeating.
- Do not use the same database for different users if you can avoid it.
- If you develop on Windows NT and the application may run on Windows 95/98 be aware that Windows'95/98 GDI memory is limited to 2 MB, while on NT it grows dynamically. So if you have very complex forms, an application that runs fine on NT may fail on Window'95/98 with a "Error 7: Out of memory" even if it has plenty of main memory available.
- Do not rely on automatic type conversion of variant type variables from string to double. Try this on VB5 SP3
Dim v as variant
Dim d as double
v = ".3"
d = v
Msgbox "v = " & v & " d = " & d
v = "0.3"
d = v
Msgbox "v = " & v & " d = " & d
- Remember that the decimal separator is country specific, and that the function CDbl has bugs (Cdbl bugs depend on OLEAUT32.DLL version). Try and see the result of: Cdbl(".3"), CDbl("0.3"), CDbl("."), CDbl("") assuming that "." is your decimal separator. I use my own function that replaces the system decimal separator by "." and calls val(). It works!
- BTW do not use the Variant data type unless you need it. Then again everybody knows this.
- Error handling: I don't think there's a final decision on this, but here it goes: Use wrapper classes around VBs Database and Recordset objects. The wrapper will provide error handling and report back the completion status. Having a central error management subroutine has the inconvenience that the error message must be generic, because you don't know where it occurred. However this should be the last case handler, the code should try to anticipate errors and prevent them from happening, so it's better to have a generic message than bombing the application.
- If your application runs inside the development environment, but not when compiled try to compile to byte code instead. I don't know why this happens but it happened to me, so be warned (Specifically, two subroutines were receiving their arguments with different values than the ones I used when I called them! Compiling to byte code solved the problem).
--
JoaoLuisSilva
- A feature of VB 3 that is broken in VB 5: In VB 3, you can draw gray letters and ovals that are not outlined in black. In VB 5, trying to draw "BeO" in large gray letters results in black outlines around the gray letters.
Criminy! With all that trouble unrelated to the actual language, I'd suggest shortening this page to Learn to program on a UNIX system
Helpful Comment there. The problems described here are specific to VbClassic but in general all frameworks have issues and quirks that need to be dealt with. When you throw in custom components written by other individuals then you have a merry mess.
Visual Basic is one of the fastest ways to create a Windows program. But like any tools you have to know when and where to use it. Visual Basic can be used to create full featured applications and you will save a lot of time using it, if you use good software development practice.
However the reason that you save time is that a lot of the nuts and bolts are in a layer beneath the VB program. (ActiveX libraries, controls, VB runtime, etc). So you have to be prepared to deal with the issues and/or bugs of that layer.
I recommend getting both Design Patterns, Refactoring by Fowler, and download one of the unit testing frameworks for VB6. Although Visual Basic doesn't support inheritance, most of the Design Patterns deal with interfaces which is supported by Visual Basic. Design Patterns will help you with the overall structure of the program, and refactoring will help you changes the program when you find that you have the design wrong or need to extend. The unit testing allow you to quickly pinpoint problems with any change you make.
My top suggestions for designing software with VbClassic
1) Learn how to and write call windows DLLs from VbClassic. This will require learning C/C++ or another language. This will greatly expand your choices for solutions.
2) Separate the User Interface from the Data Structures by using ActiveX DLLs.
3) In the User Interface separate the Forms from the Commands. Use the Command Pattern from Design Patterns. Again use Active X DLLs. Ideally the only thing that should be in your EXE project are the forms.
4) Don't blow off unit testing. If you use the command pattern to encapsulate actions you will find that unit testing becomes much easier.
5) You should design your VB ActiveX DLLs so that the number of files you need to update for specific types of changes or bug fixes is minimized. For example if you want to add or change a report a good design will require that only DLL be changed.
6) For features that are continually being updated consider making an interface, and use the Factory pattern to isolate those features from the rest of the software. For example have all reports in their own DLL, and have them all implement IReport. When the software starts have a factory class in that DLL return a collection of IReport. Typically the two areas that need this are reports, database connections, and files import/export.
7) Test for extreme cases where object parameters are passed nothing, collections with 0 items, collections with extermely large items.
8) Never have double link child to parent, parent to child. If a child needs to know its parent use the proxy pattern instead. VbClassicObjectProxy
I go into detail because double linked pairs of Object are such an evil for large applications in VB. Similar the evil of null pointers in C/C++. The garbage collector of VB can't get rid of double-linked objects, so memory will be chewed up eventually causing much weirdness and grief.
9) Find a copy of Hardcore Visual Basic by McKinney?. He will take you under the hood of VB.
10) FileSystemObject? in the MS ActiveX Scripting DLL is a much saner way of dealing with files. In addition, the PropertyBag? Object can take any object and turn it into an array of bytes. You can save and reload this array and recreate the object.
CategoryVbClassic