http://qs321.pair.com?node_id=705411

missingthepoint has asked for the wisdom of the Perl Monks concerning the following question:

Greetings, monks.

This is a 'meta-programming' question, I guess... Recently I've been meditating upon the cause of the errors I make while programming. It seems that most of my errors are what you might call 'silly mistakes'.

For instance, recently I decided to expand my mind and learn another programming paradigm (in addition to 'imperative', which is all I've had thus far). So I set out through perltoot, and learned much. Along the way I learned about destructors and how they must be named 'DESTROY'. So I proceeded to add a thus-named sub to my source file... which promptly failed to run. After 10 seconds reflection and a forehead smack, I had put the sub in my class's module, instead of the file which use()d that module. Then it ran. Doh!

My other silly mistakes are similar - they generally take 10 seconds to fix, but can take longer to spot, especially if sleep-deprived. What annoys me is that I waste time this way. If I was paying attention in the first place, I reason, I would be a more productive (and less stressed) coder.

Can any other monks relate to this behavior? What are your strategies for avoiding those 'doh' moments? Obviously experience helps, but are there things I could do now to reduce the number of silly mistakes I make?

I eagerly await your monastic wisdom.

P.S. Please be nice, it's my first post. :o)

-- email: perl -e 'print scalar reverse map { chr( ord($_)-1 ) } split //, "ufo/hojsfufqAofc";'

Replies are listed 'Best First'.
Re: Avoiding silly programming mistakes
by GrandFather (Saint) on Aug 20, 2008 at 05:40 UTC

    Um, always use strictures (use strict; use warnings; - see The strictures, according to Seuss). :-D

    Try whittling problem code down to a small sample suitable for posting to PerlMonks - you almost never have to post the actual code though.

    Use a good syntax checking editor. Heed all warnings. Write test suites and run coverage tests.

    Avoid writing code (use other peoples modules - CPAN).

    Think about edge cases and test for them.


    Perl reduces RSI - it saves typing
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Avoiding silly programming mistakes
by moritz (Cardinal) on Aug 20, 2008 at 06:25 UTC
    There are "doh" mistakes that I still do sometimes, like writing a sub to the wrong file accidentally, or mis-typing a package name and wondering why everything fails.

    So far I haven't really found a way to avoid those, and I suspect that nothing can defeat human stupidity ;-)

    If it comforts you, over time you'll get a feeling for what mistakes are "do'h mistakes", and you'll get accustomed to the few most frequent, and identify them rather quickly.

Re: Avoiding silly programming mistakes
by Limbic~Region (Chancellor) on Aug 20, 2008 at 13:28 UTC
    missingthepoint,
    A lesson learned as a result of being bitten sticks much more readily than one learned as a theoretical precaution. Here are two cases in point:
    sub foo { my $arg = shift; # ... } vs sub bar { my ($arg) = @_; # ... }

    I started using the second construct because adding additional parameters only requires me to change the LHS. I had got bitten enough times to warrant the change.

    if ($foo == 0) { # ... } vs if (0 == $foo) { # ... }

    The reason some people recommend the latter is because if you accidently type the == equality operator as the = assignment operator, you will get an error (not so for the former). Since I vary rarely get bitten by this, I still use the former.

    In a nutshell, there is no substitute for experience. The gray area becomes how much needs to come from your own personal experience or how much you can learn from someone else's experience. I recommend reading Re: Refactoring a large script and adopting any advice there that you don't currently use. Share what common mistakes you make and ask around what methods others use to avoid them. Share what you have come up with on your own so that others can benefit.

    Cheers - L~R

      Thanks, L~R. That first trick seems useful... I'll work hard to adopt it.

      I've come across the second before as I have some C experience. Initially, I found it useful. After using it for a few months I realised I'd gotten into the habit of writing

      if (constant == variable)

      ... so I deliberately switched back to writing

      if (variable == constant)

      ... and I haven't made the 'one-equals' mistake since. For me it was a good mental training exercise.

      Oh, and I'm reading the refactoring post now. Ta.


      email: perl -e 'print scalar reverse map { chr( ord($_)-1 ) } split //, "ufo/hojsfufqAofc";'
      {if (0 == $foo) vs if ($foo == 0)} The reason some people recommend the latter is because if you accidently type the == equality operator as the = assignment operator, you will get an error (not so for the former). Since I vary rarely get bitten by this, I still use the former.

      That's a C thing; that is, a practise that was used among C programmers long before Perl programmers started coding.

      It's not really necessary to do so in Perl; with warnings on, if you mistake the operator, Perl will warn (Found = in conditional, should be == at ...). I think some C compilers (like gcc) will warn if you have an assignment in a conditional as well; which can be disabled by using an additional set of parenthesis.

        JavaFan,
        It's not really necessary to do so in Perl...

        Probably why I have never adopted it. That doesn't mean that there aren't people out there recommending it. For those following along at home, perl doesn't always issue a warning with the assignment operator in a conditional:

        #!/usr/bin/perl use strict; use warnings; if (my $foo = foo()) { print "No warning\n"; } if (my @asdf = (1..5)) { print "No warning here either\n"; } if (my $bar = {one => 1}) { print "Look Ma, no warning\n"; } while (my $rec = <DATA>) { # ... } sub foo { return 42; }

        Of these, the only suspect one is the first and perl assumes you know what you are doing. Writing it with the operands reversed would have generated an error (assuming no lvalue attributes) but I agree, this is a stretch.

        You have re-inforced my two points. A lesson learned the hard way is learned best and there is no substitute for experience but figuring out how much of other's experience to rely on is tricky.

        Cheers - L~R

        Some compilers do. Some compilers do not tell you a thing "'cause you should use lint". Get used to the former and if you happen to come across the other you end up wasting hours of time. Luckily it did not take me so long when I was asked to make some changes while doing the "Unix and C I." exam several years ago after only ever using Borland C for a bit. The fact that there was just a single plain old textmode terminal with vi or pico to do anything with did not help a bit.

        I like the if ( 0 == $foo ) construct over if ( $foo == 0 ) because the s/==/=/ typo is an error in the first but not the second.

        Can't modify constant item in scalar assignment

        I'd rather have that than some mere warning.

Re: Avoiding silly programming mistakes
by JavaFan (Canon) on Aug 20, 2008 at 09:56 UTC
    I've been coding for over 30 years, and I'm still making "doh" mistakes. I keep misspelling Fcntl. I keep putting a comma after the filehandle in a print statement. I keep forgetting to put Exporter in @ISA, and then I wonder why my subs aren't exported. Oh, and the number of times I left of '1;' (or another true value) at the end of a module.

    And then I write some C, and I keep forgetting parenthesis around function arguments. Or forget that my variables need to be declared upon entering a scope. And that they don't need sigils, but may need casting. And when my job still required me to use Pascal, I tried using /* */ comments in Pascal, and (* *) comments in C. Worse is trying to use // comments in C, as some compilers accept it, and others don't.

    And when (interactively) querying a database, the client has to remind me over and over again that 'cd' and 'ls' aren't valid commands.

    Retirement or death, which ever comes first, will be the moment I stop making "doh" mistakes.

      Using a boilerplate to start a module will help with your problems with exportation and ultimate truth.

      The trick to using such templates is to make them congenial; make your own. Avoid building a template which is more comprehensive than you will be willing to alter.

      Here is what I'm currently using, minus pod.

      package XXX_name; use 5.008004; use strict; use warnings; require Exporter; our $VERSION = '0.01'; use Carp; use vars ( 'XXX_exported', '@EXPORT' ); ## no critic use base qw/ Exporter /; @EXPORT = qw/ XXX_exported /; XXX_code_here 1;
      Be well,
      rir

      Golly! At least 2/3 of those errors are caught by using strictures or a decent syntax highlighting editor!


      Perl reduces RSI - it saves typing
      A reply falls below the community's threshold of quality. You may see it by logging in.
      I keep forgetting to put Exporter in @ISA

      I don't really like to inherit from another module just to use one or two subs. Instead I write use Exporter qw(import);.

      And when (interactively) querying a database, the client has to remind me over and over again that 'cd' and 'ls' aren't valid commands.

      This happens to me all the time as well. When I use the mysql prompt and enter ls<return> I see my mistake, and then press Ctrl+C to abort the command. But of course Ctrl+C actually exists the client...

        When I use the mysql prompt and enter ls<return> I see my mistake, and then press Ctrl+C to abort the command. But of course Ctrl+C actually exists the client...

        I'd estimate I make the ctrl-c in mysql about twice a week. Of course, the only reason it's not once a day anymore is because I'm doing less database work.

        At this point, it's been years since I used Oracle, but I have problem overriding my old habits.

        Oh -- and as of mysql 5.1.10 -- ctrl-C aborts the running query, rather than dumping immediately. (still doesn't fix the problem when you're used to sqlplus and are just trying to clear the command, though).

Re: Avoiding silly programming mistakes
by Skeeve (Parson) on Aug 20, 2008 at 09:50 UTC

    Yesterday I had a 'DOH' moment twice. One moment twice? Yes ;-) The second one was a deja-vu because it was the same mistake in the same sub at another position.

    What I learned from it is: NEVER EVER use if ( $somevariable ) if you really wanted if ( $somevariable ne '' )


    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
Re: Avoiding silly programming mistakes
by talexb (Chancellor) on Aug 20, 2008 at 16:01 UTC

    Getting to be good at something requires focus, patience and continuous improvement.

    For writing code, that's a good mental state: you've already spent some time thinking about the problem and have now come up with a solution that you're going to implement. Start to write the code slowly, thinking about the 'big picture' as you do each piece. Review often, and stop when you've got a chunk done, save the file and perhaps run some early tests, then code some more and test some more. Above all, put everything into that piece of code -- don't leave error checking, useful comments or nice variable names for later. Put all that stuff in now, not At Some Convenient Point In The Indistinct Future That May Never Come.

    Everyone's got a different way of focussing -- I like to have a cup of coffee to hand and my iPod pumping tunage into my brain via headphones. My step-son does a lot of homework on a clipboard while lying in bed with IRC open and the TV on. I'd find that too much distraction, but I'll go with Whatever Works For Him.

    Patience comes with experience -- as someone who's been driving since I was 16, I learn this every day. Faster isn't necessarily better -- although it can be fun. :)

    For me, continuous improvement (at Perl, anyway) comes from being a member of Perlmonks, and staying in touch with what's going on with the community and the language. It's possible to develop in Perl without taking part in the community, but that strikes me as a task made much harder than it needs to be.

    The happiest man is one who never works a day in his life -- because his occupation is something he enjoys, and he would do it for free. So if you get real satisfaction in writing code and chasing down bugs, then you're in the right profession.

    And in the immortal words of our founder, "Have the appropriate amount of fun."

    Alex / talexb / Toronto

    "Groklaw is the open-source mentality applied to legal research" ~ Linus Torvalds

Re: Avoiding silly programming mistakes
by bruno (Friar) on Aug 20, 2008 at 14:04 UTC
    Being a beginner myself, I know what you mean. I am unable to write two statements in a row without making one mistake. The best way that I found to come around this is by writing code in small chunks and testing them in isolation.
    So I will normally have two open buffers; in the first one I am writing the actual script and in the second one I test the current working paragraph. This way, spelling mistakes and bugs are caught earlier, and I seldom have to hunt them down too much.

    Of course there is also the case that other bugs arise when this "code chunks" interact poorly, but most of the "d'oh" mistakes become evident earlier this way.

Re: Avoiding silly programming mistakes
by tilly (Archbishop) on Aug 24, 2008 at 06:02 UTC
    Dumb mistakes that are caught immediately are not a problem. The figure that I've heard is that on average 1 line in 10 of code as initially typed has a mistake of some sort. That figure isn't unique to programming - it seems to be a fairly standard cognitive failure rate in humans that shows up in everything from errors made in formulas in spreadsheets to typos while writing. And it isn't a problem if most of the time you catch the error almost immediately. (For a similar phenomena think about how often you hit backspace while you're typing.)

    The problem seems to be innate. To the best of my knowledge, you can't really reduce the rate of initial errors. Therefore you need to focus on how you catch errors. People have offered a number of suggestions. There are tools. People have mentioned strict.pm and syntax highlighting. There are programming strategies to give you additional cognitive cues. Things like making boolean variables be given names that are yes/no questions which the value is an answer to. The book Code Complete 2 has a lot of very valuable advice on that. There are practices like having good unit tests. And then there is the simple experience of having seen and caught certain mistakes so often that you're just on the lookout for them.

    Now there is a funny phenomena. Which is that once you adopt strategies to correct these errors, the frequency with which you make them tends to go up! Why? Well it is because there is a lot that you have to think about during programming. As you get better, you devote less brain power to catching your trivial errors before they are made, and more to keeping track of the "big picture". This is actually a good thing. You see by adopting practices that immediately capture the trivial errors you make them utterly harmless. And the extra attention on the big picture results in better designs, better approaches, better code, and fewer of the really serious errors that could cost you a lot in the long run.

    And one of the big picture items to keep track of is your sleep. It is sad, but one of the first things that goes when our mental functioning is impaired is our ability to judge how impaired we are. Which means that when you impair yourself, for instance by sleeping too little, you have no real monitor of how badly impaired you are. And the effects of lack of sleep are pretty serious, particularly for programmers. If you're noticing it, you need more sleep, then trust me, you would benefit a lot from having it.

      And one of the big picture items to keep track of is your sleep. It is sad, but one of the first things that goes when our mental functioning is impaired is our ability to judge how impaired we are. Which means that when you impair yourself, for instance by sleeping too little, you have no real monitor of how badly impaired you are. And the effects of lack of sleep are pretty serious, particularly for programmers. If you're noticing it, you need more sleep, then trust me, you would benefit a lot from having it.

      In addition to tilly's very valid points about sleep (I just spent the better part of the last two days getting caught up myself), I'd also like to point out the importance of doing something, anything - walking, running, biking, swimming, whatever works - to get your body moving and blood flowing to your brain. You don't have to be a world-class athelete. You just have to do it. The benefits are more than worth it, and not just to your mental concentration.

      Now, where're my biking shoes?

      HTH,

      planetscape
        Let me support that by pointing out that research has found that regular aerobic exercise results in better short-term memory. Since programmers often have to keep multiple things in short term memory, improvements there are very helpful.

        Note that the effect is very specific to aerobic exercise. It does not happen with, say, weight training. The cause is believed to be that regular aerobic exercise improves blood flow, and the brain responds to blood flow.

      And the effects of lack of sleep are pretty serious, particularly for programmers

      Ewww... Tell me about it. The number of times are legion I've hacked on a piece of code when tired, only to go back the next day after a good sleep and think "What was I thinking?". Unfortunately caffeine just doesn't substitute for sleep when it comes to cognitive function. :)


      email: perl -e 'print reverse map { chr( ord($_)-1 ) } split //, "\x0bufo/hojsfufqAofc";'
        Isn't it more like "WTF was I thinking?" :)
