Don't forget to look at the code after the line number in the message, too. Compare: $ cat -n elsif.pl 1 use strict; 2 use warnings; 3 4 our $foo; 5 6 if ($^O eq "23niWSM") { 7 print "bugaboo

"; 8 } 9 elsif ($foo eq "bar") { 10 print "foobar

"; 11 } $ perl elsif.pl Use of uninitialized value in string eq at elsif.pl line 6. $ cat -n if.pl 1 use strict; 2 use warnings; 3 4 our $foo; 5 6 if ($^O eq "23niWSM") { 7 print "bugaboo

"; 8 } 9 if ($foo eq "bar") { 10 print "foobar

"; 11 } $ perl if.pl Use of uninitialized value in string eq at if.pl line 9. $ diff -u if.pl elsif.pl --- if.pl 2004-07-20 15:00:49.412472000 -0700 +++ elsif.pl 2004-07-20 15:02:28.875492800 -0700 @@ -6,6 +6,6 @@ if ($^O eq "23niWSM") { print "bugaboo

"; } -if ($foo eq "bar") { +elsif ($foo eq "bar") { print "foobar

"; } [download]

Excellent writeup. Off topic, I have to comment on introductory regexp: s/girlfriend/wife/ [download] Boy, one can encapsulate a huge amount of life change in 18 chars of perl! Also it is good you did't have to use the /g modifier there!

that can be shortened:

tr/glrind/wi/d;

=)

Could someone explain what exactly does it do?

tr/glrind/wi/d

Thanks.

Have you noticed areas of confusion? When trying to explain your code to others, have you noticed where they get confused? Have you noticed where you get confused? Spend some time in those areas. Try refactoring, simplifying, or rewriting until the confusion goes away.

I hate when this happens, but it happens to me. I spent a couple of hours renaming several sets of modules because one sentence in the documentation made no sense with their original names.

A tough idea: Having checked your code several times, you might know it by hard. So, rewrite it all again without peeping at the original one. Then compare boths scripts. There might be some significant differences, that might brainstorm or ( lateral think ) some solutions. And if you are not able to know it by hard, it might be too long and should be shorten into more simple chunks of well structured code :) .{\('v')/}

