http://www.perlmonks.org?node_id=986908


in reply to Perl Elitist Code vs Functional Code

Most of our esteemed Monastery Elite are taking the expected position that this so-called "Elitist" code, with it's mandatory OO design and dependence on modules to perform even simple tasks is better because it makes your code "clearer" and "easier to maintain".

The more attuned monks are adding that, while a 10-minute hack will always be better than an hour-long struggle when solving a single, specific problem, most of these small hacks will eventually grow into full-fledged packages and distributions, even if they were originally never designed to do more than that one small function.

I am curious as to the turning point at which one should abandon the hack in favor of a package. For example, to tie in the reference to the Unix shell vs. Perl post, I have a collection of tiny hardware monitoring shell scripts that run every second and output to the notification area of my window manager. Right now there are three "module" scripts, one "daemon" that is required by a "module", and one that runs each "module" and compiles/formats the output onto a single line. Most are 3-5 lines long, one is about 15 or so because it has to do a switch on the different battery states. I wrote the first version of these over a year ago when I first started using dwm, and recently rewrote them for my new netbook almost from scratch and with considerable improvements as I have learned more about bash scripting. Over the last year, I have thought many times, "Hmm... If I combine everything into a super-duper Perl script I can put everything into separate packages and use better logic and tie in CPAN modules and event handling and all sorts of other fun stuff. But-- if I try to make the move from thinking about to writing it, I end up worrying too much about scary OO concepts and being unsure about how to actually prototype everything I want to add without limiting my options. Also I'm a little worried about a tradeoff in resource use, although that shouldn't really be that much of a concern. I kinda lost my train of thought, but I guess the point is, even when you have an idea to expand a quick and simple hack, and when know exactly what kind of features you could get out of it, the sheer complexity of converting everything into OO is too much to overcome the inertia of having a perfectly working thing right now. Unless, of course, you're an OOP elitist who spends the first 30 minutes of every script writing 50 lines of package infrastructure. (Sadly?) I am not experienced enough to do this comfortably.

There is another important aspect to best practices--formatting and naming conventions, comments/documentation, stylistic things--and these I tend to disregard with such inconsistency that it's downright dangerous for anyone to look at my code if they are (not?) on mind-altering drugs. I never remember what I chose to name some random variable, I constantly mix awkwardly short control structures with my clear, fully-typed-out ones because I feel that it would save time and space on the screen, I don't think I have a single file longer than 50 lines that uses the same indentation or delimiter placement scheme throughout the whole file, and I usually only bother to comment when I know from the start I'm not going to finish something right away, or if I've already spent 20 minutes starting at something and don't want to figure it out a third time. This is probably much much worse than not using modules and such, and the Elitists will argue that writing code this way is not even "functional". I say it's functional if it works, and if I wrote it and it worked, then it's functional enough, until I have to go back and fuck with it some more. But I think the root of the problem is that Perl is positioned as this practical language with its quick-and-dirty one-liners and such, which makes it very attractive when you want to sit down and pump out a feature for something in 10 minutes. But then at the same time, it goes "No no no no, this is BAD PRACTICE, you really should treat it like one of those other languages, where everything should be verbose for the sake of clarity." And yeah, I suppose the latter is what all programming should be, regardless of language, and that's just something any code will have to deal with. Then this is really just a rant about how annoying it is to have to type the same thing all the time, because even if you claim that you don't rewrite your code, you do have to rewrite all those long method names, all those long object references, all that nice white space and other assorted "fluff", etc. Like, I've been working with Catalyst for way too long, and it's such a pain in the ass to constantly have to type out the same one or two-line snippets to handle routine things like reloading model data that was saved to the stash, or setting status/error messages (the "best practice" way is: $c->res->redirect($c->uri_for("/some/url/goes/here",{mid=>$c->set_error_msg('Oh noes, ANOTHER FUCKING ERROR!!!'}));$c->detach(); and that is with minimal whitespace). But it works. And it has big advantages over other "simpler" methods. So I grunt and I deal with it, but it certainly makes me laugh at the notion that Perl is, by its very nature, a terse language.

