节点四:架构规划之如何划分任务边界?

架构系列课专栏目录总览

上节课我们讲了任务边界划分的五个核心信条,可以作为任务划分与调整时的策略依据。那么实际工作中应该怎么运用呢?这节课我们就来聊聊这个问题。

任务梳理和粒度控制

我们上节课提到的实体和用例的过程,其实就是建模中常用的用例梳理的过程。一般来说,产品同事会有相对完整的梳理。那么我们作为架构师,在用例梳理的过程中能创造什么价值呢?

有些架构师很少关心从用例到任务的分解过程,认为这就是产品和相关技术人员的事情。事实上,这是你这个架构师为企业注入思考的核心切入点:从技术角度来理解这些用例对现有或未来架构设计的影响,然后再在任务定义上体现出你的思考。

比如在梳理实物商品时,你可能会问起平台上有哪些库存类型,这些类型的库存,跟商家仓库中的库存分别是怎么关联的。这样你才能确认系统与商家的集成边界在哪里,然后再决定是复用现有的能力还是重新开发新的能力。如果复用,那么你的任务分配上其实就有一个约束条件,即:这个任务必须分配给当前实现库存功能的团队。

再举一个任务分割的例子。如果商品风控在你所在的行业是个非常重要的操作,迟早需要投入。那么现在就要把这个任务独立出来。哪怕最初的风控需求人日再少,也不能打包到商品相关的需求中去。因为风控和商品管理的技术底层与人次能力需求完全不同,只有把任务分开,未来才能通过康威定律的效应产生领域分支和技术专业性。

技术架构分支的判断条件还有很多。你应该关心的,除了刚才提到的需求相似度、行业特性、技术底层依赖和人才能力外,还要关心用户体验的差异、规模差异,以及行业竞争的激励角度。这些维度都会影响到当下和未来的技术走向,以及需求变化的趋势。同时,这些维度也决定了技术分支是否必要。

你可能会问,为什么要做分支判断呢?我们不看细节的时候,几乎所有的实体都差不多。而一旦分解到最小的需求单元的时候,两个需求就不一样了。

就好像你抽象人类的生活需求,不外乎“衣食住行”四个字,似乎全世界人都一样。然而当你从中国人、美国人、印尼人和埃及人里,随便拉出两个人,恐怕他们在这四个方面没有任何类似的地方。哪怕只是从所有中国人里随机挑选出两个,那么从细处看,差异肯定也不小。

这时候一个好问题就来了:既然宏观层面都类似,微观层面都不同,那么正确的分解粒度应该是什么呢?

我认为这件事情不应该由你说了算。具体的用户需求和任务的分解粒度,是由市场说了算的。在法则五里我们就提到过,互联网时代赢家通吃。我们做技术是为了服务用户,那么给用户提供的服务的精细程度、服务质量、迭代速度,都必须保证能赢得竞争才行。

这也意味着架构师的取舍不是一个艺术,而是一个基于商业和技术环境的理性的思考决策。

边界划分和任务分配

大多数时候,你都不是从零开始做一个新系统,所以产品用例往往已经有了现成的从需求到执行方的映射关系。但这也不妨碍你从用户视角出发,从全局去思考最优的、从需求到任务再到执行者的映射。无论是已有的映射关系,还是尚未确定承接方的新需求。

那么怎么做分配调整呢?我在这节课的末尾,附加了一个关于任务分配的讨论。你可以作为参考资料来学习。其中有两个比较重要的结论,如下:

在独立性假设之下,任务分配是个局部优化的过程,所以不需要在全局上做优化。

在独立性假设之下,真正导致失败的正是你的最软肋,也就是架构活动中成功概率最低的强依赖。这是架构师最重要的关注点,而不是大家都在注意的光环点。

还是来举例吧。大促的交易营销链路就是一个光环点,但是往往大促出问题的地方不是交易营销链路,而是类似获取物流费用这样一个下单页面的强依赖。作为架构师,如果此时能用附件里描述的理性思考的方法,来正确摆放你的注意力,那就显示出作为架构师的真正的功夫了。

