When I hear the word tool, I always think of a crowbar — not because of any past life as a bank robber (hopefully?), but because it so clearly embodies the concept of leverage.
Have you ever tried to open a safe with a 12-inch-long crowbar?
I probably haven’t.
But if I had, I imagine I’d be all sorts of disappointed with how much effort I had to put in to get a decent result. Now a 12-foot-long crowbar is much better, but good luck fitting it in your standard Ford Econoline™ van.
What does leverage mean as a working developer in 2020? It means that the tool does more work for you. The work can be tangible (writing fewer lines of code, deploying more quickly) or intangible (having to think less to get the result you want, sleeping better at night).
Most of all, leverage means getting more s**t done, faster. Not because we’re in a productivity cult, but because we can now start companies with half the engineering staff of just a few years ago. And because we’ve all got a limited tank of mental gas to throw at programming problems, and we’d like to spend that budget on the fun and creative ones, instead of the tedious ones. And because frankly, we’ve all got lives to live.
The good news is that we’re living in unprecedented times in terms of the tools available to developers and teams. I can’t think of any other industry where productivity has (or even can) advance at such an incredible rate, and I think that we’re absolutely privileged to be writing software right now.
So without further ado, here are the really big crowbars that I’m using in 2020.
I learned React before UIKit, and the imperative-to-declarative escalator only goes in one direction. This meant that for several years, I was stuck using React Native to build and deploy things on iOS — which was, you know, fine.
I still get a big grin on my face every time I fire up a SwiftUI project. Bugs and rough edges aside, Apple just completely nailed the developer experience. Having a live preview integrated right in the IDE is a ton of fun, and it’s doubly impressive when you think about where they came from — full project rebuilds, loss of all testing state, etc.
Swift itself is a lovely language. The other day I added a
~= operator to a
LatLng struct, so that I could check if two locations were basically the same. When I find myself doing something tedious, adding an extension to the underlying type is often the answer. Protocols are an extremely powerful way to compose behavior. Trailing closure syntax is super cool. Async stuff is mostly fine now.
Most importantly, we finally have a declarative UI language on iOS. I can’t overstate how excited this makes me to work on mobile projects — luckily, I’ve had several back-to-back ARKit projects this year!
🕴 Next.js and Now
Filesystem routing reminds me of PHP, but I don’t care, I’m in love with Next.js. You get so much for free that I can’t imagine using anything else right now. Maybe with time these memories of webpack configs will fade (or even grow fonder?), but right now I’m still relishing exactly how little work is required to get something ready for deployment on the web.
TypeScript support is baked right in (no plugins), as is server-side-rendering. There are well-thought-out APIs for almost everything, and more often than not they’re opt-in rather than opt-out, which keeps the “minimum viable projects” extremely slim and flexible. Most importantly, with a few caveats you can just write React, without worrying too much about where your app is running.
Now is also a lot of fun to use. I’ve mostly used it on smaller sites, so I’m not sure how the economics scale, but so far it’s been amazing. I’ve really come around on monorepos (again, smaller projects), and being able to spin up a serverless GraphQL API alongside a Next.js react app in like 20 minutes is just magical.
I remember struggling to write a “Why GraphQL?” post a few years back — at the time, it was new enough that comparing it to REST seemed like a good idea. Maybe it still is.
But what I really want to talk about here is how the experience of building (and consuming) a GraphQL API is heads-and-shoulders above everything else. One of the biggest indications that things are going well is that you stop needing so much coordination between frontend and backend developers. You don’t need to accommodate the particular query patterns of the client. You don’t need a special query language for nested payloads.
You just write types and resolvers. That’s it. Clients can use it however they want.
I’ve also noticed that growing a GraphQL API feels more additive than a REST API. Once you’ve added a type/field, you can use it in a ton of different places without any extra consideration — and without any hacks to avoid headaches on the frontend. It Just Works. Lovely.
I can’t imagine using GraphQL without Relay, and it’s one of the things that I’m missing the most in SwiftUI (project on this coming soonish?).
Relay’s biggest benefit is the ability to colocate data-dependencies with components. In fact, it’s a requirement. Remember how, with React, once you accepted that data flow is unidirectional you eliminated a whole class of bugs? Remember how quickly you forgot about angular’s scope digest cycles and dirty checking?
Relay feels like that, but for consuming APIs.
Once you really buy in to “one component, one fragment”, Relay starts magically getting all of your data from your GraphQL API to your components. It makes all of your GraphQL requests for you, handles caching data where possible, and ensures that you don’t rely on any data not explicitly requested inside the component.
A nice bonus is that I’ve been able to ditch Redux on a bunch of projects (praise be). With most of my data flowing though Relay, I only need a minimal app-level state container like MobX. Neat.
🌌 Aurora Serverless
This one is super weird and interesting. Last year, AWS launched a serverless flavor of their Aurora SQL database, and they gave it an HTTPS API. What a nice thing to do!
The DB has always been a big bottleneck when trying to build a truly serverless stack. I consistently come back to SQL (despite trying all the new hotness), and scaling a SQL cluster is cumbersome. You can do it, but you’re never going to get really responsive autoscaling by adding and removing replicas.
Well, Aurora Serverless is a big step in the right direction. You pay for “compute units” on a per-second basis, and you can run all of your queries over a secure HTTPS API if you want to hit your DB from outside of AWS.
From a pure DX perspective, I’ve really enjoyed combining a Next.js app and a GraphQL API (both hosted on Now) with an Aurora Serverless instance. There may be limitations on how economically this scales for large projects (data transfer?), but a lot of my current client work involves spiky traffic patterns, so pay-what-you-use is a great fit right now.
Bad programmers worry about the code. Good programmers worry about data structures and their relationships.
- Linus Torvalds
I’m going to gloss over most of the things that people usually mention about TypeScript — compile-time type safety, easier refactors, etc — and focus on something a little more fundamental.
If you really invest in designing good data structures, the rest of your code falls into place.
Using a typed language like TypeScript forces you to think about those data structures first, which will almost certainly lead you to write less (but better) code.
Of course, this is habit that you have to practice and enforce — not something that you get for free from TypeScript — but it’s a hell of a lot easier when you’ve writing in a language with a robust type system.
That’s it for now!
I hope you enjoyed this list of tools, and that they bring you copious amounts of enjoyment in your work.