2004年,Gregor Hohpe发表了令人赞叹的《星巴克不使用两阶段提交》一文。在读到此文时,我突然意识到大学时在星巴克的兼职经历有多么重要。多年以来,我逐渐意识到应该有更多程序员从这家高人气咖啡连锁企业身上学习宝贵经验。
构建可扩展软件无疑是很多从业者的目标,但初次实践却往往困难重重。正如在各类任务的处理过程中,我们经常陷入某种陷阱,即认为每项工作都同等重要、需要同样的资源并应当根据预先定义的顺序逐步进行。
事实证明其并非如此——至少在可扩展系统中并非如此,而星巴克也早就意识到了这一真相。
如何制作咖啡
在星巴克,咖啡饮品的筹备工作共分四步。首先,客户排队在吧台确认订单,并按照顺序依次制作。第二,员工(咖啡师)从客户手中获取订单并接受付款。第三,着手准备饮品。第四,饮品制作完成后,将其放在吧台上并按姓名提示客户前来拿取。
尽管整个流程听起来非常合理,但却往往会导致客户排出长长的队伍。而且采用这种方式,员工同一时间只能处理一项任务,因此客户就需要在咖啡师制作饮品时在队列中枯等。具体来讲,要服务更多客户,员工们需要进行规模扩展。下面来看星巴克选择的扩展方式。
扩展咖啡师队伍
星巴克可以选择的扩展方式之一就是雇用“超级咖啡师”——他们极具才华、工具效率惊人且非常睿智。星巴克需要投入巨额资金留住这些人才,并不断优化其工作中的各个侧面并改进生产效率。立足于软件,这种方案被称为向上扩展(或者垂直扩展)。不过这种作法的问题在于,单一员工的工作速度及工作时间是有限的。在某种程度上,即使是超级咖啡师也无法彻底满足所有要求。一旦出现这种状况,客户就会沮丧地离开店铺并可能再也不会选择在星巴克消费。
同样的,这种排序处理方式也会给软件的优化效果带来局限。我们不可能买得到主频高达200 GHz的处理器。即使是目前最先进的多核心CPU,其每个核心的时钟速率也仅在3到4 GHz水平。
星巴克可以采取的另一种扩展方式则着眼于组织结构,意味着添加更多普通员工以通过并行方式进行饮品制作。这在软件层面即为并发处理。当一位咖啡师接到订单后,另一位接力进行筹备。这样第一位咖啡师就可以接收更多订单,各位员工之间并行不悖。
大家可能会想到,最理想的办法就是只有在需求量达到一定水平后才采用并发处理方式。遗憾的是,事情远没那么简单。世界上可不存在那种能在必要时一下子实现并发处理的魔法开关。换言之,我们需要事先以此为基础进行规划才行。
星巴克当然也清楚这一点。每建立一家新的门店,他们每班只会设置一位员工,而且从起步阶段即做好进行并发处理的准备。只要有需求,他们可以随时增添人手。
经验:如果不在系统构建阶段就考虑到支持需求,那么并发处理将无从谈起。
现在,让我们看看星巴克的具体实现方式。
从信息传递开始
如果大家曾在星巴克点过咖啡,就会注意到杯子上的那些小框框里总是标有某些符号。这些符号是一种简写,旨在帮助咖啡师快速了解饮品类型以及其它额外要求(例如奶油与泡沫量等等)。
杯子,或者说其上传达的信息,正是员工之间的沟通基础。它代表着这杯饮品的制作方式并通过符号提醒咖啡师如何对细节做出调整。即使店内并不忙碌而且只有一位客户在排队等候,员工们也仍然会在杯子上标注符号。
乍一看,这种方式似乎有种杀鸡用牛刀之嫌。但是,如果一大批客户突然涌入店内,那么后备员工能够马上参与进来——无需任何额外的沟通流程,他们即可着手制作客户指定的饮品。
经验:突发性峰值需求并不可怕,只要我们能够随时轻松添加更多员工并为其分配任务内容。而充分利用消息收发正是实现这一效果的必要途径之一。
分而治之
正如之前提到,整个咖啡制作流程都可以由单一员工——即咖啡师——完成。不过星巴克的默认流程则是由一位员工(即收银员)接收订单及付款,再由另一位员工(咖啡师)制作饮品。
通常来讲,整个流程中速度最慢的环节就是咖啡制作,这也正是店铺忙碌时需要由多位咖啡师协同工作的原因所在。他们往往会从同一叠纸杯中拿取容器并均匀地分担任务内容。而这正是“竞争消费方”模式的直接体现。
不过在某些场景下,这种方式也有可能带来麻烦。举例来说,有三位咖啡师共同使用一台咖啡机与一台星冰乐机。而三位客户点了一杯咖啡,第四位则点了一杯星冰乐。接收订单的员工在这四个杯子上分别写下对应的符号。这意味着每位咖啡师都需要拿取一个杯子准备制作饮品,但在第一位操作咖啡机时、其他两位则只能拿着杯子枯等。
要避免这种状况,我们需要对工作进行划分。一种方式就是对信息加以进一步细化,这样后台咖啡师就能更为具体地加以执行。例如,我们都知道星巴克会利用杯子上的信息来表示需要准备的饮品类型。但事实上,这套系统还会对热饮与冷饮进行区别处理:热饮用纸杯盛装,冷饮则用塑料杯盛装。当我们先接到三份热咖啡订单,再接到一份星冰乐订单时,则需要从两叠杯子中拿取三个纸杯与一个塑料杯。第一位咖啡师从纸杯叠中拿取一个并开始制作,而第二位咖啡师由于暂时无法使用咖啡机,因此会转而拿取一个塑料杯并制作星冰乐。好了,这样就有两位员工同时制作两杯饮料了。
这种方式能够帮助咖啡师进行任务拆分并同时推进,我们将其称为“分工”。
经验:事实证明,有效的分工正是实现扩展战略的一大关键性元素。并非全部工作都需要同等水平的扩展能力。小型任务可由单一员工迅速完成,而规模更大且速度更慢的任务则由多位员工共同进行。通过分工机制的引入,我们能够对每项操作进行独立扩展。
每项工作的重要性并不相同
星巴克之所以如此成功,最重要的一点就是其会对员工进行培训,从而帮助他们理解常客的重要性。每天早上定期前来为团队成员购买两杯美式与两杯大号拿铁的客户当然值得重视,而每周三都会点杯焦糖玛奇朵并在店内待上一个小时的客户也同样颇有潜力。
如果咖啡师注意到了这位“焦糖玛奇朵客户”,他们会在其真正开始下单之前就着手制作这款饮品。这种预先准备的方式也会给客户带来惊喜与感动。收银员了解对方的喜好,因此可以与其打打招呼并直接接过付款。在付款结束时,客户的咖啡已经准备好并被放在吧台上了。
大家可能会讶异于星巴克忠诚客户的比例。事实上,为客户提供最佳体验一直是星巴克的优先工作。常客们获取饮品的速度往往也远高于普通客户。这让他们感到自己受到了重视,并变相鼓励他们继续定期前来——而星巴克也从中获取到更多价值。
经验:某些任务较其它任务更为重要。通过构建针对这些可复用的、独立构建块的标准化操作方式,我们能够轻松修改流程以为更具价值的任务提供更加优势的服务。
并非所有错误都有必要避免
通过以上示例,我们了解到星巴克员工需要在交付咖啡之前首先确认客户已经成功付款。为了确保这一流程,咖啡师们可以在交付咖啡之前要求客户出示其购物小票。然而,实际操作中星巴克员工往往不太会这么做。
星巴克发现,鲜有客户会在尚未付款的情况下冒领饮品。他们的分析结论表明,让咖啡师专注于处理订单才是重点,相比之下极低的咖啡丢失可能性甚至可以忽略不计。如果有人碰巧拿走了其他人的咖啡(通常只是拿错了),咖啡师可以直接再准备一份新的——而无需提出任何问题。
经验:要构建可扩展系统,我们需要认同错误的不可避免性。有时候避免这些错误会带来高昂的成本,因此我们不妨将注意力集中在对问题的快速检测以及出现后的应对举措身上。
总结
就这样,简单的四步式咖啡制作方案变成了一种有趣的业务流程。那些乍看起来不重要或者有些反常的作法反而成了业务的立足根基。
突发性峰值或者故障等状况每天都会出现。在设计系统时,我们应当将其纳入预期范畴之内。另外,大家也需要在实施过程中不断添加更多预期之外的情况,例如取消订单等。
从星巴克的例子可以看出,如果我们仅仅部署一厢情愿式的方案,那么业务将无法顺利扩展并为更多客户服务。随着客户数量的增加,我们的服务水平将不断下降甚至最终停滞。相反,我们需要在组织结构层面考虑到不断增长的实际需求,并最终将系统构建与规模设计作为同技术对等的业务流程元素加以思考。
号外号外
由InfoQ主办的面向中高级移动开发者的GMTC全球移动技术大会(点击文末阅读原文链接了解详情)将要召开了,携程高级技术经理、《React Native入门与实战》联合作者魏晓军将为我们带来搭建React Native生态的分享。大会目前正值6折售票期间,欲购从速!