那么什么东西会影响单个任务的成功率呢?这个任务的目标设定、设计方案、用人、研发测试资源、运维环境,这些影响整个架构活动的因素。不过这些因素,在一个更小的任务尺度下同样生效。此外,上节课开头提到的四种任务分配的棘手情形,也会影响任务的成功率。

准确计算这个概率很难。不过我分享给你一个小技巧。如果有多个理性的人,同时对一个随机事件做期望值预估的话,那么参与预估的人越多,他们给出的中位值就越接近实际值。这里仅仅要求参与者是理性决策,而不要求必须是相关项目的负责人这样的角色。其实这个有点儿像我们做 Scrum 估算人日。 这个过程你和参与者需要花费的时间是以分钟计算的, 是顺便完成的。 而不是需要你花一个小时开会讨论来估算每个任务的成功率。

总体而言,我个人不太主张在任务梳理、粒度控制和任务分配环节里,有太多的脑暴和发散。因为此时此刻,我们已经进入到执行环节了,那么就要尽量减少分散注意力的动作,尽快作出决策。

锁定项目必保需求的交付资源

一旦任务边界确认,那么就必须迅速锁定所有必保需求相关的资源。除了研发人员外,还包括业务、产品、研发、流量入口、发布窗口,甚至营销资金池。

不过最难锁定的往往还是研发人员。互联网企业中,每个研发人员都是多个必保项目在身。不是一个团队主管说锁定就锁定了。

那么怎么办呢?我的建议是,一旦确认了项目的可行性,请立即把大家聚在一起去做技术规划。当然,在这个过程中,我也会做一些动员工作,告诉大家项目中都有哪些机会。其实就是我们常讲的“画大饼”。你可能觉得这么做没什么用,因为人人都在画大饼。

而我想强调的是,人人都在画大饼, 你却连个小饼都画不出来,那就别想混了。不信的话,可以去翻翻我们第一节课评论区中的留言。针对我留下的第一道思考题,也就是“最让兴奋的目标是什么”。几乎回答者都有自己的选择,但没有一个人说“老板让我做啥我都兴奋”!那是还没上过磨的小驴犊子,而不是优秀的研发人员。

如果你的架构活动中有隐含的技术需求,比如在做项目的同时还需要完成代码重构。这个时候,就需要有个技术 PMO 的角色来帮你协调和验收了。我并不建议架构师来兼任这个角色,除非你的项目是十几个人的小项目,否则你的关注度不足以同时保障重构质量和交付时效。

另外,在这个环节你还可能会遇到这么一个棘手的问题。某个需求承接者有很强的意愿,不过你判断他可能没有能力来承接这个需求。在这种情况下,我建议你先冷静一下。首先要敢于质疑自己的判断,因为你很可能是在项目压力和交付风险的忧心下做出的判断,忽略了一个人成长的潜力。我的个人经验是,项目的成功概率跟参与者的意愿度和投入度的关系更大一些,跟这个人的能力关系略小一些。

完成边界划分

如果你对所有的必保需求、任务承接和资源锁定都全部完成了,那么任务的边界划分工作就初步完成了。不过你还需要从实施细节上再对架构规划进行确认。这个我们下节课会讲。

需要注意的是,在实际执行的过程中,你往往会漏算,也会碰到突发事件,比如需求方会更改他们的需求。那么在这个过程中,你还需要不断迭代任务分解,尽量把用例从粗到细做成多层分解。

一来,你会及早发现更多细节和不自洽的部分;二来,你跟锁定的核心研发人员也能较快地建立信任,让他们尽早参与到需求确认中来, 从而在减少风险的同时增加项目的成功概率。

小结

我们这两节课讲了边界划分的过程。在做任务边界划分之前,你必须和决策者、参与方在信条上达成一致。否则,在一个充满冲突的环境中,如果没有任何信条的指引,可以说就是堕入了万劫不复的深渊。所以这些信条就是我们架构师的护身铠甲。

