Skip to main content

在约束与机会中权衡

在我看来,经济学应该是当代人人都应该掌握的基础知识,现推荐一本《斯坦福极简经济学:如何果断地权衡利益得失》,比之前那本《经济学的思维方式》更容易入门。

经济学的三个基本问题是:

1. 社会应该生产什么?
2. 应该如何生产?
3. 谁来消费所生产的东西?

比较有启发性的内容包括:

做自己最适合的事,就有更好的生产力:在经济学教科书里,我们称之为比较优势。前段时间和几个创业的朋友聚会,发现创业起步者,尤其是靠项目盈利者,有一个最大的误区就在于复制客户或上游链条企业的模式,不少行业级的大企业也正在步入同样的误区:比如设备商做运营商的事,运营商做电商的事,电商做社交的事——这本质上都变成了服务商涉足自己客户的领域,同时又要求客户买单。

这也可以理解为,中国社会依然没有很好地理解分工合作,依然没有从农业经济模式到商业经济模式发展上进行思维的转变。

在任何情况下都必须有所取舍:公平只是一个相对的词汇,企业会说,如果有更高的产品价格,他们有办法扩大生产,创造更多的就业机会;而消费者会说,他们的收入已经无法负担当下的产品价格了。管制,包括价格管制和最低工资限制,都会掩盖成本,但以最低工资为例,如果在此标准下,企业会不愿意雇佣一批技能非常低下的工人,造成了这批人的失业,但却有90%的工人因最低工资标准而在收入上受益,那政策倾向后者就是一个相对公平的取舍。

人一生积累财富的关键是什么?发现周围许多上了30岁的朋友依然处于“储蓄—消费”偏好的阶段,非常缺乏投资的眼光。记得刚毕业时身边的“高帅富”同学已经在投资土地(而非房市)了,现在更发现越早有投资经验,就越容易真正扩大财富。

在财富积累这个层面,关键是懂得利用复利——如果储蓄是为了大额消费,无疑是损失了更高的利益收入。在投资上,无论是个人投资、企业投资,投资人的风险承担能力是最关键的因素;另外一点是自己能用多少时间来投资。

主张绝对的零污染是不可能的:几十年来,高速发展中的国家如中国,环境问题非常敏感。在经济学中我们称之为“外部性”(Externality),指在直接的买家与卖家之外,有第三方直接受到这笔交易的影响。

外部性可能是正面或负面的。例如:你的邻居正在举办宴会,找来一个很吵的乐团,邻居快乐地享受音乐,乐团也开心地表演。至于你,身为局外人,可能会有两种反应:如果你喜欢这种音乐,那很棒,你可以享受一场免费的音乐会;如果不喜欢,那就不妙了,你只好忍受(或是报警)。无论是哪种情况,你的邻居和乐团之间的交易,都没有考虑到你。

染污是负外部性(Negative externality)最重要的例子。在不受约束的市场交易中,厂商只注意生产商品的私人成本,至于社会成本,是不用支付的生产成本,因此厂商不会将其纳入考虑范围。如果倒垃圾不必花一毛钱,厂商可能会制造很多垃圾;但如果必须付钱处理垃圾,那厂商自然会想办法减少垃圾。

不过问题来了,这个社会成本也好,额外增加的处理成本也好,最终都会转嫁到消费者头上。当我们享受着便宜的工业制品时,却没有考虑到,它的便宜是建立在某些方面未支付成本上面而已——比如说靠破坏不发达地区地理环境为代价的便宜的水电,比如说靠制造空气与水高污染的廉价合成化工用品塑料,等等。

什么样的收入不均程度算合理?这依然是一个可能被“公平”掩盖的问题,许多人关注公平,但人的背景、智力、知识与努力程度,本身就不是不公平的;大多数情况下,收入是被个人的产出结果衡量的。所以更好的问题是:目前的收入不均的程度是否合理?

另一个非常容易被“公平”掩盖的问题是流动性。收入分配只是一个静态分析,它告诉你在某个时间点,人们处于某个收入水平,但并未告诉你他们的发展趋势:向上、向下或是稳定发展。对收入分配的持续动态追踪,被目前大部分政府忽略了,但我们可以通过一些事例,观察到中国大部分上代务农的低收入人群的子女,都在向城市准中产阶层转变。比如说,有篇文章叫做《我奋斗了18年,终于和你一起坐在星巴克喝咖啡》,现在又有新一篇文章叫做《我奋斗了18年,不是为了和你一起坐在星巴克喝咖啡》……

穷国可能追赶上富国吗?这是一个开放式问题,但可以肯定的是,穷国的高速增长离不开低成本获得富国现有的技术与发明。关键点在于富国是否能继续保持在技术和效率上的领先,穷国是否能降低技术升级对富国的依赖。

政府的钱怎么花?对政府的财政政策来说,具有自发性或权衡性两种。

