Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Style vs Idiot-Proofing 12

Status
Not open for further replies.

CajunCenturion

Programmer
Mar 4, 2002
11,381
0
0
US
A while back, we had a thread dedicated to Idiot Proofing Programs. This thread seemed to run down two paths. The first path was to essentially get a better class of idiots. Amusing and entertaining, this unfortunately also has some truth behind it. The second path dealt with getting accurate functional requirements up front in writing, and so forth. Excellent points were made, but this isn’t really the job of the programmer – it’s the job of the analyst. I am aware that most, if not all of us, wear both hats (analyst and programmer) from time to time, but what the previous thread lacked was a path that dealt with how programmers can write better programs. Assuming that the analyst has done his/her job, and that we have been provided a good, complete, and accurate functional requirements specification, I now pose the following paraphrased question:

How do we write an Idiot-Proof Program that meets those specifications?

Obviously our logic must be correct, and we need to have error handling to deal with unexpected inputs, but does our choice of control structures (Do While vs For Each) make a difference?

Found = False
For Each Item in Items
If Item.Property = “What We Want” Then
Found = True
Exit For
End If
Next

Found = False
Index = 1
Do While (Index <= Items.Count and Not Found)
If Items(Index).Property = “What We Want” Then
Found = True
Else
Index = Index + 1
End If
Loop

Does the complexity of the code make a difference – not just for the sake of performance, but for the sake of program testing and validation? From a purely Software Engineering standpoint, the For Each with Exit For statement is more ‘complex’ because the Exit For is an additional branch that must be dealt with during program testing and validation. It’s another path thru the code that must be taken into account. Or is this simply a matter of style? This is a very simple case, of course, and if your answer is different because it’s a simple case, then at what point does the case not become simple enough to warrant legitimate consideration of alternatives in light of program complexity?

Does having functions and procedures have single entry and exit points affect program complexity, thus in turn leading to easier or more difficult programs to write, test, and/or maintain?

What other programming “guidelines” (indendation, variable nameing, modularity, single-function procedures, program routes, modularity, object oriented, <add your own list>, etc, etc) have their roots in providing mechanism by which we as programmers can write better, (or more idiot-proof) programs? What “guidelines” matter to you?

All opinions and comments welcome. There really are no wrong answers here.
Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein


 
Complexity is certainly an issue - comment EVERYTHING! Think of the poor shmuck who has to work with the beastie long after you've retired to the Bahamas!

Code should essentially be intuitive, but there's an element of personal style in there as well... So as for For/Next vs Do/Loop, I'd suggest it's the choice of the coder...
 
The most important thing that I have seen, both in writing my own, and in beta-testing programs written by others, is that you must validate *all* data that is brought into the program ( either by direct input by the user, through reading a data file, or via com port / modem ). This means lots of extra lines of code to check for data types and length and so forth, but it means a lot in the end.

Some ( if not most ) of the most famous software bugs in history have been a result of failure to validate the data coming into the program. Rockets exploding because the guidance program tried to shove a 64 bit # into a 16 bit field, Nuclear powered cruisers shutting down because someone entered a 0 into a field and got a divide by zero error, and so forth. Not that you are going to be using VB for these kinds of things, but you get the idea. :)

Secondly, you have to open up your mind and think like a perverted user... ( No, not that kind of perverted [3eyes] ). Do weird things when testing. Try things that no resonable person should try, because that's exactly what some end user is going to do.

Robert
 
Hey Cajun - bjm1335 from the &quot;Am I just being 0old fashioned thread the other day -

The first, most &quot;intuitive&quot; rule is - The more complex the code, the more comments there should be.

Second, consistancy is very important. If you do something one way in one pgm and another way in the next pgm, the poor slob inheriting the code will have a more difficult time understanding.

Per my thread the other day about GoTo's vs Exit Sub, I think code is a lot more &quot;followable&quot; if you take care of an &quot;If&quot; case by having to state only one side of the case:

If not blnEditRec and not blnNewRec then GoTo ExitProc:

if blnEditRec or blnNewRec then
.
.
end if
ExitProd:

That way you &quot;get rid of&quot; the need to follow the logic, align the code, etc. I don't particularly like &quot;GoTo's&quot; (I as &quot;raised&quot; as a COBOL pgmmer where it was practically forbidden), but ths issue to me is the same as the one you raise about complexity of the Do While loop. Again its a matter of &quot;followability&quot; as well as inherent complexity.