ok. rant over. OBLIGATORY IMAGE MACRO


$,=qq.\n.;print q.\/\/____\/.,q./\ \ / / \\.,q.    /_/__.,q..
Happy, sober, smart: pick two.

Replies are listed 'Best First'.
Re^2: Perl Elitist Code vs Functional Code (test)
by tye (Sage) on Aug 13, 2012 at 01:59 UTC

    Frankly, it just sounds like you're doing it wrong.

    mandatory OO design and dependence on modules to perform even simple tasks

    I don't consider either of those to be best practices.

    you're an OOP elitist who spends the first 30 minutes of every script writing 50 lines of package infrastructure

    If it takes you 30 minutes or 50 lines to create boilerplate for a new class, then I think you are certainly doing it wrong.

    where everything should be verbose for the sake of clarity

    Verbosity doesn't lead to clarity. An obsessive devotion to terseness certainly is unlikely to lead to clarity, usually the opposite. But clarity doesn't require verbosity. And verbosity can certainly go far enough that it interferes with clarity.

    constantly have to type out the same one or two-line snippets to handle routine things

    That's the opposite of a best practice.

    I am not experienced enough to do this comfortably.

    Based on what you wrote above, I'd personally encourage you to ease off on worrying about OO, verbosity, and consistency and instead concentrate on trying to write unit tests. Not primarily for the sake of testing (though that will likely prove useful), but to help you see how to do practical abstraction.

    Code that can be unit tested well usually ends up being broken into logical subroutines, each with a unified and rather isolated purpose.

    I think you need to first concentrate on breaking code up into logical units and get more experience and skill at figuring out how to split code effectively, producing routines with small and clear interfaces and purposes that match their names.

    Once you start breaking code into subroutines with simple interfaces (which is called "modularity"), then you'll be able to wrap your head around moving some of those routines into a module.

    And if your code is well tested, then you'll build confidence in your ability to refactor things without breaking them.

    - tye        

Re^2: Perl Elitist Code vs Functional Code
by tobyink (Canon) on Aug 12, 2012 at 07:32 UTC

    Don't constantly retype boilerplate code. Wrap it in reusable functions. Here's an example for your status/error messages...

    package MyProject::Sugar::Catalyst; use Sub::Exporter -setup => { exports => [ error_msg => \&_build_error_message, ], groups => { default => [qw/ error_msg /], }, }; sub _build_error_message { my ($class, $name, $def) = @_; return sub { my ($c, %arg) = @_; my $uri = $arg{uri} || $def->{uri} or die "No URI supplied"; my $msg = $arg{msg} || $def->{msg} || 'Oh noes, ANOTHER FUCKING ERROR!!!'; $c->res->redirect( $c->uri_for($uri, { mid => $c->set_error_msg($msg) }) ); $c->detach(); } }

    An example of usage:

    package MyProject::Controller::Foobar; use MyProject::Sugar::Catalyst db_error_msg => { msg => "Database Error!" }, http_error_msg => { msg => "HTTP Error!" }, error_msg => { }; ...; sub foo_bar { ...; db_error_msg($c, uri => $uri); } sub foo_baz { ...; db_error_msg($c, uri => $uri, msg => "specific error message"); }

    It makes things easier in the long run.

    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

        Yes, closures are how Sub::Exporter works. Moose uses Sub::Exporter under the hood to export its has, extends, etc keywords. has, extends, etc are all closures. Catalyst is Moose-based. You use Catalyst; you're using closures.

        Catalyst is Plack-based. Plack is an implementation of the PSGI spec. Under PSGI all web apps are closures. You use Catalyst; you're using closures.

        perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re^2: Perl Elitist Code vs Functional Code
by Tux (Canon) on Aug 13, 2012 at 06:23 UTC

    You got a ++ from me for your honesty. With such (bad) styling practice, I bet it will be hard for you to fit in a team.

    Weather you need OO and/or modularization or not is not important when no-one can read your code. Consistency is WAY more important then the way you write code (imperative, OO, recursive, whatever).


    Enjoy, Have FUN! H.Merijn