A very subjective overview of common practices in modern front-end development

A few thoughts and reflections on what front-end development generally looks like in 2017, what practices are most common and what is the baseline of knowledge an average front-end developer is expected to possess.

The points:

  • write in Javascript,
  • write functional code,
  • write universal code,
  • lint!
  • use unit testing,
  • use static type checking,
  • avoid coupling,
  • keep the number of dependencies as low as possible, and
  • aim at smallest total size of assets possible.

Javascript

Even though Elm is quite a powerful language, ClojureScript does wonders to performance, and WebAssembly is almost there, Javascript is still de facto standard. ES6 and above, in addition, have been doing really great job enriching the language with nice features. And of course Javascript is still the only language native in all browsers.

Although the problem with bringing the right language features to users’ browsers or running on different versions of Node is here to stay (at least you can control the latter), it’s possible to use latest syntax and transpile into good old ES5, thanks to Babel. Many fresh syntax features of modern Javascript are supported in Node as well, like “async/await”.

Functional code

Just a few years ago, it was quite easy to see a project done in jQuery, Backbone or, later, Angular and Ember frameworks. Mutating an object prototype was quite common, and replacing context of a function in order to make “this” refer to something you need was the most preferred solution. An object in global scope that ruled all the controllers didn’t raise any concerns. (maybe it did, but what other options did we have?)

These days, the right way of doing web means the code is more deterministic, and sometimes quite verbose. A little more typing is better than time spent debugging.

These days, the patterns used in functional programming are applied in Javascript, thanks to its design that naturally supports them:

  • immutable data structures,
  • pure functions,
  • and generally more diversified code that consists of smaller pieces rather than of huge object declarations.

As a positive side-effect, the code gets self-documented over time automatically and requires lesser amount of comments. As a side-effect, it requires relatively short time to pick up by freshly on-boarded engineers, regardless of their general knowledge of front-end technologies.

Universal code

A common practice these days is universal Javascript. It’s the code that you possibly can execute both in browser and on server. There still are different APIs provided by different environments, for example, there’s no “window” on server and there’s no “process” in browser.

It’s actually quite common these days that more than half of the code is shared between browser and server. This actually comes from functional programming applied to Javascript. Great part of the code, especially functions that operate on simple data structures and perform data traversal and manipulation, can be (and should be) done in a way to be used in virtually any environment, be it Node or Chrome. Whenever it’s only syntax features and no coupling with host API, this code is universal, although the opposite is not a limitation.

This makes it way easier to enable server-side rendering, for one. Which makes it easier to serve visitors better, humans or robots. Which makes the web be a powerful driver in marketing, and eventually, greater optimization in the conversion funnel.

Linting

Well, of course.

There are two remarkable tools these days that are worth using with the front-end code: ESLint and Prettier.

It’s especially worth the effort for a team to use ESLint to keep code styling consistent and aid the development process. The best part of it? Well, for one, there is eslint-import-plugin and its “import/no-unresolved” rule. Ensuring the project compiles because all the references are valid is critical for productivity, and of course it’s always nice to let your editor do this kind of task.

Prettier, on the other hand, doesn’t recommend. It formats the code as it feels should be the right way. It’s constantly evolving and does weird things sometimes (try to use it with multi-line template string) but it’s promising and it does exactly the job needed: without any discussion and painful search for consensus, just normalize the code formatting so that everybody gets used to exactly the same visual patterns.

Unit testing

Any pure function can be easily unit-tested. As many functions as possible should be pure in modern front-end code (same goes for back-end Javascript, actually).

Unit testing is small effort, big improvement. Originally used in teams to avoid getting code broken without noticing, it should be practiced in front-end development starting on day 1. In modern era of decoupling the code from browser DOM API, it’s easier than ever.

There are great modern tools for unit testing, AVA and Jest among the most advanced, well-maintained and delightful to use.

Static type checking

Yes, the pendulum swung there again. Static type checking is back.