Re: Avoiding silly programming mistakes
by Cefu (Beadle) on Aug 21, 2008 at 14:30 UTC

    I see a lot of good advice here already; the perl dogma (strictures etc.), code reuse (CPAN or your own), small chunks and early testing. However, there is one thing I don't see here yet.

    The absolute best tool for catching all kinds of mistakes that cannot be seen by syntax checkers, interpreters or any other automatic tools is.....

    .... another programmer.

    Yes, I'm talking about extreme programming. It may be hard to convince the corporate overlords that paying two people to do the work of one is worthwhile but the time saved in having a second set of eyes watching AS YOU CODE is incredible. You can always find new and unique ways to make errors that are beyond the scope of any automated checking tool. It takes another human brain to understand the ingenious ways you've screwed things up. And because they are there with you, in the moment, following along with your thinking as you construct the code, they do a much better job of catching your mistakes than they could ever do in an after-the-fact code review.

    You may never be afforded the opportunity to code this way but if you are, it's worth it.

Re: Avoiding silly programming mistakes
by amarquis (Curate) on Aug 20, 2008 at 14:28 UTC

    I've found that silly mistakes almost never leave me, unless I change my habits to make the mistakes obvious as soon as I type them.

    For example, I would constantly forget which variables were references to a data structure and which were actually hashes or arrays or whatnot. Was active_user_list the name of an array or a reference to an array? I'd assume the wrong answer often and cause myself grief, so now I append "ref" to the end of my reference names.

    Conway's Best Practices book is chock full of ideas for coding in a way to avoid silly mistakes despite yourself, by the by. I think some of the suggestions in there I've adopted have helped a lot.

