Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How has your coding style changed over the years?

by stevieb (Canon)
on Aug 07, 2022 at 01:42 UTC ( [id://11145989]=perlmeditation: print w/replies, xml ) Need Help??

Since I started coding C and C++ in 2000, and Perl very shortly afterwards, my style hasn't fundamentally changed. If anything, I've simply become more pedantic about certain things. I'm bored so I thought I'd put a list together off the top of my head. What's your list look like?

- Four space tabs!

- I like no space between function parens:

function($param1, \%param2);

- I'm very much a K&R style person who likes 'else' type statements on their own line:

sub function { if ($_[0] == 1) { do_something(); } else { do_something_else(); } }

- When dereferencing a list, I always use whitespace:

my @list = keys %{ $href->{thing} };

- I always use the deref indicator where it is needed:

my $thing = $hash{one}->{two}; my $other = $href->{one};

- In my personal Perl code (60+ CPAN distributions), I always put the POD at the bottom of the file after all code (at $work, it's inline):

package Blah; ... 1; =head1 NAME Blah - The thing with the guy and the place ...

- I *ALWAYS* write unit tests before or at least during writing each function/method. I use the test scripts as test runs to prototype the code I'm writing instead of having a separate script. The test scripts are inherently part of the test suite. I also *ALWAYS* review my unit test suite for each piece of functionality and update it if necessary if patching/updating subs days, weeks or years later.

- I (almost) *ALWAYS* write POD documentation as I'm writing the code (rarely before, but sometimes I do that too).

- I frequently peruse the documentation of a random publication of my own software (regardless of language), and make fixes or produce relevant updates I may have missed.

- I use the same editor all the time (vi/Vim) when I don't have my IDE handy, intelliJ IDEA (with vim support, of course). (VSCode for some of my work projects).

- I rarely have to use the perl debugger, because I almost always find base issue cause through Data::Dumper statements. If I do use a debugger, it's more often for C code than it is for Perl code.

- One of my favourite topics for new development is writing code to help other developers (including me). Introspection and unit test software is a big thing for me.

- I love PPI, and am fluent enough with it that I rarely need to refer to the documentation when I want to use some of its functionality.

- For my Perl code, I strive with great effort to achieve 95%+ unit test coverage, and that coverage generally covers that 95% 16 ways from Sunday. I often write additional code just so that tests can test code it just cant cover. This includes special constants, env vars etc. Some of my software has complete routines as add-ons just to get a single statement covered that otherwise couldn't have been.

- I use Continuous Integration testing (CI) for almost everything. Mostly Github Actions (formerly Travis CI until they pissed me off tremendously), but some of my code can't run there, so I use my own Test::BrewBuild for such software.

- I used to, but not so much anymore, review CPAN latest releases to try to find bugs to fix, even if its just documentation.

- I am very specific about honouring other artist's copyright information. To further, I regard and honour the license of projects I've taken over from other authors. I'm a published author, poet, lyricist and music producer so the copyright thing in ingrained and imprinted. Appreciating other's art ownership isn't a desire to me, it's a core instinct.

- I am diligent in acknowledging contributors to my software. My Changes files and commits generally have the persons name and/or CVS username embedded.

- I take criticism very well; that said, I *ALWAYS* give credit where it is due, and *NEVER* claim credit for things I did not myself do

- I take bug/issue/feature requests very seriously, and do my utmost to respond in as timely a manner as I humanly can (sometimes I don't, but that's very rare).

- I use a bug tracker for almost everything I find myself; new features, real life bugs, security issues or even POD typos. If I'm perusing a random distribution of my own and I see a typo in the SYNOPSIS, I create a ticket for it.

- I never use shift in an OOP module, I always use my ($self, ...) = @_;

- I *ALWAYS* do parameter validation in each and every function/method.

- I use pure perl OOP; very, very rarely do I ever use any of the helpers. The only time that happens is if I'm requiring a distribution that has that required already.

- My POD format for subs is typically:

=head2 method($param) Contemplates the reason for life, using common sense as a modifier. my $explanation = My::Continuity->new; my $thing = 'Reason for living'; my $reasoning = $explanation->method($thing); I<Parameters>: $param I<Mandatory, String>: The explanation of the formation of humanity in +a single string. I<Return>: Hash reference, where each key is a continent, and its valu +e is a colour. C<croak>s on failure.

- I very sparsely use comments. Almost always my comments within code refer to *why* something is happening. It very rarely (if ever anymore) refer to 'what' is happening. The code says what is happening. Said comments when I make them are generally one to two lines only, and I use them only when I, myself will need to be reminded why in the fsck I did something so bizarre.

I'm sure I can add a hundred other particulars I've formed over the years, but that's a start. How about you?

Edit: Oh dear, I completely forgot. If it isn't blaringly obvious, Perl is my language of choice. Always has been, and I'm sure always will be. I'm decently fluent in C, C++, C#, wrote code in Python for four years as part of a job, can dabble my way through Javascript/JS, but I always lean back to Perl. Need an API for something (eg. Raspberry Pi)?, I'm making it available in Perl! New unofficial API for a new toy (eg. Tesla)? I'm ensuring it can be accessed with Perl! My priorities in life: My health, contentedness and happiness, my sobriety, my wife and children, Perl, everything else :)

Replies are listed 'Best First'.
Re: How has your coding style changed over the years?
by choroba (Cardinal) on Aug 07, 2022 at 21:45 UTC
    Nice! I've recently started documenting my style used in my personal projects, the document is not complete. Over the years, my style changed a lot. The main difference is I hated spaces when I was younger which makes most of my old code unreadable :-)

    Here's the document (converted from pod):

    Choroba's Perl Style

    Parentheses

    Omit parentheses in builtin functions where possible.

    print int rand $x;

    Sometimes, I add parentheses to keep parallel structures similar.

    return if substr($x, 0, 2) eq substr($y, 0, 2); # Second pair not ne +eded.

    For subroutines, almost always use parentheses. You can omit them when it creates a nice DSL-like effect:

    my $first = first { $x > 0 } @array; # List::Util

    I also don't write them after test assertions.

    is_deeply $response->{content}, bag(1 .. 10); # Test::Deep

    I don't write empty parentheses after method calls.

    $object->frobnicate;

    For m, s, and qr, I use / or m{} (resp. s{}{}, qr{}). I use qx{} for code and usually q() and qq() for lists. I use different types of brackets for qw depending on the semantics of the enclosed expression:

    use Exporter qw{ import }; # sub name my $from_roman = {qw{ I 1 II 2 III 3 IV 4 V 5 }}; my $primes = [qw[ 2 3 5 7 11 13 17 19 ]];

    Whitespace, indentation, aligning

    I use 4 spaces for indentation and spaces to align. No tabs at all.

    I use a space after control flow statements and before the opening curly bracket:

    while (my $item = $iter->next) {

    I use spaces inside parentheses when the parenthesised expression does something on its own, e.g. changes a variable value. I only do it after functions, though, not control flow statements.

    chomp( my @lines = <> );

    I don't put spaces after [ or { when indexing an array or hash with a simple index. I usually use spaces for complex indices (both around the operators and around the whole expression). I write spaces after commas.

    my $first = $array[0]; my $middle = $array[ $#array / 2 ];

    I don't add space after a bracket starting a list, unless it's a qw() list or dereference.

    my $arr = [1, 2, 3]; my @directions = qw( left right ); my @items = @{ $ref{items} };

    I cuddle elses and use the K&R style:

    if ($x > 0) { say 'Positive'; } elsif ($x < 0) { say 'Negative'; } else { say 'Zero'; }

    For lists, though, I use the List style for the closing bracket:

    my @planets = qw( Mercury Venus Earth Mars Jupiter Saturn Uranus Neptune );

    After a control flow command, I usually insert an empty line (unless the following line is a closing bracket).

    while ($x = $iter->next) { next if $x > $threshold; $x -= $correction; }

    If there is a longer sequence of the same commands, the inner empty lines might be omitted.

    return if $x > $threshold; return if $err || ! $success; return [] if $not_found; my $result = count($x);

    I use empty lines to separate code chunks semantically. In larger projects, I use two empty lines to separate subroutine definitons.

    Boolean operators

    I use ||, &&, and ! in expressions and and and or for control flow (which means I don't use not much).

    Implicit variable

    I usually don't type the $_ if not needed (i.e. map and grep blocks).

    my @normalised = map lc, @words;

    Expression forms of map and grep

    Expression forms of map and grep are OK. I switch to the block form when the expression can't be written without +().

    my %pairs = map { $_ => value($_) } @labels;

    I don't use map and grep in void context. That's why we have for (and I never spell it foreach).

    Semicolon

    I don't put a semicolon after the command that leaves the block.

    sub new { my ($class, $name) = @_; return bless { name => $name }, $class }

    It protects me from adding code below and wondering why it's never executed.

    Similarly, I don't put a semicolon after the 1 at the end of a module. Moreover, I usually spell it

    __PACKAGE__

    I also omit the semicolons in short one-line subs:

    sub second { $_[0][1] }

    I never put whitespace (including newline) before a semicolon.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: How has your coding style changed over the years?
by kcott (Archbishop) on Aug 07, 2022 at 05:54 UTC

    G'day stevieb,

    That's an extraordinarily similar list to what I might have written. :-)

    My coding style generally falls into two camps: what I write for myself, and what I write for $work. Over the years (close to 30 now for Perl) my style has changed: not in leaps and bounds, but just a slow progression of what I hope is general, incremental improvements.

    Given the similarity, I'll just go through your list and indicate what I do differently. Basically, if it's not mentioned, I do the same as you.

    • I don't add that extra white space when deferencing. Something of a moot point for personally coding: I'm more likely to write "keys $href->{thing}->%*" (not a lot of oppotunity for whitespace there).
    • I disagree that '->' is needed in '$hash{one}->{two}'. Of course, I can't see the underlying code but '$hash{one}{two}' would surely suffice.
    • I do have some standard tests which I get through module-starter (some are just ones I added to the template directory and install manually from there). I'm not a huge fan of TDD. I do write tests during development; usually after I've added a handful of related methods, but never before.
    • I don't use IDEs. I use vim for pretty much everything: possibly giving away my age when I think back to when vim was vi and my "monitor" was a roll of paper on the back of a teletypewriter console.
    • I don't use the debugger either. I prefer Data::Dump over Data::Dumper in most cases.
    • I don't use PPI; although, I am aware of it.
    • GitLab CI/CD for $work only.
    • Reading params with shift was something I did a lot, but not anymore. Too many instances of needing a extra param and changing "my $x = shift;" to "my ($x, $y) = shift;" — and that can be a surprisingly difficult bug to track down. Anyway, I've used "@_" pretty much exclusively since the early 2000s.
    • I would have written hundreds of modules using "pure perl OOP"; mostly for $work but also for personal code. I was very pleased when modules started to appear to shoulder some of the work. I used quite a few but mainly use Moose, and occasionally Moo, these days. I'm keeping my eye on Cor.

    ++ for a good post. It'll be interesting to see what others come up with.

    — Ken

Re: How has your coding style changed over the years?
by haj (Vicar) on Aug 07, 2022 at 16:16 UTC

    People are different, aren't they?

    Whenever I read old code I've written I find that my coding style seems to change continuously. Somewhat like the movement of an amoeba: I learn something (which isn't necessarily a new feature, but something I had not known), I like it and include it into my coding habits. Other habits die out, mostly because I don't need them for some time.

    At one point in time I broke with several habits at once, that was after working through Perl Best Practices. I am using this book's layout conventions until today, and configured my editor to help me doing so. I am not (and never was) religious about it: I can not claim a single *NEVER* nor *ALWAYS* rule for anything I've written.

    I guess this has to do with my personal history. I started working for mainframes, making small changes to huge amounts of code written by someone else. Being the beginner in the team, it seemed a good idea to keep the overall style. With Perl, my first job was to fix a broken CGI, again code written by someone else, I decided to keep its style. When I took part in the CPAN Pull Request Challenge, I found very different styles, and I found that all of them work.

    I used to start my OO methods with my $self = shift; because I saw others do this. I can not claim I'm doing it *ALWAYS*: I have adopted the habit to use subroutine signatures, and recently I use Object::Pad which predeclares $self. Over the years I have used plain bless-style OO, Moose (which I consider a game changer), and MooseX::Declare (until it became frowned at because of too much magic). Panta rhei.

    Habits I haven't changed in the last decades: I use Emacs, and I like the Perl debugger. Occasionally I work to improve these tools.

      > I am not (and never was) religious about it:

      I mostly agree with you, I have to adapt to the style of my client.

      As a funny side effect, we can mostly tell who made a change just by looking at the style.

      Like one of my colleagues prefers qq~...~ for multi-line SQL and I always use heredocs like <<"__SQL__";

      > and configured my editor to help me doing so

      could you please share your settings? I find configuring layout settings quite tedious and frustrating, because the cross-influences make it a try and error game.

      More so if perltidy is also involved and I can see my code flip-flop-ing between different settings. And also configuring perltidy is no fun...

      In the end I stopped using perltidy and configured my emacs to auto-indent the surrounding expression/block with every typed semicolon.

      Like that I get life formatting without needing to think (and it's much faster than shelling out to a restarted perltidy)

      But of course this isn't as feature rich as perltidy, so I'd like to become "compatible" no matter which style.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        could you please share your settings?

        Sure! If you are using the "current" cperl-mode.el from git, you can do:

        • Interactively: <M-x>cperl-set-style<RET>PBP<RET>
        • In your Emacs config: (cperl-set-style "PBP")
        • As customize option, file- or directory variable (which makes sense if you have different projects with different style requirements): Set cperl-file-style to "PBP"

        For older versions of cperl-mode.el, here's the list of settings:

        ("PBP" ;; Perl Best Practices by Damian Conway (cperl-indent-level . 4) (cperl-brace-offset . 0) (cperl-continued-brace-offset . 0) (cperl-label-offset . -2) (cperl-continued-statement-offset . 4) (cperl-close-paren-offset . -4) (cperl-extra-newline-before-brace . nil) (cperl-extra-newline-before-brace-multiline . nil) (cperl-merge-trailing-else . nil) (cperl-indent-parens-as-block . t) (cperl-tab-always-indent . t))
        In the end I stopped using perltidy

        That reminds me of an issue "A command to run perltidy with the input from an emacs buffer" for which a first implementation never made it to Emacs....

Re: How has your coding style changed over the years?
by roho (Bishop) on Aug 08, 2022 at 04:44 UTC
    The biggest change for me, coming from a COBOL background in the 70's and 80's, is to declare variables where they are used instead of declaring all variables near the top, as COBOL requires. My early Perl programs in the 90's have all variables declared near the top, which can be problematic, especially when tracking down "errors at a distance".

    "It's not how hard you work, it's how much you get done."

Re: How has your coding style changed over the years?
by Discipulus (Canon) on Aug 08, 2022 at 10:22 UTC
    very nice read and thread my friend!

    My coding style changed a lot because Perl was and still is my only programming language and I started horribly :)

    Notably:

    • I switched from &my_sub(..) to my_sub(..) where I used & to highlight my own subs defined in the current program. I was bored to receive perl4 accusation :) and "you should be aware of.." YES I'M AWARE! :)

    • in quick hacks (I still do a lot of quickies) I just like to have decent style

    • probably biggest change was not in style but in preparation: if I plan something that can be a module then I think about it more hours than before before coding, trying to highlight eventual critical points before coding. I have been burned by my own Game::Term where I missed completely the right implementation of my idea and now I have no more will to rewrite it..

    • if a module, then I write tests, documentation and code in parallel and I use gitlab or github, with a bit of pain but rewarding effort!

    • I always put POD after __DATA__

    • I comment complex code but mainly for my lack of memory after a short while

    • I generally put all subs at the end of the file, sometimes separated by long ##### lines

    • I close braces at the indentation level where I open them, and I like spaces with parens:

      foreach my $it ( @eles ){ foreach my $part ( split '|', $it ){ ....; } }
    • sometimes I align nested parens in another way, adding newlines too (see below example wher GetOptions parens follow this style, dfferently from unless parens)

    • I align hashes and the alike only for my own eyes plesure and because a program should be beutiful
      unless ( GetOptions ( 'url=s' => \$url, 'agent=s' => \$agent, 'extraparts|cache=i' => \$cache_size, 'debug=i' => \$debug, + ); ) { die "$0 -url URL [-agent STRING -extraparts N -debug [0-2]]" }
    • I use as above short blocks in one line style.

    • I put a blank line where my eyes need it, after complex blocks or deep indentation end

    • I put attention to variable names, more if they spread all over the program. A speaking long name is not a problem if you have autocomplation. This can be verbose using Tk where if I have a part of the program managing Sierpinski fractals I have vars named: $input_sie $color_sie $title_sie $label_sie $hint_sie or $jpeg_quality_ent for the entry field

      L*
    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: How has your coding style changed over the years?
by eyepopslikeamosquito (Archbishop) on Aug 07, 2022 at 12:38 UTC
Re: How has your coding style changed over the years?
by hippo (Bishop) on Aug 07, 2022 at 12:21 UTC

    Yes, a lot of your patterns here are the same with me. These are the differences:

    • I do like a space between the function name and the opening bracket - I find it aids eye-parsing. This is so ingrained now that it irks me when some SQL dialects prohibit it.
    • Cuddled elses and elsifs for me. The alternatives just waste vertical space.
    • No whitespace when dereferencing.
    • I have only just recently started the "all POD at the end" technique and while I can see the benefit it in terms of compilation efficiency I'm still not sure it's better from a dev point of view. Ask me in another 5 years. :-)
    • I use the same editor all the time (vim) because it is my IDE.
    • I've only used PPI very rarely but that's likely more of a domain-related thing.
    • I should use a bug tracker for everything. Habit instead results in a lot of small .txt files littering the place. Or worse, handwritten notes on the backs of envelopes.
    • Parameter/argument validation is only done where the programmer deems it necessary/beneficial.
    • I used to use pure perl OOP almost exclusively. Recently however, Class::Tiny has been beneficial in some situations in removing a lot of boilerplate. Might be worth a look for you too?

    Over the years I have taken on board a lot of what are widely regarded as Best Practices. There are one or two exceptions which I still cling to:

    • Don't use /x as a regex modifier willy-nilly, only when there is a real benefit. (similarly for other modifiers but I see a lot of occasions where x is used as a habit and actually has no bearing on the regex at all)
    • Exporting symbols by default is OK. If people don't want their namespaces polluted there are easy ways to avoid it in the importing code.
    • Implicit returns are fine, especially for subs expected to run in void context. Same for explicit return undef.
    • Postfix dereference is just annoying. It's like a surprise twist at the end. Fine in a novel, not in code.

    🦛

Re: How has your coding style changed over the years?
by hda (Chaplain) on Aug 07, 2022 at 17:05 UTC
    I am pretty much on the same page as the OP and others, but I have a fondness for this type of indentation:
    foo { some code line; foo { some code line; some code line; } }
    which I find it useful for tracking nested structures and more visually pleasing than the pure K&R. Indentation is four spaces.

    I also use a final semicolon in the last line within curly brackets even when that is not strictly necessary. In that way I do not need to think about the last semicolon when doing tests or adjustments in the code.

    TIMTOWTDI :-)
Re: How has your coding style changed over the years?
by Tux (Canon) on Aug 07, 2022 at 15:07 UTC

    The only things I can come up for things that changed over the past 40+ years:

    • sub foo {
      

      instead of

      sub foo
      {
      

      where the old style was mainly used because it made vi happy on the { and } navigation keys

    • Indentaion 6 to 4 spaces. That was when I stopped using Pascal and Basic

    I know many will NOT agree with my style, but at least I am very consistent. *AND* I have an explanation for every guide I follow, which I cannot say for people leaving school and just follow the basic rules of their IDE.

    Anyway, not having a space between the function name and the opening paren is a reasong for me to not use the language at all.

    I've summed it all up on my style guide. I will not accept PR's that do not strictly follow that guide.

    Whatever style you follow, do so consistently, otherwise maint will be a nightmare.

    Oh, and I do care a single *** about leading tabs or spaces even if you mix them. I don't see them. My editor does the right thing.


    Enjoy, Have FUN! H.Merijn
      *AND* I have an explanation for every guide I follow

      This is the compelling statement for me. I'm sure most of the (in my view) nasty coding practices prevalent now are simply because "that's the way I was taught" or, even worse, "I never thought about it".

      My primary guide is "format it like prose" - which speaks mostly to horizontal white space usage and use of blank lines to group blocks of related lines (paragraphs). A secondary guide is that stuff at the start of a line is much more important than stuff at the end of a line - which speaks to how "long" lines get wrapped and to what constitutes "long".

      I use K&R for Perl because "everyone" does, but I can't think of any justification for it. Elsewhere (mostly C++) I indent curlies to the same level as the rest of the block they are part of. My justification is that a curly wrapped block of statements is semantically the same as a single statement and should be indented the same. In my mind the curlies are part of the block so ...

      Would anyone care to suggest why K&R is compelling?"

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        I use 1TBS which is close to (or perhaps even what you were meaning by) K&R. It (opinion!) makes maximum use of space without sacrificing clarity and in my mind the end of a block statement being at the same indentation as the start of that statement makes perfect sense.

        Elsewhere (mostly C++) I indent curlies to the same level as the rest of the block they are part of.

        If you were to do the same in Perl would you write like this?

        sub foo { my @args = @_; unless (scalar @args) { warn "No args in foo!"; return; } return join ':', @args; }

        That is (or looks like) full Whitesmiths which I have seen on occasion in some Perl code but it just messes with my head. It also seems to go against this comment in perlstyle:

        Regarding aesthetics of code lay out, about the only thing Larry cares strongly about is that the closing curly bracket of a multi-line BLOCK should line up with the keyword that started the construct. Beyond that, he has other preferences that aren't so strong ...

        I am happy to adhere to Larry's wishes on this one.


        🦛

      > Oh, and I do care a single * about leading tabs or spaces even if you mix them. I don't see them. My editor does the right thing

      If someone is using an indentation different to 4 you'll get ugly results. (That's actually a running gag in code sections posted here, because browsers still default to tab=8)

      The only right thing your editor can do is reindenting all the code, which will result in a full diff when checking into version control.

      And even with indent 4 calling untabify (or whatever it's called in vim) will cause unwanted diffs.

      My strategy is to commit the untabified version first. But doing this everytime a colleague touched the file might get annoying.

      So this question is of relevance when working in a team, IMHO. (And yes certainly YMMV)

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        (That's actually a running gag in code sections posted here, because browsers still default to tab=8)

        this seems to have been fixed in the CSS or at least for Chrome

        for my $x (@a) { print; # 1 tab print; # 4 blanks }
Re: How has your coding style changed over the years?
by LanX (Saint) on Aug 13, 2022 at 18:39 UTC

    > - I *ALWAYS* write unit tests before or at least during writing each function/method. I use the test scripts as test runs to prototype the code I'm writing instead of having a separate script. The test scripts are inherently part of the test suite. I also *ALWAYS* review my unit test suite for each piece of functionality and update it if necessary if patching/updating subs days, weeks or years later.

    Could you please elaborate a bit more?

    does it mean you start every project with something like Module::Starter and populate the /t dir first? Even for a simple script.pl ?

    I often don't have a clear goal and am prototyping different approaches in experimental scripts in an /exp directory. And these scripts are internally littered with tests to proof the concepts.

    I find jumping between two files for testing and dev cumbersome at first, but refactoring these POCs into distinct code and test parts is cumbersome too.

    So I'd be interested to know in detail how you do this.

    I have the impression that what I keep in /exp already starts its life in your /t and once you are happy you just copy the implementation to the main module?

    Is that it?

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    Wikisyntax for the Monastery

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://11145989]
Approved by Athanasius
Front-paged by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (6)
As of 2024-04-19 16:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found