跳到正文
册页

图示

WorkflowFigure - 流程图

按泳道和阶段排的流程,主路径画得比它的分支重。

用法

什么时候用它

运行手册、审批链、CI 流水线——任何每一步都有归属的东西。mainPath 才是把十四个方框变成一张有主语的图的那一下。

来自@misoto22/folio/diagrams

TSX
import { WorkflowFigure } from '@misoto22/folio/diagrams'

说明

一段流程:谁做什么、按什么顺序、以及哪里会出错。

三层结构叠在同一张网格上。之所以是三层,是因为它们回答的是读者带到一份运行手册前的三个不同问题。

泳道是行,回答谁。标了 exception 的泳道是唯一一条拿到底色而不是细线的带子;它之所以能豁免「框只能是线」这条法则,是因为没有任何路由横穿它——它就是失败路径的地面,而不是画在顺利路径之上的一个框。

阶段是横跨所有泳道的列,回答何时。印成表头线上的说明文字,因为阶段是一个坐标轴标签。分组是单条泳道内部的框,回答什么属于一起——一个规划循环、一条取证路径。

主路径更重,层级就在这一处。mainPath 列出读者应该不用思考就能跟下去的那串节点 id。它上面每两个相邻 id 之间的边,无论自己的 variant 说什么,都按强调的粗细来画——正是这一下,把十四个方框、十九根箭头,变成一张有主语的图。error 角色走的是反方向:虚线、更淡,让异常路径退后但不消失,async 也一样。branch 不额外加任何笔画:一条分支就是主路径没有列出的那条边,而这在页面上已经构成区别了。

结构

WorkflowFigure anatomy
部件说明
图外框必填每张图都待在的同一个框。流程交给它的是一份图例,列的是线的 variant,不是节点的种类——Call、Primary path、Crosses a trust boundary、Asynchronous——因为运行手册是冲着它的箭头读的,不是冲着它的方框。
泳道必填一条泳道一条 92 单位高的带子,名字排在它左侧 118 单位宽的边槽里。带子只覆盖这条泳道真正装着的东西;标了 exception 的泳道是上底色而不是描线——这个包的图里唯一的一处底色,因为没有任何线会从它上面穿过去。
列必填col 索引的东西:168 单位宽的列,配 58 单位的间距,每条泳道上都一样。节点在自己泳道的高度里居中,只有 yOffset 能把它从那条中线上挪开。
阶段表头一行等宽小标题,印在它 fromCol 的 x 上,下面那条线从 fromCol 一路横到 toCol——所以一个阶段管到哪里,是读者看得见的,而不是只有作者才知道的一个字段。variant 会把这条线在 security 下画成虚线、在 emphasis 下加粗。阶段是一个轴标签,所以它按轴标签来排,而不是被框起来。
分组框一圈带标签的线,围住单独一条泳道之内连续的几列——一个规划循环、一条取证路径——variant 是 security 时画成虚线。
主路径mainPath,用线重来画,而不是另给一种标记:它上面每两个相邻 id 之间的那条边都会加重,不管这条边自己的 variant 写的是什么。

实践建议

推荐

  • 每个节点的 lane 都要是 spec.lanes 声明过的。不认识的 lane id 照样会落到第一条泳道上——那个盒子没有别的地方可放——于是一个本该写进异常带的步骤,被画在正确的列、正确的尺寸、错误的行上,而开发环境会打印 DIAGRAM_LANE_UNKNOWN 并点出是哪个节点。
  • mainPath 要按路径的顺序写。加重只作用在相邻的两个一组上,所以 [intake, review, ship] 强调的是 intake→review 和 review→ship,别的什么都不强调;某个 id 在这份列表里的邻居若不是一条真实边的另一端,它什么也改变不了。
  • 用 role 说清楚一条边的含义,画法自会跟上。async 和 error 走安静的虚线,return 出空心箭头,而 main 和 branch 自己不加任何线型,因为 mainPath 已经用线重把这个区别画出来了。显式的 variant 会盖掉这一切,而它存在的意义正是如此。

避免

  • 阶段的 toCol 不会被画出来。小标题印在它的 fromCol 上、落在一条横贯全图的线上,所以起点在同一列的两个阶段会叠着印,而一个阶段的跨度不是读者看得见的东西。
  • 空泳道不是间隔物。带子的尺寸是按泳道装着的东西算的,所以没有节点的泳道会塌成边槽旁边大约一列宽,名字却还排在那里——而处在这个状态的异常泳道,铺出来的底色是在图旁边的一条地,不是在失败路径底下。

示例

default

一条发布流水线,失败路径单独占一条泳道。mainPath 才是给这张图一个主语的东西:它上面任意两个相邻 id 之间的每一条边,无论自身的 variant 是什么,都会按强调分量绘制,于是一个顺着那条重线走下去的读者,一个字都不用读就拿到了正常路径。异常泳道是这些图里唯一那条打了淡色底的带子,而那条回滚边是刻意画成虚线且弱化的——一条按正常路径的分量画出来的失败路径,是一份没人能扫读的操作手册。

Release

Green tests ship; a red deploy rolls back.
Release4 elements and 3 relationships. Green tests ship; a red deploy rolls back.SERVICELinteslintSERVICETestsvitestCLOUDDeployCloudflarePOLICYRoll backprevious build

