Computer, Build Me an App

Learning to code with AI without feeling terrible about it.

Issue 32 /

Hey friends đź‘‹ First off, a massive thank you to everyone who checked out the Fundamentals course after the launch and helped spread the word about it. If you've been reading this newsletter for a while, you know I've been working on it for a long time and I'm oh-so-happy that the course is finally out there for everyone to watch.

If this is your first-ever edition of Frontend at Scale, first of all, welcome! And second of all, let me give you a quick walkthrough of what the newsletter is all about: every two weeks I send out an essay on software design and architecture tailored specifically for frontend developers. It's short and sweet, and it includes my favorite talks, articles, and podcasts, as well as my least favorite jokes and bad puns. I hope you like it.

This week, we'll talk about AI in frontend development, the value of component composition, and how small UI details can make a huge difference over time.

Let's dive in.

SOFTWARE DESIGN AND AI

Computer, Build Me an App

Photo by Christopher Gower on Unsplash​

I wasn't planning on writing about AI today.

In fact, I could say that of most days. If I'm being honest, AI is not a topic I ever felt particularly excited about, which is why I only wrote about it once before.

But last week I had a bit of a revelation. Watching Laurie Voss on Learn with Jason and listening to Simon Willison on The Pragmatic Engineer's podcast made me realize that my feelings toward AI had changed quite a bit after spending the last few months incorporating LLMs into my workflow.

I no longer feel dread, or anxiety, or fear that the bots will take my job and I'll have to move to a farm and raise chickens for a living. You could now say that I actually look forward to playing with these various AI tools and learning how to use them more effectively.

And there's something else that I'm feeling. Is this... is this joy?

Whatever it is, it's a positive feeling (or at least not a negative one), and while I don't consider myself an AI enthusiast by any means, I felt inspired to write about some of the ways I'm finding it enjoyable to use AI tools in my frontend adventures.

These aren't revolutionary findings or anything like that, but I thought I'd share them with you sooner rather than later while this positive feeling lasts. That is, before the next AI breakthrough brings back the dread and anxiety and makes me think about chickens again.

Refactoring and Cleaning Up

This is my most common day-to-day use case for LLMs. By refactoring, I don't mean only rewriting old, messy code—I use AI all the time to refactor brand-new code as well (which tends to be equally as messy.)

In the last issue of the newsletter we talked about the "make a mess, then clean it up" strategy I like to use for building small to medium-sized features. It works something like this:

  1. Write terrible code
  2. Check that it actually works (and maybe write a test for it)
  3. Clean up the terrible code

As I mentioned in that issue, LLMs are great for step #3 because your terrible code serves as the perfect prompt for coming up with a cleaned-up version. If your mess is small enough (like a single function), you could just ask the AI nicely to "clean it up, pls", and it will likely do a decent job.

But I've found that this also works well for the big messes.

For example, I tend to write big messy chunks of code in my React components. My initial implementations are typically all within the same file, which ends up spanning thousands of lines of code with dozens of useEffect calls, state variables everywhere, and mysterious references to DOM elements that may or may not exist on the page.

Cleaning this up by hand isn't necessarily hard, but it can be a massive chore. And who wants to do chores these days when the weather is so nice? I don't. Luckily for us, AI-powered IDEs are pretty good at taking care of those.

​Cursor's Composer feature is my personal favorite for this type of task. It can work not only in the file you're currently editing but can also create new files and folders as needed. This makes it perfect for when you want to grab a big, messy component and break it down into a series of smaller chunks.

In the example from the screenshot below, I took a small to-do application that was implemented entirely in a single React component, and I asked it to break it down into two smaller components and a custom hook. The Composer did a pretty good job on the first try.

You can see a 1-minute demo with this same example here.

Cursor's Composer cleaning up my mess by breaking down a large component into a series of smaller ones

Learning and Prototyping

We talked before about the massive value of prototyping in software design—creating a "quick and dirty" version of a feature or product can help us confirm assumptions and eliminate risks at a fraction of the cost of building the real thing. Prototypes allow us to fail fast and fail forward into the right solution.

"Quick and dirty, you said? That's what I live for!"​
​
— LLMs everywhere

LLMs are great for creating quick and dirty prototypes. One of my favorite new AI toys is Claude's Artifacts, which not only produces code but can also run it for you in an iframe so that you don't even need to leave the chat interface. This is perfect for creating single-purpose mini-apps to prototype quick interactions.

For example, I recently had to implement a bunch of CSS animations for a series of UI components I was working on. If you've worked with animations before, you know that making them feel just right usually involves a lot of trial and error: tweaking the easing function a little bit, making it a bit faster or a bit slower, adding a 50-millisecond animation delay, and so on.

