Live data from Hacker News

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

seeinglogic.com

221–230 of 383 posts

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

#221

Earlier quoted context omitted.

> Nope, pure functions are referentially transparent. The key idea is that you can replace the function invocation with a value and it shouldn’t change the program. [Edit: This is wrong: And idempotent.] Generally you can expect that you can call them as many times as you like and get the exact same result. It _feels_ very safe. > This isn't just a Haskell thing though. I'll write code this way in C# (and have built…

That's not what idempotent means. Idempotent means forall x, f(x)=f(f(x)). Most pure functions are not idempotent. Heck, f(f(x)) doesn't even type-check for most f. The typical name given to always getting the same results is just "pure". It doesn't depend on any implicit state anywhere.

Right you are. I wish I had an excuse for my mistake, but I don't.

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

#223
post #157
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…

SELECT DISTINCT author FROM books WHERE pageCount > 1000;

This is 5 times more readable than FP example above for the same computation. The FP example uses variable book(s) five times, where using it once was sufficient for SQL. Perhaps FP languages could have learned something from SQL...

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

#224
post #61

My pet peeve: function getOddness4(n: number): if (n % 2 === 0): return "Even"; return "Odd"; While it is shorter, I prefer vastly prefer this one: function getOddness2(n: number): if (n % 2 === 0): return "Even"; else: return "Odd"; Reason: getOddness4 gives some sense of asymmetry, whereas "Even" and "Odd" are symmetric choices. getOddness2 is in that respect straightforward.

90% of the time I prefer the first. I am allergic to indentation and I hate anything remotely like:

    function foo(a) {
        if (a) {
            return doThing()
        } else {
            return Error();
        }
    }
I like all of my assertion and predicate guards nicely at the top of a function:

    function foo(a) {
        if (!a) {
            return Error()
        } 

        return doThing()
    }
And for that reason, I would probably go for getOddness4 even though I see your point.

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

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

More readable? How about this:

SELECT DISTINCT authors FROM books WHERE page_count > 1000;

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

#226

Earlier quoted context omitted.

The problem is that it's easy to overdo it. When you are writing the code, you already know what it's supposed to do, and adding a few more things to the chain is convenient and attractive. But when you are reading unfamiliar code, you often wish that the author was more explicit with their code. Not just with what the code is actually doing, but what it's trying to do and what are the key waypoints to get there. Wit…

> The problem is that it's easy to overdo it. Welcome to all features of every programming language? Sacrificing readability, optimization, and simplicity for the 95% case because some un-principled developers might overdo it in the 5% case (when the cost of fixing it is trivially just inserting variable assignments) is… not a good trade-off.

5% is common enough that you'll encounter it almost every time you read code. And fixing it is not easy, because you first need to understand the code before you can add useful variable names.

Besides, programming language evolution is mostly driven by the fact that everyone is lazy and unprincipled at least occasionally. If you need to be disciplined to avoid footguns, you'll trigger them sooner or later.

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

#227

Earlier quoted context omitted.

> The problem is that it's easy to overdo it. Welcome to all features of every programming language? Sacrificing readability, optimization, and simplicity for the 95% case because some un-principled developers might overdo it in the 5% case (when the cost of fixing it is trivially just inserting variable assignments) is… not a good trade-off.

5% is common enough that you'll encounter it almost every time you read code. And fixing it is not easy, because you first need to understand the code before you can add useful variable names. Besides, programming language evolution is mostly driven by the fact that everyone is lazy and unprincipled at least occasionally. If you need to be disciplined to avoid footguns, you'll trigger them sooner or later.

The cost of this "footgun" is basically zero. Every step in a functional pipeline is isolated and wholly independent. If you want to split such a pipeline in two, doing so is trivial.

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

#228
post #219

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,…

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…

  o_node := graph.GetNodeByName(name)
  var ret []string
  for _, node := range o_node.connectedNodes() {
    if !node.isHidden {
      ret = append(ret, node.name)
    }
  }
  return ret

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

#229

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,…

>For me, roughly 5 calls in a chain is where things begin to become harder to read, which is the length of the example I used. This isn't just about readability. Chaining or FP is structurally more sound. It is the more proper way to code from a architectural and structural pattern perspective. given an array of numbers 1. I want to add 5 to all numbers 2. I want to convert to string 3. I want to concat hello 4. I wa…

you have this backwards: reusing code couples the code. copy+paste uncouples code

if you have two functions, they're not coupled. you change one, the other stays as-is

if you refactor it so that they both call a third function, they're now coupled. you can't change the part they have in common without either changing both, or uncoupling them by duplicating the code

(you often want that coupling, if it lines up with the semantics)

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

#230
post #204

Earlier quoted context omitted.

I tried scaling up the original into an intentionally convoluted nonsensical problem to see how a more complicated solution would look like for each approach. Do these look right? And which seems the most readable? # Functional approach var favoriteFoodsOfFurryPetsOfFamousAuthorsOfLongChineseBooksAboutHistory = books .filter(book => book.pageCount > 100 and book.language == "Chinese" and book.subject == "History" and…

Your FP example is needlessly complicated. No one who does FP regularly would write it like that. var favoriteFoodsOfFurryPetsOfFamousAuthorsOfLongChineseBooksAboutHistory = books .filter(book => book.pageCount > 100 and book.language == "Chinese" and book.subject == "History" and book.author.mentions > 10_000 ) .flatMap(book => book.author.pets) .filter(pet => pet.is_furry) .map(pet => pet.favoriteFood) .distinct()…

I didn’t see the original, but the FP example here looks fairly idiomatic to me.

An alternative, which in FP-friendly languages would have almost identical performance, would be to make the shift in objects more explicit:

    var favoriteFoodsOfFurryPetsOfFamousAuthorsOfLongChineseBooksAboutHistory =
      books
        .filter(book => isLongChineseBookAboutHistory(book))
        .map(book => book.author)
        .filter(author => isFamous(author))
        .flatMap(author => author.pets)
        .filter(pet => pet.isFurry)
        .map(pet => pet.favouriteFood)
        .distinct()
I slightly prefer this style with such a long pipeline, because to me it’s now built from standard patterns with relatively simple and semantically meaningful descriptions of what fills their holes. Obviously there’s some subjective judgement involved with anything like this; for example, if the concept of an author being famous was a recurring one then I’d probably want it defined in one place like an `isFamous` function, but if this were the only place in the code that needed to make that decision, I might inline the comparison.
Post reply on HN