People often wish that PerlMonks did more code reviews.
They want a special section for that.
I think that this post is an excellent example of why it
doesn't happen. This is code that boo_radley clearly
put work and thought into. He asked directly for feedback.
While plenty duly voted him up, so far nobody was willing
to put their neck on the line and put out the energy to
give him any.
My opinion is that this happens because enough code to be
useful for review is enough code to be more work than most
people want to put out. Also when dealing with code that
is meant to be good, and has nothing glaringly wrong with
it, people don't generally feel comfortable
criticizing.
Unfortunately I don't have energy to follow this up with a
real dialog. But I will put down a baker's dozen of
things that I noticed and think could be done differently.
I sincerely hope that someone else follows up with a third
opinion on some of these issues (or anything else you
see)...
- Why the prototypes? As you know I am not a fan of
them, but since you clearly intentionally using them, I
am curious what led you to do so.
- I prefer seeing stuff in @EXPORT_OK rather than
@EXPORT. (Just like Exporter recommends.)
Particularly if (like get_var and set_var) the names are
generic with no relation to the module at hand.
- You do a lot of passing by reference and passing of
references. Compared to the work it takes to process
arguments, the work to pass them is minor. I prefer to
not worry about that.
- A related API note. You seem to do (see the get and
set methods) a lot of modification of variables through
references. To my eyes this is a disguised global.
OK, it isn't called a global, but the same locality of
reference issue exists.
- If you are going to access by reference, I prefer to
see $foo->{bar} rather than
$$foo{bar} because that way the code reads
more naturally "left to right".
- In your 2 InsertPage* methods I count the same list
of 10 items appearing no less than 4 times. That is
repeated information that can and should be abstracted
into an array and used internally. Otherwise it is a
potential maintainance problem. (It would also be nice
if one of those methods called the other behind the
scenes.)
- Some of your arguments should be able to default to
reasonable things. You have 10 variables, some of
which you admit are useless...
- I don't like passing errors in a global variable
that may or may not get checked. I would suggest
making those errors be raised. If the user page wants
to it can catch them with an eval block (which is
efficient). At the top level you can trap that and
do something reasonable.
- Similarly numerical return codes tend to be a lot
harder to track down when things go wrong than nicely
formatted string errors. At the best the string gives
you a description of what went wrong. At worse the
contents of the string are easy to grep for. This is
(of course) in addition to the fact that it is easier
to type 13 when you meant 14 than it is to type
Permission denied when you meant Bad
address. (Example error messages taken from what I
get for system errors 13 and 14 on my machine.)
- Your load_lib routine will probably not work as you
intend since confess is a fatal error. (In my
example code that you borrowed, I intended that
result. The only soft error was an undefined return
value without $! or $@ being set.)
- I would wonder about loading code into package main.
I think it would be better to require the code and
let the user make sure that their libraries are valid
modules, which are loaded into the package that they
should be. Something like this:
# Load a package
sub load_lib {
my $pkg = shift;
my $file = $pkg;
$file =~ s/::/\//g;
$file .= ".pm";
require $file;
}
Note that this does not import. If the modules
are OO, then that should not matter. Note that if the
module was already loaded, then the above will avoid
redoing work.
- I would be inclined to have a worse dump_struct
method. Just use Data::Dumper and print out a
plain text page. That may not be pretty, but it is
easy to do, handles difficult issues with recursive
references et al, and is likely to be useful in
debugging.
- In your example code, I notice no locking logic.
I would suspect race conditions where your simple
database handling will cause data corruption. For a
personal journal, regular backups are good enough.
But it still is an issue to be aware of.
Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
Read Where should I post X? if you're not absolutely sure you're posting in the right place.
Please read these before you post! —
Posts may use any of the Perl Monks Approved HTML tags:
- a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
| |
For: |
|
Use: |
| & | | & |
| < | | < |
| > | | > |
| [ | | [ |
| ] | | ] |
Link using PerlMonks shortcuts! What shortcuts can I use for linking?
See Writeup Formatting Tips and other pages linked from there for more info.