权衡性财政政策的第三个困难,在于政治的本质。自从经济大萧条和凯恩斯的著作问世以来,很多经济政策制定者都要求政府制定反经济周期的财政政策,亦即在经济差时花钱,在经济好时节俭。但政治上很难这么做,为什么?想象经济飞快增长的情况,税金像洪水般涌入,经济学家说:“不要花掉这些钱!要累积非常大的盈余,削减支出并提高税收。”这是一个很好的反经济周期政策,但它在政治上不容易获得认同。当经济萎缩且资金吃紧时,经济学家说:“这是大肆挥霍的良机,我们知道收不到税金了,管它呢,花吧!”但很多公民和政治人物会说,如果人们都在不景气时勒紧裤带过日子,那么政府也应该这么做。在经济好时节制政府支出,经济差时扩大支出,这种敏锐的洞察力不是一般政治人物能有的智慧。

其实权衡性措施在过去的农业经济中不难看到:丰收年,地主或政府管理者会存储大量粮食在粮仓,在欠收的年份,使用粮仓中的粮食向受到损失的地区发放救助。而货币的需求供给弹性却远远高于粮食,这也是权衡性政策难以操作的原因。

未来全球经济面临的危险:能源短缺和环境危机。在上面提到,工业化生产其实是以能源高消耗和忽略环境成本为代价的,一旦能源和环境的阈值达到,当前经济的长期增长就会面临危机。

现在越发认识到,人类社会最主要的矛盾就在于内部的竞争。当一部分人的技术发展起来时,他们需要竞争获取其它人的市场来使自己获得更大的利益;当市场竞争结束后,原本落后地区的人在成本上和原产地竞争;大量生产技术的转移,又会引发新一轮的技术发展竞争。人类的智力、知识、工具甚至语言的多样性,都远远超越了造物主在自然创造的复杂度,自然的简单性与漫长的修复周期,又反过来制约着人类的欲望与想象力。

经济学告诉你的,就是在约束与机会中果断地权衡自我的利益得失。

本文原文:http://www.justinablog.com/archives/1671

Share

DevOps中文名: 开发自运维

谜面

在实践和推广 DevOps 的过程中, 当对着客户吐出 DevOps 这个词之后, 收获的往往不是大腿一拍热泪盈眶, 而是一脸困惑欲言又止想问又没问的场景. 在一番解释后, 到团队中落地的时候, 往往又单独拉几个人出来, 划了个圈说这是一个 DevOps Team. 这类做法背离 DevOps 的初衷. 背后的原因很多, 但一个浅显却影响深远的原因往往被忽略, 就是 DevOps 这个名字本身.

DevOps 目前并没有中文翻译, 对于中国人来讲, 即使直觉的望文生义也无法产生. 当几番了解知道是” Development” 和” Operations” 的拼接之后, 对应的中文是”开发运维”, 依然一头雾水不明所以. 而由于” 开发”和”运维”目前是常见的两种角色, 两个团队, 而 DevOps 需要新的技能和工具, 因此把 DevOps 作为一种新的角色, 成立一个新的团队, 就自然而然了.

开发自运维

语言的边界就是思想的边界. 一个精确表达概念的词汇将阻止误解的产生. TDD 也好, Pair Programming也好, 虽然实践本身争议不断, 但其含义却少有误解. DevOps 对于英语母语的人来说或许精确表达了它的意思, 但对于中国的开发团队来说, 带来的只有困惑.

开发自运维” 是我推荐的 DevOps 中文翻译. 它依然没有反映全部的含义, 甚至暗示着不再需要运维团队, 但它至少从字面上就阻止一件事: 成立专门的 DevOps 团队. 想想吧, 把几个人弄出来, 说你们是”开发自运维”团队, 这从语义上就说不通啊. “开发自运维”从字面上就意味着运维是开发团队内置的责任, 这也符合 DevOps 运动的初衷.

历史即未来

在高度不确定性的产品创新中, 对市场的响应速度越来越快, 开发自运维是一个趋势, 可以缩短交付时间和对反馈的修复时间. 这种趋势的前一波浪潮, 则是”开发自测试”/“开发自设计“, 而下一波运动则极有可能是”设计自开发”.

”开发自测试”已经接近成功而即将成为过去式, 可最初也曾经面对”开发”和”测试”天然是两个团队这种概念而阻力重重. 并没有一个像 DevTest 这样的运动来指导开发和测试的融合, 而是敏捷推行的”全功能团队”帮了忙. 而最终的结果是并不会取消测试这种活动, 甚至依然有专职的测试人员, 但相当一部分测试活动被”开发人员自测”涵盖了. 对照历史, 我们有理由相信, “开发自运维”并不会取消运维这种活动, 甚至依然会有专门的运维人员, 但相当一部分运维工作, 将被”开发自运维”涵盖.

“开发自设计”几乎从未引起过困惑和质疑. 事实上无论是 PC 时代还是 Mobile 时代, 大量软件都是个人能力的结晶. 这里面的制约因素是开发能力而非设计能力. 即使对企业应用开发, 架构师, 交互设计师等也都算作开发团队成员.

