21 ms·
How true hackers write JavaScript
- manojlds 8y ago...for a site as simple as hn Yes!
- JanSuly 8y agoTrue Because hackers need much more code lines than those.
- erkin 8y agoMost bloated sites don't even have an excuse to be more complicated than this.
- LiterallyDoge 8y agoWeb apps do, though.
- Tajnymag 8y agoThat might be one of the most readable pieces of code that I've ever read.
- jm547ster 8y agoReally? 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.
- oh-kumudo 8y agoWell, 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
- olavk 8y ago> there is enough information to infer the function's semantics without being excessively specific You mean you can just read the function definition to see what it does?
- mosselman 8y agoHe doesn't like being excessively specific with his writing I guess. Plus it makes you sound more like an engineer when you speak like this.
- vorticalbox 8y agoReally? It has horrendous naming and it isn't even using es6 function byClass (el, cl) { return el ? el.getElementsByClassName(cl) : [] } const byClass = (el, cl) => el ? el.getElementsByClassName(cl) : []
- arnvald 8y agoHow 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
- sashimy 8y agoIt 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.
- cyphar 8y agoGiven 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.
- mercer 8y ago> 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.
- olavk 8y agoIt 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.
- gpvos 8y agoNo, it is because some array-like objects like node lists actually aren't Arrays and don't have those functions in their prototype.
- Vinnl 8y agoI think the main reason this is somewhat readable is because there's hardly any code. Which is fine.
- jwally 8y agoThe supreme art of war is to subdue the enemy without fighting. -sun tzu
- LiterallyDoge 8y ago(y)
- noobermin 8y agoIt'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.
- onion2k 8y agofunction onready () { recoll(); } document.addEventListener("DOMContentLoaded", onready); Just attach recoll() directly. There's no benefit of going via onready().
- lifthrasiir 8y ago`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.)
- gpvos 8y agoYou 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.)
- onion2k 8y agoonready 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.
- deleted 8y ago[deleted]
- dang 8y agoOriginally there was something else in that function body. That's also why we didn't collapse it when we took that bit out.
- tobyhinloopen 8y agoNeat
- TAForObvReasons 8y agohttps://twitter.com/triskweline/status/798443082740023296 https://twitter.com/triskweline/status/798443082740023296 > 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.
- gear54rus 8y agoAnd 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.
- whydoineedthis 8y agoso 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.
- gear54rus 8y agoyour choice, it's your cells :) I would not want to dot that to my sanity.
- pdpi 8y agoI haven't had my morning coffee yet. 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.
- whydoineedthis 8y agoYup, 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.
- LolNoGenerics 8y agoNo ES2046, is that legacy?
- pygy_ 8y agoThis is neat (how the up/downvote onclick handler sends the info to the server). new Image().src = el.href; Where href looks like this: vote?id=xxxxxxxx&how=up&auth=yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy&goto=item%3Fid%3Dzzzzzzzz#wwwwwwww
- perfunctory 8y agoMaybe it's neat but this is not how anyone would write it today. This is the legacy code still left from the time before ajax was invented.
- winrid 8y agoProbably. I wonder though if they are trying not to use any libraries and Image was just easier than xhr.
- TekMol 8y agoHacker News was launched 2007. XMLHttpRequest has been around for about 7 years then and using it was called Ajax for about 2 years already.
- qbonnard 8y agoNot to mention the "ajax" function in the script...
- pygy_ 8y agoThere's also an XMLHttpRequest wrapper for when they care about the response. This is used for write-only GET requests (with graceful fallback when JS is disabled since those are plain anchor elements).
- pryce 8y agoIt 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). This is complete supposition on my part.
- mullikine 8y agoany more javascript than this and you're probably making something that's full of ads
- arendtio 8y agoWhile 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. Nevertheless, the code looks kinda beautiful.
- adamjc 8y agoEither 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?'.
- tzs 8y ago> Terrible naming, e.g. 'vis' -> reading the function it means toggle visibility, so it should be called 'toggleVisibility' But it doesn't toggle visibility. It sets visibility.
- adamjc 8y agoYeah, you're right, I misread the code. It should be called 'setVisibility' then. A problem that wouldn't exist if it was named correctly in the first place ;)
- dave333 8y agoI 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.
- dave333 8y agoOfficial name of the one line per function framework is FOOL - Functions on one line.
- oh-kumudo 8y agoThe code is very much readable, without suffering from being concise. Love it.
- saagarjha 8y agoHacker 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.
- nickthemagicman 8y agoI actually think this code is nice! Love the one liners. Variable names could be a little more....explicit.
- amelius 8y agoTo me this looks more like transpiler output ...
- deleted 8y ago[deleted]
- dotancohen 8y agoIt 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.
- fuzzy2 8y agoNot all that impressive, considering non-consistent code style and the like. Also not a fan of unnecessarily cryptic variable names.
- kowdermeister 8y agoI think the title is ironic.
- perfunctory 8y agoIn 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.
- noobermin 8y agoGo 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.
- olavk 8y agoSo you would like to work a place with no code review? You will be happy to hear that many many workplaces have no code review at all.
- perfunctory 8y ago> So you would like to work a place with no code review? How does this follow from my statement?
- olavk 8y agoSorry if I misunderstood.
- dmitriid 8y agoIt only exists because DOM APIs are crap, and jQuery is too big. So it ends up reimplementing parts of jQuery needed to run.
- vntok 8y agoFor 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. [1]: https://code.jquery.com/jquery-3.3.1.min.js https://code.jquery.com/jquery-3.3.1.min.js [2]: https://code.jquery.com/jquery-3.3.1.slim.min.js https://code.jquery.com/jquery-3.3.1.slim.min.js
- winrid 8y agoBarely 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.
- deleted 8y ago[deleted]
- zbentley 8y agoThere's minimal optimization (as in tricks), but lots of optimization (as in readability and common sense). It's also incredibly readable; I'm puzzled as to what the bar for "readability" is if this doesn't meet it.
- stephengillie 8y agoIt's just a pile of functions; no actual processes are scripted to execute.
- qbonnard 8y ago> function addClass (el, cl) { if (el) { var a = el.className.split(' '); if (!afind(cl, a)) { a.unshift(cl); el.className = a.join(' ')}} } 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...
- TekMol 8y agofunction aeach (fn, a) { return Array.prototype.forEach.call(a, fn) } Does this win anything over using forEach directly?
- tthisk 8y agoThis function could be used to iterate over the `arguments` array like object, but I do not think it is used for that purpose here.
- boomlinde 8y agoIt's used to iterate over HTMLCollection objects here.
- braythwayt 8y agoA 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.
- Flenser 8y agoDOM functions like getElementsByClassName return a nodelist, which as you say behaves like an array.
- deleted 8y ago[deleted]
- TheAceOfHearts 8y agoThis 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].
- mr_vile 8y agoThis 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
- olavk 8y agoI'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.
- LiterallyDoge 8y agoI think there are several different types of C programmers, and that terseness and functional design are very different.
- combatentropy 8y agoYes, and it reminds me also of Unix shell commands.
- boubiyeah 8y agoLooks like pretty average code to me.
- damir 8y agoLove it. Looks like lisp (can almost tell pg or rtm wrote it?), functions all over. No bloat...
- sonnyblarney 8y agoThanks 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! That code is 'humble-bragging' ...
- SmellyGeekBoy 8y agoReally? It just looks compact and efficient to me.
- smt88 8y ago"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.
- eadmund 8y ago> 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. 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.
- smt88 8y agoPost-processors do that much better than a human and can also tree-shake. There's no reason for a human to do it.
- PunchTornado 8y agoExactly, those function names hurt my brain: 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
- joosters 8y agoMore garbage ycombinator hero worship. 'True Hackers' ? Grow up!
- smt88 8y agoI understood it to be a tongue-in-cheek title
- damir 8y agoYep, kinda recursive...
- Dirlewanger 8y agoYou do things ironically long enough, you end up just doing the thing...
- TekMol 8y agoOne trait of true hackers is that they actually create things. As in "hack something together". And yeah, this playful attitude to "just do it" tends to goes away when people become adults. So in my book, it is better to grow down!
- slx26 8y agoIn defense of some adults, I think a key point here is to realize that it's very different to do something alone, basically for yourself, and with the idea of (mostly) learning and exploring, that working with other people, for other people, and expecting the thing you are working on to keep functioning for the foreseable future. I think it's important to understand both contexts (and practice them!).
- noncoml 8y agofunction hidestory (ev, el, id) { for (var i=0; i < 3; i++) { That 3 there is the problem with “simple” JS. It’s tightly coupled to the HTML but they live in completely different places. On a side note this 3 should be at least assigned to a variable with a meaningful name.
- paulintrognon 8y agohidestory() is not even used anywhere ; why is it here for? Debugging?
- joshschreuder 8y agoIt is probably called in an onclick=“” in the HTML somewhere
- wiether 8y agoLike JS is never attached to a HTML template ?
- fenomas 8y agoIt's called by the "hide" link under each story on the top page.
- bausshf 8y agoIs this sarcasm? I hope it is.
- xigma 8y agoExcept there isn't any problem here whatsoever. Yes, it's coupled, but it doesn't matter. No, this kind of code doesn't scale. It doesn't have to. The time you spent writing this comment was longer than what it took writing this code. Considering what kind of site this is, that code may work indefinitely. Or, if necessary, someone from the future will need to change that 3 to a 4 at some point. In terms of total cost, it's almost certainly the cheapest solution.
- bsaul 8y ago
- jek0 8y agoThe authors is quite lazy or cannot type fast enough, so he has to create all those cryptic abbreviations: `rks` for `ranks`, `unv` for `unvote`, etc. Which makes it really hard to read. But it's especially the inconsistent use of camelcase in function names than makes me think it's pretty amateurish.
- Rapzid 8y agoYeah, just looks like a grease monkey script I would have banged out a decade ago in about an hour. Nothing wrong with that. It's far more interesting how much people are reading into this code haha. It was clearly not written to be read by us today IMHO.
- richrichardsson 8y agoHard to read? The sum total of the script fits on 2-3 pages at most, no single function exceeds about 10 lines, if you have trouble reading and reasoning about that code then something is wrong.
- paulintrognon 8y agofunctions will not be any line longer by writing ranks instead of rks, but it will greatly improve readability. You can have the exact same code wihtout abbreviations, and I can assure you that it will still be 2-3 pages long, with very short functions.
- dang 8y agoYou can't evaluate readability without knowing the conventions that a system is working with. (That means knowing something about the people as well, btw.) In this system, 'rks' communicates something that 'ranks' does not: that this is a local variable denoting a collection, and that it is a collection of the things that 'rk' denotes one of. So actually it adds quite a bit to readability. If I were going to edit that code to make it more readable, the one change I'd consider is using 'r' (or maybe 'n', because these are integers) instead of 'rk'. One can argue either way whether the k adds information or just noise.
- Capbara 8y agodocument.querySelector('pre').style.color = '#17c517';
- SmellyGeekBoy 8y agoIs it September already?
- fithisux 8y agoIs this some Arc-to-JS transpilation?
- TheAceOfHearts 8y agoThis code would be a bit shorter and simpler if it dropped support for old browsers (specifically, Internet Explorer). Some examples: The functions hasClass, addClass, and remClass could be replaced by Element.classList [0]. Another one is remEl, which can be replaced with a direct call to ChildNode.remove() [1]. I was going to give more examples, but I don't feel like rewriting the whole script. [0] https://developer.mozilla.org/en-US/docs/Web/API/Element/classList https://developer.mozilla.org/en-US/docs/Web/API/Element/cla... [1] https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/r...
- masswerk 8y agoWhy should anyone invest lifetime to remove compatibility from a perfectly working application? Just to prove that not everyone is using an evergreen browser?
- krapp 8y agoIt works... every criticism beyond that is just an argument about taste, although personally I think it's unnecessarily terse. I've written uglier code and gotten paid for it. ¯\_(ツ)_/¯
- jenscow 8y agoAnd no doubt I've written single methods/functions that where uglier.
- DanHulton 8y agoNot necessarily. Sure, all code has to work, but unless you're going to ship a product and then never, ever return to it, it has to be maintainable as well. There are a few arguments in this thread about poor maintainability of this code, when coupled to the HTML it affects (which always must be considered, otherwise this code is pointless), and I tend to agree with them. Personally, I wouldn't mind some less terse names and some more semantic groupings of HTML nodes. Thankfully, it is simple. I'm pretty sure doing that would be the task of an afternoon, though I would definitely want to accomplish that before trying to change anything else on the page.
- krapp 8y ago>but unless you're going to ship a product and then never, ever return to it, it has to be maintainable as well. This is Hacker News... there's a good chance it will go more or less unchanged for a while.
- Jaruzel 8y agoI don't understand why people are dissing this. It does what it's designed to do, and fills a specific need for one website. It's not there as a teaching aid, nor is it meant to be shared for other people to use elsewhere. Not everything has to be gold-standard code full of perfect variable names, extensive comments and good whitespacing. If you have a day job that isn't primarily writing code, and/or you are likely to be the only person ever working on that code, who cares if it's not up to the standard that people around here seem to expect of every project? As long as the code works, anything else is just gravy. If you were to peel back the layers on all the major websites out there, I'm sure you'd find less than stellar code everywhere.
- pacifika 8y ago>If you have a day job that isn't primarily writing code, and/or you are likely to be the only person ever working on that code, who cares if it's not up to the standard that people around here seem to expect of every project? Future you that has to decipher the code. Why make it hard on yourself? Software is a living thing eventually a decision will need to be made about it and without understanding what it does it's easier to make suboptimal assumptions.
- watwut 8y ago> Future you that has to decipher the code. Why make it hard on yourself? Software is a living thing eventually a decision will need to be made about it and without understanding what it does it's easier to make suboptimal assumptions. To the defense of the title, in my experience, whenever label "hacker" was used on programmer or code, it meant "difficult to read, full of hard to maintain shortcuts and tricks" kind of code. Really always, I don't ever remember it to be used in any other sense.
- yani 8y agoTrue this
- kruczek 8y agoEh, it's only 150 lines of simple functions without external dependencies. It's simple enough to understand and modify on the spot. As long as these are not expected to grow significantly in the future, I don't see why it'd be making it hard on yourself (and if it does grow, then it can always be refactored).
- Aardwolf 8y agoUm, is this supposed to be a criticism? Because this is MUCH better than sites loading megabytes worth of scripts to do nothing more than render text, have dozens of floating elements everywhere, auto playing videos that follow you, "use our app" buttons, etc... JS is the assembly of the web, do you also criticize games written in assembly?
- krapp 8y ago>JS is the assembly of the web, do you also criticize games written in assembly? No it isn't, any more than C++ is the assembly of your operating system. Assembly has the terseness that it does because of constraints that javascript doesn't have -- this javascript looks the way it does because the author wanted it to look like lisp code, not because it has to.
- Aardwolf 8y agoAt least it's the lowest level programming language for browsers I know. So perhaps I should have said "machine language of the web" because assembly isn't the lowest level :)
- erikpukinskis 8y agoAssembly, used this way, just means “the words that create action at the layer below which you cannot go”. Also referred to as “metal”. Depending on where you are starting that could be JavaScript, or it could be Basic, or any of a number of things. In the browser it’s JavaScript. This only makes sense if you can see that there are machines within the machines, within the machines.
- krapp 8y agoFair enough, it's a metaphor, but a fragile one that breaks down easily, as I believe it has here. Using actual assembly to defend terse coding in javascript because javascript is "assembly for the web" doesn't work.
- 8y ago
- hguhghuff 8y agoLooks like they are wrapping javascript functions instead of just using the functions.
- olavk 8y agoSomeone else points out that older versions of IE didn't support array methods like forEach on nodelists. So it is basically a thin compatibility layer.
- timrichard 8y agoThere might be more appreciation for "how future maintainers write JavaScript", but that's not cool and it takes a couple of decades more experience. Looks a lot like "read-only" web code I've encountered on projects, where waves of people decided it's easier to work around what's already there than amend it (and that's also how you end up with 20,000 line CSS files).
- michalstanko 8y agoThis is very similar to what I'd do for my small projects, I really love the small size and the brevity of it. On the contrary, it's not what I'd do at work for one of our bigger web apps. No need to criticize, it does what it's supposed to.
- olavk 8y agoThere are some polarized opinions in this thread. Someone wrote That might be one of the most readable pieces of code that I've ever read. Apparently it improves readability immensely to rename 'forEach' to 'aeach'. To be honest the code is not very readable, but it is very simple and self contained. It would be very easy to dive into to fix a bug because there are no external dependencies or frameworks you have to understand. The list of one-liners at the top seem like a very minimal 'jQuery'-like layer. Perfectly fine except for the l33t identifier names. But there is also some really fragile coupling to the HTML, e.g.: for (var i=0; i < 3; i++) { remEl($(id).nextSibling) } I wouldn't dare to modify the HTML when the JavaScript looks like this! What are the three elements which are being removed? Why exactly three? Probably the author and maintainer of the code knows, but this is the kind of coupling where nobody except the original author would dare to change anything. Perhaps this why HN still uses tables for presentation - nobody dares to change it?
- aleksei 8y agoPerhaps this why HN still uses tables for presentation - nobody dares to change it? There's also simply no reason to change it, it works.
- TeMPOraL 8y ago> There's also simply no reason to change it, it works. It works, and it's arguably simpler than the div-soup with extensive styling, which is the "kosher" way of doing this.
- olavk 8y agoWell using divs would at least make you able to group the elements semantically so you could remove a single node rather than having a for loop which removes exactly three nodes. This would be significantly simpler in my opinion. And it would be less fragile since now you can redesign everything inside this node without the JavaScript breaking.
- 8y ago
- LukaszWiktor 8y agoThe less lines of code, the less chance for a bug.
- olalonde 8y agoIf there's one take away from this, it is that programmers have widely differing opinions on what constitutes good code.
- userbinator 8y agoThe spectrum seems to span from APL at one extreme, and Enterprise Java/C# at the other. This is closer to the former but still not that extreme (I personally lean toward that direction too, mostly working with Asm and C.)
- ourmandave 8y agoI can eventually see this coming up on SO asking how to, "make this work. I copied it from the internet." It will be tagged javascript and jquery. =(
- anta40 8y agoany example on how to use this JS code?
- jenscow 8y agoYes, the page you are currently reading.
- Ataraxy 8y agoCriticisms and bizarre fawning over beauty that a couple of people have made aside, the one thing that bugs me the most is the inconsistent usage of ;
- strainer 8y agoTo my eyes semicolons are like comments in JS code which indicate "this has been linted for publication". But this > (one); (occasion) where a semicolon can have meaning in JS leaps out of the screen - even easier if they are not blanketed everywhere. The incomplete blanketing in this code is very casual. I see it no more than an invitation to hand-lint what I want to touch.
- dang 8y agoI should fix that, since sctb probably agrees with you and is too polite to say so. Any suggestions for me as a shitty semicolonist?
- spiralx 8y agoYou can always use either Prettier or Standard JS to lint and format your code, and both can be set up with or without semicolons... https://standardjs.com/ https://standardjs.com/ https://prettier.io/ https://prettier.io/ I prefer Standard JS, but either way it's easier to not need to think about the exact details IMO :)
- Ataraxy 8y agoI'm not some grand arbitrer of the semi colon debate to tell you what is the best possible thing to use (to the best of my knowledge it's a preference thing at this point). Personally I prefer to just use none at all these days in practice, but that's just me. I just found it weird that they were seemingly arbitrarily used here on occassion.
- giancarlostoro 8y agoWhile everyone's freaking out over the code I'm remembering the old code that was only 2 functions[0], which leaves me to believe this code was changed not too long ago. I wish we had a github or something of some of these front-end changes to HN just to see how things change over time. I figure it wouldn't be too much, but still. The original JS was inlined and contained two functions: hide and vote. [0] https://news.ycombinator.com/item?id=11307758 https://news.ycombinator.com/item?id=11307758
- dang 8y agoWe expanded it for collapsible comments a few years ago.
- giancarlostoro 8y agoBeen here a little minute, feels like it was just yesterday, but if I had to guess at least after 2016? Since that's when that comment is from. I guess it's my fault for not looking once collapsible comments were added though :)
- Timpy 8y agoSeriously though... do you guys declare variables with var or let? I thought let was the new standard for scoping reasons. I'm not trying to start a holy war, I'm just a junior looking to learn.
- strken 8y agolet and const are good practice in code that will be transpiled, or in Node.js, but they're newish features that don't have 100% browser support yet, so they shouldn't be used if your code has to run directly in a browser. https://caniuse.com/#feat=let https://caniuse.com/#feat=let
- gnode 8y agovar is maximally compatible with older browsers. let and const are more tightly scoped, and that can help you write more maintainable code. I think maintainability was not a first class concern in the writing of this script (consider the terse naming of variables), but it doesn't really matter; it's short, and you can understand it all because there's not all that much to understand. It does the job, and works everywhere.
- kowdermeister 8y agoconst. I always use const and if I need to mutate a variable, then let. var is pretty much just for legacy codes. Yes, it has unique behaviors, but better stick to the new keywords, can prevent some headaches.
- fb03 8y agoWay better than loading megabytes of .js just to display stupid animations and other useless gimmicky stuff. This file is just in consonance with this website's style: concise, terse, to-the-point and with minimal bs. Of all of my currently in-rotation news websites, this loads and reacts the fastest, no matter where I am or how crippled my current connection is. I am sure they are factoring load times and speed over 'shiny new features'. Keep going, YC!
- davnicwil 8y agoAnimations being badly/over used aside, this is a bit of a straw man argument. If you load megabytes of JS to do animations, as opposed to using CSS, then yes you are just doing it wrong. Things aren't either exactly right and done one way, or else terrible. You can of course have bells and whistles like animations if your usecase requires them (HN doesn't!) and still have a fast loading site with clean code, if you do it right.
- fb03 8y agoI agree with you. And the animations example was simply one of the bad offenders (merely one of the symptoms of the disease). The disease is overutilizing buckloads of js scaffolding which is blatant in the majority of the websites right now. Even a small blog now "has to have" the latest xzibit framework which pulls 32 foobar dependencies, all gulped into one huge blob of minified compressed clusterfuck-pack.
- davnicwil 8y agoYeah, I guess it is a tradeoff between engineering productivity and performance. Both are features. Past a certain level of complexity it is usually the correct decision to choose the framework and toolchain so that you can deliver and maintain features at all. "Make it work -> make it good -> make it fast" is very relevant here. Though I agree about what you're saying for blogs and other content sites, where the tradeoff is clearly inappropriate in a lot of cases. With that said, things like https://www.gatsbyjs.org/ https://www.gatsbyjs.org/ offer an interesting '3rd way' here, allowing you to keep the productive toolchain and framework stuff but still serve a blazing fast static content site.
- aaaaaaaaaab 8y agoYep, that's about how much JS your site should contain if you're a sane person.
- linkmotif 8y agoYeah this is nothing bad at all just some code. I’m fact I can grok it on my phone so I’d say it’s good code.
- AltruisticGap 8y agoI thought I was smart... BEFORE function vis(el, on) { if (el) { on ? remClass(el, 'nosee') : addClass(el, 'nosee') } } AFTER function vis(el, on) { if (el) { window[on ? 'remClass' : 'addClass'](el, 'nosee') } } ...sadly we have to add window when using the square brackets so it's not much shorter. Oh well.
- Arkanosis 8y agoWhy not: function vis(el, on) { if (el) { (on ? remClass : addClass)(el, 'nosee') } } ?
- AltruisticGap 8y agoAhh thanks! I forgot about that. I'm guessing I didn't think about it because I'm used to the following pattern ,which is actually useful from time to time in my projects. And typically it happens in an object/class: this[expr ? 'method1' : 'method2'](args) So I have to add "this" as the methods are not global. Now if I overlooked something again I'm definitely getting rusty :)
- dang 8y agoYes, that's better, especially since we do it elsewhere. Thanks!
- expertentipp 8y ago"var", "function", one explicit "return" at the end of function body, working directly with the DOM? I still do this sometimes and the Angular/React/TypeScript kids look at me like at some alien wizard, while Java/.NET folks still think "it's just a dumb website".
- AltruisticGap 8y agoHe/she could have put much of the function in the top under the $() to make a super mini jquery. That's close to what I use with Vue. It's made even easier to write considering I almost never find a need for jquery's default behaviour of running its methods on multiple nodes. 99% of the time in my projects I just need to do something with one node.
- acdha 8y agoI’ve replaced jQuery on several projects with $ = querySelector, $$ = querySelectorAll (wrapped in Array.from if you need to support IE11 so you can use all of the new array methods which their NodeList implementation didn’t get until Edge), classList and fetch. Beyond the code size savings, I find the newer standard methods are generally easier to understand when scanning code.
- AltruisticGap 8y agoI like what this guy did, talking about native methods. However it's too flexible for me, I prefer to have the most minimal functionality in order to ensure consistency in my code. But maybe that's just me. If the library opens up too many possibilities, then I have both the "problem of choice" when writing code, and also it's more difficult to refactor down the line if you want to change lib. Whereas using your own super simple solution (as long as it's sufficient), you can also do a simple abstract layer when including some vendor API. https://github.com/eorroe/NodeList.js/ https://github.com/eorroe/NodeList.js/
- acdha 8y agoI've been using this for years – it's not the end of web development but an awful lot of projects don't need more framework than can fit in a tweet: let $ = (selector, scope=document) => { return scope.querySelector(selector); }; let $$ = (selector, scope=document) => { return Array.from(scope.querySelectorAll(selector)); };
- 8y ago
- bovermyer 8y agoIt works reliably and quickly, so mission accomplished.
- jmull 8y agoHere's something maybe productive to take away from this kibitzing thread: Consider this code and the range of comments on it while doing (or undergoing) your next non-trivial code review. (For one thing, it reminds me that a great value of adopting comprehensive code standards is that it resolves these kinds arguments, letting teams get on with the important stuff.)
- danschumann 8y agoI dunno. Is posf really better than indexOf? Why not use more conventional names for the underscore-ish functions they made?
- kozak 8y agoWrite it with all the modern "proper" approaches, and good luck even just recompiling it in 10 years. While this code - however imperfect - remains just as maintainable today as it was when originally written (which is probably more than 10 years ago).
- acdha 8y agoThat's true if you're talking about using React, Vue, etc. but do you really think ES5 JavaScript is more likely to be supported in the future than ES6?
- kozak 8y agoI'm talking about NPM modules and the build toolchain (which consists of even more NPM modules). This stuff goes stale very quickly (at the 10-year scale). It's good for a project that is kept continuously alive (i.e. when there is a team of developers that is continuously making changes to the project), but not when the project sits on a shelf for 10 years and then needs to be modified.
- acdha 8y agoRight, my point was that this is a subset of modern approaches.
- kozak 8y agoYou are right.
- LiterallyDoge 8y agoThis is a good point, but if you take NPM / Yarn / Bower (RIP) with a grain of salt and secure your codebase against failures, they work nicely as a toolchain.
- kozak 8y agoDo you mean committing node_modules to the Git repository? Unfortunately, that's not a panacea with build tools, because some of them contain non-JS code that is tightly coupled to Node and OS versions.
- JoeCortopassi 8y agoEverything has a context. If your site has: - minimal functionality - rarely if ever changes - is maintained by a very small group (Hacker News) ...then something like the example linked is perfect. Most web app developers don't live in this world. The more common situation is: - large and/or transient teams - large quantity of inter-dependent features - constant changes ...which means that the thing you need to optimize for isn't pretty/fast code. It's clarity and resiliency in the code. Can a junior and senior dev both work on the same code base? Can someone new to the project be effective with minimal ramp up time? Can you work on a feature without accidentally stepping on another persons current task? Modern web apps are less about being performant and minimal, and more about dealing with the complexities of large software teams
- slantyyz 8y ago>> Modern web apps are less about being performant and minimal, and more about dealing with the complexities of large software teams If that's true, then the app will likely have what I call a "programmer's interface" (which is especially common in most enterprise web apps I encounter). Those apps might be solid from a code perspective, but don't tend to be very user friendly. I tend to think that modern web apps are more about dealing with the complexities of balancing functionality with ease of use to the end user while still dealing with the complexities of large product teams, which include but are not limited to designers, UX experts and developers.
- too-soon-ago 8y agoThe fancy-lookin' sites are the ones which hijack basic keyboard functionality, scroll in weird ways, etc. I can't be the only person who finds browser default behavior more intuitive and usable in general. Why does "UX" so often mean mouse-heavy and always favor the beginner over the power-user.
- richiebonilla 8y agoI agree that following browser default behavior is more intuitive in general. I'm not a fan of scroll jacking. I'd say apps skew towards mouse-heavy because controls are on-screen and therefore discoverable. It takes a good deal of product-market fit before you can count on your users knowing/caring enough about your app to remember keyboard shortcuts. Most apps are grown by adding users, so optimizing for the new user is more important to the business until a certain level of maturity and market saturation is reached. Applications with a dedicated professional user base can go deeper into power-user territory sooner since they can charge more per user, and new users expect there to be a learning curve.
- sbr464 8y agoI feel like this was written in this particular style assuming it was not going to be minified. I think it's ok to use this style if only maintained by a couple of people, or for a small project like this. I do like it's conciseness, but I don't feel the title is appropriate.
- gcb0 8y agowe are way overdue for a source code and architecture evolution history here. the way this started as a toy and exploded without any noticeable performance problems shpuld be a good case study.
- biznickman 8y agoLol this title is literally a recipe for fighting. That said, I love how they eliminated the need for JQuery with all the functions up top. Super minimalist.
- EamonnMR 8y ago"True Hackers" can write LISP in any language?
- lucisferre 8y agoI'm not sure if this was linked fatously, but this is actually pretty good JS. - All functions - The functions are simple and decomposed into smaller functions - No usages of "this" (except one necessary one in an event handler) - No ham fisted attempts at doing OOP with JS Only complaints really are naming and code style is overly compact which would potentially make it harder to understand, but in this context I think that is ok. There is nothing overly complex going on here. The code seems reasonably easy to understand. If there are criticism I'd like to hear them.
- criveros 8y agoshould be using fat arrow functions.
- lucisferre 8y agoWhat possible benefit would this have? Particularly considering it doesn't rely on "this" anywhere.
- rs86 8y agoJS is OOP, although does not have classes. It has prototypes
- lucisferre 8y agoJavascript works half-decently as a functional language but is a pretty bad OOP one. Pick your poison. Add to that the general consensus that functionally-oriented programs are easier to test, debug and reason about and you have my reasoning.
- habosa 8y agoThe code style is fine, it's practical. But how about what it does? Has anyone ever tried to collapse or expand a 100+ comment thread here? It can lag for 1-2s. So all the talk of "it's simple code that serves its purpose" is not really true. That said, please don't solve my complaint by adding a bunch of SPA stuff to HN. I love how fast the base content loads here and how there's nothing dynamic.
- bstar77 8y agoIMO, this code is perfectly fine if you are one guy, never plan/want to change anything and don't expect your site to grow.
- JTbane 8y agofunction $(id) { return document.getElementById(id); } Nice! Now I don't need jQuery.
- spiralx 8y agoHere's the smallest jQuery replacement I've seen :) https://gist.github.com/paulirish/12fb951a8b893a454b32 https://gist.github.com/paulirish/12fb951a8b893a454b32 It let's you do $('p').on('click', el => /* ... */) which is handy for smaller scripts :)
- omar12 8y agoSimple, straight forward and does the job.
- dandare 8y agoAm I the only one who thinks this is unreadable? var on = !afind($(id), collapsed()); (on ? addClass : remClass)($(id), 'coll'); where function afind (x, a) { var i = apos(x, a); return (i >= 0) ? a[i] : null; } where function apos (x, a) { return (typeof x == 'function') ? posf(x,a) : Array.prototype.indexOf.call(a,x) } where function posf (f, a) { for (var i=0; i < a.length; i++) { if (f(a[i])) return i; } return -1; }
- Topgamer7 8y agoIt's not too descriptive, however it is descriptive by function name. Take the afind line, you can ascertain what it does by afind's name and provided params: afind -> find, $(id) -> find id, collapsed -> find id's collapsed state. I agree it's not a simple glance to figure out what it does, however it is not unreadable.
- deleted 8y ago[deleted]
- crazygringo 8y ago+1,000. The best programming advice I ever got was to write code for other people to read (and understand at a glance), not for the machine to execute. This code is the precise opposite of that.
- mandeepj 8y agoWhy it can't be both? And, Yes - it can
- deleted 8y ago[deleted]
- dang 8y agoIt is a precise embodiment of that: the code was written specifically for people to read, and those people find it very readable. It is a mistake to assume a single standard here. Does a German speaker find a Sanskrit text readable, or a trombone player find a guitar piece playable?
- iamleppert 8y agoBut where is Webpack??? Why aren't they using ES7 decorators and lambda syntax? Each one of those functions should be broken out into its own separate source file and they should be using classes, not functions. For the love of god, how do they trust this code will do the right thing without the obligatory type safety of a shoe-horned type system? And what is with this code returning false for everything? Everyone knows you're supposed to return JSX wrapper in another DIV in order to talk to browsers! Lastly, how could they ever expect this solution to scale? I bet this is only slightly worse than okay for a hack-a-thon but hell would surely freeze over the minute a single user was forced to use it! It's a maintenance nightmare. It's far better to start with some webpack + react boilerplate. Each one of the dependencies means that someone else is maintaining the code, so you can wash your hands of that responsibility and sleep well knowing internet elves are maintaining your web app!
- draw_down 8y agoCome on.
- masswerk 8y agoAlso, there's an inexcusable lack of modal popups and dialogs on this site! They simply do not care about users! :-)
- reitoei 8y agoIt looks like you're using an adblocker. Click here to upgrade to HackerNews Gold for just $1 a week!
- dave333 8y agoI see no smiley but I assume the tongue is firmly in the cheek, no?
- deleted 8y ago[deleted]
- anonlastname 8y agoI approve of those wrapper functions in the first few lines... those would have saved me so much time when I was a web dev I'd say I'm going to copy them next time but there is no license header...
- spiralx 8y agoIf you really need a shortcut then const $ = (sel, elem = document) => [ ...elem.querySelectorAll(sel) ] is nicer as you can use CSS selectors.
- damir 8y agoOP here, looking at the vote function, I learned something new today - this code: new Image().src = el.href; will make image request to server with any params from href so you can process the voting stuff. Nice one.
- dang 8y agoMaybe I'll respond in a general way to what's come up here. This code isn't unreadable, or accidentally readable—it was written specifically for readability. Similarly, it isn't unmaintainable or accidentally maintainable—it is written specifically for maintainability. Unlike in most programming debates, we can actually prove this. Here is the proof: I've talked to everyone whose job it has ever been to read this code, and all agree that it is easy to read. I've also talked to everyone whose job it has ever been to maintain this code, and all agree that it is easy to maintain. The point is that readability and maintainability are determined by who is reading or maintaining, and the 'who' that matters for determining that is the team responsible for a system. If that sounds strange or obviously wrong, it may be that you're taking certain widely-held beliefs about programming as if they were truths about programming. Also, the conventions of the larger codebase which this small program is drawn from carry a lot of information, and free us to work with concision and simplicity that aren't so common in production codebases. I know this sounds weird, but hope that it will stir curiosity in one or two of you. By far the biggest mistake I made as a young programmer was staying within what one might call the shallowculture for longer than I needed to. The outstanding properties of the shallowculture are that it 'knows' how to program and 'knows' to dismiss uncommon approaches to programming as wrong and inferior. If you notice yourself reacting this way, my grizzled advice is to pause and start questioning. Look into it deeply, and you'll find that this seeming 'knowledge' is spurious. That will open up for you more satisfying ways of making software. For example, you'll find ways of avoiding the complexity bloat that is routinely lamented in Hacker News threads as a plague on our industry.
- jacques_chester 8y ago"Everyone I know agrees with me" is not a trustworthy signal. It doesn't mean you're wrong, of course. I am still learning to assume that smart people are smart people who, by and large, have smart reasons for things that on their face seem silly to me. I think this is one of those times for me. Not knowing the bigger picture, I want to give you the benefit of the doubt. But as one piece of stylistic feedback, since bikeshedding is easy: Congress repealed the Taxation of Readable Variable Names Act around the time that autocompletion was invented. I am dumb and find those far easier to read at a first glance. Edit: I guess this thread is one of those times that software reveals its true nature, which is that it has almost nothing at all to do with computers.
- halis 8y agoMy opinion of the code is this. It's pretty tight, which I can respect. I haven't run it, but it PROBABLY works. But it's hard to read. Things are named poorly. Many edge cases are missed (not checking args properly). These functions are not pure and therefore, harder to test. Maybe true 1337 H@X0Rz don't need to write tests, but some of us have mortgages to pay... I didn't re-write all of this mess, but check out the few util functions that I re-wrote. As a developer, which version would you rather work with? If you said the original version that's cool with me. But don't try to come work on my team. // isNull :: a -> Boolean const isNull = x => x == null // isNullOrEmpty :: String -> Boolean const isNullOrEmpty = string => string == null || !string.length // $ :: String -> HTMLDocument -> HTMLElement const $ = (id, _document = document) => { if (isNullOrEmpty(id)) return null if (isNull(_document)) return null return _document.getElementById(id) || null } // findClassInElement :: HTMLElement -> String -> [HTMLElement] const findClassInElement = (el, className) => { if (isNull(el)) return [] if (isNullOrEmpty(tagName)) return [] return el.getElementsByClassName(className) || [] } // findTagInElement :: HTMLElement -> String -> [HTMLElement] const findTagInElement = (el, tagName) => { if (isNull(el)) return [] if (isNullOrEmpty(tagName)) return [] return el.getElementsByTagName(tagName) || [] } // findClass :: String -> HTMLDocument -> [HTMLElement] const findClass = (className, _document = document) => { if (isNullOrEmpty(className)) return [] if (isNull(_document)) return [] return findClassInElement(_document, className) || [] } // elementHasClass :: HTMLElement -> String -> Boolean const elementHasClass = (el, className) => { if (isNull(el)) return false if (isNullOrEmpty(className)) return false return el.className.includes(className) } // addClass :: HTMLElement -> String -> Boolean const addClass = (el, className) => { if (isNull(el) || isNull(el.className)) return false if (isNullOrEmpty(className)) return false if (el.className.includes(className)) return true el.className = `${el.className} ${className}` return true }
- aprdm 8y agoI prefer the original one. I don't see the value, for this use case, of all those checks. We know what the input values are, essentially what's in the DOM that we 100% control. I feel ES6 syntax much less readable than ES5 (probably because I have worked more in ES5 than ES6), it introduces a bunch of new symbols. How can this const isNull = x => x == null Be more readable than function isNull (x) { return x == null} Another example, const addClass = (el, className) => { } I always have to remember what this construct means and translate / unroll it in my mind to a regular function. Also, why would an addClass return a boolean? Doesn't make much sense. // $ :: String -> HTMLDocument -> HTMLElement const $ = (id, _document = document) => { if (isNullOrEmpty(id)) return null if (isNull(_document)) return null return _document.getElementById(id) || null } How can above be more readable than function $(id) { return document.getElementById(id); } I bet I can give the original code for Python/C/Java developers and they would understand / change it easily. That said, I consider myself a backend / devops person who sometimes needs to do work in the frontend, the biggest project I did was a medium size app with around 40 routes that I used react, es5 and bootstrap. Big fan of Go and it's very readable / limited syntax.
- reitoei 8y agoITT: People losing their shit over 149 lines of basic JavaScript code.