A about complexity - the more complex project or pgm, the smaller the procs should be that make it up. This makes maint. easier ( the &quot;black box&quot; effect) and the pgmmer trying to maintain it can say to him/herself, &quot;OK, that's the end of this proc, and I understand it all. Now I can move on to the next.&quot; How many times have I (with 30+ yrs of experience and a pretty good mind for logic) been in the middle of a long piece of code and said, &quot;Where the heck did this thing start, anyway ?&quot;

And, of course, there's the old saying that as soon as you write some idiot proof coding, some idiot will come along and prove that it isn't !
 
What a big topic!
Having coding guidelines is certainly useful where more than one developer is working on a project as it makes it easier for everyone involved to understand and maintain each others code.

Having sufficient comments is definitely important.

One other important thing is to have consistant error handling. I can recommend Keith Dimmock's add-in which can be found at This add-in will also help with indentation which can make code a lot more understandable.

Another important thing is to split complex statements into multiple lines of code e.g.
If x=y and a=b then
is better as
If x=y then
if a=b then
If something goes wrong it is easier to identify the error and it also avoids VB evaluating a=b when it is not needed.

In the example you give I would prefer the for each loop which I believe is more efficient and certainly involves less lines of code and less logical branches.
 
Certainly, making your program simple, logical and
readable is a good habit. The idiot who tries to debug the
program may be you!
Try to name variables with a consistent and semi-
descriptive manner. For instance, I prefix ALL of my
integer variables with &quot;int_&quot;.
I also try to keep ALL of my declarations in a standard
place. For instance, ALL of my variable declarations are
in the GENERAL|DECLARATIONS portions of the modules.
I really try to adhere to the rule &quot;ONE action per
module.&quot;. When I need more complex actions, I use
multiple modules, rather than one highly specialized
module.
Ease of debugging. I insert a lot of message boxes, to
track the flow of execution during development. However, when I'm done with them, I don't erase them, I just put
a ' in front of them, turning them into comments.
These should all be done by the programmer. I wouldn't
delegate my future workload to another person.
 
I would like to touch on the &quot;additional branch&quot; with regards to looping and the &quot;exit whatever&quot;. Yes this does add addition exit points and I agree that this is a nightmare. However I beleive that there are some times when it is a better option, but it must be used tastefully and should be commented so it is readable. I have seen code where the &quot;exit whatever&quot; is used for every test condition and I see this as very poor programming. But say for example you develop your app after extensive analysis and planning and you stand proud of your &quot;exit free&quot; app, then the idiot you work for decides that the functionality must change? Swearing, you re-evaluate the situation only to find that a sprinkle of a couple of &quot;exit whatever&quot; will provide the results with a couple of small coding changes. Now what? Do you throw the &quot;exits&quot; at the code and call it done or go back to the design stage and start from scratch? My point being we work in a world where users (idiots?) make the call. You can spend all the time in the world trying to think of all the possible things a user will want from your super app but the bottom line is things will stray from your original ideas. If we try to idiot proof our work while maintaining sound design and text book structure, the world will fall short of mental institutes to house us. In summary multiple entry/exit points should not be considered at design time when you still have the option If you are at rev 1276 go back to the drawing board. Your beta test uncovers a bug, throw comments and the fix at the code. Note I said comments, this will help the next guy who sees your code understand why you did what you did.

Just venting. Anything is possible, the problem is I only have one lifetime.
[cheers]
 
Guys, I can only say one thing:

read some of the books of Steve mcConnel:

I read a.o. Code Complete and it helped me in such a way that 'transparent programming' has become my middle name...;-)
Making software self explanatory, coding in such a way that even your futureself can still understand your coding, and others programmers as well.

Allthough I have just started in VB, I have been programming the OOP way in VFP for some years and some points I have always taken into account when rogramming:
- use globals only when necessary. They can be very hard to trace.
- Don't put all your business logic/data handling in the user interface (I love the 3-Tier or n-Tier design)
- Give your variables logical names like iCounter or bSuccess iso a, b, or whatever unclear names.
- Use top to bottom coding iso jumping around in your code.
- Try to use defensive programming, so that you prevent crashes with wrong assumptions about var types or the existence of variables etc. It is better to do nothing than to crash.


HTH,



Weedz (Edward W.F. Veld)
My private project:Download the CrownBase source code !!
 
I agree with most of the comments made so far but i am not sure about &quot;It is better to do nothing than to crash&quot;. I have found programs which ignore errors very difficult to debug. If you want a program to continue after an unexpected error has occurred then at least display a message or write a log message.
 
