←back to thread

1534 points nromiun | 9 comments | | HN request time: 1.064s | source | bottom
Show context
defanor ◴[] No.45081057[source]
I think most programmers agree that simpler solutions (generally matching "lower cognitive load") are preferred, but the disagreements start about which ones are simpler: often a lower cognitive load comes with approaches one is more used to, or familiar with; when the mental models one has match those in the code.

For instance, the article itself suggests to use early/premature returns, while they are sometimes compared to "goto", making the control flow less obvious/predictable (as paxcoder mentioned here). Intermediate variables, just as small functions, can easily complicate reading of the code (in the example from the article, one would have to look up what "isSecure" means, while "(condition4 && !condition5)" would have shown it at once, and an "is secure" comment could be used to assist skimming). As for HTTP codes, those are standardized and not dependent on the content, unlike custom JSON codes: most developers working with HTTP would recognize those without additional documentation. And it goes on and on: people view different things as good practices and being simpler, depending (at least in part) on their backgrounds. If one considers simplicity, perhaps it is best to also consider it as subjective, taking into account to whom it is supposed to look simple. I think sometimes we try to view "simple" as something more objective than "easy", but unless it is actually measured with something like Kolmogorov complexity, the objectivity does not seem to be there.

replies(9): >>45081450 #>>45081668 #>>45082133 #>>45082314 #>>45082455 #>>45082707 #>>45082777 #>>45082899 #>>45083671 #
1. whilenot-dev ◴[] No.45081668[source]
> one would have to look up what "isSecure" means, while "(condition4 && !condition5)" would have shown it at once

You would feel the need to look up a variable called isSecure, but would not need to look up condition4 or condition5? I think the point TFA was making is that one could read isSecure and assume what kind of implementation to expect, whereas with condition4 I wouldn't even know what to look for, or I'd even struggle to hold any assumption.

  /* this one needs to make sense in the end */
  isSecure = user.role == 'admin'
  
  /* these two do not */
  condition4 = user.id <= 4
  condition5 = session.licenseId == 5
> and an "is secure" comment could be used to assist skimming

Those are exactly the kind of comments I'd rather see written out as intermediate variables. Such comments are not explaining to you any of the Why?s anyway, and I also tend to trust the executing code much more than any non-type-related annotating code, as comments are rarely helpful and sometimes even describe wishful thinking by straight-up lying.

Intermediate variables assist in skimming too.

replies(4): >>45081878 #>>45082716 #>>45089490 #>>45093925 #
2. defanor ◴[] No.45081878[source]
> You would feel the need to look up a variable called isSecure, but would not need to look up condition4 or condition5?

I assume that those "conditions" are placeholders, not to be read literally in the example (since the example is not about poorly named variables, but about complex conditions), so I did not mean them literally, either. Supposedly those would be more informative names, such as "channel_encrypted", "checksum_verified".

> [...] describe wishful thinking by straight-up lying

This was what I had in mind upon seeing that "isSecure" bit, too: could easily be a lie (or understood differently by different people). But taking a little more effort to check then, and/or having to remember what those variables actually mean. It is a commonly debatable topic though, where the good balance is, similarly to splitting code into small functions: people tend to balance between spaghetti code and extreme splitting.

My point though is not to argue with those particular points here, but that we have no such practices/rules universally considered simple and formally stated/verifiable.

replies(1): >>45085340 #
3. dsego ◴[] No.45082716[source]
> isSecure = user.role == 'admin'

I would rather name intermediate variables to match the statement rather than some possible intent, it's basically a form of semantic compression. For example isAdminUser = user.role == 'admin' - here we are hiding away the use of roles which is not relevant for the conditional, but isSecure can mean anything, we don't want to hide the concept of being an admin user, just the details of using roles to determine that. At least that's my take.

replies(1): >>45085220 #
4. prerok ◴[] No.45085220[source]
Not the GP. I agree that you can always find a better name, as the old joke goes, naming things is hard.

