TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

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

414 pointsby homarp2 months ago

45 comments

feoren2 months ago
&gt; Chaining together map&#x2F;reduce&#x2F;filter and other functional programming constructs (lambdas, iterators, comprehensions) may be concise, but long&#x2F;multiple chains hurt readability<p>This is not at all implied by anything else in the article. This feels like a common &quot;I&#x27;m unfamiliar with it so it&#x27;s bad&quot; gripe that the author just sneaked in. Once you become a little familiar with it, it&#x27;s usually far easier to both read and write than any of the alternatives. I challenge anyone to come up with a more readable example of this:<p><pre><code> var authorsOfLongBooks = books .filter(book =&gt; book.pageCount &gt; 1000) .map(book =&gt; book.author) .distinct() </code></pre> By almost any complexity metric, including his, this code is going to beat the snot out of any other way of doing this. Please, learn just <i>the basics</i> of functional programming. You don&#x27;t need to be able to explain what a Monad is (I barely can). But you should be familiar enough that you stop randomly badmouthing <i>map</i> and <i>filter</i> like you have some sort of anti-functional-programming Tourette&#x27;s syndrome.
评论 #43336084 未加载
评论 #43335661 未加载
评论 #43335774 未加载
评论 #43341265 未加载
评论 #43337442 未加载
评论 #43335789 未加载
评论 #43338344 未加载
评论 #43338337 未加载
评论 #43356350 未加载
评论 #43339765 未加载
评论 #43341698 未加载
评论 #43337133 未加载
评论 #43343752 未加载
评论 #43339824 未加载
评论 #43338113 未加载
评论 #43338630 未加载
评论 #43343120 未加载
评论 #43334341 未加载
评论 #43336866 未加载
评论 #43338604 未加载
评论 #43338994 未加载
recursivedoubts2 months ago
There is a (large, I believe) aspect of good code that is fundamentally qualitative &amp; almost literary. This annoys a lot of computer programmers (and academics) who are inclined to the mathematical mindset and want quantitative answers instead.<p>I love dostoyevsky and wodehouse, both wrote very well, but also very differently. While I don&#x27;t think coding is quite that open a playing field, I have worked on good code bases that feel very different qualitatively. It often takes me a while to &quot;get&quot; the style of a code base, just as a new author make take a while for me to get.
评论 #43332730 未加载
评论 #43332200 未加载
评论 #43332928 未加载
评论 #43333044 未加载
评论 #43332887 未加载
评论 #43332612 未加载
mrkeen2 months ago
The article&#x27;s good, but misses my most mentally-fatiguing issue when reading code: mutability.<p>It is such a gift to be able to &quot;lock in&quot; a variable&#x27;s meaning exactly once while reading a given method, and to hold it constant while reasoning about the rest of the method.<p>Your understanding of the method should monotonically increase from 0% to 100%, without needing to mentally &quot;restart&quot; the method because you messed up what the loop body did to an accumulator on a particular iteration.<p>This is the real reason why GOTOs are harmful: I don&#x27;t have a hard time moving my mind&#x27;s instruction-pointer around a method; I have a hard time knowing the state of mutable variables when GOTOs are in play.
评论 #43333268 未加载
评论 #43332578 未加载
stared2 months ago
My pet peeve:<p><pre><code> function getOddness4(n: number): if (n % 2 === 0): return &quot;Even&quot;; return &quot;Odd&quot;; </code></pre> While it is shorter, I prefer vastly prefer this one:<p><pre><code> function getOddness2(n: number): if (n % 2 === 0): return &quot;Even&quot;; else: return &quot;Odd&quot;; </code></pre> Reason: getOddness4 gives some sense of asymmetry, whereas &quot;Even&quot; and &quot;Odd&quot; are symmetric choices. getOddness2 is in that respect straightforward.
评论 #43335218 未加载
评论 #43334230 未加载
评论 #43333493 未加载
评论 #43333868 未加载
评论 #43342848 未加载
评论 #43334528 未加载
评论 #43338061 未加载
评论 #43337122 未加载
CharlieDigital2 months ago
Maybe it&#x27;s just me, but TypeScript makes code hard to read.<p>It&#x27;s fine if the data model is kept somewhat &quot;atomic&quot; and devs are diligent about actually declaring and documenting types (on my own projects, I&#x27;m super diligent about this).<p>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 because it&#x27;s very hard to trace fields back to their origin in a _deep_ stack (like 4-5 levels of type indirection; some inferred, some explicit, some derived, some fields get aliased...).<p><pre><code> type Dog = { breed: string size: &quot;lg&quot; | &quot;md&quot; | &quot;sm&quot; &#x2F;&#x2F; ... } type DogBreedAndSize = Pick&lt;Dog, &quot;breed&quot; | &quot;size&quot;&gt; function checkDogs(dogs: Dog[]) : DogBreedAndSize[] { return dogs.map(d =&gt; &#x2F;* ... *&#x2F;) } const checkedDoggos = checkDogs([]) </code></pre> Versus:<p><pre><code> function checkDogs(dogs: Dog[]) { &#x2F;&#x2F; ... } </code></pre> Very subtle, but for large data models with deep call stacks, the latter is completely unusable and absolutely maddening.
评论 #43332726 未加载
评论 #43333886 未加载
评论 #43340184 未加载
userbinator2 months ago
<i>Smaller functions with fewer variables are generally easier to read</i><p>I hate how a lot of focus on &quot;readability&quot; is on <i>micro</i>-readability, which then tends to encourage highly fragmented code under the highly misguided assumption that micro-readability is more important than macro-readability. The dogma-culting around this then breeds plenty of programmers who can&#x27;t see the forest for the trees and end up creating grossly inefficient code and&#x2F;or have difficulty with debugging.<p>APL-family languages are at the other extreme, although I suspect the actual optimum is somewhere in the middle and highly dependent on the individual.
评论 #43340350 未加载
jorams2 months ago
This is an interesting article, but also rather unsatisfying. It very quickly jumps to conclusions and goes right back to opinion. I agree with several of those opinions, but opinion was explicitly not the point of the article.<p>&gt; Prefer to not use language-specific operators or syntactic sugars, since additional constructs are a tax on the reader.<p>I don&#x27;t think this follows from the metric. If a function contains three distinct operators, a language-specific operator that replaces all three of them in one go would reduce the &quot;effort&quot; of function. It&#x27;s highly scenario-specific.<p>&gt; Chaining together map&#x2F;reduce&#x2F;filter and other functional programming constructs (lambdas, iterators, comprehensions) may be concise, but long&#x2F;multiple chains hurt readability<p>I don&#x27;t think this follows either. One effect of these constructs when used right is that they replace other operators and reduce the &quot;volume&quot;. Again this can go both ways.<p>&gt; ...case in point, these code snippets aren’t actually equivalent!<p>That&#x27;s a very language-specific diagnosis, and arguably points at hard-to-read <i>language design</i> in JS. The snippet otherwise doesn&#x27;t look like JS, but I&#x27;m not aware of another language for which this would apply. Indeed it is also commonly known as a &quot;null-safe operator&quot;, because most languages don&#x27;t have separate &quot;null&quot; and &quot;undefined&quot;.<p>&gt; variable shadowing is terrible<p>&gt; long liveness durations force the reader to do keep more possible variables and variables in their head.<p>These can arguably be contradictory, and that is why I am a huge fan of variable shadowing <i>in some contexts</i>: By shadowing a variable you remove the previous instance from scope, rather than keeping both available.
shortrounddev22 months ago
There&#x27;s a cool plugin for vscode called Highlight[1] that lets you set custom regexes to apply different colors to your code. I think a common use of this is to make &#x2F;&#x2F;TODO comments yellow, but I use it to de-emphasize logs, which add a lot of visual noise because I put them EVERYWHERE. The library I maintain uses logs that look like:<p><pre><code> this.logger?.info(&#x27;Some logs here&#x27;); </code></pre> So I apply 0.4 opacity to it so that it kind of fades into the background. It&#x27;s still visible, but at a glance, the actual business logic code pops out at you. This is my configuration for anyone who wants to modify it:<p><pre><code> &#x2F;&#x2F;In vscode settings.json: &quot;highlight.regexes&quot;: { &quot;((?:this\\.)?(?:_)?logger(?:\\?)?.(debug|error|info|warn)[^\\)]*\\)\\;)&quot;: { &quot;regexFlags&quot;: &quot;gmi&quot;, &quot;decorations&quot;: [{ &quot;opacity&quot;: &quot;0.4&quot; }] } }, </code></pre> ---<p>[1] <a href="https:&#x2F;&#x2F;marketplace.visualstudio.com&#x2F;items?itemName=fabiospampinato.vscode-highlight" rel="nofollow">https:&#x2F;&#x2F;marketplace.visualstudio.com&#x2F;items?itemName=fabiospa...</a>
gwbas1c2 months ago
&gt; For long function chains or callbacks that stack up, breaking up the chain into smaller groups and using a well-named variable<p>&gt; Is the second one marginally less efficient?<p>&gt; Yes.<p>No, both versions are just as efficient:<p>In both versions, the same objects are allocated, stored on the heap, and garbage collected. The difference in efficiency comes down to the compiler.<p>For the second version, the compiler should observe that each variable is only used immediately after it&#x27;s declared, and thus treat those objects as &quot;out-of-scope&quot; as if it&#x27;s a chained function call.
评论 #43336331 未加载
jt21902 months ago
Kudos to seeinglogic for trying to quantify that “readablity” is. We need a lot more of this. (I feel like the most common definition of readability in use today is “readable to me“.)<p>I have a half-baked thought that we could find the actual dimensions of readability if we gave a test to a very large group of people and asked them to pick a sentence that describes what the code does. Each question would be timed. The questions that most people answered correctly in the shortest average time would provide us with examples of “real-world readable” code, and more importantly, might help us identify some truly not-readable practices.<p>I predict we’d see respondents start to cluster around various things, like “how long have they been programming?“, “do they understand programming paradigm X?“, etc. Perhaps the results would shift over time, as various things came into and out of fashion.
评论 #43332013 未加载
评论 #43332024 未加载
评论 #43331975 未加载
James_K2 months ago
I my view, code complexity is best expressed in the size of it&#x27;s syntax tree, with maybe an additional term for the number of unique nodes. The real mistake here is the assumption that local reductions in complexity make a meaningful difference to overall complexity. Small local decreases in complexity may guide you towards the local minimum of complexity, but will never substantially change the complexity of the code-base overall. All measurements of code complexity are essentially as good as asking &quot;how much code do you have&quot;.
评论 #43332270 未加载
Izkata2 months ago
I think the only one I disagree with here is the function chains example. I may agree with a different example, but with this one I find the chained version without variables much easier to understand because I&#x27;m traversing the graph visually in my head, while the variables are additional state I have to keep track of in my head.<p>----<p>Really I was hoping this would be about actual visual patterns and not syntax. It&#x27;s my major issue with how strict code linting&#x2F;autoformatting is nowadays.<p>For example, the &quot;black&quot; formatter for python requires this:<p><pre><code> drawer.ellipse((10, 10, 30, 30), fill=(256, 256, 0)) drawer.ellipse((370, 10, 390, 30), fill=(256, 256, 0)) drawer.arc((20, 0, 380, 180), 15, 165, fill=(256, 256, 0), width=5) </code></pre> The first argument is (x1, y1, x2, y2) of a bounding box and black wants to align x1 for &quot;ellipse&quot; with y1 of &quot;arc&quot;. Do people really find that more readable than this?<p><pre><code> drawer.ellipse( (10, 10, 30, 30), fill=(256, 256, 0) ) drawer.ellipse( (370, 10, 390, 30), fill=(256, 256, 0) ) drawer.arc( (20, 0, 380, 180), 15, 165, fill=(256, 256, 0), width=5 ) </code></pre> Or perhaps something more common in python, kwargs in function arguments. No spacing at all is standard python style:<p><pre><code> Foobar.objects.create( name=form.name, owner=user, location=form.location, source=form.source, created=time.now, ) </code></pre> Instead for me it&#x27;s much easier to read this, since I don&#x27;t have to scan for the &quot;=&quot; and mentally parse each line, it&#x27;s just a table:<p><pre><code> Foobar.objects.create( name = form.name, owner = user, location = form.location, source = form.source, created = time.now, ) </code></pre> But no linters&#x2F;formatters accept such spacing by default. I think flake8 (linter) could be configured to ignore whitespace like this, but black (formatter) can&#x27;t.
评论 #43333050 未加载
评论 #43335165 未加载
评论 #43338482 未加载
dchristian2 months ago
This talks about the &quot;what&quot; of the code, but you have to also convey the &quot;why&quot;.<p>If you have a well understood problem space and a team that is up to speed on it, then the &quot;why&quot; is well established and the code is the &quot;what&quot;.<p>However, there are often cases where the code is capturing a new area that isn&#x27;t fully understood. You need to interleave an education of the &quot;why&quot; of the code.<p>I was once asked to clean up for release 10k lines of someone else&#x27;s robotics kinematics library code. There weren&#x27;t any comments, readmes, reference programs, or tests. It was just impenetrable, with no starting point, no way to test correctness, and no definition of terms. I talked to the programmer and he was completely proud of what he had done. The variable names were supposed to tell the story. To me it was a 10k piece puzzle with no picture! I punted that project and never worked with that programmer again.
throwaway20372 months ago
This image shows six different ways to write a simple function, getOddness(): <a href="https:&#x2F;&#x2F;seeinglogic.com&#x2F;posts&#x2F;visual-readability-patterns&#x2F;6-oddness.png" rel="nofollow">https:&#x2F;&#x2F;seeinglogic.com&#x2F;posts&#x2F;visual-readability-patterns&#x2F;6-...</a><p>Personally, 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.<p>I would like to hear about other people&#x27;s style and why they choose it.<p>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&#x2F;recommended?
bluGill2 months ago
Towards the end he had an example of splitting a sequence of &quot;graph.nodes(`node[name = ${name}]`).connected().nodes().not(&#x27;.hidden&#x27;).data(&#x27;name&#x27;);&quot; 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 difference from that optimization applied by hand will be far smaller than the performance improvements you will get by rewriting in a language with an optimizer. Either way, readability trumps performance: either because the performance is the same, or if performance mattered you would have choosen a different language in the first place.
评论 #43332776 未加载
评论 #43332370 未加载
BorgHunter2 months ago
I think things like Halstead complexity or cyclomatic complexity are more heuristic than law. To read code, the most important thing to me is the abstractions that are built, and how effectively they bury irrelevant complexities and convey important concepts.<p>As an example, I recently refactored some Java code that was calling a service that returned a list of Things, but it was paged: You might have to make multiple calls to the service to get all the Things back. The original code used a while loop to build a list, and later in the same function did some business logic on the Things. My refactoring actually made things more complex: I created a class called a Spliterator that iterated through each page, and when it was exhausted, called the service again to get the next one. The upside was, this allowed me to simply put the Things in a Stream&lt;Thing&gt; and, crucially, buried the paged nature of the request one level deeper. My reasoning is that separating an implementation detail (the request being paged) from the business logic makes the code easier to read, even if static code analysis would rate the code as slightly more complex. Also, the code that handles the pages is fairly robust and probably doesn&#x27;t need to be the focus of developer attention very often, if ever, while the code that handles the business logic is much more likely to need changes from time to time.<p>As programmers, we have to deal with a very long chain of abstractions, from CPU instructions to network calls to high-falutin&#x27; language concepts all the way up to whatever business logic we&#x27;re trying to implement. Along the way, we build our own abstractions. We have to take care that the abstractions we build benefit our future selves. Complexity measures can <i>help</i> measure this, but we have to remember that these measures are subordinate to the actual goal of code, which is communicating a complex series of rules and instructions to two very different audiences: The compiler&#x2F;interpreter&#x2F;VM&#x2F;whatever, and our fellow programmers (often, our future selves who have forgotten half of the details about this code). We have to build high-quality abstractions to meet the needs of those two audiences, but static code analysis is only part of the puzzle.
评论 #43332907 未加载
zesterer2 months ago
I&#x27;ve never understood the hate for variable shadowing. Maybe it&#x27;s because I mostly use Rust, but I&#x27;ve always found it a useful boon for readability. You often want to extract&#x2F;parse&#x2F;wrap&#x2F;package some value within the middle of a function in a manner that changes its type&#x2F;form but not its semantic purpose. Shadowing the old value&#x27;s variable name is brilliant: it communicates that there&#x27;s a step-change in the responsibilities of the function, demarcating layers from one-another and preventing accidental use of the old value.
评论 #43334848 未加载
评论 #43337498 未加载
stopthe2 months ago
I always shrugged off the concept of code metrics (from LoCs to coverage) as a distraction from getting actual things done. But since doing more code-review I started to lack a framework to properly explain why a particular piece of code smells. I sympathize with the way the author cautiously approaches any quantitative metrics and talks of them more like heuristics. I agree that both Halstead Complexity and Cognitive Complexity are useless as absolute values. But they can be brought up in a conversation about a potential refactoring for readability.<p>What I didn&#x27;t find is a mention of a context when reading a particular function. For example, while programming in Scala I was burnt more than once by one particular anti-pattern.<p>Suppose you have a collection of items which have some numerical property and you want a simple sum of that numbers. Think of shopping cart items with VAT tax on them, or portfolio positions each with a PnL number. Scala with monads and type inference makes it easy and subjectively elegant to write e.g.<p><pre><code> val totalVAT = items.map(_.vat).sum </code></pre> But if `items` were a `Set[]` and some of the items happened to have the same tax on them, you would get a Set of numbers and a wrong sum in the end.<p>You could append to the list of such things until the OutOfMemoryError. But it&#x27;s such a beautiful and powerful language. Sigh.
评论 #43352060 未加载
Pannoniae2 months ago
This is probably a bit of a cheap dismissal.... but I think this article misses the forest for the trees. They set a standard which they manage to meet - but do not really introspect on whether the standard is appropriate or not.<p>All of these metrics (except variable liveness) are on a method&#x2F;function level. Guess what this encourages? Splitting everything into three-line methods which makes the codebase a massive pile of lasagna full of global or shared state.<p>If a method is long to read from top to bottom, the answer isn&#x27;t always splitting it into 5 smaller ones, sometimes life just has inherent complexity.
评论 #43331784 未加载
评论 #43331941 未加载
评论 #43331895 未加载
评论 #43332051 未加载
评论 #43331838 未加载
alan_n2 months ago
I think a lot about code readability a lot. I agree with most of this except the names part and shorthand constructs. Especially for the latter, it&#x27;s unfair to make a comparison with the wrong operator. The example in general is a bit weird. I think a better one is `if (myObj !== null) myObj = someOtherObj`. A very common pattern for which js now has a nullish coalescing assignment you can use insteal (`myObject ??= somOtherObj`) or there&#x27;s also ||=. These sacrifice some readability upfront due to them being &quot;uncommon&quot; operators and the code might be harder to read for someone whose never seen it, but is so much easier to read once you get used to it. There is of course, always a trade off. Using a lot of .? to access properties can be code smell, but also sometimes very helpful, as the alternative would expand into a lot of code.<p>Regarding names, I think the suggestions are a bit in conflict, as often to avoid variable shadowing you have to do stuff like name things node, _node, node2. I try to have distinct names, but I&#x27;d rather the shadowing in those cases where it&#x27;s hard. As for i, and j. I don&#x27;t like them, but they&#x27;re such conventions it&#x27;s hard to avoid them. I always try to use them only once, and assign the variable I need: `item = obj[i][j]` if possible.
slevis2 months ago
Do people really really agree with &quot;Shorthand constructs that combine statements decreases difficulty&quot;? The author even identifies a problem with the example from the original guide.
评论 #43333799 未加载
评论 #43333396 未加载
评论 #43333979 未加载
mannykannot2 months ago
I would like to add something to the point made here:<p>&quot;For long function chains or callbacks that stack up, breaking up the chain into smaller groups <i>and using a well-named variable or helper function</i> can go a long way in reducing the cognitive load for readers. [my emphasis]<p><pre><code> &#x2F;&#x2F; which is easier and faster to read? function funcA(graph) { return graph.nodes(`node[name = ${name}]`) .connected() .nodes() .not(&#x27;.hidden&#x27;) .data(&#x27;name&#x27;); } &#x2F;&#x2F; or: function funcB(graph) { const targetNode = graph.nodes(`node[name = ${name}]`) const neighborNodes = targetNode.connected().nodes(); const visibleNames = neighborNodes.not(&#x27;.hidden&#x27;).data(&#x27;name&#x27;) return visibleNames; } </code></pre> The names of the functions being called are rather generic, which is appropriate and unavoidable, given that the functions they compute are themselves rather generic. By assigning their returned values to consts, we are giving ourselves the opportunity to label these computations with a hint to their specific purpose in this particular code.<p>In general, I&#x27;m not a fan of the notion that code can always be self-documenting, but here is a case where one version is capable of being more self-documenting than the other.
评论 #43332446 未加载
satisfice2 months ago
Interesting how important mere opinion seems to be, because the author doesn&#x27;t seem to mention two issues that matter a great deal to me:<p>- Alignment of braces and brackets, instead of an opening brace at the end of one line and the closing brace at the beginning of a subsequent line. - everything I need to see is within an eyespan, instead having to jump to several different files to trace code.
WillAdams2 months ago
Why not apply a programming methodology which allows one to leverage a rich set of tools which were created for making text more readable and visually pleasing?<p><a href="http:&#x2F;&#x2F;literateprogramming.com&#x2F;" rel="nofollow">http:&#x2F;&#x2F;literateprogramming.com&#x2F;</a><p>For a book-length discussion of this see:<p><a href="https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;39996759-a-philosophy-of-software-design" rel="nofollow">https:&#x2F;&#x2F;www.goodreads.com&#x2F;book&#x2F;show&#x2F;39996759-a-philosophy-of...</a><p>previously discussed here at: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=27686818">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=27686818</a> (and other times in a more passing mention --- &quot;Clean Code&quot; adherents should see: <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43166362">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=43166362</a> )<p>That said, I would be _very_ interested in an editor&#x2F;display tool which would show the &quot;liveness&quot; (lifespan?) of a variable.
评论 #43332440 未加载
评论 #43332650 未加载
austin-cheney2 months ago
I have seen this subject come up as the most important factor of human behavior in every one of my employments. Counting both my corporate time and military time that is nearly 50 years employment time at more than 20 different organizations.<p>First things first, <i>complex</i> is a fancy word that means <i>many</i>. That&#x27;s it, so don&#x27;t over think it. Everything else is bias and opinions. If you feel conflicted about that see the fantastic Rich Hickey talk: Simple Made Easy <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=SxdOUGdseq4" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=SxdOUGdseq4</a><p>Secondly, how this actually manifests is that people are eager to solve some problem in a way they feel comfortable, whether by process or automation, and then nobody wants to maintain anything, especially if it was written by somebody else. This is a critical failure.<p>The best solution I have found to solve for this is speed, not code style or anything else. Uncertainty increases proportionally to the duration between testable iterations. For example if it takes 30 seconds to try out an idea and reset back to the prior state people feel more certain about the environment in which they work because risk is low and learning is fast. If, on the other hand, it takes 90 minutes to try out an idea people will be exceedingly cautious about what they try and propose because everything is fragile and expensive.<p>Knowing that speed is the solution is not convincing in a world where most software developers cannot measure anything. Instead it must be mandated that software has only one purpose: automation, so automate the shit out of it. When that becomes the thesis of all work speed naturally self-amplifies and people split into two camps. The first camp is people that can actually write original software and the second camp is people who will kill you with internal processes, such as complexity checks and code style rules, because they cannot automate their way out of it.
davidw2 months ago
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.<p><pre><code> ((( (( ( </code></pre> Takes some staring at to figure out what&#x27;s what.
评论 #43335652 未加载
评论 #43335635 未加载
gwbas1c2 months ago
&gt; 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.<p>FYI: If you get into this situation in C#, the .editorconfig file and the &quot;dotnet format&quot; command are a godsend.<p>I inherited a very large, and complicated C# codebase with a lot of &quot;novice&quot; code and inconsistent style. I spent about 3 weeks adding rules to .editorconfig, running &quot;dotnet format&quot; and then manually cleaning up what it couldn&#x27;t clean up. Finally, I added a Github Action to enforce &quot;dotnet format&quot; in all pull requests.<p>As a result: 1: The code was significantly more readable. 2: It trapped mistakes from everyone, including myself.<p>There are a few areas where we have to disable a rule via #pragma; <i>but these are the exception, not the norm.</i>
评论 #43346936 未加载
m4632 months ago
I enjoy the visual uncomplexification of python indenting.<p>After switching back and forth with languages with &quot;extra&quot; syntax, it seems visually and cognitively cleaner.<p>that said, there were some things about perl that I liked cognitivel, like being able to say &quot;unless&quot; instead of &quot;if not&quot;
farceSpherule2 months ago
I was an engineering manager back in the day (Java). People would get lost in the sauce with bracket placement, number of tabs, etc., etc. In order to avoid religious battles, I instituted a code formatter&#x2F;beautifier. It would format all code upon commit.<p>Problem solved.<p>Although another conversation, people did not want to document their code. So I took the carrot &#x2F; stick approach. I had to approve all commits and if code did not have javadoc, I did not approve the commit. If your commit was not on time, then that impacted your performance which, in turn, impacted your pay. People bitched at first but whatever. At this particular place, we were trying to get bought. Having documentation and other IP made us more valuable. It forced devs to put actual thought into how to manage their time.
deadbabe2 months ago
You really should try to pack an unbroken thought as a single line of code as much as possible. That’s the idea behind chaining multiple functions together on one line instead of spreading it out over several lines. Eyes go horizontally more naturally than up and down, it fits our vision’s natural aspect ratio. And stop making deep nestings.<p>Making a single function call per line assigning output to a variable each time is really just for noobs who don’t have great code comprehension skills and appreciate the pause to have a chance to think. If the variable’s purpose for existence is just to get passed on to a next function immediately, it shouldn’t exist at all. Learn to lay pipe.
评论 #43336621 未加载
评论 #43357693 未加载
zombot2 months ago
&gt; Let me be upfront: there is no commonly-used and accepted metric for code readability.<p>Indeed, I haven&#x27;t found an autoformatter yet whose default settings I find &quot;readable&quot;. The best of them is still clang-format, because it has so many parameters I can tune. By now I have a .clang-format config file that almost comes close to producing the formatting I do manually.<p>I also find functional patterns way more readable than their procedural counterparts.
deepsun2 months ago
&gt; there’s a better chance that the programmer forgets to properly handle all of the possibilities<p>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.<p>Also depends on the language, e.g. it&#x27;s less reliable in Javascript and Python, but in static typed languages it&#x27;s pretty obvious at no additional cognitive load.
TrianguloY2 months ago
As someone with relatively bad memory, in general less variables = easier to understand. The more I need to remember, the more time I&#x27;ll spent. IDEs help by providing inline hints and documentation, but the main issue is that a variable _can_ be used later, so you need to remember it. No variable (like on a chained&#x2F;piped construct) means that the value is generated and immediately used.
seeinglogic2 months ago
Author here.<p>Thank you for all the thoughtful comments and great stuff I didn&#x27;t think of (also has been a hot minute since I wrote the article).<p>I appreciate the discussion!
评论 #43336053 未加载
fs_software2 months ago
This came up at work the other day re: client-side code readability.<p>In one camp, folks were in favor of component extraction&#x2F;isolation with self-documenting tests wherever possible.<p>In the other camp, folks argued that drilling into a multi-file component tree makes the system harder to understand. They favor &quot;locality of behavior&quot;.<p>Our consensus - there needs to be a balance.
评论 #43332596 未加载
moi23882 months ago
I find the main problem is not wanting to split up functions.<p>I greatly prefer small helper functions, so that a more complicated one becomes more readable.<p>Even declaring a little local variable which explains in English what the condition you’re going to test is supposed to do is greatly appreciated
snitzr2 months ago
Shoutout to the pipe operator in R. The code equivalent of &quot;and then.&quot; It helps to unnest functions and put each action on one line. I know R is more for stats and data, but I just think it&#x27;s neat.
评论 #43332827 未加载
评论 #43333463 未加载
begueradj2 months ago
The notion of &quot;readable code&quot; involves 2 parties:<p>a) The skill level of the person who produces the code<p>b) The skill level of the person who reads the code.<p>Most of the time, we tend to blame the a) person.
评论 #43338508 未加载
morning-coffee2 months ago
&gt; These metrics definitely are debatable (they were made in the 70’s…)<p>What is it about a decade that makes contributions produced thereabout &quot;debatable&quot;?
评论 #43334497 未加载
评论 #43333981 未加载
Duanemclemore2 months ago
It would be interesting to see how APL and other array languages stack up in this kind of analysis. I&#x27;m guessing they would do well...
odyssey72 months ago
When are they planning on updating the simple sabotage field manual pdf?
mwkaufma2 months ago
All of the leading code samples look _fine_. This whole article is the kind of superficial bikeshedding feedback one gets from code-reviewers who are just phoning it in and don&#x27;t care about the substance of the problem or solution.
ezoe2 months ago
Any nesting and indirection burden the mental fatigue on understanding the code: nesting conditional statements, macros, functions, classes while it&#x27;s necessary to use or we will have so many duplicated codes which also burden the mental fatigue anyway.<p>There was an extreme argument on a SNS recently that someone claimed that he prohibit nesting if in their work.<p>Shorter-lived Variables argument doesn&#x27;t always work. One of the most horrible code I read use very short-lived variables:<p>val_2 = f(val), val_3 = g(val), ...<p>It&#x27;s Erlang. Because Erlang&#x27;s apparent variable isn&#x27;t a variable, but just a name bound to a term.
0xbadcafebee2 months ago
I just wanted to point out that &quot;Cognitive Complexity&quot; [1] was not invented by SonarSource, it is an academic principle created in the 1950s and has more to do with psychology than computer science. Computer science has over-simplified the term to mean &quot;hey there&#x27;s a lot of stuff to remember this is hard&quot;.<p>Psychology tends to have a wider scope of thought and research put into it [2] [3]. For example, one way it&#x27;s used is not to measure how complex something is, but how capable <i>one particular person</i> is at understanding complex things, versus a different human [4]. This can affect everything from leadership decisions [5] to belief in climate change [6].<p>I point this out because all too often Engineers hyper-focus on technical details and forget to step back and consider a wider array of factors and impacts - which, ironically, is what cognitive complexity is all about. It&#x27;s the ability of a person to think about more things in a deeper way. Basically, cognitive complexity is a way to talk about not just things, but people.<p>We also have a tendency as Engineers to try to treat everyone and everything as a blob. We have to design our language in X way, because <i>all people</i> supposedly work in the same way, or think the same way. Or we have to manage our code in a certain way, because <i>all the team members</i> are assumed to work better that way (usually in whatever way is either easier or simpler).<p>One thing I wish people would take away from this, is that not only is cognitive complexity actually useful (it describes how language is able to work at all), but some people are better at it than others. So &quot;avoiding cognitive complexity&quot; is, in many ways, <i>a bad thing</i>. It&#x27;s like avoiding using language to convey ideas. Language and communication is hard, but you&#x27;re reading this right now, aren&#x27;t you? Would you rather a pictogram?<p>[1] <a href="https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cognitive_complexity" rel="nofollow">https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cognitive_complexity</a> [2] <a href="https:&#x2F;&#x2F;www.jstor.org&#x2F;stable&#x2F;2785779" rel="nofollow">https:&#x2F;&#x2F;www.jstor.org&#x2F;stable&#x2F;2785779</a> [3] <a href="https:&#x2F;&#x2F;pubmed.ncbi.nlm.nih.gov&#x2F;11014712&#x2F;" rel="nofollow">https:&#x2F;&#x2F;pubmed.ncbi.nlm.nih.gov&#x2F;11014712&#x2F;</a> [4] <a href="https:&#x2F;&#x2F;testing123.education.mn.gov&#x2F;cs&#x2F;groups&#x2F;educ&#x2F;documents&#x2F;basic&#x2F;mdaw&#x2F;mdaw&#x2F;~edisp&#x2F;000089.pdf" rel="nofollow">https:&#x2F;&#x2F;testing123.education.mn.gov&#x2F;cs&#x2F;groups&#x2F;educ&#x2F;documents...</a> [5] <a href="https:&#x2F;&#x2F;deepblue.lib.umich.edu&#x2F;handle&#x2F;2027.42&#x2F;128994" rel="nofollow">https:&#x2F;&#x2F;deepblue.lib.umich.edu&#x2F;handle&#x2F;2027.42&#x2F;128994</a> [6] <a href="https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;abs&#x2F;pii&#x2F;S0272494419300192" rel="nofollow">https:&#x2F;&#x2F;www.sciencedirect.com&#x2F;science&#x2F;article&#x2F;abs&#x2F;pii&#x2F;S02724...</a>
jedisct12 months ago
Rust.