Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic

Linear programming is bad

by Ovid (Cardinal)
on Mar 24, 2002 at 22:22 UTC ( #153951=perlmeditation: print w/replies, xml ) Need Help??

Many programmers (myself included), have a habit of presenting programs in a very linear style. The program reads straight through from top to bottom. I call this linear programming. While this is very easy to do, programs should not be written for ease of writing, but ease of reading. Consider the following example. This program is not bad. The variable names are generally chosen well. They are scoped properly, and repeated non-changing elements are turned into constants. I even pulled out a "magic number" (the number of fields per record) and made that into a constant.

Further, note that there are no comments in the program. You might think that this program does not need comments as it's only 32 lines long. Now, ask yourself what this program does.

#!/usr/bin/perl -w use strict; use constant EXPENSE_FILE => 'expense.dat'; use constant EXPENSE_REPORT => 'final_expense.txt'; use constant FIELDS_PER_RECORD => 4; use constant REPORT_HEADER => "Department,Total\n"; open IN_FILE, "<", EXPENSE_FILE or die "Cannot open ".EXPENSE_FILE." for reading: $!"; my @expenses = <IN_FILE>; close IN_FILE; my %deptTotals; foreach my $expense ( @expenses ) { my %record; my @fields = qw/ dept empID amount desc /; @record{ @fields } = split /,/, $expense, FIELDS_PER_RECORD; if ( ! exists $deptTotals{ $record{ dept } } ) { $deptTotals{ $record{ dept } } = 0; } $deptTotals{ $record{ dept } } += $record{ amount }; } open OUT_FILE, ">", EXPENSE_REPORT or die "Cannot open ".EXPENSE_REPORT." for writing: $!"; print OUT_FILE REPORT_HEADER; foreach my $dept ( sort keys %deptTotals ) { print OUT_FILE "$dept,$deptTotals{ $dept }\n"; } close OUT_FILE;

This is a very simple program. Your boss has come to you and told you that department expenses have been lumped in a CSV file and he wants a report summing total expenses per department. The above program is a quick, well-written tool that does exactly what your boss wants. However, it uses linear programming and if this is going to be used repeatedly, it's going to have to be maintained. This is a problem. Consider this alternative way to write this program:

#!/usr/bin/perl -w use strict; use constant EXPENSE_FILE => 'expense.dat'; use constant EXPENSE_REPORT => 'final_expense.txt'; use constant FIELDS_PER_RECORD => 4; use constant REPORT_HEADER => "Department,Total\n"; my $expenses = get_expense_data( EXPENSE_FILE ); my $deptTotals = sum_expenses_by_department($expenses, FIELDS_PER_ +RECORD); write_report( $deptTotals, EXPENSE_REPORT, REPORT_HEADER ); sub get_expense_data { my $file = shift; open IN_FILE, "<", $file or die "Cannot open $file for reading +: $!"; my @expenses = <IN_FILE>; close IN_FILE; return \@expenses; } sub sum_expenses_by_department { my ( $expenses, $fields_per_record ) = @_; my %deptTotals; foreach my $expense ( @$expenses ) { my %record; my @fields = qw/ dept empID amount desc /; @record{ @fields } = split /,/, $expense, $fields_per_reco +rd; if ( ! exists $deptTotals{ $record{ dept } } ) { $deptTotals{ $record{ dept } } = 0; } $deptTotals{ $record{ dept } } += $record{ amount }; } return \%deptTotals; } sub write_report { my ( $report_data, $file, $header ) = @_; open OUT_FILE, ">", $file or die "Cannot open $file for writin +g: $!"; print OUT_FILE $header; foreach ( sort keys %$report_data ) { print OUT_FILE "$dept,$report_data->{ $_ }\n"; } close OUT_FILE; }

Ugh! What the heck have I done? I took a simple, straightforward program, added three subroutines and several lines of code. Why the heck would I do something like that? What happened to laziness?

There are several benefits to breaking a program out like this. First of all, each function does precisely one thing and does it well. There is no ambiguity. If I realize that I am going to be doing a lot of work with multiple files like this, I could probably take my &get_expense_data and &write_report subroutines and stuff them into a module with absolutely no change (except perhaps the names). Further, rather than reading through the entire program to figure out what's going on, the maintenance programmer only needs to look at three lines of code:

my $expenses = get_expense_data( EXPENSE_FILE ); my $deptTotals = sum_expenses_by_department( $expenses, FIELDS_PER +_RECORD ); write_report( $deptTotals, EXPENSE_REPORT, REPORT_HEADER );

Remember what I said earlier about the program not having any comments? Well, when you break code up into a series of small, single-purpose functions, avoid "magic variables" (FIELDS_PER_RECORD), and carefully choose your variable names, programs often don't need many comments. You can simply read what you need and skip the rest.

Time passes...

You're no longer with the company and the boss comes in and says to the new programmer "Expenses are too high. I want you to change this program so that all expenses over $200.00 are not totalled, but reported to me in an error report for personal evaluation. Here's how the program might change:

use constant EXPENSE_FILE => 'expense.dat'; use constant EXPENSE_REPORT => 'final_expense.txt'; use constant FIELDS_PER_RECORD => 4; use constant REPORT_HEADER => "Department,Total\n"; use constant ERROR_REPORT => 'expense_error.txt'; use constant ERROR_HEADER => "Department,Employee,Total,Descr +iption\n"; use constant EXCESSIVE => 200; my $raw_expenses = get_expense_data( EXPENSE_FILE +); my ( $expenses, $largeExpenses ) = split_normal_from_excessive( $raw_expenses, EXCESSIVE ); my $deptTotals = sum_expenses_by_department($expenses, FIELDS_PER_ +RECORD); write_report( $deptTotals, EXPENSE_REPORT, REPORT_HEADER ); write_report( $large_expenses, ERROR_REPORT, ERROR_HEADER );

Note that in this change, we have added three constants and one function, &split_normal_from_excessive. How's that function implemented? Who cares? It's going to be fairly straightforward and, because everything has been modularized, we have less worry that it's going to impact anything else in the program. Further, we still have no comments, but it's easy to read. Also, because &write_report is a generic routine, It's been reused.

Linear programming is not always a bad thing. If you know you're doing a one-time data migration or need a quick data file analysis, it's not that big of a deal. If the program is going to be reused, though, it's better to take the time up front to break it out into a series of small, descriptive subroutines. It's much easier to read and extend and the poor maintenance programmer who comes behind you will breathe a sigh of relief.


Update: I think a big point to this node was kind of mentioned in passing: programs grow. I started programming in 1982 and have been programming for a living for about four years. If I had a dollar for every program that didn't experience "feature creep", I probably wouldn't have enough to buy my double tall half-caf flat tepid Irish cream latté :)

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: Linear programming is bad
by chromatic (Archbishop) on Mar 24, 2002 at 22:51 UTC
    I am certain Ovid knows this, but it's worth presenting a counterpoint. I have two rules for this situation:
    • Code should be as maintainable as possible at all points in the development cycle.
    • Code should do only what is absolutely necessary at the current state of the development cycle.
    By maintainable, I mean that the intent of the code is evident, there is no duplication, and the names of items and any comments are sufficient so that a decent programmer can fix bugs or add features.

    By absolutely necessary, I mean that there is no code that "might be used at some point in the future". If you don't need a feature now, don't pay for it yet. If you're writing an IRC client, don't add a web browser until it's absolutely necessary.

    The not-so-subtle difference is that I argue to put off taking advantage of the possibility of modularity until you actually need to re-use a function or an object elsewhere. It's hard to convince me to invest in something that doesn't have an immediate benefit.

      Your points seem to fit rather well with Extreme Programming ;-)

      I agree with you that unecessary features should be avoided. I also agree with you that code should be as maintainable as possible during all stages of development. What I disagree with you on is the priority of the two and how they interact.

      I would have broken Ovid's code down into subroutines like he did in the second example in his post. I find code in such a format is far easier to maintain and ultimately saves a lot of time. So if the modular version of the code is more maintainable, then in order to adopt its use, the benefits of increased maintainability should outweigh the costs of adding a 'feature.'

      Let's examine the costs then. There are three reasons why I avoid adding features that are not absolutely unecessary:

      1. It introduces more potential bugs and in doing so can greatly reduce the usability and security of the product.
      2. It wastes time and money for features that may not ever be used.
      3. It makes the codebase harder to maintain. This is especially important in open source projects where you want to attract developers. If your code is a bloated mess they're far less likely to get involved.

      If at the beginning of a project you decide to modularize the code, you will not be introducing any additional bugs. In addition, if modularity is put off until later, and then required, programmers may introduce new bugs during the transition.

      Number two may partially apply. It may take extra time to set up the program as modular (then again it may not), but this time is not spent on a wasted feature, it is spent on making the program more maintainable and reusable. Assuming you agree that modular code is more maintainable, number three gives the advantage to modularity as well.

      So you have to weigh a possible small price/time increase against greater long term maintainability. I find that I consistantly value maintainability enough to spend the extra time modularizing my code.

        There is a definite tradeoff, and it would be silly (or arrogant) for me to write an authoritative rule. Your point about adding modularity potentially introducing bugs is spot on correct. Of course, test freaks would suggest that unit tests will catch that. (Hopefully...)

        Besides the complexity concern, I hate to be stuck with a bad interface for backwards compatibility reasons. If you modularize too early, there are two yucky possibilities. Either your interface is too limited for the general uses and you'll have to rewrite code anyway, possibly creating bugs, or you'll have to write an overly generic interface, adding more complexity in the hopes that you'll catch all the ways you might want to call the function.

        In my experience, by the third time you use a piece of code, you'll know enough to write a good interface.

        Besides all that, the cleaner your code, the easier it will be to modularize. By the time I get over 100 lines, generally I'm writing functions anyway. There's a definite intuitive understanding that's not coming across in my posts very well...

