Building front-end web applications has been my primary job for the past 5 years. Having a pulse of the current javascript ecosystem is exhausting. The ecosystem is under constant churn where new tools are being built at a rapid pace that radically changes the way we build web applications. There's also a lot of tools in our stack in order to build a production-grade web application. How did we go from being able to inline javascript in our HTML to having a build pipeline that involves making a handful of tooling decisions before a single line of javascript code can be written?
Software engineering as a profession has been around for decades, there are
dozens of modern programming languages, thousands of tools and frameworks to
help satisfy our business requirements for a product or service. After hundreds
of thousdands of minds building software and learning from previous mistakes,
why does it feel like the front-end is churning the tech it uses so much? Why
does it seem like the front-end is such a mess? From fiasco's like left-pad
to
tooling churn, front-end development stands alone as the black swan in software
development.
I'm constantly reading on hackernews and the ilk that people who consider themselves competent software engineers -- generalists even -- avoid front-end web development like the plague. Why do so many professional engineers have disdain for front-end development?
The answers to these questions are why I love front-end web development. Javascript sucks and that's why it's amazing. Let's explore this ecosystem together while I try to convince you why front-end development is so exciting.
A black swan #
Javascript has a very unique set of challenges that differentiates itself from the rest of the programming world. The primary driving factor for its unique position is javascript is downloaded on the client's browser. Languages that run on the server, for example, don't need to send code that it runs onto client machines, they merely respond to requests made from the browser. The computation runs on the server. Traditional desktop applications only require the client to download the code or executable once to run the application. For front-end development, it's downloaded everytime. This is the key requirement that differentiates front-end development from the rest of its comrads:
Front-end development needs to consider total code size.
Where other slices of the tech stack don't need to worry as much about code size, it's a primary consideration for us.
What's the side-effect of this requirement?
- Small libraries are preferred over large ones
- A lot of tooling focuses on reducing code size
Let's look at these side-effects to better understand how it affects the ecosystem.
Small libraries are preferred over large ones #
Because code size matters, javascript libraries are hyper-focused on delivering the most powerful set of functionality in the smallest amount of code possible. When I think of modern javascript libraries, I'm reminded of the unix philosophy of doing one thing and do it well.
Javascript libraries do one thing and do it well out of necessity
This is taken to the extreme when there are libraries that are one line of code.
is-promise
is a popular one-line javascript function that was infamous for
breaking a ton of applications and libraries because it introduced a regression.
1function isPromise(obj) {
2 return (
3 !!obj &&
4 (typeof obj === "object" || typeof obj === "function") &&
5 typeof obj.then === "function"
6 );
7}
left-pad
was another famous example of a tiny library causing projects all
over the world to fail to build.
It seems silly, but this side-effect is perfectly explained by the unique requirements of front-end web development.
A lot of tooling focuses on reducing code size #
From code minification to tree-shaking, there's an abundance of tools that help reduce the overall filesize of our javascript code that gets downloaded over the wire. The front-end development build pipeline needs to spend time figuring out what code is actually being used in an application as well as figure out how to mangle it to be as small as possible. I've never worked on another project, outside of front-end development, that needed to care so much about code size.
For example, projects that use python don't have to consider the ramifications
of bringing in large dependencies. numpy
is a very popular pypi package for
data science and statistics. Adding that one package to your project will
increase the total code footprint by ~30MB. Can you imagine the vitriol
front-end developers would receive if they had a javascript bundle size of even
a fraction of that? It would be reprehensible.
Sometimes we do need to pull in large libraries because of how useful they are to us. They save hundreds and thousands of person hours and are cost effective to the business. We have to get creative and that is illustrated in the incredible amount of tooling in the javascript ecosystem. The ecosystem is constantly churning through tooling libraries in order to satisfy this one requirement.
One ring to rule them all #
There is only one programming language that we can target for browsers: javascript. We have other languages that can target javascript, but the end result must always be javascript -- for now.
For better or worse, thousands of developers must use javascript
Since there is effectively only one language ecosystem, there is an immense amount of creativity and labor hours put into solving its toughest problems. The ecosystem is under constant churn because it needs to satisfy so many requirements for a wide range of businesses. If we had the same number of popular programming languages on the front-end as we do on the back-end, there would be far less churn within each ecosystem. I would also argue that because javascript has its faults -- like any language -- there are a lot of incredible people coming up with ingenious solutions to patch those issues.
Because developers are forced to use javascript, they are forced to come up with creative solutions.
This creativity leads to fantastic and ingenious solutions. It's truly one of the most vibrant and interesting programming ecosystems to be apart of. In recent years, there are some tools that have revolutionized javascript. In particular:
- Typescript
- Prettier
- ESLint
- React (
view = f(state)
)
I would argue that the type system in typescript has contributed to more stable web applications than any single piece of tooling within the ecosystem. I would also argue that its type system is superior not in design, but by its application than any other type system I have worked with.
Prettier is just as good as gofmt
which is saying something considering
gofmt
was built by the golang language designers.
ESLint is the best linter I have ever seen in a programming language. There might be comparable linters in other languages, but I haven't seen any convincing evidence of them yet.
Everytime I grab another programming language, I miss these three tools almost immediately. Going to python after working with javascript is like going back in time in terms of tooling.
I would also argue that React is another library that has completely revolutionized how to build UI applications. There's a reason why so many applications are built with electron and I would argue it's not because people don't know how to use Qt. There's a reason why people don't want to use Qt and it's because the ergonomics of it pale in comparison to React and the web. Thinking of the view as a function of state was groundbreaking to the UI world.
There are many ways to run javascript #
Javascript has a specification: ECMAScript. This specification is implemented in different browsers in subtly different ways. The number of javascript implementations has been slowly declining over the years since v8 has dominated the browser market with its speed as well as it server side implementations (e.g. node). However, the fact still remains: javascript is implemented in subtly different ways and getting adoption of new features is very slow. Getting users to update their browsers is a momumental undertaking, one that has plagued front-end developers for years. The delay from a new feature in ECMAScript to market-share adoption is on the scale of years, not months. This creates yet another unique constraint for javascript.
The solution to this problem was two-fold:
- new features -- introduced by ECMAScript -- need to be backwards compatible
- tooling can be created to transpile code from one spec to another
Because the designers of ECMAScript make new features backwards compatible (for the most part), we can build tooling around converting code from a later specification to an earlier one. This created a new set of tools called transpilers (e.g. babel) which would convert ES6 code to ES5.
These transpilers allowed developers to write code in the latest specification without really worrying about market-share adoption. At the same time, it forced us to be okay with a compilation step to our build pipeline. This opened the flood gates for all sorts of tooling. Modern javascript code is compiled and that's not going away anytime soon. Does it add friction for people trying to learn the ecosystem? Absolutely, but the benefit is huge.
Conclusion #
Because so many talented people are forced to use javascript, because javascript has wholly unique requirements, we get the pleasure of working within a vibrant ecosystem. There isn't a year that goes by without some new innovation that takes the community by storm. However, at the same time, the ecosystem is starting to mature. React, arguably one of the most popular javascript view libraries ever built, has been around for 7+ years now. Typescript is essentially required for all new projects.
Building modern, production-grade web applications is difficult and there are times when it seems like all of this tooling really gets in the way. There are times when I'm sick of re-implementing the same components, dealing with the minor details of moving pixels on the screen, or satisfying the similar-but-slightly-different UX of an app that makes abstractions difficult. However, that's what makes front-end development so interesting. A new project rarely looks like the last.
If we attempted to replace javascript with some other language, it would still be restricted by the same requirements that restricts javascript today.
When I think about the challenges that face front-end developers I get excited to be part of this community.