而”设计自开发”则已初露端倪. “心声”是一款帮助听障患者与他人沟通的 iOS App, 由 ThoughtWorks 设计师朱晨独自设计并开发. 随着对市场响应速度的追求, 对不确定性快速验证的追求, 设计师们发起了”Lean UX” 等工作方式, 而对开发工具的掌握, 将极大提高其产品设计和验证效率. 开发工具及平台朝着简单易用的方向发展, 也会助设计师们一臂之力.

Share

敏捷咨询日记——沟通问题

强调沟通和杜绝浪费是敏捷最核心的东西,这两项基本是贯穿我这次咨询活动的主线-任何细微的活动都需要用心审视两个问题:我做这件事情的前提是传递价值给团队另一个人,那么价值的传递过程中有没有沟通的阻碍?价值的传递过程有没有什么东西导致了传递损耗既是浪费?从一对一沟通谈起,逻辑是你不可能消除所有的沟通壁垒,譬如你的口齿不够清楚,那么至少发现那些你可以消除的壁垒,消除它,并告知和提醒你的听众那些你不能消除的。往往人们犯的错误是:

  • 察觉不到那些可能成为沟通壁垒的微小细节;
  • 对自己不能消除的壁垒过分乐观;
  • 对自己的听众过分乐观;

很多微不足道的东西都可能称为沟通壁垒。传统上,邮件和文档理所当然称为阻隔沟通的最大障碍。文字的修辞不如口头表达直白有效;文字很难达到及时的确认反馈;超过一定数量的文字考验被交流者的耐心;绝大部分的文档撰稿人无法理解文档是一种用户界面的思想,我所看到的情况,大部分的文档达不到可读(readable)的标准。

未曾想到的是,某种不经意的细节也许也能成为沟通的障碍,譬如,某个不及时统一的术语运用,因为小,更容易被听者忽略或者不愿意直接打断;或者某个图省事的英文缩写;或者一个白板上随意的箭头;或者某个夹在在中文里的英文单词。归根结底,任何沟通的承载物都是一种界面(interface),界面设计种盛行的”Don’t make me think”完全应该引入到你的任何一次沟通中来。就跟蹦出个对话框说“对不起,请耐心等待上传结果”的意义跟“对不起,我的普通话不标准,如果有听不清楚的地方,请打断我”一样,都是一种降低使用者(被沟通者)预期的方法,目的都是达到更好的沟通效果。

当然,更重要的是提升自身的沟通技巧。这里面有几种技巧是可以提供帮助的:

学会察觉沟通者的身体语言

据说有60%的沟通依靠身体语言,熟悉几种常见的身体语言和它们背后的故事会有帮助。譬如,说反馈的话却不对着你说而是对别人笑,代表他不确定自己的观点是不是受人支持,希望找到这种支持;双手护胸代表对你的内容有抵触,他有更多自己不同的看法;双手叉腰,虎口对你代表疲倦,虎口对内代表急于表达自己的看法;看着茶杯喝水代表对你说的内容不感兴趣,看着你喝水代表对你说的极感兴趣;低头看你代表不信任,把某一边耳朵倾向你代表很关注你的内容,扬起下巴两指拖着代表关注并思考,等等。

会展现你的观点

画图是最好形成共识的工具,相当于一个美的用户界面。居我观察,A公司的专家没很少有能够干净准确表达自己观点的,共同的问题是,要么就不画,要画也是不知道如何画,最后的结果是白板上什么都不是。因为国人的教育偏究其理而轻表其象,也许这种技能是无法在短时间内获得,但是,根据大熊这个把Parking Lot画成熊猫的同志的经验,画的时候不要着急,画一点是一点,对自己要求严一点没画好的地方擦掉重画。

要持续确认

敏捷最美的地方在于任何活动都遵守敏捷原则,在沟通的过程中需要持续地把各自的理解与对方确认,可以说:我是不是可以这样理解…等等。

要鼓励对方进行沟通而不是制造障碍

譬如,很多人在一个阐述的结尾喜欢加:你明白我什么意思吗?或者,你能理解我的意思吗?等等,这样的话很容易让人在每个“吗”字后面不自觉地加一个“笨蛋”,认为这时候说不明白会有一种羞耻感,因此,更换成:我不知道我是不是表达得很清楚?或者,我会不会说得有点不太明白?会起到更好的效果。

要把已经达成一致的东西展示出来

看!这又是敏捷原则之一-阶段性的showcase,对于不再需要重复已经达成一致的观点,应该及时写出来,因为接下来的某些言论如果是基于一个已经达成一致的观点,风险会降低很多。你可以使用身边的纸笔,最好是白板纪录下这些内容。

(编者按:五年后再看这个会议沟通海报,据说已经变成了文物展出)

关于沟通的问题,也许还有更多的话题可以探讨,更重要的还是实践中的体验。作为ThoughtWorks的面试人员,沟通可是我的第一加分点,一个乐于或者善于沟通的人往往离成功不远,是我最欣赏的品质没有之一。

