Hacker News new | past | comments | ask | show | jobs | submit login
How true hackers write JavaScript (news.ycombinator.com)
403 points by damir on Sept 5, 2018 | hide | past | favorite | 328 comments



Way 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!


Animations 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.


I 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.


Yeah, 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/ 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.


I was at the bottom of Africa last month with unstable internet connection barely faster than dial-up. HN was the only site I could connect before getting timeouts and bs.


I get one of your points, that some sites should work in the bottom of Africa. But there is a counter-point here, no? Why should a site be developed for the worst of connections out there? Is there a middle point here?


If it works on a crappy dial-up connection it should be nice and fast on a decent connection. Slow loading pages turn visitors away.


Horrible designs and lack of features do too.


Um, 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?


I don't know if the author is experienced or not. But something I do know, is that the more experience I get, the more I fear dependencies and the more I value simplicity.

HN is a simple website. I'm glad that they decided to keep the code simple as well. I love the fact that the code almost fits in a single screen. Zero dependencies. You can understand the entire code in a few minutes.

I think new developers greatly underestimate the negative impact of dependencies. Today, something like create-react-app downloads hundreds of megabytes of dependencies. Libraries, transpilers, compiler extensions, and various tooling. Of course all those things come with many advantages, but what most people miss is the huge cost of all that. The increased complexity introduced by dependencies. The unnecessary bloat.

Sure, the way you name your variables have an impact on readability. But it's nothing compared to adding thousands of dependencies to your project.


>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.


Assembly, 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.


Fair 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.


That’s true.


At 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 :)


macOS just notified me that one tab in Safari was using so much memory it was threatening performance of my laptop. The website in question? https://idioms.thefreedictionary.com/ It was close to 2Gb RAM usage. Bunch of ad-tracking stuff, I assume, as Firefox and its related processes seem to be using less than 1250mb with 6 tabs open, including the site mentioned in 2 tabs. My firefox has uBlock origin installed.

Seemed related to the second paragraph in your comment


Last week my bandwidth grounded to a halt which is usually the result of someone uploading on my network.

I went to my girlfriend's computer to see if she was syncing with Dropbox or something. Nope. She quit all of her applications just to be sure. Except for a single browser tab opened to a recipe for pita bread.

Yep, turned out that a recipe for pita bread was saturating our router because what looked to be buggy error-handling for ad-related network code. I think her ad-blocker only partially maimed it, so it went apeshit.


How was the pita?


Sounds like a PITA recipe


There is a certain irony about a dictionary web-page using 3 times more memory than it takes to store the entire Oxford English dictionary (and accessory publications), that is undoubtedly more complete.


> 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...

False dilemma. Code can be concise and readable.

> JS is the assembly of the web

No. Assembly is supposed to have a virtually one-to-one correspondence with machine code. JavaScript is far from that. It is a higher-level language.

> do you also criticize games written in assembly?

I would indeed criticize someone writing a game in assembly if an alternative was available.


> JS is the assembly of the web, do you also criticize games written in assembly?

If it's a typical platformer from 1980s, now. If it's a modern game with a modern game's complexity, it would never be finished in assembly anyway.


Then again, clones of games from 1980s in modern engines are considered toy projects. The equivalent on the web is considered standard practice.


> JS is the assembly of the web, do you also criticize games written in assembly?

hm


Maybe 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.


I don't like criticizing the code since it clearly works as intended and HN works very well, and I am a happy user. But since you argue that the code is very deliberately maintainable I will challenge that, because I am not convinced. The code is tightly coupled to the HTML in a way that makes it difficult to change the HTML without breaking the code. For example it should (if the code is so maintainable) be trivial to change the use of tables for presentation into semantic HTML like say UL/LI. Since this would improve accessibility this is a net win with no drawbacks, right?


