Live data from Hacker News

Simple Ways of Reducing the Cognitive Load in Code

chrismm.com

191–200 of 203 posts

Re: Simple Ways of Reducing the Cognitive Load in Code

#191
post #121

Earlier quoted context omitted.

I think people underestimate the cost of vertical length. It's less obvious in small examples, but there's a huge difference in readability between a class or function that fits on one page and one that doesn't, so it's well worth making individual lines a bit less readable if it means you need less of them.

> so it's well worth making individual lines a bit less readable if it means you need less of them What does it mean?

Making individual lines a bit less readable is well worth it if making individual lines a bit less readable means you need less of them. ("Worth it" is a construct I don't really understand the grammar of - I'm a native English speaker)

Re: Simple Ways of Reducing the Cognitive Load in Code

#192
post #4

I really like the advice from "Perl Best Practices" to code in paragraphs. Sometimes, a large function cannot be broken up usefully, because a lot of state needs to be shared between the different parts, or because the parts don't have a meaning outside of the very specific algorithm. In that case, code in paragraphs: Split the function body into multiple steps, put a blank line between these and, most importantly, a…

Situations like this are exactly where nested functions can be helpful. I've always thought that it was a shame that C didn't have them. Sometimes I almost wish that Algol flavored languages like Pascal anf Modula 2 would have won out for systems programming, instead of C and the languages it inspired. Actually, GNU C supports nested functions, and a new round if standardization is just starting up, so maybe there's…

> Situations like this are exactly where nested functions can be helpful.

Indeed. When I'm writing Haskell, I'm using a lot of nested functions in `where` blocks, sometimes cascaded down.

Re: Simple Ways of Reducing the Cognitive Load in Code

#193
post #78

Earlier quoted context omitted.

In languages where braces define a scope even if there's no if, for, etc. keyword around, you can get a lightweight version of that just by sticking braces around your "paragraphs", as needed. They aren't the same as nested functions, in particular because you can't invoke a naked block multiple times, but if you've got a long function that hasn't got any useful break points in it, but you just want to chunk things,…

The thing is, naked scope blocks are missing the main reason I'd use a nested function: the ability to be named. I do occasionally use scope blocks when I want to constrain the scope of one or more local variables, and there isn't an otherwise appropriate scope already created by a flow control construct.

I also use naked scope blocks sometimes. To me, their main purpose is to make temporary variables go out of scope, to clarify which variables are still intentionally live beyond the block.

Re: Simple Ways of Reducing the Cognitive Load in Code

#194
post #73

Earlier quoted context omitted.

state can be passed through as arguments...

Sure, but then there are more questions :) e.g. how many parameters ? 3, 4 ... ? what if they are of the same type ? would you change your numbers then ? users can get the order wrong etc. another thing : if you pass too many parameters, isn't that a hint to the fact that something is amiss ? edit-1 : fixed typo

Remember this is in the case of spiting out smaller functions to improve readability.

Variable naming will only add to that, as you can rename variables in the extracted methods for their local purpose.

If you have too many arguments you can package them up in a object/map/tuple of your choosing (depending on language).

(Reverting to local state would in my opinion increase confusion and decrease readability.)

Re: Simple Ways of Reducing the Cognitive Load in Code

#195

My current pet-peeve: - If your code deals with values where the units of measure are especially important and where they may change for the same type of value in different contexts, PUT THE UNITS USED IN THE VARIABLE NAME! I work primarily with systems that talk money values to other systems, some of which need values in decimal dollars (10.00 is $10.00) and some that need values in integer cents (1000 is $10.00). T…

Or put the units in the type system: https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual...

Re: Simple Ways of Reducing the Cognitive Load in Code

#196
post #80

Earlier quoted context omitted.