Share

建设全功能团队——实践篇

上篇文章中我们一起回顾了分工历史,对于技术团队影响以及建设全功能团队的必要性 ,在实践篇中我将详细分享一些实践以及我们团队的经验数据。

吃自己的狗粮

当开发人员坐在测试工作站前,你将会诧异于多少开发人员因为繁琐的步骤而不会安装/升级自己参与制作的软件,多少人认为自己设计的复杂配置是荒唐的。在很多情况下,这都不是安装、配置的问题,而是设计问题,将开发和测试过程分离而把痛苦转嫁给了另一个团体(测试、用服、用户),开发人员丧失了亲身使用软件的机会,进而无法发现问题的存在。暴露并修正这些问题,是将开发人员和测试人员进行轮换的主要价值之一。从我们的经验数据看,开发人员可以在一周内掌握大多数的测试技巧,个人的建议是从经验丰富的开发人员开始轮换,一方面他们更能认识到测试的必要性,便于交流,也便于形成表率。另一方面丰富的经验更容易帮助他们察觉到问题的存在。其它的一些要点是:

  • 一对一的充分交流,让开发人员认识到进行测试工作的价值和目的。
  • 引导开发对痛点进行思考、改进。改变测试简单、重复的工作面貌,要对开发人员形成挑战。
  • 一周轮换2天持续数周或连续轮换2星期为宜。

睁开眼睛看大象

开发人员习惯于正确性驱动,然而正确的返回结果却不一定是必须的,有时甚至是一种浪费。我们项目所需要处理形如1001的期货时间戳,10代表2010年,01代表一月份。开发人员自然想到了如何区分1910年、2010年、2110年的问题。于是复杂的内部表达被设计出来,用于推断正确年份。这是必须的么?如果我们能了解到客户最大的压力在于半年后项目能否成功上线、替换掉现有无人能够维护的应用,而不是100年后才可能出现的问题,我们是否能在类似的技术决策中,做出更聪明的选择呢?帮助开发/测试角色获取更多的信息,让他们了解到制定需求的上下文,而不仅仅是需求是什么;让他们从更高的层面认清各个故事之间的关联,能够分辨可以给客户带来最大价值的任务,这是将开发角色/测试角色与分析角色对换的主要价值。一些要点是:

  • 在进行分析工作前,开发人员需要完成多个模块的开发,而测试人员最好完成开发轮岗,否则收效甚微。
  • 分析工作可以兼职进行,我们认为比较有效的方法是每天下午花40分钟让开发/测试人员在教练的带领有重点的分析一、两个故事。
  • 重点放在提供一套思考框架帮助新手梳理分析思路,我们发现一个有效的方法是结对工作、独立思考、演讲并点评。(参见结对工作,不止与结对一节)

根据我们的经验,两周全程跟踪式的结对分析足够帮助新手初步掌握分析思路,教练可以考虑逐渐减少在新手思考过程中的侵入,再经过大概2个月的练习,新手基本可以独立工作。

和客户对话

在进行过分析角色的轮换后,可以进一步利用需求管理作为主线让团队成员参与到客户交流中,慢慢削弱项目经理的客户联系人角色,其主要价值在于:

  • 提升交流质量,一线人员常常比项目经理更了解产品。
  • 展示开发人员的能力,增强客户信心。
  • 弱化项目经理在客户眼中的重要性,为未来平滑的取代项目管理者,减少开销作准备。
  • 帮助技术人员掌握交流技巧、提升团队能力。

个人建议是:

  • 从例行的功能展示会(showcase)开始,让每个成员练习从客户的角度进行思考(客户想看什么?),锻炼语言能力,消除与客户交流的恐惧感,并且让客户熟悉开发团队的每个成员,习惯开发团队的交流方式。
  • 由多人分别准备客户进行电话会议中需要讨论的议题,每人深入思考的一、两个问题,通过充分思考弥补经验、技巧上的不足。
  • 结对完成发给客户的邮件,让另一双眼睛检查有没有把该说的问题点到,表达方式、方法是否得当。
  • 提供一套与客户交流的思考框架,并在与客户的交流中不断强化它。我们采用的框架是“客户,交付,流程,员工”,团队成员在思考问题时,首先从这四个点出发再逐层展开。

这项练习需要贯穿项目始终,对于团队成员无差别的进行,我们的经验数据是经过5个月左右的练习,项目经理就不需要出现在与客户的例行电话交流中了。

写程序,我行么?

测试人员普遍编程技术能力欠缺,同时有常常对编程这一未知的经验产生恐惧。从经验看,如果测试人员不能编写、维护自动化测试,测试工作将很快成为交付瓶颈。通过编程,让测试人员掌握技术,避免瓶颈的出现是测试到开发角色转换的主要价值。我们所采取的步骤是:

  • 与测试人员结对完成简单的编码任务,不断树立信心。在这个团队中,我们从设计与实现自动测试框架开始,亲手设计的框架让测试人员更有能力来编写、维护测试,同时增强了编程的信心。
  • 在测试人员消除了编程恐惧、具备编程基础后,安排测试人员与开发人员结对进行功能开发。