This is hard to discuss clearly without the rest of the code being visible (sorry—I know that would be interesting but we just can't). But the general reason why that argument doesn't apply is that maintainability is relative to the goals of a project, and making it "trivial to change the use of tables for presentation into semantic HTML" is not a main goal of this project [1]. Meanwhile the cost would be high: it would take a lot of code to give HN's software the property that its markup could easily be switched between two dissimilar structures. High cost and low benefit adds up to not worth doing for this program. (Of course it could be different for other programs.)

And that's merely the best-case scenario; systems that go for that rarely make it to 100%. What usually happens is they find abstractions that give 90% of the desired flexibility, but break down at the problem's edges and require special-casing and workarounds to sort of hobble their way to the finish line. The complexity of that special-casing means you end up giving back a lot of the maintainability you hoped to win with such a design. It's like grabbing a handful of sand: a lot slips through your fingers.

Since we're not going for full decoupling and flexibility, what should we do? Here we differ from what most developers would consider best practice. We don't adopt half-measures, we try to avoid them. Since we're not trying to fully abstract away the structure of the markup, we just let that structure be naked in the code. For example, since 'hide' needs to remove 3 nodes, it just removes 3 nodes. We do it this way not because we don't know the risks of dependencies, but because we know the risks of abstractions: most cost more than they're worth. Programmers have been so steeped in 'best practices' that they tend to incur those costs without being sufficiently aware of them. Alice does it for her feature, Bob does it for his, neither's top priority is the system as a whole, and the costs build up like mercury in the blood. To be fair, most programmers have little choice, given the project they're on and the culture of the profession. You can see how deeply engrained this culture is by the bulk of the responses in this thread. In my experience, one can't fight it. One can only look for a project with different thinking (which btw is why sctb and I are here).

Our profession has a large blind spot about the downside of adding code. Obvious abstractions that have a best-practicey feel (e.g. assigning names to the nodes that 'hide' has to remove, or putting the nodes into a collection so 'hide' need only remove one thing instead of three) are like that old adage "no one ever got fired for buying IBM". You make a suboptimal choice because it feels like you're supposed to and it feels safer. That dooms software. All those little choices add complexity, complexity compounds rapidly, and soon you are paralyzed with bloat. To avoid this you need heightened, even paranoid awareness of the downside, which unfortunately runs opposite to most software culture. I'm actually not very good at it; others are much better [2]. pg never adds a line of code unless he's forced to. Me, I add 10 lines of code, then feel embarrassed and and remove 7 or 8 of them. But at least I feel embarrassed.

So that little number 3 in 'hide' is not there because we're naive and made a rookie error, waiting to be uncovered by the internet—it's because we considered the code that various options would cost, considered what they'd buy us, and decided that in the context of this system the simpler approach was best. That's what I meant about the code being written for maintainability. If you do that in every case and you're lucky and the moon is in Sagittarius, maybe you evade the rigor mortis of complexity and live to hack another day.

[1] In case that sounds like dissing accessibility, I'm not, but it would take time to explain why and I don't think those reasons are in the critical path of this discussion.

[2] If anyone wants more grizzled advice, mine is to search out a programmer who is better at this than you are and make it a career goal to work with them.


Thanks for an interesting answer. I really appreciate to hear the thinking behind the design of the code. But when it comes down to it, the argument seem to be that this piece of code is not supposed to be maintainable because you don't find it important to be able to easily change the HTML. Which again is totally fine if that is a deliberate decision, but there is a difference between arguing that some code is designed for maintainability and arguing that it it does not need to be maintainable.

As for adding code, note that my suggestion would remove code - removing a single node in code is obviously simpler than removing a fixed number of nodes in a for loop. But you are correct it introduces an abstraction. I appreciate the cost you assign to abstraction, but I personally think this should be weighed against the cost of more complex and fragile code as here.

Again, I'm not criticizing the code itself, just the assertion that the code is super maintainable. The proof of the pudding is in the eating. If it is too costly to accommodate users using screen readers (how few and unimportant they may be) because of the complexity and risk of changing the HTML, then you have a maintainability issue.


It sounds like we mean different things by maintainability. What I mean is ease of keeping the existing system aligned with its current goals. What you're talking about, I would probably call extensibility, and indeed that is not what our code is written for.

In my experience the way to get extensibility is not to try for it, which leads to bloat, but rather to have the smallest system you can. A smaller system is easier to make a major change to than a larger system, and you don't need to anticipate the change in advance.


I'm sure nobody decided that it was an explicit goal of the site to have accessibility issues. It has those issues for historical reasons. Maintainability to me is being able to fix such relatively minor issues without everything coming crashing down. If it is too difficult to fix then the code is not maintainable whether or not the code is super small and compact. (Note I'm not arguing HN should be redesigned to use semantic markup, just using it as an example of reasonable maintenance.)

I would say simplicity is a really important part of maintainability, but that is not the same as smallness. For example, the for-loop mentioned is quite short and compact, no doubt about that. But to me it it not simple, because it is hard to figure out what it does and what happens when you change it. It is tightly coupled to the particulars of the HTML (even including the whitespace) so you have to dive into the HTML to see what nodes is removed and figure out yourself what is the implicit relationship between these three nodes. So is difficult to change without accidentally breaking something.

Making code simpler often leads to it also being shorter, which is good. But making code shorter without making it simpler just leads to unmaintainable cryptic code.

But I acknowledge maintainability also depends a lot on the people who are supposed to do the maintenance. I personal have limited memory, and I would forget what exactly those three nodes represented within hours of writing the code. I use abstraction and simplicity not because of some lofty ideal, but because I simply do not have the mental capacity to keep this amount of accidental complexity in my head. Your mileage may vary.


"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.


> 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.

So, like, maybe two people besides yourself.


The 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.


Hard 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.


functions 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.


