Cookie Notice

As far as I know, and as far as I remember, nothing in this page does anything with Cookies.

2010/08/18

The Heartbreak of Copy/Paste Code

This is actual CGI code that I'm working on.

  1. if ( 0 ) { }    # BLANK to make adding and changing elsifs easier  
  2. elsif (    defined $cgi->param( 'request_id' )  
  3.         && defined $cgi->param( 'status' ) ) {  
  4.     my @keys ;  
  5.     my @vals ;  
  6.     my $data ;  
  7.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  8.     $data->{ status }     = $cgi->param( 'status' ) ;  
  9.     $data->{ program }    = $cgi->param( 'program' ) ;  
  10.     $data->{ notes }      = $cgi->param( 'notes' ) ;  
  11.     create_new_request_status $data ;  
  12.   
  13.     my $request_id = $cgi->param( 'request_id' ) ;  
  14.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  15.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  16.     }  
  17. elsif (    defined $cgi->param( 'request_id' )  
  18.         && defined $cgi->param( 'barcode' ) ) {  
  19.     my $data ;  
  20.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  21.     $data->{ val }        = $cgi->param( 'barcode' ) ;  
  22.     my $err        = update_request_barcode( $data ) ;  
  23.     my $request_id = $cgi->param( 'request_id' ) ;  
  24.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  25.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  26.     }  
  27. elsif (    defined $cgi->param( 'request_id' )  
  28.         && defined $cgi->param( 'request_name' ) ) {  
  29.     my $data ;  
  30.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  31.     $data->{ val }        = $cgi->param( 'request_name' ) ;  
  32.     my $err        = update_request_name( $data ) ;  
  33.     my $request_id = $cgi->param( 'request_id' ) ;  
  34.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  35.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  36.     }  
  37. elsif (    defined $cgi->param( 'request_id' )  
  38.         && defined $cgi->param( 'species' ) ) {  
  39.     my $data ;  
  40.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  41.     $data->{ val }        = $cgi->param( 'species' ) ;  
  42.     my $err        = update_request_species( $data ) ;  
  43.     my $request_id = $cgi->param( 'request_id' ) ;  
  44.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  45.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  46.     }  
  47. elsif (    defined $cgi->param( 'request_id' )  
  48.         && defined $cgi->param( 'source' ) ) {  
  49.     my $data ;  
  50.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  51.     $data->{ val }        = $cgi->param( 'source' ) ;  
  52.     my $err        = update_request_source( $data ) ;  
  53.     my $request_id = $cgi->param( 'request_id' ) ;  
  54.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  55.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  56.     }  
  57. elsif (    defined $cgi->param( 'request_id' )  
  58.         && defined $cgi->param( 'library_type' ) ) {  
  59.     my $data ;  
  60.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  61.     $data->{ val }        = $cgi->param( 'library_type' ) ;  
  62.     my $err        = update_request_library_type( $data ) ;  
  63.     my $request_id = $cgi->param( 'request_id' ) ;  
  64.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  65.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  66.     }  
  67. elsif (    defined $cgi->param( 'request_id' )  
  68.         && defined $cgi->param( 'lab_director' ) ) {  
  69.     my $data ;  
  70.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  71.     $data->{ val }        = $cgi->param( 'lab_director' ) ;  
  72.     my $err        = update_request_lab_director( $data ) ;  
  73.     my $request_id = $cgi->param( 'request_id' ) ;  
  74.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  75.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  76.     }  
  77. elsif ( defined $cgi->param( 'request_id' ) ) {  
  78.     my $request_id = $cgi->param( 'request_id' ) ;  
  79.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  80.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  81.     }  
There's value-scrubbing on the other side of all the update_request_* stuff. At one point, there were four cases here, and now there's nine. The if (0) {} bit at front was there to make it easy for me to juggle order if I want, but the rest ....

I'm Dave, and I'm a Copy/Paste Coder.

If I was tossing to the same function at the end, it would be one thing. I can imagine having something like the following function to fix things, but the big elsif chunk in the center seems only marginally better.
  1. sub un_copy-paste {  
  2.     my $output ;  
  3.     my ( $request_id , $key , $val ) = @_ ;  
  4.     $data->{ request_id } = $cgi->param( 'request_id' ) ;  
  5.     $data->{ val }        = $cgi->param( 'source' ) ;  
  6.     my $err ;  
  7.     if ( 0 ) {}  
  8.     elsif ( $key eq 'source' ) { update_request_source( $data ) ; }  
  9.     elsif ( $key eq 'species' ) { update_request_species( $data ) ; }  
  10.     # and more like this  
  11.     $output .= $cgi->h2( 'Request #' . $request_id ) ;  
  12.     $output .= $cgi->div( show_request( $request_id ) ) ;  
  13.     return $output ;  
  14.     }  
I think reading more Higher Order Perl could help me come up with something non-stupid.

5 comments:

  1. Make the elsif a trinary table, as shown below? (or a given/when if you're requiring or running on 5.10 or above?)

    ('species' eq $key) ? update_request_species($data) :
    ('source' eq $key) ? update_request_source($data) :
    ();

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. I posted some code but it looked like crap, so I made it a gist at github

    It uses a hash of coderefs, which I think is the most straightforward solution. It also uses curried coderefs, which is a little weird, but kind of like HOP. I love coderefs :P

    ReplyDelete
  4. Thanks for the ideas. My Wednesdays are busy, so while I tossed my physical copy of HOP into my bag and my PDF copy into my Dropbox, I didn't read a word of it.

    ReplyDelete
  5. I eventually had to add a table for the names of fields in the input hash and the names of the params that fit into it, but now I'm special-case-less and free!

    ReplyDelete