在这个过程中,必须首先要帮助测试人员正视编写程序的必要性以及消除恐惧,同时针对每天的工作内容留一些家庭作业效果也非常好。必须承认的事实是即便在完成轮换后,测试人员较开发人员还有一定距离,然而我们得到了一个意外的收获:进行过轮换后,再讨论需求时,测试人员越来越熟练的使用开发术语与团队交流,越来越多得参与讨论,甚至主导讨论,她开始直接引用核心组件的设计思想来推导测试用例,不断质疑和挑战开发人员,极大的提升了交流的效率和功能实现的质量。从经验数据看,大致需要3个月的时间测试人员可以达到在辅导下完成功能的程度。

订最后一颗纽扣

前端开发有其独特的知识领域,但这并不意味着任何界面工作都要由前端开发工程师来完成。前后端的分离增加了开发过程中的瓶颈以及人员认知领域中”Unknown Unknown”的区域,降低了找到更优解决方案的可能性。前端开发能力的培养特别适合在全团队中无差别的展开:让后端开发人员进行前端开发可以减少瓶颈,积累知识,构造“T”型知识区。测试人员需要测试界面,所以了解界面是如何工作,可以帮助她们设计出更高质量的用例,对于需求分析人员来说,高保真原型可以用作高效的交流工具。一个有效的方法是全面铺开,引入专家,重点培养,我们所采取的步骤是:

  • 要求全团队在业余时间完成一组界面练习,在全团队普及Html, Css和Javascript知识。
  • 引入界面开发专家重点培养一名有兴趣进行界面开发的团队成员,对系统的界面结对进行改进,优化。
  • 在界面开发专家的带领下,全员重新完成之前的界面练习,专家每天用一个小时讲解对应的前端技术并点评作业。

从全面普及知识到引入界面专家再到培养出新人,总共花费3周时间。值得一提的是,在整个过程中,由于之前团队建设的铺垫,其它成员有能力完全分担工作,团队重点培养的开发人员可以不受任何干扰,全职投入到前端开发中,最大程度的利用了界面开发专家的价值,提升了学习效果。

上同一艘船

项目经理是和技术领袖是作为现场管理者存在的,他们必须能够理解现场,能够通过现场的痕迹找到团队的不足和改进方向。那么,没有什么比卷起袖子参与到一线的工作中更能帮助这些角色理解现场。形成对产品质量和进度的亲身体验。理解现场,有效的管理现场而不是管理数据,是这些角色轮换到开发,测试或者分析工作的主要价值所在。现场管理人员常常有太多的职责,既要对内负责也得对外负责,一个自然而然的问题是:”没有时间投入一线工作“。我认为现场管理人员的工作主要是两个部分:首先是职位责所赋予的管理性事务,譬如状态的汇报,客户的管理等;其次是能力所赋予的工作,作为团队中最有经验的成员,他们需要参与到需求分析、架构设计、决策的制定、培训等活动中。基层管理者应当有意识的主动的卸下身上的工作职责,完成到一线角色的转换,从另一个角度看,这个过程就是整个团队能力提升的过程,个人经验是:

  • 对职位责所赋予的工作,首先做到对团队的状态、开发的进度等尽量的做到自动化、透明化、可视化,让所有人都能获得这些信息,其次通过知识传递,把不涉及敏感内容的工作下放,重点培养一两名团队成员参与管理。
  • 对能力所赋予的工作,一是针对团队急需提升的能力组织培训,二是通过结对工作(参见结对工作,不止于结对)传递知识,提升能力,让团队习惯于自行决策,有意识的逐步弱化自己在团队中的重要程度。

我们的经验数据是大约需要4个星期,新人可以在指导下正确的进行管理实践(正确的做事),这已经可以保证基层管理角色参与一线工作的时间;而让新人具备辨别团队目前需要什么帮助(作正确的事),进一步将原有的管理角色基本弱化为开发角色,则需要6个月左右的引导和练习。

结对工作,不止于结对

我完全认可结对工作在知识传递、提升工作正确性方面的作用。我们几乎结对作所有的事情,某种程度上结对工作成为一种文化,成为了思维惯性和一种必然。长期的结对工作让我发现目前的结对方式对于培养新人还不够友好,这里,新人所指代的是广义的新人概念,不仅仅指毕业生,刚刚从事测试工作的开发达人也算是测试新人。目前结对方式的的缺点在于:

  • 培养了思维惰性,心理上依赖于别人的带领。
  • 无法从失败中学习。有经验的人常常会跳过很多陷阱,新人的工作经历全是各种成功,一旦独立工作就被这些陷阱打的措不及防。
  • 只见树木不见森林。譬如在TDD的过程中,新手可以看到一个个的方法是如何被设计的,如何从测试中被驱动出来,但很难从他的搭档那里学会如何想到要设计这些方法?从下向上驱动还是从上向下,各有什么分别?为什么这个方法要被放在这个类,而不是那个?

