Hacker News new | past | comments | ask | show | jobs | submit login
Human JavaScript (humanjavascript.com)
154 points by robin_reala on June 26, 2014 | hide | past | favorite | 40 comments



I really like opinionated books like these.

I've a question for HN on one of the opinions in this book: "use Browserify". There is only 1 single reason I don't currently use Browserify for client-side web apps: debugging. If Browserify turns all my files into one big file, all the time, and that's the only way, then how am I going to debug without going insane?

I know about source maps, but I use many compile-to-JS languages (TypeScript and React's JSX, in my case), and they provide source maps already. Afaik, Browserify doesn't re-map those source maps, or something like that.

Can I conclude that people who use Browserify simply never use compile-to-JS languages? Am I really forced to choose one of:

    * Avoid Browserify (and similar tools)
    * Write only vanilla JS
    * Deal with having to in-browser-debug a single 20000 line JS file
    * Finally spend time to contribute source map remapping to Browserify
Any ideas? Am I missing something awesome?


Browserify's --debug flag sets up source maps per-file and works just fine for me with transpiled CoffeeScript files (mapping to the original .coffee)

I'm not sure if there's something different about TS and React but I'd imagine if they have source map support it should work similarly?


You can't use the default transpilers. If you do, browserify can't really follow the source maps. But you're not alone!

For React JSX, you can use the browserify transform reactify. For typescript, you can use typescriptify. They should be right there in npm :)

If you're using karma as a testrunner though, I highly s suggest karma-browserifast over karma-browserify. It's orders of magnitude faster, and supports the latest jasmine and karma (the former does not). The former runs in O(n!) where n is the number of spec files. Yikes!


Browserify has had source maps since v2: http://thlorenz.com/blog/browserify-sourcemaps

Just pass {debug: true} to build function.


This probably only works if you're using a transpiler transform in the browserify pipeline. (instead of running browserify on an already-transpiled codebase)


Oh, got it. I misread the original comment.


No worries :)

I like that you're focusing so heavily on commonjs+browserify. We've made the switch for new projects as well. I'm curious as to why you advocate wildemitter over browserify's client side port of EventEmitter? Is it a lot lighter?


I use Browserify with Coffeescript modules, and the source maps work great. I'm using Coffeeify to do it: https://github.com/jnordberg/coffeeify


Browserify manages to remap our source maps... but we're using coffeeify to do that


> "What about load times and performance?!?!"

If you're rendering everything on the client like that, how many HTTP requests are you making, other than the initial 3 (stylesheet + javascript + html document)?

I'm especially focusing on mobile performance, here. On 3G you have 200-2500ms latency on the control plane, 200ms latency for dns lookup, 200ms latency on establishishing a tcp connection, your TLS handshake will have a latency anywhere from 200-400ms and the actual http request will have a latency of 200ms.

That's 1000-2900ms per http request, minus 100 if your client can cache DNS responses (and everything is on the same domain). Sometimes these will be multiplexed. You can't count on it though. 4G is only marginally better: you have an overhead of 240-500ms on 4G.

And none of that takes into account the time it takes your server to process a request, or the time it takes for the client to parse and execute your rendering codebase.

