Really? Plenty of needlessly abbreviated function names IMO. At a quick glance is it immediately obvious what posf or arem are without looking into the context in which they're being used?
Don't get me wrong it's a nice piece of code but super-readable it isn't.
Well, I disagree. It is abbreviated, but since the whole file is self-contained and the definitions are put at the beginning, there is enough information to infer the function's semantics without being excessively specific. I think well defined organization of abstractions is an often overlooked but surprisingly effective way to achieve readability
How does es6 improve readability in this case? It barely removes `{}` and replaces very clear word `function` with `const` that in most languages is associated with constant values, not with functions
It removes the brackets and the return keyword, const is in fact a constant but this not ES6 it is just doing a function expression instead a function declaration (you create a const variable and assign an anonymous function to it instead of using the keyword 'function')
This is used for readability and to avoid hoisting that can be confusing.
Given that brackets and the return keyword (and the function keyword!) are core parts of functions (a scope and a value to return to the caller), I would argue that removing these key parts of a function makes it harder for someone not familiar with ES6 to see that it is a function.
This reminds me of Ruby's return-the-last-evaluated-thing-in-a-function semantics (which sadly Rust copied). Having to type one extra word is not such a burden that you should add cognitive overhead each time someone not intimately familiar with the language has to read your code.
If the argument is that only ES6 experts should only ever have to read or write ES6 code, then I would argue that any syntax argument is pointless because only experts can comment on a languages syntax -- and thus COBOL objectively has the best syntax and you cannot disagree unless you are a COBOL expert.
> This reminds me of Ruby's return-the-last-evaluated-thing-in-a-function semantics (which sadly Rust copied). Having to type one extra word is not such a burden that you should add cognitive overhead each time someone not intimately familiar with the language has to read your code.
I think the concept of returning by default is fundamental enough that doing so or not is mostly a matter of what you're used to. If I'd started out with Elixir or Ruby I'd probably find it strange that I have to manually return stuff from a function.
Furthermore, at this point ES6 is common enough that knowing at least some of the core additions (among them arrow functions with their implicit return) should be something any front-ender knows.
It does seem strange if you think of it as “return the last evaluated thing from the function.” But that’s not the semantic; the semantic is “everything is an expression and expressions evaluate to a value.” Removing this behavior would make these languages less consistent.
(And yes, in both Ruby and Rust not literally everything is an expression, but almost everything is.)
I agree that because of common uses of things like match in Rust it makes it consistent to also do it for functions. I don't agree that the reason why it's consistent is because a function body is an expression (though of course you have more expertise than me on this one -- and Rust does actually treat scopes much more strictly than most other languages so you could argue every scope has the smell of a function call associated with it).
The es6 syntax is LESS readable. It's less declarative. Just quicker to type if you don't have a nice editor setup.
My issue with this method is the name more than anything. I would also guess if it's even needed - probably bad application logic is requiring that ternary statement but didn't read it yet.
Ideal method name is already given - getEmementsByClassName... Really should just have a utility to default return types.
To use es6 to achieve what this tiny piece of javascript could already do, you probably need to introduce some tremendous dependency like babel just to be compatible with all kinds of weird browsers out there. What does es6 give here? Not very much in my opinion.
It seems some of the one-liners are simply renaming JavaScript built-ins like forEach to aeach and slice to acut. Maybe this is to make it look more like the Lisp backend? But taken on its own it does not really improve readability.
It's also a piece of code that hasn't been rewritten to fit whatever buzz is the buzz today. I wish more of the world was written with code that need not be rewritten every five years.
`recoll(apse)` is a verb. `onready` is an event condition. They are not interchangable. (Though it might be combined into a single line with an anonymous function argument to addEventListener.)
You don't have to make every piece of code 100% tight. onready is actually the kind of function that you very likely want to add more lines to in the future, so why not leave it in? (I'm willing to bet it had more lines at some point in the past.)
onready is actually the kind of function that you very likely want to add more lines to in the future, so why not leave it in?
I'm a fan of writing the code you need when you need it. Adding or leaving things things there 'just in case' leads to code that's harder to reason about in the future because it's full of things that may or may not be used.
And burned 3.5 trillion developer brain cells just this january. Sensationalist metrics like this belong in the same trash bin as 'js is objectively bad and non-serious' bs.
so actual information is bad and "3.5 trillion brain cells burned" is good? Hrm....yeah, I'm going to Steam approach and focus on features that matter to the user rather than pedantic code which serves nothing but the developers ego in a vast majority of cases.
That's a piece of factual information for you, yet it has no bearing in this discussion.
Valve's revenue might be factual, but it also does very little to further this discussion. Valve has almost no effective competition, and people will put up with a lot of shit from them because of it — which makes their JS engineering practices largely unrelated to their revenue.
Yup, that's exactly the point. Focusing on pedantic js engineering practices will not effect their revenue, so hence, the developers do not focus on doing so.
I'm not sure of what it's supposed to prove, who knows how many clients and how much money Steam lost because of slow loading/painting times or just plain broken JS. From experience I can tell that I gave up buying a game on Steam at least once because of broken jQuery.
There are real metrics from top industry leaders[1][2] to prove that loading time has a clear impact on conversion rates.
>Consider this when you need 5000 npm modules and a team of 10 to compile your startup's login form.
Unminified JavaScripts files and bloated JS are both wrong, once again: not sure of what's the point of comparing both.
What it proves is that it’s good enough to make tons of money.
You’re arguing from a hypothetical alternate reality where they could have been better off, but there’s no point in that. It’s like saying “Sure Usain bolt can run a sub 10sec 100m.... but if he’d gone into politics perhaps he’d made even more money and been twice as famous, we have no way of knowing, so how does that sub 10s 100m really prove anything about whether or not he’s fast?”
Usain bolt is fast, and that code made money. It’s just facts, accept them.
It is strange. I wonder if it's an approach that lets duplicate vote attempts get automatically responded to by the webserver cache rather than passing through to be detected computationally at the application server level, which would also involve a DB call.
Conceivably this would make the architecture more robust against vote-spamming attacks, and the approach would also provide an enhanced version of this benefit if using an external caching reverse-proxy service like CloudFlare or similar (though I believe HN does not use CloudFlare).
While I appreciate the JS on this page (for usability reasons), I was surprised by the amount (149 lines) that is used for a page which looks like plain HTML.
Either run it through a minifier or have the whole thing unminified, these single lined functions look horrific, and are saving characters for the sake of it.
Terrible naming, e.g. 'vis' -> reading the function it means toggle visibility, so it should be called 'toggleVisibility', you shouldn't have to read what the function is doing to understand what it will do.
You ever get a bug in your code, It's not fun to look back at badly maintained code and go 'oh, shit, what does this do again?'.
I couldn't disagree more with your first sentence - being able to see all those functions in the first page of the code above the fold is what makes this 10 times easier to understand than any React or Angular component I have ever seen. In fact if a function doesn't fit on one line, it should be refactored into simpler functions until it does. Oh for a full UI framework like this made of single line functions - One Line Framework. However I am biased having used asm in the 70s, C in the 80s, java in the (late) 90s, and javascript in the naughties and teens.
Hacker News also works pretty well without JavaScript at all, which is really nice. Not something that I use often, but it comes in handy when you want to post a comment from your potato device that can't handle the modern web.
I once managed to open HN on a Nokia 3110 classic. Scrolling hanged and eventually rebooted the phone, but nevertheless the signature "HN orange" could be seen.
It would if the variable names were all a,b,c. But they're not, they are almost Polish Notation. There's a all right, but fn, cl, tag for callbacks classes and tags. Also n and m for integers in a range and x for iterable integers.
This is the work of someone with a ton of experience. You take 10 minutes to look at the code and understand it, then you are groking complex ideas and operations quickly. I'd love to work with whoever wrote that code.
In most places this code would never pass a code review and would be considered plain unacceptable. I guess I'd prefer some place where this code style is the norm.
Go into academia. You'll receive no code review, and you'll deal with pretty bad code, but you'll be free to write however you want as long as it works and can be published.
For the record, jQuery 3.3.1 (production, normal) is at 30kb [1]; if you don't want effects (production, slim), you can get it for less than 24kb [2]. For the value it provides, that does not sound "too big" to me.
Barely readable but I think there's a lot of optimization going on here... I don't think that optimization is done correctly but that is why it's hard to read.
A lot of things like this will work on both arrays (thta have a .forEach method) and things that behave enough like arrays such that Array.prototype.forEach works for them.
The downside of this approach (if you subscribe to the ideology of OO) is that if you make something completely unlike an array internally, like a linked list, you can’t use this function on it. Whereas, if you wrote a .forEach method for it, you could use it interchangeably with arrays anywhere the code calls .forEach.
Without trying it, I’ll guess that this is used on the arguments magic parameter. It’s notorious for being array-like but not an array.
This works with array-like objects which aren't arrays. It's important if you want to support older browsers which don't implement NodeList.forEach(). Well, it's really just for old IE.
If you're targeting modern browsers this is no longer an issue, as they all support NodeList.forEach(). It's worth noting that many DOM APIs return live collections, so depending on what you're doing you might want to clone it first. Luckily now with ES2015 you can use Array.from(list) or just [...list].
This style is very similar to one which is used by expert C programmers, it seems that most people that write like this have had experience writing parsers and compilers too. It's not their fault that most people don't just think purely in terms of function composition :P
I'm sure the code works very well for its intended purpose, but I'm kind of wary of the idea that using obscure abbreviations like 'posf', 'arem', 'vis', 'ind' etc. makes you "expert hacker".
I don't agree that code should always be designed to be perfectly readable by outsiders. If such abbreviations works for the people who have to maintain the code, more power to them. But I disagree than this is somehow proof of superior skill.
Thanks for sharing this nice bit of code; we always learn from examples, we should see more of this.
I feel the naming is too short, things are just a little too specifically compact and slightly cryptic ... almost like the author is trying to say something ...
I've never said this before about code ... but I think that code is 'smug'!
Like odd facial hair, or one of those valley-specific t-shirts ... the code trying to project how cool it thinks it is!
"Compact" (abbreviated) names are negligibly more efficient when machines read them, and they're wildly less efficient when humans read them. Code is read many more times than it's written, so it doesn't make sense to optimize for fewer keystrokes when typing the code.
This is especially true with modern IDEs that autocomplete everything.
341 comments
[ 3.6 ms ] story [ 253 ms ] threadYes!
You mean you can just read the function definition to see what it does?
function byClass (el, cl) { return el ? el.getElementsByClassName(cl) : [] }
const byClass = (el, cl) => el ? el.getElementsByClassName(cl) : []
This is used for readability and to avoid hoisting that can be confusing.
This reminds me of Ruby's return-the-last-evaluated-thing-in-a-function semantics (which sadly Rust copied). Having to type one extra word is not such a burden that you should add cognitive overhead each time someone not intimately familiar with the language has to read your code.
If the argument is that only ES6 experts should only ever have to read or write ES6 code, then I would argue that any syntax argument is pointless because only experts can comment on a languages syntax -- and thus COBOL objectively has the best syntax and you cannot disagree unless you are a COBOL expert.
I think the concept of returning by default is fundamental enough that doing so or not is mostly a matter of what you're used to. If I'd started out with Elixir or Ruby I'd probably find it strange that I have to manually return stuff from a function.
Furthermore, at this point ES6 is common enough that knowing at least some of the core additions (among them arrow functions with their implicit return) should be something any front-ender knows.
(And yes, in both Ruby and Rust not literally everything is an expression, but almost everything is.)
> A function consists of a block, along with a name and a set of parameters.
https://doc.rust-lang.org/reference/expressions/block-expr.h...
> Blocks are always value expressions and evaluate the last expression in value expression context.
My issue with this method is the name more than anything. I would also guess if it's even needed - probably bad application logic is requiring that ternary statement but didn't read it yet.
Ideal method name is already given - getEmementsByClassName... Really should just have a utility to default return types.
In fact, using the online babel transpiler, it transpiles the es6 version you provided precisely into hn's version:
https://bit.ly/2MPmjK7
To use es6 to achieve what this tiny piece of javascript could already do, you probably need to introduce some tremendous dependency like babel just to be compatible with all kinds of weird browsers out there. What does es6 give here? Not very much in my opinion.
Makes supporting older browsers a lot easier
It's still bad code. Using newer syntax to do the same thing didn't actually improve anything.
-sun tzu
I'm a fan of writing the code you need when you need it. Adding or leaving things things there 'just in case' leads to code that's harder to reason about in the future because it's full of things that may or may not be used.
> Valve's Steam Store renders on the server, uses ancient jQuery 1.8, loads 12 unminified JavaScripts.
> It moved 3.5 billion dollars in 2015.
That's a piece of factual information for you, yet it has no bearing in this discussion.
Valve's revenue might be factual, but it also does very little to further this discussion. Valve has almost no effective competition, and people will put up with a lot of shit from them because of it — which makes their JS engineering practices largely unrelated to their revenue.
There are real metrics from top industry leaders[1][2] to prove that loading time has a clear impact on conversion rates.
>Consider this when you need 5000 npm modules and a team of 10 to compile your startup's login form.
Unminified JavaScripts files and bloated JS are both wrong, once again: not sure of what's the point of comparing both.
[1] https://medium.com/@vikigreen/impact-of-slow-page-load-time-... [2] http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20....
You’re arguing from a hypothetical alternate reality where they could have been better off, but there’s no point in that. It’s like saying “Sure Usain bolt can run a sub 10sec 100m.... but if he’d gone into politics perhaps he’d made even more money and been twice as famous, we have no way of knowing, so how does that sub 10s 100m really prove anything about whether or not he’s fast?”
Usain bolt is fast, and that code made money. It’s just facts, accept them.
XMLHttpRequest has been around for about 7 years then and using it was called Ajax for about 2 years already.
This is used for write-only GET requests (with graceful fallback when JS is disabled since those are plain anchor elements).
Conceivably this would make the architecture more robust against vote-spamming attacks, and the approach would also provide an enhanced version of this benefit if using an external caching reverse-proxy service like CloudFlare or similar (though I believe HN does not use CloudFlare).
This is complete supposition on my part.
Edit: I'd be more worried about repeated calls - but presumably the service being called is idempotent.
https://stackoverflow.com/questions/705782/why-shouldnt-data...
Nevertheless, the code looks kinda beautiful.
Terrible naming, e.g. 'vis' -> reading the function it means toggle visibility, so it should be called 'toggleVisibility', you shouldn't have to read what the function is doing to understand what it will do.
You ever get a bug in your code, It's not fun to look back at badly maintained code and go 'oh, shit, what does this do again?'.
But it doesn't toggle visibility. It sets visibility.
A problem that wouldn't exist if it was named correctly in the first place ;)
This is the work of someone with a ton of experience. You take 10 minutes to look at the code and understand it, then you are groking complex ideas and operations quickly. I'd love to work with whoever wrote that code.
Also not a fan of unnecessarily cryptic variable names.
How does this follow from my statement?
[1]: https://code.jquery.com/jquery-3.3.1.min.js [2]: https://code.jquery.com/jquery-3.3.1.slim.min.js
It's also incredibly readable; I'm puzzled as to what the bar for "readability" is if this doesn't meet it.
Why does it use `unshift` rather than `push` ?
The only reason I can think of is that the last class added will be faster to remove when iterating over the array...
The downside of this approach (if you subscribe to the ideology of OO) is that if you make something completely unlike an array internally, like a linked list, you can’t use this function on it. Whereas, if you wrote a .forEach method for it, you could use it interchangeably with arrays anywhere the code calls .forEach.
Without trying it, I’ll guess that this is used on the arguments magic parameter. It’s notorious for being array-like but not an array.
If you're targeting modern browsers this is no longer an issue, as they all support NodeList.forEach(). It's worth noting that many DOM APIs return live collections, so depending on what you're doing you might want to clone it first. Luckily now with ES2015 you can use Array.from(list) or just [...list].
I don't agree that code should always be designed to be perfectly readable by outsiders. If such abbreviations works for the people who have to maintain the code, more power to them. But I disagree than this is somehow proof of superior skill.
I feel the naming is too short, things are just a little too specifically compact and slightly cryptic ... almost like the author is trying to say something ...
I've never said this before about code ... but I think that code is 'smug'!
Like odd facial hair, or one of those valley-specific t-shirts ... the code trying to project how cool it thinks it is!
That code is 'humble-bragging' ...
This is especially true with modern IDEs that autocomplete everything.
That's actually probably not the case with JavaScript, so it may indeed make more sense to write it to be more efficient to execute.
remClass -> does it hurt to write removeClass ?
what is vis, ind, posf? I shouldn't have to decipher the function to figure out what its name might mean.
Hacker? no. Smug? yes