Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

The rule of thumb is put ifs and fors where they belong -- no higher or lower. And if you're not sure, think about a little more.

I don't think these rules are really that useful. I think this is a better variation: as you write ifs, fors and other control flow logic, consider why you're putting it where you are and whether you should move it to a higher or lower level. You want to think about the levels in terms of the responsibility each has. If you can't think of what the demarcations of responsibility are, or they are tangled, then think about it some more and see if you can clarify, simplify, or organize it better.

OK, that's not a simple rule of thumb, but at least you'll be writing code with some thought behind it.



This reply is akin to "just think about it and do it perfectly dummy" which might sound "obvious" and "smart" but is really just unhelpful commentary. The ideas provided in this blog are actually a good heuristic for improving code in general, even if they don't apply in all cases. Simple and practical rules of thumb can go a long way for those without enough experience yet to have internalized these kinds of rules.


I don't agree it is unhelpful commentary. I think it makes an important point that just following some rules you found won't be enough because the right answer isn't a result of something arbitrary/universal but is a side effect of a better understanding of the responsibility of each piece of code you're writing.


I think you’ll have better code on average if you always apply these rules than if you don’t.

It’s not always helpful to give people the option to do it as they think is best.


> than if you don’t

If by “don’t” you mean “do the opposite” then I agree. The third option is “don’t follow the rule blindly but think about the situation”, and for that case it depends entirely on the person and how well they think.


I do think it is shortsighted, and equally helpful and harmful. Helpful in that it reminds the reader this is only one of many considerations that should be taken into account. Harmful because it borders on implying that this shouldn't even be a consideration taken into account because it is irrelevant.


Trying to help too much, and give shortcuts to people who cannot otherwise evaluate when these shouldn't be applied has ill effects.

On the same note, I find the reasonning behind the advice way more interesting than the advice itself. It gives a good framing of the different issues to consider when writing conditional and iterative code.

Basically it should help newcomers to identify the issues they're facing and build their own personal heuristics.


A lot of replies in this tree read to me as "don't concisely express a general heuristic principle, because someone might read it and apply it without nuance".

This way of thinking is infantilizing. It is also self-defeating, because it is itself a failure to apply with nuance a general heuristic principle (don't oversimplify). It's doing what it tells you not to do.

Heuristics are only heuristics, but you have to articulate what they are before you can append "and this is only a heuristic, don't apply it blindly and universally".

Appending "everything depends on context" is the trivial part. The heuristics are the substantial contribution.


I see your side, but take it the other way: the basic message is really "you'll have to think for yourself anyway, heuristics from random strangers won't help", which I don't see as infantilizing.

I see post mortems and issue discussions on public projects as a better resource and contribution than sharing personal heuristics.


Better phrasing might be, this is a really good point, and while you can't rely on it alone, the more of these you learn, the better of a programmer you'll be.


Our job is to think about problems and solve them, I'm in completely agreement with GP


If you were going to generalize your hard-won knowledge and pass it on to a junior, what would you say?


"Draw the rest of the fucking owl"[1]

1: https://knowyourmeme.com/memes/how-to-draw-an-owl


There isn't an easy shortcut. Experts exist for reasons. Just like Doctors and other specialists, find a good expert you trust and evaluate their evaluation of the topic.


Doctors rely on an enormous number of heuristics and shortcuts exactly like this.

My wife teaches doctors, and so much of what she does is giving them rules of thumb much like this one.

edit: I want to note that I'm pretty ambivalent on the actual advice of the article, just commenting that doctors in my experience have a truly astounding collection of rules of thumb


An expert in a field tends to be an expert of the rules of thumb, the references to consult when the rule of thumb doesn't deliver the desired results, and the nuances and exceptions that are the art part of 'science and useful arts' for their field.


"Keep at it, it can be frustrating at times but if you keep studying and practicing how to become a better developer, you will become one"

There are no shortcuts in life. You need to work at it. Cognizant practice got me there, and I think it will get you there, too.

I get people asking me how to become a programmer all the time -- and I always say the same thing: You can't talk about it, you need to do it. You need to write programs, writing software will make you a better programmer.

Have opinions on how to write good software, be open about these opinions, but also be aware that they could be bad opinions, misinformed, or lacking greater context.


In reality these ‘rules of thumb’ become dogma and people forget why the rules of thumb existed in the first place, or make up other bullshit rules to justify it.

This industry is full of dogma and self-appointed experts and it’s utterly tedious.


Exactly -- write code that matches clear, intuitive, logical, coherent organization.

Because easy counterexamples to both of these rules are:

1) I'd much rather have a function check a condition in a single place, than have 20 places in the code which check the same condition before calling it -- the whole point of functions is to encapsulate repeated code to reduce bugs