Re: Avoiding silly programming mistakes
by dragonchild (Archbishop) on Aug 20, 2008 at 23:01 UTC
    I have ,c aliased to :!perl -wc %^V^M in vim. My fingers know that sequence better than they know any other sequence, and they should - I obsessively type it every 3-5 lines I type and every 2-3 lines I edit. ALWAYS. My template is:
    package XXX; use strict; use warnings FATAL => 'all'; 1; __END__
    (Yes - every single piece of code I write has warnings throwing fatal errors.)

    What these two practices do make it very easy to find the lines that have caused any problem. They would have made it very easy to find your error and they make it very easy to find other errors, too.

    There's a number of other practices that help as well, but those are for another post.


    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Avoiding silly programming mistakes
by NateTut (Deacon) on Aug 20, 2008 at 18:15 UTC
    'Assembly of Japanese bicycle requires great peace of mind.' - Robert M. Pirsig from "Zen and The Art of Motorcycle Maintenance" Your state of mind is the biggest factor in your coding. Don't assume, check. Also don't worry so much about the mistakes that cost you 10 seconds to figure out and fix worry more about the design mistakes that can cost weeks, months or years.
      Your state of mind is the biggest factor in your coding.

      The second point also sounds wise, but that first statement resonates very strongly with me. Allow me to share an anecdote...

      One evening, back when I was learning C, I'd spent a hour or two reading Snow Crash by Neal Stephenson. Perhaps this primed my mind in some way for what followed. :)

      I sat down and began coding... but my 'state of mind' was singular. I don't think I've ever been that focused. I began writing a routine to convert strings containing numbers in arbitrary bases to their numeric values... in Perl terms, this was a super oct().

      I spent perhaps two hours total. My mind seemed very clear, and I thought through the problem in depth... I probably spent 20 minutes doing nothing but thinking between brief periods of typing. At the end - I hadn't yet heard of TDD, you see :) - I ran my code and started testing it. It worked the first time. Perfectly. Everything happened exactly as I expected. I made no changes to the code after that, because there were no more to make. My memory's a bit fuzzy, but I think I also had a routine to do the reverse operation, and that worked perfectly too. I was shocked.

      I know I've improved since then and today I could probably find an edge case or two to break that code. But at the time, it was an amazing, almost transcendent experience. I couldn't believe I'd produced what I had.

      So I concur - it's the biggest factor. This begs the question... What techniques do the monks have for 'focusing'? How do you enter 'deep hack mode'? Perhaps I should start a new thread. :)


      email: perl -e 'print scalar reverse map { chr( ord($_)-1 ) } split //, "ufo/hojsfufqAofc";'