That is why you have to do defensive programming.
With 'the phrase it is better to do nothing than to crash', I meant, it is better to let the procedure stop and do nothing i.e. not continue the things the users wishes to do, than to crash. And yes, this involves a good error handling routine.

Cheers,

Weedz (Edward W.F. Veld)
My private project:Download the CrownBase source code !!
 
As for user input. I find the best way to deal with both validation, and user actions is to limit them.

For example, I make one function sued over and over, I pass it several things such as what type of field, the max length or value and the existing text.

What I found works best is to check every last keystroke. Everytime a key is pressed it goes to a Keypress validator, I then decide whether the key is valid for this box, whether they have entered too many keys and etc.

That worked fine for a bit, until I found 1 client who never pressed keys, they cut and pasted from a spreadsheet, which totally circumvented my checking. So now I added the validation to Change as well as key down.

Basically what I am saying is the best way I have found to deal with Idiots, is to limit what they can do. If we keep them from entering bad data in the first place, then our validation in the end is made a lot easier.

Here is some older code that I've used for validation. This is the actual validation function (I have a more advanced one for time, date and postal code fields, which also deals with cut and pastes but you get the idea.
[tt]
'======================================
'Validation and Display properties Code
'======================================
Private Function ValidateInkey(strType As String, KeyAscii As Integer, strInbox As String, intMaxLen As Integer) As Boolean

If KeyAscii = 13 Then ' On tab or enter move to the next feild
SendKeys &quot;{tab}&quot;
KeyAscii = 0
ValidateInkey = True
Exit Function
End If

If KeyAscii = 8 Then ' Backspace always allowed
ValidateInkey = True
Exit Function
End If

' Allow only numbers
If strType = &quot;N&quot; Then
ValidateInkey = False
If KeyAscii >= 48 And KeyAscii <= 57 Then ' Numbers
ValidateInkey = True
End If
End If

' Allow only Characters
If strType = &quot;A&quot; Then
If (KeyAscii > 64 And KeyAscii < 91) Or (KeyAscii > 96 And KeyAscii < 123) Then
ValidateInkey = True
Else
ValidateInkey = False
End If
End If

' Allow both
If strType = &quot;AN&quot; Then
If (KeyAscii > 64 And KeyAscii < 91) Or (KeyAscii > 96 And KeyAscii < 123) Or (KeyAscii >= 48 And KeyAscii <= 57) Then
ValidateInkey = True
Else
ValidateInkey = False
End If
End If

'Check the length of the field
If Len(strInbox) >= intMaxLen Then
ValidateInkey = False
End If

End Function
[/tt]
Then In each text box, I add the following code.
[tt]
Private Sub txtNumeric_KeyPress(KeyAscii As Integer)

If ValidateInkey(&quot;N&quot;, KeyAscii, txtNumeric, 4) = False Then
Beep
KeyAscii = 0
Me.ActiveControl.SetFocus
End If

End Sub
[/tt] Craig, mailto:sander@cogeco.ca

Remember not to name the Lambs...
It only makes the chops harder to swallow
 
I agree with Craig that a generic validation routine is a good idea, but have the following comments about his code:
1.I would validate the maximum length of a text box in code as it is simpler to use the maxlength property.
2.As an example of how to make code more understandable I would replace the hard-coded integers in his code i.e. for numerics ensure the key is between Asc(&quot;0&quot;) and Asc(&quot;9&quot;).
3.The example given will not allow cutting and pasting using Ctl-X, Ctl-V etc. Users often want to do these things! I usually permit any of the Ascii control codes (< 20).
4.You were right to mention cutting & pasting as an issue. Ctl-V is now the usual way of pasting and this generates a keypress event. Alt-Insert can however also be used and this does not generate a keypress event.
 
I don't mean to pick on you Craig - I completely agree with your intention, but I would've have written your ValidateInkey as follows which would have eliminated the Exit Function statements:

Private Function ValidateInkey(strType As String, KeyAscii As Integer, strInbox As String, intMaxLen As Integer) As Boolean

Dim lBol_ValidEntry As Boolean

lBol_ValidEntry = False
Select Case KeyAscii
Case 13
SendKeys &quot;{tab}&quot;
KeyAscii = 0
lBol_ValidEntry = True
Case 8
lBol_ValidEntry = True
Case Else
Select Case strType
Case &quot;N&quot;
If ((KeyAscii >= 48) And (KeyAscii <= 57)) Then ' Numbers
lBol_ValidEntry = True
End If
Case &quot;A&quot;
If (KeyAscii > 64 And KeyAscii < 91) Or (KeyAscii > 96 And KeyAscii < 123) Then
lBol_ValidEntry = True
End If
Case Else
If (KeyAscii > 64 And KeyAscii < 91) Or (KeyAscii > 96 And KeyAscii < 123) Or (KeyAscii >= 48 And KeyAscii <= 57) Then
lBol_ValidEntry = True
End If
End Select
End Select

