Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

Re: hacking a project in groups

by Rudif (Hermit)
on Sep 02, 2001 at 00:42 UTC ( [id://109676]=note: print w/replies, xml ) Need Help??


in reply to hacking a project in groups

Hi melguin

I agree *totally and completely* with everything that tachyon and maverick said.

If you agree, too, your question might be: where do I start?

I would suggest that you read up on eXtreme Programming , especially about code refactoring and unit testing. Also search the PM site here for eXtreme Programming.

Your code saute_0_0_2 looks neat and well organized, so it should not be difficult to morph it.

Let me try to suggest a recipe (untested) for putting the OO advice into the practice.

You have 2 perl files -
dbsetup.pl, 152 lines - uses DBI - creates the database schema
saute.pl, 1435 lines - uses Gnome and DBI - main program, creates Gnome main window and accessories, lets the user view and edit recipes

If I were you, I would start with making a module (a.k.a. package a.k.a. class) that wraps all your interactions with the database. This would separate your data storage and maintenance from your GUI application, and let you develop each separately, perhaps by different participants.

In particular, all subs (or their inner code chunks) in the main program that interact with the db should become methods of this module.

Step 1

Create a module file RecipeDb.pm containing this

#!/usr/bin/perl -w use strict; package RecipeDb; sub new { my ($class, %args) = @_; my $self = { dbname => $args{dbname}, dbuser => $args{dbuser}, dbpasswd => $args{dbpasswd}, # more options if needed ... #workspace dbh => undef, }; bless $self, $class; $self->{dbh} = DBI->connect("DBI:mysql:$self->{dbname}","$self->{d +buser}","$self->{dbpasswd}", { PrintError => 1, RaiseError => 0, }) || die "Can't connect to $self->{datasource}: $DBI::errstr"; return $self; } sub DESTROY { $self->{dbh}->disconnect(); } # your code from saute.pl, slightly modified sub get_recipe_info { my ($self, $recipeID)=@_; # notice $self my %recipe; #get main recipe parts my $sth = $self{dbh}->prepare("SELECT name,descr,instruct, preptime,notes,source FROM recipes WHERE PriKey=$recipeID"); # notice $self{dbh} $sth->execute(); while (my @row = $sth->fetchrow_array) { $recipe{"recipeID"}=$recipeID; $recipe{"name"}=$row[0]; $recipe{"descr"}=$row[1]; $recipe{"instruct"}=$row[2]; $recipe{"preptime"}=$row[3]; $recipe{"notes"}=$row[4]; $recipe{"source"}=$row[5]; } $sth->finish(); #get ingredients my @ingredients_list; $sth = $self{dbh}->prepare("SELECT recipeIngredients.quantity,units.name, ingredients.name FROM recipeIngredients,ingredients,units WHERE (recipeIngredients.recipe=$recipeID) AND (ingredients.PriKey=recipeIngredients.ingredient) AND (units.PriKey=recipeIngredients.units)"); # notic +e $self{dbh} $sth->execute(); while (my @row = $sth->fetchrow_array) { push (@ingredients_list, [$row[0],$row[1],$row[2]]); } $sth->finish(); $recipe{"ingredients"}=\@ingredients_list; #get categories my @categories_list; $sth = $self{dbh}->prepare("SELECT categories.name FROM recipeCategories,categories WHERE (recipeCategories.recipe=$recipeID) AND (categories.PriKey=recipeCategories.category)"); +# notice $self{dbh} $sth->execute(); while (my @row = $sth->fetchrow_array) { push (@categories_list, $row[0]); } $sth->finish(); $recipe{"categories"}=\@categories_list; return \%recipe; } # more methods here 1; # true enough

Run this file to make sure that it compiles.

Step 2

Write a little test program, say TestRecipeDb.pl

use RecipeDb; my $rdb = new RecipeDbase( dbname => $DBNAME, dbuser => $DBUSER, dbpasswd => $DBPASSWD, ); my $ID = ""; # please fill in my $recipe = $rdb->get_recipe_info($ID); Use Data::Dumper; print Dumper $recipe;

Does it work? Is the dumped recipe what you expected? If not, fix it.

Step 3

Now copy the code from TestRecipeDb.pl into your main program, saute.pl.

Replace all calls to  get_recipe_info() by calls to  $rdb->get_recipe_info() .

Test thoroughly. Does it work as before? If not, fix it.

OK? Now remove  sub get_recipe_info() from saute.pl.

Step 4..N

Repeat for all other subs that interact with the database what you did for  get_recipe_info() : make a clone in RecipeDb, test it, call it from main program, remove the original sub from the main program. When done, remove  use DBI; from the main program.

What next?

Above should leave you with a considerably smaller saute.pl, a module RecipeDb.pm and a test program for it. And enough OO experience to take another hard look at what you have and decide what would be the next useful steps.

You should probably move some of the code from dbsetup.pl into RecipeDb.pm, and leave dbsetup.pl as a command-line interface to creating the database. If some day you decide to provide a graphics interface for this activity, you'll be ready.

Next, turn those recipe hashes into packages, perhaps?

You can turn the test program into a regression test by hardcoding the expected results and comparing with what you get from the database.

Oh, I almost forgot the most important advice: enjoy!

Rudif

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://109676]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (3)
As of 2024-03-28 16:48 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found