Re: Avoiding silly programming mistakes
by wol (Hermit) on Aug 20, 2008 at 12:53 UTC
    Better to make silly programming mistakes than serious programming mistakes.

    Is that a profound revalation? I'm really not sure.

      For me, they both lead to the same "end result"...non-working code.

      But the difference between the two, as moritz conveys well, is profound: in the first case a simple whack to forehead and few keystrokes solves the problem, in the latter it takes hours of my time to figure out and typically hours more to resolve.

      In the balance I have been blessed with far more of the "silly mistakes" than of the "programming mistakes". That is *not* because I'm a good programmer (not by any means), rather because I fret so much and stew so much over everything I code that I end up mentally walking though the code over and over before I commit much of it to the computer and then I tend to take almost every small but significant code segment (especially ones that I'm not sure if I've got the right strategy or constructs) and try them multiple ways on their own. A lot of work for what arguably is not much payoff. But for me, it is so painful to track down and figure out my programming errors that I'd rather suffer the pain of my strategy to my alternative.

      I am so envious of how most all programmers can just "get it right the first time" (or nearly the "first time").

      UPDATE: Sorry, I typed moritz when I meant wol. See..."silly mistakes". My bad. Sorry wol. Also, having just gotten back from 3 weeks of vacation, I can't remember the syntax for "bolding"...so this update is not in good form. And there isn't a "preview" with an update. Please forgive me.

      ack Albuquerque, NM

      I personally believe that the real problem lies in the fact that the two terms are far from being mutually exclusive: some programming mistakes can arise for silly reasons, but they may have serious consequences in many different ways.

      --
      If you can't understand the incipit, then please check the IPB Campaign.
