编码前的思考
软件设计的起点
大部分人打开编辑器就开始写代码。这很自然。代码是可见的、具体的、能运行的。但真正的设计发生在代码之前。
软件设计的本质是把模糊的想法转化为清晰的结构。这个过程需要一套思维框架。
💡 Click the maximize icon to view in fullscreen
从想法到代码,中间缺失的那一层就是思考。
Want-Have-Need 框架
设计任何系统,都可以从三个问题开始:
我想要什么(Want):需求的本质是什么。不是功能列表,而是真正要解决的问题。很多时候,表面需求和真实需求不一致。
我有什么(Have):现有的技术栈、架构、约束条件。这些决定了可能性的边界。忽略现实约束的设计是空中楼阁。
我需要做什么(Need):从 Want 到 Have 之间的差距,就是需要填补的部分。这才是真正的工作量。
这个框架强制你面对现实。它阻止你跳过思考,直接开始堆砌代码。
想要:博客评论系统 有:静态生成的 MDX 博客 需要:在静态内容中注入动态交互
这个"需要"揭示了真正的挑战:如何在构建时和运行时之间建立桥梁。
四个递进的层次
确认了 Want-Have-Need,设计工作才真正开始。这个过程有四个递进的层次。
理解边界
边界是约束。约束不是限制,而是设计的基础。
在静态生成和动态交互之间有一条边界。内容在构建时确定,交互在运行时发生。这条边界决定了架构的形状。
不理解边界,设计就会侵入错误的领域。比如试图在构建时处理用户登录,或者在运行时重新生成静态内容。
定义数据
数据结构是系统的骨架。先定义数据,再考虑功能。
什么是一条评论?它包含哪些字段?评论之间有什么关系?数据如何存储和检索?
数据模型的清晰度直接决定了代码的复杂度。模糊的数据结构会导致混乱的逻辑。
设计函数
函数是操作数据的方式。每个函数回答一个问题:这个数据需要哪些操作。
创建、读取、更新、删除。这是基础。但真正的设计在于:如何定位一条评论?如何处理文本变化?如何确保数据一致性?
函数的粒度和组织方式决定了系统的可维护性。
建立抽象
抽象是隐藏复杂度的方式。好的抽象让高层代码不需要关心底层细节。
表现层不需要知道数据如何存储。业务逻辑不需要知道 API 如何调用。数据访问层不需要知道数据库的具体实现。
分层不是为了好看,而是为了让每一层都能独立演化。
💡 Click the maximize icon to view in fullscreen
为什么顺序很重要
这四个层次必须按顺序进行。跳过任何一步,后果都会在代码中体现。
不理解边界就定义数据,数据结构会侵入错误的层次。不定义数据就设计函数,函数的接口会反复变化。不设计函数就建立抽象,抽象会泄漏实现细节。
设计的过程是从外到内、从粗到细、从抽象到具体。每一步都为下一步提供基础。
复杂度的本质
复杂度来自两个地方:问题本身的复杂度,和不必要的复杂度。
问题本身的复杂度是必然的。行间评论的文本定位就是复杂的。DOM 会变化,内容会更新,浏览器有差异。这些复杂度无法消除,只能管理。
不必要的复杂度是设计不当造成的。混乱的数据结构、职责不清的函数、泄漏的抽象。这些复杂度是可以避免的。
好的设计不是消除复杂度,而是把复杂度放在正确的地方。把问题本身的复杂度隔离在专门的模块里,让其他部分保持简单。
文本定位引擎(复杂):
- 处理 DOM 变化
- 实现模糊匹配
- 处理浏览器差异
评论 UI 组件(简单):
- 调用定位引擎的接口
- 渲染定位结果
- 不关心定位细节
复杂度被封装在引擎层,上层代码保持简洁。
策略与选择
设计不是找到唯一正确的答案,而是在约束下做权衡。
同一个问题可以有多种解决方案。全客户端、混合渲染、完全集成。每种方案都有优势和代价。
选择的依据是:时间、资源、技术能力、未来扩展性。没有绝对的好坏,只有当下的合适。
重要的不是第一次就选对,而是留出调整的空间。好的设计允许方案的演进,而不是一开始就锁死。
设计的终点
设计什么时候结束?当你能清晰回答这些问题:
- 系统的边界在哪里
- 核心数据结构是什么
- 关键操作有哪些
- 抽象层次如何划分
不需要完美,只需要清晰。清晰的设计可以随时调整,模糊的设计只会越改越乱。
编码是设计的延续,不是设计的替代。好的代码源于清晰的思考。
下次开始一个新功能时,试着先问自己:
- 我真正要解决的问题是什么
- 我有哪些约束和资源
- 从这里到那里,中间缺什么
- 数据的形状是什么样的
先想清楚,再动手。
Related Posts
Articles you might also find interesting
从意图到架构
技术方案不是设计出来的,而是从问题中涌现的。理解这个过程,就理解了软件设计的本质。
调用链路追踪法:从断点到根因
功能失效的背后,是一条完整的调用链路。追踪这条链路,定位断点,才能从根本上解决问题。
依赖注入
依赖注入不是关于框架或工具,而是关于控制权的转移。理解这个转移,就理解了软件设计的核心原则。
在运行的系统上生长新功能
扩展不是推倒重来,而是理解边界,找到生长点。管理层作为观察者和调节器,附着在核心系统上,监测它,影响它,但不改变它的运行逻辑。
引入懒加载模式
懒加载不是优化技巧,而是关于时机的选择。何时创建,决定了系统的效率和复杂度。
队列、可靠性与系统边界
探讨消息队列系统如何通过时间换空间,用异步换解耦,以及可靠性背后的权衡
Context 驱动的认证状态管理
认证系统的核心不在登录按钮,而在状态同步。如何让整个应用感知用户状态变化,决定了用户体验的流畅度。