返回博客

「已授权」背后的谎言:误导性完成态 Flag 让排查多走三条弯路

某次接到运营反馈:「后台显示某用户已完成企微授权,但小程序里看不到他的联系二维码。」

运营的推断链非常自然——「已授权」→「数据应该有」→「一定是小程序渲染出了问题」。于是我们并行开了三条排查链:小程序渲染层、后台数据展示、企微 API 同步。最后发现根子是 Presenter 层的脱敏逻辑,与这三条都没关系。排查多走了约半小时。

现象

后台管理表格有一列「企微授权」,展示逻辑如下:

// 数据库字段
$user->oauth_done = $hasMobile || $hasAvatar ? 1 : 0;
// 前端表格列
if (row.oauth_done) { '已授权' } else { '未授权' }

某用户 oauth_done = 1,表格显示「已授权」。但他的联系二维码字段 contact_way_qr_code 实际上为空,小程序自然拿不到二维码。

根因

企微的完整授权链路分三步:

  1. OAuth 回调 — 拿到 mobile / avatar(基础资料)
  2. follow_user 配置 — 企微后台开启「客户联系」
  3. contact_way 生成 — 调 API 生成带参二维码,写入 contact_way_qr_code

oauth_done 只校验了第 1 步。字段名用了 done,却只代表「有头像或有手机号」,跟「整条链路可用」差了两步。

坑:字段名 done / complete 暗示「全部完成」,但实现只覆盖第一步

oauth_done 的命名隐含语义是「OAuth 已完成」,运营和工程师看到这个词,脑子里自动补全的是「整个授权功能可用」。

当功能不可用时,他们第一反应不是「这个 flag 是否准确」,而是「flag 说 OK,那一定是别处坏了」——把排查方向完全引偏。

误导性越强的 flag 名,越能在 bug 现场制造「信任税」,让人把时间浪费在验证那些其实没问题的环节。

正解

按字段的实际语义拆成多个精确布尔列,让「完整可用」成为它们的 AND 组合:

ALTER TABLE wecom_user
  ADD COLUMN has_basic_profile  TINYINT DEFAULT 0,  -- mobile/avatar 任一非空
  ADD COLUMN has_followed       TINYINT DEFAULT 0,  -- follow_user 配置完成
  ADD COLUMN has_contact_qr     TINYINT DEFAULT 0;  -- contact_way_qr_code 非空

前端 derive 真正的「完全就绪」状态:

function isFullyReady(row) {
  return row.has_basic_profile && row.has_followed && row.has_contact_qr
}

后台表格可以进一步细化展示,把三列独立显示,运营一眼看出卡在哪一步。

| 旧命名 | 准确命名 | |-------|--------| | oauth_done | has_basic_profile | | auth_status | oauth_callback_received | | is_complete | has_contact_qr(具体到步骤)|

正解:字段名描述「有什么」,不描述「做没做完」

has_basic_profilehas_contact_qr 这类名字,第一眼就传达了精确的覆盖范围——它不说「授权完了」,只说「这个具体东西有没有」。

运营看到 has_basic_profile = 1 但功能不可用,第一反应自然是「那二维码生成步骤走了吗?」——直接命中正确链路。

识别误导性 Flag 的三个问题

在给多步骤业务流(OAuth / 入驻 / 上架 / 实名)的「完成态」字段命名前,先问自己:

  1. 这个 flag = true 时,哪些子步骤可能仍未完成?
  2. 运营/PM 看到这个名字,会假设哪些功能已经可用?
  3. 功能不可用时,他们的第一排查方向是否因此走偏?

三个问题里只要有一个答案让你不舒服,就换名字或拆字段。

一句话外卖

xxx_done 命名是一张空头支票——它承诺了功能可用,但实现可能只兑现了第一步;把字段名锚定到具体的「有什么」,而不是抽象的「做完了」。