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.

Want cleaner code? Use the rule of six

319 pointsby da12over 2 years ago

80 comments

kouteiheikaover 2 years ago
I don&#x27;t necessarily agree with the step of putting the code in a separate function; that often works, but just as often makes it so that the code can&#x27;t be read top-to-bottom anymore which hurts readability.<p>In this case there&#x27;s, I think, a better alternative; the equivalent-ish code in Ruby for the example code here would be something like this:<p><pre><code> values = s .partition(&#x27;?&#x27;)[-1] .split(&#x27;&amp;&#x27;) .map { |key_value| key_value.partition(&#x27;=&#x27;)[-1] } </code></pre> You can write these nice functional pipelines where you just read the code top-to-bottom and see step-by-step what is being done to the data on each line. You don&#x27;t have to jump up-and-down around the code when reading it, and you don&#x27;t have to keep too much context in your head when reading it.<p>This is one of the reasons why I vastly prefer Ruby over Python for most data processing tasks. I wish more languages would support this style of programming.
评论 #32964540 未加载
评论 #32964515 未加载
评论 #32964445 未加载
评论 #32965290 未加载
评论 #32964350 未加载
评论 #32966233 未加载
评论 #32964332 未加载
评论 #32965213 未加载
评论 #32964444 未加载
评论 #32969961 未加载
评论 #32969649 未加载
评论 #32966756 未加载
评论 #32964516 未加载
评论 #32966339 未加载
评论 #32969502 未加载
评论 #32965418 未加载
评论 #32968608 未加载
评论 #32966345 未加载
jiggawattsover 2 years ago
Now I know where Rust got some of its syntax from...<p>As an aside, when I see samples like this, it makes me <i>itchy</i>. I hope and assume that they&#x27;re being used as made-up snippets just to illustrate a point, and aren&#x27;t being lifted from an actual codebase.<p>Because... <i>ugh</i>... isn&#x27;t it obvious? Attacker-controlled input such as URLs should never be manipulated with naive string processing! Always use a proper parsing library. Not to mention that complexities of URL encoding, character escapes, etc...<p>The problem is that the author is using abstractions at the wrong level, with or without his fixes. The correct solution would be something like:<p><pre><code> var uri = new Uri( &quot;http:&#x2F;&#x2F;foo&#x2F;demo?test=a&amp;blah=b%20c&quot; ); var map = System.Web.HttpUtility.ParseQueryString( uri.Query ); Console.Out.WriteLine( &quot;is blah equal to &#x27;b c&#x27;?\n{0}&quot;, map[&quot;blah&quot;] == &quot;b c&quot; ); </code></pre> The above example is C#, but similar code can be written in any language. It&#x27;s simple, direct, and doesn&#x27;t violate the &quot;rule of six&quot;. It can be read like English:<p>1. Construct a URI from a given string.<p>2. Parse the query part of the URI into a map.<p>3. Test if the &#x27;blah&#x27; value in the query is &quot;b c&quot; as expected, with the escaped space decoded properly.<p>The example of how to apply the &quot;MORF&quot; rule in the article <i>still</i> has low-level operations involved, which doesn&#x27;t make the code more readable. It doesn&#x27;t describe the <i>intent</i>, which is the key thing to writing code that doesn&#x27;t need comments every second line.
评论 #32979745 未加载
评论 #32966895 未加载
didibusover 2 years ago
What the author is missing is that easy to read&#x2F;reason&#x2F;understand about is within the context of making a change to the code to fix a bug, add a feature or make some non-functional improvement to it.<p>This is what most of the &quot;easy to read&quot; articles forget.<p>Show me why it is easier to fix a bug, add a feature or make a non-functional improvement to the code with their style than without.<p>For example, if you&#x27;ve extracted something into its own function, are you then sharing this function and using it in other places as well? If you then change the body of that function, are you now possibly breaking other parts of the code that relied on its old behavior?<p>If you&#x27;ve introduced a local mutable variable in between two lines, are you then mutating that variable prior&#x2F;later? Is the query_params different at the end of the function then in the middle? Can you safely use it again?<p>How easily can you now introduce new behavior before, in the middle, after, and anywhere in-between?<p>When you modify the behavior to fix a bug, add a feature or make a non-functional improvement, is it an isolated change? How many tests break? Did it require major refactoring to make or very few things had to change? How easy was it to add a test for your new behavior? Was it easy to find the most appropriate place in the code to make the change? Etc.<p>Sure sometimes maybe you just read code for the fun of understanding what it does, but almost always in practice when you&#x27;re working on a code base, you only care to understand and reason about the code because you&#x27;re looking to deliver that next sprint task that involves changing something about it.<p>I wish more people focused on &quot;easy to change&#x2F;modify&quot; then simply on &quot;easy to read&#x2F;understand&quot;.
评论 #32984348 未加载
评论 #32965645 未加载
aaronbrethorstover 2 years ago
My opinion is that maintainable code is written first for reading by humans and second for executing by computers.<p>Unless I&#x27;m writing throwaway prototype code (famous last words, lol), I try to write code such that I will be able to figure out what my intention was 6-18 months from now when I&#x27;m staring at a piece of code in a panic trying to debug a production issue.<p>That doesn&#x27;t mean I&#x27;m going to get it right when I write this code. Instead, I&#x27;ll be able to better ascertain what my assumptions were, how they fell apart in practice, and what a minimal, correct fix that doesn&#x27;t make things worse might be.<p>Edit: Incidentally, this also applies to my commit messages. I’m writing them primarily for my future self so that I can figure out WHY I made a change, not WHAT the change was.
评论 #32970141 未加载
评论 #32966520 未加载
评论 #32967050 未加载
noncomlover 2 years ago
We break everything down and then we reach one of the most difficult problems in software engineering: Coming up with good and short names for all these extra intermediate variables and functions.
评论 #32964387 未加载
评论 #32964739 未加载
评论 #32964180 未加载
评论 #32964239 未加载
评论 #32964999 未加载
评论 #32968786 未加载
评论 #32964446 未加载
bloafover 2 years ago
I have pretty mixed feelings about this. Personally I find it much easier to debug code that:<p>1) fits entirely on my screen and<p>2) doesn&#x27;t involve much state modification<p><i>Every</i> intermediate variable is a chance for me to miss some modification (e.g. it was passed to a func that modifies its arguments) and consequently misunderstand what is happening.<p>I&#x27;ve been experimenting in Python with the function chaining style of coding enabled by the toolz library. So while not at all idiomatic, the example in the original article would come out as something like this:<p><a href="https:&#x2F;&#x2F;gist.github.com&#x2F;ZeroBomb&#x2F;8ac470b1d4b02c11f2873c5d4e0512a1" rel="nofollow">https:&#x2F;&#x2F;gist.github.com&#x2F;ZeroBomb&#x2F;8ac470b1d4b02c11f2873c5d4e0...</a><p>I would say that function-chaining this example would constitute over-engineering, but I have found that writing in this style has really helped me express pretty complex function composition in a way that is still concise without using a bunch of intermediate variables.
评论 #32966503 未加载
评论 #32969774 未加载
overgardover 2 years ago
This really resonates with me. I remember when I started programming (at like 10 or so), my dad tried to teach me Smalltalk. Smalltalk is a great language, but there were just too many concepts and abstractions happening on each line of code. To understand even basic code required understanding messages, objects, classes, blocks, etc. Maybe to an 18 year old that would have been ok, but for my 10 year old brain it was too much.<p>A few months later though, I started with QBASIC. BASIC of course gets an awful rap, but it was so much more intuitive for me at the time. I started out with just global variables and GOTO&#x27;s everywhere. Over time, I worked up to loops, and subroutines, etc. etc. However, the simplicity of &quot;program runs one line at a time, each line does something obvious&quot; was incredibly important to beginner-me.<p>Even once I moved to C, when I was an amateur I still had a tendency towards one line per thing happening. I really hated code like<p><pre><code> while(i++ &lt; 10) { doSomethingWith(i); } </code></pre> (Actually, I still do).<p>As I got more sophisticated in my 20s, I started packing a lot more ideas into a single line. If I&#x27;m being perfectly honest, I think some of it was just showing off. You certainly look clever if you can put 3 list comprehensions on one line or use some of the more advanced collections apis. However, besides understandability, I found that style of code had two really big problems:<p>1) It&#x27;s a lot harder to debug. Either you can&#x27;t get a breakpoint in the precise place you want, or you can&#x27;t insert a print statement easily into a complex expression, or iteration variables become implicit and you lose context.<p>2) It&#x27;s hard to add error handling to that type of code. When a lot of things happen in a complex expression, you&#x27;re depending on the entire expression working.<p>Luckily I&#x27;ve grown out of that phase, although ironically now my much more mature code looks a lot like the very simplistic code I wrote as a teenager.
评论 #32965903 未加载
stagasover 2 years ago
Another useful rule is to think it terms of intentions and split to those individual intentions. You can always reduce code down to a single function call, but was that the original intention? Try to think as a reader that just stumbled on it without any other context. `result = DoEverything(payload)` is often less readable than `step1Result = DoImportantStep1(payload); finalResult = DoImportantStep2(step1Result);` if Step1 and Step2 mirror the actual process that goes in your mind when solving that particular problem, so when re-visiting you can understand what&#x27;s going on faster, without having to visit the implementation of the single `DoEverything` function.<p>Edit: To clarify a bit more, in contrast to the rule of six, i&#x27;d definitely keep a line that is more complex than usual but conveys the intention of my thinking, rather than splitting it to multiple lines and losing that important information, losing the original intention.
rzimmermanover 2 years ago
“Rule of six” is generally interesting - I came upon the concept when reading the book “Nightfall” by Isaac Asimov as a kid. There’s a line in the book about the number of stars in the sky, and how people can’t really grasp numbers more than 5-10. It got me thinking about trying to visualize a set of 3, 4, or 5 distinct objects without splitting them into groups. I genuinely can’t do it for more than 5 or 6 of something.<p>I also remember reading about a study where chess masters and non-experts were asked to memorize chess boards. Average people could only remember 5-7 piece locations where chess masters could remember the entire board. But when the piece layout was random (rather than from real chess matches) the experts weren’t much better than the non-experts. It’s speaks to the abstractions our brain creates to deal with limited working memory.<p>That cumbersome line of python is a good example. As an experienced python person, I immediately found myself giving names to the chunks to understand it.<p>Overall very good advice. Your code should explain the steps it takes to solve a problem (or in a more functional language, explain the solution), not be as terse and clever as possible. Keystrokes are cheap; thinking is expensive.
WastingMyTime89over 2 years ago
It’s funny because what I found confusing initially reading the code is the behaviour of <i>split</i> and I still do after the article. I know see that this is because the article uses a magic value and magic values are the bane of readability.<p>See, the first <i>split</i> use made me think it always returned the left and right part after splitting at the first match - 0 being left and 1 right. This is not the case. The code implicitly relies on this being a url.<p>But then the second <i>split</i> is accessed with the weird [-3:] which I have to assume to mean the last 3 elements. I assumed then that <i>split</i> must return a list but started wondering: why 3 elements only? I still don’t know. I wasn’t helped by the single letter named variables either.<p>I think people might want to focus on the basics before venturing into grand consideration about splitting lines and putting code in function. The one liner with proper names is too long but understandable:<p><pre><code> last_three_url_param_values = lambda(query_string: query_string.split(‘=‘)[1], url.split(‘?’)[1].split(‘&amp;’)[-3:])</code></pre>
longrodover 2 years ago
If you are going for human readability then making your code expressive is the only way. Abstract away the code parts under a layer of very simply named functions&#x2F;classes and boom! even a child will be able to understand what&#x27;s going on.<p>Obviously, that isn&#x27;t always possible. I find this approach especially useful in writing e2e browser tests. You write an abstraction over the testing framework&#x27;s (playwright, puppeteer etc) interaction and then use that in your tests.<p>So instead of writing:<p><pre><code> await page.click(&quot;.play-button&quot;); </code></pre> You do:<p><pre><code> await app.play(); </code></pre> This also has the benefit of extreme reusability. Doesn&#x27;t work for everything though.
jstimpfleover 2 years ago
I like how this article explains that &quot;clean&quot; must be &quot;readable for humans&quot;. However, the concerns raised are only superficial. It&#x27;s much more important to get the larger scale structure right. I recommend drawing diagrams and explaining the architecture to humans. Then again, I&#x27;m not saying overdo it, because some things are hard to draw, some are hard to explain. In the end, it&#x27;s important to get a complete understanding of a certain module, and the code should then be relatively easy to write.<p>I have learned to take a step back when I find myself having a hard time to get the code &quot;clean&quot;. Often I put that thing to rest if possible, maybe for days, months, or even years. There could be a simple solution that solves 80% of the problem, and that can ease the pressure coming from the stakeholders. If it kind-of-works and can be produced in a short time, that is much better than going down a rabbit hole for months, coming out at the other side (probably burnt out) with a solution you can&#x27;t deploy because it&#x27;s too complicated.
评论 #32964465 未加载
评论 #32965050 未加载
评论 #32964974 未加载
dcowover 2 years ago
This is why setting an arbitrarily short max line length matters. And consequently why auto-formatters suck.<p>A short line length, while yes imperfect, forces complex lines to be decomposed into individual concepts. And it allows the code to read like a book rather than &lt;there is literally no other media format that you read sideways&gt;. Ultra-wide monitors be damned.<p>And auto-formatters suck because they don’t split concepts onto individual lines. They can’t. They just mangle code and scrunch it into whatever space is allowed without regard to how the code reads. The idea of them is great and intensely alluring, but the implementation leaves much to be desired. If an auto-formatter could make my code look and read like a LaTeX document, I’d shut up already.<p>So if you want people to implicitly start structuring their code as advised in this post, set a 80 or 100 char line length. And adopt a fuzzy “one statement per line” philosophy.
评论 #32970005 未加载
hardwaregeekover 2 years ago
This seems perfectly reasonable advice. However I do wonder how many people actually struggle with this sort of code quality. It&#x27;s certainly more than a few, since I&#x27;ve encountered bad code with these issues. But it&#x27;s not exactly the most pressing issue either. As the author demonstrated, you can refactor this with a little thought. It&#x27;s the code equivalent of tidying your room, sweeping the floors and putting your stuff away.<p>Whereas the refactoring issues I&#x27;d love to learn more about are the equivalent of a sinkhole in your living room. Stuff like &quot;you have data dependencies that go in, out, left, right, and through the code&quot;, or &quot;the codebase is a mishmash of React combined with Vanilla JS that is hooked up to a custom PHP MVC&quot;. Basically refactoring that involves issues that cannot be cleaned up all at once, that involve deep architectural decisions and that require some amount of buy-in from the team.<p>Mostly I&#x27;d like to know more about this because I&#x27;ve realized that I&#x27;m not very good at it. My inclination is to just refactor everything and that&#x27;s not a feasible strategy. I also struggle to balance it with getting feature work done. Definitely something I plan on reading more about.
评论 #32964507 未加载
评论 #32964668 未加载
评论 #32969752 未加载
评论 #32964757 未加载
standardUserover 2 years ago
I see a troubling trend with some coworkers where they seem to stretch the limits of time and space to make every line as dense as possible, usually using lodash. I think it is a point of pride for them, but I think it&#x27;s obvious that everyone&#x27;s life would be easier if they just wrote their code out &quot;long form&quot; and, god willing, added some comments for various steps. Instead, I find myself having to re-write ultra-dense blobs of code in order to debug or even simply understand what&#x27;s going on.
评论 #32964245 未加载
评论 #32964084 未加载
评论 #32975388 未加载
评论 #32966222 未加载
评论 #32964205 未加载
评论 #32964195 未加载
iafiafover 2 years ago
Early in my career, I took to heart such books and articles and often felt guilty and lessor-programmer when I cut corners. Here&#x27;s my 2 cents now:<p>- Some of this is the coding equivalent of &quot;6 rules for financial freedom&quot; or &quot;6 ways to find your dream soulmate&quot;. Generic advice that doesn&#x27;t reflect highly nuanced reality.<p>- These rules are guidelines at best. There are justifiable reasons to break them; which I do often. Albeit this requires experience (and dare I say, wisdom). For example, refactoring code into a separate function levies a cost (of indirection) on the reader. Therefore copy-paste is sometimes fine.<p>- Clode &quot;cleanliness&quot; is a moving target. For a coder&#x27;s mental health and value proposition for his project, he&#x2F;she should know what code can afford to stay dirty.<p>PS: I love Jonathan Blow&#x27;s opinions on coding&#x2F;programming. Here are a few: <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=21JlBOxgGwY" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=21JlBOxgGwY</a> <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ubWB_ResHwM" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=ubWB_ResHwM</a> <a href="https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KcP1fXQv0iU" rel="nofollow">https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=KcP1fXQv0iU</a>
评论 #32964728 未加载
评论 #32965134 未加载
dan-robertsonover 2 years ago
I want code that is easy to read, write, update, and debug. It isn’t obvious that this means it should be ‘clean’, or indeed, what ‘clean’ is. Some other things described as clean code (eg uncle Bob) seem pretty bad to me. But then lots of people who complain about that also suggest things that seem bad. Perhaps lots of these things are too insignificant compared to other business or design decisions that one can’t really learn from experience or past successful or failed projects.
upsideDownBlueover 2 years ago
I enjoyed the article and agreed that working memory places a fundamental limit on the intelligibility of otherwise equivalent pieces of code. As a former psychologist with experience of memory research (though not quite this area), it might be useful to others if I add that:<p>- The size of the short-term store is normally said to be 7 plus or minus 2 (the &#x27;magic&#x27; number 7)<p>- The Working Memory model has somewhat overtaken the &#x27;short term&#x27; memory model, and it is unusual to see them being presented alongside each other like this (though &#x27;short term memory&#x27; remains a useful, good-enough metaphor for explaining certain key aspects of memory)<p>- Chunking is typically viewed as a memory-supported division of stimuli (what you&#x27;re reading, hearing etc.) into meaningful units based on LTM memory representations. A good example is a chess expert &#x27;chunking&#x27; the layout of a chess board with many pieces in perhaps one or two units (e.g. &#x27;It&#x27;s the mid game configuration of [famous players] in [famous game], except the king&#x27;s position is different&#x27;). We would expect more expert programmers to &#x27;chunk&#x27; increasingly large units, I think (e.g. &#x27;Oh, this is just the [famous sorting algorithm]&#x27;).<p>- A single chunk is usually considered to take up a &#x27;slot&#x27; in short term memory<p>If anyone wants papers&#x2F;sources for the above, let me know.
评论 #32964554 未加载
评论 #32965157 未加载
userbinatorover 2 years ago
Counterpoint: I&#x27;m sure most of us wrote far shorter sentences when we were learning our first (human) language, or perhaps even subsequent ones; yet now I suspect we can all read and write sentences with dozens of words.<p>Yet when it comes to programming languages, the majority of &quot;advice&quot; seems to be about absolute dumbing-down and propagating an attitude of &quot;it&#x27;s too hard, you can&#x27;t possibly learn, just give up&quot;?<p>I&#x27;ve always wondered about this dichotomy. Some languages like the APL family appear to have gone far into the &quot;it&#x27;s a language, to be learned like any other&quot; territory, while more &quot;mainstream&quot; ones are drifting further in the opposite &quot;don&#x27;t even bother trying harder&quot; direction.<p>Kernighan&#x27;s Lever: <a href="http:&#x2F;&#x2F;www.linusakesson.net&#x2F;programming&#x2F;kernighans-lever&#x2F;index.php" rel="nofollow">http:&#x2F;&#x2F;www.linusakesson.net&#x2F;programming&#x2F;kernighans-lever&#x2F;ind...</a> (look at the rest of his site; he has clearly leveraged that attitude with great success)<p>(I looked at the one-line example in Python and, despite having <i>very</i> little experience in the language, it was actually faster to read and understand as a whole than the 3-line version.)
hirundoover 2 years ago
I know it was just used as an example, but in reality when I see code like this I think &quot;I really don&#x27;t want to reinvent URL parsing for this, I&#x27;ll import the library for that instead,&quot; resulting in much cleaner code.<p>But I do agree on keeping individual lines, if not entire statements, small and simple. The ruby chainsaw is a great tool for that. I find a chain of simple statements arranged in a flow to be more readable than using lots of intermediate variables.
quickthrower2over 2 years ago
This seems a little light to me, doesn’t give me the feeling of being written by a veteran coder. Unless the idea is to dumb it down for a particular audience.<p>The real answer is write code like you write words: Rework it to make sense to the reader. How many newlines you need as a hint for your editor to wrap and where you put them will fall out of that.<p>Or autoformat! I love autoformatters!<p>Edit: edited to make easier to parse mentally.
lbrinerover 2 years ago
Perhaps a more helpful principle I heard a long time ago was that all methods are <i>either</i> a specific method doing a specific thing (like splitting up a string) <i>or</i> they call a series of methods of the first type. When we mix the two, it becomes harder to reason since type 1 is generally logically complex, so keeping these small makes them testable and readable, and the logic of the high level is more easily encapsulating as a series of DoThis(), DoThat(), ThenDoThat() calls.<p>If I&#x27;ve only helped one person today, it was worth it ;-)
评论 #32964524 未加载
RajT88over 2 years ago
I have written a lot of Powershell in the last few years. I eschew the clever powershell ways of doing things if someone else <i>may</i> end up owning it (think: where-object, foreach-object) in favor of expressions that resemble other languages (foreach, for).<p>If I&#x27;m writing it for myself, and only ever myself, I&#x27;ll use the more clever powershell ways of doing things. Expressions like:<p>1..10 | % {$_}<p>If you&#x27;re coming from another language, you&#x27;re going to have to run it to understand it, or look it up. That is time lost.
评论 #32964599 未加载
评论 #32964283 未加载
happyweaselover 2 years ago
use statically typed programming languages. Favor composition over inheritance . Develop bottom-up (reusable classes) instead of large-scale up-front design. SOLID principles (SRP being the most important). The Bottom-up approach also favors Unittesting. Code reviews, clear code formatting rules (simple editor plugins do the trick). Use static code analyzers. IMHO this kind of object-oriented programming leads to NEW code being written to implement features and NOT old code being tampered with. Ideally, the (tested) units of code (classes) have such clear responsibility that you do not have to touch them once they are implemented. If Super-classes begin to emerge, refactor.
评论 #32966281 未加载
评论 #32968449 未加载
评论 #32965292 未加载
davesqueover 2 years ago
I&#x27;m sure there are specific programs that would benefit from a treatment from these rules. However, there&#x27;s one thing pretty fundamental to this article that I have a hard time agreeing with. And that is the notion that there are these three different memory types, two of which can only store &quot;4 to 6&quot; things.<p>I&#x27;m inclined to believe that there are probably many gradations of long vs. short term memory in the structure of the brain. In fact, I bet the gradations even vary by topic and of course depend on what sorts of tasks a person is accustomed to performing from day to day.<p>I imagine that the &quot;4 to 6&quot; figure fell out of a study that aggregated a large amount of data collected across subjects and that the figure itself can&#x27;t capture much of the nuance or even the nuance of cohorts.<p>In other words, it may very well be that a large percentage of people who work professionally as software developers are capable of keeping more than 4 to 6 &quot;facts&quot; about code they&#x27;re looking at in their head. But that they would also appear to have the same capacity as random people when it comes to arbitrary facts that one would be asked to memorize in a psychological study.
tgvover 2 years ago
The starting assumption is highly dubious: &quot;Short lines of code require less brainpower to read than long ones.&quot;<p>I&#x27;m not going to nitpick the incredibly bullshitty term &quot;brainpower&quot; and what is less and if that&#x27;s actually advantageous, but if you write short lines of code, you&#x27;re going to write more lines, which requires &quot;more brainpower&quot; to understand. You don&#x27;t simply &quot;chunk&quot; lines in memory. If that were true, you could just as easily chunk function calls.<p>That memory plays a role is fairly certain. There is a pretty hard finding from psycholinguistics: it&#x27;s hard to understand nested structures. The sentence &quot;the rat the cat the cook hit chased escaped&quot; is much harder to understand than it&#x27;s right-branching equivalent &quot;the cook hit the cat that chased the rat that escaped&quot;. However, reading code is not the same as reading natural language.<p>If you want to know if what you wrote is understandable, try reading your code without falling to back to remembering <i>why</i> you wrote it. Try to read <i>what</i> you wrote. Wait a few days if your recollections get in the way.
d_burfootover 2 years ago
Split Into Multiples Lines has a real problem, which appears in the example code.<p>Let say you have a long code block that includes the revised snippet:<p>&gt; query_params = s.split(&#x27;?&#x27;)[1].split(&#x27;&amp;&#x27;)[-3:]<p>&gt; mylist = map(lambda x: x.split(&#x27;=&#x27;)[1], query_params)<p>&gt; ...<p>&gt; ...<p>&gt; (some more complex transformations, that only depends on mylist)<p>When you&#x27;re reading the later stages of the code, you still have to maintain a memory of what &quot;query_params&quot; does, even though it&#x27;s no longer relevant. That actually increases the burden on your working memory. The one-liner is more complex to understand initially, but it self-documents that the only info that is relevant to the downstream is the result of the map(...).<p>In general, the more variables that are declared in a code block, the more effort it is to understand, and the effect is probably superlinear with the number of variables. I&#x27;d say if you have to declare more than 5-6 variables, you should split into a separate function.
im3w1lover 2 years ago
Give mysterious things room. In this case the most mysterious is [-3:]. That, together with the split, should have it&#x27;s own line or maybe even multiple (function declaration, comment).
评论 #32964264 未加载
评论 #32966367 未加载
jollybeanover 2 years ago
I object to the &#x27;re-write as function&#x27;.<p>Functions come with abstraction overhead. You don&#x27;t know who will consume them, so you may have to put up type checks, null checks other BS.<p>Also - functions split up the logic all over the place, it&#x27;s confusing.<p>I think what we need are &#x27;nested functions&#x27; which serve to kind of create a scope pushed to the stack - with an implicit &#x27;return&#x27; - which we can then &#x27;collapse&#x27; in the GUI etc..<p>I mean, it&#x27;s purely cosmetic from a CS point of view, but it might help to organize things a bit better and hand off abstractions in long function implementations.<p>Huge projects with 1 or 2 line functions drive me crazy - you have to constantly jump around all over place to figure out what&#x27;s going on. I actually believe it&#x27;s a historic anti-pattern.<p>I make functions when we need 1) used in different places 2) meaningful abstraction.<p>Otherwise, well documented longer functions for me.
ppieraldover 2 years ago
If there is some legitimate reason (say performance) to keep a tighter form (inline assembly, Python 1-liner, whatever), then making the unfurled equivalency as a comment nearby to allow the next developer to have a fighting chance would be really helpful. Also, error handling tends to be not included in the 1-liners.
rekrsivover 2 years ago
The original code is perfectly readable until it does something completely unexpected, and the human parser has to start over to make sure they didn&#x27;t miss anything. But unfortunately, the context for that &quot;get the last 3 parts specifically&quot; is never explained, so the entire line never makes sense. The human has to think a lot to come up with an (hopefully correct) explanation for the &quot;why&quot;.<p>The solution isn&#x27;t to extract every token from the expression to separate lines, but to document the &quot;why&quot; of the unexpected token. That can take many forms: a new variable <i>with a meaningful name</i>, a new function <i>with a meaningful name</i>, or a meaningful comment that warns the reader about the upcoming reason for getting just the last 3 parts.
twblalockover 2 years ago
The &quot;bad&quot; Python code in that example is perfectly fine. I&#x27;m not a Python programmer but I can read Python a little bit, and the example uses basic programing concepts like string splitting and array ranges.<p>If you don&#x27;t understand that, multiple smaller lines won&#x27;t help you, because you just don&#x27;t know what you are doing.<p>In addition, that code example is easily testable. Testability is more important than readability in modern programs that follow modern CI&#x2F;CD principles -- and the readability is not really that bad either. Also, modern debuggers don&#x27;t have issues with nested&#x2F;lambda statements like these.<p>If the article&#x27;s author had a legitimate bone to pick, they would have better examples.
评论 #32966590 未加载
评论 #32966644 未加载
irrationalover 2 years ago
This is the main reason I don’t like arrow functions in JavaScript. People overuse them to create “clever” code - lots of things going on in a single line. Then they try to claim that by having everything on a single line the code is easier to read and understand.
cc101over 2 years ago
If I use elaborate camel-case variable names, it seems to reduce the load on my short-term memory because I don&#x27;t have to remember what a variable name represents. It&#x27;s meaning is there when I need it and can be forgotten otherwise.
Waterluvianover 2 years ago
I flexibly agree with the “does one thing” approach. But what a “thing” is can be up to you.<p>Sometimes my one thing is “turns a Json file into an in memory dictionary” which might be three operations on one line.
jonnycomputerover 2 years ago
Then you have to <i>name</i> things. And naming things sucks, especially because not every intermediate has an obvious name for it, distinct enough to distinguish it from the next intermediate chunk.
评论 #32965532 未加载
gilchover 2 years ago
At least for the contrived example from the article, the solution isn&#x27;t to break up the code, but to use denser code. Use a regex.<p>Does anybody really think that e.g. sregex[1] is better than just learning and using the regex language directly? Because that&#x27;s where this kind of thinking leads.<p>[1]: <a href="https:&#x2F;&#x2F;github.com&#x2F;jwiegley&#x2F;emacs-release&#x2F;blob&#x2F;master&#x2F;lisp&#x2F;obsolete&#x2F;sregex.el" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;jwiegley&#x2F;emacs-release&#x2F;blob&#x2F;master&#x2F;lisp&#x2F;o...</a>
评论 #32965840 未加载
评论 #32965360 未加载
skitterover 2 years ago
In this case `query_params` works well, but it&#x27;s sometimes hard to find descriptive and reasonably concise names for the intermediate value. In those cases, the ideal would be using only postfix chaining, so that you can read it by only keeping the intermediate value and the next operation in mind:<p><pre><code> s.split(&#x27;?&#x27;)[1] .split(&#x27;&amp;&#x27;)[-3:] .map(lambda x: x.split(&#x27;=&#x27;)[1]) </code></pre> Unfortunately, that&#x27;s not how Pythons map(), len() and such were designed.
评论 #32964652 未加载
xigoiover 2 years ago
When I clicked on “More settings” in the cookie dialog, it displayed a loading animation (ignoring my prefers-reduced-motion setting) and got stuck. Just straight-up user-hostile design.
3pmover 2 years ago
Reminded me of &#x27;Object Calisthenics&#x27; by Jeff Bay. Basically an exercise for a toy project where you adhere to 9 rules:<p>1. Only One Level Of Indentation PerMethod<p>2. Don’t Use The ELSE Keyword<p>3. Wrap All Primitives And Strings<p>4. First Class Collections<p>5. One Dot Per Line<p>6. Don’t Abbreviate<p>7. Keep All Entities Small<p>8. No Classes With More Than Two InstanceVariables<p>9. No Getters&#x2F;Setters&#x2F;Properties<p><a href="https:&#x2F;&#x2F;williamdurand.fr&#x2F;2013&#x2F;06&#x2F;03&#x2F;object-calisthenics&#x2F;" rel="nofollow">https:&#x2F;&#x2F;williamdurand.fr&#x2F;2013&#x2F;06&#x2F;03&#x2F;object-calisthenics&#x2F;</a>
评论 #32965150 未加载
评论 #32965274 未加载
评论 #32970084 未加载
gilchover 2 years ago
The article starts with some reasonable premises, but the conclusion does not follow.<p>I think most APL programmers would disagree with this take. Dense code has real advantages, and naming everything has real costs that are hard to see. There&#x27;s nothing magic about a &quot;line&quot; that suddenly allows for chunking. You have to build a parse tree in your head in any case.<p>I&#x27;m reminded of Doug McIlroy&#x27;s challenge to Knuth.[1] It&#x27;s worth a read. Would you rather have 6 lines of dense shell, or 10 pages of Fabergé egg? I&#x27;ll take the shell, thanks.<p>Look at the source code for J (an APL derivative)[2]. It&#x27;s written in C, but that C was written in APL style by APL programmers. Lines leverage macros and 1–2 character names, making them extremely dense. Some files have a comment on nearly every line. For an average C programmer, this code looks absolutely insane. But it&#x27;s <i>not</i>. The J devs find this perfectly readable and maintainable. It&#x27;s clean code! If written with the typical C idioms, it could easily be 10x as long, and therefore <i>harder</i> to maintain. Your first impression is a snap judgement due to a difference of culture. You can learn to read this style with practice. Whatever your current style, that took practice too.<p>[1]: <a href="http:&#x2F;&#x2F;www.leancrew.com&#x2F;all-this&#x2F;2011&#x2F;12&#x2F;more-shell-less-egg&#x2F;" rel="nofollow">http:&#x2F;&#x2F;www.leancrew.com&#x2F;all-this&#x2F;2011&#x2F;12&#x2F;more-shell-less-egg...</a><p>[2]: <a href="https:&#x2F;&#x2F;github.com&#x2F;jsoftware&#x2F;jsource" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;jsoftware&#x2F;jsource</a>
评论 #32965447 未加载
jwilliamsover 2 years ago
All comes down to good naming in the end. The craft is finding both compact and specific names.<p>I think the mantra for all names to be short can be counterproductive here. If the code span of a variable is short, a long name can be fine (and very clarifying, perhaps even resulting in a comment not being needed).<p>Shorter names for longer spans are much better. But you’d hope they’re the very obvious subject of that span.
dasil003over 2 years ago
Although I agree the original line is a bit long, and the first refactoring is a clearly more readable, but after that it starts to feel like bike-shedding. FWIW I don&#x27;t believe in refactoring things into tiny methods that are just used once—it&#x27;s a lot of boilerplate which makes zero sense if you are not going to reuse it, but it&#x27;s not the hill I&#x27;m going to die on.<p>Overall a lot of this boils down to minor style issues. I care very little if you give me 5 short lines with named intermediate steps versus a dense one-liner, however I do care very much if your code leverages pure functions, minimizes cyclomatic complexity, encapsulates messy bits, and has some form of test coverage. The former might take me a minute or two longer to grok (depending on my personal context), but the latter compounded over a wide surface area can lead to a completely unmaintainable system and a pathological fear of touching anything.
Krasnolover 2 years ago
Your cookie banner &quot;manage settings&quot; thing never stops loading.
评论 #32966203 未加载
hedoraover 2 years ago
I think this article is missing the forest for the trees.<p>I&#x27;ve found that dividing software into layers, and making sure that each file relies on the same set of invariants from its dependencies, and also maintains a (different) consistent set of invariants for its callers works much better.<p>For instance, I&#x27;d prefer a function that takes a string and confirms it is a valid URL.<p>That would delegate to URL character esacaping logic and DNS validation. (Are &amp; or ? valid DNS name characters? Will they be in the future? I neither know nor care.)<p>On top of that, there would be a parser for key=value config file lines.<p>Then, the example in the article becomes something like:<p>keyvalue = parseConfLine(input)<p>URL(keyvalue.value).params[-3]<p>Plus a few more lines to confirm key is as expected and that value has enough query parameters.<p>Alternatively, I&#x27;d use a perl oneliner with a regexp. I see no purpose for code that lands in the middle ground between these extremes.
mkoubaaover 2 years ago
A reviewer can usually tell which code is easier to understand side by side, even when it&#x27;s yourself as the reviewer.<p>Applying rules like these to your code may or may not result to cleaner code, but that&#x27;s a testable hypothesis.<p>I&#x27;ve seen all too often some clean code recommendation or other applied to code and it gets harder to understand. And the person doing the refactoring (often myself) gets caught in sunk cost.<p>Now my recommendation is always:<p>1. Use your intuition to predict if a change makes code cleaner.<p>2. Try to make that change, and be open to doing things a little differently that you first imagined.<p>3. Test your hypothesis to see what others think. Decide what to do, but be mentally willing to throw it away.<p>4. Repeat<p>Articles like this are good resources to help train your intuition, but there is no substitute to developing your personal and team &quot;flavor profile&quot; for what styles suit your way of thinking.
GuB-42over 2 years ago
Writing &quot;clean&quot; code is more of an art form, you can&#x27;t really have easy rules.<p>I think the general idea is that clean code is short code, that&#x27;s the base guideline. Generally shorter code does less things, reducing cognitive load. It may also have performance benefits. It also takes less space on-screen, which is also a good thing: less scrolling, ability to use bigger, more readable fonts, etc... And as explained, short-term memory is limited. Short code also tends not to repeat itself, another common advise.<p>But that&#x27;s the baseline, all the art is in appropriate breaking of that guideline, to have short code that doesn&#x27;t look like it came out of a minifier.<p>Splitting lines makes longer code, bad, but sometimes it is justified. So what is your justification? The article focuses on &quot;one liners&quot; being hard to understand, but really, it depends on many things. For example you may use a longer form if you think that it is an essential part of your code and it is critical that you should pay attention to it. On the other hand, you can use a shorter form if it is a common pattern, what is &quot;common&quot; depends on who is going to read your code, or the project you are working on. For example, bit manipulation can make a good part of your code base, or be a one-off thing and it will have an influence on how you write that code.<p>Moving code into functions is generally a good thing if that function is used often (shorter code). I think it is the origin for the term &quot;refactoring&quot;: factoring ax+bx+cx+dx becomes x(a+b+c+d), only a single &quot;x&quot; remains and it is shorter. But if that function is only called once, of if the operation is hard to extract from its context, it can lead to longer, harder to understand code, and again you have to exercise judgment. For example you may want to write a specific function because it is a tricky, specific part that you want to separate from the boilerplate. There are interesting considerations to using functions, because it actually reorders code, for example &quot;a(){do_x}; do_y; a(); do_z&quot; is written as x,y,z and does y,x,z, which is often, but not always unintuitive.
catlifeonmarsover 2 years ago
The examples and improvements in the article feel obvious like “common sense” — which is a good thing. I’m not 100% sold on the reasoning though. It kind of feels like a just-so explanation without much justification
soulofmischiefover 2 years ago
&gt; STM and WM are small. Both can only store about 4 to 6 things at a time!<p>I&#x27;m sorry but this is such an asinine statement. Your brain doesn&#x27;t store &quot;things&quot; and the number of working items depends on so many factors the complexity of the information, the level of association between items, the attention span of the individual, which can be trained, and a multitude of other things.<p>Neuroscience is a useful tool for self-programming but you must be careful peddling absolutist statements like this which can do more harm than good.
geeweeover 2 years ago
I&#x27;m really tired of hearing the 4 items +&#x2F;- 2 being parroted around in cases like these. The studies that come to that number are basically &quot;Remember these completely arbitrary things such as numbers or words in order&quot;. That&#x27;s nothing like reading lines of codes where you have variable names, and you&#x27;re able to construct meaning and relationship between the things in your mind.<p>Sure, it might be relevant if all variables were named &quot;x&quot;, &quot;xx&quot;, &quot;xx&quot;, - but they&#x27;re not.
avnigoover 2 years ago
A map lambda example is what I had in mind when reading the article. I&#x27;m not a big fan of the temporary variables, though.<p>Admittedly the example below is not a perfect solution, but that&#x27;s where I thought the article was heading when splitting that code over multiple lines for readability.<p><pre><code> map( lambda x: x.split(&#x27;=&#x27;)[1], (url .split(&#x27;?&#x27;)[1] .split(&#x27;&amp;&#x27;)[-3:] ) ) </code></pre> Is this still too unreadable or more messy?
meitrosover 2 years ago
This seems like an interesting heuristic for anything that could automatically either generate or &quot;format&quot; code - a little more semantic than just relying on a text parser
评论 #32963874 未加载
shadowofneptuneover 2 years ago
As other people have noted, this seems like a criticism of expression-heavy languages. I&#x27;m not sure the working memory idea really is a good argument for short lines. Assembly language is entirely short statements, and has only a few operands per line, but is so tedious to read because of how much state&#x2F;working memory is occupied. Complex expressions can actually reduce the mental overhead by reducing the number of used variables to a minimum.
Beltirasover 2 years ago
Can&#x27;t get past the obnoxious cookies. Anyone have the text?
schemathingsover 2 years ago
For the example in the text I&#x27;d typically just include a one line comment above to show what an example string would look like and leave the code as is<p># URL with params <a href="https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32963021&amp;something=value1&amp;something=value2" rel="nofollow">https:&#x2F;&#x2F;news.ycombinator.com&#x2F;item?id=32963021&amp;something=valu...</a><p>map(lambda x: x.split(&#x27;=&#x27;)[1], s.split(&#x27;?&#x27;)[1].split(&#x27;&amp;&#x27;)[-3:])
charles_fover 2 years ago
Ok, quick rules that focus on single lines. That&#x27;s neat, but from experience most of the complexity comes from the structure more than just how the code is written, conventions about how to write a line of code won&#x27;t fix corrupt indirections, misplaced coupling, lack of cohesion, undue repetitions, missing tests, etc.<p>Clean code is not just a few rules about how to write a line. You can write nice lines that still don&#x27;t make sense and amount to shit code
评论 #32964550 未加载
xfzover 2 years ago
I can&#x27;t access the linked page without accepting cookies.
评论 #32965173 未加载
kazinatorover 2 years ago
This rewrite is more performant than the original:<p><pre><code> query_params = s.split(&#x27;?&#x27;)[1].split(&#x27;&amp;&#x27;)[-3:] map(lambda x: x.split(&#x27;=&#x27;)[1], query_params) </code></pre> The calculation of query_params, having no dependency on the lambda parameters or anything being mutated, has been lifted out of the lambda, and thus spared from repeated execution by map. The compiler for that language won&#x27;t do this automatically.
评论 #32965015 未加载
michaelwwwover 2 years ago
If you&#x27;re like me and like to step through code with a debugger, shorter lines are better for setting breakpoints and checking values.
评论 #32966343 未加载
AtlasBarfedover 2 years ago
The issue is that short code lines increases the length of code aka wastes vertical screen reasl estate aka visible code, so you&#x27;re overburdened short term memory has to context switch to scroll.<p>&quot;Simple, put code in small methods&quot;<p>Oh great, now I do a nav jump or a string search as a context switch rather than scroll.<p>Comments? increase vertical screen pollution.<p>Proper chunking is hard.<p>Maybe APL was right.
djmipsover 2 years ago
Coming from a background in lower level languages where you can only express one simple thing per line my tendency has always been to be more verbose than my colleagues. The worst time I ever had was when I had to work on someone&#x27;s Perl code that one time. So I really like this heuristic to make code more readable.
artemonsterover 2 years ago
I always liked the quote &quot;you need to be twice as smart to debug a code. If you write smart code, you, by definition, cannot debug it&quot; (sorry I have no idea who said this). This is why I still code in C. No smartass bullshit, just plain old undefined behaviour and out of bounds access. Lovin it.
评论 #32964580 未加载
ravenstineover 2 years ago
The main reason I stopped using the old school for loop in JavaScript is that it&#x27;s doing too much in a single line. If I can&#x27;t do for-of, I much prefer a while loop because it does effectively the same job as for-in but each step gets its own line. I find it easier to follow at a glance.
pavonover 2 years ago
Never cleaned up the most obtuse part of that code snippet - why are we only keeping the last three parameters?
评论 #32964436 未加载
exabrialover 2 years ago
The suggestions here are so not 1337. The whole point of writing code is to show off how much smarter you are. During code reviews, you can teach everyone else a lesson; you’re basically doing them a favor by making them read your 1337 code. If they can’t read your code they aren’t your equal.<p>Lame.
he0001over 2 years ago
This is so subjective. Some people do want to write such code as that is “cleaner” because it’s compact. Some wants to explain every single step because that’s “cleaner”. Some tries to do something in between and it’s somehow “cleaner”. But in the end, it’s mostly subjective.
评论 #32965509 未加载
schwartzworldover 2 years ago
&gt; Is that hard for you to read? Me too. There&#x27;s a good reason why. You have to know what map, lambda, and .split() are.<p>This is pretty weak. Not knowing what a function or language feature does, doesn&#x27;t make it inherently unreadable.
nmzover 2 years ago
This is forth code 101, factorization is an absolute must when writing forth code.
notjustanymikeover 2 years ago
Engineers would benefit from talking to designers more often. The rule of 5 +&#x2F;- 2 has been around in UX design forever. When you write code for others you&#x27;re designing a human interface for solving a problem.
glintikover 2 years ago
«Every line does only one thing» - that’s not related to real clean code. And there are bunch of languages that’s OK to have few things on the same line - perl, ruby, groovy, scala and even php.
评论 #32965193 未加载
nottorpover 2 years ago
My, the very dark pattern in the cookie dialog... closed the page when manage cookies didn&#x27;t load in 20 seconds. I bet there&#x27;s an explicit delay in there.
sdoeringover 2 years ago
Offtopic:<p>The fact that the site uses a consent solution that fakes a loading screen when trying to configure (read disable) tracking&#x2F;advertising is an instant bounce for me.
评论 #32965774 未加载
readthenotes1over 2 years ago
The author misunderstands Miller&#x27;s research on working memory, often reported as &quot;7 +&#x2F;- 2&quot;.<p>But, Miller states that limit is valid only for unrelated items.
iLoveOncallover 2 years ago
Readable code and clean code are two different things and I think this article does a prety poor job at writing clean code.
whiddershinsover 2 years ago
Code has a typo ‘slit’ instead of split after bringing up the concept of moving something into a function.
retrocryptidover 2 years ago
in the example given, I started with 10 things to keep in working memory. now that we&#x27;ve added a named function or a named variable, we have 11. I suggest it is at least as important to name things well (or add comments) as it is to break lines up.
评论 #32963779 未加载
评论 #32964101 未加载
评论 #32964146 未加载
gauddasaover 2 years ago
The magic number for programmers is 7. 4 to 6 is for the rest of the world.
foolfoolzover 2 years ago
the only known metric for code complexity is as number of lines grows complexity grows
评论 #32964156 未加载
评论 #32964475 未加载
评论 #32964531 未加载
NonNefariousover 2 years ago
And also: Use tabs.
thisismyswampover 2 years ago
Skimmed the article and the comments and got no answer - can someone tell me what the rule of six is?
评论 #32963973 未加载
评论 #32963967 未加载