If you're aiming for sub-1000ms request-to-glass, you can't follow the advice of this book (don't render anything on the server ever) - unless you don't mind the client showing a loading animation for the 2-15 seconds it'll take to load your "app."

(good luck with that mobile bounce rate)

0. https://www.youtube.com/watch?v=Il4swGfTOSM


Yup, I don't disagree, this fact sucks. If you keep reading you'll notice I suggest not doing this for apps that aren't behind a login.

You can use login pages to prime caches, pre-render, etc. That's certainly not a panacea, but can help.

With the right cache headers on the main application assets and a primed cache you can start executing code immediately and eliminate all but your data calls on a good portion of app loads. From my experience, with a primed cache it's not too difficult to get comparable load times to opening a native app.

I'm hoping ServiceWorkers, Improved local databases, and HTTP 2.0 can help us out here.

There's also the option of trying to do the initial render server-side. I've experimented a bit with this, and have some more thoughts and approaches I want to try for this. But, I have yet to see someone do this is a way that didn't add a significant amount of complexity to the codebase :-/


Yup. For those of us working on highly dynamic non-app sites things are a bit more difficult.

I only had time to skim the introductions earlier - I'll have to give it a full read.


I skimmed a few chapters and as someone who writes Javascript all day, this looks pretty good. I want to dig into it more.

But I'm going to be "that-guy" and say $39 is too much just to get the kindle/PDF version. I buy a ton of programming books and I tend to only fork that much over for authoritative paper textbooks on particular subjects. Rarely digital versions. Otherwise I'm all with Patrick McKenzie on charging more.


Agreed, I don't have a problem buying digital books, but $39 is too much.


I suspect that if Henrik is already giving away a digital version, with the paid version he's targeting high-rollers motivated to buy one out of a sense of gratitude/largesse. So a high price tag sort of makes sense.


It seems a tad silly to argue about price when it's free, no? ;)

If you pick up a single tip that saves you an hour of effort you've paid for the book.


Yea I agree, since it's online for free I think it'd be better if they went the HumbleBundle route and allowed users to enter in a price.


You can likely write it off for a tax deduction, at least, or ask your employer to expense it.


In the 'Writing code for humans.' section are the first three code examples meant to do the same thing? The first and third check whether the array contains 'hello' but the second does the opposite.


I guess it wasn't so clear after all. I think this makes the third example even stronger: use a method that is named what it does.


Haha, this is an epic typo :) Sorry, will fix.


No problem :) it looks really good - just thought I'd point that out!


I stopped reading at the tilde argument for readability. I find the tilde token far more readable and easier to spot, and there's no confusion as to what the indexOf is checking for, the existence of an element in an array, where with the equality comparison tokens I need to stop and read what the heck it is comparing to. These should be reserved for when it's checking for a specific index or range.

Those extra seconds add up and in my opinion readability is more about optimizing reading speed by using common shapes and patterns conventionally, not making something dumb proof.

It even suggests using a dependency like underscore for something that is already in the language. So if I don't use underscore, I need to stop my reading completely because my mind doesn't recognize this _(array).contains('foo') pattern and I need to actively read the entire line and in cases lookup the documentation of some random method in a random obscure _ library that I also need to lookup in the code to find the actual dependency name. Because even if I were to check the implementation of that underscore method using the IDE, it's even more obscure and magic. Good luck following the advice in this book.


I think the tilde operator and Underscore are both equally cryptic and represent similar degrees of obfuscation. Tilde doesn't get much use, because it's prone to quirky behavior, particularly with respect to negative one in javascript. Gven that javascript has junk lying around like NaN, undefined, null, ==, ===, I tend to mistrust anything that isn't dog-ugly bland convention.

Aliases are also ugly in my opinion, given that they can be reassigned any old time. Even the much-used dollar sign alias demands extra scrutiny, when inspectng unfamiliar code. The advantage is that they're (aliases, that is) are easy to write, not easy read. On the other hand, the "contains" function should adhere to the sanest contract most would expect from it, and if it does, "contains" is easy enough to understand. But yeah, depending on libraries is either laziness or bullshit, when it comes to core language functionality. The only thing advanced libraries really offer is cross-browser compatibility.

Meanwhile, (x.indexOf(y) == -1) is dead simple, as long as you know that arrays start at zero, never have negative indices, and that indexOf() returns a negative value when the argument isn't matched by an object in the array. Returning a negative value, as parlance for "not found", when an absolute integer value is expected, is a pretty sane convention.


That's what I mean by using patterns and shapes conventionally. By using the tilde only on indexOfs (math aside), it immediately communicates its reason and when you don't see it and instead see equality operators you know that it's NOT a 'has' operation but it's something that needs more attention. Of course this depends on a lot of people doing it besides you, but most of the code I trust and use mostly uses this pattern.


