Last week I launched a fancy new website for Frontend at Scale 🎊 If you missed any previous issues of the newsletter, you'll find them all in there. Also, a brand new blog is coming very soon where I'll be writing more in-depth frontend architecture content, so stay tuned for more updates!
In today's issue, we'll talk about prototyping, reactivity, the golden era of CSS, and giving technical books a second chance. Let's jump in.
Failing Fast with Prototypes
You know how you always design the perfect plan for a new feature, implement it flawlessly, users immediately love it, and everyone lives happily ever after?
I know; that never happened to me either.
The truth is that our first approach to building anything will often be full of flaws—and the earlier we learn about those flaws, the cheaper and easier it will be to fix them. That's where prototypes come in.
Prototype to Learn
Building a prototype takes time and effort, but when it comes to learning about shortcomings in our designs, prototyping is one of the best investments we can make. A good prototype can teach us as much as building the real thing but at a fraction of the cost, time, and pain.
“They slow us down to speed us up. By taking the time to prototype our ideas, we avoid costly mistakes such as becoming too complex too early and sticking with a weak idea for too long.”
– Tim Brown
Prototypes are an excellent investment because they can expose risks, unknown unknowns, and all sorts of potential issues earlier in the development life cycle.
In software development, it's often a good idea to "shift left" on prototype building. This means making those investments as early as possible, at a time when fixing issues is both cheap and easy.
What you learn from your prototype will help inform every decision you make going forward. It will bring clarity and confidence to your implementation and prevent issues from happening before the product hits real users.
As frontend developers, we often build UI prototypes to get early feedback on the look and feel of the application. But prototypes are not limited to user interfaces—they are also incredibly useful for making architectural decisions.
Imagine we're building a chat application and we're trying to figure out the best place to put our web socket client so that we can send and receive messages in real-time. Here's what an initial diagram of our architecture might look like:
This diagram is intentionally vague, but it's good enough for creating a rough but functional prototype.
If we put all the details of the application's UI aside, we could put together a prototype for this architecture in about a day. It would be far from perfect, but it would give us enough information about what's working and what's not.
For instance, we might discover that the Sidebar component–which needs to show whether the chats have unread messages or not–doesn't have a way to update its state in real-time. Sticking to our initial design would mean duplicating state and logic between Chat and Sidebar, so pulling the web socket client up to the root component level might make more sense.
You might be thinking that we could have figured this out from our first diagram without having to write any code. And you would be right! Diagrams by themselves are a form of low-fidelity prototype of our architecture. If we understand the system we're working on well enough, we can identify gaps in our design by simply looking at our diagram—no coding required.
In any case, prototyping architecture allows us to learn and fix issues in hours or days instead of the weeks or months it would take to build the fully fleshed-out product.
Prototypes vs. Tracer Bullets
An alternative (but complimentary) approach to prototyping is what's known as tracer bullet development.
This term was popularized by the classic book The Pragmatic Programmer (today's bookshelf pick) and is a strategy for building software iteratively when we cannot afford to throw away the code.
"Tracer code is not disposable: you write it for keeps. It contains all the error-checking, structuring, documentation, and self-checking that any piece of production code has. It simply is not fully functional."
Tracer bullet development is particularly useful when building a platform for other developers to work on. For instance, setting up the foundation for a new project (creating a new repository, setting up the build process, configuring the CI pipeline, etc.) is a great fit for this approach. The initial version might not have all the bells and whistles, but it will provide a solid structure you can learn from and iterate on.
"Prototyping generates disposable code. Tracer code is lean but complete, and forms part of the skeleton of the final system."
When used in combination, these two approaches will help you get a better understanding of your design. Just be careful not to mix them up: using disposable code from a prototype as the foundation for your system is a recipe for bugs and future headaches.
Prototyping can take many shapes and forms, but no matter which flavor you choose, your goal remains the same: failing fast, failing often, and learning as much as you can along the way.
State of the CSS Community
Browsers have shipped a ton of new CSS features over the past few years, and many more are on the way. Some of my favorites from Una's talk are:
- Nesting, which will likely replace the need for using a pre-processor in 99% of the cases.
- Expanded color spaces and new color utilities like color-mix.
- Container queries, style queries, and (future) state queries.
But the golden era of CSS is more than just new features. As Una says in her talk, some of these new capabilities enable a new mental model of responsive design that puts components front and center.
This is, as Anchorman's Ron Burgundy would say, kind of a big deal. Features like nesting, scoping, and container queries can change the way we organize code around UI components, and they'll even make us reconsider the tools (pre-processor, post-processors) and libraries we choose to build our frontends.
CSS is paving the path to new ways of building and structuring frontends, and personally, I'm all here for it.
Bonus: My coworker Rikki recently shared this other talk by Lea Verou from last year's CSS Day which talks about the secrets of CSS variables. If you're wondering "how many secrets could CSS variables possibly have?", prepare to have your mind blown by Lea's talk.
|Watch on YouTube|
Links Worth Checking Out
Learn about the benefits and challenges of server-driven UIs (as well as a case study using this approach at Instagram) in this practical guide from the builder.io crew.
The role of Suspense in React applications has evolved significantly since the API was first introduced years ago. This article gives a great overview of all of its different use cases, as well as the new features unlocked by React 18.
Nolan Lawson has been building with web components for years. His latest blog post gives us a detailed overview of the benefits and downsides of building web applications with them.
The Pragmatic Programmer
As a young and easily distracted UI developer I had waaay more important things to do (not really), but I ended up grabbing a copy of the book anyway. And… I didn't like it very much.
So when the 20th-anniversary edition of the book came out in 2019, I wasn't particularly excited about it. It took another round of recommendations from people I look up to for me to give the book a second chance. And let me tell you, I'm so glad I did.
It was clear to me now that my problem wasn't that I didn't like the book the first time, but that I didn't fully understand it. So while I wouldn't recommend it to someone who's just starting out, I think it's a fantastic resource for anyone who's been building software for at least a couple of years.
The Pragmatic Programmer covers some of the most important tools in the software developer's toolkit. The idea of tracer bullet development we discussed in today's essay comes from this book, and it's only one of the many subjects it covers. In no particular order, here are some of the topics you'll find in it:
Duplication, Estimating, Version Control, Prototyping, Debugging, Decoupling, Concurrency, Refactoring, Naming, Reversibility, Domain Languages, and something called Orthogonality which apparently is a very important thing.
We're not just playing developer-jargon bingo here. Understanding these concepts can play a big role in your career as a software engineer, and this book does a great job of explaining them.
The Pragmatic Programmer is one of my go-to reference books, and it has become one of my most recommended reads for anyone looking to level up their coding skills.
|Read more on Goodreads|
That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)
Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.
I read and reply to all of your comments. Feel free to reach out on Twitter or reply to this email directly with any feedback or questions.
Have a great week 👋