如果我早点知道这7个教训,我的前端工程师生涯就能节省好几年。
几年前,如果你问我什么是系统设计,我可能会说“后端的东西,对吧? ”😅
我非常擅长构建用户界面、设计组件,并且能做到像素级完美。
但是,当涉及到构建大规模前端应用程序、做出权衡取舍,或者仅仅是知道如何沟通设计决策时,我却感到……完全迷茫。
事实是——我并不孤单。
系统设计有时会让人感觉像个黑匣子,尤其是对于前端工程师而言。
我们大多数人都没有被教导如何思考这个问题。人们只是期望我们能神奇地知道。
我把项目搞砸了。我不该过度设计的地方,我却过度设计了。
有时,我会完全不知所措——因为我不知道从哪里开始。
我意识到我不能再这样凑合下去了。
我开始提出更好的问题,向更聪明的人学习,观察团队如何做决定——最重要的是,把这一切都记录下来。
以下是我希望早点知道的 7 件事——这些经验教训能让我成为一名更优秀、更高效的工程师,并且肯定能帮我省去不少麻烦。
1. 系统设计并非后端工程师的专属领域
我花了太长时间才意识到前端系统也需要设计。
我以前认为系统设计主要涉及后端方面的内容,比如数据库、队列和服务器扩展。但实际上,我们在前端每天都要做同样重要的决策。
你不仅仅是在页面上放置按钮。你是在做决定:
- 页面加载方式
- 当数据被获取时
- 如果出现故障会发生什么?
- 如何保持用户体验的快速流畅
我举几个简单的例子:
-
一个旅行网站首页(例如 Airbnb):
你希望它加载速度快、个性化,并且对搜索引擎友好。
那么,应该在客户端渲染、服务器端渲染,还是使用静态生成呢?每种方法都有其优缺点。选择一种方法意味着要考虑性能、基础设施和用户体验。这就是系统设计。 -
内部仪表盘:无需 SEO,但包含海量数据和筛选器。
您可以使用客户端渲染、防抖搜索输入框,并在加载时显示框架 UI。这些都是小细节,但它们共同决定了用户体验的成败。 -
博客或营销网站:内容很少更新?非常适合静态内容生成+CDN。
这也是一种经过深思熟虑的设计决策。
这些都是日常决策。但当你退后一步审视它们时,你会发现它们不仅仅是“前端选择”,而是系统选择。
我真希望自己能早点意识到这一点。
2. 从问题入手,而非从解决方案入手。
我早期犯的最大错误之一就是直接跳到图表绘制上去。
只要有人让我设计系统,我就会开始画各种方框,谈论 React,可能还会为了保险起见加上 Redux 😅
但我完全不知道自己为什么会做出那些选择。
随着时间的推移,我逐渐明白,最优秀的工程师并非从架构设计起步。
- 他们以提问开始。
- 他们停顿了一下,倾听着。
- 他们会先尝试理解问题,然后再提出解决方案。
以下是我现在会问的一些问题——无论是在面试中还是在工作中开发项目时:
问题与背景
- 该系统的核心目标是什么?
- 用户群体有哪些?
- 他们首先需要看到的是什么?
- 用户角色是否有所不同(管理员、访客等)?
范围与限制
- 哪些内容在范围内?哪些内容明确排除在外?
- 是否有时间限制、团队规模限制或技术限制?
- 这款产品可以在手机、台式机和平板电脑上运行吗?
表现与经验
- 我们是否应该关注搜索引擎优化(SEO)?(例如,我们是否应该考虑搜索引擎排名(SSR)或搜索引擎优化生成(SSG)?)
- 预期性能如何?(首次加载、交互)
- 预计该功能在离线或网络信号较弱的情况下也能正常工作吗?
极端情况与可靠性
- API 故障时会发生什么?
- 用户在加载过程中应该看到什么?空白页面?错误信息?
- 不同的用户会看到不同的用户界面版本吗?
问了这些问题之后,我的一切人生都改变了。
现在,我不再盲目地尝试各种技术,而是构建有明确目标的系统。
因为提出更好的问题,才能做出更好的决定。
3. 性能并非事后才考虑的因素
曾经有一段时间,我会先构建一个完整的应用程序,确保所有功能都能正常运行,然后再考虑性能问题。
不出所料,这常常导致痛苦的修复、不必要的重写以及缓慢的体验,令用户和我感到沮丧。
我过去常常把性能当作锦上添花的东西。但最终我意识到,性能不是最后才添加的,而是从一开始就要精心设计的。
对我帮助最大的一个思维转变是在项目开始时设定一个清晰简洁的性能目标。例如,我一开始就决定“在4G网络下,第一个屏幕的加载时间应该在2秒以内”,这个目标影响了我之后做出的每一个技术选择。这并非追求完美或Lighthouse评分,而是致力于打造一个可用、快速且符合用户需求的产品。
卓越的性能并非源于某个神奇的技巧,而是源于无数细微而周全的选择,这些选择最终会汇聚成巨大的影响。以下是我在设计过程早期阶段会考虑的一些因素:
随着时间的推移,我逐渐养成了在系统设计中考虑性能的习惯。以下是我现在会尽早考虑的一些因素:
- 我对非关键组件进行延迟加载,这样用户就不会因为等待所有内容同时加载而阻塞。
- 我将大型 JavaScript 文件拆分,这样浏览器就不会因为解析大型文件而卡顿。
- 我预加载首屏内容,以缩短首次有效绘制时间。
- 我会压缩图片,并且更喜欢像 WebP 这样的现代格式,以便在不损失质量的情况下减小文件大小。
- 我延迟加载首屏以下的内容,尤其是在移动设备上。
- 我使用骨架加载器而不是旋转加载器,以创造更流畅的用户体验。
- 我会尽可能缓存 API 响应,以避免不必要的网络调用。
- 我经常将长列表或大型表格虚拟化,尤其是在仪表板和内部工具中。
- 我会对开销较大的交互进行防抖或限速处理,例如实时搜索或需要大量输入的表单。
- 我使用 React.memo 或 useCallback 等工具来避免 React 中不必要的重新渲染。
- 我为关键资源添加了 dns-prefetch、preconnect 和 preload 等资源提示。
你不需要在每个项目中都实现所有这些功能。但尽早了解它们能让你做出更明智、更有针对性的设计决策。
如今,表现不再是我“以后再说”的事情,而是我从一开始就思考的一部分。
4.权衡取舍比“正确答案”更重要
当我开始学习系统设计时,我认为目标是找到最佳解决方案——代码最简洁、架构最佳、没有任何妥协的解决方案。
但随着时间的推移,我学到了更有价值的东西:
很少有唯一的“正确”答案。更重要的是理解和解释其中的利弊权衡。
作为前端工程师,我们经常需要做出这类决定:
例如,我曾经需要在新的产品详情页面中使用客户端渲染 (CSR)还是集成服务器端渲染 (SSR)之间做出选择。
- 企业社会责任 (CSR) 更简单,而且完全可以融入我们现有的架构,但团队希望提高产品曝光率的搜索引擎优化 (SEO)。
- SSR 可以提高爬虫性能,但也增加了我们以前从未处理过的复杂性。
我们最终决定在初始版本中使用CSR,并计划稍后为高影响力页面引入SSR。这并非完美方案,但它让我们能够在加快开发速度的同时,兼顾未来的需求。
还有一次,我为内部仪表盘开发一个包含大量筛选条件的表格。
后端 API 非常灵活,所以我们有两种选择:
- 一次性获取所有数据并在客户端进行筛选,或者
- 每次交互时按需获取筛选后的结果。
我们选择客户端过滤是为了在小规模情况下简单快速,因为我们知道如果数据量太大,最终还是要切换到客户端过滤。
两种方案都不完美,但都奏效了——因为我们是经过深思熟虑后做出的决定。
前端系统设计的真正技巧在于:不是选择“最好”的技术,而是知道你要权衡什么,并能够说:“这就是我选择的,这就是它在目前情况下合理的原因。”
简而言之,我认为设计不在于正确与否,而在于深思熟虑。
5. 为团队设计,而不仅仅是为自己设计
曾经有一段时间,我非常喜欢编写“巧妙”的代码。
可复用的钩子、抽象组件、自定义配置、动态属性——这一切在我看来都简洁而强大。
但我慢慢开始注意到一些事情。
团队中的其他人——尤其是新来的开发人员或没有参与过那部分代码库开发的人员——很难理解我所构建的东西。
我原以为“干净干燥”的地方,实际上却是“难以触及,而且触摸起来令人害怕”。
那时我才意识到:好的系统设计不是为了炫技,而是为了构建一个其他人可以利用的东西。
现在,当我设计组件、流程或数据结构时,我会问自己:
- 这份工作容易上手吗?
- 一个完全不懂的人能在10-15分钟内理解吗?
- 如果我休假,其他人可以帮忙调试吗?
我也开始接受那些枯燥乏味、显而易见的解决方案。
例如:
- 编写一些略有重复但易读的组件。
- 添加行内注释以供将来参考
- 避免过度抽象,即使逻辑看起来有点重复。
- 创建清晰的文件夹,并有目的地命名,而不是为了耍花招。
这并非降低标准,而是为了善待你的团队、未来的自己,以及几个月后可能接触你系统的任何人。
因为最好的前端系统?
他们看起来并不是最聪明的。
正是它们让每个人都能充满信心地进行创作——而不用担心会弄坏东西。
6. 状态管理是一个设计问题
很长一段时间以来,我一直把状态视为“另一个实现细节”。
如果某个东西需要记住它的值,我会把它放到 useState 中,或者如果它是“全局”的,就放到 Context 中。
没有具体计划,只是凭感觉。
但随着时间的推移,我开始注意到状态经常导致错误、混乱和痛苦的重构。
我意识到:国家存在于何处,国家如何流动,国家属于谁——这不仅仅是一个编码问题。
这是系统设计问题。
我见过一些组件因为在不应该相互通信的地方共享状态而崩溃的情况。
我见过一些团队努力管理加载标志、本地 UI 状态、后端数据和用户偏好——所有这些都纠缠在一个巨大的存储中。
我学到的是:最好的系统在编写任何一行代码之前,都有一个清晰的状态计划。
现在当我接近州政府时,我会问:
- 这是什么状态?(用户界面状态?服务器状态?应用级配置?)
- 它应该放在哪里?(本地组件?上下文?还是像 React Query 那样的服务器缓存?)
- 它应该归谁所有?(可以放在一起吗?还是需要吊装?)
- 它需要在路由或会话之间保持持久性吗?
有时候,答案很简单——比如使用 useState 来实现切换功能。
有时,如果状态是共享的或与 API 响应关联,则最好使用 Zustand、Redux Toolkit 或 React Query 等工具。
有时候……我根本不需要图书馆。
一个清晰、有目的的结构。
目标不是“使用最好的工具”。
目标是设计一个流程,让正确的数据位于正确的位置——团队无需经过五层上下文即可对其进行推理。
当我开始把状态看作是系统架构的一部分,而不仅仅是组件逻辑时,一切都变得更加顺利:bug 更少,调试更容易,而且随着应用程序的增长,压力也小了很多。
7. 真正的技能是沟通
当我第一次听到“系统设计”这个词时,我以为它全是关于架构图、性能技巧和我还没记住的命名模式。
但随着我作为一名工程师的成长,我越来越发现,那些脱颖而出的人并不总是那些拥有最花哨答案的人——他们是那些能够清晰地表达自己想法的人。
在面试、设计评审,甚至只是与队友进行白板讨论时,能够说出以下观点:
- 以下是我考虑过的方案……
- “我选择这个产品是因为X,尽管它也附带Y。”
- “如果规模扩大,我们可以这样改进系统……”
这种沟通方式能够建立信任。
这表明你不是在随意使用技术——你是在有目的地思考、计划和设计。
我也有过一些轮次没能全部做对的情况。
我并没有选择他们预期的那种图案。
但我最终得到了这个角色——因为我问了一些好问题,解释了我的理由,并且在不确定的情况下保持了冷静。
说实话,这反映了现实世界。
你永远不可能掌握全部背景信息。
你很少能百分之百确定。
但如果你能大声思考,让其他人参与到你的过程中,并表明你在深思熟虑地权衡决策——这才是系统设计的真正意义所在。
归根结底,完美与否并不重要。
关键在于清晰表达、协作配合和灵活应变。
这是一项值得练习的技能。
得知这一切之后发生了什么?
一旦我开始用这种视角看待前端系统设计,一切都发生了改变。
我不再毫无计划地盲目编写代码了。
我开始问一些更好的问题。
我开始像一个建造者那样思考——注重结构、思路和目标。
随着时间的推移,我为自己建立了一套系统——一个我可以遵循的心理清单。
- 它对我的面试很有帮助。
- 它对我的实际项目很有帮助。
并非因为我掌握了所有答案。
但我希望在我努力理解这一切的时候,有人能给我提供这样的东西。
那时我决定把它写成一本手册。
📘前端系统设计:我希望我拥有的指南- 为想要构建更好的系统并超越编写代码思考的工程师提供的实用指南。
它涵盖了我们在这里讨论的所有内容以及更多——如何解决问题、构建你的思维、处理权衡取舍,以及真正享受系统设计。
感谢阅读💙
如果你想提升前端技能——尤其是在系统设计方面——我希望这篇文章对你有所帮助。
如果你正在准备面试——你一定可以的。
文章来源:https://dev.to/smilegupta/7-lessons-that-wouldve-saved-me-years-as-a-frontend-engineer-fje