Linear programming for linear programs?
by Petruchio (Vicar) on Mar 25, 2002 at 13:37 UTC

    It's always interesting when I see a good programmer espousing something with which I strongly disagree. More interesting, really, than reading things I agree with; it makes me consider my own position. Sometimes I wind up changing my opinion, sometimes the other fellow (or lass) does, and sometimes we come to recognize a fundamental difference in premises, which usually means we've come to understand the whole problem better. I ++ you for starting an argument, in the best Socratic sense of the word. :-)

    The practice you describe I have called 'storybook programming', and I have gone so far as to tell people to avoid it. Each subroutine is only called once, and the main part of the program consists in calling each of them in order. It's very much like a storybook with a table of contents and chapters:

    The Accountant and the Ledger

    1. Wherein our Hero gets the Expenses
    2. The Summing of the Expenses
    3. A Report is Written

    Chapter 1: Wherein our Hero gets the Expenses

    Once upon a time there was a little accountant named Irwin, who lived in a cubicle. One day the Lord High Fiduciary visited the cubicle, and asked Irwin to create a financial report. So Irwin opened up the Big Boring Book of Expenses, and...

    You get the idea. The chapters describe what happens, in the order in which it happens, and are mostly there to divide things up by topic. There's never a point in a storybook where it says, 'And Then he wrote another report... please go read Chapter 3 again.' And the chapter titles seem to describe what goes on in the chapters... which itself is a point of dread for me. Like comments, reading subroutine names is no substitute for reading code, particularly since things, as you've noted, tend to change over time.

    I find that novice programmers often think this way, and that, for the naive, it leads to a predictable set of problems which are not wholly unrelated to the point I'm trying to make to an experienced programmer.

    Because the subroutines describe the events in sequence, rather than the events which happen repeatedly, they'll often have redundancy... Irwin does the same thing in chapter 10 that he did in chapter 2, for instance. It's like unrolling a loop without a good reason; the result is awkward and unnatural.

    Another consequence of 'storybook programming' is that there is a strong temptation to use global variables. The novice understandst that Irwin needs to deal with @expenses in most of the chapters, so he simply deals with it directly.

    Soon someone tells him that he should be using strict, and so he does, and everything breaks, and he eventually solves the problem by turning the globals into package-scoped lexicals, which he declares at the beginning of the program, though he doesn't quite see why that was helpful.

    Then he's told that he should really be passing these variables along as parameters... and so he begins the tortuous task of passing the same 20 variables along to every subroutine in the program.. and if he's got any sort of intuition, he realizes his program is getting steadily worse, for having taken all this good advice.

    Now the problem, of course, is that the programmer is looking at the problem in a less-than-helpful fashion. Sure, he's divided up the task into parts... but those parts don't reflect the aspects of the problem which are important to him as a programmer. It's as if a surgeon-in-training were analyzing a human body by saying, "Well, there's a top half and a bottom half, certainly. And there's a left half and a right half... the body must have both of those, or it's not complete." These things are true, of course, but it's simply more useful to divide the body into functional units, such as organs.

    Likewise, a programmer would do well to recognize that when a single task, or closely related set of tasks, is done multiple times, it is a good candidate for being enshrined as a subroutine. It is my opinion that, most of the time, things which are done only once are better off not separated into subroutines... though I'm certainly not dogmatic on the point. I've seen cases where it seemed aesthetically sensible.

    But you're certainly not a novice programmer. One would expect you to have a pretty good idea as to how to structure a program... indeed, structuring programs is the point of your post. So what's the point of mine?

    Well, what you're doing strikes me as being something like premature optimization... guessing as what's going to be needed down the road. As you note, project requirements change, and features are added; and the thing that makes that a challenge is that you don't know what's coming. In making a 'naturally' linear program non-linear, you've made a guess at which tasks might need to be repeated.

    If things change, and you guessed correctly, all is well. On the other hand, what if the way you divided up the problem turns out not to reflect the nature of the new problem? For instance, say you have to accomplish tasks A, B, C and D once each. So you write a program that looks like this:

    w(); x(); sub w { A; B } sub x { C; D }

    Now, if the project changes, and you have to do A and B more than once, or C and D more than once, you're set. But perhaps task E gets added, and you need to do A to get ready for it. So you say:

    sub y { A; E }

    Now it seems A should have been a subroutine. And then it becomes necessary to perform D multiple times for each C... suddenly you're refactoring a problem that didn't need 'factored' in the first place. At this point, life would be easier if you had some linear code you could simply sequester into the subroutines which are now obviously appropriate.

    Now, this description is rather abstract, and I'll have to beg your pardon for not supplying concrete examples... at the moment, I'm pressed to finish this post and do other things. In light of real examples, I think several things would likely become clear. One of which is, there's a measure of common sense involved. I'm not suggesting that a programmer should strictly refrain from making reasonable guesses as to what has a high probability of being needed tomorrow. But I do think there's a danger in it and I think there are good reasons to prefer your original, simple program. In my opinion, the solution should fit the problem... and linear problems deserve linear solutions.

      petruchio had some good points and I love a rebuttal like this. It forces one to really dig into things. In the case of this post, any single good programming practice, when stripped of context and meaning, can become "cargo cult" programming. As a result, breaking things out like I have can be a bad thing if you don't understand other good programming practices. Thus, the objections that I see you raise become reasonable if the programmer doesn't understand the bigger picture.

      Another consequence of 'storybook programming' is that there is a strong temptation to use global variables. The novice understandst that Irwin needs to deal with @expenses in most of the chapters, so he simply deals with it directly.

      Global variables are not evil. They're just typically misused. Have you ever passed $x to &foo, which passed it to &bar, which in turn passed it to &baz? If the only purpose of passing $x to &foo was to let it get, untouched and unused, to &baz, then you can what's called "tramp data", which is just hanging around for the ride. It might be better to make that tramp data a global (with proper accessors, of course). Configuration information such as whether or not your program is running in debugging mode is often another reason to use globals. Globals are just misunderstood.

      Since you write that, in this style of programming, the programmer is tempted to make everything global, that's merely because they don't really understand programming and my little suggestion isn't going to help them, anyway. Further, your argument that the programmer is going to be passing 20 variables to every function just furthers my point: the person has bigger programming problems than just learning how to modularize things.

      It is my opinion that, most of the time, things which are done only once are better off not separated into subroutines... though I'm certainly not dogmatic on the point. I've seen cases where it seemed aesthetically sensible.

      It all depends upon why the new subroutine is being created. It can often be good to hide complex pieces of code this way. Do you want the following?

      if ( (defined $request and $request>0 and $request<2000) and $acco +unt_num=~/^[Gg]\d{3}-\w{5,6}+/) { ... }

      Code like that really shows up. We've all had it sooner or later. The programmer who maintains that will often just glance at it and say "I'll figure that out later if I need to". Now, what if I take those simple tests and move them into subroutines, but never reuse them? My code is still much easier to read:

      if ( expense_in_range($request) and is_expense_account($x) ) { ... } sub expense_in_range { my $expense = shift; return ( defined $expense and $expense > 0 and $expense < EXPENSE_ +LIMIT ) ? 1 : 0; } sub is_expense_account { my $account = shift; return $account =~ /^[Gg]\d{3}-\w{5,6}+/ ? 1 : 0; }

      Note how the code has grown considerably, but it is much easier to understand the intent of the conditional. These small, easy to understand subroutines are self-documenting as is (now) the if statement. Of course, complicated conditionals are just one example. There are plenty of areas where hiding the data or process is a good thing.

      Regarding your pseudo-code snippet:

      w(); x(); sub w { A; B } sub x { C; D }

      You wrote:

      Now, if the project changes, and you have to do A and B more than once, or C and D more than once, you're set. But perhaps task E gets added, and you need to do A to get ready for it...

      Just to make sure that I understand what you're saying, for function &w above, you have actions A and B. Now, if you later need to do E, but have A happen first (but not B), then you have to refactor something that was possibly poorly factored in the first place.

      In your example, this is correct. In fact, in the real world, this happens all the time. However, you have set up a bit of a straw man. The functions you describe are not cohesive. In function &w, as you describe it, B quite possibly requires A as a predecessor, but A does not necessarily require B as a successor. As a result, it probably should not have been grouped with it in the first place (though I admit that, in the real world, this is not always so obvious).

      I tend to hold with the idea that each function should do one thing and do it well. That "thing", though, may be hideously complicated. That's okay if we have something like this:

      function foo: A -> B -> C -> D -> E -> F

      In that simple little example that I made up, the arrow notation means that the left action requires that the right action succeed it, and the right action requires that the left action precede it. In the above example, what if we realized that, while E requires D for a predecessor, D does not require E as a successor? Then we have two functions:

      function foo: A -> B -> C -> D function bar: E -> F

      The trick, though, is to figure out how to call function bar. You clearly need foo first, though foo is not required to have bar following. There are various ways to approach that, but at least the functions are correct and they're probably cohesive.

      In my example in the parent node of this thread, each of the three functions is small and does pretty much one set of logically related activities (as per the notion of what I said above).

      To summarize, you raise excellent points. A programmer who doesn't know how to structure a program well may very well be worse off following my advice. But I wouldn't have people shy away from good practices because they don't know other good practices. They'll never learn good stuff! :) They have to learn to put things together as a coherent whole.


      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Re: Linear programming is bad