我认为结对工作其中一个被忽略的要点在于让新人在可控的状态下经历失败,获取经验,并且在工作中学会思考问题的方式(如何发现问题?从何处着手?怎么在不同的方案中取舍?从哪里开从哪里开始分析?),而不仅仅是思考问题本身(写什么测试?如何让测试通过?)。从我的观察看,培养新人比较有效的途径是从全程结对工作开始,通过对细节的指导让新人了解工作的主要方式和职责,进行必要的知识贮备,学会如何正确的做事。接下来应当让新人逐渐学会什么是正确的事情。我们的做法是:

  1. 新人接到任务后,自行思考。
  2. 在白板上写下完成任务的主要步骤
  3. 向教练讲解主要思路和考虑点,教练通过提问引导他(输入特殊字符会怎样?)
  4. 自行完善方案
  5. 和教练一起确认方案
  6. 教练对整个思考过程进行点评,告诉新人这类问题的思考要点

整个过程大致耗时半个小时,这种方式的优点是新人对方案非常了解,执行起来不容易跑偏;有机会在可控范围内犯错,成长更快; 新人可以通过不断的练习有能力通过多个任务逐渐总结出一套思维方式。教练利用这种方法可以通过代码检视和有选择的结对(譬如针对任务中的难度部分结对)同时帮助多人,更有效率。

结局

在咨询的过程中,我见过太多的团队把目标放在交付上,寄希望于工具、外部力量,期望快速的解决问题,往往对小步前进不够耐心,不关心团队的成员。在我们这个 90%以上成员没有.Net经验,50%是毕业生的团队中,那些微不足道的改进,一点点的提升,最终造就了这个9个月中没有一天加班,几乎没有缺陷,提前交付的项目,客户甚至愿意为他们的满意额外支付3万美金作为奖励。我把全篇总结为一句话:把项目目标放在人员能力提升,让项目成功成为能力提升的副产物。

本文转自:http://www.infoq.com/cn/articles/hk-build-full-function-team-practice

Share

基于微服务架构,改造企业核心系统之实践

1. 背景与挑战

随着公司国际化战略的推行以及本土业务的高速发展,后台支撑系统已经不堪重负。在吞吐量、稳定性以及可扩展性上都无法满足日益增长的业务需求。对于每10万元额度的合同,从销售团队准备材料、与客户签单、递交给合同部门,再到合同生效大概需要3.5人天。随着业务量的快速增长,签订合同的成本急剧增加。

合同管理系统是后台支撑系统中重要的一部分。当前的合同系统是5年前使用.NET基于SAGE CRM二次开发的产品。 一方面,系统架构过于陈旧,性能、可靠性无法满足现有的需求。另一方面,功能繁杂,结构混乱,定制的代码与SAGE CRM系统耦合度极高。由于是遗留系统,熟悉该代码的人早已离职多时,新团队对其望而却步,只能做些周边的修补工作。同时,还要承担着边补测试,边整理逻辑的工作。

1

在无法中断业务处理的情况下,为了解决当前面临的问题,团队制定了如下的策略:

  1. 在现有合同管理系统的外围,构建功能服务接口,将系统核心的功能分离出来。
  2. 利用这些功能服务接口作为代理,解耦原合同系统与其调用者之间的依赖;
  3. 通过不断构建功能服务接口,逐渐将原有系统分解成多个独立的服务。
  4. 摒弃原有的合同管理系统,使用全新构建的(微)服务接口替代。

2. 什么是微服务

多年来,我们一直在技术的浪潮中不断乘风破浪,扬帆奋进,寻找更好的方式构建IT系统。微服务架构(Micro Service Architect)是近一段时间在软件体系架构领域里出现的一个新名词。它通过将功能分解到多个独立的服务,以实现对解决方案或者复杂系统的解耦。

微服务的诞生并非偶然: 领域驱动设计指导我们如何分析并模型化复杂的业务;敏捷方法论帮助我们消除浪费,快速反馈;持续交付促使我们构建更快、更可靠、更频繁的软件部署和交付能力;虚拟化和基础设施自动化( Infrastructure As Code)则帮助我们简化环境的创建、安装;DevOps文化的流行以及特性团队的出现,使得小团队更加全功能化。这些都是推动微服务诞生的重要因素。

实际上,微服务本身并没有一个严格的定义。不过从业界的讨论来看,微服务通常有如下几个特征:

小,且专注于做一件事情

每个服务都是很小的应用,至于有多小,是一个非常有趣的话题。有人喜欢100行以内,有人赞成1000行以内。数字并不是最重要的。仁者见仁,智者见智,只要团队觉得合适就好。只关注一个业务功能,这一点和我们平常谈论的面向对象原则中的”单一职责原则”类似,每个服务只做一件事情,并且把它做好。

运行在独立的进程中

每个服务都运行在一个独立的操作系统进程中,这意味着不同的服务能被部署到不同的主机上。

轻量级的通信机制