想想看,无论是资源冲突还是个人冲突,如果没有任何铠甲护体,单靠肉身给天神劝架。你是想找死呢,还是想找死呢?

这个过程的王道,是你以最大化项目的成功概率为基础,做出决策,并引导大家达成共识。虽然在极端情况下,你可以邀请决策者来强压,但这是霸道的行为。作为架构师, 你更需要做的是用一个相对客观的思考方式来做决策。

比如我们这节课附件里提出的建议,可以对强依赖和备份任务作区分,并对成功概率进行估算,从而将所有参与者引导到一个基于规则的决策环境中来。

在这个过程中,你不仅需要保持开放和包容的心态,同时也要引导参与者保持开放和包容的心态。这样你才能让大家都从全局视角出发,做出全局最优的决策。到时候会,所有人都会为一个更高的成功概率而兴奋的!而你要做的,就是找到实现目标的真实路径,并跟大家一起看清楚这个路径。

思考题

三道题目,任选一个作答。

在你参与的项目中,有没有边界划分不合理的?你在划分之初是如何判断边界不够合理呢?为什么你会做出这个判断?这个思考你有告诉过其他人吗?最终的结果呢?

我们在附件中讲了最弱的链接这个概念。意思是说,架构活动成功率的天花板,就是成功概率最低的那个强依赖。而这也应该是我们架构师的思考关注点。你经历过的最难忘的最弱链是什么?

我们在这节课还强调了一个非常重要的理念,就是“架构不是艺术”,而是一个基于商业和技术环境理性的思考决策。你有没有被架构艺术家蒙骗了的情况?或者反过来,你有没有见到过一个能带来竞争优势的技术架构?

附件:任务边界划分过程中承接分配

架构师在边界划分的过程中需要做什么事情呢?接下来,我们会讨论一些关于任务分配的基础假设,以及由这些基础假设而带来的决策路径。

所谓任务边界划分,就是判定某个任务在多个承接方中,应该归属到哪个承接方的过程。这个任务可能对应着一个或多个需求、实体和操作。一般来说,一个项目有多种不同的任务划分策略。那么在这多个策略中,我们需要有个决策逻辑来确定自己的选择。这个决策逻辑就是我们上节课提到的信条。

这里我们假设每个任务都是独立的。一旦开始,单个任务执行成功的概率将不受其他任务的影响。当然,它也不会影响其他任务的执行。

任务与任务之间的关系分为两种基本类型,一种是强依赖关系,另一种是备份关系。

任务 a 强依赖于任务 b,如果 b 失败,那么 a 失败。这种关系我们可以表示为 a>b。这种关系是传递的,即:a>b&b>c=>a>c。这种关系也是自反的,它们不是对称的。

任务 a 的备份任务是 b,如果 b 成功,那么 a 成功。这种关系我们可以表示为 b->a。 这种关系是传递的,即:a->b&b->c=> a->c。这种关系也是自反的,它们不是对称的。

如果两个任务互为备份,那么 b->a 且 a->b。这种关系可以表示为 b=a,证明这种关系是自反、传递和对称的。

我们之前找到了最小必要,也就是架构活动所强依赖的任务集。只有完成了这部分任务,我们架构活动才能成功。而我们之前提到的预案,其实就是一个任务的备份。当某个任务没办法完成的时候,我们就需要实现这个任务的某个预案。那么从完成架构活动的视角来看,这个任务也相当于完成了。

如果用图来表示,这三种关系可以表示如下:

节点四:架构规划之如何划分任务边界?

在这张图中,一个架构活动强依赖于任务 a,任务 a 则强依赖于互为备份的任务 b 和任务 c。而任务 b 和 c 中,只要有一个完成即可。同时,任务 a 强依赖于任务 d,而任务 d 则有一个备份 e。这种关系可能有多层,如下图所示:

节点四:架构规划之如何划分任务边界?

当我们完成整个架构活动的最小化之后,这些节点应该都是整个架构活动的强依赖,或者是这些强依赖的备份。也就是说,图中的右侧部分其实是一棵依赖树。

在图中的右侧部分,我们把备份关系表达成一个单个节点,其中互为备份的多个节点用 {a,b,c… }来表示,而 a、b 两个节点间的备份关系则用 <a,b> 来表示。当然这种关系还可以递归地分解下去,甚至一个备份任务就可能分解成一棵依赖树。不过这种递归关系并不影响我们接下来的分析。

其中有部分任务在这棵依赖树中多次出现。它们既可以是强依赖,也可以是个备份。但是同样也不影响我们接下来的分析。

如果某个有备份节点的任务,两个任务是互为备份,那么这个节点上的任务都是等价的,可以当成单个节点来对待。如果它们不是互为备份的,比如 a->b,那么 a 节点和 b 节点各自的依赖树就不相同。这会影响到任务优化中的剪枝决策,但是不影响我们的分析结论。

也就是说,一个强依赖关系的形成,从叶子节点到根节点是一个串性关系。而一个有备份的节点,则在节点内部形成了并行关系。依赖关系与并、串行执行顺序,跟现实中的研发任务非常接近的。不过我们这里的串行和并行关系中并没有时序的概念,只是一个依赖的概念。

对于一个架构活动中的任意一个任务 t0,如果这个任务失败,则整个架构活动失败,那么这个任务就是整个架构活动的强依赖任务。这个定义用公式表达出来就是:

P(T) = P(t0)*P(T–t0)

这里的 T 是整个架构活动的所有任务。T–t0 是除掉 t0 之外的所有任务。P (T) 是整个架构活动的成功概率,P(t0) 是任务 t0 的成功概率。

对于架构活动中的任意一个任务 t1,如果这个任务失败,不一定导致整个架构活动的失败。而是包含 t1 一组任务的 T1 全部失败,才会导致整个架构活动失败,那么这个任务 t1 就是整个架构活动的一个备份任务。这个定义用公式表达出来就是:

P(T) = P(T1)*P(T–T1)

where P(T1)= max {P(t)}∨t∈T1

比如上图中,任务 b 和任务 c 就是整个架构的备份任务。它们共同形成的节点的成功概率为:

P({b,c})= max {P(b), P©}

也就是说,对于一组互为备份的任务{a, b, c,…}或者是 <a,b,c>,它们整体的成功概率是任务集里成功概率最大的任务。

所以在任务分配这件事情上,我们认为成功概率和任务的执行者有关。也就是说,P() 是任务和执行者的函数。

有了这两个概念,我们抽象出任务分配的决策场景就比较容易了。如下图所示:

节点四:架构规划之如何划分任务边界?

对于整个架构活动而言,任务 a 和任务 b 都是整个架构活动的强依赖。任何一个任务失败,都会导致整个架构活动失败,那么这两个任务就可以表示为图中的串行关系。而任务 c 和任务 d,如果都属于同一组互为备份的任务,那么这一组任务可以表示为图中的并行关系。

根据前面的定义,整个架构活动的成功概率 P(T), 那么:

P(T)=P(a)P(b) P(T1)P(e) P(T2)

针对第一种情形,如果我们要在两个强依赖之间做任务划分的调整,那么我们的划分策略对于整个架构活动的影响,就可以表示为:

Ps(T)=P(a>g1)P(b>g2) P(T-a-b)

在这个公式里,p(a>g1) 其实就是将任务 a 分配给 g1 小组之后,任务完成的成功率。公式表示,我们把任务 a 分给 g1 团队,任务 b 分给 g2 团队,对于整个架构活动成功概率的影响是连乘的关系。如果交换这个分配关系,也就是把 a 分给 g2 团队,把任务 b 分给 g1 团队,那么:

Ps’(T) = P(a>g2) P(b>g1)*P(T– a-b)