2) I'd often much rather leave the loop to the calling code rather than put it inside a function, because in different parts of the code I'll want to loop over the items only to a certain point, or show a progress bar, or start from the middle, or whatever

Both of the "rules of thumb" in the article seem to be motivated by increasing performance by removing the overhead associated with calling a function. But one of the top "rules of thumb" in coding is to not prematurely optimize.

If you need to squeeze every bit of speed out of your code, then these might be good techniques to apply where needed (it especially depends on the language and interpreted vs. compiled). But these are not at all rules of thumb in general.


I think a key thing software engineers have to deal with opposed to physical engineers is an ever changing set of requirements.

Because of this we optimize for different trade-offs in our codebase. Some projects need it, and you see them dropping down to handwritten SIMD assembly for example.

But for the most of us the major concern is making changes, updates, and new features. Being able to come back and make changes again later for those ever changing requirements.

A bridge engineer is never going to build abstractions and redundencies on a bridge "just in case gravity changes in the future". They "drop down to assembly" for this and make assumptions that _would_ cause major problems later if things do change (they wont).

I guess my point is: optimizing code can mean multiple things. Some people want to carve out of marble - it lasts longer, but is harder to work with. Some people want to carve out of clay - its easier to change, but its not as durable.


I've been impressed watching the crews meticulously replace each cable assembly of the George Washington Bridge over the past year or so. All the work that doesn't require disconnected cables is done in parallel, so you can get a sense of the whole process just driving across once (they've finished the north side so you want to drive into Manhattan for the current view).

It's more or less the same as code migrations we're doing on a regular basis, done far more diligently.


Whether marble or clay, both ideally take into consideration the fact that he/she who write it today may not be he/she who maintains it tomorrow.

When stuck between longevity v less durable, maintainability should be the deciding factor.


Part of my point though was that the bridge builder of today does not need to take into consideration that the person maintaining it 20 years from now will have to deal with gravity changing. So they can make certain assumptions that will be impossible for future maintainers to ever undo.

Software doesn't have these set-in-stone never-changing requirements. I think we are making similar points.


1) I'd much rather have a function check a condition in a single place, than have 20 places in the code which check the same condition before calling it -- the whole point of functions is to encapsulate repeated code to reduce bugs

That's fine, but it's often a good idea to separate "do some work on a thing" and "maybe do work if we have a thing". Using the example in the article, it is sometimes useful to have multiple functions for those cases:

    fn frobnicate(walrus: Walrus) {
        ...
    }

    fn maybe_frobnicate(walrus: Option<Walrus>) {
        walrus.map(frobnicate)
    }
But also… in languages like Rust, most of the time that second one isn't needed because of things like Option::map.


I think the argument here could be stated sort of as push "type" ifs up, and "state" ifs down. If you're in rust you can do this more by representing state in the type (additionally helping to make incorrect states unrepresentable) and then storing your objects by type.

I have a feeling this guide is written for high performance, while it's true that premature optimization is the devil, I think following this sort of advice can prevent you from suffering a death from a thousand cuts.


A good rule of thumb is validate early and return early. Prevents endless if else nesting


Conditions inside the function are also in line with Postel's law, if we drag it from networking to API design. And in large parts of programming the entire "enforce it with types" (say null check without saying null check) isn't a thing at all. It only gets worse with languages where api evolution and compatibility is done by type-sniffing arguments. Those will just laugh at the idea of pushing an if up.

But it's an interesting discussion nonetheless. What I picked up, even if it wasn't directly mentioned (or I might have missed it?), is that a simple check on the caller side can be nice for the reader. Almost zero cost reading at the call site because the branch is a short one, and chances are the check provides some context that helps to understand what the call is all about:

   if(x is Walrus) frobnicate(x);
is not just control flow, it doubles as a friendly reminder that frobnication is that thing you do with Walrusses. So my takeaway is the check stays in the function (I also don't agree with the article), but make it a part of the naming consideration. Perhaps "frobnicateIfWalrus" wouldn't be so bad at all! I already do that occasionally, but perhaps it could happen more often?


> OK, that's not a simple rule of thumb, but at least you'll be writing code with some thought behind it.

This reflects one of my answers to the question: What separates an engineer from a developer?

Engineers are intentional, or at least hope to be as often as possible. On the other hand, developers may arrive at similar or same ends but they're generally more reactive and less intentional.


Yes, this advice has the scent of premature optimization with the tradeoff sacrifice being readability/traceability.


If you know where they belong, this post isn't for you.


You also want to avoid branches in loops for faster code. But there is a tradeoff between readability and optimization that needs to be understood.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: