顾问、老师及教练

由于工作的原因,这些年接触了很多的公司和团队,大家对我的称呼也各不相同。有叫肖顾问的,有叫肖教练的,还有叫肖老师的。最近一直合作的一个企业举办了规模不小的教练大会,引起了我的一些反思,于是想撰文跟大家分享一下在教练、顾问和老师这三个头衔上的认知,不一定正确,权且写出来跟大家切磋。也希望能唤起正处于数字化转型时代企业对自身教练力量建设的关注。

解决问题的顾问

实际上我的工作多是顾问,邀请我的企业或团队一般都希望我能够带领他们解决某些“问题”。为什么问题要用引号呢?原因是很多企业和团队初始描述的要求其实不是问题,比如“我们没有单元测试,帮我们搞TDD吧”。作为顾问,我要做的第一步是发现真正的问题,当然这个过程中有很多技巧,并不是本文的重点,按下不表。

作为顾问的一个基本要求是很了解自己的行业,并且有不少的相关经验,比如企业请我去一般都是做软件产业相关的工作,决然不会请我去做投资管理顾问(显然我自己也错过了比特币)。原则上顾问工作是给出客户面临的客观问题和挑战(也包含组织及团队的赋能问题)的解决方案。

从纯粹意义上讲如果已经给出了详细可落地的解决方案,顾问的工作就完成了。可能由于我个人资历尚浅,解决方案即使得到认可也还是被要求必须负责落地执行(至少一个试点团队是必须的)。我也见过不少银发顾问给了一个PPT就能够赢得客户最终认可的。当然在软件行业可能这样的情况会越来越少。

所以顾问这个头衔在我的认知里就是一位能够帮助企业和团队发现自身问题根源,并设计解决方案的人。

推动改进的教练

为什么不少项目上也有人叫我肖教练呢?想想大抵是因为不仅仅给出了一个自认为合理的解决方案,并且需要带着核心人员实施。为了能够落地解决方案,一般我会要求客户团队成立教练组,和我一起来承担改进任务的执行和反馈调整。这个时候大家自然也开始叫我教练。

教练这个头衔比较有意思,一般客户方负责人都会问我咋选教练,经过这两年的揣摩,我个人比较认可两点:第一、主动交流沟通好的;第二、自我驱动推动能力强的。注意这里我并没有要求专业能力,比如需求管理改进并不一定是一位资深的BA来作为教练。

为什么这样要求呢?因为改进工作无疑是破旧立新的一个过程,无论是烟斗曲线还是U型理论实际都告诉我们这是一个先抑后扬的过程。即使咨询顾问给出的解决方案是百分百正确的,也可能因为下挫的过程中无人扶正而被团队所放弃。

(图:著名的改变烟斗曲线,每个改变都要经历一定时期的痛苦Frustration和挣扎Depression。而这个下挫的过程是最需要关注和扶正的。)

一些组织确实能够通过行政手段保证下挫的过程中也可以“削足适履”的落地,但确实极其少见,也不建议效仿。大多数组织都需要一帮专注改进方向、持续鼓励团队的教练。而且很多时候这些教练还需要专职专用,把推动团队改进、扫除改进障碍做为自己的工作目标。

有人会说“程序员激励师”就是教练了!如果你的改进目标是让几个开发人员自信心爆棚,多写两三个功能,确实也可以算。但改进工作其实是很严肃的,事关一个组织未来的存活,目标也是全组织共享的,涉及整个组织各个角色和部门。这个时候不是简单让几个员工“high”两天就能转型的。所以教练也是一个长期工作,需要卷起袖子和团队一起实干落地。

那如果没有相关的专业能力,怎么能够落地呢?不少同事和客户都知道我也经常调侃高谈类似打坐参禅的业内“教练”为“走心流”。原因当然不是我想用“你会写Scala吗?”这样的问题去怼人,而是教练的核心工作是去务实的影响一个正在改进道路上下挫的团队,让他们坚定信心和方向。在这点上不是教练个人的修为重要,而是如何影响团队重要。如果参禅打坐能够感染团队,提升士气,实际上也无妨。但咱们这个行业毕竟有很强的工程学基因,恐难完全从悟道的角度去解决问题。

然而这并不是说教练一定要是某个改进领域的技术专家,而应当是一个引导者:这个引导者能够帮助团队建立改进的共识,持续反思改进过程中的问题;同时又是一个催化者:像催化剂一样让团队能力得到放大。催化剂这个说法《人件》中早有论述,我认为应该是一个教练的终极目标!

比尔盖茨在自己的TED演讲上说“所有人都需要教练”,论述了包括老师在内的每个人都需要一面会说话的镜子,才能够持续提升。良好的教练可以根据团队或个体希望改善的具体领域提供可行的见解和发展机会。这个改进的过程中目标必须清楚,成功标准必须明确。 但不管是改进目标还是成功标准,都不是教练制定的,而是改进团队或个体在教练的引导下完成的。

传授技艺的老师

老师也许是我最早的一个工作头衔,大学勤工俭学的时候,助教是我最喜欢的一份工作,每次上完一堂辅导课总是感觉一天十分充实。然而经常的困扰是学生们提交上来的作业五花八门,看得哭笑不得的也不在少数。

从那个时候到现在我都还是比较相信“没有不愿学习的学生,只有不会授课的老师”。当然老师并非是越资深就越会授课,比如我敬爱的博导一辈子都不喜欢授课,反而每年给了我很多机会去体会怎样做一个好老师。一个好的老师能够把一个知识点用不同的形式演绎给学生,让整个课堂的氛围变得活跃,有时候甚至是学生们自己在推着课程一步步深入。

对于我的导师来说讲课是痛苦的,因为总是要求他年复一年重复类似傅里叶变化这样的公式,但对于好的老师来说,每年可能都会有新的角度来讲授看似死板的公式。某种意义上这是对技术知识点认知的一种深入,把认知本身做为了一种匠艺来追求。正是在这方面的兴趣,促成了教学上的热情,把认知的传递作为了工作的回报。当然这样的人其实并不多,也是非常难坚持的,如《中国合伙人》中的主角成东青把终身热情奉献给讲台的老师是值得尊敬的。

不同的胜任力要求

回想自己的工作,其实即使在一个项目上也可能随时切换角色,比如调研分析时我是一名顾问,试点项目上我是一个教练,规模推广时我成了一名老师。但既然分析,就希望能够看看这三个角色有啥不同。我首先想到的是各个角色在胜任力方面可能要求不同。

尝试着列举出了一系列胜任力,发现其实重叠的不少,附件中也有一个小调研(金数据表),很想听听大家的意见。为了找到不同,迫使自己用单一指标的方法来“区分”到底这三个头衔有什么不同,于是产生了下面针对每个角色我认为最重要的胜任力。(记住单一意味着我只给自己一个选项,类似“交流沟通”这样的共性能力都只能被“无情”地去除了。)

选择胜任力时我采用了Workitect公布出来的通用的胜任力字典。我的选择如下:

  • 顾问:概念思维(Conceptual Thinking)—— 从一个整体视角,一定抽象层面或理论高度来寻找有效的解决方案。
  • 教练:赋能他人(Empowering Others)—— 表达对团队取得成功能力的信心,特别是在挑战新的任务方面。 委托重大责任和权力,让团队自主决定如何实现目标并解决问题。
  • 老师:技术专业(Technical Expertise)—— 在技术领域的知识和技能的深度。

欢迎大家通过链接的表格给出自己的选择!

(调查表二维码,欢迎告诉我们你的选择!)

从某种意义上讲,顾问是问题解决者,老师是知识的传授者,而教练则是改进的引导者。解决问题需要从整体出发,能够通过概念思维进行一定的抽象来找到有效解决方案。传授知识则需要对知识技术有系统理解,才能深入浅出地诠释一个专业方法。改进引导如前文所述更多是赋能被改进的团队,让团队建立起追求成功的信心。

按照这样的胜任力分析,我们可以进一步找到三个角色在工作模式和成功标准上的不同。

不同的工作模式

《精益企业》作者之一Barry在最近的一篇博文中指出了教练的重要性,他从客户(聘用方)和服务提供者(受聘方)在工作过程中的信息输入对比了这三个角色。我们在这里借用他的分析产生了下面的图示模型。

(图:角色的工作模式)

教练被放到了最左边,在教练的工作模式下,客户(团队)的输入占比是很大的。顾问被放到了最右边,在顾问的工作模式下,服务提供者(咨询顾问)的输入是绝大部分。这显然是成立的,在改进的上下文里,解决方案是由顾问独立设计和提出的,而具体的目标和标准则是团队共同决定的。

从信息输入角度我们可以看到这三个角色工作模式的差异。教练需要更多的团队交流沟通,启发大家产生更多的想法。顾问需要深入的自我洞察,从系统的信息收集中找到解决方案。而老师则需要持续的双向沟通,掌握学员们的学习状况,并作出相应的调整。

实际工作过程中,我们会看到好的顾问总是在侧面观察和系统分析,好的教练则奋斗在团队的一线,在实际工作中给团队提供反馈和启发,而好的老师能够让自己的授课充满互动,以检查学生们的认知。

不同的成功标准

按照咱们这里的定义,这三个角色的工作产出是比较明确的。但实际工作中往往很少有人能够真正思考清楚请的是老师还是顾问,所以出现文章开头我的三个称呼。就时下大家最关注的数字化转型这个话题来看,显然这三个角色都是缺一不可的。

企业在进行数字化转型的时候首先需要明确市场的趋势和技术的进展,这个时候聘请外部顾问来拓展认知,明确初步的转型路径是必要的。当转型的决策者们建立了一定信心后,老师和教练这两个角色就成为了推动改进工作的关键。转型实施过程中需要老师来给与正确的工作方法,需要教练持续深入的鼓励和反馈。

从上面的简单描述不难找到各个角色的成功标准:

  • 对于顾问来说,提供业界的洞察,找到适合于企业的转型方案是工作的目标。顾问工作的成功意味着帮助企业找到了从上至下共识的转型路径。(注意这个路径只是一个起点,而不是终点。所以这个阶段共识重于正确。)
  • 对于老师来说,打开团队的脑洞,带领团队学习新的工作方法和实践是目标。老师工作的成功意味着团队看到了新工作方式会给他们带来的优势,愿意尝试自己去实践。
  • 对于教练来说,鼓励团队改进,并提供有效反馈,持续纠偏是重点。教练工作的成功意味着团队持续向着转型的目标前进,并建立了持续改进的意识。

说到这里,也想给很多正在焦虑于如何开展转型工作的企业一点建议:转型本身就是一项复杂工作,选择合作伙伴的过程中应该保持开放,理解这三个角色需要发挥的作用。没有一个人可以是所有方面的专家。

相同的专业历练

以上谈了我认为的三点教练、顾问和老师的不同,尝试区分这三个头衔。当然很多时候这些称呼都在被混用着,那么它们之间有什么相通之处呢?

这样的头衔同时也存在于其它行业和领域,我们会发现在一个领域里,教练不一定是最好的技工,比如NBA禅师杰克逊是一名伟大的教练,但之前并非是一名如科比一样的篮球巨星;而在各个运动专项上,比如力量、速度,又都有专门的老师。这两年也有不少顾问通过历史数据的分析来告知球队存在的问题及可能的改进方案。这样的场景其实也可以类比到咱们IT行业。

显然教练和老师都有很强的相关领域背景和经验,老师还需要在这个领域的某个具体方向上有比较独到的见解。就上面的例子仿佛顾问不需要多强的领域背景和经验,看数据分析就可以了。但我们知道能够从数据中看出门道的顾问十有八九都是同领域出身,就好像某项体育赛事的解说员都会邀请该领域某某著名运动员。即使央视体育频道的名嘴,至少也是球迷出身,自己私底下的学习和分析可谓数十载。

对比体育等成熟产业,软件和数字化领域显然拥有更大的不确定性,甚至没有一个顾问能够告诉你确定的产业发展方向。从这点出发不管是顾问、教练还是老师都必须重视持续的专业历练,脱离专业很快就会被淘汰。在数字化产业里还没有拉格朗日方程这样的公式,认知的刷新往往是一日千里的,作为老师我也经常告诉大家去年的实践只能是今年的奠基石了。

正是由于强调持续的专业历练,所以数字化产业里好的顾问、老师和教练都是一将难求的。如何在辅导过程中保持不“拖媒”是每一个从事上述工作人员的挑战。所以我经常还是建议刚刚起步从事教练工作的同仁们不要离开一线,在解决客观工程问题的过程中保持团队赋能和自身专业历练的平衡。时刻坦诚自己不是所有方面的专家,在动手的过程中持续学习和成长是教练自身修炼的必经之路。

最后也借此文呼吁大家提高对教练能力的重视。第四次工业革命才刚刚开始,这个过程中的不确定性意味着任何组织都需要做好持续改进的准备,而这个过程中能够持续赋能团队的教练队伍将是一个企业持续生存和发展的基础。未来两三年我们会在领先企业身上看到这方面的突出能力,而这样的能力建设不是短期花钱能够外购的。


更多精彩洞见,请关注微信公众号:思特沃克

Share

银行IT的敏捷转身

[摘要]

中国银行业的数字化转型才刚刚拉开帷幕,作为转型重点的银行IT部门正在经历从开发模式到组织定位的巨大变革。本文从时下银行IT广泛的敏捷转型开始分析,揭示了中国银行业面临的数字化挑战,分享了应对挑战的一些共识,同时给出了中国银行数字化转型的大方向。

数字化挑战

过去的3年时间里,我作为敏捷转型顾问,合作频次最多的,就是全国大大小小的银行。银行业IT这一波的敏捷转型,很多人会归因为互联网金融的冲击,认为银行业IT被迫从原来的内部职能部门走上前台,迎战外部市场的挑战。也有不少银行从业人员,对此持有不同看法:类似P2P这样的互联网业务,对中国的银行业还谈不上任何的冲击。在我看来,真正冲击中国银行业的,是以下两个方面:

  • 服务渠道的变迁——渠道从过去实体的网点向数字化渠道转移。注意,这并不是说所有的服务都变成了移动APP,而是所有的服务都会用某种数字化的形式呈现,比如现在到工行建行网点办卡都是通过一台综合服务机;交行几年前开始试点网点机器人,而招行已经在刷脸取款。由于银行之前是没有数字化部门的,所以这些要求自然跟IT挂上了钩。
  • FinTech的冲击——技术突破正在改变业务形态。最近火过了头的加密货币(比特币)正是这样的技术案例,它可能对未来银行业务产生颠覆性影响。在欧美很多利用智能技术做征信的平台也快速崛起,替代了传统费时费力的背景调查。对比之前的传统银行科技,FinTech拥有非常大的不确定性,这给习惯于购买成熟软件产品的银行带来了不小的挑战。当然由于又是科技相关,所以这口锅自然也得IT背了。

以上两点带来的变化显而易见,所以,无论提不提敏捷,银行IT都得转型。建立在支撑基础业务、保证业务稳定运行之上的IT部门,不可能自然而然演进成为“以用户为中心,思考服务体验,并保持对业界先进技术洞察”的新型数字化IT部门。下面就结合我过去3年中,近10家银行的顾问经历,谈谈这个转型中的挑战和可能的应对之策。

稳与快

我们辅导过一家外资银行,一上来就要求全球范围实施DevOps,“全面”敏捷。作为顾问,感觉很爽,改进起来气贯长虹。半年之后,已经没有不做敏捷改进的项目了,就连基于小型机AS/400的系统也都走上了DevOps的持续发布之路。