by andreychek (Parson) on Mar 25, 2002 at 00:30 UTC
    For just about every case, I would have to agree with Ovid's thoughts on this subject. Particularly his point in the following:

      Ugh! What the heck have I done? I took a simple, straightforward program, added three subroutines and several lines of code. Why the heck would I do something like that? What happened to laziness?

    This is a trick question, as it isn't actually laziness we're seeing here. Larry calls this false laziness! Laziness isn't about always trying to do the least amount of work now -- laziness is about having the correct program design so that we don't end up rewriting the whole thing every time you need to add or modify a feature. Laziness is about saving time in the long run, which possibly may require spending some extra time up front.

    The following is a direct quote from the Camel book, page 993:

    The quality that makes you go to great effort to reduce overall energy expenditure. It makes you write labor-saving programs that other people will find useful, and document what you wrote so you don't have to answer so many questions about it. Hence, the first great virtue of a programmer. Also hense, this book.

    I think Ovid does a fine job at expressing the intent of the Camel book, and more specifically, the 3 virtues of a good programmer, with his above thoughts. Two thumbs up!
Re: Linear programming is bad
by seattlejohn (Deacon) on Mar 24, 2002 at 22:59 UTC
    Good comments on programming style, but you might want to choose a name other than "linear programming", as that term was long ago adopted (with no negative connotations that I'm aware of) by the kind of folks who try to solve optimization problems. More info here if you really want to know.

      Aack! I just knew that was going to happen. It just seemed like the most straightforward description. I'm open for suggestions. A free, random ++ to the first monk to come up with a better name :)

      It bugs me because there is a better name and I know I've seen it somewhere; I just can't remember ... grr!


      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

        I'm open for suggestions. A free, random ++ to the first monk to come up with a better name :) It bugs me because there is a better name and I know I've seen it somewhere; I just can't remember ... grr!

        Imperative programming.


        Can't resist:
        • Concrete Programming. Because it lacks abstraction.
        • Ballistic Programming. You launch the interpreter on its way and it sails along a simple trajectory to the end (where there might be a big kaboom).
        • Linguini Code. Like spaghetti code, only not quite as messy.

        Now you all know why I don't do stand-up comedy for a living.

        I would suggest "straight-line programming", since I usually write like this when I want to go from point A to point B as quickly as possible. ;-)

        • non-procedural programming;
        • unstructured programming; 1
        • linear code
        • spaghetti code?


        1. which sort of steps on the definition of structured programming but is still pretty accurate.

        ___ -DA

        I've occasionally referred to it as "waterfall programming", since you start at the top of the code, and write straight down to the bottom. *shrug*

        "As information travels faster in the modern age, as our days are crawling by so slowly." -- DCFC


            It bugs me because there is a better name and I know I've seen it somewhere;
            I just can't remember ... grr!

        I recall a term Drop-through programming for what I think you mean with (Operational Analysis reserved word) "lineair" programming. A drop-through program is a program where the execution starts at the top of the file, drops through the code and stops at the end of the file (this is not to be named "top-down" which is also reserved allready).

        That makes sense I think - though english is not my native language. As soon as you introduce a subroutine you have to decide where to put it: on top? at the end? In the middle? Anyway somebody (the programmer or the language-programmer) has find a way to exclude it (this first subroutine) from the drop-through execution flow, so that it only gets executed when you want it executed.



        narrative programming?

        for its and-then-and-then-and-then structure.

        but then i was thinking, maybe just 'programming'? most things seem to start this way and only deserve special names later when their true nature is clearer. but then i am given to 'making it up as i go along programming' . perhaps some people know what they're building :(

        How about crow flight programming, as in "as the crow flies" ???

        Hmmm, maybe not.


        This would seem to be a slightly refined version of what I call "programming by typing".   You start at the top and take care of each thing as it comes up until you're done.   Perfectly good idea for programs less than, oh, say five lines.