If (lBol_ValidEntry = True) Then
lBol_ValidEntry = (Len(strInbox) <= intMaxLen)
End If

ValidateInkey = lBol_ValidEntry

End Function

Also Craig, not sure if this last conditional statement is exactly what you want

If Len(strInbox) >= intMaxLen Then
ValidateInkey = False
End If

Should this be only Greater Than? If the len of strinbox is equal to intMaxlen - should that be invalid?
Good Luck
--------------
As a circle of light increases so does the circumference of darkness around it. - Albert Einstein


 
A good rule that I had to learn the hard way is always optimise, debug and comment your code as you write it. DO NOT SAY TO YOURSELF I WILL COME BACK AND DO THIS LATER. By the time later comes you'll have a million lines of code to sort out!
 
Interesting thread...Regarding the function below, I have a few questions

Private Function ValidateInkey(strType As String, KeyAscii As Integer, strInbox As String, intMaxLen As Integer) As Boolean


I understand the logic of the function but what would fill the strInBox parameter?? Also, how would you determine the strType at run time. Would you have to do a check on the ascii character from the KeyPress event.

If someone could show me an example of how and where to call this function I would be grateful...

Thanks

Darren
 
I really hate to wade in on this, but what the heck? Show me 2 programmers and I'll show you 2 styles. Show me 5 programmers and I'll see 5 styles. Show me 2 things written by the same programmer, but, say written a year apart, and I'll see 2 styles. I know that my style changes as I better understand the language. So, this issue of style is really a tough one.

I've been on projects where issues of methodology and style are overtaken by the schedule placed on the programmers. You know, to heck with methodology, we have to get something out the door. Not good, but real world. You know, you never have time to do it right, but you have time to do it over.

I've seen screens not getting completed because the programmer (comp scientist) was agonizing over methodology. In the meantime, users needs are not being met and management squirms.

Standard things like commenting code, being consistent, and breaking code into logical reusable components is definitely important, but often not done. I'd suggest that failure to do all of these things is not always the fault of the programmer.

A programmer's ability to do all this grand and glorious stuff is inhibitted by:

1. Failure of the analyst to provide complete and clear requirements that fit within the abilities of the selected tool.

2. Failure of the analyst to understand the toolset the programmers are using. If you're working with a character based system you may have a requirement to provide GUI tools. But clearly this cannot be done. It is the responsibility of the analyst to reconcile this before the requirement gets to the programmer.

Probably the biggest problem I currently have in this regard is that everyone thinks everything can and should be web based. I don't know about y'all out there, but I find trying to understand the mix of html, java script, vbscript, client side this and server side that and cdi this and activeX that, firewall this and firewall that, yada, yada, yada much more difficult than simple ole VB. Yet! This is typically the first thing asked for....&quot;Why can't ya just stick it on the web?&quot;

3. Management's propensity to read the glossies and then dictate the toolset that will be used. So often programmers are stuck learned a new language to support a new program requirement. One day you're working in Hypertext, the next it may be PowerBuilder, then VB, etc. etc. This results in programmers being on the wrong spot on the learning curve more often than not.

4. Unrealistic schedules. See item 3 above. Chance are you're working with a new lanquage coupled with a rediculous schedule. So, you're stuck in &quot;just get it done&quot; mode. The guy the ponders methodology too long will bring the project down.

The last thing I'll say about this is that, believe it or not, not all IQs or people's areas of interest are not equal. Consequently a style, or methodology that comes easy to one programmer may not be so easy for another. Styles and methodolies have to be greatly influenced by this factor alone.

vbvictim
 
Good comment. We seem to have wandered off the point somewhat from generalities to some specific line of code. And I think thats an important point. It's called 'not seeing the wood for the trees'. The number of meetings I've been in to discuss programming style or somesuch, that end up in an enormously elaborate and ultimately worthless discussion about 'what should we pick for the first letter of integers'.
The only thing that is actually important usually is that you can understand the code. That's it. If you are writing with others, they all need to understand it too. The way to do this is by writing the least amount of code possible. And one way to do that is by using 3rd party controls and dll's (providing they actually work) as much as possible. As an example, it is probably possible to produce a font combo like Word that shows what the fonts actually look like, by doing all sorts of complex sub-classing etc etc. It would be a swine to get working, it would take a week and you would feel dead proud. It would however have been cheaper and quicker to buy an ocx that does just that. I don't know if it exists, just an example.