For cases like this one, I like to build tiny mini-apps with a few toggles and slides that can help me play with the different values until I find the ones that make the animation feel nice and smooth. The problem is that these mini-apps take a bit of time to build (and they aren't necessarily fun to build), so I'm happy to delegate them to one of our new bot companions.

A single-purpose mini-app that you can get up and running within a minute with Claude Artifacts

But these one-off apps aren't my only use case. LLMs are also useful for creating prototypes within an existing codebase.

For example, I recently needed to do some research to estimate the effort of bringing tRCP to an old React SPA codebase. I had never used tRPC before, and I wasn't even sure it would be a good fit for this particular project, but within an hour of starting my research, I had a working prototype that taught me everything I needed to know to come up with my estimate.

I wouldn't recommend treating these AI prototypes as production-ready code, though—and I'd be cautious to even use them as a starting point. But a good prototype can teach you more in an hour than spending days reading a library's documentation, and LLMs can really make this building, failing, and learning process a lot faster.

Structure and Architecture

Ok, so we know that LLMs are great for the little things like writing a small function or creating a quick and dirty prototype. But what about the "big stuff"? What about the overall shape and structure of the application?

As someone who's always rambling about architecture and software design, this is the use case of AI I'm most interested in. And while I still don't think LLMs are a revolutionary tool for software architecture, I'll admit I had a few "oh, this is pretty cool!" moments while experimenting with them.

For instance, one of the exercises in the Fundamentals of Frontend Architecture course is about visually breaking down a design spec into a series of components and organizing them using a simple component hierarchy. Here's what one of the breakdowns looks like (on the left):

A component breakdown on the left, and the placeholder app generated by Cursor on the right

For these exercises, I also wanted to share an example implementation to show what the component hierarchy looks like in actual folders and files within the codebase. The components' contents were placeholders (as you can see on the right-hand side of the screenshot above), but the folder structure and naming convention were the final production-ready versions.

Cursor's Composer came to the rescue here once again. I gave it a screenshot of my component breakdown and asked it to create the necessary files and folders following my component hierarchy and naming conventions. It worked surprisingly well.

I've been trying to use this method more often recently, and I've found that AI can also be helpful for domain modeling and keeping the entities of your application's domain organized. I plan to continue experimenting with this over the next few months, and depending on how those go, you might have to read some more AI-powered architectural ramblings from me in an upcoming issue (I apologize in advance.)


You might have noticed a couple of common themes in the examples I shared above.

The first one is that, by far, the most effective way to get useful results out of an LLM is to give it tasks that are as small and specific as possible.

If your AI prompt is just "computer, build me an app", the LLM will most certainly do a very poor job at it. But break down the application into a series of small tasks, and you could have it build the entire thing without actually writing a single line of code yourself. I'm not saying that's something you'd necessarily enjoy doing, though.

The second one (and this is perhaps the most important point of the article, so get ready for some bold text), is that you can always delegate the implementation to an AI, but you should never delegate your thinking.

Don't let it make decisions about how you organize your code, or how you name your functions, or how many props your components should have. Remember that you, the human developer, are the one in the driver's seat—and whether you use an AI or not to write your app's code, those very important decisions are ultimately up to you.

And now that I think about it, maybe that's the reason I no longer feel anxious or nervous around our AI companions.

The more I use these tools, the less I fear that my job will be replaced or reduced to just writing prompts. Because no matter how good LLMs are at producing lines of code, the actual thinking and understanding continue to be jobs for my imperfect and 100% organic human brain—a brain that, apparently, likes to think about raising chickens a lot.

ARCHITECTURE SNACKS

Links Worth Checking Out

Computer, build me an app by Rich Harris
  1. 📬 I love tech newsletters. I know, I'm sure that's shocking news to you all. The only problem with loving them so much is that there aren't enough hours in the day to read all of them. But there are a few newsletters I never miss, and one of them is Web Weekly by Stefan Judis—it's a short weekly read that is the perfect way to keep up with what's happening in the web dev world while learning cool and interesting things at the same time. Needless to say, I highly recommend subscribing to it if you haven't already. Plus, Stefan is just the best.
  2. I borrowed the title of today's essay from this fantastic 2018 talk by Rich Harris at JSConf EU. As you might be able to guess, Rich's talk wasn't about AI but about Svelte. And even though he ran into a million issues with his live demos, this talk continues to be one of my favorite examples of great storytelling in a tech presentation. That's how good of a speaker Rich is.
  3. Tomasz Ducin wrote a detailed answer to the million-dollar question: what is frontend architecture? As someone who has been thinking about this question for quite some time, I'm happy to see that I'm not alone in my conclusion of what frontend architecture is all about—decisions, decisions, and more decisions.
  4. While putting together the course platform for the Fundamentals course, I made the questionable decision to try out a couple of new tools for the first time: Drizzle and Cloudflare D1. It wasn't easy to get started, but this article by Kevin Kipp on building a full-stack Astro app with Cloudflare D1 and Drizzle came in to save the day.
  5. TkDodo wrote a great article about component composition and its natural enemy: conditional rendering.
  6. ​Clean React with TypeScript is a pretty good read if you're looking to incorporate TypeScript into an existing React application. I learned quite a few things from this article by Robin Weser, even though I've been using this setup for a while now (you might call this a skill issue on my part, and you might actually be right.)
  7. I enjoyed this short article by Jim Nielsen on Sanding UI. These little details might seem insignificant, but they make a huge difference in user experience when you add them all up.
  8. The Arc browser recently had a pretty serious security vulnerability. Thankfully, it looks like no bad actors were able to exploit it, but it was scary nonetheless. The write-up by the security researcher who found this vulnerability is a very good read. Thanks Justin for sharing this one!
  9. DHH was on the How About Tomorrow podcast with Dax Raad and Adam Elmore. I enjoyed listening to their conversation on all things Linux, Apple, running your own servers, and what all of this has to do with Robert Pirsig's classic book Zen and the Art of Motorcycle Maintenance.
  10. I had the enormous privilege of participating in the latest episode of Jason Lengstorf's Web Dev Challenge this month. This is my favorite online show right now, so being part of an episode was truly a dream come true 🥲 It was a lot of fun. Thanks you so much for having me, Jason!

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, LinkedIn, or reply to this email directly with any feedback or questions.

Have a great week đź‘‹

– Maxi

Is frontend architecture your cup of tea? 🍵

Level up your skills with Frontend at Scale—your friendly software design and architecture newsletter. Subscribe to get the next issue right in your inbox.

    “Maxi's newsletter is a treasure trove of wisdom for software engineers with a growth mindset. Packed with valuable insights on software design and curated resources that keep you at the forefront of the industry, it's simply a must-read. Elevate your game, one issue at a time.”

    Addy Osmani
    Addy Osmani
    Engineering Lead, Google Chrome