中国的银行业可就不是这样一个情况了。我和业内熟悉的几个人,经常开玩笑说“‘喝茶’就是悬在中国银行敏捷转型头上的‘达利摩斯之剑’”——高管们心里羡慕着互联网玩法的“小、快、灵”,脑子里却时刻担心着因生产事故被请去“喝茶”。转型需要经历烟斗曲线,当刚好处于曲线下挫点时,很可能因为一次事故而被全面叫停。一位银行科技高管曾经在内部会议上对我直言:“不要以为我不支持敏捷,正是因为我支持,所以才拉着你们跑慢一点”。

团队里有顾问找到我说不想做中国的银行了,太纠结,犹抱琵琶半遮面。于是我反问这位顾问,为什么中国的银行不能像外行一样一步到位呢?是因为太保守或者太官僚?一时问得对方语塞。其实,外行比起咱们可能更保守,生怕有一点负面消息,有的机构更庞大,更官僚。那么是什么原因,让我们中国的银行不敢“全面”敏捷呢?

就我目前认知,中国银行和外资银行有两点显著不同:一是中国银行集中精力办大事儿的构建方式;二是中国银行IT的历史定位。

如果我们对比中外银行的业务架构,会发现咱们的银行在业务设计上非常集中。这样的集中思路投射到IT系统建设上也是非常明显的:一般会考虑一套系统支持多条业务线。经典的例子是咱们的银行一般只有一套清算、核算平台,而外行每条业务线可能有自己的独立平台。集中建设的好处自然已经体现出来了,短时间我们就构建起来了一个相对完善的金融电子平台,但带来的问题就是系统非常复杂。

(图:中外行典型组织结构区别)

在敏捷转型过程中,有两个领域的复杂度是让我头疼的:电信和金融。大家可能想象不到,打通一次电话和完成一笔转账都要涉及近亿行代码!一条业务需求动辄要求修改十几个独立应用!咱们集中建设的银行系统显然不是随便就敢改的,早期即使在银行大型机系统上引入迭代开发都是很困难的。而这些系统往往又是银行的核心主干,任何小错误都可能造成致命的连锁反应。

在IT定位上,从国有五大行到各大股份制银行,基本都将IT归到了科技部下面统一管理。从组织结构上,可以看到IT的定位是一个共享的内部服务部门,或者说,是一个成本中心。最初的IT只是管理一些购买的商业软件和平台,并没有作为一个强自研能力的组织存在。银行IT的自有员工和外包人员比例,普遍都在1:6左右,一个主要的IT系统可能也就能投入两三个长期自有员工。到了现代,这个以科技为核心(Tech@Core)的时代,这样的人员配置显然已经捉襟见肘了。

以上两个因素,从技术架构和人员架构两个方面制约了敏捷的大规模推广。所以,银行想要“快”起来,往往不那么容易。各家银行的转型,都会选择相对新的技术领域,或和用户结合比较紧密的应用开始试点。而初期的转型目标,也会设定为“探索在现有约束条件下,如何进行敏捷模式落地”。最终,大多数银行都会走向“双模”:明确哪些系统和应用更看重业务表现的稳定性(采用瀑布模式),哪些更看重市场变化的响应速度(采用敏捷迭代模式)。

(图:源于Gartner总结的双模IT架构基本示意图)

理论上讲,“双模”只是一个过渡状态,这种方式也受到了不少专家的批评。“双模”可能会掩盖掉一些更深层次的问题,比如系统快不起来,根本原因其实是架构质量问题。从科技的发展趋势来看,确实止步于“双模”是不明智的,微服务化和平台化架构的逐步成熟会让以前稳定第一的系统也快起来。但就目前的约束来看,“双模”是已有成型建制银行IT的必经之路,其意义更多是在组织里植入管理不确定性的能力,从而构建对市场变化的快速响应能力。

效率与响应力

“唯快不破”是互联网服务发展的必备条件,而这个“快”其实是被很多管理者误解的。这个误解也造成了银行IT管理者们对“快”的提法有些许反感。这个误解的根源,在于对效率和响应力的混淆。

如果我们正确分析互联网成功服务的特质,就会发现他们根据市场变化推出和改变服务的速度特别快,而这个快很明确是在响应力上。举个日常生活中的例子,作为干洗店的客户,我们其实并不关心干洗店内部的效率问题(例如单位时间处理多少件衣服、干洗机的利用率等),我们关心的是干洗店能多好多快地把我们衣服洗好。

互联网时代给银行业带来的一个明显转变,就是从过去“以自身服务为中心”,到现在“以客户为中心”。从前在以自身服务为中心的时候,我们的管理方法及技术实践都是围绕效率来做的;到了这个时候,显然我们必须用客户的视角来思考问题,所以就需要更加关注响应力。当我们在追求效率的道路上走到一定程度,就有可能伤害响应力。比如为了干洗机的利用率,我们批量分类客户的同类型衣物放一个批次,显然这样的做法在订单达到一定数量的时候,会减缓每个客户的交货时间,让客户等待更久,伤害了对客户的响应力。

同理,这也是为什么在敏捷组织里,我们提倡少分角色、跨职能协作。当我们的分工过于细化时,对外部的变化响应能力就下降了。在传统银行IT系统里这样的情况是很普遍的,一个业务需求需要分解到十几个应用模块完成,而每个模块都只能由一个专人完成。

理解响应力的重要性并不难,但实践高响应力的管理却是相当困难的。银行业是一个重流程管理的行业,银行IT显然也继承了这样的基因。重流程标准化的管理方法,造成大家习惯性地进行自身局部效率的优化,实则增加了端到端的响应时间。我经常举一个发生在我们每天日常工作中的例子让大家意识到这个问题的严重性。

你是一位IT管理者,小王是一位认真负责的开发人员。一天他告诉你,现在项目A上他的工作进入尾声了,接下来只需要占用他一半的工作时间。这样的情况下,小王希望请示接下来的工作安排。在实际工作过程中,大家会赶快告诉小王启动项目B的工作,或者分配给他项目C的部分工作。假设小王启动了项目B的工作,很快他发现需要小李协助才能开展分析工作,而小李这个时候正在项目A上忙得不可开交。接下来有意思的事情就发生了,小王显然会要求小李配合,而这事儿如果真正发生了,显然就耽误了项目A的工期,那么项目A的完成时间就要推后了。小王和小李有可能找到你来请示工作优先级,然而,可怕地是,在你的意识里,会觉得这显然是“加加班”就能解决的问题!

于是,整个IT产业陷入了做不完的需求和越来越严重的内耗!

(图:小王工作安排示意,由于项目B的引入工作越来越多,成效却变少了)

实际上,如果我们认识到项目A的关键要素是快速推向市场,那么我们给小王的安排应该是让他继续专注于项目A,看看什么地方能够协助团队尽快完成项目。这个认知的转变是困难的:

  • 作为管理者,要放弃过去对人员利用率的执着,理解利用率和响应力不是正比关系,在一定阶段后甚至和效率也没有正比关系。
  • 作为员工,要放弃一个萝卜一个坑的工作模式,保持持续学习和跨职能工作的能力,把自己构建成一个T型人才。这个案例中,小王要能够帮助项目A的其它工作,就要求他具有开发之外的其它能力,比如测试。

在这样一个时代背景下,银行IT的敏捷转型,实际是基于以用户为中心的根本原则,加强整个组织的响应力。如果大家还在以“一个功能实现是不是更快了”来度量和牵引转型方向,那么请尽快调整到“面向市场和用户的端到端交付指标”上来。

业务与技术

懂业务是银行业人员晋升的关键因素。曾经在一次银行IT中层管理干部的培训上,我让大家举手表决是向业务方向发展,还是向技术方向发展,结果是全部都选择的业务方向。不可否认,银行业务的复杂度,要设计一套IT系统需要很强的业务理解。但数字化时代,技术成为了越来越重要的一个支柱,各银行组织如果不能快速构建技术人员的职业通道,必然很难在数字化上取得真正的收益。

我们从两个方面来看看中国银行业技术方面的挑战。

第一点是没有足够的技术封装。经常看到一个有意思的现象是,银行业务人员会看数据库,每一张数据库表就映射一张物理世界的报表。这样的设计结果往往是一张银行数据库表可能有好几百个字段。一段时间内,这样的设计是很流行的,因为沟通需求和最后验收都会相当顺畅,直接看数据库表就完成了技术和业务的交流。隐患就是,数据库根本就没有模型可言,修改任何的数据项都需要波及整个系统,所以大家就倾向于一开始就把所有的数据项全部列好,如果不确定就先留下一些空字段以备后续不时之需。

由于根本没有数据模型封装,看似业务上便于理解的设计,到后来也会因为冗余严重、耦合紧密而变得难于理解,或根本不可维护。只要是在基于如此架构上工作过的IT人员,就特别能理解,“为什么弄懂一个几千行的存储过程,需要花几天时间”。没有封装的结果,就是每个维护修改者都需要理解已有系统的所有复杂细节。这也是为什么我们在银行核心COBOL系统中,会看到大量的冗余代码——与其修改已有的程序,还不如忘记已实现的业务,为新增业务重新开发。

第二点是没有开放的技术生态。银行业经常把基于Java这样现代语言的开发称之为开放平台,与之对比的是传统基于大型机和小型机的封闭开发环境。最近还就开发效率问题和一个老牌银行技术人员进行过讨论。一个观点是,基于成熟封闭环境的开发一旦上手其实效率可以很高,对金融行业来说更加模式化,并且硬件保证了高性能和稳定性。于是我也花了不少时间,来研究这样环境下的开发模式,比如在绿色的传统命令界面上完全采用键盘操作,从代码管理到部署都是私有的平台和工具。

从我的角度来看,传统封闭开发环境有以下几个致命伤:

  • 技术设计的表现力不够,造成可维护性差。长期下来,系统修改十分困难,成本随时间爬升很快。
  • 不能够利用很多已有资源。从开源到云服务,实际上都是开放生态中的可用资源。开放技术的全球知识库早已超越了任何一家企业可以提供的技术服务。使用这些共享资源的门槛,就是需要加入到这样的开放生态中去,随着环境的发展而持续演进。
  • 难以支撑快速的市场和用户扩张,对基础资源抽象隔离不够。以云服务为例,某种意义上,云是对之前我们计算机硬件资源的封装,让其成为像日常生活中水电气一样的公用资源,它使得我们在数字世界扩张的时候可以不再受基础资源的限制。然而,在银行IT中,这样的基础资源和服务抽象很少。

很多银行已经意识到了上述的问题,在科技发展方向上,决定逐步将系统应用向开发技术平台迁移。但还存在很严重地照搬过去架构设计的倾向,如前述数据库设计问题仍然存在于新系统中。在敏捷转型过程中,会发现即使在开放平台上也很难实现端到端的业务价值交付,其中核心症结之一仍然在技术架构上。去年,我花了比较大的精力在领域驱动设计(DDD)的推广上,也是希望通过这个方法让银行IT组织认识到正确的架构设计思想。

未来的银行数字化部门应该在应用设计上达成业务和技术的架构绑定,而在人员任职上形成业务和技术的双通道。

文档与人

曾经一句玩笑话“人走文档留”,引起了我对银行IT人才观的深入思考。从较长一个时期看,IT人才观的转变可能是中国银行业的最大挑战。在前沿程序设计会议上,当我倾听一家外行科技VP讲函数式编程,看到两家美国银行收购硅谷技术公司的业界新闻的时候,就深刻地意识到,把“文档”当成IT资产的观念,将会严重阻碍中国银行的科技发展。

也许,在国家鼓励下的BATJ合作,可能给咱们的银行IT业带来深层次的冲击。从去年开始,这个冲击已经超越了我们经典意义上的敏捷转型,而是银行组织级的变革。在这个过程中,我认为我们要解决三个组织级的定位问题。

  • IT合作伙伴的战略定位——从现在的人员外包模式,到面向价值共享的战略合作模式。现行包人头的方式,是敏捷转型的障碍,在银行数字化转型过程中必须重视并解决。当IT和数字化成为银行业未来业务的重要支柱,合作伙伴的定位及合作方式就必须相应改变。
  • IT人员的能力定位——从现行的流程执行模式,到面向业务和技术创新的持续学习模式。随着智能技术在未来几十年的持续渗透,追求效率的金融领域会逐步用机器替代掉重复性工作中的人。这对IT的影响是更深远的,很快我们就会有机器来代替基础的程序员和测试人员,也不再需要管理这些基础人员的IT自有组织。但更为紧缺的是,具备持续学习能力、能够快速响应市场需求变化的数字化人才。
  • 数字化平台的支撑——从过去组织统一流程、检查规范模式,到平台化快速支撑模式。针对未来的不确定性,做细管理流程、强化检查节点的帮助其实是有限的,而提供快速的试验支撑,能够灵活快速地启动小规模多点尝试,则是成功的关键。

人才这个话题上,有一点是确定的:整个组织需要构建数字化人才的能力模型及持续培养体系。去年在国内,我也很欣喜地看到,若干家银行的高管们,开始过问大数据人才的招聘和留用问题,关心在现有体系下如何开辟新的渠道来灵活留用人才。

数字化未来

前面谈了目前银行业IT转型的挑战,最后让我们展望一下未来可能的方向。在前文中我已经多次提到了“数字化”。一个可以预见的未来就是数字化银行,其实《银行3.0》中已经描述了这样的现实,作者也已经开始讲“银行4.0”了。

应该澄清的一点是,数字化不等于IT系统,数字化能力不等于写计算机程序。IT系统仅仅是数字化的一个基础,数字化包含了以用户为中心的实时战略方法和高响应力的敏捷组织,在这样的组织里对技术卓越及创新生机文化的追求是大家的共同目标。

(图:数字化转型模型)

银行业IT的敏捷转型,显然必须服务于这个数字化未来。通过敏捷转型,我们需要把现行的IT部门变成未来数字化银行业务的支撑平台之一。而IT的敏捷转型最终目标应该明确为:

  • 提升端到端的市场响应能力,从而能够为科技引领创新提供能力支撑。
  • 探索科技和业务融合的新模式,从而能够为数字化业务提供模式支撑。

中国银行业的转型才刚刚拉开帷幕,敏捷转型的模式还需要更多的实践者出来分享和交流,谨以此文作为和大家交流的起点。


更多精彩商业洞见,请关注微信公众号:ThoughtWorks商业洞见

Share

DDD战术篇:领域模型的应用

领域驱动设计DDD在战术建模(后文简称建模,除非特别说明)上提供了一个元模型体系(如下图),通过这个元模型我们会对战略建模过程中识别出来的问题子域进行抽象,而通过抽象来指导最后的落地实现。

(DDD构建的元模型元素脑图)

这里我们谈的战术阶段实际就是这样一个抽象过程。这个抽象过程由于元模型的存在实际是一定程度模式化的。这样的好处是并非只能技术人员参与建模,业务人员经过一定的培训也是完全可以理解的。在带领不少团队实践建模的过程中,业务人员参与战术设计也是我要求的。

由于已经有不少书籍介绍DDD的元模型,这里我们就不再赘述,转而谈谈这个抽象过程中大家经常遇到的一些困惑。这些比较常见的问题可能是DDD元模型未来演进需要解决的,但我们仍然要注意业务问题和架构设计的多样性,不要过度规范,以至于过犹不及。

业务对象的抽象

通过对业务问题的子域划分,我们找到了一些关键的业务对象。在开始进行抽象前一个必须的步骤就是“讲故事”!

讲什么故事呢?关于这个子域解决的业务问题或者提供的业务能力的故事。既然是故事,就必须有清晰的业务场景和业务对象之间的交互。这件事情看起来是如此自然和简单,然则一个团队里能够站起来有条不紊陈述清楚的却没有几人。读到这里的读者不妨停下来试试,你是否能够把现在你所做的业务在两三分钟内场景化地描述出来?

这么做显然目的是让我们能够比较完整地思考我们所要提炼和抽象的业务对象有哪些。只有当我们能够“讲”清楚业务场景的时候,才应该开始抽象的步骤。对于一个业务对象,我们常见的抽象可以是“实体”(Entity)和“值对象”(Value Object)。

这两个抽象方式在定义上的区别是,实体需要给予一个唯一标识,而值对象不需要(可以通过属性集合标识)。当然另外一个经常引用的区别是,实体应该是有一个连续的生命周期的,比如我们在一个订单跟踪领域里抽象订单为一个实体,那么每个订单应该有一个唯一识别号,订单也应该有从下单创建到最后交货完成的生命周期。

显然,如果不增加其它约束条件,值对象的抽象是没有意义的,都用实体不就行了?但如果我们稍微思考一下一个实体的管理成本,比如需要保证生命周期中实体状态的一致性,那么我们就会发现值对象变得很简单很可爱。当一个对象在我们(抽象)的世界里不能改变的时候,一切都变得简单了,这个对象被创建后只能被引用,当没有引用时我们可以把它交给垃圾回收自动处理。

随着高并发、分布式系统的普及,实际上我们在对业务对象抽象的第一步思考是能否用值对象。如果大家实现的技术架构采用函数范式的语言(类似Closure),那么首先考虑值对象抽象可能就是一个建模原则了。

对象抽象初步完成后,一定要再重复一次之前的故事来审视一下我们的建模。经历这个抽象过程后,参与讨论的每个人都应该发现自己更清晰业务的需求和需要提供的能力了。

聚合的封装

DDD元模型中一个核心概念叫“聚合”(Aggregate)。这个从建筑学来的名词非常形象,建筑学上我们翻译为“骨料”,是形成混凝土的重要元素,也是为什么混凝土如此坚固的基础。

(混凝土里的一种骨料)

同理,在DDD建模中,聚合也是我们构建领域模型的基础,并且每个聚合都是内聚性很高的组合。聚合本身完成了我们对骨干业务规则的封装,减小了我们实现过程中出错的可能。

以上面那个订单跟踪领域为例,假设我们允许一个订单下存在多个子订单,而每个子订单也是可以独立配送的,这种情况下我们抽象出“子订单”这个实体。显然订单和子订单存在业务逻辑上的一致性,没有订单的时候不应该创建子订单,更新子订单的时候应该同时“通知”所属的订单。这个时候如果采用把订单和子订单聚合起来的封装就很有必要了。

采用聚合抽象的结果就是访问每个子订单都需要从相关的订单入口(i.e., 订单为聚合根),存取时我们都是以这个聚合为基本单位,即包含了订单和订单下面的所有子订单。显然这样的好处是在订单跟踪这个领域模型里,订单作为一个聚合存在,我们只需要一次性梳理清楚订单和子订单的逻辑关系,就不需要在未来每次引用时都考虑这里面的业务规则了。

(订单跟踪领域的订单聚合)

在建模过程中,很多团队并没有努力思考聚合的存在。封装这个在技术实现领域的基本原则在建模时却很少被重视起来。开篇提到在战术建模过程中强调业务领域人员的参与也是为了解决这个问题,聚合的识别实际是针对业务规则的封装,当我们不理解业务规则的时候是无法做出是否封装的判断的。

一言以蔽之,识别聚合是认知潜在核心业务规则的过程,而定义出来的聚合是在大家共识基础上对核心业务规则的封装。

领域服务的定义

在最初的元模型定义里,领域服务让不少人纠结,一个经典的例子是在账户管理领域里对“转账”这个业务行为的抽象。由于转账本身是作用在至少两个账户上的,所以把转账作为一个账户的行为显然是不合适的。那么如果我们把转账名词化抽象成一个实体呢?感觉也是比较别扭,毕竟转账是依附于账户存在的。

这个时候DDD在元模型里提出了服务(Service)这个抽象,转账被抽象为一个服务感觉就顺畅多了。同样道理,在我们上面的订单跟踪领域里,如果跟踪的过程中需要进行短信的通知,一个比较好的建模就是抽象出一个“通知”服务来完成。

我经常会用静态方法来帮助技术人员理解服务的抽象(虽然服务并不一定用静态方法来实现)。服务本身就像一个静态方法一样,拥有一定的逻辑但不持有任何的信息,从整个领域来看也不存在不同“版本”的同一个服务。

一个经常困扰大家的问题是对Service这个词语的限定,有的分层架构设计里会出现领域服务(Domain Service)和应用服务(Applicaiton Service)。大多数时候应用服务在领域服务的上层,直接对外部提供接口。如果存在这样的分层,那么领域服务就不应该直接对外,而应该通过应用服务。

举个例子,前面的订单消息通知如果是一个领域服务,在完成订单状态变化时创建通知消息,而最后的通知以短信的方式发给设定的人群,这样就应该有一个相应的应用服务,包含了具体的业务场景处理逻辑。之后也可能有一个邮件通知的应用服务,同样调用了这个通知领域服务,但通过邮件渠道来完成最终的业务场景。

由于微服务架构的流行,每个子领域的粒度已经相当细了,很多时候已经没有这样的领域服务和应用服务的区分了。当然从简单性角度出发这是好事情。在整个建模过程中,服务的抽象往往是最不确定的,也是最值得大家反复斟酌的地方。

Repositories的使用

Repositories是一个非常容易被误解的抽象,很多人会直接联想到具体的数据存储。在初期采用DDD建模的时候,我经常刻意回避这个抽象,避免让大家陷入思考紊乱。

这个抽象概念实际可以追溯到Martin Fowler的Object Query模式。另外一个相关概念是DAO(Data Access Object),都是用来简化需要存储的数据和对应的业务对象之间的映射关系。不同的是Repositories针对更加粗颗粒度的抽象,在DDD这个方法里我们可以认为映射对象是我们的聚合。针对每个实体在实现时候也可能创造出对应的DAO(比如采用Hibernate这样的ORM框架),但显然在建模过程中不是我们需要关注的。

那么Repositories的抽象为什么是必要的呢?让我们再回到订单跟踪这个例子,通知订单状态发生变化的服务在发出通知前,需要定位到订单的信息(可能包括订单的相关干系人和子订单的信息)。通知作为一个服务是不应该持有具体订单信息的,这个时候我们就需要通过Repositories的抽象来建立对订单这个聚合的查询,即有一个订单的repo,而具体的查询逻辑应该在这个repo中。

这样的抽象在需要存储和查询值对象的时候也是必要的。假设我们分析订单查询这个领域,在这个领域里订单记录显然已经不允许修改了,自然的抽象方式就是值对象。同时一个查询的服务来持有具体的查询逻辑(比如按时间或用户)是合理的。外部应用直接调取了查询服务(接口)并给出规定的参数,我们就需要一个订单记录的repo来持有跟存储相关的查询逻辑。当然这并不是说有一个查询就一定有一个repo与之对应,如果查询的逻辑非常简单,未尝不可以让服务直接针对数据存储实现。记住我们抽象的目标是让建模更简单,抽象过程中应该保持灵活。

限界上下文的意义

经过最近10多年的演进,我们在如何支撑一个组织的规模化上达成了一些基本的共识。我们知道微服务架构(Microservices)能够帮助我们把成百上千的工程师们组织起来,而小团队的自组织性是至关重要的。我们也逐步就如何能够在技术和业务团队之间明确沟通“架构”这个难题上找到了DDD。那么DDD和微服务架构的关系是什么呢?很多人会提到限界上下文(Bounded Context)。

我曾经就这个话题专门撰文一篇(DDD&Microservices)。一个限界上下文封装了一个相对独立子领域的领域模型和服务。限界上下文地图描述了各个子领域之间的集成调用关系。这个定义某种意义上和我们的微服务划分不谋而合:以提供业务能力为导向的、自治的、独立部署单元。所以虽然我们不能百分百依据限界上下文划分服务,但限界上下文,或者说是DDD,绝对是我们设计微服务架构的重要方法之一。

如果我们再追溯到DDD的战略设计,我们会发现在问题域上,DDD通过子问题域(subdomain)的划分就已经进行了针对业务能力的分解,而限界上下文在解决方案域中完成了进一步分解。当然我们不能完全认为子问题域和限界上下文有严格意义上的一对一关系,但大多数情况下一个子问题域是会被设计成一个或多个限界上下文的。子域subdomain和限界上下文某种意义上是互相印证的,重点在区分问题域和解决方案域,这是落地DDD最困难的地方,也是判断一个架构师能力进阶的分水岭。

战术建模小结

DDD的建模元素比较简洁,本文中叙述的元模型应该是满足了大多数场景下的建模。毛主席曾经有一句名言“战略上要藐视敌人 战术上要重视敌人”,就架构设计来说我们没有敌人,业务需求是我们的朋友。所以在领域驱动的架构设计方面,咱们需要的是“战略上要重视朋友,战术上要简化建模”。希望这句话能够帮助正在实践DDD的团队重新思考自己在战略问题域的投入和重视程度,不要挥舞着战术模型的大锤到处寻找实际不存在的钉子。

在这里我们也希望通过第一届DDD China建立起一个架构设计人员的交流平台。期待更多的中国技术人员能够通过这个平台和世界一流架构大师们建立起沟通的渠道,不仅在战略层面,也在战术层面和所有人一起分享讨论关于DDD的一切。


更多精彩洞见,请关注微信公众号:思特沃克

Share

DDD实战篇:分层架构的代码结构

不同于其它的架构方法,领域驱动设计DDD(Domain Driven Design)提出了从业务设计到代码实现一致性的要求,不再对分析模型和实现模型进行区分。也就是说从代码的结构中我们可以直接理解业务的设计,命名得当的话,非程序人员也可以“读”代码。

然而在整个DDD的建模过程中,我们更多关注的是核心领域模型的建立,我们认为完成业务的需求就是在领域模型上的一系列操作(应用)。这些操作包括了对核心实体状态的改变,领域事件的存储,领域服务的调用等。在良好的领域模型之上,实现这些应用应该是轻松而愉快的。

笔者经历过很多次DDD的建模工作坊,在经历了数天一轮又一轮激烈讨论和不厌其烦的审视之后,大家欣慰地看着白板上各种颜色纸贴所展示出来的领域模型,成就感写满大家的脸庞。就在这个大功告成的时刻,往往会有人问:这个模型我们怎么落地呢?然后大家脸上的愉悦消失了,换上了对细节就是魔鬼的焦虑。但这是我们不可避免的实现细节,DDD的原始方法论中虽然给出了“分层架构”(Layered Architecture)的元模型,但如何分层却没有明确定义。

分层架构

在DDD方法提出后的数年里,分层架构的具体实现也经历了几代演进,直到Martin Fowler提炼出下图的分层实现架构后,才逐步为大家所认可。DDD的方法也得到了有效的补充,模型落地的问题也变得更容易,核心领域模型的范围也做出了比较明确的定义:包括了Domain,Service Layer和Repositories。

(Martin Fowler总结提出的分层架构实现,注意“Resources”是基于RESTful架构的抽象,我们也可以理解为更通用的针对外界的接口Interface。而HTTP Client主要是针对互联网的通信协议,Gateways实际才是交换过程中组装信息的逻辑所在。)

我们的核心实体(Entity)和值对象(Value Object)应该在Domain层,定义的领域服务(Domain Service)在Service Layer,而针对实体和值对象的存储和查询逻辑都应该在Repositories层。值得注意的是,不要把Entity的属性和行为分离到Domain和Service两层中去实现,即所谓的贫血模型,事实证明这样的实现方式会造成很大的维护问题。DDD战术建模中的元模型定义不应该在实现过程中被改变,作为元模型中元素之一的实体本身就应该包含针对自身的行为定义。

基于这个模型,下面我们来谈谈更具体的代码结构。对于这个分层架构还有疑惑的读者可以精读一下Martin的原文。有意思的一点是,这个模型的叙述实际是在微服务架构的测试文章中,其中深意值得大家体会。

这里需要明确的是,我们谈论代码结构的时候,针对的是一个经过DDD建模后的子问题域(参见战略设计篇),这是我们明确的组件化边界。是否进一步组件化,比如按照限界上下文(Bounded Context)模块化,或采用微服务架构服务化,核心实体都是进一步可能采用的组件化方法。从抽象层面讲,老马提炼的分层架构适用于面向业务的服务化架构,所以如果要进一步组件化也是可以按照这个代码结构来完成的。

总体的代码目录结构如下:

- DDD-Sample/src/
    domain
    gateways
    interface
    repositories
    services

这个目录结构一一对应了前文的分层架构图。完整的案例代码请从GitHub下载

可以看到实际上我们并没有建立外部存储(Data Mappers/ORM)和对外通信(HTTP Client)的目录。从领域模型和应用的角度,这两者都是我们不必关心的,能够验证整个领域模型的输入和输出就足够了。至于什么样的外部存储和外部通信机制是可以被“注入”的。这样的隔离是实现可独立部署服务的基础,也是我们能够测试领域模型实现的要求。

模型表达

根据分层架构确立了代码结构后,我们需要首先定义清楚我们的模型。如前面讲到的,这里主要涉及的是从战术建模过程中得到的核心实体和服务的定义。我们利用C++头文件(.h文件)来展示一个Domain模型的定义,案例灵感来源于DDD原著里的集装箱货运例子。

namespace domain{
struct Entity
{
    int getId();
protected:
    int id;
};

struct AggregateRoot: Entity
{
};

struct ValueObject
{
};

struct Provider
{

};

struct Delivery: ValueObject
{
    Delivery(int);
    int AfterDays;
};

struct Cargo: AggregateRoot
{
    Cargo(Delivery*, int);
    ~Cargo();
    void Delay(int);
private:
    Delivery* delivery;
};
}

这个实现首先申明了元模型实体Entity和值对象ValueObject。实体一定会有一个标识id。在实体的基础上声明了DDD中的重要元素聚合根 AggregateRoot。根据定义,聚合根本身就应该是一个实体,所以AggregateRoot继承了Entity。

这个案例中我们定义了一个实体Cargo,同时也是一个聚合根。Delivery是一个值对象。虽然这里为了实现效率采用的是struct,在C++里可以理解为定义一个class类。

依赖关系

代码目录结构并不能表达分层体系中各层的依赖关系,比如Domain层是不应该依赖于其它任何一层的。维护各层的依赖关系是至关重要的,很多团队在实施的过程中都没有能够建立起这样的工程纪律,最后造成代码结构的混乱,领域模型也被打破。

根据分层架构的规则,我们可以看到示例中的代码结构如下图。

Domain是不依赖于任何的其它对象的。Repositories是依赖于Domain的,实现如下:引用了model.h。

#include "model.h"
#include <vector>

using namespace domain;

