Choosing your tech stack, 2020 Edition

Part 1/3: Client Side Tech Picks

We started Radical in 2020 in the middle of a pandemic. Our mission is building absolutely killer real-time and asynchronous collaboration features that work with any existing SaaS tools.

In other words…

Collaboratify all the SaaSes!

This idea sounds simple enough, but when you dig into what’s required to deliver this, you start to see a lot of unique constraints starting to emerge, which lead us to some very specific technical choices.

TL;DR: If you just want to know what tech stack we’re running here’s a quick run down. For more detail, see below. We’ve chosen TypeScript for both server and client; modern React with Hooks for the client UIs; GraphQL for the client-server interaction; Apollo on the client and server using WebSockets; React-JSS for managing styles; Webpack + Babel for transpilation.

Our Constraints

We’re building tools that enhance tools. That in itself creates some super interesting constraints for how we have structure our tech stack. For instance, we can’t expect to have control of the page our code runs in. Our implementation has to play very nicely with our neighbours.

We have a heavy focus on both real-time and asynchronous features. On one extreme end, we want to be able to reflect up-to-the-second information like whether or not your teammate is typing a message. On the other end, we want to be able to reflect an entire conversation history in a tool quickly. This means we have to support short-term storage features, a lot like how WhatsApp works, and we have to support long-term storage features like complete-history retrieval, like Slack.

The Picks

TypeScript

TypeScript is a mixed blessing everywhere you take it. It means that writing the code in the first place will be slower and more annoying. Learning all the finicky interactions between React and TypeScript is definitely a learning curve. Want to create an input event listener outside of your JSX markup? Cool, just learn the magical incantation e: React.ChangeEvent<HTMLInputElement>. Dead simple?! Right!!? Well, yes, once you’ve scratched your head and read docs for a while. Still, once you’ve paid the bill to create the TypeScript code correctly in the first place, it becomes indispensable for maintaining your codebase. I’ve now bounced between TypeScript and non-TypeScript codebases a few times and I miss TypeScript annotation every time.

Wow, no mystery about what properties this component supports!

The downside of the React + TypeScript combo is that you’ve pretty much guaranteed your compilation is going to feel sluggish. If you work locally on a reasonably modern laptop, it’s tolerable. Still, even after some optimisations, we’re seeing warm-recompile times in the low single-digits seconds. That’s just slow enough to feel sluggish. No whizbang tech is free. Come on Deno!

Choosing TypeScript has huge implications for the rest of the stack, so I’ve listed it first. If you start off with TypeScript, you have to think about the TypeScript implications of every next technical choice. DefinitelyTyped will save you some of the time, but some projects are not TypeScript friendly and you’ll be incentivised not to choose them.

Visual Studio Code

It may seem strange to include VS Code in the Tech Stack discussion, but the raw truth is that if you’re using TypeScript, you’re using VS Code. I grew up in the generation of developers who love to hate Microsoft. But I have to admit VS Code is the best IDE I’ve ever used. Ugh. I hate saying that. The ultra rich support for TypeScript is a killer feature. I still work in Vim/iTerm most of the time, but when I’m hacking React, I’m in VS Code (with Vim bindings!).

React

React was the easiest of the choices for this project. Especially since Hooks have come out, React is just the clear, clear winner over everything else out there right now. In my last role, I ported an existing PolymerJS app into modern React and generally had an excellent experience with React. The tooling support is excellent. The React core team are beasts with incredible velocity. Couldn’t be happier with this choice.

Runners up are thing like AngularJS or VueJS, but honestly, it’s not a remotely close race.

GraphQL with Apollo

GraphQL. Ooph. Where to start. Is it good? Yes. It’s really good. Especially with all the nice things you get from Apollo. Having pre-built hooks for queries and mutations is awesome. Being able to create queries that get you exactly what you need. Killer. When combined with TypeScript, this means that you get back typed, well structured data from your queries, which is pretty great. The downside is that GraphQL isn’t JavaScript or TypeScript. It’s GraphQL. Yet another language to support in a project that is, at least theoretically, JavaScript.

The GraphQL query UI is fantastic. Super useful for debugging and for composing exactly the right query. No Swagger or Postman UIs for our frontend engineers.

React-JSS

Oh my goodness. Someone took CSS and found a good way to represent it in JavaScript? Shut up and take my admiration. This one is an easy yes. CSS-in-JS for life. Remember all the hype about CSS variables? Guess what’s better than CSS variables. Actual TypeScript variables!

Pro Tip™: Always alphabetise CSS declarations.

Webpack

An oldie but a goodie. I’ve encountered the Metro bundler more recently in interacting with some ReactNative/Expo code and I’m curious how it compares performance-wise with Webpack. Still, I wanted something I knew and something that is reliable. The Webpack plugin ecosystem is extremely hit-or-miss, but the core tech is solid.

Still, when it slows down (which it will with all these bells and whistles and spinning rims), there is a huge body of well-documented Webpack optimisations to employ to reclaim that performance. I’m happy with Webpack for now, but I’d happily jump on something faster and simpler.

Tradeoffs

The biggest negative tradeoff of this whole setup is that it has so many damn languages in it. We have to have HTML, CSS, and JavaScript. It’s the web. Those are table stakes. React-JSS gives us the ability fold the CSS into the JS, which is awesome. So, that means there are only two languages, right? Wrong. We’re using TypeScript on top of JavaScript. And we’re using GraphQL in addition to that. Oh and don’t forget React’s JSX language. So, this means we have HTML, JSX, JavaScript, TypeScript, GraphQL all in a codebase that compiles into pure JavaScript. All this complexity isn’t free. It’s actually super expensive. Onboarding junior engineers or interns shows the cost. Our designer is a confident CSS hacker and he feels cautious around all this complexity. There is a lot of cognitive load to manage in understanding how the pieces fit together.

The flip side of this negative is that once it clicks, the codebase is pretty great. Having TypeScript underneath everything means that you can hover over just about any variable in VS Code and get a massive amount of context on what it is, where it comes from, what its types are. The constant sense of mystery you feel exploring a big JavaScript codebase isn’t something we feel. In fact, I can navigate this codebase faster than any JavaScript codebase I’ve ever worked in.

Another subtle tradeoff is that we’ve started from scratch. The upside of this choice is that we’re running the best-of-breed everything. Our codebase doesn’t suffer from any legacy ailments or poor technical choices (at least not that we know about yet!). No tech debt to pay off. Clean, linear commit history thanks to the Stacked Diff Workflow. The downside is that we’ve had to fit all the pieces together ourselves. We didn’t start with any boilerplate project helper or create-react-app. So that cost us some time. Still, this tradeoff seems easily worth it.

Like what you’re reading? Come join us! We’re currently hiring for a small number of great people to join our merry band. We’re going to change the way people work. Help us get there. Email me — jack@getradical.co.

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 )

Google photo

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

Twitter picture

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

Facebook photo

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

Connecting to %s