Underscore is not an obscure library. It's one of the most widely used JS (or even just code) libraries in existence. Look at the number of stars and forks on github.


I'm really interested how people here react to the "Picking your tools" part in the introduction.

Some pretty strong opinions that contradict current trends in front-end world. I actually waited for someone to break the mould and start questioning the status quo. Especially regarding the use of DSLs and logic in templates.


Until recently I didn't even know that there was a status quo in the frontend development. I worked with JavaScript in exactly the same way I'd work with any other language where stdlib is minimal at best (like Scheme or C) and that was to design the app, fill as many blanks as possible with libraries and write the rest myself.

Now I'm forced to use Angular and frankly, I'm frightened. There is no room for designing the architecture of my app - it's been taken care of - yet I'm still going to be held responsible for this architecture shortcomings, if I happen to stumble upon some of them.

Of course, codification of some conventions may be convenient and so I'm not against frameworks in general. But I know that sooner or later I will need an escape hatch to do something less than conventional and I want my framework to just get out of my way for a while. That's what Pyramid does and what Django starts to support in recent versions. I'm not yet familiar enough with them, but I suspect Angular, Ember and some others are not that great in this respect.

In short, while I never was very interested in front-end development, I did build some single-page apps, and I - after skimming a few chapters of this book - always worked similarly to what the author proposes. I really do hope that this approach will become dominant (once again, everything old becomes new again and all that), if for no other reason then because I just enjoy designing and writing in this style more.

[PS. It's nice to see you're still alive :)]


Hi, likewise :)

On topic: agree on Pyramid / Django comparison. It was a nice, eye-opening experience to work on Pyramid project after only Django-based ones.

Though I doubt the same applies to Angular / Ember.


My personal opinions on templates, for Javascript and other languages are:

* Use something that is HTML-aware instead of something that treats HTML as text. Even if you have the template engine still spit out HTML strings in the end its going to be able to escape user data in a context-aware manner and get rid of useless whitespace.

* Logic in templates is fine and separation of concerns between view and model does not have to mean using different languages for them. My impression is that most "logic-less" templates eventually reinvent broken versions of variables, loops, conditionals and subroutines so I would rather use a real language from the start. An example I like is giving different classes to odd and even rows in a table. The solution is obvious if you use regular loops but can be quite tricky in many template engines.


I generally agree with him regarding the picking your tools part, but some of it seems a contradiction.

   Tools where you build the app by writing code in
   JavaScript files, not by trying to declare too much of 
   your app logic in your HTML (no AngularJS, sorry).

   The DOM is simply a view of the state and reacts to 
   changes in the model layer.
That's pretty much Angular's philosophy as well.

that said, this:

   People who already know JavaScript should be able to 
   work on the app without lots of knowledge about a 
   specific tool or framework.
IMO trumps all.


My main point was just that it's never felt right for me personally when I try to write too much logic into templates directly. Because at the point where you hit the limit of what that abstraction supports you now have to solve that problem outside of the abstraction, fragmenting your code.

/me shrugs

It's all about how much you actually need to customize beyond what you get from something like angular out of the box.

I'm not wanting to fight a framework war, that's for sure. If angular works well for someone, that's awesome they should keep using it.

The item you pointed out in the second quote, yup... that's a big deal for us.


I'd like to comment on this remark: "Tools that are "just JavaScript." Not tools where you describe your app in a DSL (no Sencha). This is to avoid requiring too much knowledge of the framework itself before being able to contribute. Focusing on JavaScript also offers some protection against investing too heavily in framework-specific knowledge."

I've been using ExtJS since 2008, so I can give some experience here. What he says is absolutely true. The DSL of ExtJS does slow down ramp-up for new developers and requires an investment in learning the framework before you can use it.

