What My First Real Client Taught Me About Frontend
My first real client — not a tutorial, not a practice project, an actual person who paid actual money for a website — taught me something I did not expect.
It had nothing to do with code quality. It had everything to do with what I thought code quality was for.
What I showed up with
I'd been building things for about two years at that point. I had opinions. Clean components, semantic HTML, no inline styles, CSS variables for theming, proper naming conventions. I'd internalized a set of standards from blog posts, open source code, and the general discourse of "good frontend."
I was proud of my code. I wanted to show it off.
My client wanted a website for his consulting business. A homepage, an about page, a contact form. Standard work — not technically interesting — but I treated it like an architecture project. Abstracted everything. Named things carefully. Wrote a mini design system for something that had three pages.
What happened
He wanted changes. Constantly. The nav color. The font size. The wording on the CTA. Each change took me longer than it should have because I'd over-engineered the abstraction — to change a color I had to update a token that fed a CSS variable that was referenced in a component that was used in three places.
He didn't care about any of that. He'd never see any of that. The abstraction was for me, not for him.
Then he asked: can you make it so I can change the text myself?
I said I'd need to integrate a CMS. I quoted him more time and money.
He said he thought this was just a website.
He was right. It was just a website.
What I got wrong
I was building for a hypothetical future developer — maybe me, maybe someone else — who would need to maintain this codebase. I was solving for scalability in a system that had no reason to scale.
Clean code is valuable. But the value of clean code is reduced maintenance cost. When maintenance cost is close to zero — a three-page static site for a one-man consulting business — clean code's value approaches zero too.
The right code for that project was the simplest code that did what my client needed. Not the most elegant. Not the most impressive to read. The most appropriate.
I had been optimizing for an audience (other developers, future me) that didn't exist, at the expense of the audience that did (my client, his users).
What changed
I started asking a different question before I abstracted anything: who benefits from this, and when?
If the answer is "future developers maintaining a large, long-lived codebase," then yes — design tokens, component architecture, proper abstraction. Worth the upfront cost.
If the answer is "me, aesthetically, right now," then it's decoration. Ship the simpler thing.
This doesn't mean write bad code. It means match the complexity of the system to the complexity of the problem. A three-page site doesn't need a design system. A trading platform with 40 views and two dev teams does.
The thing about client work specifically
Client work has a useful pressure that solo projects don't: someone else's expectations. That pressure forces you to confront where your standards are actually for users and where they're for yourself.
Most of the things I'd called "quality" were for myself. They felt like quality because they matched what I'd read quality was supposed to look like. But quality isn't an aesthetic — it's fitness for purpose.
The website shipped. My client updated his own text using a simple CMS integration I added in two hours. He referred me to someone else.
That referral was the review of my work that mattered.