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

Hi, I am person trying to learn programming and sometimes I am confused at what is bad code?

Can you guys please read my method below and answer if this is really bad coding? or point me to a book/website to learn what is good/bad practice at coding?
1) I know duplicate code is bad... so is my code below bad? as I have some duplication.
2) I also know one method should do one function only, my function below does three things.
a) create http connection
b) foreach through the tokens
c) determine with another function addDaily()/addTest() to see if the term should be added to an array list

my method takes a string $daily_test and calls different part of codes depending on the String value
44 sub constructList($release, $daily_test) { 45-52 Logic to handle getting a HTML page 53 if ($res->is_success) { 54 my @tokens = split('\n',$res->as_string); 55 my @List = (); 56 57 if($daily_test == "daily"){ 58 foreach my $token (@tokens){ 59 if($token =~ m/HREF="([a][^\/]*)/i) { 60 my $extracted = $1; 61 if ($1 !~ m/win/i){next;} 62 if (addDaily($extracted) == 1) { 63 push(@List, $extracted); 64 } 65 } 66 67 } #end foreach 68 69 } #end if 70 71 elsif ($daily_test == "test"){ 72 my $atLeastOneMatch = 0; 73 foreach my $token (@tokens){ 74 if($token =~ m/HREF="([a][^\/]*)/i) { 75 my $extracted = $1; 76 if ($1 !~ m/win/i){next;} 77 if(addTest($extracted) == 1){ 78 push(@List, $extracted); 79 } 80 } 82 } #end foreach

I could have turn this code to... less duplication but maybe a bit more unclear?
58 foreach my $token (@tokens){ 59 if($token =~ m/HREF="([a][^\/]*)/i) { 60 my $extracted = $1; 61 if ($1 !~ m/win/i){next;} 57 if($daily_test == "daily"){ 62 if (addDaily($extracted) == 1) { } elsif($daily_test == "test"){ 62 if (addTest($extracted) == 1) { } 63 push(@buildList, $extracted); 64 } 65 } 66 67 } #end foreach
Thanks!

Replies are listed 'Best First'.
Re: How to write good code?
by moritz (Cardinal) on Jun 16, 2009 at 15:21 UTC
    The first step should be to make the code correct. For example, use eq for string comparison (and not ==). Also use strict; use warnings;, that would have caught that mistake.

    IMHO your second solution is much more readable, but it suffers from bad indentation. Fix that, and be happy.

    Of course you could also use a dispatch table:

    my %dispatch = ( daily => \&addDaily, test => \&addTest, ); foreach my $token (@tokens){ if($token =~ m/HREF="([a][^\/]*)/i) { my $extracted = $1; next unless $extracted =~ m/win/i; if (eval { $dispatch{$daily_test}->($extracted) } == 1 ) { push(@buildList, $extracted); } } }
Re: How to write good code?
by jdporter (Paladin) on Jun 16, 2009 at 17:05 UTC

    Please don't insert line numbers when posting code here. If people want to see line numbers, they can turn them on in their Display Settings.

    Sub declarations like sub constructList($release, $daily_test) don't work, at least not in Perl 5 (but maybe you were just showing that as pseudocode).

    '\n' does not result in a string containing a newline character, as \n is not special in single-quoted strings. But remember that the first argument of split is a regex, so it is probably clearer to write split /\n/ anyway.

    == is not for comparing strings, only numbers (as a previous respondent said). Use eq for comparing strings.

    You use [a] in a regex. That is a character class which matches the single letter a. I suspect that you meant the character class [a-z].

    You assign $1 to $extracted, and then you use $1. You should use $extracted.

    Use modules where possible. Don't reinvent the wheel, let alone the Space Shuttle.

    I might rewrite your code as:

    my %add = ( daily => \&addDaily, test => \&addTest, ); $add{$daily_or_test} or return; # should die instead? my @List; for ( split /\n/, $res->as_string ) { if ( my( $extracted ) = /href="([a-z][^\/]*)/i ) { $extracted =~ /win/i and $add{$daily_or_test}->( $extracted ) == 1 and push @List, $extracted; } }

    But since it looks like you're dealing with HTML, I'd use an HTML parser module, such as HTML::TreeBuilder.

    Also, instead of passing in a string which symbolically indicates whether we're doing a daily or a test, you could pass in the function (by reference) directly:

    ref($daily_or_test) eq 'CODE' or die; . . . $daily_or_test->( $extracted ) . . .

    Between the mind which plans and the hands which build, there must be a mediator... and this mediator must be the heart.
Re: How to write good code?
by ELISHEVA (Prior) on Jun 16, 2009 at 17:34 UTC

    Good code...

    • works - it does what it should.
    • is easy for you to read - even six months after the last time you saw it
    • is easy for others to read - today, tomorrow, and always.

    As in all writing, whether in programming languages or human language, easy to read is a matter of context and audience. When you are first learning to code or if your whole development team is new to a programming language "easy to read" means lots of explanatory comments and white space. Later on, when you and your teammates are more experienced, those very same comments can seem like clutter and the white space can make the code so spaced out that it is difficult to skim. print "@{[%$hSomeHash]}\n" is easy for a Perl expert to read without comment, but probably makes your average Perl newbie's head spin (it did mine the first time I saw it). However, as long as you focus on getting things to work and checking in with others (and yourself) about the readability of your code, I suspect you will do fine.

    When you get further on in programming and have to design large programs, there are a lot of other issues to consider: common standards for teams and associated issues of compliance; which combinations of paradigms (object oriented, functional or procedural) are best for a particular problem; architecture; testability; maintainability; re-usability; and so on. But even on big programs, the same issues are still there: an architecture that is so convoluted that it takes a new team member six months to learn better be solving a really complicated problem that really, really can't be solved any other way. Generally, the best solutions still are (a) easy for you to read and (b) easy for others to read, even on the large scale.

    Best, beth

Re: How to write good code?
by eyepopslikeamosquito (Archbishop) on Jun 16, 2009 at 22:02 UTC
      Thank you all for the suggestion
      Thanks for letting me know about the dispatch table
      I will be checking out those books soon
      cheers!
Re: How to write good code?
by toolic (Bishop) on Jun 16, 2009 at 15:55 UTC
    point me to a book/website to learn what is good/bad practice at coding?
    Perl Best Practices is a book which contains well-written guidelines for creating consistent Perl code. The focus, naturally, is on Perl syntax, but many of the principles apply generally. There are many examples of what the author considers bad coding style and good coding style.
Re: How to write good code?
by Limbic~Region (Chancellor) on Jun 16, 2009 at 17:58 UTC
    ahhlun,
    I wrote Re: Refactoring a large script which has bits and pieces on writing good code as well as writing code effectively. Each one of those things can be expanded further. In my opinion the best way to write better code is to learn from others more talented than you who are willing to teach. The Monastery is a perfect place to do that (which is what I did).

    You may also be interested in "Modern Perl" which is the idea that we should be taking advantage of all the advances and lessons programming has made over the last few decades and standardize more on how we program. There are differing philosophies but googling around should get you started.

    Cheers - L~R