You 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.


Yeah, I also like to minify the code before reading. It makes up to 5 times less code and it's fun to guess which letter stands for which function.


This is the only part that I thought could be significantly improved for the use case they have here. But to each his own.


Maybe the author used to write C


>But it's especially the inconsistent use of camelcase in function names than makes me think it's pretty amateurish.

Despite its size, this .js file has been modified throughout many many years probably by various authors.


A real amateur would have figured out how to write everything in a single function.


Yeah, 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.


But 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!


Also, there's an inexcusable lack of modal popups and dialogs on this site! They simply do not care about users! :-)


It looks like you're using an adblocker. Click here to upgrade to HackerNews Gold for just $1 a week!


I see no smiley but I assume the tongue is firmly in the cheek, no?


There 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?


I think the purpose of 'aeach' is not to rename, but to provide a conversion. 'aeach' converts to an array in order to be able to perform a 'forEach' on the non-array NodeLists.

The 3 elements being removed are the tr containing the story options, a literal whitespace node, and a tr used as a spacer.

I agree it is a coupling, and while accurate to describe as fragile or even really fragile, I personally would not have used those words.

I would feel more comfortable daring to make changes in this html and JavaScript than any other front-end code I've worked with in the last 15 years of my career. If for no other reason, the sheer small size of it and lack of external dependencies that you mentioned.


I did a lot of work on HNES for performance, and most of it was assigning meaning to HN's markup. I don't know if it's intentionally opaque or what, but this is just the way it is. The javascript and the html are bound together.

It's terse and effective, I suppose, but it was really interesting measuring pixels to judge comment nesting.

The JS itself is fine. It's the markup that's a mess.


Perhaps this why HN still uses tables for presentation - nobody dares to change it?

There's also simply no reason to change it, it works.


> 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.


Well 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.


Agreed. But getting divs to do what you want has also gotten considerably easier in the last 10 years. It used to be a lot more work/boilerplate to get a consistent div-based layout across all browsers down to IE 6.

As for the redesign, the total amount of code (HTML/CSS/JS) you’d need to touch is still small. Do web designers still exist that only do HTML/CSS but no JS?


> Do web designers still exist that only do HTML/CSS but no JS?

I hope so, given that most websites (as opposed to web apps) in existence should not need JS for core functionality.


> Do web designers still exist that only do HTML/CSS but no JS?

That is really beside the point. HTML and JS should not be coupled to the extent that adding or removing some whitespace from the HTML will cause the JS to fail. This kind of things turns a trivial improvement into a nightmare, so you end up not daring to change anything.


I expect the layout would also be simpler in another way: Give every "child" div a static indentation, nothing more. They'll nest and the indentation will stack the deeper the comments go.

Right now there's already nested tables-within-tables, just to work around how table columns work in order to handle indentation (and each row's indentation is handled separately with a stretched 1x1 image with a width attribute that's calculated server-side).


Or better still, use the HTML elements whose sole purpose is to display nested content: <UL> and <LI>


I'd argue it's far from ideal. Mainly because closing a large tree of comments can often hang the UI for a second or so while this JS runs to find and hide all the children that need to be hidden.

But it is simple, and it does get the job done for the most part.


It's true that the code is slow on large threads. That's on our list to fix. The last time I profiled it, it was (surprisingly to me) forEach that showed up as the culprit.


I figured, and to be honest it's not that big of a deal. I swear it used to be much worse when the collapsing comments first came out, but as I made that comment I realized that I actually had trouble triggering it.

Either way, it's a minor annoyance on an otherwise fantastic site!


Guys, it's 2018. Let's not have this conversation.


When I last looked into it, tables caused issues for screenreaders and the like.


Sure, don't fix it if it ain't broken. Today there is no reason to use tables for presentation, but that was probably not the case when HN was initially designed many years ago.


You could reach a happy medium if everything was well commented. Introduce a build step to strip comments if you have to. But you would get maintainability while still having full visibility into all the code that is executing.


It might be interesting to see an example of a comment that you (or anyone) thinks would add to maintainability. What isn't expressed in the code?

If there is such information, there are two possibilities: either we could easily modify the code to express it; or we could not. Each would be interesting, but for different reasons.


It's probable that HN is so feature-frozen it's not worth doing at this point, but if it were not, there are a few good reasons. The parent's example in hideStory() is a good start:

    for (var i=0; i < 3; i++) { remEl($(id).nextSibling) } // pop following options row, whitespace text node, .spacer
This way, if (for instance) someone were to try to modify the layout to use margins rather than spacers, or if someone were to strip whitespace from the rendered HTML, a quick search (or manual skim of the code when something breaks) for "spacer" or "whitespace" would help someone avoid needing to step through what's being removed in Dev Tools. Minimally invasive, would greatly help someone doing code review, and doesn't even increase line count. Documenting the helper methods at the top would help newcomers to the codebase as well.

