Live data from Hacker News

Simple Ways of Reducing the Cognitive Load in Code

chrismm.com

121–130 of 203 posts

Re: Simple Ways of Reducing the Cognitive Load in Code

#121

"Use names to convey purpose. Don't take advantage of language features to look cool." I can't say enough about this. Please write code that is easy to read and understand, not the most compact code, and not the most "decorated" code, or "pretty" code or neat because it uses that giant list expression or ridiculous map statement thats an entire paragraph long. Similarly what bugs me is when I receive a pull request w…

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…

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.

Re: Simple Ways of Reducing the Cognitive Load in Code

#122
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

State can be stored in instance variables as well, and should be if many small functions share them, it's what objects are for.

Re: Simple Ways of Reducing the Cognitive Load in Code

#124

Earlier quoted context omitted.

I completely disagree, every method can be split in private methods. In that way you don't need awful and unhelpful comments in the middle because you can understand what it does simply from the method name.

I've gone back and forth on this one over the years. My current advice would be that if you can find something that is naturally a sub-function, factor it out as one. Keep it private initially, but do not do this if that private function makes absolutely no sense on its own and your public code isn't calling it from more than one site. If you factor things out into sub-functions that have no semantic meaning on their…

Every method can be split sensibly. Using the functional paradigm it becomes natural to understand it because you usually work in the opposite way using composition of functions rather than dictating what happens in an imperative way. And large, complex functions do increase the cognitive load. I personally abhor regions or sections because most of the time they can go in a separate method and they just break the code-flow with something completely unrelated.

Re: Simple Ways of Reducing the Cognitive Load in Code

#125

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…

Perhaps an alternative would be

  valid_user = loggedIn() && hasRole(ROLE_ADMIN)
  if (valid_user) {
    valid_data = data != null && validate(data)
    if (valid_data) {
      ...
    }
  }

Re: Simple Ways of Reducing the Cognitive Load in Code

#126
post #98

Get a decent high level architecture, good, consistent database design and you don't write anywhere near as much application code. Start hacking about using one field for two purposes or having "special cases" and everything starts to get messy. These special one off cases will involve adding in more code at the application level increasing overall complexity. Repeat enough times and you will code a big ball of mud.…

>Start hacking about using one field for two purposes or having "special cases" and everything starts to get messy.

That advice is not as easy to put into practice as you make it sound. For instance, using one field for two purposes is often done to avoid special cases.

I think the eternal problem of software development is that both being more abstract and being more specific comes with a cost, and the middle ground is always shifting as requirements keep changing.

Re: Simple Ways of Reducing the Cognitive Load in Code

#127
post #73
post #26

Earlier quoted context omitted.

sorry, but given this pre-condition (from gp): > ... a large function cannot be broken up usefully, because a lot of state needs to be shared between the different parts ... there is no way to break that up with multiple smaller functions without stowing away the state somewhere. sometimes reading a large function is not half as bad as reading 10 different ones with each altering the shared state.

state can be passed through as arguments...

When coding in C, I often package the state that's shared between a high-level function and its local subroutines in a local "struct context" that's instantiated in the high-level function and then passed by address as the first argument to the subroutines. Makes it easy to see what the shared state is, and adding/changing the shared state doesn't require changing all the formal and actual argument lists.

Re: Simple Ways of Reducing the Cognitive Load in Code

#128
post #78

Earlier quoted context omitted.

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…

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.

Re: Simple Ways of Reducing the Cognitive Load in Code

#129
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…

If you're a .NET programmer, we've been doing that kind of stuff with LINQ for years; it's all over the place.

The only patterns that I still like to keep as old-style loops are constructs that ReSharper transforms into hairy-looking Aggregate() expressions

Re: Simple Ways of Reducing the Cognitive Load in Code

#130
post #40
post #31

Earlier quoted context omitted.

I recently got a code review that in several places suggested I switch to the new Java 8 stream API [1]. I just flatly responded that it was far less readable, even if I could condense a half-dozen lines of code down to one. Where I can quickly scan over a foreach loop to get the jist of what it's doing, I have to closely examine each call in the new approach to have any idea what it's doing. [1] http://www.oracle.co…

As someone who could very easily be on the other side of that code review (and I'm preeeettty sure I'm not in this case?) I feel obliged to at least try to provide a counterpoint :). So I agree that enormous blobs of unreadable crap are indeed unreadable, and that regardless of how neat and functional your code is, it can still be complete gibberish to most people. That being said, long chains of streams can be broke…

This is a place where local variable type inference really comes in handy for cutting down the noise of the type declarations.

  var descendingTransactionsByValue = comparing(Transaction::getValue).reversed();
  var groceries = transactions.filter(t -> t.getType() == Transaction.GROCERY);
  var sortedGroceries = groceries.sorted(descendingTransactionsByValue);
  var transactionids = sortedGroceries.map(Transaction::getId).collect(toList());
is much easier to understand
Post reply on HN