What makes code hard to read: Visual patterns of complexity (2023)
281–290 of 383 posts
Re: What makes code hard to read: Visual patterns of complexity (2023)
#282Earlier quoted context omitted.
There is just no way that reasonable people consider this to be clearer. One certainly might be more familiar with this approach, but it is less clear by a long shot. You've added a temp variable for the result, manual appending to that temp variable (which introduces a performance regression from having to periodically grow the array), loop variables, unused variables, multiple layers of nesting, and conditional log…
Everything you said is true for both of our programs, the only difference is whether or not it's hidden behind function calls you can't see and don't have access to. You don't really think that functional languages aren't appending things, using temp vars, and using conditional logic behind the scenes, do you? What do you think ".filter(node => !node.isHidden)" does? It's nothing but a for loop and a conditional by a…
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 languages that compile down to machine instructions are equivalent. After all, it winds up in the same registers and a bunch of CMP, MOV, JMP, and so on.
`.distinct()` could sort the result and look for consecutive entries, it could build up a set internally, it could use a hashmap, or any one of a million other approaches. It can even probe the size of the array to pick the performance-optimal approach. I don't have to care.
> [".filter(node => !node.isHidden)" is] nothing but a for loop and a conditional by another name and wrapped in an awkward, unwieldy package.
This is honestly an absurd take. I truly have no other words for it. map, filter, and friends are quite literally some of the clearest and most ergonomic abstractions ever devised.
Re: What makes code hard to read: Visual patterns of complexity (2023)
#283Earlier quoted context omitted.
You don't ever need to "understand everything at once". You can read each stanza linearly. The for loop style is the approach where everything often needs to be understood all at once since the logic is interspersed throughout the entire body.
In the example above, you first have a list of books. Then you filter it down to books with >1000 pages. Then you map it to authors of books with >1000 pages. Then you collapse it to distinct authors of books with >1000 pages. Every step in the chain adds further complexity to the description of the things you have, until it exceeds the capacity of your working memory. Then you can no longer reason about it. The stan…
var authorsOfLongBooks = books
.filter(book => book.pageCount > 1000)
.map(longBooks => longBooks.author)
.distinct()Re: What makes code hard to read: Visual patterns of complexity (2023)
#284Earlier quoted context omitted.
How so? The states of the intermediate steps are logically and easily exposed in a debugger. You can also easily set conditional breakpoints relative to the intermediate states. I know that intermediate states are generally easier to comprehend, because I never have to explain them in code reviews. To avoid having to explain chains to others, I end up having to add descriptive comments to the intermediate steps, far…
Build up and debug the chain as you work in an environment like Jupyter. No need to create variables. Just run the code and verify that the current step works. Then, proceed to the next. Then, put the chain in a function. If you want to be nice, put a .loc as the first step to explicitly list all of the input columns. Drop another .loc as the last step to validate the output columns. (This also serves as a test and d…
> Just run the code and verify that the current step works. Then, proceed to the next.
Yes, it's not debuggable/"viewable" without cut/paste/commenting out lines, once it's constructed.
Re: What makes code hard to read: Visual patterns of complexity (2023)
#285Earlier quoted context omitted.
>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 t…
Re: What makes code hard to read: Visual patterns of complexity (2023)
#286Earlier quoted context omitted.
> mainly because "fluent" chains should never be mutating their operand. I see this quite often with builders, actually, and I don't mind it so much there. FooBuilder() .setBar(bar) .setBaz(baz) .setQux(qux) .build()
everytime i see this i just would prefer a variadic function lol
Re: What makes code hard to read: Visual patterns of complexity (2023)
#287> 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…
It actively hurts maintainability, please stop using it.
Re: What makes code hard to read: Visual patterns of complexity (2023)
#288Personally, my normal style is getOddness2(). I try to never have an expression in my return statement -- only return a literal, local variable, or class data member. Why do I choose getOddness2()? It is so easy to debug. When I write code, I am mostly thinking about difficult to debug -- control flow and local variables.
I would like to hear about other people's style and why they choose it.
Related: Does Google Code style guidelines (perhaps the most famous of such guidelines on the Interwebs) have anything to say about which version of getOddness() is best/recommended?
Re: What makes code hard to read: Visual patterns of complexity (2023)
#289Earlier quoted context omitted.
function getOddness(n: number): return (n % 2 === 0) ? "Even" : "Odd"; Lowest boilerplate makes it the most readable. If working in a language with the ternary operator it ought to be easily recognized!
Putting “return” on a different line from the actual value you’re returning?
To me and my style of coding, there's a difference of intent between the two. A ternary connotes a mere computation, something that should have no side-effects. A conditional connotes a procedure; the arms of the conditional might be expected to have side-effects. (And the case of `if (_) return` or similar are pure control flow guards; they neither compute a value nor perform a procedure as such.)
It's not just about where the symbols go on the screen.
Re: What makes code hard to read: Visual patterns of complexity (2023)
#290> 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;
SELECT DISTINCT authors.some_field FROM books JOIN authors ON books.author_id = authors.author_id WHERE books.pageCount > 1000
And if you wanted to grab the entire authors record (like the code does) you'd probably need some more complexity in there:
SELECT * FROM authors WHERE author_id IN ( SELECT DISTINCT authors.author_id FROM books JOIN authors ON books.author_id = authors.author_id WHERE books.pageCount > 1000 )