More generally, going a step further, I've been inspired in my commenting style by Jeremy Ashkenas's literate code for the Backbone library. See, for instance, http://backbonejs.org/docs/backbone.html#section-111 . The code itself is as self-explanatory as any other code I've ever seen, but the comments serve to accelerate that browsing process. Backbone, while somewhat dated nowadays, is a great level of abstraction in that the entire library can be grokked in an afternoon - but without comments, I think it would take longer. Reading time does not monotonically increase with number of characters :)

And as a third point, if there's ever something confusing enough, or you're using some infrequently-used feature of the CSS/DOM spec, such that the author or reviewer needed to look up how it worked in documentation or a forum somewhere, I encourage my team to simply add that documentation or forum link into the comments. Extremely helpful for maintainability, particularly when onboarding junior team members, allows code reviews of that line to be asynchronous whereas they would otherwise require synchronous explanation, and it's ideally just as quick to keystroke "select-url/copy/close-documentation-tab/tab-into-codebase/start-comment/paste/enter" as it is to "close-documentation-tab/tab-into-codebase."

This is Hacker News - we're the antithesis of enforced Javadoc-style comments :) But if you consider someone needing to read code without having the live input of the author, minimal comments for especially terse or creative code can quickly start to make sense, certainly in the territory of the rightmost columns of https://xkcd.com/1205/


While I agree that comment would be very helpful given the code, It would be much better to rewrite the code so it didn't have to know about those three nodes at all. For example by collecting them into a single element which could be removed in a single operation. The comment here is just a bandaid for code which is much more complex than it needed to be.


I'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.


JS is OOP, although does not have classes. It has prototypes


Javascript 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.


should be using fat arrow functions.


What possible benefit would this have? Particularly considering it doesn't rely on "this" anywhere.


This 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


Is this a GET request? What if my browser wants to peek ahead on some links?


If the Image is being created dynamically there won't be anything for browser to peek ahead at.

Edit: I'd be more worried about repeated calls - but presumably the service being called is idempotent.


It's more the side effect of upvoting the whole thread that makes me wonder.

https://stackoverflow.com/questions/705782/why-shouldnt-data...


This would indeed be problematic :-) The up/down vote buttons are plain anchor elements.


Image makes the HTTP request without appending the Image to the DOM? TIL


That's how most tracking scripts operate...


Maybe 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.


Hacker News was launched 2007.

XMLHttpRequest has been around for about 7 years then and using it was called Ajax for about 2 years already.


Not to mention the "ajax" function in the script...


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).

This is complete supposition on my part.


There'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).


Probably. I wonder though if they are trying not to use any libraries and Image was just easier than xhr.


Not all that impressive, considering non-consistent code style and the like.

Also not a fan of unnecessarily cryptic variable names.


I think the title is ironic.


That might be one of the most readable pieces of code that I've ever read.


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


> 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?


He 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.


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.


I think the main reason this is somewhat readable is because there's hardly any code. Which is fine.


The supreme art of war is to subdue the enemy without fighting.

-sun tzu


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.


No, it is because some array-like objects like node lists actually aren't Arrays and don't have those functions in their prototype.


this is why I usually go for something like const $ = (el) => [...document.querySelectorAll(el)]


Although NodeList has forEach defined on it now at least.


Really? 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) : []


Your code is not more readable, it is just shorter.

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.


It's 2018. Unless you're using Internet Explorer arrow functions are supported natively.


And I bet there are some people here using IE. And old browsers.


I would REALLY love to see the browser usage statistics for HN :)


Well.. I might be an outlier, I use OmniWeb and Camino as they give the best results with my 2005 Mac. So I'm still living in the Pre-=> Age.


You're still returning a live HTMLCollection or an Array.

It's still bad code. Using newer syntax to do the same thing didn't actually improve anything.


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.


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).


Here's the citation: https://doc.rust-lang.org/reference/items/functions.html

> 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.


> 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.


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.


It was almost certainly written long before ES6 was widely supported.


Probably not worth setting up a babel transpiler for that small amount of JS tbh

Makes supporting older browsers a lot easier


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.


"pretty bad code"? That's an euphemism.


yes


So 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.


> So you would like to work a place with no code review?

How does this follow from my statement?


Sorry if I misunderstood.


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.


I usually read HN using w3m. It's entirely usable with no javascript.


It 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. ¯\_(ツ)_/¯


Not 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.


>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.


And no doubt I've written single methods/functions that where uglier.


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.


I think there are several different types of C programmers, and that terseness and functional design are very different.


Yes, and it reminds me also of Unix shell commands.


If there's one take away from this, it is that programmers have widely differing opinions on what constitutes good code.


The 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.)


    function 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.


Except 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.


