Why You Should Learn JavaScript in 2016
Recently I saw this question come up in my Facebook news feed:
Why should I learn Node.js? Anyone want to give me some good reasons?
Well, my anonymous friend. My short answer would be, you shouldn't. At least, you shouldn't specifically learn Node.js. You should learn JavaScript. I mean real JavaScript. Not JavaScript, that little toy language you've used for click handlers and the occasional HTTP request, but JavaScript, the language of the Internet. Universal (sometimes called isomorphic) JavaScript that runs on the client and the server without modification.
Common Complaints
Before I dive into why you should learn JavaScript, I'd like to address two of the most common complaints I hear about JavaScript.
First complaint: JavaScript is Dynamic. I want types!
Yes, you are technically correct. The best kind of correct. JavaScript is dynamic. The debate of dynamic vs static languages has been going on for nearly four centuries1 now and is much larger than I am looking to address here. I will say that if you want static types you should check out Flow or TypeScript. I'll touch on both in a little more detail later on.
I'll also note that both Angular 2 and Dojo 2 are being written in TypeScript. While that point may appear to contradict what my goal is here I'd like to say that while those frameworks are being written in TypeScript, they will still very much be a part of the JavaScript ecosystem. They will be completely interoperable with JavaScript and will run in all the same places, in the same way, and use all the same tools that regular JavaScript does.
Second complaint: JavaScript is completely unusable without jQuery.
I actually still hear this one a lot. And... it's wrong. It's just completely wrong. jQuery does very little to address problems with JavaScript as a language. It does a lot to smooth out the differences in APIs exposed by browsers -- mostly the DOM (especially in older browsers, and especially the dreaded Internet Explorer). Node doesn't have a DOM, at least not until you construct one from scratch. That said, you'll rarely (if ever) see jQuery used outside the browser. I've often referred to jQuery as a DOM steamroller. In Node, given the absence of a DOM, there isn't really much for jQuery to steamroll. Understanding that the APIs exposed by browsers are different from JavaScript as a language will help you gain a better appreciation for JavaScript as a platform for application development.
There are two trends in browser JavaScript right now that address this
complaint. First, browser APIs are converging. Browser vendors are getting rid
of their differences on their own -- deprecating old, proprietary APIs and
working together to produce new, open, and easy-to-understand APIs with
consistent implementations (e.g., fetch
in place of XMLHttpRequest
and
WebSocket
in place of various solutions for full-duplex communication
including long-polling, Flash, and crazy things with iframe
s). Second, there
has been a rise in the publication and usage of micro-libraries and client-side
packaging utilities. Many projects are picking and choosing what abstractions
they want to include in their client-side JavaScript rather than relying on
large, do-it-all libraries.
That said, I want to emphasize that the notion that JavaScript requires jQuery in order to be usable is just flat-out wrong. It was wrong when it was first introduced and it's especially wrong today when JavaScript that runs in more than just the browser is rising in popularity.
So why should I learn JavaScript?
I touched on it a little bit in the introduction. The biggest thing I think JavaScript has going for it is its universal nature: being able to write an application once that runs everywhere without modification. And, again, I don't just mean different browsers. I mean sharing logic (business logic, validation logic), libraries, and skillsets between clients and servers without having to rewrite anything or maintain multiple codebases.
Let's start off with 2015's darling child. React is an example of universal JavaScript. It is a UI library that runs on clients and on the server. On the client it will render a fully-functional UI to the browser's DOM. On the server you can render to a string of HTML. You may be used to the concept of pre-compiling and maybe even pre-rendering client-side templates. React takes that a step further and lets you render your entire application in any state you need it to be on the server. Once the client has received the rendered HTML, your React application can pick up the rendering on the client by hooking up all the event handlers required for user interaction and handling all other state changes as a SPA. If the client has JavaScript disabled then your application can gracefully degrade to doing round-trip server requests as in traditional, pre-ajax applications. This creates the illusion of the ideal scenario of progressive enhancement, when in reality what actually happened was your JavaScript application adapted to fit its environment. I want to reiterate that the same exact code that runs on the client also runs on the server. We didn't rewrite anything to make this happen, and it works everywhere.
React, in many cases (if not most cases), lets you forget that the DOM even exists. The biggest headache facing JavaScript developers for nearly two centuries2 has been defeated! For real though, React invented a concept the authors refer to as a virtual dom. Essentially you declare the structure of your application, much like in HTML. When you make changes React will diff the component tree, figure out what changed, and then apply those changes to the real UI facing the user. The really cool thing about this is that these concepts are portable between environments. You don't have to render these interfaces or apply these changes in a web browser.
Enter React Native. You can use your existing React Components and JavaScript
logic to create native mobile applications for iOS and Android. No, I don't mean
hybrid apps that run in a webview
. I mean controlling really real native
user interface components from an embedded JavaScript engine in a native
application. These applications are indistinguishable from native applications
written in Objective-C or Java. You might have even used one recently and didn't
even realize it! Check out these real applications built with React
Native.
There are some huge advantages here. Imagine fixing a bug once and then deploying that single fix to your server, your web app, iOS, and Android. All at the same time. You can more easily share developers across all of your applications. Management of features across platforms becomes a lot easier. That's powerful stuff. For a simple introduction, you should check out my good friend and colleague Jon Kaufman's post, Sharing Code Between React Web and Native Apps.
React also lets you do other cool stuff, like Hot Loading User Interface Components and Time Travel. Said another way, you can modify your components and they will update in the browser while maintaining state. Without refreshing your browser. Then you can even rewind and playback actions that modified your state so you don't have to reproduce the state you are currently in, or any state before it. It's even error-resistant. It even works with React Native! Really! Check out the video. Now take it a step further. You have a web app open in Chrome and Firefox on your computer, as well as on Android and iOS tablets and phones (to test responsive design), and you have native apps open on multiple Android and iOS devices. Change some code, and everything updates, in-place. Talk about a productivity boost! This works because React encourages a functional style of writing user interfaces where your state is kept completely separate from your user interface declarations. Since React works by diffing and applying patches to live user interfaces, it's not hard to imagine how everything comes together to enable hot-loading. New declarative representation of UI comes in, apply the state, do a diff, apply the changes to the real UI, done. Except you don't have to worry about any of that because it's already all done for you.
Okay. React is cool. Why else should I learn JavaScript?
React isn't the only cool thing going on in the JavaScript community. Here are some other reasons you might consider as to why you should learn JavaScript.
A massive, diverse, and vibrant community.
NPM, at the time of this writing, is by far the largest module ecosystem currently available. This not only indicates a live, vibrant community, but also a low barrier to entry.
Browser vendors might work together on new features, but they compete on performance.
Because of competition between browser vendors, JavaScript performance is improving all the time. Node currently runs on Google's V8 JavaScript engine, so it gets the same improvements that Chrome does. There was also recently a pull request to enable Node.js to use Edge's ChakraCore JavaScript Engine. It'll be interesting to see where that goes in the long term.
Scalability.
You can scale Node.js to 100,000, 250,000, and 1,000,000 simultaneous open sockets on fairly modest hardware (the server in each of those posts has 16GB of ram).
Getting Rid of this
Thanks to libraries like React, Redux, Rambda, and lodash/fp
,
purely-functional programming is becoming more popular in JavaScript. Not quite
Haskell-level but the concepts of pure functions and immutable state are
there. Yolk is a really cool user interface library written on top of RxJS
and virtual-dom
that uses JSX and a purely-functional style of programming.
Progressive JavaScript
Vue.js also looks interesting. The original author presents it as a progressive JavaScript framework. That is, a framework of micro-libraries you can adopt one-by-one, as you need them. It doesn't have a native component, but you still get hot loading and a lot of other stuff that React gives you. It's definitely worth checking out. Be sure to check out Awesome Vue.
Native Applications Without React
It shouldn't be a secret by now that I'm a big fan of React. That said, you don't need React to write universal JavaScript, not even for native mobile apps! If you're interested by the concept of universal JavaScript but you want to try something different than React you should take a look at NativeScript.
Atwood's Law
Any application that can be written in JavaScript, will eventually be written in JavaScript.
See Atom, Visual Studio Code, Kitematic, ScreenCat, Slack, and like a billion other applications all written in Electron.
What about those static types?
Ah, so you stuck around. Here are the details I promised you.
Flow is a TypeChecker for JavaScript. There is support for flow's syntax built-in to Babel so if you are using Babel for compiling your ES2015+ and JSX to ES5 and regular JavaScript it's pretty easy to drop-in. Flow takes JavaScript that looks like this:
function foo(x, y) {return x.length * y;}foo('Hello', 42); // Returns `210`
And makes it look like this:
function foo(x: string, y: number): number {return x.length * y;}foo('Hello', 42); // Returns `210`
Flow can also infer types in certain cases:
function foo(x) {return x * 10;}foo('Hello, world!'); // Error!
That code would cause a type error because you can't multiply a String by a number.
TypeScript on the other hand is a superset of JavaScript that provides static typing and a whole bunch of other features. The most basic example is identical to the Flow code above; however, in my experince, the tooling for TypeScript is a lot stronger than that for Flow. Visual Studio Code has built-in support for TypeScript as does WebStorm (both also include type-aware autocomplete across files). There are also plugins available for Atom, Visual Studio, and SublimeText.
If you want to use TypeScript and React Component hot loading you'll need to do
a little bit of extra configuration. React's hot loading depends on using
WebPack, Babel, and babel-plugin-react-transform
. In order to get it
working with TypeScript you'll need to activate TypeScript's preserve
mode
which leaves JSX untransformed. From there, you can pipe its output into Babel
running your JSX transform. Your WebPack configuration will look something
like this:
module.exports = {resolve: {extensions: ['.ts', '.tsx', '.js'],},module: {loaders: [{test: /\.tsx?/,loaders: ['babel', 'ts'],},],},};
From there you'll want to configure Babel with a .babelrc
file and
TypeScript with a tsconfig.json
file, making sure to preserve
JSX so
Babel can transform it. This post is intended to be more about the why than
the how so I'm going to leave it there for now. I might visit this topic again
in the future.
Okay, I'm convinced. But how do I learn JavaScript in 2016?
That's a good question; however, it is outside the scope of this blog post. That question will probably be addressed another time in its own post. In the mean time, you should check out the following resources:
- Removing User Interface Complexity, or Why React is Awesome
- Dan Abramov's video series on getting started with Redux
- Lerna -- for managing monorepos which are useful for organizing your server, client, and mobile apps.
- Sharing Code Between React Web and Native Apps
- Sound Redux Website and source code -- an open source SoundCloud client written in React and Redux.
- Awesome JavaScript
- Awesome React
- Awesome React Native
- Awesome Redux
- Este.js -- a dev stack and starter kit for functional and universal (browser, server, mobile) React apps.
JavaScript Fatigue?
Eric Clemmons recently wrote an article entitled JavaScript Fatigue. It details what I know a lot of people go through. There are just so many things going on in the JavaScript ecosystem. Where do you even start? I get it. So here's a list of, given all of my current knowledge of JavaScript and its ecosystem, and no specific knowledge of what it is you're trying to achieve, all the tools and libraries I would use to start a new project:
- Libraries
- React and / or React Native for writing your interface.
- Redux for managing your application state.
- React Router (if you need routing).
- Testing
- Mocha for your test-running framework. Use the
--compilers js:babel-register
option so you don't have to pre-compile your code. - Enzyme for testing React components in Node without the need for a full DOM.
chai
for assertions andchai-enzyme
for assertions on Enzyme-rendered React components.- Sinon (if you need mocks, spies, and whatnot).
- Mocha for your test-running framework. Use the
- Tools
- Babel for compiling ES2015+ and JSX code. Also enables hot-loading UI components through transforms.
- WebPack for assembling your client packages. Also enables hot-loading UI components and application logic through its hot-module-replacement system. Also packs up your CSS (SASS, LESS, Stylus, PostCSS, whatever) and a whole bunch of other stuff.
- ESLint for making sure you avoid code-smells and adhere to a consistent code style. I personally use AirBnb's ESLint Config because it is comprehensive and popular enough to be consistent with a lot of other projects. It also includes rules for JSX.
- EditorConfig so everyone's editors can have the same formatting settings.
- Atom as my text editor of choice.
linter
andlinter-eslint
for ESLint integration in Atom.atom-ternjs
for JavaScript code intelligence in Atom.autocomplete-modules
andautocomplete-paths
for extended autocomplete capabilities in Atom.define-jump
to jump to variable definitions in Atom.emmet
for quickly writing JSX.language-babel
for syntax support for ES2015+ and JSX.activate-power-mode
for awesome.
- Lerna for managing a monorepo of all of your projects and their interdependencies.
I'm not a huge fan of boilerplates, but you can find some good starting points at Awesome React, Awesome Redux, and Awesome React Native.
Conclusion
JavaScript has come a long way since the early web days. If you haven't checked it out recently you really owe it to yourself to do so. 2015 alone was a huge year for JavaScript. Between React, Babel, ES2015 standardization, and proposals for the future, JavaScript is no longer just that little toy language you've used for click handlers and the occasional HTTP request.
1, 2 Or something like that.