尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

概要设计与详细设计区别、实践方法与文档评审指南

概要设计与详细设计区别、实践方法与文档评审指南 开篇先抛一个我这两年带项目时经常遇到的现场需求评审过了排期也定了到了开发阶段前后端联调时才发现接口字段对不上或者数据库表结构改了三轮底层数据模型跟最初的设计完全走样再或者一个功能模块两个人写出了两套截然不同的实现方式。追根溯源问题大多出在设计阶段——要么没做设计直接开写要么把概要设计和详细设计混为一谈写了一摞文档却没踩在点子上。很多开发者和软件工程专业的学生都卡在这个问题上概要设计和详细设计到底有什么区别界限在哪里各自要写到什么程度才算合格我在多个中大型项目的设计评审和落地过程中反复踩过这些坑也在带新人时被迫把很多“只可意会”的东西掰开揉碎讲清楚。这篇就把我的理解、实践方法、文档骨架以及容易翻车的细节一次性讲透。1. 先理清一个被问烂的问题概要设计和详细设计到底差在哪这个问题在面试、软考、课程作业、实际项目评审里反复出现但大多数人的回答停留在“概要设计是粗略的、详细设计是细致的”这种表面理解。真到了要动手写文档、画图、定方案的时候这种模糊认知会直接导致两类典型事故一类是概要设计写得过于琐碎把每个类的每个方法都定义出来结果评审会上吵成一团没人关注整体架构是否合理另一类是详细设计写得过于宏观拿到手的开发人员发现很多关键决策根本没定边写代码边拍脑袋。这两者的本质差别不在“篇幅长短”也不在“写得细不细”而在决策层次和受众的不同。概要设计面对的是系统整体解决的是“这个系统由哪些部分组成、部分之间怎么协作、技术上选什么路线”的问题受众是架构师、技术负责人、项目干系人以及参与评审的其他模块负责人。它的核心是勾勒系统的骨架和边界回答的是“我们打算怎么搭这个系统”。详细设计面对的是系统内部的具体模块解决的是“这个模块内部的数据结构是什么、接口的入参出参怎么定、核心流程的状态怎么流转、异常路径怎么处理”的问题受众是真正要写代码的开发人员包括未来的维护者。它的核心是把概要设计确定好的骨架填上肌肉和血管让开发人员拿到文档后可以不经过二次决策直接落笔。用盖房子来类比概要设计是建筑方案设计——定地块红线、建筑高度、容积率、功能分区、人车流线、水电暖通的大致走向详细设计是施工图设计——每面墙的配筋、每一根梁的截面尺寸、插座开关的精确位置、管线怎么转弯。这里要特别强调一个容易忽略的点概要设计是详细设计的前置约束。如果在概要设计阶段没有把模块边界、接口协议、数据流向定清楚详细设计做得再精细也只会是在错误的地基上精装修。反之概要设计文档写得再厚如果详细设计没有把关键决策落实到可编码程度概要设计的意图也会在执行中走样。2. 概要设计把“做什么”和“怎么拆”钉死在纸面上我见过不少团队的所谓概要设计其实就是把需求文档的目录抄了一遍加上一张复制来的系统架构图再贴一段项目背景就交差了。这种文档在评审会上往往没人能提出实质问题因为里面根本没有可评审的技术决策。真正合格的概要设计至少要回答下面几个层面的问题。2.1 系统边界与外部接口先划清“我的”和“不是我的”概要设计的第一步不是画架构图而是定义系统边界。系统边界解决的是“哪些功能在这个系统内部实现哪些功能依赖外部系统提供外部系统之间的交互协议是什么”。这一步做不好后面会出现典型的“踢皮球”式问题两个团队都以为某个功能是对方做的结果到了联调阶段才发现中间有一大段空白。具体落地时需要产出系统上下文图或者叫关联图把本系统、用户角色、外部依赖系统如支付网关、短信平台、统一登录认证、第三方数据源全部画出来并注明每个外部接口的交互方式同步HTTP还是异步消息、数据格式、SLA要求。哪怕目前还没定具体协议也要在概要设计里明确接口的负责人和确认状态作为后续详细设计的输入约束。一个实用的经验在概要设计评审时让每个外部系统的负责人逐个确认自己负责的交互链路。评审不通过的唯一标准就是“是否存在没有归属方的接口或数据流”。这个标准比任何技术指标的检查都更早暴露项目风险。2.2 逻辑架构视图分层、分模块、分职责划完外部边界再切内部蛋糕。逻辑架构是概要设计里信息量最大、也最容易写走样的部分。很多团队喜欢在这里堆砌框架名和技术栈清单Spring Cloud、Kafka、Redis、MySQL……列了一大堆但你问他们为什么把服务拆成这几个模块、模块之间的依赖方向是什么、数据归属怎么划分他们往往答不上来。我习惯用“三张图”法来组织逻辑架构的内容第一张图是业务功能架构图从需求出发把系统要支撑的所有业务能力按功能域聚合形成几个大的业务域或模块。这张图不涉及任何技术细节纯粹回答“系统从业务上要分成几块”。第二张图是技术架构图分层图在业务模块的基础上叠加技术层次接入层、应用层、服务层、数据层、基础设施层。每一层承担什么职责、层与层之间的调用规则是什么比如禁止跨层调用、禁止同层互相依赖等都要在图或配文里明确。第三张图是部署架构图物理视图回答“这些逻辑上的模块最终跑在哪几台机器/容器上网络如何分区数据如何备份”。我经常遇到的情况是业务功能架构和技术架构混着画一张图上既出现了“订单管理”这种业务模块又出现了“Redis缓存”这种技术组件最后谁也讲不清楚系统的逻辑分层。一个避免混乱的技巧先画纯业务的再画纯技术的最后合成一张体现映射关系的图。2.3 数据架构设计那是数据归属问题的核心决策数据架构是概要设计里最不该省、却最常被省的部分。很多团队的概要设计只写了“数据库采用MySQL缓存采用Redis消息队列用Kafka”这种选型清单但最关键的数据归属、数据流转、数据一致性边界几乎没有涉及。举个具体例子电商系统有订单服务和库存服务。是把订单数据和库存数据放在同一个库里还是拆成两个独立的库如果是两个库订单创建时需要扣减库存这个跨库事务怎么处理是采用分布式事务还是通过消息队列做最终一致性这些决策直接决定了详细设计中每个服务的表结构设计和接口设计方向必须放在概要设计阶段定下来。在做数据架构设计时我会强制团队回答下面几个问题并把答案作为设计文档的一部分所有核心业务实体订单、用户、商品等分别归属于哪个服务/模块实体之间的关联关系通过什么方式维护数据库外键、应用层关联、还是冗余字段是否存在跨模块的数据流转流转方式同步调用/异步消息/定时对账是什么关键链路的数据一致性要求是什么级别强一致/最终一致用哪些机制保证这些问题可能无法在概要设计阶段全部给出最终答案但至少要给出倾向性的方案和后续验证计划而不是选择性遗忘。2.4 关键技术决策与风险识别概要设计还需要明确哪些关键技术路线。比如是单体架构、微服务架构还是模块化单体选择哪种消息队列、什么版本缓存的失效策略用什么需要读写分离吗延迟容忍度是多少这些技术选型需要给出决策理由和备选方案而不是简单地“因为大家都在用”或者“因为领导选了”。我习惯在概要设计里专门开一节“关键技术决策记录”用表格列出决策项、选择方案、备选方案、决策理由、可能风险、替代时机。这样做有两个好处一是评审时可以快速聚焦争论点避免漫无边际地讨论二是项目运行一段时间后如果当初的选型被证明不合适可以通过这份记录找到当时的上下文判断是执行问题还是决策问题。3. 详细设计让编码人员可以不思考就落笔如果说概要设计的交付物是“让评审者看清楚系统的骨架”那么详细设计的交付物就是“让执行者拿到后不需要再做设计决策”。这句话听起来简单做起来却很难因为很多写详细设计的人自己都没想清楚到底哪些细节需要落到文档里3.1 接口设计不只是定义入参出参接口设计是详细设计中最核心的组成部分。这里说的接口不只是RESTful API或RPC接口还包括类与类之间的公开方法、模块对外提供的服务。很多详细设计文档里接口写得很简单方法名、参数列表、返回类型就没别的了。但真正能减少沟通成本和生产事故的接口设计至少还需要包含下面这些内容业务语义说明这个接口解决什么业务问题在什么场景下会被调用。这能防止调用方在不合适的场景下错误使用。参数约束与校验规则每个参数的取值范围、必填可选、格式要求、是否涉及权限校验。比如手机号字段是在接口层校验格式还是只做空值判断这需要明确否则前端和后端很容易对同一字段出现两套理解。异常与错误码定义接口可能抛出的所有异常类型、错误码、提示信息以及调用方应该怎么处理。我最常看到的详细设计缺失项就是错误码设计开发时浪费时间反复确认测试时才发现错误码和异常行为乱成一团。性能预期与降级方案接口的响应时间目标、吞吐量预估、被限流或依赖服务不可用时的降级策略。3.2 数据库详细设计表结构是写进代码的“契约”数据库表结构设计属于详细设计的重头戏。很多项目的表结构是开发人员边写代码边建表写到哪建到哪结果数据模型反复变动连带影响已完成的代码逻辑。详细设计阶段就应该把核心表结构定义到可评审的程度表名、字段名、字段类型、长度、是否可空、默认值、索引、主外键关系、唯一约束一张表一张表地过。这里有个很容易被忽略的细节数据库设计的命名规范也要在详细设计里定下来。表名用单数还是复数、字段名用驼峰还是下划线、时间字段统一叫什么、软删除字段怎么处理这些看似琐碎的规定实际上决定了多人协作时表结构的一致性和可维护性。我见过一个项目两个开发人员各建了十几张表一张库里有两种命名风格后续写SQL的老手都要再三确认字段名维护成本高得吓人。此外数据量预估和索引设计要放在详细设计里给出初步判断。即使暂时无法精确估算也要根据业务预期的数量级十万级、百万级、亿级选择合适的设计策略避免表结构定型之后推倒重来。3.3 流程与状态设计把状态机画清楚业务系统中大量逻辑是状态流转的逻辑订单从待支付到已支付到已发货到已完成审批单从草稿到提交到审批中到已通过。很多bug的根源在于状态流转条件不明确——开发人员A认为某状态下可以执行某操作开发人员B认为不行最后测试阶段才发现逻辑冲突。详细设计阶段对每个核心业务对象建议输出状态机图或者至少是状态流转矩阵明确对象有哪些状态、每个状态允许哪些操作、操作触发的条件是什么、状态变迁时是否有副作用比如发送通知、写审计日志、调用外部接口。对于更复杂的业务流程比如一个订单从创建到完成经历的全部环节建议画流程图或活动图把每个步骤的执行主体、前置条件、成功路径、失败处理画清楚。这是详细设计里最能减少开发和测试之间扯皮的部分。3.4 类设计与模块内部结构别过度设计也别偷工减料类图、模块内部结构图属于面向对象详细设计的核心。这里要拿捏一个度详细设计不等于把每个类每个方法都写出来——那样等于直接写了一遍伪代码维护成本极高而且代码实现时稍有变动文档就成了一堆没用的废纸。我的实践是类设计只画到有一定复杂度或存在明确设计模式选择的类和关系这个粒度。具体来说核心业务实体类包括字段定义和关键行为方法要画清楚。采用了特定设计模式策略、模板方法、观察者、工厂等的部分要把模式的参与者类和相互关系画清楚。关键业务逻辑类的核心方法接口要定义到入参出参级别。工具类、配置类、DTO/VO这些低技术含量的部分用包图概括一下即可不必逐个类画。说到底详细设计的目的是消除编码阶段的不确定性而不是把代码先写一遍。凡是能在实现时毫无争议地做出来的东西都不需要写进设计文档凡是可能被不同人实现出不同结果的东西才需要设计文档来定规矩。4. 概要设计与详细设计的红线详细到什么程度才算够这是所有写设计文档的人最纠结的问题写多了嫌冗长写少了怕说不清。我自己经历了几轮“过设计”和“欠设计”的来回折腾总结出几条判断红线。重要的判断依据是受众的熟练度和项目的不确定性。如果团队里是全一色三年以上经验的熟手详细设计的粒度可以粗一些因为很多“行业常识”不需要你写进文档如果团队里有大量新人、实习生或者跨团队协作频繁详细设计的粒度就需要更细尤其接口语义、数据字典、异常场景这些部分不能省。另外还要看项目所处阶段。一个探索型的新业务比如全新的AI产品线很多需求本身就是假设过于详尽的详细设计很可能在开发过程中被推翻性价比极低一个成熟领域的存量系统改造需求高度明确、技术和业务约束基本清楚详细设计就可以也应当做得更完备。我自己的一个硬性判断标准是**详细设计评审结束后每个功能的负责人是否都清楚自己要做哪些接口、建哪些表、走哪些流程。**如果评审完还有人追着问“这个状态变更后要不要通知用户”说明详细设计不合格得回炉如果评审会上大家都在纠结某个类的命名这种细枝末节说明写过头了该收敛。这里强烈建议团队在详细设计评审时引入“测试视角”请测试负责人提前介入。测试人员对状态流转、异常分支、边界条件是最敏感的。我多次在评审会上被测试提出“这个流程如果失败状态回滚到哪里”“这个接口并发调用会怎样”之类的问题问住这些问题在评审阶段暴露成本还很低等开发完了再发现来回沟通和返工的代价就大了。5. 可直接复用的文档骨架与评审检查单很多读者要的是“能直接拿去用”的东西。下面这两个框架是我多年实践里打磨过的版本可以直接改造成自己团队的模板。5.1 概要设计文档标准章节一份合格的概要设计说明书不必拘泥于国标模板但建议覆盖以下核心章节项目背景与目标说明为什么做这个系统衡量成功的关键指标是什么。系统边界与外部依赖系统上下文图、外部系统清单、交互协议初步约定。逻辑架构设计业务功能架构图、技术分层架构图、模块职责说明。部署架构设计物理部署视图、网络分区、关键基础设施选型。数据架构设计核心数据实体及归属、数据流转关系、数据一致性策略、存储选型。关键技术决策记录决策项、选择方案、备选方案、决策理由、风险与替代时机。安全设计初步认证授权方案、敏感数据加密要求、审计要求概要阶段先定原则。风险识别与应对技术风险、进度风险、外部依赖风险清单。5.2 详细设计文档标准章节详细设计通常按模块或子系统分别成文每个模块的设计文档建议包含模块概述模块职责、在概要设计中的定位、与其他模块的关系。接口设计所有对外接口的完整定义入参、出参、异常、错误码、性能预期。数据库设计涉及的表结构定义、索引设计、数据量预估、数据生命周期策略。核心流程设计主要业务流程的流程图/文字描述状态机定义并发与一致性考虑。类设计如适用核心类图、设计模式应用、类间关系。异常与边界处理关键异常场景的处理方案、降级与兜底逻辑。安全设计落地接口鉴权方式、敏感字段处理、越权防护详细阶段落到具体方案。5.3 设计评审检查单重点自查项评审环节我建议直接拿检查单逐条打钩避免评审变成“读文档”的过场总体层面模块划分是否足够内聚、模块间耦合是否清晰可控是否存在没有明确归属方的功能或数据流关键技术决策是否有明确理由和替代方案记录是否遗漏了非功能性需求性能、安全、可用性、可维护性概要设计层面外部接口的交互方式同步/异步、数据格式是否都已定义或已确认负责人每个模块的数据归属是否唯一是否解决了跨模块数据引用问题部署架构与逻辑架构是否一致逻辑上分层的服务在物理上如何分布异常与容错策略关键链路依赖挂掉时系统表现是什么详细设计层面每个接口的异常和错误码是否定义完整调用方能否不追问就写代码核心表结构的索引是否考虑到了主要查询路径数据量增长后是否需要分库分表状态流转矩阵是否完整覆盖了失败回退和异常路径并发一致性关键更新操作是否说明了锁策略或乐观锁方案测试视角测试人员是否能从文档中提取出完整测试用例5.4 评审过程中最容易被忽略的三个角色设计评审不能只有开发人员参与。除了前面提到的测试负责人还建议请运维/部署人员提前介入让他们从部署角度审查概要设计的物理架构是否可行、基础设施选型是否与现有运维能力匹配同时请产品经理参与评审概要设计中的数据流和业务边界防止技术方案在架构层面偏离业务需求。这个投入会在后期省下大量补救成本。我见过最惨痛的一次教训是概要设计评审只叫了开发团队没有请运维结果设计了一个依赖某种特殊消息队列的方案而运维团队根本没有维护该组件的经验也没有对应的集群资源。项目做到了后半程才发现这个问题不得不临时改方案硬生生拖慢了两个迭代。6. 踩坑经验这些坑几乎每个项目都会遇到设计文档这件事做和不做的区别往往要到项目后三分之一才看得明显。下面这些坑来自我亲眼见过、亲身踩过的失败和教训逐个拆开说。6.1 “先写码后补文档”等于没有设计有些团队名义上做了设计实际上是先让开发人员写代码项目中期再安排人补设计文档。这种模式下的文档除了应付评审和验收没有任何指导意义。更糟的是团队成员会逐渐形成一种预期反正是先写码再补文档那设计评审就随便说说。周而复始文档彻底沦为废纸。我的建议是**设计文档的价值必须在编码之前兑现否则宁可砍掉写文档的时间改为集体方案推演。**如果时间紧可以缩短文档篇幅但思考和决策的过程不能省——哪怕是用一个下午在白板上画出模块划分和数据流大家一起推演过几轮也好过每个开发自己边写边设计。6.2 概要设计和详细设计被硬拆成两个团队交接的手续不少组织按流程要求概要设计由架构师/技术经理完成详细设计由开发骨干完成两个阶段用文档交接。这个流程本身没有错但它隐藏着一个致命假设概要设计是完全正确、不需要迭代的。实际项目中详细设计阶段发现概要设计不合理的情况太常见了某个模块拆分得不够内聚、某个接口协议根本不适合这个业务场景、某些约束在实现层面做不到。一旦出现这种情况如果详细设计者只是“按文档执行”或者发现问题也不回传或者回传通道极其漫长最后交付出来的系统就会有隐性偏差。解决方法是建立双向通道详细设计过程中发现概要设计的问题先记录下来实质性影响方案的问题要尽早拉上架构师商量调整而不是等到代码写完才说“当初设计有问题”。概要设计文档也需要伴随项目进展做版本更新不能把它当成一次性交付物。6.3 详细设计文档的“八股化”还有一种很常见的问题详细设计文档写得很精美UML图一张不少格式工整但内容高度重复或空洞——每张图旁边都没有必要的解释每个接口的描述都是“用于完成XX功能”这种话参数语义、异常路径、边界处理全都没有。这种文档最大的问题是提供了“我们做了设计”的安全感实际上什么都没定。为了防止八股化我在团队里定了一条规矩**评审时不允许逐页读文档而是由设计者按“这个模块对外承担什么职责、依赖谁、内部核心流程是什么、最难处理的三个场景是什么”来讲评审者就这几个追问。**讲不清楚的地方就是设计没到位的地方。这一条在很多项目里都高效地逼出了真正的问题。6.4 模式复用失误为了设计模式而设计模式详细设计阶段设计模式的选择既有实际用途也是新手最容易犯糊涂的地方。最典型的问题是为了“高级”而强行套用模式。我见过一个项目里一个简单的实体数据存取硬要套上工厂模式加抽象工厂模式代码量翻了几倍可读性明显下降后期维护的人叫苦不迭。判断是否值得用设计模式的规则其实很简单**当前场景是否存在明确的可变点未来的变化概率大不大模式是否显著降低了核心逻辑的复杂度**如果一个模式引入之后连书写代码的人都要花时间查资料才能搞清楚调用链那大概率是用错了地方。反过来也有问题有些场景明明非常适合策略模式或模板方法模式但设计者不做抽象把相关的几个分支逻辑全部用if-else堆在同一个方法里后期加一个新策略就得改动原有代码违背开闭原则非常容易引入回归问题。我的经验是在详细设计里用模式时要写出“模式意图”这一段明确说明为什么在这里引入模式、哪个业务维度是可变的、未来预计有哪些扩展方向。如果写不出来可能就不该用如果能写出来但设计里没有画清参与者类的关系那设计就不完整。6.5 接口文档与实际代码脱节没有流水线的文档是死文档详细设计文档定义了接口如果开发完成后文档没有跟着代码更新很快文档就会变成和代码对不上的“死文档”。后期接手的人看文档做开发照着错误的信息写调用代码就会踩进坑里。这个问题不能靠“大家自觉维护”来解决我实践下来比较有效的手段是接口定义优先采用代码即文档的方式比如OpenAPI定义、gRPC proto文件、Thrift IDL让接口文档从代码中自动生成避免手工维护两份信息源。数据库表结构用版本管理工具管理如Flyway、Liquibase表结构变更走评审和迁移脚本而不是直接改线上库。设计文档中引用的接口和表名要和代码中的定义保持一份准确的索引目录至少做到“文档中出现的名字在代码里能找到、代码里出现的对外接口在文档里有据”。工具的自动化替换不了人对设计的理解但它能省去大量“文档和代码到底哪个是对的”的无谓争执。6.6 评审会变成“念文档”的形式主义最后讲评审本身。很多团队的评审会开成了设计者念PPT、其他人边听边走神、最后项目经理问“有什么问题吗”、大家沉默、然后散会。让评审会有效的方法前面已经提到了不少我再补充两个技巧第一个技巧是评审前提前分发文档并约定必须提两个问题。每人至少提两个问题哪怕不成熟可以有效避免“没读过文档就来开会”的形式主义。第二个技巧是按评审角色限定提问范围。让测试关注异常和边界让运维关注部署和基础设施让产品关注业务覆盖让开发关注接口和数据结构——每个人都聚焦自己最擅长的视角而不是笼统地“看一遍提意见”这样效率和效果都会明显提升。7. 设计文档的延续价值远不止应付评审和验收很多开发者和团队把设计文档当成项目流程中的一个不得不交的作业交完就束之高阁。但我的经验是设计文档真正的价值在项目上线后才会集中显现新成员入职后的系统熟悉路径、线上问题追溯时的背景还原、系统重构时的现状盘点、以及年度技术复盘时“这个决策当时是怎么定的、现在看对不对”的回顾。尤其对于需要长期维护的系统一份忠实记录“为什么这么设计”的文档远远比事后靠代码反推架构要高效得多。代码只能告诉你系统“现在是什么样”设计文档结合变更记录才能告诉你系统“怎么变成了今天这样”。理解了后者你才有资格对系统做任何重大修改。所以每次写概要设计和详细设计时不妨把自己代入半年后那个接手系统的运维同事的角度去写他能不能只看这份文档就理解系统的整体结构他能不能快速定位一个线上问题应该看哪段代码、查哪张表他能不能知道改一个字段会影响哪些上下游系统如果答案是肯定的这份设计文档就真正合格了。这也可以作为每个人的一个自检维度建议在每次设计评审时对照着手里的文档问自己一遍。我自己坚持这个习惯多年不能说所有的设计都完美落地但至少避免了大多数因为“设计缺失”或“设计失真”而产生的后期灾难这也是我分享这篇长文的核心原因——希望这些经验和教训能帮助更多团队在设计阶段就把大部分成本消灭掉。
返回列表