I've only actually once done software properly. That is, design it on paper, do ALL the documentation, write test schedules. Then and only then, code it. Run the tests. Correct the code to be the same as the design. It worked actually, didn't half take a long time though.

Style and Idiot-proofing are entirely different. Idiot-proofing means clicking things in the 'wrong' order and typing in junk, and the programme behaves itself. Style is the bit the customer doesn't see. It's the code. Unless you mean the style, or lack of it in the forms design. That's another subject altogether.

One specific. use globals only when necessary. They can be very hard to trace.
I really don't understand this. I've read it often, and I really don't see any problem at all. Peter Meachem
peter@accuflight.com

Support Joanna's Bikeathon
 
Interesting comments. As noted about different styles from different developers, the same applies for the users of our programs. Each User has his/her own style, level of experience, understanding of logical processes and, as a result, their own approach to using our programs. Anticipating each and every action of each and every user is unrealistic even with the best functional requirements. The best we can do is to try to understand our user group, their understanding of technology, etc. and write our programs with those parameters in mind.

An interesting parallel is the varying level of understanding and frustration in using VB displayed by the group using this forum. All of us have some degree of knowledge of technology yet sometimes even the simplest of things stump all of us, even the experts. It would seem Microsoft has the same issues with creating understandable and idiot proof software for us to use as we have in writing code for our users. It amuses me to think that some thread in a Redmond based group is discussing the same notion as it applies to developers.
 
Hi folks,

<<How do we write an Idiot-Proof Program that meets those specifications?>>

1) Code reuse. Don't reinvent the wheel when you have a network full of tested code whether it is your code or a 3rd party's. Find something similar, modify it, and abuse it.

2) Adhere to the caveat of &quot;the code being written WILL be CHANGED&quot; so use comments, both descriptive and debugging, and use descriptive naming conventions so that the code speaks for itself. (remember why COBOL was created?)

3) Code has to be easily maintainable. To do this modularize, encapsulate, Eliminate redundant code and reduce the LOC count, If you have to make a major design change it wasn't designed correctly in the first place.

4) Do not propagate bad code whether it is your own or someone else so stay a little longer in the office and rewrite it. It helps everyone in the long run.

5) Practice your problem-solving skills. The essence of code banging isn't the style or the syntax...that's the easy part it is being able to convert those specs into syntax that makes a programmer worthy of a pay cheque.

Some truths

1) Unless you are working on a hobby project, the bottom line is the return on investment of a project, and happy clients. There will always be tradeoffs between bulletproofing an app and getting it to market. Microsoft, is a perfect example they have patches already done just as the new version of a product is released.

2) If you have an analyst that can illustrate every last detail in a spec...you are dead and in heaven. They have a much stricter timeline, in order, to have their software design implemented by the programmer(s).

Have a good one!
BK
 
I have (and occassionally refer to) two small books:

The elements of Programming Style, Kernighan & Plauger, 1974 Bell Labs ISBN: 0070341990

Cobol with Style, Louis J. Chmura & Henry F. Ledgard, Hyden Book Company. 1976 ISBN: 081045781

Either one includes most of the topics covered here. If these were not copyrighted, and I were a decent typist, I would share some of the content with the participants. One item which DOES appear to be consistient throughout both issues is the simple theme of 'readability', often being used as the rationale for the violation of many other tenants.

Refering back to Cajun's examles:


Found = False
For Each Item in Items
If Item.Property = “What We Want” Then
Found = True
Exit For
End If
Next

Found = False
Index = 1
Do While (Index <= Items.Count and Not Found)
If Items(Index).Property = “What We Want” Then
Found = True
Else
Index = Index + 1
End If
Loop


Please note that the do loop construct will iterate throught he entire collection of Items, while the for loop uses a convenient exit. These are SIGNIFICANT differences in programming. If the processes are &quot;normalized&quot; - in either direction, I think the discussion of which is 'better' becomes a moot point.

I often (usually) would code validation procedures to simply set an (error) return value and exit at each test , rather than have to go looking for a LABEL to determine what course of action was taken. I LIKE and USE the approach taken by CraigSanders' validation routine. When the input is validated, he SAYS SO & EXITS. No need to follow nested constructs to see if something else happens. NO need to look for lables to determine the 'continuing saga of ... &quot;. Plain. Simple. Direct. Easy to Follow.


MichaelRed
m.red@att.net

There is never time to do it right but there is always time to do it over
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top