namespace repositories {
struct Repository
{
};
...

Services是依赖于Domain和Repositories的,实现如下:引用了model.h和repository.h

#include "model.h"
#include "repository.h"

using namespace domain;
using namespace repositories;

namespace services {
struct CargoProvider : Provider {
    virtual void Confirm(Cargo* cargo){};
};

struct CargoService {
    ... ...
};
...

为了维护合理的依赖关系,依赖注入(Depedency Injection)是需要经常采用的实现模式,它作为解耦合的一种方法相信大家都不会陌生,具体定义参见这里

在测试构建时,我们利用了一个IoC框架(依赖注入的实现)来构造了一个Api,并且把相关的依赖(如CargoService)注入给了这个Api。这样既没有破坏Interface和Service的单向依赖关系,又解决了测试过程中Api的实例化要求。

auto provider = std::make_shared< StubCargoProvider >();

api::Api* createApi()  {
    ContainerBuilder builder;
    builder.registerType< CargoRepository >().singleInstance();
    builder.registerInstance(provider).as<CargoProvider>();
    builder.registerType< CargoService >().singleInstance();
    builder.registerType<api::Api>().singleInstance();

    auto container = builder.build();

    std::shared_ptr<api::Api> api = container->resolve<api::Api>();

    return api.get();
}

测试实现

有了领域模型,大家自然会想着如何去实现业务应用了,而实现应用的过程中一定会考虑到单元测试的设计。在构建高质量软件过程中,单元测试已经成为了标准规范,但高质量的单元测试却是困扰很多团队的普遍问题。很多时候设计测试比实现应用本身更加困难。

这里很难有一个固定标准来评判某个时间点的单元测试质量,但一个核心的原则是让用例尽量测试业务需求而不是实现方式本身。满足业务需求是我们的目标,实现方式可能有多种,我们不希望需要持续重构的实现代码影响到我们的测试用例。比如针对实现过程中的某个函数进行入参和出参的单元测试,当这个函数发生一点改变(即使是重命名),我们也需要改动测试。

测试驱动开发TDD无疑是一种好的实践,如果应用得当,它确实能够实现我们上述的原则,并且能够帮助我们交流业务的需求。比较有意思的是,在基于DDD建立的核心模型之上应用TDD似乎更加顺理成章。类比DDD和TDD虽然是不恰当的,但我们会发现两者在遵循的原则上是一致的,即都是面向业务做分解和设计:DDD就整个业务问题域进行了分解,形成子问题域;TDD就业务需求在实现时进行任务分解,从简单场景到复杂场景逐步通过测试驱动出实现。下面的测试用例展现了在核心模型上的TDD过程。

TEST(bc_demo_test, create_cargo)
{
    api::CreateCargoMsg* msg = new api::CreateCargoMsg();
    msg->Id = ID;
    msg->AfterDays = AFTER_DAYS;
    createCargo(msg);
    EXPECT_EQ(msg->Id, provider->cargo_id);
    EXPECT_EQ(msg->AfterDays, provider->after_days);
}

上面测试了收到一条创建信息后实例化一个Cargo的简单场景,要求创建后的Cargo的标识id跟信息里的一致,并且出货的日期一致。这个测试驱动出来一个Interface的Api::CreateCargo。

下面是另外一个测试推迟delay的场景,同样我们看到了驱动出的Api::Delay的实现。

TEST(bc_demo_test, delay_cargo)
{
    api::Api* api = createApi();
    api::CreateCargoMsg* msg = new api::CreateCargoMsg();
    msg->Id = ID;
    msg->AfterDays = AFTER_DAYS;
    api->CreateCargo(msg);
    api->Delay(ID,2);
    EXPECT_EQ(ID, provider->cargo_id);
    EXPECT_EQ(12, provider->after_days);
}

长期以来对于TDD这个实践大家都有架构设计上的疑惑,很多资深架构师担心完全从业务需求驱动出实现没法形成有效的技术架构,而且每次实现的重构成本都可能很高。DDD的引入从某种程度上解决了这个顾虑,通过前期的战略和战术建模确定了核心领域架构,这个架构是通过预先综合讨论决策的,考虑了更广阔的业务问题,较之TDD应用的业务需求层面更加宏观。在已有核心模型基础上我们也会发现测试用例的设计更容易从应用视角出发,从而降低了测试设计的难度。

关于预先设计

如果没有读战略篇直接看本文的读者肯定会提出关于预先设计的顾虑,毕竟DDD是被敏捷开发圈子认可的一种架构方式,其目标应该是构建架构模型的响应力。而这里给大家的更多是模式化的实现过程,好似从建模到代码一切都预先设计好了。

值得强调的是,我们仍然反对前期设计的大而全(Big-Design-Up-Front,BDUF)。 但我们应该认可前期对核心领域模型的分析和设计,这样能够帮助我们更快地响应后续的业务变化(即在核心模型之上的应用)。这不代表着核心领域模型未来会一成不变,或者不能改变,而是经过统一建模的核心部分变化频率较之外部应用会低很多。如果核心领域模型也变化剧烈,那么我们可能就要考虑是否业务发生了根本性的变化,需要建立新的模型。

另外不能忘记我们预先定义的模型也是被局限在一个分解出来的核心问题域里的,也就是说我们并不希望一口气把整个复杂的业务领域里的所有模型都建立起来。这种范围的局限某种程度上也限制了我们预先设计的范围,促使我们更多用迭代的方式来看待建模工作本身。

最后显然我们应该有一个核心团队来守护核心领域模型,这不代表着任何模型的设计和改动都必须由这个团队的人做出(虽然有不少的团队确实是这样落地DDD的)。我们期望的是任何对核心模型的改动都能够通过这个核心团队来促进更大范围的交流和沟通。检验一个模型是否落地的唯一标准是应用这个模型的团队能否就模型本身达成共识。在这点上我们看到很多团队持续通过代码走查(code review)的方式在线上和线下实践基于核心模型的交流,从而起到了真正意义上的“守护”作用,让模型本身成为团队的共同责任。

实践DDD时仍然需要遵循“模型是用来交流的”的这一核心原则。我们希望本文介绍的方法及模式能够帮助大家更容易地交流领域模型,也算是对DDD战略和战术设计的一点补充。


更多精彩洞见,请关注微信公众号:思特沃克

Share

面向变化的组织

[摘要]

科技狂欢的时代,市场响应力是决胜法宝,小型化、微型化的组织结构成为了这个时代的主旋律。很多企业争相效仿Google扁平的小团队集群组织结构,却发现组织反而越来越低效。本文结合企业服务化转型的案例,给出小型化组织治理的三条基本原则,相信你能从中得到启发。

组织结构的小型化

站在第四次工业革命的风口,每天被各种创新和变化刷新着,从我们的工作到我们的生活都在改变,“唯一不变的是变化”。这似乎是一个科技狂欢的时代,却给我们这些企业管理者带来了巨大的挑战。“自组织”的救赎并没有那么容易实现,现实是从有章可循变成了“定制化”多元管理。深知市场响应力是这个时代的决胜法宝,但庞大的组织结构却成为了沉重的掣肘,以至于我们开始怀疑过去辛苦打造的管理体系是否多余。小型化、微型化成了这个时代的主旋律,从Amazon到海尔,组织的架构和管理也在同样经历着颠覆。

随着微服务架构风格的流行,组织内部不可避免的产生了许多小规模团队,原来一个几十上百人的产品团队被拆分成了类似Amazon这样的“2个披萨饼”(6~10人)小团队。组织结构上也由之前的层级化职能团队变成了扁平的小团队集群。每个做这样调整的企业,都希望借助小团队的灵活性,跟上市场变化和科技创新的脚步。

组织的两种基本模式示意

当然这样的组织方式本身就带来了一系列的挑战,技术实践方面Martin Fowler已经通过微服务的定义文章做了很形象的叙述,还用了“你必须长这么高”(You must be this tall!)来比喻在技术实践方面所需做出的投入。

在组织管理方面,越来越多的挑战浮现,关于集群小团队组织和管理出现了各种各样的问题。把“自组织”当做银弹来回答这些问题,是行业里存在的一个不太好的趋势。在最近和Matin Fowler的讨论中,我们达成的共识之一是:与其说微服务是一种技术架构,还不如说是一种企业组织架构

组织原则:对齐业务

科技时代带来的最大变化就是对变化本身的认知。在上一个时代,变化被认为是高成本甚至是有害的,大家总是希望能够尽量减少变化,或者能够循序渐进地变化;而现在我们会认为变化是必然的,它会带给我们新的市场机会,甚至会引发颠覆式创新。 由于这样的认知变化,企业必须具备相应的灵活性,而扁平的小团队集群组织结构被不少企业(例如Google和韩都衣舍)证明是提供这种灵活性的有效组织方式。很多企业争相效仿,但会发现并没有得到预期的灵活性,反而做事情更为复杂了,以前一个接口部门变成了现在的多个团队。

作为咨询顾问,这两年经常接触到不少人抱怨划分成小团队后需求的实现成本增加很多,以前简单的业务需求现在要分解到很多“服务”团队才能完成。有的团队觉得这是技术问题架构设计前瞻性不够;有的团队觉得是管理问题——没有跨团队的协调机制。而我往往喜欢从组织入手,让团队从业务需求出发,分析为什么有那么多“集成”。

熟悉康威定律的同学可能已经理解我的用意了。以上团队出现的问题核心症结在于团队的组织结构和市场业务没有对应关系,大量的服务集成等同于把市场需求“翻译”适配到已有的组织结构。这样的痛苦在过去职能组织结构的时候就广泛存在,而错误的“服务化”只是把这种痛苦转换成了小团队之间的集成。

所以微服务化组织结构的核心原则是:小团队的组织结构应该和市场业务对齐,并跟随市场业务变化而改变

稍微实例化一下以上的原则,比如最近一个客户的电商团队,100人左右规模。开始时候划分成了10人上下的小团队,每个团队负责几个服务,其中有几个“重要”服务,如customer(客户)和catalog(目录)。在一段时间里,几乎所有的需求都要经过这两个服务,工作量很大,团队实际上也根本不是十几人,而是几十人。团队告诉我:撑过这段高峰期模型就稳定了,以后就可以真正“微服务化”了。

我用领域驱动设计的思想很快指出,就现在业务需求驱动出来的大量集成已经可以明确这些“重要”服务的划分是有问题的,新增加电子产品(比如点卡)的customer和之前的电商customer已经有不同的含义了,电子产品要求客户提供对应电子平台的账号和授权。按照上面的原则,不应该继续去扩充已有的customer服务,而应该重新分析新的业务模式下是否应该有新的服务(其中也包含新的customer模型)。

不同业务空间的Customer概念

以上的例子在很多走向服务化组织结构的企业里比比皆是,而遇到问题时大家更容易从看似明确的技术或管理手段入手。遇到这样的挑战时,别忘了康威定律。

管理原则:适应不确定性

《大教堂与集市》这本书中对比了两种不同的组织架构模式,很多特质也能够类比到单体架构和微服务架构之上。当微服务架构落地形成生态时(如Google),好比一个繁荣的集市,中央管理固然重要,但各个经营摊位却自主在为客户提供着琳琅满目的商品和服务。

作为一个企业,不太可能完全容忍集市一样的市场化,当然也有企业如海尔,把这种市场化更大程度上地引入到了内部。假设刚刚从过去职能层级组织结构转换到扁平小团队集群结构,这个时候管理者最大挑战,就是如何还能够获取过去“全面一致”的信息。管理者往往会告诉我他们感觉到随时可能失控,因为每个团队都没有统一的开发方法和流程。

很不幸的是,大多数从MBA课堂走出的企业管理者们都是管理“大教堂”建设的高手,却很难驾驭集市带来的“混乱”,但又都渴望着自己的企业能够有创新的环境。根据创新理论(Edge of Chaos),集市混乱产生创新的可能要远大于大教堂的整齐划一。那么在这个你不创新就被别人颠覆的时代,管理者就必须正视这个挑战。

管理的原则应该改变为:放弃对掌控全局的虚幻追求,拥抱不确定性带来的挑战和机遇

同样实例化一下上面的原则。一个300多人的大产品经理,自从转型成为扁平小团队结构后,他的会议比之前多了N倍,基本每天正常工作时间全部在开会。自己的产品方向和运营只能靠夜深人静的时候加班。他告诉我如果这就是所谓小团队要付出的代价,那么这事儿没法持久。

我首先肯定了他的观点,即如果作为产品经理都没有时间看产品方向和运营,那么模式上肯定是错了。进而询问最占用他时间的会议需要他做什么?答案是:“我需要知道XYZ信息才能保证计划的传达和理解”、“开会是已经同步各个小团队最高效的方式了”……。这里传递出来的,其实全部是希望掌控全局的急迫,和他表面上表达的赋权团队、打造自组织文化大相径庭。接下来,我们花了很多时间来讨论为什么一定要有拉通的计划、为什么要中央同步各个小团队……。当然,知行合一本身就是困难的——这位管理者最后带着更多的困惑离开了那次讨论。

对比组织结构的调整,管理者思想和方法的转型确实任重道远。我往往给出的建议是从小处着手,比如放弃给每人安排任务,让大家自己来选择;又比如在团队之间冲突时,放弃作为管理者的“拍板权”,让团队通过快速实验来验证哪种方式更好。另一位大师级同事Jim Highsmith在八年前就总结出了适应性领导力(Adaptive Leadership),十年后的今天仍是少有管理者能够真正践行。

合作原则:简化集成关系

微服务下小团队集群的结构,不可避免需要更多的团队合作。一个运作良好的微服务生态圈背后是一个紧密协作的小团队网络,而团队之间的合作就是这个网络里无形的手。合作很多时候是团队和团队在运营过程中实时发生的,并非是预先设定或中央控制的,这个时候如何高效合作就成了一个很大的挑战。

在共同满足业务需求的过程中,大多数的合作是由于实现过程中服务之间的集成关系产生的。如前面讨论组织结构时的案例,很多组织在转型后反而集成多了,造成交流沟通成本持续增高,最后不得不安装很多会议和流程来“协调”这样的合作。结果当然是响应力越来越差,小团队名存实亡。

在团队合作方面,《领域驱动设计》一书中提出的业务限界上下文的关联关系可以借鉴。服务划分强调从业务视角出发,限界上下文提供了很好的划分指导。由于每个服务对应一个小团队,那么实际上我们就建立了团队之间集成关系的模式。在微服务开始落地实施的时候,其中描述的基于领域模型耦合方式的关系模式,就变得十分重要了,因为这些模式本身也是团队之间的合作模式。

限界上下文关系模式要求矩阵(领域驱动设计,248页14.4)

上面的矩阵总结,告诉我们集成是高成本的,要尽量避免集成。同样道理在咱们团队合作的过程中,原则也是简化集成关系。在微服务架构下,显然右上角的“大泥球”(Single Bounded Context)和“共享内核”(Shared Kernel)是不推荐的;“独立自主”(Separate Ways)这种完全松耦合的关系是值得我们考虑的,但大多数情况下小颗粒度的服务之间还是会被不同的业务需求串联起来。

很多刚转型的企业会出现不少的“用户/供应商”(Customer/Suppier Teams)模式,主要是团队之间关系还是由更高层的领导在指挥,作为一个演进的合作关系应该更进一步向“开放主机服务”(Open Host Service)模式推进。现代的服务多是以API的形式更为规范的对外提供接口,所以其实在团队沟通方面的成本并非比领导中央决策高多少。

随着API规范的更进一步发展,如采用RESTful架构,很多时候服务团队之间只用做简单的翻译或遵从提供者的模型即可,耦合程度进一步下降,这个时候左下角的另外两种模式“防护层”(Anticorpution Layer)和“跟随者”(Conformist)就更为常见了。显然这两种模式集成关系更为简单,合作过程中调用服务的团队是不需要知道提供方的内部模型细节的,当然这个时候团队之间的信任关系也应该是相当高的。

结语

采用微服务架构后,自然会产生小团队扁平化组织结构,我们应该意识到在组织、管理、合作的原则及思维观念上都应该发生转变,忽略任何一个方面最终都会造成转型的失败。

  • 在组织结构上,团队划分要面向业务能力,持续提供市场价值。
  • 在企业管理上,管理者要拥抱不确定性,持续提升管理适应力。
  • 在团队合作上,考虑跨团队领域模型的耦合,持续简化集成关系。

无论我们是否采用微服务架构,组织想要持续响应外部变化、获得灵活性,就必须在组织级架构上“小型化”。组织管理上,我们必须适应和促进这样的架构落地和持续演进。起步必然是痛苦的,正如老子千年前指出“一生二 二生三 三生万物”,包容多样性是全局管理的精髓。

同海尔张瑞敏的认知一样,我认为有着这种全局视角基因的中国哲学,可能在这个时代的组织管理上大放异彩。


更多精彩商业洞见,请关注微信公众号:ThoughtWorks商业洞见

Share