Re: Linear programming is bad
by Stegalex (Chaplain) on Mar 25, 2002 at 14:00 UTC
    While nobody likes to write or read excessive storybook comments and while the structure of a storybook (or top-down) program is equally uninteresting and simplistic (perhaps it may be too verbose), my opinion is that these dull practices make it simpler for *other* people to maintain your code. *Other* people are not always as brilliant as you or I and they don't have the same knowledge of your code that you have. Since you may be hit by a bus someday, you owe it to your clients to employ these dull and sometimes patronizingly simple programming techniques. I like chicken.
Re: Linear programming is bad
by Buzz (Novice) on Mar 25, 2002 at 06:41 UTC
    linear programming... I think its called top down programming, or top down design. Or at least that's what I was taught in high school.
Re: Linear programming is bad
by Maclir (Curate) on Mar 25, 2002 at 16:28 UTC
    ++ Ovid. Us old COBOL programmers would structure our programs using what Petruchio calls "Storybook" programming (and, in COBOL, would have been just as verbose).

    The key is structuring the subroutines thougtfully, and to allow reuseability.

Re: Linear programming is bad
by muesli (Novice) on May 20, 2002 at 20:50 UTC
    I totally agree with this attitude and programming style. The biggest effect I like is that the purpose and algorithm of the code is clearly written, at the start, in the form of the procedure calls.

    But in reality, I can't remember thinking about this as an issue: I just automatically program like this - it wouldn't occur to me to do it another way, and I'd probably refuse to. Same thing with going on a larger scale and talking about OO programming or refactoring. I would never just write new functionality into an existing class that made no sense there. I just do it correctly at the beginning - say, creating two extra classes to implement orthogonal functionality. Same with documenting my work. As far as I'm concerned, the thing isn't done until it's documented.

    (This has gotten me into trouble with previous employers, who've said they have no time for comments or documentation. To me, though, it's part of the product.)

    I think that Ovid starts out with the right propositions (don't add functionality you don't need - features that might be handy in the future), but then draws a conclusion I disagree with: That this style of coding is a feature that's optional functionality.

    An auto engineering example:

    * XP Done right: You don't want to build 4 cigarette lighters into a car because we think some people might want to run 4 accessories at the same time, and therefore we ought to support that hypothetical case.

    But my whole point is that this isn't what we're talking about:

    * Analogy with proper coding/documenting: You do put in seatbelts in cars, although strictly speaking, you don't need them to get from point A to point B. Because, as professionals, that's just how cars are made.

    PS: In software, the end user is usually another programmer. If a programmer gave me long, or un-idiomatic code that's all one procedure and not documented, I'd give it back to them and say that their job isn't done yet. (And I have done this!)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://153951]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others imbibing at the Monastery: (5)
As of 2018-06-23 03:09 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (125 votes). Check out past polls.