Re: Avoiding silly programming mistakes
by Mutant (Priest) on Aug 20, 2008 at 18:10 UTC

    Lots of good advice already, but I had a couple of things to add. First, it's likely programming will always allow you to make stupid errors relatively easily. Programmers design and build systems so that other people (or computers) won't be able to make stupid mistakes. In order to do that, a language has to give us lots of flexibilty, which equates to lots of rope to hang ourselves. It's just part of the job.

    Secondly, I find Eclipse with EPIC really useful (there are other tools that give you similar functionality. That's just what I use). A lot of stupid errors are detected right away. Maybe not *everything*, but small errors like typos are highlighted as you type, so you don't have to run anything to find your compilation problems. A small time saving, you might say, but lots of small savings can add up to something big, allowing you more time to track down the really nasty problems.

Re: Avoiding silly programming mistakes
by Lawliet (Curate) on Aug 20, 2008 at 15:37 UTC

    Perl catches most of my 'doh' mistakes. I am probably most familiar with editing a large chunk of code quickly, being happy I finished editing, and try to run the code without ending a statement with a semi-colon.

    I'm so adjective, I verb nouns!

    chomp; # nom nom nom

Re: Avoiding silly programming mistakes
by pileofrogs (Priest) on Aug 20, 2008 at 17:17 UTC

    I actually have advice for the OP! How cool is that?

    I make D'oh! mistakes every two seconds. My best strategies involve reducing the opportunities for mistakes. In practice that mostly means code re-use. So, for instance, if you had based your object on a superclass that already did that job of destruction, you wouldn't have made that D'oh mistake. Or, in a less elegant but probably more applicable example, if you had taken an already existing class that included a destructor, gutted most of the code leaving a class skeleton and then wrote your own code, you wouldn't have missed it.

    -Pileofrogs

Re: Avoiding silly programming mistakes
by Porculus (Hermit) on Aug 23, 2008 at 17:43 UTC

    I made a lovely silly mistake yesterday. One of the kind where neither strictures, nor warnings, nor syntax highlighting can help. One of the nasty kind where the code appears to work, and produces a plausible but incorrect result. Something functionally equivalent to:

    my $bitstring = get_bitstring(); # Number of records is stored in first octet my $record_count = oct $bitstring; for my $i (0 .. $record_count - 1) { process_record( get_record($bitstring, $i) ); }

    It must have taken the best part of ten minutes for me to spot the two-character brainfart that was causing that never to process any records...

    Seriously, I don't think there's any way to prevent "doh" moments. The best one can hope to do is to prevent those errors that can be prevented, and make sure your tests are comprehensive enough to catch the rest.