|Perl: the Markov chain saw|
Re: Best practices - if any?by afoken (Monsignor)
|on Feb 21, 2010 at 12:27 UTC||Need Help??|
If you have that much code that you feel the need to spread it over several files, think about modularising it.
In C, you would better NOT simply #include "second_part.c", but instead split your code into smaller parts, compile them separately into object files, and use the linker to create a single executable. You would perhaps end with something like main.c, inputreader.c, logger.c, smoothify.c, prettyprint.c, and perhaps utils.c and globals.c. For most of the files, there would be a corresponding *.h file containing the "public" interface, i.e. those functions that are called by one of the other files (logger.h would perhaps contain something like extern int initlogger(const char * logfile); and extern void log(int level, const char * message);, globals.h would instead define the few needed global variables, e.g. extern int verbose; extern char frobnicate;). All functions (and global variables) not needed outside one of the source files would be declared as static, so that the linker does not try to resolve those names.
In Perl, you would do pretty much the same: Put groups of functions into modules, have a public interface for each module (i.e. use Exporter for non-OOP code), and have a short main program that delegates to the modules.
Because Perl already has a lot of modules, use a unique prefix for your module names. If you have no better idea, use the application name and / or your last name or your company's name. You would end with AriSoft::Frobnicate for the main routines, AriSoft::Frobnicate::InputReader, AriSoft::Frobnicate::Logger, AriSoft::Frobnicate::Smoothify, AriSoft::Frobnicate::PrettyPrint, AriSoft::Frobnicate::Utils, and perhaps AriSoft::Frobnicate::Globals.
Thinking about "big subs":
Some big things are a pleasure to the eye, but "big" subs spanning more than one or two screens (i.e. more than 50 lines) are a sure sign of wrong design. You will become confused when you need to change the code, you will pile up status variables and obscure if-then-else constructs, and perhaps you even will abuse goto. Split them into smaller, specialised functions. This is pretty independant from Perl, you have exactly the same problem in nearly every other language.
I'm currently earning my money by refactoring C-like code written by an ungifted amateur, full of bugs, copy-and-paste, gotos and cargo cult, without any proper indenting, with functions spanning literally thousands of lines, with loops and ifs nested more than 10 levels deep, and of course without any useful documentation. I've removed more than 30% of the code without any loss, and I will remove about another 30% before the will go back to the production machines. During the process, the number of functions will at least double. That code is a real nightmare, no one has a clue about what it does, and just deleting the crap and starting from scratch is not an option. All we can do is to cleanup every piece of code we need to touch, and hope for a slow improvement over time.
Learn from that, start writing clean, structured, and documented code NOW.
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)