Full-stack Javascript

I’m a Java guy. Or rather, I’m a C++ guy who ended up in Java. I like statically-typed languages, and think it would be cool if Java had double pointers (or at least reference parameter types) and explicit memory deallocation. I spent the better part of a decade coding video games in C++, and twelve years writing web apps in Java. I come from a pretty conservative, backend-focused coding background. So, after a year of working in an almost 100% Javascript stack, it’s fair to say that I have some opinions.

Architecture

First, let’s take a look at what our stack actually looks like.

javascript

The backend API is pretty straightforward – a Node/Express server, connecting to a Mongo database mostly through mongoose.

The front-end is a bit more complicated. At its heart it’s a React-based single page app composed of a simple html file and a fairly large Javascript file that manages all aspects of the site. The html used to be static, but when we implemented our SEO engine it made sense for a couple of reasons to hit the server on initial page load, so we added a Node/Express-based isomorphic render engine. The original plan was to fully render the first delivered page, but after some experimentation it turned out to be easier to go with a hybrid approach – we do some minor server-side rendering, but the html content is still minimal, and mostly static. Our mobile app is built in React Native, but is mostly just a wrapper on a web view with some native widgets. We used to wrap the Javascript and html using Cordova, but the web view approach gives us the ability to implement native features as necessary, while reducing the work necessary to keep the native app at parity with the web.

Scripting is one area in which we’ve diversified. We do have a fair number of scripts written in Javascript, but bash is better for tasks that require sequences of shell commands, and python is our language of choice for AWS manipulation (yay boto and troposphere). In many cases the right tool for the job is clear, but there’s some wiggle room depending on personal preference.

On to the feels

You can find a lot of hate online for the browser’s favorite only scripting language, and it isn’t hard to understand why. Javascript the language has a fair amount of legacy cray-cray. “Truthy,” and Javascript’s concept of equality, for instance, are pretty much the worst ideas ever, and make complaints about null seem somewhat quaint. The old class system is hilariously awful, and there’s a baker’s dozen of annoyances and gotchas (hoisting, scope, etc.) that add pain without power or flexibility. However, all of this, while true, is also mostly obsolete. ES6 (and babel, which transpiles ES6 features down to ES5-compatible code) has dramatically improved Javascript’s syntax and functionality. While it’s still possible to program using the crappy old language features (and people will, for a long time to come), it’s no longer necessary, and a good linter / static analysis tool will prevent you from making a wide variety of common mistakes.

The toolchain is also equal parts awesome and bizarre. Node, which is necessary for doing anything server-side, is fast, easy to use, and occasionally face-palmingly obtuse. Domains, for instance – which are deprecated, without having a replacement – and kinda mostly work, except when they don’t. Or the file system commands, which require you to use a try-catch to detect file existence. Or npm, which can easily fail due to network congestion, creates cascading, ballooning dependencies, and encourages an easy dependence on external, mutable code (<cough>left-pad<cough>) – but is also the gateway to an incredible ecosystem of critically important tools and libraries.

When I first agreed to join Scratch, the codebase was in Angular. By the time I joined three weeks later, the team had started rewriting the app in React. Although some of their reasons weren’t great (one engineer joked that they were afraid I’d nix the plan if they waited till after I joined), in retrospect, it turned out to have been a good decision.

It wasn’t immediately apparent. There weren’t a lot of accepted best practices at the time, the Flux/Redux/etc. wars were still playing out, and we made a lot of mistakes along the way. Over time, though, we’ve learned effective idioms, aggressively retired technical debt based on bad early decisions, switched out plain vanilla Flux for alt.js, and are generally pretty happy with where things are (though, of course, there’s still plenty of room for improvement).

React can feel a bit odd at first, or atavistic – a throwback to JSP scriptlets sprinkled through html, or the horror of Java files System.out.println‘ing frontend code directly into the response stream. But use it a little and not only does it start to make sense, it starts to feel natural.

React Native

Our first mobile app used Cordova – a bundled version of our single page app, with some fairly trivial native components. We were interested in switching to a new architecture which would enable a snappier, more native experience, and ultimately decided on Swift for our iOS app.

Well, no.

I managed the mobile team at TripAdvisor for three years. I’ve coded my own hybrid, and fully native iOS apps in Objective C. And I picked up Swift when trying to teach my niece mobile development a while back. I wanted to build a Swift app. I thought it was the right approach. But the team was interested in using React Native, and I didn’t want to railroad the process. So sure, I said, let’s do two time-boxed proofs of concept – one in Swift, one in React Native – and make a decision based on what we learn.

Both projects made progress quickly, setting up environments, getting a critical UI element in place, and then… things stalled. Other priorities came up, and our time-boxed tasks got put on hold. I worked on it nights, and was repeatedly frustrated when trying to set up things that should have been straightforward. I eventually picked up Bonnie Eisenman‘s Learning React Native, blew through it in a couple hours, and was sold.

If I’d had a team of iOS experts, going with Swift likely would have been the right choice. But I didn’t. Don’t. I have a strong team, and I don’t doubt their ability to come up to speed on any required technology – but the choice was ultimately between a language that two of us knew to varying degrees, and all would have had to spend precious time learning… vs. a variant of the language and framework we were already using daily. Once I was able to set aside my personal desire to use Swift (which was quite independent of any fact-based decision-making process), the answer immediately became clear.

Mongo

Let us imagine that there are, in fact, good use cases for Mongo. And, perhaps, even people who like its particular syntax (though not, I would bet good money, a single user who hasn’t wiped out important data by forgetting to use $set in an update call). While I’m tentatively willing to accept both of these hypotheses, after a year of working with Mongo, I would trade it in a heartbeat for a database that can do joins.

Conclusions

If you come from a traditional coding background and are used to spending your time on the backend, frontend coding can feel like a chore. HTML, Javascript, CSS – these are necessary annoyances on your way to completing a task, but not where you live. You like logic puzzles, and complicated algorithms, and likely have become just good enough at the frontend technologies to get things done, but not enough to understand the choices you’re implicitly making. There are lots of ways to get something done, and the simplest, most intuitive, best-known, older methods are frequently wrong.

Unfortunately, if you stop at the level of expert beginner (which is where I was a year ago), you’re going to look at Javascript’s warts, throw up your hands in frustration, and start a snarky series of blog posts on why Javascript is a terrible language. It’s easy to write poorly, but possible to write well, and while I don’t claim to have mastered it, I’ve certainly come to appreciate it. Yes, there are annoyances, but once you’ve learned more modern idioms, killed off some bad habits, gotten yourself a good linter, and come to understand your tools (Node, Express, React, npm, etc.), it’s quite an effective, and even reasonable language.

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s