But, really, here’s Flow for that. It does amazing job detecting discrepancies in types between modules and giving valuable information about your code that you might miss in haste, especially in the code that is referred to from many different places.

What is particularly notable about it is that any valid Javascript is valid Flow code, so it’s okay to add type checks gradually over time into existing code, as the old features are getting refactored or the new ones implemented, without dedicating a truckload of time and resources to simply rewriting the code. (which your tech lead or CTO would not approve anyway)

Avoid coupling

A classic example would be React and React Router. It’s a perfect example of coupling: you just can’t use the latter without the former. They are coupled.

On the other hand, Universal Router is completely decoupled from React. You can use it with any other library or just alone. You can use it on the server. What it provides is a simple as a stone library that takes two arguments, a path and a list of possible routes, and returns the matching route. No black magic. Works like a charm. A pure function with clear logic.

Same goes for setting meta-tags and other head information: there is React Helmet for that, but it’s coupled with React again. It acts as a component while it’s clearly not. It’s a function that outputs the same component and causes a bunch of side-effects to update properties in DOM in “head” section of the document.

It’s not just a React thing. It is a common pattern. And it is possible to do better, with no extra effort.

What distinguishes modern front-end development practices from them 10 years ago is that, along with FP, engineers should be (and tend to be) really careful about bringing any sorts of libs that depend on each other. Other engineers who will be taking over that codebase in a few months or years will be really happy to see clear code that is hard to break.

Minimum number of dependencies

There’s number of libraries every front-end developer relies on these days, including Babel for latest ES6+ language features and Webpack for bundling all the things into a single JS file. Which is great, these tools are hard to replace or reimplement on one’s own. But when it comes to utility functions or reusable logic, well, it can go really bad.

Whenever possible, consider these simple things:

  • static type checking already ensures that a certain variable has expected type,
  • whenever it’s hardly possible, for example in parsing and traversing data from an API, being cautious and using default values and doing some extra type checking in run-time works, and
  • you really, really don’t need a library because there’s already language syntax for that.

Every library added to a project comes with the running cost of maintenance and some extra cost of bloating bundle size. A library that implements X, Y and Z, when you only use Z, still brings all three with it!

There’s a nice library that fully depicts our philosophy, blunderscore. The one that shows that many things we blindly relied on in the past are actually not worth extra kilobytes delivered to every browser that hits our servers.

Small bundle

The whole point of front-end is to bring information and experience to the user, to the visitor of a web resource. Even if it is a web app, it is likely updated on a regular basis, so the assets every user downloads are always new. In this case the user will never enjoy browser caching.

What should regularly appear in focus is that, more often than not, people experience all sorts of bad connection. I like this line from “Most of the web really sucks if you have a slow connection” post:

Complaining that people don’t care about performance like they used to and that we’re letting bloat slow things down for no good reason is “old man yells at cloud” territory; I probably sound like that dude who complains that his word processor, which used to take 1MB of RAM, takes 1GB of RAM. Sure, that could be trimmed down, but there’s a real cost to spending time doing optimization and even a $300 laptop comes with 2GB of RAM, so why bother? But it’s not quite the same situation — it’s not just nerds like me who care about web performance. In the U.S., AOL alone had over 2 million dialup users in 2015. Outside of the U.S., there are even more people with slow connections.

Regarding websites and all sorts of landing pages, the results may be even worse: they get opened so little times, by so many visitors. Almost none of them will ever enjoy that cached version of assets because it’s simply their first visit. Bring them a 500KB JS bundle and be sure that growing bounce rate will ruin all your hopes.

It’s really worth investing in discovery of ways to minimize the bundle size, and of course it may sometimes affect the scope and set of features brought to the user.


I’m curious about what’s coming to the front-end next. It already is cheaper than before to create truly great experience on the web and maintain clean and scalable code at the same time. And it’s feels to me that front-end has become “a real job” only in the last 5–10 years, and was more like a form of punishment before. So buckle up and drive!