_`(___)' __________________________

Did you check the effective user?(in the same vein as Did you check the environment?) A typical problem for people developing CGI code on Windows / IIS - My script runs from the command line but breaks when I run it under IIS. Problems like this usually relate to the script being run under a restricted user account. Scheduled jobs suffer from a similar range of problems. Things that may not work if you have user/permissions issues include: Read/write to a local file.



Accessing network shares.



Read/write registry settings.



Working with functionality that depends on any of the above e.g. ODBC.

Great node ++. Some oft-repeated advice but it is great to have it all in one place, I can see this being a much linked to node and worthy of promotion to tutorials (it is currently under consideration for readmore tags). On the topic of references I don't have The Perl Pocket Reference but I do have Perl in A Nutshell which lives permanently on my desk, I have long since given up trying to put it back on the shelf for exactly the reasons you describe. You might be emotionally attached to a certain part of the code, so you do not change it. A lot of writers fall into this same trap of emotional attachment "but I like this sentence/passage" and because they like it they can't see that it detracts from the piece of writing. The golden rule of editing is "be bloody ruthless", it seems like good advice for coding as well. --

Do not seek to follow in the footsteps of the wise. Seek what they sought. -Basho

Fantastic Node!! ++ A couple of suggestion I'd add, some in alignment with some of your own suggestions.



Is your code intuitively simple?: I've only been programming for a little while but one thing I found once I got use to the concepts/ideas the best solutions have a simple-ness about them. And often have less bugs. If you find your solution is a bit convaluted/verbose chances are there is a neater and cleaner way of doing it. By chance, my recent node 375782 is a perfect example of what I mean (a few suggestion but the final solution {thanks to tye} only required two small changes to a problem I'd been considering for quite a while). I love that about programming.



In addition to "Personal Responsibility" Make the effort to solve it yourself: Programming, the knowledge behind and the ability to research it are skills that are acquired in time. The time spent debugging and finding solutions is a skill unto itself. In time this skill develops and you get faster at it. The ability to research for yourself (to be self reliant) is a skill also. Later when you get a problem you can solve it in a matter of moments because of the problem-solving skills you've developed. And trust me this comes from experience ... I've NEVER EVER done a computer course or training. NOT ONE! I'm completely self taught. A skill that now has be challenging even some of the senior technicians at my work.



Take a shower: Hey it works for me! The break from the screen and code gives your mind time to relax, rethink. The water is meditative and soothing. I often walk out of the shower with my mind flowing with new ideas (excuse the pun!) Plus after 12+ hours in front of a monitor the hygiene is probably beneficial. :-)





Dean

The Funkster of Mirth

Programming these days takes more than a lone avenger with a compiler. - sam

RFC1149: A Standard for the Transmission of IP Datagrams on Avian Carriers The Funkster of Mirth

A quick googling found an earlier version which includes the copyright information. Alas, it is "all rights reserved." Is there any chance you would open this up with a less restrictive license, such as the Perl Artistic License, a Creative Commons license, or the GNU Free Documentation Licence? Of course, I can give people a link or tell them to google it, but this is the kind of guide that you want to have hard copies of -- one for yourself and several to pass out to anybody who stops by.

I'm not worried about people printing it out. You just can't publish it yourself, sell it, or put your own name on it. If you are making a couple of copies to give to friends and co-workers, you don't have a problem. If you want to put it on thousands of CDs, then you should talk to me first. :) --

brian d foy <bdfoy@cpan.org>

In the line of verifying everything, you said that you did an s/girlfriend/wife/ but don't appear to have actually done it. :-P Otherwise this is all good advice. UPDATE: It's been done now.

Most of these things also apply to any programming task in any language not just Perl. At a first glance the only thing that doesn't fit into any language is "Are you using the right special variable?".

There is also the Perl pragma's, using perldoc, several mentions of the perl documentation, using Data::Dumper, using the perl debugger, checking module versions, setting the environment in %ENV, using Test::Harness, and probably a few other things. :) --

brian d foy <bdfoy@cpan.org>

Yes, but other languages has profilers, docs and so on. These things are not perl only. :)

In general, it's a good idea to declare variables using my instead of using a global or using local. It forces namespace and scope awareness and eliminates pernicious bugs caused by same-named variables with different scope. Practically anything you can do with a local or global variable, you can do with a change in design using my, and you'll get a much more robust design. Also, in general, avoid exporting variables from modules. Exporting methods can sometimes be OK, although I still think it's better to say use Foo::Bar; ... my $barian = Foo::Bar->baz(); [download] so the method's origin is clear. Variable and method names should be communicative of the intended use; it's better for a name to be long and communicative than short and cryptic. Document, document, document. Also: I'm astonished no one's mentioned using functional spec's and test suites before now. (Visit this Joel Spolsky article and scroll down to the second headline, "Painless Functional Specifications," for information on the former; perldoc Test::Harness and perldoc LWP::UserAgent for details on the latter, and on user agents which are also an enormous boon to web developers seeking a means of testing functionality and sounding the alarm when things go wrong.) Writing a spec before the program saves loads of time and heartache, as well as keeping the MBA's and the techies on the same page. Similarly, fleshing out the spec into a test suite before any code gets written -- and continuing to flesh out the test suite while coding -- reduces the likelihood of bugs, increases confidence in the final product, and makes a predictable timeline actually possible. Ideally, you want to test as high up the call chain as possible, drilling down into the nitty gritty only when -- and to the extent that -- the need presents itself. There are even times where it can be helpful to write a tiny program whose specific purpose is to test the syntax or the effect of some (for you) uncharted Perl functionality. I did this in my formative Perl years and it saved me an enormous amount of time. Oh, and also it helps -- particularly if you're working in a country whose primary language is English -- not to comment your code in, say, Croatian. (Don't laugh, I actually inherited a project some years ago containing some sections of code in which this had been done!)

Along similar lines as that last point, I'd find myself (particular for CPAN modules) always writing my APIs in American English, despite being in Australia.



It just makes life similar if everybody uses the same spelling for classes and methods. It's a swallowing your pride thing.

Any reason why you type all of require Data::Dumper; print Data::Dumper::Dumper(...); [download] rather than use Data::Dumper; print Dumper(...); [download] ? Also, in your particular example, I always prefer the output of Dumper(\%hash) to that of Dumper(%hash) . Recently, I've been sometimes using the even-less-typing-required use YAML; print Dump(...) , but that requires actually installing YAML first. And I'm still not nearly as used to the YAML format as I am to Data::Dumper format.

Most style guides I work under ask for the full package name of external functions, and I generally agree with that. I have found that I shouldn't expect others to know where all of these functions came from. Also, I don't have to keep track of every modules exports. Some decided to have the same names for things. Remember: @EXPORT is evil. This way would cause a problem if someone wanted to use YAML as a drop in replacement, though. --

brian d foy <bdfoy@cpan.org>

Most style guides I work under ask for the full package name of external functions, and I generally agree with that. I have found that I shouldn't expect others to know where all of these functions came from. I totally agree that you should know where a subroutine comes from, but i pretty strongly disagree with using FQ package names to acomplish that, and I definately don't think that using require is wise at all. There are two reasons for these opinions. The first has to do with encapsulation. When you use FQ subroutine names you are totally violating the encapsulation of your package code. Take the following contrived example: Package Foo has two subs defined, BarA() and BarS(), BarA is defined for export, BarS is defined as a more or less private internal version. You want to use BarA(), so you write Foo::BarS() and then wonder why your program A) doesnt fail when it gets to that line, and B) why its just done something horrible to your data that BarA() promises not to do. With use and explicit exports you dont have this problem. You EXPLICTLY request the export of a subroutine. Assuming the private version isnt in @EXPORT_OK then youll never blow your foot off by saying: use Foo qw(BarS); [download] A second serious objection i have to using require like this is that requires are run time constructs. Your program could have half finished before it gets to the require only to fail, leaving your program in the tough position of having to recover, something that it may be bad at, which could leave your overall system in an indeterminate state. Wheras with use the error would have occured at compile time, and would have happened before almost anything else did, a situation much easier to recover gracefully from. My personal feeling is that require is a badly named keyword. Most often when I see the keyword in use is when the code doesnt in fact "require" the module at all, but rather would just prefer it to be there. AFAICT when code really require s a module its much better to use it instead. Anyway, good thread. Thanks. ---

demerphq





Most style guides I work under ask for the full package name of external functions What an awful idea. Just being explicit about what you import from any module you use is a much better idea. @EXPORT is evil but @EXPORT_OK makes for easier-to-read/-write code and provides reasonable interface verification (at compile time, no less). demerphq already said all of this, but I just boggle at the sentence I quoted so I had to chime in against such insanity. - tye

I agree that @EXPORT is evil but in your case you miss possible invocation of "import" function, which could do some necessary setup. Yet you don't do require strict; , don't you?

use YAML; print Dump(...), but that requires actually installing YAML first. You might try installing Data::Dump::Streamer (along with the DDS alias.) Then its just use DDS; Dump(...); :-) Its a Data::Dumper replacement (not drop in) which does a more or less breadth first dump of your data so its usually a lot easier to read, especially for cyclic and selfreferential data structures. ---

demerphq





use YAML; print Dump(...) , but that requires actually installing YAML first. You might try installing Data::Dump::Streamer (along with the DDS alias.) So, your suggestion to sfink's drawback of having to install a module is to install a module?

The best debugger in the universe is print . print STDERR "The value is [$value]

"; [download] To which I'd add, while not earthshaking or original, that I like using warn even more than print STDERR . Besides being shorter, the fact that it's different makes it easier to find such statements and comment out those lines when I'm through with them. More particularly, I put my debugging 'warn' messages at the start of a line. Since most of my perl code has been indented a couple of tabs away from column 1, the fact that these statements are 'debug' type statements stands out. And since I might want to reuse the same debugging statements from time to time, rather than erase them when I'm done, I just comment them out when I'm "through" with them. This way, when I'm desparate later to know what's happening in some region, those previously written warn statements are there, waiting to be uncommented. And if I uncomment seven or eight of them (among the dozens/hundreds in my code :-), I can easily find them again to turn them off when I'm done with them by doing a vim search for them at the start of a line. /^warn Then repeat my search with n and repeat my 'uncomment' with a dot. Because these statements are at the start of a line, they can be found differently than the warn statements that are in the clear and are SUPPOSED to fire when triggered by real problems.) I also find that including use Carp qw(cluck); early in my program and using cluck statements at the start of a line (a la warn ) helps me figure out just how a particular subroutine got invoked.

I use warn() for program warnings rather than debugging output. However, if I'm doing really big things, I usually have a debug() or trace() function lying around. --

brian d foy <bdfoy@cpan.org>

However, if I'm doing really big things, I usually have a debug() or trace() function lying around. But not a log() function. (Don't laugh, I've been bitten by this one.) Being right, does not endow the right to be rude; politeness costs nothing.

Being unknowing, is not the same as being stupid.

Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.

Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Of course it's fine to save warn() for "real" error messages, but then the same could be said for only using print() for real output messages. My problem, for which I'd welcome suggestions, is that I'm not familiar with how to use debug() in the midst of debugging a huge Tk-based application that I'm working on. The subroutines I am debugging get fired when I click one of the Tk buttons, and I know for sure that I can get at my warn() messages as above via my STDERR files. Out of ignorance, I'm just expecting use of debug() to be impractical.

A most enlightening post, if I may say so, brian_d_foy. I also used to use warn() until I realised that, when re-running Test::* based modules, it [the use of warn() ] 'gets in the way' of true warnings - ever since when I, like you, define an additional sub to printf STDERR ... - thus the code behaves as I think it should whilst still generating debugging messages that don't cause test case failures. A user level that continues to overstate my experience :-))

Somebody updated their French translation with your patch... :-)

Somebody? :) I'm getting a lot of good comments here (I'm surprised really: not by the quality but the quantity), so I'll eventually roll them back into the other version along with credit to anyone who helped. I should also list all transations in the main document too. I could really use a Russian translation though. And maybe a Swedish Chef one. --

brian d foy <bdfoy@cpan.org>

Have you watched The Daily Show with Jon Stewart?, Several people commented along the lines of "take a break and do something else and it will come to you". This has happened to me enough times that I really started to think about how/why it worked. My theory is that it puts your mind into a different problem solving mode, similar to problem solving in the dream-like state, which I've also experienced. This seems to allow greater creativity, new approaches, and synthesis.

I've learned to love my dry erase board at work. When the mental block is on full it sometimes helps to step back and diagram the problem showcasing both flow and\or expectation of how the code is intended to work. More often than not, if there is a problem in logic, it becomes apparent from the flow and if it is a choice of code function, the expectation becomes apparent. Dry erase makes it easy to edit and if all else fails, I guess sniffing the marker comes to mind.



Great article Brian.

Two possible typos: "The value is ]$value]

"



You can check the most module version with a simple perl one-liner

I particularly like these two suggestions: Does the problem look different on paper?



Explain your problem aloud. Actually say the words. Cheers.

I find going for a pee solves most of my problems. You think I'm joking?!! (forgot to login the first time doh!!)

Amazing text first of all, a ++ to it and all other good suggestions around it

now my part of contribution If you want to do some changes in order make your (huge in number of lines of code)script working(on which you recently faced some problems during extending code or adding new functionality), before incorporating the new change in the original script try to write a small script(probably a perl one liner) and check whether your that small logic will work in the small script, they try applying in the original script I use this method if I want to include a regular expressions in to my existing scripts(huge in size), and it is assured that it works correctly provide I check it simple program or one liner. Vivek

-- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.

Brian, Thank you for the excellent work you have created here, I just stumbled onto this by a comment from the ChatterBox! Some of these items I was already following, however, several are new thoughts on old habits. And I thought I was the only one to have fallen into these traps! Thank you for your wisdom. This is a node I shall have to link to. pmonk4ever "No trees were harmed in the creation of this comment. However, a rather large number of electrons were somewhat inconvenienced." Update: This line is still broken: print STDERR "The value is ]$value]

";