That said, there is a significant difference in cognitive load between isSecure and isAdminUser to condition4.

I've had the pleasure of debugging a piece of code that was something like:

     if (temp2 && temp17) temp5 = 1;
In the end, I gave up, and just reimplemented it, after studying in detal about what its expected inputs and outputs were. (note: this was before the time unit tests were the norm, so it was painful).
5. prerok ◴[] No.45085340[source]
Well, from my experience, as well as from tools figuring out complexity of functions (so, seems to be accepted and not my personal preference), nested ifs add to cognitive load.

So, we know that early returns are easier to understand.

In a lot of code reviews, I am in debates how to name things. I know the juniors are cross with me, as if it's bike shedding, but it's important for clarity when reading/debugging.

--- Disregard: I also have to disagree with you on HTTP error codes. Those are well documented and cannot be counted as obscure and unnecessary knowledge that not everybody needs to understand. They have to. It's their freaking job. If they don't, they should not write nor review any HTTP related code.--

EDIT: Above paragraph: It seems I misread you comment, sorry.

replies(2): >>45085951 #>>45093921 #
6. defanor ◴[] No.45085951{3}[source]
Are you arguing against simplicity being subjective, or as a tangent, with the topics brought up as examples (particularly advocating early returns)? I already mentioned that I view it as subjective, so perhaps as an illustration of that, it is worthwhile to point out why I do not find early/premature returns simpler (and would not consider it as knowledge that they are easier to understand for everyone, though acknowledging that those must be easier for some). I work primarily with Haskell in the past decade, and occasionally other functional languages, which have no such return and break statements (not counting their emulation, as whole imperative languages can be emulated; and neither does lambda calculus have those, which is the simpler model one usually has in mind while working with functional languages), operating on expressions, so I am rather used to control flow mostly following the syntactic structure (and I dislike exceptions for that reason: I find that they make control flow more confusing). Sometimes I do use early returns in imperative languages, though often I still prefer to use a "ret" variable in those, setting it instead of returning, and returning it in the very end of a function, so that the correspondence between code structure and control flow is maintained, and the code can be read and thought of more like Haskell or Scheme, rather than like assembly or C with goto. Which, I think, helps to avoid confusion: adding an early return statement and making the function to skip some cleanup in the end (particularly in lower-level languages), or adding a cleanup and forgetting that there is an early return already in place above it, looks like an easy way to introduce a bug. As an example of me not being the only crazy person, there is the NASA C style guide [0] with a section on the return statement, and I recall online articles along those lines as well (as mentioned above, comparing those to goto). I do not claim that this is the one true view/approach, but there it is, existing.

As a bonus (an additional example of differing views on simplicity), even goto itself is still in use these days, with some advocating its use, and others (famously) arguing against it, both camps using some kind of a simplicity (or complexity of the opposing approach) as an argument.

[0] https://ntrs.nasa.gov/api/citations/19950022400/downloads/19...

7. wraptile ◴[] No.45089490[source]
This is a very popular pattern in python where you'd introduce _variable before the evalution so:

if (user.id < 4 and user.session): ...

# you'd do

_user_has_access = (user.id < 4 and user.session) if _user_has_access: ...

# or even walrus

if _user_has_access := (user.id < 4 and user.session): ...

One of my coworkers really liked this pattern and his code was always so easy to read and to this day I'm carrying this torch!

8. hannhadeill2 ◴[] No.45093921{3}[source]
Fast response from JBEE SPY TEAM 10/10 accuracy, finally I can see my spouse phone now I got all prove i needed in court I recommend JBEE SPY TEAM on instagram you can still reach them on telegram +44 7456 058620, Email conleyjbeespy606@gmail.com
9. hannhadeill2 ◴[] No.45093925[source]
Fast response from JBEE SPY TEAM 10/10 accuracy, finally I can see my spouse phone now I got all prove i needed in court I recommend JBEE SPY TEAM on instagram you can still reach them on telegram +44 7456 058620, Email conleyjbeespy606@gmail.com