第三课 建一Twitter之复制品 - 软件建模实用指南
在第二课吾等既明其义。 Bird 当须 勿忘二库存焉,表列其中,每字段皆可溯其用例。今当绘之。 Bird 当须 行者,以 "Post a message" 为独例,次第构绘三图:首为流程图,以次第溯用户之行;次为功能图,直取流程图而读所需之件;终为时序图,示诸件相语之状。及至终,始为便签上句之用例,遂成完整可溯之蓝图。
序言 - 基础已备
第二课终,有约在先,其言甚确:
“此即第三课之始:以数据模型为基,绘三图。”
时至其期。然当驻足一顾,察今昔之异。
于 第一课,吾等始倡三图之议——流程图、功能图、时序图——为窥一系统之三镜。既述心智之模,复辩次第之序,遂止于此。实未绘一图,此中深意:项目未启,先绘之图,其界已定,其数已明,必重绘之。
第二课,吾辈已为之界定。吾等读 Bird所陈数据之三点应用,举二实体(User 与 Message),定二库(ums 与 twitter)之五表,并立其相系之关。架构已成:一 messages 之列,有定形——一 id, content 之字段限以280字, author_id指于 ums.users之一行,而 created_at 为时戳。 users 之行亦有形。凡吾辈所绘之图,每有“存此消息”之步,皆有所指,具体而微。
是此具体者,乃变诸事。于真实数据模型之上所绘之图,非草稿也——乃规约也。方框有义。箭头载名之字段。当步骤言曰 "核验其言" 吾等已知验证所检者(谓验证之标准也):非空。 content 字符串,不超过280字符,附有认证 author_id空无一物,虚位以待.
此课绘三图毕。吾辈当依序而行——先行为,次其结构所寓,终其结构内之详谈——盖因吾辈恒循此序,盖因每图皆为次图之输入,输入必先立,而后输出方得正.
略述三镜之进阶
执笔之前,且回第一课之桥,非全然重述,惟使架梁稳固而已。
其要旨在此:凡软件之系统,可自三途观之,各途需异图以明。
| 镜 | 所答之问 | 图式 | 所见者 |
|---|---|---|---|
| 行止 | 该应用何为 行? | 流程图 | 步履、抉择、果效——此系统之态也 处理 时序渐展 |
| 结构 | 何哉 部件 必存而后其行乃成乎? | 功能之图 | 构件及其联结——系统之如 物成于片 |
| 相与应和 | 彼诸部何如? 论道 相与于运行时乎? | 时序图 | 组件间往复之讯 - 系统之如 清谈 |
此皆无以逾彼。流程图不能示以何构件当建。功能图不能言用户提交空消息时何事将生。时序图不能决功能范围是否得当。此皆 相辅不竞不争——三者皆需,盖无一可独全也.
要者,在 序之理。行止→结构→互动,每步皆承前而得:
制式既定之由:未明系统所须,焉知构件之宜?未辨构件之属,焉述其相与?行止为要旨,结构为辅佐,交感存乎结构之中。
设喻以明进境。 试想营构庖厨。初须决庖厨所当 为。-烹食藏粮,涤器洁皿。此乃行止。复问 之属何物。 必存以持诸务:庖厨、冰窖、涤器。此乃结构,自行为生。终,溯其具体流程——庖者自冰窖移至备料面,复至庖厨,依序递送食材。此乃交互,寓于结构之中。无布局,则无以设计流程;无任务,则无以设计布局。序者,法也。
镜一:行止——绘流程图
流程图答一问: 系统何为,逐步而述? 非其部属之谓也,非其器用相召之谓也,惟其行事之序、决断之次,自“吾欲发帖”以至于“事毕”——若途中有变,则至“有误”耳。
此使流程图为始之宜。其摄需求之至纯,未涉实施之择也。
循序渐进而为之
第一步 - 定起点与终点。
流始自用户按"发",即系统得所呈。终或为新行。 twitter.messages 或确认于用户,或报错而无一行写入。先列此端点名,方填其间文。
第二步 - 按序列诸行。
先行乐途,诸事顺遂,将何以处之?若“发布消息”,其序乃:
- 呈一讯
- 验真伪,察用户是否已登。
- 檢權,可乎?
- 驗文,可乎?
- 存之於庫
- 告之於人
六步耳。二為行,三為決,一為證。是謂明理,不為工籤。
第三步——增设抉择之点.
有三抉择之菱门,导引乐途:
- 用户是否已登录? 若否,则引至登录之页。登录既成,用户复归提交之步——此为循环,非绝境.
- 用户是否得发帖? 非所有账户皆有权发布——仅具读取权限或已暂停之角色,于此受阻。若无共享错误节点,则程序终止。
- 此讯是否有效? (非空乎?限280字内乎?)若无效 → 共享错误节点 → 终。
须知二误枝会于一点 Error 节点未达之前 END此乃图示之有意设计:系统对权限失败与内容失败之响应,实为同质之物——皆返用户以错误。合并之,使图示洁净,且显此等价。
第四步——连接并标注。
自上而下次第列之,以箭头相接,每箭出决策之菱形皆加标识。其枝之标识("是/非",或更详尽之"有效/无效")乃使图示一目了然之由也.
流程图
此图所示——及其未示之理
流程图故作缄默于 何 每步皆已施行。未言何组件验真,或何库核字符串之长,抑或数据库写是否同步。此等细末,非所宜言。流程图所善者,正在此也。 理也 显者:决断,枝分,果效。此乃镜一之全务也。
察之,数据之模已砺其言。 "存消息"之步,非徒言 "存消息"——乃标其域: "存消息"——书其字: author_id, content, created_at,而入之。 twitter.messages此精微之理,直出于第二课。流程图犹为高远,然不复茫昧。
既尽绘其行止,次问自现: 何部须存,方使诸步皆成? 此即第二镜——其解直自读此流程图得之。
镜二:结构——自流程图读功能图
流程图已毕。吾知“发帖”之务——其步骤、其决断、其分支。今又一问主事: 系统内须存何部,方能使诸步成之?
此乃初学者多陷之境。彼辈启新图,始创构件——一泛型 AuthService,一 APIGateway,一 DatabaseLayer ——或凭直觉,或依旧识。其果乃图,映开发者已知,非用例所实求。
然有良法。功能图非必自创。可 直读流程图.
其法:遍察诸步,一问即得
于流程图每步,问曰: 孰司其责? 其答为块。遍行诸步,合者并之,结构自现于行。
吾等循流程图,步步细览之。
| 流程图之步骤 | 任重道远 | 组件 |
|---|---|---|
| 用户提交消息 | 发HTTP之请 | 前端客 |
| 用户已登录乎? | 识其请者何人 | 推特服务 |
| 转向登录页 | 返回登录页 | 前端客户端 |
| 用户可否发帖? | 获取用户记录并检视其 PRODUCER角色 |
推特服务 → 用户管理系统 |
| 信息是否有效? | 行文之规(非空,≤280字) | 推特之务 |
| 存讯 | 书行于 twitter.messages
|
推特之务 → MySQL之库 |
| 证其成 | 返 201 所创之讯 |
推特之务 → 前端客 |
| 报错 | 返回 403 Forbidden 于客 |
推特服务 → 前端客 |
两事立显。一者, 推特服务 最重,盖其受请,核验其文,调谐其库之写。然不持用户之数——此存于UMS。故为权验,Twitter Service呼 UMS Service ,以内HTTP请,取用户之职,决其行否。此跨服务之呼,乃此术之枢要。
其次,并无别物 API Gateway 或 Auth Service 在 Bird前端客直与推特服务于端口语。 9001角色核查乃推特服务之责,应需而委诸UMS,非独立组件,居其间也。
此予吾等四物:其 前端客, Twitter服务, UMS服务,及 MySQL数据库。
功能之图
此图示若为诸名块,以标箭相连。箭承关系之性,非步骤之理(此乃流程图之责),实乃结构之依:前端客送请于推特服务;推特服务召UMS以验用户;推特服务直读与写于MySQL。每箭皆代表码库中一实名通信之径——HTTP于 :9001 为界面至服务之调用, WebClient 为服务至服务之调用,JDBC为数据库连接之用。
此图所示——及所非
功能之图,乃 组件之地图,非为步骤之图。其问"何物存焉,及其相接若何?"而非"孰先孰后?"流程之图与功能之图,非属冗余;二者所答不同,缺一不可。
亦观功能之图,其有意略去者何:无标以字段名之箭,无决断之枝,无错误之径,无序号之列。此等细目,存于时序之图。于此,其旨在于结构之明——读者应能一览而见其构成之由,及诸部之相系。 Bird 既名其件而联之,犹有一问存焉:
彼等于"发帖"之时,果如何相语乎? 此乃时序图也——既知诸组件所在,终可精绘之。
镜三:互动——时序图
流程图示告吾 何哉 "发帖"之能,功能图示已告之。 何为构件 存以为之。时序图答其末问: 诸组件互语何事,序何如,及功能实施之时?
此乃前二图之投效所系。功能图所列每组件皆成脉络。流程图每步皆化为一言于诸脉络。无所新造——悉自已知而集之。
自构件至命脉
一序列图,乃围绕而建。 生命线 - 垂直列,每组件一列,表交互之参与人。观其功能图,吾之生命线者:
- 前端客 - 浏览器,发起新的请求
- 消息控制器 者,Twitter服务之入口也,受HTTP之召。
- MessagesService 者,总司也:呼UMS,察权责,启数据库之写。
-
UMSConnector 者,薄HTTP之客也,与UMS语,道由UMS Service。
WebClient - UMS Service 者,外务也,主用户之身分与权责。
- JdbcMessageRepository 者,执行SQL插入之DAO也
- MySQL 者,持久行于数据库者也
读其流
诸生命线间之消息,循代码执行之正途。今溯之:
- 其 前端客户端 发
POST /messages/message以{ author, content }至 消息控制器。 -
消息控制器 将内容反序列化为
Message数据传输对象,并委派至 消息服务 ,经由createMessage(message)。 -
消息服务 需验证作者——因其不持用户数据,故调用 UMSConnector 以
retrieveUmsData(/users/user/{id})之 -
UMSConnector 发非阻
WebClient GET于 UMS之务。 -
UMS之务 返
UserDto,内含用户之职分。 -
MessagesService 以之__JHSNS_SEG_95b60364_278__解其应。
HttpResponseExtractor者察Roles。若用户非PRODUCER者,则此程止,返403 Forbidden于客。 - 若职检无碍, MessagesService 召
createMessage(message)于 JdbcMessageRepository。 -
JdbcMessageRepository 乃行。
INSERT INTO messages逆 MySQL (UUID以DaoHelper转换)。 -
MySQL 返
ok。 - 所存
Message复返: JdbcMessageRepository → MessagesService → MessageController → 前端客户端 为201 { message }.
时序图
此图所示,非他图所能及
观之 alt 之块。此乃权限之检,流程图中所见之菱形,亦即 MessagesService 于功能图中所负之角色检之责。然今其形已定:较 PRODUCER 之角色,若不谐,则返 403 Forbidden ,应答复经 MessageController 而达于客。
此即 可追溯性 于实践行之。流程图之 MessagesService 功能图之块→ HttpResponseExtractor → User → Roles 时序图之调用链。一意,三级之解。
亦观时序图所增,前二者皆无: 反应链。 UMSConnector调用非阻塞 MessagesService 颁布之 WebClient 请与链之其余部分于内执行 .flatMap()时序图借助于激活框,使此显明。 MS 常存而不息 UC 且 UMS 其工既毕,复续之。此并行之细,于流程图及功能图皆不可见。
三图既成,"发帖"一用,遂有全备层阶之蓝图。下节将三图并置,示终始可溯之貌。
行文暂驻,为三图独力所不能之事:并置观之,溯一意于三者之间。
取权验之时——系统决其作者可否发帖。此乃各图之所在:
| 图 | 权验之现处 | 所见之状 |
|---|---|---|
| 流程图 | 菱形 "用户可否发帖?" 分岐之所向 Error或续行验证 |
吾 逻辑 二果一决 |
| 功能图 | 箭自 MessagesService 标记之 检视角色是否含PRODUCER 指之 Roles
|
吾 物之有主 - 谁司此责 |
| 时序图 | 其 alt 段: HttpResponseExtractor → User → Roles,分岐于 403 Forbidden 或 INSERT
|
其 理法 - 何数据流,何次第,何果生 |
同此检视。三级解析。汝可指图示之钻石,循之至 MessagesService箭于功能图,再抵 alt 块于时序图——每一步皆有所得,非前图所能言也。
此性即 可溯之理。:能自上而下逐级剖析一事之要旨,至其末节而不失其本者。此乃区分图式之优劣,一者徒饰文书,二者实为蓝图之别也。
亦观可追溯性于他向所显。时序图示之,明其理。 403 Forbidden 应声返溯 MessageController 未至客户——此细末于流程图(仅书“Error → END”)及功能图(所示)皆不可见。 MessageController 相连于 GlobalExceptionHandler 不须言其时也)。图式非徒复沓,各尽其旨,以补余所遗缺.
局限与未决之问
三图既绘,一用例既溯。临终,当明此程为何——及非为何.
图式易朽。 本课之图皆映今代码之状。新域增之时 messages,或許可模式變更,或 UMSConnector 以共享之认证库易之——图示须更新。无维护之图示,其误导之速,甚于全无图示。绘制图示之学,仅半之功;另一半,乃使其诚。
此乃快照,非规格也。 此间图谱,所述为何 Bird 非其所当为也。若夫规约,则更进一步——明示不变之则、误失之约、效能之限,及偏颇之例。此图示乃规约之基,非规约之体。其答"何以而动?"非"何以而恒动?"
过度模拟,实乃大患。 于巨系统之中,为每项功能绘三图,所费时日,远逾所省。三镜之法,尤贵于决断之境:或初创新功能,或引入新员于未谙之域,或排异行于违心之模。若不择而用,则失其工而近于礼。
此图非UML也。 知統一建模語言(UML)者,察此課程之圖,借UML之制——序圖之命脈,流程圖之決策菱形——然未盡遵UML之全規。此有意也。UML精確而周全,然其精確,則損其易達。然若移於需正式規範之生產系統,則UML或C4或為當選。
何所之哉
三课毕,而 Bird 其有界定之域,实有数据之模,复具三镜之图,以成其核心之要。
其所无者,尚无可用之API。图示所示,一 POST /messages/message 端点须存,必纳之。 { author, content },必先呼 UMS,而后方可书于数据库——然此皆未成之码也。
第四课 此乃图绘与线缆交汇之处。吾等将界定API契约与端点,以达连接之效。 Bird其构成——何者所呈,何者所求,何者所返。序列图已示吾等。 POST /messages/message 必存,是所召也 GET /users/user/{id} 在UMS之上,且二者皆载有特定之负载。第四章使此契约显明而正式:请求之形、响应之形、状态码,及Twitter Service与UMS间之通信协议。
图式非所终。其为知所营建之最明之法,于营建之前可知之。


















