Live data from Hacker News

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

seeinglogic.com

121–130 of 383 posts

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

#121
> there’s a better chance that the programmer forgets to properly handle all of the possibilities

Author totally forgot about IDEs. Yes, I know some coders frown upon IDEs and even color coding (like Rob Pike), but any modern code editor will shout loudly about an unhandled null-pointer check.

Also depends on the language, e.g. it's less reliable in Javascript and Python, but in static typed languages it's pretty obvious at no additional cognitive load.

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

#122

Maybe it's just me, but TypeScript makes code hard to read. It's fine if the data model is kept somewhat "atomic" and devs are diligent about actually declaring and documenting types (on my own projects, I'm super diligent about this). But once types start deriving from types using utility functions and then devs slack and fall back to type inference (because they skip an explicit type), it really starts to unravel b…

I'd prefer to have some type information over nothing if the choice were between TypeScript with some inferred return types, versus JavaScript where you're never really sure and constantly have to walk back up/down the stack and keep it in your mind.

I'd say on backend, my preference is statically something like C#. Statically typed but enough type flexibility to be interesting (tuples, anonymous types, inferred types, etc)

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

#123
post #115
post #109

> Chaining together map/reduce/filter and other functional programming constructs (lambdas, iterators, comprehensions) may be concise, but long/multiple chains hurt readability This is not at all implied by anything else in the article. This feels like a common "I'm unfamiliar with it so it's bad" gripe that the author just sneaked in. Once you become a little familiar with it, it's usually far easier to both read an…

authors_of_long_books = set() for book in books: if len(book.pages) > 1000: authors_of_long_books.add(book.author) return authors_of_long_books You are told explicitly at the beginning what the type of the result will be, you see that it's a single pass over books and that we're matching based on page count. There are no intermediate results to think about and no function call overhead. When you read it out loud it's…

fwiw, once Python's introduced there's the third option on the table, comprehensions, which will also be suggested by linters to avoid lambdas:

    authors_of_long_books: set[Author] = {book.author for book in books if book.page_count > 1000}
These are somewhat contentious as they can get overly complex, but for this case it should be small & clear enough for any Python programmer.

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

#124

Earlier quoted context omitted.

for the codebase i work on, i made a rule that "functions do what the name says and nothing else". this way if the function does too much, hopefully you feel dumb typing it and realize you should break it up.

Then what does the function that calls the split functions get called? foo_and_bar_and_qoo? And if they’re called only under some conditions?

I have definitely been guilty of naming functions foo_thenBarSometimes. I wince whenever I write them, but I've never really regretted seeing them later on, even after years. So sometimes it really is a perfectly good name. Sometimes there are two related functions that are often called together and don't have a succinct label for the combined operation.

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

#125

I've never understood the hate for variable shadowing. Maybe it's because I mostly use Rust, but I've always found it a useful boon for readability. You often want to extract/parse/wrap/package some value within the middle of a function in a manner that changes its type/form but not its semantic purpose. Shadowing the old value's variable name is brilliant: it communicates that there's a step-change in the responsibi…

> I've never understood the hate for variable shadowing. Maybe it's because I mostly use Rust,

That's likely a good chunk of it. My impression is it's more acceptable in languages where you have a very correctness-focused compiler, and `rustc` is that both with types and liveness/ownership. In a language where it's less clear when you copy values or hand out mutable references, or where implicit conversions occur on type mismatches, it's gonna be a different experience.

I think this article is best read as js/ts-specific advice, e.g. the split between null and undefined also isn't something you have to worry about in most other languages, and the semantics of various `?` and `?.` operators can vary a lot.

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

#126
post #102

Earlier quoted context omitted.

I think piping and method chaining are a little bit different. Piping generally chains functions, by passing the result of one call into the next (eg result is first argument to the next). Method chaining, like in Python, can't do this via syntax. Methods live on an object. Pipes work on any function, not just an object's methods (which can only chain to other object methods, not any function whose eg first argument…

Good to know. I assumed it was all done via objects or things like objects. So is piping more functional programming?

I think it's often a syntax convenience. For example, Polars and Pandas both have DataFrame.pipe(...) methods, that create the same effect. But it's a bit cumbersome to write.

Here's a comparison:

* Method chaining: `df.pipe(f1, a=1, b=2).pipe(f2, c=1)`

* Pipe syntax: `df |> f1(a=1, b=2) |> f2(c=1)`

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

#127
post #126

Earlier quoted context omitted.

Good to know. I assumed it was all done via objects or things like objects. So is piping more functional programming?

I think it's often a syntax convenience. For example, Polars and Pandas both have DataFrame.pipe(...) methods, that create the same effect. But it's a bit cumbersome to write. Here's a comparison: * Method chaining: `df.pipe(f1, a=1, b=2).pipe(f2, c=1)` * Pipe syntax: `df |> f1(a=1, b=2) |> f2(c=1)`

Ok, that’s helpful. Thanks!

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

#128
post #57
post #21

Towards the end he had an example of splitting a sequence of "graph.nodes(`node[name = ${name}]`).connected().nodes().not('.hidden').data('name');" adding variable between some of the . in there and claimed it was marginally less efficient. This is sometimes true, but if it ever is you need to talk to your tool vendors about a better optimizes. If you are working in a language without an optimizer than the marginal d…

I found this example troubling because once all the line noise is added, first-op second-op third-op fourth-op fifth-op sixth-op feels so much more impenetrable than - first-op - second-op - third-op - fourth-op - fifth-op - sixth-op The point of functional styles isn't purely brevity (as implied by the commentary around this example), it also puts a focus on the clear sequence of operations and helps reduce "operato…

IME what we want is generally for the code to be close to the left margin and flow predictably downwards. The example with intermediate values has a lot more value to me for complex instantiations, where we can avoid nesting like it's json or yaml by using some helper variables. That problem is fundamentally the same as with deeply nested if/while/try/etc: It gets hard to visually tell what's in which scope. (Rainbow indent guides help, but they're still mitigation for a situation that can be eliminated.)

But completely linear dot chains? They're fine.

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

#129
post #115

Earlier quoted context omitted.

authors_of_long_books = set() for book in books: if len(book.pages) > 1000: authors_of_long_books.add(book.author) return authors_of_long_books You are told explicitly at the beginning what the type of the result will be, you see that it's a single pass over books and that we're matching based on page count. There are no intermediate results to think about and no function call overhead. When you read it out loud it's…

fwiw, once Python's introduced there's the third option on the table, comprehensions, which will also be suggested by linters to avoid lambdas: authors_of_long_books: set[Author] = {book.author for book in books if book.page_count > 1000} These are somewhat contentious as they can get overly complex, but for this case it should be small & clear enough for any Python programmer.

Without syntax highlighting, "book.author for book in books if book.page_count > 1000" requires a lot more effort to parse because white space like newlines is not being used to separate things out.

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

#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.
Post reply on HN