Stream based programming is a paradigm that with some training and proper code indentation is much , much faster to read than a nested for loop. Once you get used to it,you can literally fast-scan code written in this style with the confidence that you are not missing anything. Also, assuming you do not use mutable state, it also has the advantage of being easily parallelizable without any code changes. (As well, as…

"Stream-based code is certainly not something you can read off the cuff." List transactionsIds = transactions.stream() .filter(t -> t.getType() == Transaction.GROCERY) .sorted(comparing(Transaction::getValue).reversed()) .map(Transaction::getId) .collect(toList()); I honestly think most programmers fluent in Java 7 programming, can guess this is finding "grocery" type transactions, sorting by "value" transaction prop…

Err..yes, Java 8's filter, sort, map and collect are the most basic stream operators and you are correct that even folks un-used to this style can determine an understanding. But in code that uses observable stream-based programming you nearly always use more complicated operators like flatMap, merge, skipWhile, takeUntil, combineLatest etc. Without spending time learning these operators and how streams work, one is always going to scratch one's head. (Unless you possess an FP background)

Even in Java 8 plain streams, the Collector is a powerful paradigm for grouping operations with a large amount of variations and it takes (at-least it did for me) some involved time learning how to effectively leverage this in day to day code.

Re: Simple Ways of Reducing the Cognitive Load in Code

#197
post #96

Earlier quoted context omitted.

Using intermediate variables is one of the most underrated tools to make code more understandable. It's the definition of something completely unnecessary from a technical standpoint that is all about conveying meaning and clarity to other programmers. And it can be used to help group and "modularize" chunks of code within a routine without necessarily going to the extreme of pulling out a separate subroutine, which…

Agreed about using intermediate variables. What's better than comments to describe what the code does? CODE that describes what the code does. (Let the code describe WHAT the code does, and if necessary, the comments describe WHY the code does it like that.) In C++, if I use an intermediate variable to decompose a complicated expression into easier-to-understand sub-expressions, I like to make the intermediate variab…

I hear this a lot, often in the for "Good code doesn't need comments", but I'm more than a little skeptical of this view.

I need actual examples to get on board, and not just the usual "idiot" programmer strawmen - actual examples that aren't obviously unreasonable.

My main reason for skepticism - Full, proper English sentences are capable of a lot more nuance, and precise semantics than whatever the programming-language syntax might support. I agree code can be written with more clarity, but it cannot substitute actual text, i.e. Code is not documentation.

Re: Simple Ways of Reducing the Cognitive Load in Code

#198
post #161

His second example to "modularize" a branch condition is not functionally equivalent in _most_ in-use programming languages: valid_user = loggedIn() && hasRole(ROLE_ADMIN) valid_data = data != null && validate(data) if (valid_user && valid_data) … Is not equivalent to: if (loggedIn() && hasRole(ROLE_ADMIN) && data != null && validate(data)) … His version will always execute `validate(…)` if `data` is not null regardl…

If validate() doesn't have a side effect then the short-circuiting doesn't matter. The micro-optimization of skipping the validation for performance reasons is premature optimization. If the performance optimization is necessary it should be stated more explicitly in the code then just being hidden being a && short circuit I've always thought this kind of short-circuiting as an implementation detail of the runtime th…

Allowing the extra constraint "doesn't have a side effect" is more dangerous than clarity in this case because it increases what a dev needs to know to modify the code, and allows for a bug to easily be introduced if the validate code is modified to have side-effects.

And though a test might be added to check for this, "Was this function run" is easier to determine than "Does this function have side-effects".

Re: Simple Ways of Reducing the Cognitive Load in Code

#199
post #161

Earlier quoted context omitted.

If validate() doesn't have a side effect then the short-circuiting doesn't matter. The micro-optimization of skipping the validation for performance reasons is premature optimization. If the performance optimization is necessary it should be stated more explicitly in the code then just being hidden being a && short circuit I've always thought this kind of short-circuiting as an implementation detail of the runtime th…

Allowing the extra constraint "doesn't have a side effect" is more dangerous than clarity in this case because it increases what a dev needs to know to modify the code, and allows for a bug to easily be introduced if the validate code is modified to have side-effects. And though a test might be added to check for this, "Was this function run" is easier to determine than "Does this function have side-effects".

That's why all your functions should not have a side effect if at all possible. And if they do it should be stated in the function's name. Maybe something like validateAndLogIt().

Re: Simple Ways of Reducing the Cognitive Load in Code

#200

His second example to "modularize" a branch condition is not functionally equivalent in _most_ in-use programming languages: valid_user = loggedIn() && hasRole(ROLE_ADMIN) valid_data = data != null && validate(data) if (valid_user && valid_data) … Is not equivalent to: if (loggedIn() && hasRole(ROLE_ADMIN) && data != null && validate(data)) … His version will always execute `validate(…)` if `data` is not null regardl…

And why not just make it clear that valid_data depends on valid_user?

    valid_user = loggedIn() && hasRole(ROLE_ADMIN)
    valid_data = valid_user && data != null && validate(data)

    if (valid_user && valid_data) …
I think this makes it clear that valid_data has a dependency on valid_user that was being hidden in the previous version, which we're now making clear. It will look a bit weird, but I think that's a positive because it draws attention to the fact that the short-circuiting is required and that double-look coupled with a short comment will make everything much more readable. The previous version does not convey as much meaning, in my opinion.

    if (loggedIn() && hasRole(ROLE_ADMIN) &&
        data != null && validate(data)) …
Post reply on HN