Meet Laura.
Hi, Lauraaa! 👋
Laura is a web developer, and she wants to start a new web project. But there is so many ways to start one! Depending on what she wants to accomplish, she can start with a back-end or a front-end app. And then, which language and frameworks to use. It's certainly not easy to make all these choices, and it's just the beginning.
Though it is not advertised as such, I always thought of programming as the art of handling choices. It means making the right choice, but it could also mean not having to choose. Programmers made design patterns and development strategies to avoid thinking over and over about the choices that stand in front of them.
Maybe Laura will dive right in a test file, as she may think that TDD is the right strategy—and I will totally agree with her if her core feature needs some computation algorithm. It allows her to focus on the specs without spending too much time on hazardous production code, thus delaying the final implementation.
Maybe Laura will delay making some technical choice, using the hexagonal architecture: creating abstractions, dependency injections and repositories to create loosely coupled application components. For example, it allows her to choose a database and to change it later if the need arises.
But no matter how hard Laura will push back these choices, she has to begin somewhere.
To limit the scope of this article, let's say Laura wants to create a front-end application, and wants to use her favorite tool for the job: React.js. She is a senior JavaScript developer, and she worked on React apps before. But even with all this knowledge, the question remains: where to start? Let's see if we can find some answers…
🛠 The fear of choosing the wrong tool
"I'm picking React.js, yaaay!", says Laura with a spark of enthusiasm.
"And now what?"
"npm install react react-dom
, and that's it?"
"Oh, and Babel."
"Or maybe TypeScript?"
"Sass or Styled-components?"
"Or should I go with Create React App, Gatsby or Next.js?"
Oh no…
When you think about it, choosing a path is not a problem per se. The true risk of making a choice too early is having to pay the cost of a refactoring.
An example to illustrate this: the choice of a CSS tool. Let's say Laura chose Sass to write the styles of her React components. At some point in her project, Laura wants to get rid of Sass to adopt styled-components. The cost of this move is the additionnal time it took to choose Sass and then switch, compared to how long it would have taken to use styled-components right from the start.
To avoid the cost of such a switch, developers tend to begin their projects searching for the perfect tool. To be sure to make the right choice, and not to suffer a switching cost later, they sometimes search endlessly. The time spent searching for the smartest tool available is often greater than the cost of a switch! How many side-projects have been abandoned at this stage? How many developers lost their ways by learning the new shiny piece of technology, without creating the product they want to build? I know I did 🙋♂️
The real cost is not only the time spent for switching to the new tool. It also depends on the time spent to choose the first tool at the beginning. It's probably best to choose Sass right away, go ahead and code, build, prototype, and then spend 1 hour switching to styled-components. Rather than, for avoiding a switch, spending 2 hours weighting the pros and cons of each technology before adopting Styled-components.
And therein the "aha" moment.
It's probably best to go ahead and code, rather than searching the perfect tools.
Instead of trying to choose the right set of tools from the beginning, experience showed me that it's far easier to get things done by jumping right into building the product, get rid of the fear of choosing the wrong tool, and rather optimize for inevitable switches. Change will happen anyway.
Let's see how Laura can do that.
♻️ Optimize your React application for change
Laura is trying to create a React application. After some thoughts, she wants to choose a set of tools which allows her to reduce the cost of a later change. What are the solutions out there that allow her to do that?
It does not matter how senior you are: when you start a project, it does not hurt to check the docs. Maybe something changed since the last time you started one. React docs are particularly well written. The React core team takes it seriously, and regularly tries to do better. I warmly recommend every React developer to check it out frequently.
So, Laura decided to take a peek at the React docs, and she discovered that there is a page dedicated to how to start a React app. Sweet!
There are a lot of options out there for starting a React project, and this page presents different kinds of strategies:
The "Jump right in" strategy
Adding a few<script>
tags in your HTML and you're good to go. I like how the React team chose to emphasize this strategy before talking about the toolchains they recommand. They even added a dedicated page about this strategy. If you need a prototype or just want to hack around, you don't need to spend hours thinking about tooling!The "Already configured" setup strategy
A few script tags may be a bit stark, adopting a tool with more features already configured seems nicer. There are a few interesting tools which allow developers to start coding. An enjoyable DX without spending hours on config.The "from scratch" strategy
As Jean-Baptiste Emanuel Zorg famously said, if you want something done, do it yourself. If you are very familiar with bundlers, linters, compilers, test frameworks, you can manufacture a project tailored for your needs. But what are your needs exactly? Tough question to answer at the dawn of a new project.
Back to Laura.
What can she choose for optimizing her setup for change?
Is there a strategy more inclined to reduce switching costs?
The "Jump right in" strategy
It's a great strategy for learning and starting to play with React. But Laura is a senior dev, she already knows ES6, Babel, JSX and stuff. This strategy does not suit her very well, as she would like to benefit from a better DX.The "Already configured" setup strategy
With this strategy, a quick look into the "getting started" page of the docs, and Laura is good to go. In minutes, she can begin to code her components. Nice! But she might face switching costs later if she wants different tools to the preconfigured ones.The "from scratch" strategy
Ah, yes, Laura can pick each tool she wants. But she will probably configure tools for hours if not days before having the perfect setup. Is this worthwhile? Will it really help her to avoid changing tools in the future? Will this pile of dependencies not crumble over the inevitable changes to come?
While it's tempting to go with option 3 to avoid switching costs, Laura understands how crucial it is to not waste time at the beginning of a project, and goes with option 2. And I totally agree with her (well, no surprise there, Laura is a character that I invented for this article after all 😄).
However, this is not a clear choice for everyone. If you are a developer who works on a large amount of small projects, maybe the "from scratch" strategy is better suited, as you can create a project tailored for your needs and then use this starter for each project you work on. For instance, it could be the case for a developer who works in a web agency, with similar features between each clients.
Like always, there is no one-size-fits-all strategy.
👩💻 And the winner is…
Laura is on board with the "already configured" strategy. OK, but which one? Again, it depends.
Some of these tools are not only focused on the front end, but allow developers to quickly set up server-side rendering, leveraging Node.js. It's the case of Next.js, Gatsby or Neutrino, among others. I really like Nx with its interesting full-stack monorepo approach.
But do you care about SSR or a backend? Laura is trying to create a front-end app, and let's say her team has already a backend in place, with an API ready to be consumed. In this category, Create React App does not seem to have many competitors around. It certainly is the go-to approach for front-end only projects, especially for single-page application.
But what I like the most about CRA is that the amount of knowledge required to be able to start is fairly limited. It can help junior developers to dive into React, but it also helps senior devs not have to bother with new versions of react, babel, typescript and so on. You just have to yarn create react-app myapp
, and that's it, you have the last version of everything. The switching cost is not very high, as you can eject
and then have the possibility to manage the tooling yourself.
With CRA, Laura can benefit from amazing DX: JSX and ES6+ syntax, live development server with fast refresh, a build script for assets, production builds, tools for making a Progressive web app, and so on. And of course, hassle-free updates with a single dependency. For those who already worked with a in-house webpack/babel config, you probably know how tricky all these dependencies can get…
Hooray, Laura is ready to code! And she's just one yarn start
away from seeing it in action in her browser! 🎉
(or npm start
. which one to choose? Oh no…)
🤔 Final thoughts
This article is not meant to be a "shut up and just use CRA" kind of article. It's indispensible to understand the importance of delay or avoiding making choice too early, and the importance of optimizing our code for change.
It has implication in the way we organize our code and create our components. It's a whole new topic to discuss, so I'll leave it there for now. But it would be a great theme for a next post!