However, I would like to point out there is a reason for the DSL. The DSL abstracts away the low level details of HTML so you can think at the level of ui elements. HTML's controls are very basic. Instead of comboboxes it has selects, which are quite inflexible. Instead of grids it has tables, which are also quite weak. The date field is minimal and in fact missing in older browsers. The list goes on and on. HTML is simply not rich enough to express desktop-level ui's elegantly. You can deal with that in two ways: embrace it and dumb down the ui (hence the trend towards minimal ui), or work around it and build a DSL on top of HTML. The core theory behind the rich DSL of ExtJS is that by bumping up the abstraction level developers can be more proficient. It is OO encapsulation at the UI level.

That is the theory. In practice it is a mixed bag. You have the same problem with ExtJS on top of HTML as you have with an ORM on top of a SQL db. You need to understand both what happens underneath and what the tool does on top of that. The cognitive load is higher, not lower. Some people thrive in that and are more proficient in the DSL than they would be in a raw templating view-driven environment. Others struggle with the larger amount of layers involved and are slowed down by the approach, and then some people fall in between and see no productivity difference. YMMV.

Update: one additional thing that I'd point out is that being opinionated and investing deep with a framework is not a bad thing when you're building a large long-lived codebase. If you're going to be living in a codebase for years, it makes sense to have as much application backbone (pun intended) as possible before you start building code on top of that. If you assemble a hodge-podge of smaller modules you're essentially constructing your own big framework anyway, so you might as well bite the bullet and choose a consistent one. The notion that you're ever going to switch js frameworks on a large single-page-app codebase is silly. The cost will always outweigh the benefits.


Sencha/ExtJS does certainly give you a lot of stuff out of the box, which is really cool. The main pain points I had were when building with it emerged when I had to do something that wasn't supported out of the box.

Picking the right abstraction layer is a fine line to walk. As you pointed out, there's tradeoffs on both sides.


Possibly slightly tangential. I am someone that has a basic understanding of JS. I don't code on a regular basis, just here and there. I'm fine with html and css, but I want to up my JS skills in a couple of specific areas. Specifically, I want to learn how to build apps that can leverage other APIs. say for example if I want to build a service that interacts with the gmail api. I can't seem to find any information anywhere that can help me do this. Every time I do a search for JS API, API, rest API or similar, all I get is results for how to build an API in your own app, which is not what I need.

Does your book have the content I need to learn how to use an API? If not -- does anyone have any suggestions as to where I can go to learn this?


There is a beta Javascript client library for the Gmail API [0]. If you are looking to interface with an API that doesn't provide a JS client, your best bet might be to just build yourself a simple client using jQuery to handle the HTTP communication (see, for example, jQuery.ajax [1] for making HTTP calls).

ETA: To elaborate a bit, "interfacing with an external API" is usually just a fancy way of saying, "making HTTP requests." In Javascript, this means using the XmlHttpRequest browser API, which people call AJAX because it sounds hip. You can use it directly, but jQuery gives some extremely convenient helper methods for easily composing requests. One thing to keep in mind is that if the API uses JSON, you will have to consider that the browser does not permit you to return JSON from a cross-domain request (which an external API call almost certainly is). There is a way to enable this using something called JSONP [2].

[0]: https://developers.google.com/api-client-library/javascript/...

[1]: https://api.jquery.com/jQuery.ajax/

[2]: http://json-p.org/


Henrik's book here can definitely help you.

But just to add my 2 cents for working with API's specifically - on the server side - a good start might be to play around with Node and CouchDB. Try building a basic app.

Couch is a database with an HTTP API out of the box, so if you can get the hang of it's basic operations then you will inherently have the fundamental knowledge needed to work with just about any other API.


I agree with almost everything, except Browserify. I guess he prefers CommonJS to integrate with Node and npm, but in the browser I'd rather wrap the modules in AMD and use an AMD module loader (not necessarily RequireJS).


It's merely an opinion, to each their own. If AMD works well for you, that's great.


The books seems really interesting. I hope it's ok to print it and read offline

https://gist.github.com/g-P/0e663535d69a06f4dcca

JavaScript rocks!




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

Search: