Cleverness has often been celebrated in software.
Sometimes it’s necessary. When performance is critical, when business logic is unusually complex, or when you’re working on a truly novel solution, being clever and solving problems in unique ways is often essential.
Most code isn’t like that. Most of the time, you’re building dashboards, CRUD APIs, workflows, and writing tests. When that kind of code gets too clever, it becomes harder to work with. And, importantly, it becomes harder for AI codegen tools, like Cursor or Claude Code, to accelerate development.
At Trunk, we previously celebrated cleverness. Now we’re trying to be boring and vanilla.
That doesn’t mean low quality. We’re rebuilding our frontend monorepo to be easily readable and actionable for both people and AI code assistants.
Clever code is a liability
Clever code has always been a liability, whether it is necessary or not.
Code readability counts for something in software. If your clever code is difficult for other developers to decipher, then it is a major liability. It might be difficult to debug and extend, and the original author might be the only person who can work on and review the code.
I’ve had the “pleasure” of owning clever code before. A heavily templated C++ library that was a tangled mess, which only the original author was able to edit.
LLMs excel at pattern recognition and pattern matching. The closer your stack gets to “vanilla” and the fewer custom patterns in your codebase, the more effective LLMs and code agents become. We expect to continue seeing benefits from our simplified code base as these AI code assistants improve.
We still need to provide Cursor with additional rules about our repo. However, because we have well-defined, simple patterns throughout our codebase, these rules were easy to write, and they enable LLMs to be effective in our repo:
1## Code Patterns23### Client Component with Data4```typescript5// RSC wrapper6export default async function Page() {7 return (8 <PreloadQuery query={QUERY} >9 <ClientComponent />10 </PreloadQuery>11 );12}1314// Client component15"use client";16export function ClientComponent() {17 const { data } = useSuspenseQuery(QUERY);18 return <div>{data.items.map(...)}</div>;19}20```
Easy-to-follow patterns also make engineers more effective. There’s less individual code ownership, and we no longer need to assign issues to the dev who originally wrote the code. With a uniform frontend, any frontend dev can tackle a new feature or bug fix, and the benefits extend beyond writing code. It’s easier to review code. Onboarding to our repo is much easier. Developers spend more time building, less time reviewing and context switching.
So we set out to simplify our custom-built frontend and microservice backend.
Build boring frontends
Our old repo was using custom components for a standard SaaS dashboard: tables, visualizations, forms, buttons. It made fixing bugs and iterating on the dashboard design slow. AI code assistants struggled to produce anything usable.
We knew we wanted to use a library for frontend components in the new version of our web app. So we replaced our custom frontend components with shadcn/ui
components. Rebuilding with an existing, popular library gave us a much more consistent, less unnecessarily bespoke frontend.
The switch to shadcn/ui
allows us to use tools like Cursor and v0 to generate and iterate on frontend designs faster than ever. Rich, interactive frontends that used to take days now take hours.
Users benefit too. Standard UI patterns help people accomplish tasks faster. That’s what matters.
Boring code is good for testing
Unit tests are easy to generate with AI. Integration tests are where things get interesting.
We have always prioritized integration tests at Trunk. A major bonus of moving to a monolithic backend is that AI-powered code assistants can now write better integration tests, with access to everything they need in one place.
Engineers still ensure all use cases are covered. But writing the actual test code, handling async logic, threading, and orchestration, is something AI can now help with meaningfully.
This shift gave us higher confidence in code changes and reduced the amount of time spent chasing bugs across services.
Vanilla code is AI and people-friendly
Engineering has always been about product, not code. The job is to ship working software that solves real problems. Code is just the tool we use to build.
Polishing abstractions, inventing patterns, and clever engineering don’t matter if they slow down delivering value to users. Rebuilding our codebase to be more boring helped us refocus on what actually matters: building things people care about.
If you want AI to write your code, test your code, and help your team move faster, the best thing you can do is make your codebase as plain as possible. Use familiar patterns. Stick to defaults. Optimize for predictability.
Boring code isn’t a compromise.
It’s a competitive advantage.