Live data from Hacker News

What makes code hard to read: Visual patterns of complexity (2023)

seeinglogic.com

351–360 of 383 posts

Re: What makes code hard to read: Visual patterns of complexity (2023)

#351
post #130

This is interesting. Something I long wondered about Lisp code, was how having glyphs that are angled (parenthesis) without much indentation in many cases might be difficult to read just because of the visual aspects of it. ((( (( ( Takes some staring at to figure out what's what.

Lisp code is an AST. Once that's internalized, the parenthesis fade in the background. Mentally, instead of editing code, you're just arranging the branches. So, when reading, you can usually ignore whole sections as they will evaluate to a single value (side effects are possible, but strongly discouraged)

> side effects are ... strongly discouraged

This is simply a false generalization about a whole family that in its broadest interpretation includes completely different languages, most of them multi-paradigm.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#352
post #168

Earlier quoted context omitted.

Lisp code is an AST. Once that's internalized, the parenthesis fade in the background. Mentally, instead of editing code, you're just arranging the branches. So, when reading, you can usually ignore whole sections as they will evaluate to a single value (side effects are possible, but strongly discouraged)

Having 4 spaces as indentation helps people tease out where the branches even are in languages like C or Python or whatever, rather than the 1 or 2 that you see with a lot of Lisp. And those angled parents make lining things up vertically a teeny bit more difficult.

Two space indentation is fairly common in C code bases.

GNU projects use a kind of hybrid indentation where child statement are indented by two spaces, but if they are compound statements the indent their interior by another two spaces:

  if (proprietary(program))
    roll_on_floor_twitching(stallman);
  else
    {
      calm_down(stallman);
      make_indent_weirdly(stallman, everyone);
    }
Google’s style guides for various "C likes" also recommend two space tabs.

"Use only spaces, and indent 2 spaces at a time." [Google C++ Style Guide, https://google.github.io/styleguide/cppguide.html]

If you've been staring at Linux kernel code for weeks, with its 8 space tabs, and the edit two-space-tab code, it will take getting used to at first. The indentation will seem small. Soon, it will expand in your mind's eye and look large.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#353

Earlier quoted context omitted.

Your assumption that filter/map/reduce is necessarily slower than a carefully handcrafted loop is wrong, though. Rust supports these features as well and the performance is equivalent. Also countless real-world production environments run on Python, Ruby, JS etc, all of which are significantly slower than a compiled FP program using filter & map. > FP languages are dead-set on "immutability" which simply means creati…

> The compiler can make it mutable for better performance Well, we already know that no pure FP language can match the performance of a dirty normal imperative language, except for Common Lisp (which I am happy to hear an explanation for how it manages to be much faster than the rest, maybe it's due to the for loops?). And another comment here already mentioned how those "significantly slower" scripting languages hav…

You complain about not having control of how the `filter` works under the hood but are happy to give the language control over memory management. How much abstraction is too much abstraction? Where do you draw the line?

Re: What makes code hard to read: Visual patterns of complexity (2023)

#354
post #308

Earlier quoted context omitted.

Are you really confused when people don't think 3 operations constitutes "long"? I would guess anyone with half a brain would agree 3 operations is not long, maybe 5 or 6 and you will have many people agreeing, and above that most.

Here's an abomination of my own design in Rust for example: for (index, node) in nodes .expect("Error: No blocks for the Body") .children() .expect("Error: blocks node has no children") .nodes() .iter() .enumerate() { let block = Block::new(node, index); self.blocks.push(block); }

Why the for loop instead of mapping the enumerate iterator into Block::new and collect::Vec?

Re: What makes code hard to read: Visual patterns of complexity (2023)

#355

Earlier quoted context omitted.

> the only difference is whether or not it's hidden behind function calls you can't see and don't have access to. You "can't see and don't have access to" `if`, `range`, or `append` but somehow you don't find this a problem at all. I wonder why not? > You don't really think that functional languages aren't appending things, using temp vars, and using conditional logic behind the scenes, do you? By this metric all lan…

> by this metric False equivalence. You're saying that the statement "both for.. append and .map() executing the _same steps_ in the _same order_ are the same" is equivalent to saying that "two statements being composed of cmp,jmp, etc (in totally different ways) are the same" That is a dishonest argument. > Distinct could sort and look for consecutive, it could use a hashmap People love happy theories like this, but…

> It unconditionally uses a hashset regardless of input.

This follows what I like to call macro optimization. I don't care if a hash set is slightly slower for small inputs. Small inputs are negligibly fast anyway. The hash set solution just works for almost any dataset. Either it's too small to give a crap, midsized and hash set is best, or huge and hash set is still pretty much best.

That's why we default to the best time/space complexity. Once in a blue moon someone might have an obscure usecase where micro optimizing for small datasets makes sense somehow, for the vast majority of use cases this solution is best.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#356
post #78
post #42

Earlier quoted context omitted.

But who talked about bad architecture? Good readable code doesn't rule out good architecture. Surely some things are complicated but even then, a dev should be able to quickly see whats going on with minimal expertise in a codebase.

The broader problem is "cognitive load to understand the code I'm looking at." There are a variety of factors that lead enabling that. This is a very limited example. function isReadyToDoThing(Foo foo) { return foo.ready } function processStuff((Foo foo) { if isReadyToDoThing(foo) { res = workflowA(foo) res2 = workflowB(foo) return res && res2 } } This might be dumb, if isReadyToDoThing is trivial, and it could be ea…

If `isReadyToDoThing` is only used in one place, I'd argue that it's better to inline it with an appropriately-named variable so I don't have to "go to definition" to understand what it's doing.

I think people get too caught up in "small functions" and lose the readability of code locality.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#357
post #74

> To bring closure to the story at the beginning of this post, the codebase that was breaking my brain had several anti-patterns, specifically related to items 1, 2, 3, 6, and 8 in the list above. FYI: If you get into this situation in C#, the .editorconfig file and the "dotnet format" command are a godsend. I inherited a very large, and complicated C# codebase with a lot of "novice" code and inconsistent style. I sp…

This is a good idea, and I also enforce something similar in my projects. I credit Go for popularising gofmt, including strong defaults and little customisation. My main complaint is that gofmt doesn't break lines.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#358

Earlier quoted context omitted.

This comment seems unnecessarily mean-spirited... perhaps I just feel that way because I'm the person on the other end of it! I agree the code you have there is very readable, but it's not really an example of what that sentence you quoted is referencing... However I didn't spell out exactly what I meant, so please allow me to clarify. For me, roughly 5 calls in a chain is where things begin to become harder to read,…

Agreed — seeinglogic's article made me think of a 3rd option: 1. Sorta long functional chain where the type changes partway through 2. Use temp variables 3. (New option) Use comments (Here's funcA from seeinglogic's article, but I added 3 comments) function funcC(graph) { return // target node graph.nodes(`node[name = ${name}]`) // neighbor nodes .connected() .nodes() // visible names .not('.hidden') .data('name'); }…

Funny, I see the need to add comments as an indicator that it's time to introduce chunking of some sort--arguably it already has been.

In this case, I'd lean towards intermediate variables, but sometimes I'll use functions or methods to group things.

I prefer function/method/variable names over comments because the are actual first class parts of the code. In my experience, people are a bit more likely to update them when they stop being true. YMMV.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#359
post #168

Earlier quoted context omitted.

Having 4 spaces as indentation helps people tease out where the branches even are in languages like C or Python or whatever, rather than the 1 or 2 that you see with a lot of Lisp. And those angled parents make lining things up vertically a teeny bit more difficult.

Two space indentation is fairly common in C code bases. GNU projects use a kind of hybrid indentation where child statement are indented by two spaces, but if they are compound statements the indent their interior by another two spaces: if (proprietary(program)) roll_on_floor_twitching(stallman); else { calm_down(stallman); make_indent_weirdly(stallman, everyone); } Google’s style guides for various "C likes" also re…

Just because it's not uncommon doesn't mean it is not wrong, though!

And it's still easier to see in C code than something with a bunch of angly parenthesis.

Re: What makes code hard to read: Visual patterns of complexity (2023)

#360
post #219

Earlier quoted context omitted.

The dig on chains of map/reduce/filter was listed as a "Halstead Complexity Takeaway", and seemed to come out of the blue, unjustified by any of the points made about Halstead complexity. In fact in your later funcA vs. funcB example, funcB would seem to have higher Halstead complexity due to its additional variables (depending on whether they count as additional "operands" or not). In general, long chains of functio…

Just want to add that I both agree with you and parent. Your examples are readable and I see no issues there. It might be a language thing as well. In Python often people take list-comprehensions too far and it becomes an undecipherable mess of nested iterators, casts and lists. There are always exceptions :)

I read the OP as disliking the Python style, which I agree with.

However the GPs example of map filter distinct I find lovely.

Mind you, I learned to program is a functional language so I probably have a different perspective to most.

Post reply on HN