The Trap of "Perfect" Architecture: What Building a Shopping Cart Taught Me
The Trap of “Perfect” Architecture: What Building a Shopping Cart Taught Me
“完美”架构的陷阱:构建购物车教会我的事
Early in my journey as a software engineer, I became fascinated with software architecture. I spent hours learning about: SOLID Principles, Clean Architecture, Hexagonal Architecture, Ports and Adapters, Dependency Inversion. The more I learned, the more I became convinced that every project should be highly decoupled, framework-agnostic, and future-proof. Then I built a shopping cart application. And that’s when reality taught me a lesson that no book could.
在我软件工程师职业生涯的早期,我曾对软件架构深深着迷。我花费数小时学习:SOLID 原则、整洁架构(Clean Architecture)、六边形架构(Hexagonal Architecture)、端口与适配器(Ports and Adapters)以及依赖倒置(Dependency Inversion)。学得越多,我就越坚信每个项目都应该高度解耦、与框架无关,并且具备面向未来的扩展性。后来,我构建了一个购物车应用程序。就在那时,现实给我上了一堂任何书本都无法教授的课。
Building It “The Right Way”
以“正确的方式”构建
Instead of creating a straightforward React application, I decided to apply a strict layered architecture. My project was structured like this: UI, Controllers, Application, Domain, Adapters, Infrastructure. Every responsibility had its own layer. Every dependency pointed inward. Every interaction crossed carefully designed boundaries. At first, I loved it. The folder structure looked professional. The separation of concerns looked clean. The architecture looked impressive. Then I started building features.
我没有创建一个简单的 React 应用程序,而是决定采用严格的分层架构。我的项目结构如下:UI 层、控制器层、应用层、领域层、适配器层、基础设施层。每一项职责都有其对应的层级。每一个依赖都指向内部。每一次交互都跨越了精心设计的边界。起初,我很喜欢这种方式。文件夹结构看起来很专业,关注点分离看起来很整洁,架构看起来令人印象深刻。然后,我开始开发具体功能。
The Architectural Tax
架构税
A simple feature change often required updates across multiple layers. Something that should have taken minutes turned into a journey through several directories and files. I found myself spending more time maintaining architectural boundaries than solving actual problems. That’s when I realized something important: Architecture isn’t free. Every layer comes with a cost. Every abstraction comes with a cost. Every boundary comes with a cost. You pay for it with: More files, More indirection, More cognitive load, More debugging effort, Slower development velocity. The architecture wasn’t wrong. The problem was that the complexity of the architecture was greater than the complexity of the application itself.
一个简单的功能变更往往需要跨多个层级进行更新。原本几分钟就能完成的事情,变成了穿梭于多个目录和文件之间的漫长旅程。我发现自己花费在维护架构边界上的时间,比解决实际问题的时间还要多。就在那时,我意识到了一件重要的事情:架构不是免费的。每一层都有成本,每一个抽象都有成本,每一个边界都有成本。你为此付出的代价是:更多的文件、更多的间接调用、更高的认知负荷、更繁琐的调试工作以及更慢的开发速度。架构本身并没有错,问题在于架构的复杂性超过了应用程序本身的复杂性。
Architecture Is a Budget, Not a Rulebook
架构是预算,而非规则手册
This realization completely changed how I think about software design. The question is not: “Is this architecture clean?” The better question is: “What problem is this architecture solving, and is that problem large enough to justify its cost?” A shopping cart application with a handful of features does not face the same challenges as a large enterprise system. Treating both projects the same way can actually make the smaller project harder to maintain.
这一认识彻底改变了我对软件设计的思考方式。问题不在于“这个架构是否整洁?”,更好的问题是:“这个架构正在解决什么问题?这个问题是否大到足以证明其成本是合理的?”一个只有少量功能的购物车应用程序,所面临的挑战与大型企业系统并不相同。以同样的方式对待这两个项目,反而可能让较小的项目变得更难维护。
The Framework-Agnostic Illusion
与框架无关的幻觉
One of my goals was to make the application completely independent of React. I wanted to be able to swap React for another framework in the future. In theory, that sounded like great engineering. In practice, I realized I was optimizing for a scenario that might never happen. The changes that are almost guaranteed to happen are: New features, Requirement changes, UI updates, Bug fixes, Refactoring. A complete framework migration is usually much less likely. Today, I still keep business logic isolated, but I no longer try to abstract every single framework detail away.
我的目标之一是让应用程序完全独立于 React。我希望未来能够将 React 替换为其他框架。理论上,这听起来是很棒的工程实践。但在实践中,我意识到我是在为一个可能永远不会发生的场景进行优化。几乎必然会发生的变更是:新功能、需求变更、UI 更新、Bug 修复和重构。而彻底的框架迁移通常不太可能发生。如今,我依然保持业务逻辑的隔离,但我不再试图抽象掉每一个框架细节。
What I Prefer Now
我现在的偏好
My current frontend architecture is much simpler:
- Domain: Pure business logic. No React. No API calls. No UI concerns.
- Infrastructure: External systems such as: API clients, Storage, Third-party services.
- Hooks: State management and orchestration. The bridge between the domain and the UI.
- UI: Presentation components. Focused on rendering and user interaction. Nothing more.
我目前的各种前端架构要简单得多:
- 领域层 (Domain): 纯粹的业务逻辑。没有 React,没有 API 调用,没有 UI 关注点。
- 基础设施层 (Infrastructure): 外部系统,例如:API 客户端、存储、第三方服务。
- Hooks 层: 状态管理与编排。连接领域层与 UI 层的桥梁。
- UI 层: 展示组件。专注于渲染和用户交互,仅此而已。
This gives me most of the benefits I care about without introducing unnecessary complexity.
这为我提供了我所关心的绝大多数好处,同时又不会引入不必要的复杂性。
The Biggest Lesson
最重要的一课
The lesson wasn’t that Hexagonal Architecture is bad. The lesson wasn’t that Clean Architecture is wrong. The lesson was this: Architecture should solve real problems, not hypothetical ones. Sometimes adding a boundary is the right decision. Sometimes removing a boundary is the right decision. The difficult part is knowing the difference. And that’s not something you learn from reading alone. You learn it by building software, experiencing the friction, and understanding the trade-offs firsthand.
这一课并不是说六边形架构不好,也不是说整洁架构是错的。这一课是:架构应该解决实际问题,而不是假设的问题。有时增加一个边界是正确的决定,有时移除一个边界也是正确的决定。困难之处在于如何区分这两者。这并不是单靠阅读就能学会的。你必须通过构建软件、亲身体验其中的阻力,并亲自理解各种权衡才能学会。
Final Thoughts
结语
Engineering maturity isn’t about applying every design pattern you’ve learned. It’s about understanding the cost and value of each decision. The goal isn’t perfect architecture. The goal is reducing the cost of future change. Build. Ship. Learn. Then simplify.
工程成熟度并不在于应用你所学过的每一个设计模式,而在于理解每一个决策的成本与价值。目标不是完美的架构,而是降低未来变更的成本。构建、发布、学习,然后简化。