all articles
Lessons LearnedSep 8, 2026· 7 min read

The Frontend Architecture Mistakes I Made in Production (And What I Do Now)

Three real mistakes from shipping SaaS and e-commerce products in production, and the specific habits I built to stop repeating them.

JH
Jaker Hossain
Frontend Team Lead

Mistake #1: I let one component do too much

Early on, I had a single ProductPanel component handling display, form state, currency conversion, and inventory sync all at once. It worked, until a supplier logistics feature needed to reuse just the currency logic. Extracting it meant untangling four responsibilities that had gotten braided together.

What I do now: if a component's props list is growing past 6-7 items, or its internal state is doing more than one job, I split it before it becomes load-bearing for three other features.

Mistake #2: I optimized for today's requirements, not tomorrow's shape

We built an early admin panel assuming a single currency. When BD Commerce needed multi-currency and multi-country support, the assumption was baked into components, API calls, and even how prices were formatted in dozens of places. It wasn't a bug — it was a design decision that quietly became a constraint.

What I do now: for anything touching money, identity, or permissions, I ask "what's the most flexible reasonable version of this," even if the current requirement is simpler. It costs a little more time upfront and saves a lot more later.

Mistake #3: I under-invested in loading and error states

It's easy to build the happy path first and treat loading/error states as an afterthought. On a POS system syncing offline and online orders, that afterthought becomes a real problem — a silent failure during a sync means a business owner doesn't know if a sale actually recorded.

What I do now: loading, empty, and error states are part of the component's definition of done, not a follow-up ticket. If I can't answer "what does this look like when the API is slow or fails," the component isn't finished.

The pattern behind all three

Each mistake came from optimizing for the feature in front of me instead of the system around it. The fix isn't perfectionism — it's asking a short list of questions before writing code: What else will use this? What's the realistic worst case? What happens when this scales 10x?

That short pause has saved more rework than any framework or library ever has.

Mistake #4: I trusted a third-party library without an exit plan

On one project, we built a core piece of UI on top of a third-party component library that was actively maintained — until it wasn't. When it stopped receiving updates and a security issue surfaced, ripping it out touched dozens of files because we'd used it directly everywhere instead of behind our own abstraction.

What I do now: any third-party dependency that touches core UI gets wrapped in a thin abstraction layer of our own. If the library disappears tomorrow, only the wrapper needs to change — not every call site.

Mistake #5: I didn't separate what changes often from what doesn't

Business rules — discount logic, tax calculation, currency formatting — changed far more often than the UI shell around them. Early on, that logic was scattered directly inside components, so a rule change meant hunting through the UI layer to find every place it was duplicated.

What I do now: business logic lives in plain, testable functions separate from components. Components call those functions; they don't reimplement the logic. When a rule changes, it changes in one place.

Turning mistakes into a checklist

I keep a short, living checklist I run through before merging any architecturally significant change:

  • Does this introduce a new external dependency in a place that's hard to remove later?
  • Is business logic separated from display logic here?
  • What does this look like at 10x the current data volume?
  • If this component's requirements double next quarter, does the current shape survive that?

None of these questions are exotic. The value is entirely in asking them consistently, before the code ships — not after a production incident forces the conversation.

tags
architecturereactlessons-learned