在上述两个公式中,最后一项完全相同。也就是说,在我们局部优化两个强依赖之间的边界划分策略的时候,可以不考虑其他任务是怎么划分的。只要我们发现 Ps 小于 Ps’,那么就可以用第二种划分策略了。

同样,在上图中任务 c 和任务 d 的分配策略中:

Pw(T) = max{p(c> g3), p(d>g4), p(t) } *P(T – T1)

Pw’(T) = max{p(c> g4), p(d>g3), p(t) } *P(T – T1)

在这个公式中,t 是 T1 任务集合里除去 c、d 的其他备份任务。对于两个备份任务 c、d,仅仅当它们的边界划分使得一个备份方案在 T1 里面对比所有划分方案下都是最可靠的方案时。也就是 max 函数求极值时胜出,那么这种划分策略才应该被采用。

在上图任务 e 和任务 f 的分配策略中:

Pm(T)= p(e> g5),max{p(f> g6), p(t)} *P(T – T2-e)

Pm’(T)= p(e> g6),max{p(f> g5), p(t)} *P(T – T2-e)

t 是 T2 集合中除去任务 f 的其他备份任务。对于一个强依赖和一个备份任务之间的边界划分,如果 Pm’胜出,那么就可以使用第二种划分策略了。同样,在这种情况下,我们可以不考虑全局任务的边界划分,仅仅在局部做优化。

到这里,我们简单总结一下。我们列举了在两个任务之间做边界划分调整的情况,当然,我们也可以对多个任务边界同时做调整。公式表达略微复杂,但这是一个局部优化的过程,不需要在全局上同时做优化。

这个非常不错的公式表达的性质,让我们能够在小范围做边界优化,而不是每做一个小的边界调整,就要重新思考整个架构活动的交付风险。当然这个性质,是基于我们前面的假设,就是团队之间可以独立并行工作,一个任务的执行不干扰其他任务。

我这种假设在互联网时代基本上是成立的,尤其适用于微服务架构的互联网公司。因此在实践中,我们估算出整个系统成功概率的上线,是非常容易的。也就是在忽略限制条件下,每个任务都能以最优方案做分配,并达到 p(T) 的极值。

需要注意的是,如果我们试图最大化的,是人才成长而不是项目的成功率。那么在估算这些公式里的概率时,就需要把任务完成的成功率,替换成该任务带来的人才成长。不过其他的推导逻辑依然有效。

企业中的技术项目经常把人才成长作为目标,尤其是在大项目中的备份任务。那么我们的确可以使用这个优化目标。我之前在稳定性建设上就经常使用这种策略。

此外,这些公式的分析过程其实也给了我们另一个启发:整个架构活动成功率的天花板,是成功概率最低的那个任务的强依赖,也就是最弱的链接。这应该是你这个架构师的思考关注点。不过实际情况是,在一个大的架构活动中,所有人的眼睛经常都是盯着那个光环点。这个时候真正导致架构活动失败的,往往是那些软肋。

准确计算这些公式里的概率很难,因为我们是在预测一群人去交付一项他们之前没有执行过的任务的成功概率。事实上,我写这些公式的目的,也不是让你去准确预估这个成功率。而是通过这组公式,让你以理性的方式来思考决策路径。我们不能依靠“酒品见人品,我认为这个兄弟最靠谱”来做决策。

免责声明:
1.本站所有内容由本站原创、网络转载、消息撰写、网友投稿等几部分组成。
2.本站原创文字内容若未经特别声明,则遵循协议CC3.0共享协议,转载请务必注明原文链接。
3.本站部分来源于网络转载的文章信息是出于传递更多信息之目的,不意味着赞同其观点。
4.本站所有源码与软件均为原作者提供,仅供学习和研究使用。
5.如您对本网站的相关版权有任何异议,或者认为侵犯了您的合法权益,请及时通知我们处理。
火焰兔 » 节点四:架构规划之如何划分任务边界?