4 elements and 3 relationships. Green tests ship; a red deploy rolls back.

  • Lane: CI
    • Lint (backend) — eslint
    • Tests (backend) — vitest
    • Deploy (cloud) — Cloudflare
  • Exception lane: Recovery
    • Roll back (security) — previous build
  • Lint → Tests
  • Tests → Deploy: green
  • Deploy → Roll back: health check failed
  • Phase Verify covers columns 0 to 1: Lint, Tests.
  • Phase Ship covers columns 2 to 2: Deploy, Roll back.
Key
  • Call
  • Asynchronous

a branch and both outcomes

一次检查,两个结果,而一个工作流的大部分就是这个形状。穿过 Checks 到 Merge 的那条重线是 mainPath,而从它岔出去的那条分支是虚线——但图例默认把虚线命名为 Asynchronous,所以这份 spec 把那个条目改了名,而不是任由图例和画面互相矛盾。从作者那儿回来的那条边带着 return 角色,那是唯一一个会改变线怎么画的角色:一个空心箭头,于是读者不必去追踪就看见这个回路闭合了。

A pull request

One gate, two ways out, and the way back in.
A pull request4 elements and 4 relationships. One gate, two ways out, and the way back in.CLIENTPR openedbranch pushedSERVICECheckslint and testsCLOUDMergesquashEXTERNALChanges requestedreview comment

4 elements and 4 relationships. One gate, two ways out, and the way back in.

  • Lane: Automation
    • PR opened (frontend) — branch pushed
    • Checks (backend) — lint and tests
    • Merge (cloud) — squash
  • Lane: Author
    • Changes requested (external) — review comment
  • PR opened → Checks
  • Checks → Merge: all green
  • Checks → Changes requested: a check failed
  • Changes requested → Checks: pushed a fix
  • Group Merge gate covers columns 1 to 2 in lane Automation: Checks, Merge.
Key
  • Call
  • Failed check

three structures on one grid

泳道回答「谁」,页眉线上的阶段说明回答「什么时候」,而分组框回答「范围里有什么」——一张栅格上的三种结构,因为一份操作手册会被三种不同的人为着这三个问题去读。那个框是虚线的,因为这一组带着 security 变体,而那是这张图上唯一一个读者不用追箭头就能核查的断言。那份回执离开主路径、画成虚线而不是实线,而这正是「一封可能会晚到的邮件」和「一批不能晚到的货」之间的全部差别。

Order fulfilment

Three teams, three stages, one hop nobody waits for.
Order fulfilment5 elements and 4 relationships. Three teams, three stages, one hop nobody waits for.CLIENTCheckoutwebQUEUEReceipt emailqueuedSERVICEPick and packwarehousePCIAuthorisecard networkSERVICECapturesettled

5 elements and 4 relationships. Three teams, three stages, one hop nobody waits for.

  • Lane: Storefront
    • Checkout (frontend) — web
    • Receipt email (messagebus) — queued
  • Lane: Fulfilment
    • Pick and pack (backend) — warehouse
  • Lane: Finance
    • Authorise (security) — card network
    • Capture (backend) — settled
  • Checkout → Authorise: card token
  • Authorise → Capture: approved
  • Capture → Pick and pack: paid
  • Capture → Receipt email: confirmation
  • Phase Take covers columns 0 to 0: Checkout.
  • Phase Settle covers columns 1 to 2: Receipt email, Authorise, Capture.
  • Phase Ship covers columns 3 to 3: Pick and pack.
  • Group PCI scope covers columns 1 to 2 in lane Finance: Authorise, Capture.
Key
  • Call
  • Asynchronous
PCI scope
  • Only the two boxes inside the dashed frame see a card number.
Off the path
  • The receipt is queued, so a slow mailer cannot hold up a shipment.

what a role draws

同一次部署上的四种边角色,每一种都配上了绘制它的那个 variant。role 说的是一条线的含义,而渲染器只读它其中一个取值——return,为了那个空心箭头——所以 branch、async 和 error 单靠自己不会改变描边的任何东西。一条留在默认 variant 上的 error 边,会按正常路径的分量和实心程度画出来,而那恰恰是一份操作手册绝不能做的事。泳道的尺寸也是照它装的东西定的,所以一条空泳道不会充当间隔——它会塌成挨着栏沟的大约一列宽,名字还在上面。

Canary deploy

One path forward, three ways off it.
Canary deploy5 elements and 5 relationships. One path forward, three ways off it.SERVICEBuildcontainer imageCLOUDCanary5% of trafficCLOUDFull rolloutall regionsQUEUEAnnounce#deploysPOLICYPage the on-callPagerDuty

5 elements and 5 relationships. One path forward, three ways off it.

  • Lane: Pipeline
    • Build (backend) — container image
    • Canary (cloud) — 5% of traffic
    • Full rollout (cloud) — all regions
  • Lane: Out of band
    • Announce (messagebus) — #deploys
  • Exception lane: On call
    • Page the on-call (security) — PagerDuty
  • Build → Canary
  • Canary → Full rollout: healthy for 10m
  • Canary → Announce: posts the diff
  • Canary → Page the on-call: errors above 2%
  • Page the on-call → Build: previous image restored
Key
  • Call
  • Asynchronous

无障碍

  • 和每张图一样的约定:一张有名字的图,节点和关系以文字发布在旁边。
  • 异常泳道是这套系统的图里唯一带底色的带子,而且它仍然有标签——底色不是单独在承载意思。