And how will that someone know what that 3 stands for ? At the minimum a comment above that line would have been nice.


They'll figure it out. They're a programmer, figuring things out is their job.


hidestory() is not even used anywhere ; why is it here for? Debugging?


It's called by the "hide" link under each story on the top page.


It is probably called in an onclick=“” in the HTML somewhere


Like JS is never attached to a HTML template ?


Is this sarcasm? I hope it is.


Write 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).


If by 10 years ago you mean two years ago, then yes. Unvote was added two years ago.

Thing is simple, unreadable, and it works. Turns out, code can both work and be shit at the same time. We've all done it.


That'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?


I'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.


This 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.


Do 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.


Right, my point was that this is a subset of modern approaches.


You are right.


I 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.


There 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).


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.


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.

[1] https://medium.com/@vikigreen/impact-of-slow-page-load-time-... [2] http://glinden.blogspot.com/2006/11/marissa-mayer-at-web-20....


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.


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.


I 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.


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.


your choice, it's your cells :) I would not want to dot that to my sanity.


Steam forums on the other hand are an abomination stitched together from every content tracker and third party js library ever written.


Why is rendering on the server part of that list?


While 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


We expanded it for collapsible comments a few years ago.


Been 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 :)


Am 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; }


+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.


It 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?


Why it can't be both? And, Yes - it can


It'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.


The 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.


The code is very much readable, without suffering from being concise. Love it.


    function onready () {
      recoll();
    }

    document.addEventListener("DOMContentLoaded", onready);
Just attach recoll() directly. There's no benefit of going via onready().


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.