服务和服务之间通过轻量级的机制实现彼此间的通信。所谓轻量级通信机制,通常指基于语言无关、平台无关的这类协议,例如XML、JSON,而不是传统我们熟知的Java RMI或者.Net Remoting等。

松耦合

不需要改变依赖,只更改当前服务本身,就可以独立部署。这意味着该服务和其他服务之间在部署和运行上呈现相互独立的状态。

综上所述,微服务架构采用多个服务间互相协作的方式构建传统应用。每个服务独立运行在不同的进程中,服务与服务之间通过轻量的通讯机制交互,并且每个服务可以通过自动化部署方式独立部署。

3.微服务的优势

相比传统的单块架构系统(monolithic),微服务在如下诸多方面有着显著的优势:

异构性

问题有其具体性,解决方案也应有其针对性。用最适合的技术方案去解决具体的问题,往往会事半功倍。传统的单块架构系统倾向采用统一的技术平台或方案来解决所有问题。而微服务的异构性,可以针对不同的业务特征选择不同的技术方案,有针对性的解决具体的业务问题。

对于单块架构的系统,初始的技术选型严重限制将来采用不同语言或框架的能力。如果想尝试新的编程语言或者框架,没有完备的功能测试集,很难平滑的完成替换,而且系统规模越大,风险越高。基于微服务架构,使我们更容易在遗留系统上尝试新的技术或解决方案。譬如说,可以先挑选风险最小的服务作为尝试,快速得到反馈后再决定是否试用于其他服务。这也意味着,即便对一项新技术的尝试失败,也可以抛弃这个方案,并不会对整个产品带来风险。

2

该图引用自Martin Fowler的Microservices一文

独立测试与部署

单块架构系统运行在一个进程中,因此系统中任何程序的改变,都需要对整个系统重新测试并部署。 而对于微服务架构而言,不同服务之间的打包、测试或者部署等,与其它服务都是完全独立的。对某个服务所做的改动,只需要关注该服务本身。从这个角度来说,使用微服务后,代码修改、测试、打包以及部署的成本和风险都比单块架构系统降低很多。

按需伸缩

单块架构系统由于单进程的局限性,水平扩展时只能基于整个系统进行扩展,无法针对某一个功能模块按需扩展。 而服务架构则可以完美地解决伸缩性的扩展问题。系统可以根据需要,实施细粒度的自由扩展。

错误隔离性

微服务架构同时也能提升故障的隔离性。例如,如果某个服务的内存泄露,只会影响自己,其他服务能够继续正常地工作。与之形成对比的是,单块架构中如果有一个不合格的组件发生异常,有可能会拖垮整个系统。

团队全功能化

康威定律(Conway’s law)指出:一个组织的设计成果,其结构往往对应于这个组织中的沟通结构(organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations)。传统的开发模式在分工时往往以技术为单位,比如UI团队、服务端团队和数据库团队,这样的分工可能会导致任何功能上的改变都需要跨团队沟通和协调。而微服务则倡导围绕服务来分工,团队需要具备服务设计、开发、测试到部署所需的所有技能。

4. 微服务快速开发实践

随着团队对业务的理解加深和对微服务实践的尝试,数个微服务程序已经成功构建出来。不过,问题同时也出现了:对于这些不同的微服务程序而言,虽然具体实现的代码细节不同,但其结构、开发方式、持续集成环境、测试策略、部署机制以及监控和告警等,都有着类似的实现方式。那么如何满足DRY原则并消除浪费呢?带着这个问题,经过团队的努力,Stencil诞生了。 Stencil是一个帮助快速构建Ruby微服务应用的开发框架,主要包括四部分:Stencil模板、代码生成工具,持续集成模板以及一键部署工具。

3

Stencil模板

Stencil模板是一个独立的Ruby代码工程库,主要包括代码模板以及一组配置文件模板。

代码模板使用Webmachine作为Web框架,RESTful和JSON构建服务之间的通信方式,RSpec作为测试框架。同时,代码模板还定义了一组Rake任务,譬如运行测试,查看测试报告,将当前的微服务生成RPM包,使用Koji给RPM包打标签等。

除此之外,该模板也提供了一组通用的URL,帮助使用者查看微服务的当前版本、配置信息以及检测该微服务程序是否健康运行等。

[
    {
        rel: "index",
        path: "/diagnostic/"
    },
    {
        rel: "version",
        path: "/diagnostic/version"
    },
    {
        rel: "config",
        path: "/diagnostic/config"
    },
    {
        rel: "hostname",
        path: "/diagnostic/hostname"
    },
    {
        rel: "heartbeat",
        path: "/diagnostic/status/heartbeat"
    },
    {
        rel: "nagios",
        path: "/diagnostic/status/nagios"
    }
]

配置文件模板主要包括NewRelic配置,Passenger配置、Nagios配置、Apache配置以及Splunk配置。通过定义这些配置文件模板,当把新的微服务程序部署到验收环境或者产品环境时,我们立刻就可以使用Nagios、NewRelic以及Splunk等第三方服务提供的功能,帮助我们有效的监控微服务,并在超过初始阈值时获得告警。

代码生成工具

借助Stencil代码生成工具,我们能在很短时间内就构建出一个可以立即运行的微服务应用程序。随着系统越来越复杂,微服务程序的不断增多,Stencil模板和代码生成工具帮助我们大大简化了创建微服务的流程,让开发人员更关注如何实现业务逻辑并快速验证。

Create a project from the stencil template (version 0.1.27)
        --name, -n <s>:   New project name. eg. things-and-stuff
        --git-owner, -g <s>:   Git owner (default: which team or owner)
        --database, -d:   Include database connection code
        --triggered-task, -t:   Include triggered task code
        --provider, -p:   Is it a service provider? (other services use this service)
        --consumer, -c:   Is it a service consumer? (it uses other services)
        --branch, -b <s>:   Specify a particular branch of Stencil
        --face-palm, -f:   Overide name validation 
        --help, -h:   Show this message

如上代码所示,通过指定不同参数,我们能创建具有数据库访问能力的微服务程序,或者是包含异步队列处理的微服务程序。同时,我们也可以标记该服务是数据消费者还是数据生产者,能帮助我们理解多个微服务之间的联系。

持续集成模板

基于持续集成服务器Bamboo,团队创建了针对Stencil的持续集成模板工程,并定义了三个主要阶段:

  • 打包:运行单元测试,集成测试,等待测试通过后生成RPM包。
  • 发布:将RPM包发布到Koji服务器上,并打上相应的Tag。然后使用Packer在亚马逊 AWS云环境中创建AMI,建好的AMI上已经安装了当前微服务程序的最新RPM包。
  • 部署:基于指定版本的AMI,将应用快速部署到验收环境或者产品环境上。

利用持续集成模板工程,团队仅需花费很少的时间,就可以针对新建的微应用程序,在Bamboo上快速定义其对应的持续集成环境。

一键部署工具

所有的微服务程序都部署并运行在亚马逊AWS云环境上。同时,我们使用Asgard对AWS云环境中的资源进行创建、部署和管理。 Asgard是一套功能强大的基于Web的AWS云部署和管理工具,由Netflix采用Groovy on Grails开发,其主要优点有:

  • 基于B/S的AWS部署及管理工具,使用户能通过浏览器直接访问AWS云资源,无需设置Secret Key和Access Key;
  • 定义了Application以及Cluster等逻辑概念,更清晰、有效地描述了应用程序在AWS云环境中对应的部署拓扑结构。
  • 在对应用的部署操作中,集成了AWS Elastic Load Balancer、AWS EC2以及AWS Autoscaling Group,并将这些资源自动关联起来。
  • 提供RESTful接口,能够方便地与其他系统集成。
  • 简洁易用的用户接口,提供可视化的方式完成一键部署以及流量切换。

由于Asgard对RESTful的良好支持,团队实现了一套基于Asgard的命令行部署工具,只需如下一条命令,提供应用程序的名称以及版本号,就可自动完成资源的创建、部署、流量切换、删除旧的应用等操作。

asgard-deploy [AppName] [AppVersion]

同时,基于命令行的部署工具,也可以很容易的将自动化部署集成到Bamboo持续集成环境。

通过使用微服务框架Stencil,大大缩短了团队开发微服务的周期。同时,基于Stencil,我们定义了一套团队内部的开发流程,帮助团队的每一位成员理解并快速构建微服务。

微服务架构下的新系统

经过5个月的努力,我们重新构建了合同管理系统,将之前的产品、价格、销售人员、合同签署、合同审查以及PDF生成都定义成了独立的服务接口。相比之前大而全、难以维护的合同管理系统而言,新的系统由不同功能的微服务组成,每个微服务程序只关注单一的功能。每个微服务应用都有相关的负责人,通过使用Page Duty建立消息通知机制。每当有监控出现告警的时候,责任人能立即收到消息并快速做出响应。

4

由于微服务具有高内聚,低耦合的特点,每个应用都是一个独立的个体。当出现问题时,很容易定位问题并解决问题,大大缩短了修复缺陷的周期。另外,通过使用不同功能的微服务接口提供数据,用户接口(UI)部分变成了一个非常简洁、轻量级的应用,更关注如何渲染页面以及表单提交等交互功能。

总结

通过使用微服务架构,在不影响现有业务运转的情况下,我们有效的将遗留的大系统逐渐分解成不同功能的微服务接口。同时,通过Stencil微服务开发框架,我们能够快速地构建不同功能的微服务接口,并能方便地将其部署到验收环境或者产品环境。最后,得益于微服务架构的灵活性以及扩展性,使得我们能够快速构建低耦合、易扩展、易伸缩性的应用系统。

参考文献

  1. http://martinfowler.com/articles/microservices.html
  2. http://jaxenter.com/cracking-microservices-practices-50692.html
  3. http://microservices.io/patterns/microservices.html
Share