[{"data":1,"prerenderedAt":1079},["ShallowReactive",2],{"post:\u002Fposts\u002Fswdesign\u002Fsw-design-notes-04":3,"posts:ordered":777},{"id":4,"title":5,"body":6,"category":758,"cover":759,"date":760,"description":761,"extension":762,"featured":763,"meta":764,"navigation":765,"path":766,"seo":767,"series":768,"seriesOrder":769,"stem":770,"tags":771,"__hash__":776},"posts\u002Fposts\u002FswDesign\u002Fsw-design-notes-04.md","软件分析与设计笔记 04：接手陌生案例的第一步：三问与一张表",{"type":7,"value":8,"toc":730},"minimark",[9,16,29,34,37,44,47,51,56,59,81,84,91,95,98,107,122,129,135,139,143,146,153,160,166,170,173,243,247,254,257,297,304,308,311,315,318,329,333,336,339,345,352,356,359,362,376,382,388,392,396,399,405,408,416,420,423,495,498,502,522,525,533,536,556,559,601,604],[10,11,12],"blockquote",{},[13,14,15],"p",{},"这是我在学习软件分析与设计时整理的系列笔记。概念部分是我按自己的理解写的，示例场景都是自己编的。理解有偏差的地方欢迎指出。",[10,17,18],{},[13,19,20,24,25,28],{},[21,22,23],"strong",{},"本篇起进入贯穿案例","：片区家电维修派单系统 —— 客户报修 → 客服派单 → 工程师接单上门 → 回填工单 → 仓管备料 → 片区经理看板。这一篇先做",[21,26,27],{},"预习","（把陌生案例读出条理），05 做范围界定，06 用数据校验，07 写成用户故事，08 起画图。",[30,31,33],"h2",{"id":32},"_0-空白页恐慌","0 空白页恐慌",[13,35,36],{},"给你一份二十页的业务介绍材料，告诉你「下周要开始访谈用户」，多半会经历这样一个阶段：对着空白文档不知道该写什么，于是直接开始想方案 —— 「我觉得应该做一个 App，里面有这些功能……」",[13,38,39,40,43],{},"这是需求分析里最典型的起手错误：",[21,41,42],{},"信息还没拿到，方案已经想好了","。一旦进入这个状态，后面所有的访谈都会变成「验证我的方案」，而不是「发现真实的问题」。",[13,45,46],{},"这一篇讲一个最小的起步动作：用三个问题把自己锚在问题上，再用一张表把发现的东西固定下来 —— 也就是先做一次预习工作坊（preparatory workshop）。",[30,48,50],{"id":49},"_1-只问三个问题","1 只问三个问题",[52,53,55],"h3",{"id":54},"_11-三个问题","1.1 三个问题",[13,57,58],{},"面对陌生业务，先只问三件事：",[60,61,62,69,75],"ol",{},[63,64,65,68],"li",{},[21,66,67],{},"Who（谁参与）"," —— 这个流程里有哪些角色？他们分别代表谁的利益（也就是利益相关者，stakeholder）？",[63,70,71,74],{},[21,72,73],{},"What（做什么）"," —— 每个角色具体在做哪些事？动作是什么？",[63,76,77,80],{},[21,78,79],{},"Why（为什么）"," —— 为什么要这么做？不做会怎样？这一步是为了满足什么？",[13,82,83],{},"三问的顺序不能换。先跳到最后一步「那应该怎么做」，就回到了上面说的那个坑。",[13,85,86],{},[87,88],"img",{"alt":89,"src":90},"接手陌生案例时的三问与记录表：三问是 Who 谁参与、What 做什么、Why 为什么；记录表四列是问题、提出人、答案、假设与理由；表下结论是假设必须写明理由，否则后面无法验证","\u002Fimages\u002Fsw-design-notes-04-preparatory-worksheet.svg",[52,92,94],{"id":93},"_12-为什么-why-最值钱","1.2 为什么 Why 最值钱",[13,96,97],{},"Why 这个问题的价值常常被低估。拿贯穿案例里的第一句话试一次：",[10,99,100],{},[13,101,102,103,106],{},"客服小林每天要接 80 多通电话，她最头疼的是",[21,104,105],{},"不知道哪个工程师现在有空","，只能一个个打过去问。",[108,109,110,116],"ul",{},[63,111,112,115],{},[21,113,114],{},"What"," —— 客服在打电话问排期；",[63,117,118,121],{},[21,119,120],{},"Why"," —— 因为系统里没有排期，她只能靠人问。",[13,123,124,125,128],{},"如果只看到 What，方案会是「做一个更快的拨号工具」—— 这毫无意义，问题不在拨号速度。看到 Why 之后，真正的需求浮出来了：",[21,126,127],{},"让排期可见","。对应的方案是派单看板，而不是通讯工具。",[13,130,131,132],{},"这个问题在本系列后面还会反复出现：",[21,133,134],{},"动作（What）几乎总是可以被替代的，目的（Why）才是需求。",[30,136,138],{"id":137},"_2-为什么要把假设单独拎出来","2 为什么要把「假设」单独拎出来",[52,140,142],{"id":141},"_21-事实与猜测必须分开记","2.1 事实与猜测必须分开记",[13,144,145],{},"在信息不全的阶段，你一定会有推断（assumption，假设）。比如看到「客服每天处理 80 通电话」，很自然会想「所以客服人力是瓶颈」。",[13,147,148,149,152],{},"问题在于：",[21,150,151],{},"这个推断是事实还是猜测，必须分开记","。如果不分开，几轮讨论之后，猜测就会变成「大家都知道的事实」，最后写进需求文档，没人记得它从来没被验证过。",[13,154,155,156,159],{},"而且在这个案例里，这个假设其实是",[21,157,158],{},"错的","：瓶颈不在客服的人手，而在于她必须一个个打电话确认排期 —— 电话量是症状，不是病因。如果照「加人手」的方案做，电话量不会降，只是多雇一个人一起打。",[13,161,162,163],{},"这就是为什么「假设」这一列必须存在：",[21,164,165],{},"它保护你不把猜测当结论，也方便日后被数据推翻。",[52,167,169],{"id":168},"_22-那张四列表","2.2 那张四列表",[13,171,172],{},"所以我用四列：",[174,175,176,192],"table",{},[177,178,179],"thead",{},[180,181,182,186,189],"tr",{},[183,184,185],"th",{},"列",[183,187,188],{},"内容",[183,190,191],{},"性质",[193,194,195,207,217,230],"tbody",{},[180,196,197,201,204],{},[198,199,200],"td",{},"问题",[198,202,203],{},"你提出的问题本身",[198,205,206],{},"——",[180,208,209,212,215],{},[198,210,211],{},"提出人",[198,213,214],{},"谁提的（团队内也要记）",[198,216,206],{},[180,218,219,222,225],{},[198,220,221],{},"答案 \u002F 事实",[198,223,224],{},"对方回答的内容，或你观察到的现象",[198,226,227],{},[21,228,229],{},"可直接使用",[180,231,232,235,238],{},[198,233,234],{},"假设与理由",[198,236,237],{},"由事实推出的推断，以及推出它的依据",[198,239,240],{},[21,241,242],{},"必须验证",[52,244,246],{"id":245},"_23-假设必须带上理由","2.3 假设必须带上理由",[13,248,249,250,253],{},"关键在最后一列：",[21,251,252],{},"假设（assumption）必须带上理由（justification）","。因为理由是验证时唯一能操作的东西 —— 没有理由，你不知道该去看什么数据、问什么问题，也就无法推翻它。",[13,255,256],{},"拿贯穿案例里的一行填出来：",[174,258,259,271],{},[177,260,261],{},[180,262,263,265,267,269],{},[183,264,200],{},[183,266,211],{},[183,268,221],{},[183,270,234],{},[193,272,273],{},[180,274,275,278,281,284],{},[198,276,277],{},"客服一天接多少电话？为什么这么多次？",[198,279,280],{},"王姐（片区经理）",[198,282,283],{},"日均 80 通，其中约 40 通是客户问「几点到」",[198,285,286,289,290,293,296],{},[21,287,288],{},"假设","：客户反复来电是因为没有进度可见性",[291,292],"br",{},[21,294,295],{},"理由","：系统里没有工单状态，客户只能打电话问",[13,298,299,300,303],{},"有了「理由」这一栏，验证动作就很具体：",[21,301,302],{},"去看这 40 通电话里有多少是在问进度","。如果确实是，那「客户自助查进度」这个功能就成立；如果不是，就得重新找因。",[30,305,307],{"id":306},"_3-一个完整的预习输出长什么样","3 一个完整的预习输出长什么样",[13,309,310],{},"预习的产出不需要很好看，但要素要齐。用贯穿案例来说，一份预习材料通常包含三块：",[52,312,314],{"id":313},"_31-组织结构","3.1 组织结构",[13,316,317],{},"有哪些角色，各自负责什么。注意只记「谁负责什么」，不评价合理不合理。",[319,320,325],"pre",{"className":321,"code":323,"language":324},[322],"language-text","客服 小林        接报修电话、记地址故障、找工程师、回电客户\n工程师 老陈等40人  上门维修、回填维修记录、领配件\n仓管 小周        收发配件、记录出入库\n片区经理 王姐     汇总月度数据、向总部汇报\n（外部）配件供应商  提供库存查询接口\n","text",[326,327,323],"code",{"__ignoreMap":328},"",[52,330,332],{"id":331},"_32-端到端流程end-to-end-process","3.2 端到端流程（end-to-end process）",[13,334,335],{},"从用户产生需求到需求被满足，中间经过哪些角色、哪些系统、哪些手工环节。这一块记录的是现有业务流程（current business process），也就是现状（as-is）；系统上线后希望达到的样子通常叫目标态（to-be）。",[13,337,338],{},"贯穿案例的现状可以画成一串方框：",[319,340,343],{"className":341,"code":342,"language":324},[322],"客户打电话 → 客服手记 Excel → 客服逐个电话找工程师 → 客服回电客户\n          → 工程师上门（可能发现没配件，白跑）→ 工程师回填纸质单\n          → 仓管事后补录出入库 → 月底王姐手工汇总 Excel\n",[326,344,342],{"__ignoreMap":328},[13,346,347,348,351],{},"注意这条链里有三个",[21,349,350],{},"手工环节","：手记 Excel、逐个电话找、纸质单回填。它们各自对应一个痛点，后面都会变成需求。",[52,353,355],{"id":354},"_33-现存问题清单","3.3 现存问题清单",[13,357,358],{},"上面那张四列表。这一块是最有价值的，因为痛点（pain point）往往就藏在这些问题背后：哪些环节在返工、哪些地方靠变通做法（workaround）绕过去。它同时记录了「已知」和「待验证」。",[13,360,361],{},"贯穿案例里已经能看出两类：",[108,363,364,370],{},[63,365,366,369],{},[21,367,368],{},"返工"," —— 工程师白跑一趟（到现场才发现没配件）；",[63,371,372,375],{},[21,373,374],{},"变通"," —— 仓管在纸上记「谁欠了哪个配件」，因为系统里没有这块。",[13,377,378,381],{},[21,379,380],{},"变通做法特别值得记","。它说明现有流程有缺口，而人们已经自己补了一个临时方案 —— 那个补丁就是需求的原型。",[13,383,384,385],{},"这三块拼起来，你就有了一个可以拿去访谈的框架：",[21,386,387],{},"你知道该问谁、该问什么、以及最该被验证的是什么。",[30,389,391],{"id":390},"_4-带着问题进访谈","4 带着问题进访谈",[52,393,395],{"id":394},"_41-为什么带着清单去更有效","4.1 为什么带着清单去更有效",[13,397,398],{},"事实调查（fact finding）的方法有很多种 —— 访谈、观察、问卷、读现有文档 —— 但无论用哪一种，空手去最容易得到的是一段泛泛的介绍；带着一张问题清单去，得到的是具体的答案。",[13,400,401,402],{},"原因是：",[21,403,404],{},"你问的是他实际做过的事，而不是抽象的「你们有什么需求」。",[13,406,407],{},"举例对比：",[108,409,410,413],{},[63,411,412],{},"空手问：「你们现在的流程有什么不方便的地方？」—— 得到的往往是抱怨，不是事实。",[63,414,415],{},"带着清单问：「上周有多少单是到了现场才发现没配件的？那单后来怎么处理的？」—— 得到的是可以被记录、被验证的事实。",[52,417,419],{"id":418},"_42-一个具体的提问顺序","4.2 一个具体的提问顺序",[13,421,422],{},"预习工作坊（讲义里叫 preparatory workshop）给了一个很实用的顺序，用在访谈里同样成立：",[174,424,425,438],{},[177,426,427],{},[180,428,429,432,435],{},[183,430,431],{},"顺序",[183,433,434],{},"问什么",[183,436,437],{},"为什么放这个位置",[193,439,440,451,462,473,484],{},[180,441,442,445,448],{},[198,443,444],{},"1",[198,446,447],{},"「你昨天这一天是怎么过的？」",[198,449,450],{},"从具体的一天开始，比「你的职责是什么」得到的细节多得多",[180,452,453,456,459],{},[198,454,455],{},"2",[198,457,458],{},"「哪一步最花时间？」",[198,460,461],{},"找瓶颈，而不是找抱怨",[180,463,464,467,470],{},[198,465,466],{},"3",[198,468,469],{},"「这一步为什么必须做？」",[198,471,472],{},"问 Why，判断它能不能被替代",[180,474,475,478,481],{},[198,476,477],{},"4",[198,479,480],{},"「有没有绕过去的办法？」",[198,482,483],{},"找变通做法，那里藏着真实需求",[180,485,486,489,492],{},[198,487,488],{},"5",[198,490,491],{},"「如果这一步消失了会怎样？」",[198,493,494],{},"判断它是真的必要，还是历史遗留",[13,496,497],{},"第 5 个问题最有杀伤力。贯穿案例里问「如果客服不用一个个打电话找工程师会怎样」，答案不会是「那就没法派单了」—— 而是「那就太好了，我每天能省两小时」。这一句就已经把需求说出来了。",[30,499,501],{"id":500},"_5-常见的三个错误","5 常见的三个错误",[108,503,504,510,516],{},[63,505,506,509],{},[21,507,508],{},"直接跳到解决方案。"," 讨论到第三句就开始说「这个用系统很好做」，从此再也听不到真实流程；",[63,511,512,515],{},[21,513,514],{},"把假设写成结论。"," 「因为人工处理，所以一定很慢」—— 慢不慢要有数据，「人工」只是理由；",[63,517,518,521],{},[21,519,520],{},"不问 Why，只记录动作。"," 你知道他每天做三件事，但不知道哪一件是真正不能省的那件。",[13,523,524],{},"再加一个这个案例里特有的：",[108,526,527],{},[63,528,529,532],{},[21,530,531],{},"只记正式流程，不记变通。"," 如果只记「仓管收发配件」，就漏掉了「纸上记谁欠配件」这件事 —— 而那恰恰是最有价值的一条。",[30,534,535],{"id":535},"本节自测",[60,537,538,541,544,547,550,553],{},[63,539,540],{},"Who \u002F What \u002F Why 三问里，为什么最后才问 Why 会出问题？",[63,542,543],{},"「客服日均接 80 通电话」和「客服人力是瓶颈」，哪一条是事实，哪一条是假设？本例中这个假设错在哪？",[63,545,546],{},"为什么假设必须写明理由？只写结论会导致什么后果？",[63,548,549],{},"一份预习输出通常包含哪三块内容？",[63,551,552],{},"为什么「变通做法」特别值得记录？举出本例中的一个。",[63,554,555],{},"访谈提问顺序里，「如果这一步消失了会怎样」为什么放在最后？它想挖出什么？",[52,557,558],{"id":558},"参考答案",[60,560,561,568,574,581,587,594],{},[63,562,563,564,567],{},"因为一旦先想方案，后面的访谈会退化成「验证我的方案」，听不到真实流程。三问的顺序是",[21,565,566],{},"先弄清现状（Who\u002FWhat），再问目的（Why）","，跳过 Why 就等于放弃判断这条流程该不该保留（§1.1）。",[63,569,570,573],{},[21,571,572],{},"「日均 80 通」是事实，「人力是瓶颈」是假设。"," 本例中它错在把症状当病因：真正的瓶颈是「必须逐个打电话确认排期」，所以加人手不会减少电话量，只是多一个人一起打（§2.1）。",[63,575,576,577,580],{},"因为理由是",[21,578,579],{},"验证时唯一能操作的东西"," —— 没有理由，你不知道该查什么数据、问什么问题，也就无法推翻它。只写结论的后果是几轮讨论后猜测变成「大家都知道的事实」，最后写进需求文档（§2.3）。",[63,582,583,586],{},[21,584,585],{},"组织结构、端到端流程（as-is）、现存问题清单","（即那张四列表）（§3）。",[63,588,589,590,593],{},"因为变通做法说明",[21,591,592],{},"现有流程有缺口，而人们已经自己补了一个临时方案"," —— 那个补丁就是需求的原型。本例：「仓管在纸上记谁欠了哪个配件」，说明系统缺少配件挂账这块能力（§3.3）。",[63,595,596,597,600],{},"放在最后是因为它",[21,598,599],{},"直接指向「这一步该不该存在」","。前面四个问题都在描述现状，只有这一问会逼出「那就太好了」这种答案 —— 而那就是需求（§4.2）。",[30,602,603],{"id":603},"术语表",[174,605,606,619],{},[177,607,608],{},[180,609,610,613,616],{},[183,611,612],{},"术语",[183,614,615],{},"中文",[183,617,618],{},"一句话解释",[193,620,621,632,642,653,664,675,686,697,708,719],{},[180,622,623,626,629],{},[198,624,625],{},"preparatory workshop",[198,627,628],{},"预习工作坊",[198,630,631],{},"在正式访谈前，先把对案例的理解整理成问题清单",[180,633,634,637,639],{},[198,635,636],{},"assumption",[198,638,288],{},[198,640,641],{},"由事实推出、但尚未验证的推断",[180,643,644,647,650],{},[198,645,646],{},"justification",[198,648,649],{},"理由 \u002F 依据",[198,651,652],{},"支撑假设成立的具体事实，是验证的着手点",[180,654,655,658,661],{},[198,656,657],{},"fact finding",[198,659,660],{},"事实调查",[198,662,663],{},"通过访谈、观察、问卷等获取事实的方法总称",[180,665,666,669,672],{},[198,667,668],{},"stakeholder",[198,670,671],{},"利益相关者",[198,673,674],{},"对流程有影响或被流程影响的角色",[180,676,677,680,683],{},[198,678,679],{},"end-to-end process",[198,681,682],{},"端到端流程",[198,684,685],{},"从用户产生需求到需求被满足的完整链条",[180,687,688,691,694],{},[198,689,690],{},"current business process",[198,692,693],{},"现有业务流程",[198,695,696],{},"系统建设之前业务实际运转的方式",[180,698,699,702,705],{},[198,700,701],{},"as-is \u002F to-be",[198,703,704],{},"现状 \u002F 目标态",[198,706,707],{},"现在怎么运转 \u002F 系统上线后希望怎么运转",[180,709,710,713,716],{},[198,711,712],{},"pain point",[198,714,715],{},"痛点",[198,717,718],{},"现有流程中受阻、返工或效率低的地方",[180,720,721,724,727],{},[198,722,723],{},"workaround",[198,725,726],{},"变通做法",[198,728,729],{},"绕开现有流程问题的临时手段，往往暴露真实需求",{"title":328,"searchDepth":731,"depth":731,"links":732},3,[733,735,739,744,749,753,754,757],{"id":32,"depth":734,"text":33},2,{"id":49,"depth":734,"text":50,"children":736},[737,738],{"id":54,"depth":731,"text":55},{"id":93,"depth":731,"text":94},{"id":137,"depth":734,"text":138,"children":740},[741,742,743],{"id":141,"depth":731,"text":142},{"id":168,"depth":731,"text":169},{"id":245,"depth":731,"text":246},{"id":306,"depth":734,"text":307,"children":745},[746,747,748],{"id":313,"depth":731,"text":314},{"id":331,"depth":731,"text":332},{"id":354,"depth":731,"text":355},{"id":390,"depth":734,"text":391,"children":750},[751,752],{"id":394,"depth":731,"text":395},{"id":418,"depth":731,"text":419},{"id":500,"depth":734,"text":501},{"id":535,"depth":734,"text":535,"children":755},[756],{"id":558,"depth":731,"text":558},{"id":603,"depth":734,"text":603},"学习",null,"2026-10-26","拿到一个完全陌生的业务案例，怎么从零开始不跑偏：只问 Who、What、Why 三个问题，把「问题—事实—假设—理由」记成一张四列表，说清为什么假设必须写明理由，以及带着问题进访谈为什么比空手去有效得多。","md",false,{},true,"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-04",{"title":5,"description":761},"软件分析与设计笔记",4,"posts\u002FswDesign\u002Fsw-design-notes-04",[772,773,774,775],"需求分析","需求获取","业务分析","学习笔记","dvDI6gX8qDBobO7A5-QzROthnd0UYvB8wVSJwSWLU3Q",[778,784,790,796,802,808,814,820,826,832,838,844,850,856,862,868,874,880,886,892,898,904,910,916,922,923,928,933,939,945,949,953,957,961,965,969,973,977,981,985,989,995,999,1005,1009,1013,1017,1021,1025,1029,1033,1038,1042,1046,1051,1056,1062,1066,1071,1075],{"path":779,"title":780,"description":781,"date":782,"series":768,"seriesOrder":783},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-28","软件分析与设计笔记 28：draw.io 作图手册：五张图的符号位置、落笔顺序与自检","不模拟软件界面，只讲清三件事：每个 UML 符号在 draw.io 里搜什么词、一张图该按什么顺序落笔、画完拿什么标准自查。覆盖用例图、活动图、顺序图、类图、界面草图五种图纸，末尾附「最容易画反的十二笔」总检表。","2026-11-19",28,{"path":785,"title":786,"description":787,"date":788,"series":768,"seriesOrder":789},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-27","软件分析与设计笔记 27：Paper 1 应试：从读案例到交卷的一次完整演算","拿一份完整的案例，从头到尾走一遍：怎么读案例列角色、怎么在四个小问之间分配时间、每一张图从哪一句话推出来、两张表怎么填、交卷前拿什么清单自查。附 C25 真题与样卷的题型分值对照。","2026-11-18",27,{"path":791,"title":792,"description":793,"date":794,"series":768,"seriesOrder":795},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-26","软件分析与设计笔记 26：总结：把整条链路串起来","系列收尾：从需求到代码的完整链路回顾、每一环的产出与验收方式、六条贯穿全系列的原则，以及一份可以直接拿去做项目自查的清单。","2026-11-17",26,{"path":797,"title":798,"description":799,"date":800,"series":768,"seriesOrder":801},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-25","软件分析与设计笔记 25：代码重构：坏味道与手法","重构不改变外部行为、只改善内部结构：四种常见坏味道与对应手法、为什么动手之前必须先有测试、什么时候该重构，以及重构和前面那些设计模型是什么关系。","2026-11-16",25,{"path":803,"title":804,"description":805,"date":806,"series":768,"seriesOrder":807},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-24","软件分析与设计笔记 24：设计原则：内聚、耦合与多态","好设计怎么衡量：内聚与耦合分别在说什么、一次从「差设计」到「多态重设计」的完整对照、抽象类与接口的选择依据，以及复用为什么会从优势变成风险。","2026-11-15",24,{"path":809,"title":810,"description":811,"date":812,"series":768,"seriesOrder":813},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-23","软件分析与设计笔记 23：设计建模：从对象模型到能实现的方案","分析模型能用但还不能直接开工：对象模型怎么映射到关系模型、继承映射的三种方案怎么选、数据访问层与 Data Broker 解决什么问题，以及三层架构与 MVC 的分工。","2026-11-14",23,{"path":815,"title":816,"description":817,"date":818,"series":768,"seriesOrder":819},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-22","软件分析与设计笔记 22：分析建模：边界、实体与控制对象","不经过分析直接写代码会踩什么坑、三种分析对象各管一段、怎么用顺序图完成一次用例实现，以及从顺序图导出类的属性、操作与关系的方法。","2026-11-13",22,{"path":821,"title":822,"description":823,"date":824,"series":768,"seriesOrder":825},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-21","软件分析与设计笔记 21：UML：类图与顺序图","为什么需要一种共同的画法：类符号三格怎么画、五种关系的符号与设计含义、每种关系落到 Java 是什么写法，顺序图的三要素怎么摆；以及这三种最容易找不到的符号在 draw.io 里各搜什么词。","2026-11-12",21,{"path":827,"title":828,"description":829,"date":830,"series":768,"seriesOrder":831},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-20","软件分析与设计笔记 20：面向对象概念：对象、关系与多态","面向对象不是「用某个语言写代码」：对象与类的区别、封装真正在保护什么、五种关系（依赖、关联、聚合、组合、继承）各自何时用，以及多态为什么能减少条件判断。","2026-11-11",20,{"path":833,"title":834,"description":835,"date":836,"series":768,"seriesOrder":837},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-19","软件分析与设计笔记 19：规范化与逻辑数据模型","一次改地址引发的数据不一致，讲清规范化的真正动机；UNF 到 3NF 每一步在解决什么问题，派生字段为什么不能存，优化为什么和规范化方向相反，以及逻辑数据模型在 3NF 之上补了什么。","2026-11-10",19,{"path":839,"title":840,"description":841,"date":842,"series":768,"seriesOrder":843},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-18","软件分析与设计笔记 18：数据库分析：实体、关系与数据字典","为什么不能拿到需求就动手建表：实体与关系怎么判定、基数为什么必须由业务方确认、数据命名要遵守什么规则，以及数据字典四列里最容易被空着的那一列。","2026-11-09",18,{"path":845,"title":846,"description":847,"date":848,"series":768,"seriesOrder":849},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-17","软件分析与设计笔记 17：用生成式 AI 做设计与开发：能用的场景与要防的坑","生成式 AI 在工作流里真正站得住的三个场景 —— 造示例数据、解释陌生代码、起草初稿；它为什么会复现社会偏见、为什么会编得像真的，以及哪些内容绝不能直接采用。","2026-11-08",17,{"path":851,"title":852,"description":853,"date":854,"series":768,"seriesOrder":855},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-16","软件分析与设计笔记 16：从 persona 到 URS：一份交付物的完整骨架","把前面十几篇串成一份能交出去的东西：用户需求规格说明书的九个部分、每一章来自哪个环节、由谁确认，以及面向决策者的提案该讲清哪三件事。","2026-11-07",16,{"path":857,"title":858,"description":859,"date":860,"series":768,"seriesOrder":861},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-15","软件分析与设计笔记 15：非功能需求：把「快、稳、安全」变成数字","为什么「系统要快」不是一条需求：非功能需求怎么量化，决定性能的用户量、交易量、数据量三张表怎么估，安全需求要写清什么，以及可靠性的「不可用」该怎么定义。","2026-11-06",15,{"path":863,"title":864,"description":865,"date":866,"series":768,"seriesOrder":867},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-14","软件分析与设计笔记 14：软件测试：层级、方法与等价类划分","「我们测过了」这句话问题在哪：为什么静态评审和动态测试缺一不可，五个测试层级各自验证什么，白盒与黑盒的差别，以及用等价类划分和边界值把无限输入变成有限用例的方法。","2026-11-05",14,{"path":869,"title":870,"description":871,"date":872,"series":768,"seriesOrder":873},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-13","软件分析与设计笔记 13：需求获取：五种调查方法与一场访谈","需求从哪里来：五种事实调查方法各自适合回答什么、代价是什么，访谈从准备到记录的全过程，问卷设计里最容易犯的错，以及访谈记录必须写下来的那几项信息。","2026-11-04",13,{"path":875,"title":876,"description":877,"date":878,"series":768,"seriesOrder":879},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-12","软件分析与设计笔记 12：前端设计：把流程变成屏幕","界面设计不是「画得好看」：从活动图走到屏幕的三步，CRUD 任务流怎么当检查表，界面必须回答的三个问题，信息架构与五种导航类型，视觉一致性与留白，以及移动端与 Web 端的差别。","2026-11-03",12,{"path":881,"title":882,"description":883,"date":884,"series":768,"seriesOrder":885},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-11","软件分析与设计笔记 11：Agentic AI 与业务流程自动化","AI agent 到底是什么：五项能力与四个核心组件，什么场景该用定时任务、什么该用程序、什么才值得用 agent，两种实现路径的差别，必须提前防住的四类失败模式，以及设计方法从提示词到编排的演进。","2026-11-02",11,{"path":887,"title":888,"description":889,"date":890,"series":768,"seriesOrder":891},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-10","软件分析与设计笔记 10：精炼用例模型：include、extend 与泛化","三种精炼用例关系的判断标准：include 什么时候用、它和 extend 的区别到底在哪、参与者泛化与用例泛化各解决什么问题，以及精炼到什么程度就该停手。","2026-11-01",10,{"path":893,"title":894,"description":895,"date":896,"series":768,"seriesOrder":897},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-09","软件分析与设计笔记 09：功能需求（二）：从流程到业务实体","活动图画完之后，怎么从流程里筛出真正的业务实体：三条判断标准、哪些名词其实不该建实体、属性从哪里来，以及领域模型和后面的数据模型分别负责什么。","2026-10-31",9,{"path":899,"title":900,"description":901,"date":902,"series":768,"seriesOrder":903},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-08","软件分析与设计笔记 08：功能需求（一）：用例模型与活动图","从用户故事到用例的翻译过程：什么才算「好」的参与者，系统边界怎么划，用例描述必须写清哪四件事，活动图怎么把分支、并行与泳道画清楚，以及这两个图在 draw.io 里各用哪个形状、最容易画错哪一笔。","2026-10-30",8,{"path":905,"title":906,"description":907,"date":908,"series":768,"seriesOrder":909},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-07","软件分析与设计笔记 07：用户故事：把需求写成可验收的一句话","用户故事的三段结构，怎么从用户画像和数据地图里把它提取出来，一条故事多大算合适、时序为什么也是需求的一部分，以及验收标准怎么写才算真的可验收。","2026-10-29",7,{"path":911,"title":912,"description":913,"date":914,"series":768,"seriesOrder":915},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-06","软件分析与设计笔记 06：范围界定（数据侧）：用数据校验你的判断","访谈结论和数字对不上时该怎么办：分析的四个层次分别在回答什么问题、为什么不能跳级、数据准备与搜集怎么做成一张应用地图，以及数据最容易在哪几个地方骗你。","2026-10-28",6,{"path":917,"title":918,"description":919,"date":920,"series":768,"seriesOrder":921},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-05","软件分析与设计笔记 05：范围界定（用户侧）：用户画像与客户旅程图","为什么「所有用户」是一个陷阱，项目边界该怎么划，用户画像要写哪五个要素、最容易写成什么废纸，客户旅程图怎么把阶段、想法和情绪画在同一张纸上，以及怎么从这两样东西一步步推到可验证的需求。","2026-10-27",5,{"path":766,"title":5,"description":761,"date":760,"series":768,"seriesOrder":769},{"path":924,"title":925,"description":926,"date":927,"series":768,"seriesOrder":731},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-03","软件分析与设计笔记 03：Agile 与 Scrum：迭代、角色与产出物","从「三周做完交付，客户说这不是我要的」讲起，说清瀑布式与迭代式的根本差别，Scrum 的三个角色和三种产出物，一个 sprint 里四次固定活动各自在解决什么问题，以及敏捷里最常见的几个误解。","2026-10-25",{"path":929,"title":930,"description":931,"date":932,"series":768,"seriesOrder":734},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-02","软件分析与设计笔记 02：设计思维、用户驱动与数据驱动","从「客服要一个能一次看完所有排期的界面」这个翻车案例讲起，说清设计思维到底是什么、用户驱动与数据驱动各自能看见什么又看不见什么、为什么真正的落点是把两者合起来的 data-informed design，以及访谈中怎么问出有用的信息。","2026-10-24",{"path":934,"title":935,"description":936,"date":937,"series":768,"seriesOrder":938},"\u002Fposts\u002Fswdesign\u002Fsw-design-notes-01","软件分析与设计笔记 01：课程地图与从需求到设计的主干","这一篇不写具体方法，先把整条链路铺开：软件分析与设计到底要解决什么问题，从需求到设计分成哪两段，中间有哪十几个环节，一份完整的交付物里应该有什么，以及后面 27 篇笔记怎么排、新人该按什么顺序读。","2026-10-23",1,{"path":940,"title":941,"description":942,"date":943,"series":944,"seriesOrder":938},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-01","Spring 学习笔记 01：IoC、依赖注入与第一个 Spring Boot 应用","从「手写 new 出来的三层结构」的痛点讲起，说清 IoC 容器、Bean 与依赖注入是怎么回事，再用 Maven 与 Spring Initializr 跑起第一个能返回 JSON 的应用。","2026-10-15","Spring 学习笔记",{"path":946,"title":947,"description":948,"date":943,"series":944,"seriesOrder":734},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-02","Spring 学习笔记 02：Spring Data JPA 基础——实体映射与 Repository","用 ORM 把类映射到表：@Entity、@Id、@GeneratedValue 怎么用，CrudRepository 三层接口怎么选，H2 与 MySQL 怎么配，以及 ddl-auto 到底该写哪个值。",{"path":950,"title":951,"description":952,"date":943,"series":944,"seriesOrder":731},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-03","Spring 学习笔记 03：JPA 查询——派生方法、JPQL 与分页排序","Repository 自带的方法只够按主键查，这篇讲三种自己造查询的方式：方法名派生、@Query 写 JPQL、原生 SQL，以及 Pageable 分页排序和投影返回。",{"path":954,"title":955,"description":956,"date":943,"series":944,"seriesOrder":769},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-04","Spring 学习笔记 04：JPA 关联映射与仓储测试","一对多、多对多怎么映射，谁负责维护外键，FetchType 与 CascadeType 该怎么选，顺带用 @DataJpaTest 与 AssertJ 把仓储层测起来。",{"path":958,"title":959,"description":960,"date":943,"series":944,"seriesOrder":921},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-05","Spring 学习笔记 05：Spring MVC 与 Thymeleaf 入门","一次页面请求在 Spring MVC 里走了哪几步，@Controller 怎么把数据交给模板，@PathVariable 与 @RequestParam 怎么取参数，以及控制器为什么必须是无状态的。",{"path":962,"title":963,"description":964,"date":943,"series":944,"seriesOrder":915},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-06","Spring 学习笔记 06：表单绑定与服务端校验","把表单字段绑到对象上，用 Bean Validation 注解做服务端校验，把错误信息显示回用户刚填的那一页，再补上自定义校验注解与全局异常处理。",{"path":966,"title":967,"description":968,"date":943,"series":944,"seriesOrder":909},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-07","Spring 学习笔记 07：Thymeleaf 片段复用与国际化","用 th:fragment 与 th:insert\u002Fth:replace 把导航栏、页脚抽成片段，页面套用统一布局，再用 messages.properties 与 LocaleResolver 做中英文切换。",{"path":970,"title":971,"description":972,"date":943,"series":944,"seriesOrder":903},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-08","Spring 学习笔记 08：HTTP Session 与会话状态管理","HTTP 无状态带来的问题，Cookie 与 Session 怎么分工，Spring 里读写会话的几种方式，以及会话固定、超时、多实例共享这些必须想清楚的事。",{"path":974,"title":975,"description":976,"date":943,"series":944,"seriesOrder":897},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-09","Spring 学习笔记 09：拦截器 HandlerInterceptor","登录检查、权限判断、请求耗时统计这类横切逻辑该放哪：HandlerInterceptor 的三个回调各在什么时机执行，怎么注册与排除路径，以及它和过滤器的分工。",{"path":978,"title":979,"description":980,"date":943,"series":944,"seriesOrder":891},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-10","Spring 学习笔记 10：Service 层与事务","一组数据库操作要么全成功要么全失败，靠 @Transactional 怎么做到；传播行为、隔离级别、回滚规则怎么选，以及自调用失效、乐观锁悲观锁这些实战里的坑。",{"path":982,"title":983,"description":984,"date":943,"series":944,"seriesOrder":885},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-11","Spring 学习笔记 11：REST API 基础——把 Service 暴露成接口","同一套 Service 怎么同时服务页面和客户端：@RestController 的路由与方法语义、状态码怎么给、DTO 怎么定，以及 MockMvc 端到端和切片测试的两种写法与各自的坑。",{"path":986,"title":987,"description":988,"date":943,"series":944,"seriesOrder":879},"\u002Fposts\u002Fjavaspring\u002Fspring-notes-12","Spring 学习笔记 12：REST 进阶——版本、更新、跨域与文档化","接口能跑通之后要处理的几件事：URL 与响应结构怎么定、版本怎么演进、更新怎么做到可安全重试、CORS 怎么配、HATEOAS 与 Spring Data REST 该不该用。",{"path":990,"title":991,"description":992,"date":993,"series":994,"seriesOrder":769},"\u002Fposts\u002Fjava\u002Fjava-functionalprogramming-notes","Java 函数式编程笔记：Lambda、函数式接口与 Streams","学习 Java 函数式编程时的个人笔记：Lambda 表达式的五步简写与方法引用、常见函数式接口、Stream 流水线与惰性求值，以及创建流、中间操作、终止操作与收集器的用法。示例代码均为自写，运行结果来自本地实测。","2026-10-13","Java 学习笔记",{"path":996,"title":997,"description":998,"date":993,"series":994,"seriesOrder":731},"\u002Fposts\u002Fjava\u002Fjava-generics-notes","Java 泛型笔记：泛型方法、有界类型与泛型类","学习 Java 泛型时的个人笔记：从重复的重载方法与多态尝试讲起，再到泛型方法与类型推断、有界泛型类型、Comparable 与 Number 边界，以及泛型类在集合中的用法。示例代码均为自写，运行结果来自本地实测。",{"path":1000,"title":1001,"description":1002,"date":1003,"series":1004,"seriesOrder":769},"\u002Fposts\u002Fmysql\u002Fmysql-learning-04","MySQL 学习笔记 04：数据操纵（增删改）","MySQL 学习笔记第四篇：INSERT 插入（含批量插入与 INSERT ... SELECT）、UPDATE 更新、DELETE 删除，以及各自的坑。","2026-10-10","SQL 学习笔记",{"path":1006,"title":1007,"description":1008,"date":1003,"series":1004,"seriesOrder":921},"\u002Fposts\u002Fmysql\u002Fmysql-learning-05","MySQL 学习笔记 05：DDL 概览","MySQL 学习笔记第五篇：数据定义语言概览——Schema、Table、View、Index、Constraints 这几类对象分别对应哪些 CREATE \u002F ALTER \u002F DROP 命令。",{"path":1010,"title":1011,"description":1012,"date":1003,"series":1004,"seriesOrder":915},"\u002Fposts\u002Fmysql\u002Fmysql-learning-06","MySQL 学习笔记 06：CREATE TABLE 与数据类型","MySQL 学习笔记第六篇：CREATE TABLE 的完整语法、常用数据类型的选型建议，以及外键的两种定义方式。",{"path":1014,"title":1015,"description":1016,"date":1003,"series":1004,"seriesOrder":909},"\u002Fposts\u002Fmysql\u002Fmysql-learning-07","MySQL 学习笔记 07：索引","MySQL 学习笔记第七篇：索引的作用与 B+ 树结构、单列与复合索引的创建、索引的代价与适用场景。",{"path":1018,"title":1019,"description":1020,"date":1003,"series":1004,"seriesOrder":903},"\u002Fposts\u002Fmysql\u002Fmysql-learning-08","MySQL 学习笔记 08：DROP 与 ALTER","MySQL 学习笔记第八篇：DROP 删除数据库对象、ALTER 修改表结构，以及常见的坑。",{"path":1022,"title":1023,"description":1024,"date":1003,"series":1004,"seriesOrder":897},"\u002Fposts\u002Fmysql\u002Fmysql-learning-09","MySQL 学习笔记 09：约束与数据完整性","MySQL 学习笔记第九篇：SQL 约束——NOT NULL、CHECK、PRIMARY KEY、FOREIGN KEY 等如何保证数据完整性，以及它们的对比。",{"path":1026,"title":1027,"description":1028,"date":1003,"series":1004,"seriesOrder":891},"\u002Fposts\u002Fmysql\u002Fmysql-learning-10","MySQL 学习笔记 10：视图","MySQL 学习笔记第十篇：视图（Views）的定义与特性、和表的对比、创建与使用，以及可更新视图的限制。",{"path":1030,"title":1031,"description":1032,"date":1003,"series":1004,"seriesOrder":885},"\u002Fposts\u002Fmysql\u002Fmysql-learning-11","MySQL 学习笔记 11：存储过程","MySQL 学习笔记第十一篇：存储过程（Stored Procedures）的概念、创建与调用、带参数的写法，以及优缺点。",{"path":1034,"title":1035,"description":1036,"date":1037,"series":1004,"seriesOrder":938},"\u002Fposts\u002Fmysql\u002Fmysql-learning-01","MySQL 学习笔记 01：MySQL 基础知识","MySQL 学习笔记第一篇：MySQL Server 与 Workbench 的安装，数据库与 DBMS 的基本概念，关系模型、ACID 事务、常见数据类型，以及后续的学习路线。","2026-10-09",{"path":1039,"title":1040,"description":1041,"date":1037,"series":1004,"seriesOrder":734},"\u002Fposts\u002Fmysql\u002Fmysql-learning-02","MySQL 学习笔记 02：SELECT 查询与过滤","MySQL 学习笔记第二篇：SELECT 的基本语法与逻辑执行顺序，WHERE 过滤（比较、LIKE、IN、BETWEEN、NULL）、各种 JOIN、UNION 与子查询。",{"path":1043,"title":1044,"description":1045,"date":1037,"series":1004,"seriesOrder":731},"\u002Fposts\u002Fmysql\u002Fmysql-learning-03","MySQL 学习笔记 03：聚合、分组与输出控制","MySQL 学习笔记第三篇：COUNT\u002FSUM\u002FAVG 等聚合函数、GROUP BY 分组、HAVING 过滤、ORDER BY 与 LIMIT，以及一条 SELECT 的完整逻辑执行顺序。",{"path":1047,"title":1048,"description":1049,"date":1050,"series":994,"seriesOrder":734},"\u002Fposts\u002Fjava\u002Fjava-oop-notes","Java 面向对象笔记：类、继承、多态与异常","学习 Java 面向对象编程时的个人笔记：类与对象、封装与访问修饰符、继承与多态、集合、抽象类与接口、异常处理。示例代码均为自写，运行结果来自本地实测。","2026-10-06",{"path":1052,"title":1053,"description":1054,"date":1055,"series":994,"seriesOrder":938},"\u002Fposts\u002Fjava\u002Fjava-basics-notes","Java 基础语法笔记：从环境安装到方法与数组","学习 Java 基础语法时的个人笔记：JDK 安装、输入输出、变量与运算符、条件与循环、字符串、数组与方法。示例代码均为自写，运行结果来自本地实测。","2026-10-05",{"path":1057,"title":1058,"description":1059,"date":1060,"series":1061,"seriesOrder":938},"\u002Fposts\u002Fgit\u002Fgit-install-and-basics","Git 安装与基本使用","从装好 Git 到跑通日常提交流程，把最常用的几条命令和它们背后的三个区域讲清楚。","2026-10-04","Git 入门",{"path":1063,"title":1064,"description":1065,"date":1060,"series":1061,"seriesOrder":734},"\u002Fposts\u002Fgit\u002Flocal-remote-repository","本地远程仓库的部署","用自己的机器当 Git 服务器：建一个裸仓库、走 SSH 连上去，把本地提交推上去。",{"path":1067,"title":1068,"description":1069,"date":1060,"series":1070,"seriesOrder":938},"\u002Fposts\u002Fguide\u002Fguide-file-layout","文件都放在哪","文章、图片、封面分别放在仓库的什么位置，哪些目录可以放手改、哪些碰了会出问题。","博客使用指南",{"path":1072,"title":1073,"description":1074,"date":1060,"series":1070,"seriesOrder":734},"\u002Fposts\u002Fguide\u002Fguide-frontmatter","frontmatter 每个字段是什么意思","文章开头那段被横线包住的字段，逐个说明作用、默认行为和写错的后果。",{"path":1076,"title":1077,"description":1078,"date":1060,"series":1070,"seriesOrder":731},"\u002Fposts\u002Fguide\u002Fguide-markdown","正文怎么写 —— Markdown 与排版效果","标题、链接、图片、代码、表格分别怎么写，以及本站对它们做了哪些自定义处理。",1793268151508]