`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.)


Originally there was something else in that function body. That's also why we didn't collapse it when we took that bit out.


Love it. Looks like lisp (can almost tell pg or rtm wrote it?), functions all over. No bloat...


This 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/cla...

[1] https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/r...


Why should anyone invest lifetime to remove compatibility from a perfectly working application? Just to prove that not everyone is using an evergreen browser?


Looks like pretty average code to me.


    function aeach (fn, a) { return Array.prototype.forEach.call(a, fn) }
Does this win anything over using forEach directly?


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].


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.


DOM functions like getElementsByClassName return a nodelist, which as you say behaves like an array.


This function could be used to iterate over the `arguments` array like object, but I do not think it is used for that purpose here.


It's used to iterate over HTMLCollection objects here.


This 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.


To me this looks more like transpiler output ...


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.


I 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.


I believe there is a difference between gold-standard perfect code and just making "beginners mistakes".

It costs almost nothing more to write "event" instead of "ev" or "removeElement" instead of "remEl", but it makes the code much more readable. You might gain 1s for writting remEl instead of removeElement but you will loose more seconds in the future trying to remember what remEl stands for, or having to check what abbreviation you chose for that function.

It's just something programmers learn with experience (even when working alone) : abbreviations are a false good idea, and people are just pointing that out.


> It costs almost nothing more to write "event" instead of "ev" or "removeElement" instead of "remEl", but it makes the code much more readable.

No, it doesn't. Unless you're an absolute beginner, it takes you a couple of seconds to realize that in this codebase, "ev" (or "evt" or even "e") means "event". The same goes for "remEl". If that's consistent, then it's not a big deal at all.

Having less characters makes code more readable (or rather "scannable") as well, it's just another tradeoff.


>Having less characters makes code more readable (or rather "scannable") as well, it's just another tradeoff.

Only to a point, otherwise minified js would be more legible than plain source. It takes "a couple of seconds" to scan the codebase and find out what el or ev refer to, but it would take zero seconds if they were just called "event" or "element."[0] There's no gain in readability from shaving off one or two characters in that case. It just "feels" more efficient because it resembles the common style of lower level code.

[0]Assuming those aren't reserved words in javascript, I don't know.


Of course, up to a point. The same goes for very long but extremely descriptive variable names. Hence, it is a tradeoff.


You are allowed to use both event and element, as they aren't strictly reserved keywords.

I think it's generally frowned upon, though. For example, I believe "event" is defined as a global in browsers (on window, perhaps?), so you run the risk of shadowed variables and accidentally referring to the wrong thing.


Having anything take a couple of seconds more to read something is by definition making something less readable.

Okay so perhaps a couple of seconds doesn't matter. How many seconds does?


There's an objective definition for readable?


426.


Less characters really only makes sense in some scenarios, e.g. "unimportant" variables (for loops, temporary storage inside a procedure). Verbose 'variablesToKeepTrackOfPositionInThisLoop' is obviously pointless when 'i' will do.

However renaming "important" things to make it quicker to read or type is, in my experience, a mistake if your code base is more than just a handful of files. Descriptive names make it much easier to understand the code which is more important in my experience. As the number of code files gets beyond a few files any benefits you get are rapidly lost because now you need to keep all that knowledge in your head and start having to jump around between 5, 10, 20 or more files to work out what everything is let alone what it is doing. This is why naming stuff in code is so important (and sometimes so hard).

Golang has a good philosophy on this front: https://github.com/golang/go/wiki/CodeReviewComments#variabl... tl-dr: the further from its declaration that a name is used, the more descriptive it should be.

This sort of attitude about brevity & speed appears to be a common problem with some developers I come across - they are absolutely obsessed with "productivity" when it comes to writing code. They've just got to have their 97 plugins/extensions to their editor and they simply must have their finely-honed emacs keybindings. If you are focusing on just churning out code as fast as humanly possible (i.e. "productivity"), then your job as a programmer can probably be safely replaced with a couple of shell-scripts.

I've never been in a situation where the limiting factor in programming has been how fast I can read it or write it - the limiting factor has always been understanding the problem at hand, and designing a solution that solves the problem and is maintainable.


The point I'm making is not "use short variables everywhere", it's that in this case, the verbose alternative is not "much more readable".

Abbreviating "element" to "el" or using "attr" instead of "attribute" (etc.) can significantly reduce noise in web client code. Everybody either knows what it means, or they shouldn't be editing the code in the first place.


I prefer "elem" as then it's easier to distinguish from "event" than it is for "el" and "ev".


> Verbose 'variablesToKeepTrackOfPositionInThisLoop' is obviously pointless when 'i' will do

Based on a Fortran convention, IIRC. Within a web setting, "el" and "ev" are extremely conventional.


> tl-dr: the further from its declaration that a name is used, the more descriptive it should be.

Interestingly, this results in more or less the opposite of entropy coding


> Having less characters makes code more readable (or rather "scannable") as well, it's just another tradeoff.

It might, in a specific circumstance, while in another circumstance it might make the code significantly less readable. That is an indication that number of characters is probably not a good metric for adjusting readability.


Couldn't agree more, sometimes too long makes things so much worse. I don't know why this is more common in Java code bases, but I've definitely seen function calls that take 6+ lines (have to maintain that 80 column limit) due to horrible naming. By the time I finish reading that, I've already forgotten what the base class is even called.

However, I've also seen large classes with members like "stN" for "set N". WTF is N, and why can't we just type set, that one char doesn't save anybody any time at all. Or nested loops with i & j reversed, just to make it especially painful.


Unless you're a machine, don't know what to tell you.


>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.


> 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.


True this


Eh, 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).


This 100x times. There is very little code there. Any effort in trying to bring it up to modern webdev standards would likely make the code expand significantly, and that's not even counting the complexity of the deployment pipeline. This here, it's just 150 lines of plain code. It's not hard to work with something like this.


I'm not saying a rewrite is necessary at all, but refactoring this code to use more modern standards would NOT increase the line count at all, my guess it it might cut it by 15%+ in total size if you leveraged the beautiful builtin functions. Compare these:

    function addClass (el, cl) { if (el) { var a = el.className.split(' '); if (!afind(cl, a)) { a.unshift(cl); el.className = a.join(' ')}} }

Could turn into something like this:

  const addClass = (el, cl) => el.classList.add(cl)
Not only is is shorter, but it's more readable too!


> Not only is is shorter, but it's more readable too!

And won't work on IE. Not just because of el.classList, but also because of the arrow notation. So by doing this change, you either have to ditch one of still used browsers, or introduce a stupidly complex transpilation chain into the mix.


I'm aware, but I'm responding to the myth of:

> Any effort in trying to bring it up to modern webdev standards would likely make the code expand significantly

That's just not true, and nowhere did that person say: "Because of legacy IE support requirements", they only mentioned "modern webdev standards".

Are you suggesting arrow functions, and classList aren't modern standards then?


I was that person, and what I meant was that "modern webdev standards" would include modules and features requiring transpilation, which would introduce many dependencies, all of which count into code size (you have to keep track of them mentally).


Why/where would modules be necessary here? Just because there's a feature now that didn't exist years ago doesn't mean it's the right time & place to use it. The code works as-is, a small refactor to leverage built-in functions to do some of the trickier logic parts would make this code a breeze. There's no need for something like Babel to help out with a small refactor.


el.classList isn't supported by IE < 10


And is it accurate to describe IE < 10 as "more modern"?


It isn't, and I don't think I have.

My point was that using a "more modern standard" would break hn for people using legacy browsers.


The code is entirely self-contained. That's what makes it easier for future-you to understand and decipher. Dependencies won't have gone out of date, library versions won't have moved on, APIs won't have disappeared, etc.


> As long as the code works, anything else is just gravy

I'll try to incorporate this in my next job interview :)


The code is readable. There is no problem.

> As long as the code works, anything else is just gravy.

How did you end up with this opinion? That's an unpopular opinion even when considering the qualifiers you've listed in the paragraph above.


I think there are two ways of looking at this.

From the top down (strategic), and from the bottom up (tactical).

Depending on your perspective, you will likely fixate on different things.

If you're starting from the bottom, you'll probably be more interested in the coding choices made by the developer.

If you're coming from the top, you'll probably look at the goals of the site and whether the code met them, and then consider other details like optimization and cleanliness to be secondary ('gravy').

When I was in biz-school in the 90s, we used to spend a lot of time talking about effectiveness (the end result does what it needs to do) and efficiency (the end result does what it needs to do and is optimized for -insert criteria here-).

Ideally, you get to be both effective and efficient. If, however, you can only be one, it's better to be effective.


> As long as the code works, anything else is just gravy.

“It works” is one of the lowest imaginable quality bars for software to meet, one notch up from “It compiles.” Through my career I’ve worked with way, way too much code where the developer stopped at step one (it works).


Yes exactly. KISS people!


> As long as the code works, anything else is just gravy.

Nonsense. Maintainability almost always matters.

As the adage goes: code shouldn't merely work, it should clearly work.

> 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.

Indeed, but Sturgeon's Law shouldn't make us feel better.


In this particular case, the fact that the code is so terse makes it immensely more maintainable than a whole architecture + framework.

The HN code is meant to be understood as a self-contained piece, and that's contextually very different from most code out there.


> Nonsense. Maintainability almost always matters.

The last three large corporations I worked for never cared about maintainability because the application or portal would only be in use for maybe a year or 18 months before a complete rewrite or total redesign.

All of the recent projects I've been on take the same approach. Get it stood up, make it look pretty and release it. Because agile development makes business owners believe it only takes a few days to build Rome now, maintainability is never a consideration on any of the projects I've been on. Even senior devs are saying, "It's pretty hacky to get this to work, but it works" is a common troupe on our teams. I agree maintainability should be important, but on the agile projects I've been on, nobody cares about it.

To some degree I think executives do it on purpose so they can create more work for themselves in the future. They can pick it apart, ask for a bigger budget, hire more devs and use some shiny new technology to build it over again. Rinse, repeat.


> The last three large corporations I worked for never cared about maintainability because the application or portal would only be in use for maybe a year or 18 months before a complete rewrite or total redesign.

The first significant web app that I wrote had a similar approach. I was a new developer, but I had a good idea and they hired a manager and a couple of other developers to flesh it out. No need to hire a senior dev, because it was just a POC. We weren't even part of IT, so anything we built would of course only be in use for a few months before IT would allocated "real" developers to rewrite it.

Four years after I left that job, I got a call one day that the site was down and they couldn't fix it. After ten minutes on the phone with a former colleague reading me the logs out loud while I read through an old copy of the code that I (thankfully) still had on an archived drive, it turns out that the LDAP server's address had changed. We updated that and it came back.

Out of curiosity, I had them run `uptime` on that box. It had been up for six years - the two years I was there, and the four since I'd left. Not only had the application continued to function and be used... the box it was running on hadn't been updated restarted since it was built. It hadn't gotten updates since I'd left either.

The point of this story is simple: there is no such thing as code where maintainability doesn't matter, because there is no such thing as "temporary" code. Code can get retired or refactored away, sure, but there is absolutely no way to tell ahead of time if any given code snippet falls into that category.


the application or portal would only be in use for maybe a year or 18 months before a complete rewrite or total redesign

Why on earth is this such a popular idea? Do customers somehow prefer to see all the buttons in new places and old urls broken every other year?


I'm honestly not sure. When I first started out, all the applications I used had been built five years prior. We made small tweaks and continued to use them because they just worked

Now? I think newer technologies come out faster and capture people's attention. They want to use the new shiny thing. I think the "business people" want to have a big budget project to get recognition within large orgs. I think developers want to use the latest and coolest stuff. I think people feel like we already live in a disposable culture, why would our sites and apps be any different? You combine all of these and suddenly the pressure and inertia not to move or rebuild or redesign regularly is too much to overcome.

I still remember going to a ReactJS class and the guy running it kept saying, "Don't get me wrong, BackboneJS is still a hell of a library and is still relevant and awesome to build stuff with BUT React does a few things better."

This is where we are. Huge financial investments, time and energy to get a 3-5% bump in efficiency? Doesn't make sense to me.


[flagged]


Please don't cross into personal swipes like that.

https://news.ycombinator.com/newsguidelines.html


Lol 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.


I 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. =(


Criticisms 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 ;


To 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.


I should fix that, since sctb probably agrees with you and is too polite to say so.

Any suggestions for me as a shitty semicolonist?


You 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://prettier.io/

I prefer Standard JS, but either way it's easier to not need to think about the exact details IMO :)


I'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.


Here'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.)


"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".


I actually think this code is nice! Love the one liners. Variable names could be a little more....explicit.


> 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...


...for a site as simple as hn

Yes!


Most bloated sites don't even have an excuse to be more complicated than this.


Web apps do, though.


True Because hackers need much more code lines than those.


OP 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.


Everything 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


>> 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.


The 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.


I 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.


Yes, and just to express the same idea from a different perspective... you need to deliver the features needed by your business.

In a small, simple, established site, those needs don't change often, so the code doesn't change often, and you can focus more on performance than maintainability, as well as spend your efforts on non-coding tasks.

In a startup when you are finding your market and seeking product/market fit, and you've got investors demanding speedy delivery of a product to customers, the attempted solution is often a large team with fast and numerous code changes. And then you do have to optimize for the devs, because even though the final goal is customer satisfaction, devs need to perform efficiently to hit that goal.

The needs of the codebase still tie back to the needs of the business. One answer does not fit all.


> Most web app developers don't live in this world

Really? Most Javascript developers live in the world of trillion-dollar startups serving billions of people? That's why they need Kubernetes, React, and 2000 nodejs modules to show a couple of confirmation dialogs on the SOHO website they are working on.


Right, and "true hackers" aren't team players if they're slanging this all over the place.


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.

Nevertheless, the code looks kinda beautiful.


  My 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
  }


I 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.


He/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.


I’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.


I 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/


I'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));
    };


My personal microframework:

    const node = (tag = 'div', attributes = {}, inner) => {
        const e = document.createElement(tag);

        for(const [key, value] of Object.entries(atrributes))
            e.setAttribute(key, value);

        if(inner) e.innerHTML = inner;

        return e;
    };
The premium version contains an additional:

    e.child = (a,b,c) => { const f = node(a,b,c); e.appendChild(f); return f; };


Yeah 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.


I 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.


Why not:

function vis(el, on) { if (el) { (on ? remClass : addClass)(el, 'nosee') } }

?


Ahh 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 :)


Yes, that's better, especially since we do it elsewhere. Thanks!


  function $(id) { return document.getElementById(id); }
Nice! Now I don't need jQuery.


Here's the smallest jQuery replacement I've seen :)

https://gist.github.com/paulirish/12fb951a8b893a454b32

It let's you do

    $('p').on('click', el => /* ... */)
which is handy for smaller scripts :)


Seriously 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.


let 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


var 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.


const. 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.


More garbage ycombinator hero worship. 'True Hackers' ? Grow up!


One 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!


In 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!).


I understood it to be a tongue-in-cheek title


You do things ironically long enough, you end up just doing the thing...


Yep, kinda recursive...


The less lines of code, the less chance for a bug.


IMO, this code is perfectly fine if you are one guy, never plan/want to change anything and don't expect your site to grow.


I dunno. Is posf really better than indexOf? Why not use more conventional names for the underscore-ish functions they made?


It only exists because DOM APIs are crap, and jQuery is too big. So it ends up reimplementing parts of jQuery needed to run.


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.

[1]: https://code.jquery.com/jquery-3.3.1.min.js [2]: https://code.jquery.com/jquery-3.3.1.slim.min.js


In contrast, hn.js only weighs 2.1kb and contains all the business logic.


And it isn't even minified. So if there would be a problem in production it would be easily debuggable.


Simple, straight forward and does the job.


Is this some Arc-to-JS transpilation?


Probably not yet, but I've heard this might be the case in the future.


We have Arc to JS working in production now, but only use it for moderation software. The generated output is inevitably more verbose and we wouldn't want to inflict that on every page load.


Looks like they are wrapping javascript functions instead of just using the functions.


Someone 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.


It's just a pile of functions; no actual processes are scripted to execute.


ITT: People losing their shit over 149 lines of basic JavaScript code.


No ES2046, is that legacy?


"True Hackers" can write LISP in any language?


It works reliably and quickly, so mission accomplished.


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.


There'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.


any more javascript than this and you're probably making something that's full of ads


Or something that has features?


Undocumented features??


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?'.


> 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.


Yeah, 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 ;)


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.


Official name of the one line per function framework is FOOL - Functions on one line.


document.querySelector('pre').style.color = '#17c517';


Neat


any example on how to use this JS code?


Yes, the page you are currently reading.


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!

That code is 'humble-bragging' ...


Really? It just looks compact and efficient to me.


"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.


> 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.


Post-processors do that much better than a human and can also tree-shake. There's no reason for a human to do it.


Too compact? It's the size of an APL implementation, and all it does is some ux... ;)


Exactly, 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


I 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...


If you really need a shortcut then

    const $ = (sel, elem = document) => [ ...elem.querySelectorAll(sel) ]
is nicer as you can use CSS selectors.


Yep, that's about how much JS your site should contain if you're a sane person.


we 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.


Is it September already?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: