时间的回报

回报加速定律

在2017年咨询师会议上,我们提出了“智能原生”的口号,自然会去想人工智能未来会怎么样。其中一个令人恐慌的预测是“奇点”,奇点的意思是有一天电脑会比人聪明一点点,然后会更加极速的发展到比人聪明很多,直到完全控制人类。奇点预测背后的原理是Ray Kurzweil在2011年提出的回报加速定律(The Law of Accelerating Returns)。

回报加速定律通过分析人类文明的发展历程,发现人类发展不是线性,而是指数发展。原理也很简单,即发展的回报会加速发展。

最有名的例子是摩尔定律,芯片运算能力每18个月翻一番。10年前iPhone刚刚发布,摄像头只有200万像素, 现在新一代的旗舰手机一般都会搭载2000万像素的摄像头。10年前最先进大型机的图像识别技术可以分辨出兔子和茶壶,而且准确率还不怎么高,2017年新一代的iPhone X已经能离线进行脸部识别。

2017年的电脑智能水平大概比昆虫要高一点了,因为有了先进的电脑等设备(生产力提高),使得生产更先进的设备加速(生产效率提高),预测2022年比老鼠聪明,2030年比一个人聪明,而大概到2050年将比所有人类都聪明。

​(图片来自:http://t.cn/RQSRzFR

加速回报定律可以说是系统正向反馈循环的一个洞见。比如马太效应,在《圣经·新约》的“马太福音”第二十五章中有这么说道:“凡有的,还要加给他,叫他多余;没有的,连他所有的,也要夺过来。”。通俗讲就是有钱的更有钱,没钱的继续没钱。还有比如滚雪球也是同样的意思,亚马逊所信奉的飞轮理论也是差不多的意思。

系统反馈循环有正向,也有负向反馈。

技术债与破窗理论

我们在给客户做敏捷转型技术咨询的时候总是会遇到技术债的问题,即系统中的烂代码和强耦合。

技术债,这个词是个很伟大的发明,只是很少有人能理解其中的含义。只是把它当做烂代码的另一个代名词。

技术债的产生源自人的能力不足或者因为资源有限赶进度而牺牲代码质量,技术债并非完全不好。这跟公司或者个人负债是一样的,可以通过承担负债获取短期收益。然而不幸的是,因为低估甚至不理解技术债所产生的代价,人们往往会选择即使在有资源的情况下仍然忽视技术债、并且不偿还。

烂代码之所以叫技术债,是因为会随着时间会产生额外的代价。今天写一段烂代码不及时修复会引出更多的烂代码,因为后来写代码的人会仿造之前的代码,或者为了绕过烂代码而产生额外的烂代码,使得整个系统陷入烂代码泥浆。我们客户的很多系统寿命不超过3年,不是因为业务变化,而是系统实在太烂无法维护了,只能重新做一个。

讲技术债也许太技术了,另一个很通俗的例子是破窗理论。讲如果一栋大楼的一个窗户破了不及时修复,会引起边上的窗户加速破损。我最近就遇到一个类似的例子,一个公共场所边上的角落有一些垃圾,过了一会有人拿着垃圾四处找了一下没找到垃圾桶,就把新的垃圾丢带了那个角落。如果这个角落一直没人清理,可以想象不需要一个星期就变成垃圾角了,甚至有人会大老远跑过来把垃圾往这个角落扔。

我觉得不理解或忽视技术债的人不是因为不懂技术,而是因为不敬畏时间的代价。

(图片来自:http://t.cn/RQS8QVp

关于系统反馈还有一个很热门的话题,也许跟时间只是恰好有关,即天才一万小时定律。

一万小时天才定律

一万小时定律解释天才之所以卓越非凡,并非天资超人一等,而是付出了持续不断的努力;只要经过1万小时的锤炼,任何人都能从平凡变成超凡;要成为某个领域的专家,需要10000小时,按比例计算就是:如果每天工作八个小时,一周工作五天,那么成为一个领域的专家至少需要五年。

这个同样基于统计的定律非常有意思,我觉得也很有用。人们常常会低估或者忘记回报加速定律、技术栈/破窗理论中时间的作用,对于一万小时天才定律往往只关注时间。世界上有太多人在同一个领域日复一日年复一年工作五年、十年、数十年,然而专家还是只是少数人。原因是什么呢——缺乏正向反馈回路。

收尾

前面讲了三个跟时间相关的系统回路定律,时间的回报有可能是正向也可能负向,更可能会加速。


更多精彩文章,请关注微信公众号:软件乌托邦

Share

精益价值、原则和软件实践(下)

所谓的精益思想的价值和原则非常多,这里引用ThoughtWorks同事Jonny Schneider即将出版的《Understanding Design Thinking, Lean,and Agile》, 通过日常软件开发实践来补充这些看起来很虚的价值和原则,以此推广“精益”成为更好的软件开发指导思想。这是下篇,上篇在这里

我们来简单回顾一下上篇:

价值一:学习和适应 优于 分析和预测

  • 通过实践验证假设,而不是分析和计划
  • 延迟决策到最后一刻
  • 刻意练习科学思维

价值二:赋权的人更快乐并容易取得更好的成果

  • 定义清晰的目标,信任团队并给予自主去取得成果
  • 去中心化决策

价值三:成果优于输出

  • 衡量交付的价值,而不是做了多少工作
  • 明确价值并经常度量

本篇将继续讲述价值四和价值五。

价值四:管理流动优化价值

  • 减少批次大小
  • 管理队列
  • 交付速度
  • 减少浪费
  • 响应客户的需求 优于 创造库存

减少批次大小

如果要我说软件开发管理中最重要的工作是什么,我觉得应该是减少批次大小。

软件管理中存在很多问题,比如需求不明确、需求易变、开发估算不准确、难测试、上线后发现没有真实价值等。

这些问题其实都可以靠减少批次大小来解决,我一般建议把User Story分解到1~2人天(当然还是要用故事点的方式,不能直接用人天来估算),这样的好处是:

  • 故事小对应的需求范围也小,比较容易明确;
  • 又因为需求小,变了也不可惜;
  • User Story小更容易暴露开发过程中的问题,比如把计划一天的任务分派给新人做,即使超出原计划的100%工作量其实也就是多了一个人天,这样团队可以及时干预;
  • 只有一两天的工作也更能消除“一天完成90%,剩下的10%需要一个星期完成”的进度报告问题。或者是一个人同时做很多事情,但都没法交付;
  • 需求小也更容易测试,能更快上线给真实用户。

微服务架构更加强化了减少批次大小的诉求和价值,达到更小的需求、更快的响应、更稳定的交付流速。

管理队列

批次大的时候,一个人好像只在处理一个事情。但实际上人脑容量有限,还是会把一件大的事情分解成多个小事情做,只是无意识的做而已。Scrum的管理方式比较粗暴,看上去只有Sprint backlog一个队列,因为在迭代会议的时候把事情都分配给开发人员了。所以对于Scrum这样的管理框架来说看不到什么队列,这样有什么问题吗?

因为人脑的局限,事情总是会溢出在外面,实际上就造成有个隐形的队列存在,只是没人刻意去管,这就造成有些人盲目的忙,有些人井井有条的干活,纯粹看个人意识。

隐形任务队列的坏处:

  • 任务间穿插、相互影响效率。一个人最佳的工作效率产生于同一时间聚焦做一件事情。但由于事情过大,看起来是在做一件事情,其实是还是处理多个事件,然后思路在不同的事情上面跳跃穿插,造成做事效率低下;
  • 不分任务轻重缓急。其实很多看似紧急的事情,都是因为一开始不做,到需要了才开始做就没时间了,搞得压力很大。比如客户突然过来问XXX事情进行得怎么样了,想明天看一下。你心里立刻开始跑马,“你们咋不早说啊,这事还没开始做呢!” 但从客户的角度讲,这个事情在两个星期前就安排了啊,而且说了很重要。但因为队列是隐形的,大家都只是脑子过一下,或嘴上说一下就过去了,全靠个人意识去处理。
  • 掩盖问题。一个人或团队手上一堆事情,然后有些出现了问题阻塞进展,但因为是隐形队列,很容易导致大家都“忽视”问题,直到所有的任务都遇到同一个阻塞点。隐形的队列越大,掩盖的问题也越大。这个问题特别严重也最常见,我们经常会听见客户说自己没有问题,因为表面上大家都在做开发没遇到问题,只是到了一个月交付的时候拖延一个星期才能交付出去而已,已经是习惯了,这也很正常啊。但是稍微聊一下就会发现需求不明确,沟通不顺畅,缺乏自动化测试,质量不稳定,手工运维经常出点“小”问题等等,这些问题其实每天都在发生,但都可以一直掩盖到最后一刻才暴露出来。

所以首先应该把任务队列显性化,要用团队的能力和意识来管理队列,而不是让个人去随便搞。

然后才是队列管理技巧,比如优先级调整,任务依赖关系管理,阻塞点识别和清除。

在精益里面有个很重要的原则,叫限制在制品数量,意思是要严格限制正在进行的任务队列大小,这样就能很容易的识别阻塞点,及时处理,并且更容易控制交付流速。

交付速度

在讲TDD特有价值的时候我提出其中了两个:

  1. 质量
  2. 可维护性

但怎么衡量这两个指标呢,尤其是可维护性。我觉得可以归到“交付速度”一个指标上。我们不把修bug当做价值而是当作浪费,这样质量差的软件开发,必然导致交付资源会被修bug挤占,从而影响交付速度。

软件的可维护性也会体现在交付速度上,做的好的软件交付速度会越来越快。因为该做的基础工作都逐渐完善,开发人员的领域知识和开发技能也逐渐提高。

然而很不幸的,能逐渐提升交付速度的团队很少,理由往往是需求越来越复杂啊,以前都没提有这样的需求现在要大改啊什么的。而且没人正在度量交付速度,所以只是开发人员和客户都抱怨罢了。

减少浪费

以前西方流行的精益观念认为“减少浪费”是精益思想的精髓,然后有非常全面的识别和消除浪费的方法。

我觉得减少浪费是精益思想的很小一部分,就像我们想增加收入要做开源节流。不能认为节流能增加收入就当做主要手段用,导致影响开源。但很不幸的是节流比开源要容易很多,所以很多企业在危机时刻很容易选择节流而导致开源不利。

比如只从业务功能角度讲,搭CI/CD所花的时间是浪费掉的,因为没有直接产出业务价值。

减少浪费的观念确实非常有用,能有效指导消除不必要的工作。

响应客户需求 优于 创造库存

我发现开发团队很喜欢创造库存,有一些原因:

  • 库存带来安全感;因为开发团队总是被客户挑战,手上拿几个已完工的需求会觉得到时候有货交差会很好。
  • 库存里的东西不用马上验证,自己认为总是对的;
  • 库存里面堆什么可以自己决定;人总是会倾向做自己熟悉或感兴趣的事情,而总是响应客户需求的话可能会被迫出舒适区。比如很多业务系统一上来就做个用户管理模块,虽然看起来这些基础模块是必须的,但在一开始的时候对客户业务人员来说真的是必须的吗,如果只有一两个用户明显可以工作,那硬写在代码里就可以了。
  • 管理者不想让开发人员闲着;尽管当前没有明确的客户需求,管理者为了不让开发人员闲着,也会要求做一些有的没的需求,号称以后用的上。
  • 客户不愿意频繁接收需求;这种情况多是因为客户接低质量的需求接怕了,所以拒绝频繁接,以为让完工的软件在库存里多呆一会质量会自动提高;第二是可以一鼓作气去应对低质量的需求,集中时间处理麻烦事。

敏捷宣言用了很大的比重来强调拥抱变化响应客户需求,很好地改变了软件开发团队和客户之间的信任关系。但是并没有什么方法很好的去响应客户需求,要不然Scrum这种固定时间盒的方法也不会大行其道了。

精益的拉动式流管理是完全面向客户的,利用客户需求驱动团队工作。而且只有需求交付到客户手上才算是完成了,使得软件尽早产生业务价值,这也是MVP思想的来源。

价值五:质量是结果而不是活动

  • 内建质量
  • 持续学习和改进
  • 追求完美

内建质量

内建质量就不多说了,是我们倡导的实践口号,只是需要配合质量度量和持续改进,不然就只是口号了。

持续学习和改进

除了交付客户所需的价值,对我们来说更重要的是团队个人能力的提升。因为软件交付给客户价值后,对我们的价值(钱)也就结束了,唯有团队个人在交付的过程中不断提升,才能提升公司的整体价值和竞争力。

在敏捷管理里面设置回顾会议以支持持续改进,而且更关注问题和解决问题。为什么要等一个月或两个星期才做一次回顾会议呢? 固定时间、固定任务、做固定的事情好处是能有一种仪式感,容易协调不同人的时间和工作内容。但因为反馈周期太长,算不上持续,只能说是断断续续的学习和改进。

其实最好的学习和改进机会是做到on demand,发现问题及时处理问题,如果处理不了及时提出来引起团队的注意。另外每日站会和每日code review都是固定的时间点,可以用来做学习和改进。

学习和改进的内容不仅仅是软件代码、架构设计、需求质量,还有协作方式、甚至座位安排、客户对接方式、价值排序原则等。

追求完美

可能对于一个商业组织来说,追求完美是最正确又是最错误的事情。因为很容易陷入闭门造车,导致投入产出比失衡,造成亏损。

但精益思想并不是一个点,而是一组。我总结的精益思想的哲学是以客户为中心,持续自我改善,追求长期利益(完美)。

每个人或组织心中应该有个对“完美”的定义,以此为愿景进行长期可持续追求,但由于是企业,所以要以客户为中心。当然基础还是富有激情的个人在每时每刻进行持续学习和改进,以达到个人的完美。


跟多精彩文章,请关注微信公众号:软件乌托邦

Share

精益价值、原则和软件实践(上)

所谓精益思想的价值和原则非常多,我这里引用ThoughtWorks同事Jonny Schneider即将出版的《Understanding Design Thinking,Lean,and Agile》, 试图通过日常软件开发实践来补充这些看起来很虚的价值和原则,希望能推广精益成为更好的软件开发指导思想。

价值一: 学习和适应 优于 分析和预测

原则:

  • 通过实践验证假设,而不是分析和计划
  • 延迟决策到最后一刻
  • 刻意练习科学思维

通过实践验证假设,而不是分析和计划

我们都知道邓小平说“实践是检验真理的唯一标准”,但在软件开发的时候往往都忘了这句话。 软件开发是一个需要高度协作的工作,涉及到想法提出、需求分析、设计和实现、测试和交付、价值验证,又因为每个环节被要求做到最好,结果就很容易陷入局部打转,进行低效的分析和计划中。

比如领导提出的一个想法,就马上变成正式需求进行大规模实施,然而没有经过验证的想法只是个价值假设,我们需要先把想法进行实践验证才能确定想法是有价值的。但是有更坏的一种情况,就是大家都有想法,但就是一直分析分析而没有任何行动。这种情况比一有想法就进行盲目的行动还要坏得多,盲目行动后至少能知道一条路是不通的,一直在原地打转却是实实在在的浪费精力和时机。

每个项目基本上都会抱怨需求多、需求不稳定,于是就加大对需求的分析投入。但过犹不及,开发团队有时候会没有具体的需求做,因为需求还在分析中。然而我又没见过一个需求分析能做到完全清晰不需要在开发阶段再进行分析和澄清的,所以INVEST原则的第二条,就是能沟通,而不是要求把需求做到尽善尽美。INVEST原则的最后一条是可测试,来验证”Done”,而不要开发扯皮说“我就是根据你说的做完了啊,怎么这个需求又变了。”

延迟决策到最后一刻

我反对Scrum管理方式的一个原因是Scrum设置了一个所谓的时间盒,在这个时间盒里面开发工作不能被打断。首先我没见过不打破时间盒的实践,第二,时间盒的概念违反敏捷宣言中“欣然面对需求变化”的原则,时间盒只是换了个花样拒绝需求变化而已。

另外Scrum又要求进行工作量评估用来做计划,然而我们知道评估工作量基本上是很扯淡的事情,基本上误差在100%以上。而且团队的产能是固定的,不知道做计划的价值是什么。

我比较同意做粗粒度的时间里程碑规划,用来规划几个特别重要的需求,而对于日常的管理工作完全没必要做计划。

具体来说就是,延迟决策到最后一刻,开发团队什么时候做下一个需求应该由什么时候做完上一个需求决定。先做哪个需求应该等到需求马上就要进入开发状态了再做决定。而不是做个Sprint计划用一天时间把一两个星期的决策都做了。

刻意练习思维方式

用Kata训练思维方式。很多时候我们所谓的知道了,其实只是记住了一些名词和解释,并没有领悟内涵。就像有很多争论的TDD一样,可能很多人没有刻意练习过TDD,并不知道TDD到底好不好,优缺点是什么,只是因为听说TDD好或TDD不可行,就给自己下了个结论。

软件开发中有很多是手艺的问题,需要手脑协同完成。我说应该把重构剥离出TDD,同事杨云说重构是软件开发的习惯,无所谓剥不剥离。就是说重构已经成为杨云进行软件开发的行为习惯,看到bad smell就会自然感觉不爽从而进行重构一把。但是对于新手来说,这不是看完《重构》就能学到的,需要刻意的练习。Pair programming和code review都是新手刻意练习重构的好时机。

价值二: 赋权的人更快乐并能取得更好的成果

原则:

  • 定义清晰的目标,信任团队并给予自主去取得成果
  • 去中心化决策

定义清晰的目标,信任团队并给予自主去取得成果

我们还是讲一个好的需求应该用User Story的方式进行阐述,而好的User Story最重要的特点是要求陈述需求的价值,而不只是说想要什么,更要说想要什么背后的目的。

所以有时候我们会拒绝客户的“需求”(其实是客户提出的解决方案),用更少的成本达到客户更大的业务价值。

去中心化决策

日常的软件开发中经常会有一些团队级别的公共事件,比如每日站会的主持、CI纪律责任、回顾会议主持和纪要等。比如Scrum就要搞一个Scrum Master来主持每日站会。但是这些所谓的公共事件,其实除了要做什么事情,背后还有一些不大不小的决策。

如果我们不把决策权给到团队,而是握在所谓的XX Manager手上,就会导致决策信息和决策执行分离,变成敏捷里面鸡和猪的故事,引发团队内的不信任和冲突。决策和执行不一定要同一个人,但需要大家都在一个战壕里面能感同身受,能即时根据情况进行变化。

价值三:成果 优于 输出

  • 衡量交付的价值,而不是做了多少工作
  • 明确价值并经常度量

衡量交付的价值,而不是做了多少工作

有个俗语叫“没有功劳也有苦劳”,然而问题是我们往往衡量苦劳而不衡量功劳。

这要说世界是多么的不公平,有些人辛苦付出却一无所获,有些人轻轻松松却满载而归。

马云说,轻松付出就能满载而归的人是福将,应该多用。

因为business is business,我们不是弱势群体互助会,而是拿人钱财替人解决问题的商业组织。

虽然这个话说起来很简单,但往往因为外部的交付价值变数多并难以衡量,而内部做了多少工作比较明确。

比如经常要加班到几点几点,前天昨天又通宵了什么的,搞得自己很敬业,其实是在唱悲情戏。

如果唱悲情戏能在企业获得认可,我觉得无论对于个人还是企业都是悲哀的。即使是在华为这样的企业,非常强调奋斗,天天加班,但在衡量绩效的时候也还是拿实际产出说话,而不会因为谁加班多(但没产出)就多给钱。(当然我不反对加班, 因为有时候加班确实能交付更多的价值)

有些人代码写得不好,经常出bug,一出bug还找不到原因,跟无头苍蝇似的乱找,搞得自己很辛苦,对客户来说其实价值很低,甚至是负产出。但如果以工作态度或工作量衡量,这种人反而应该得到嘉奖。所以公平其实是相对的,要看从哪个角度去看,精益思想认为应该从外部价值来看。

明确价值并经常度量

什么是价值?

可能很多人会说,但又明确不了,就更不要说经常度量了。

我觉得我们的重要价值是高响应力、高质量、可持续维护的软件,然后应该度量每个交付项目,看看是否获得了重要价值

比如外部缺陷率是否很少并持续降低(并持续增加需求),需求响应力是否持续提高,维护成本是否持续降低?

这些指标都可以在精益价值流中明确的度量和展现出来。

—未完待续—

价值四:管理流动优化价值

  • 减少批量大小
  • 管理队列
  • 交付速度
  • 减少浪费
  • 响应客户的需求 优于 创造库存

价值五:质量是结果而不是活动

  • 内建质量
  • 持续学习和改进
  • 追求完美

更多精彩内容,请关注微信公众号:软件乌托邦

Share

认识微服务——一颗银弹

微服务架构是一颗银弹吗?

如今微服务架构正逐渐演变成一种主流的架构风格,那么微服务架构是一颗银弹吗?我们提倡微服务架构的目的是什么?

1987 IBM大型机之父Fred Brooks在《没有银弹:软件工程的本质性与附属性工作》中提出软件工程包括本质性工作和附属性工作。本质性工作是创造出一种由抽象的软件实体所组成的复杂概念结构;附属性工作是用程序语言来表达抽象概念,并在空间和时间的限制下,翻译成机器语言。《没有银弹》主张并断言在未来的十年之内(从1986年文章发表后开始计算),不会有任何单一软件工程上的突破,能够让程序开发的生产力得到一个数量级(10倍)的提升。

我们讨论或推广一项软件实践或技术的时候,实际上是在谈如何提高生产力。本文试图利用《没有银弹》对本质性工作四个原因的归类,去认识微服务架构的生产力。《没有银弹》认为本质性工作大部分的活动是发生在人们的脑海里,具有四大难题:复杂性、隐匿性、配合性和易变性。

软件工程的本质性难题

1、复杂性

软件要解决的问题通常牵扯到多种元素和计算步骤,这是一种人为的、抽象的智能活动,多半是复杂的。随着“软件吞噬世界”不断深入,软件所对应的社会活动越来越多,也越来越复杂。

单体架构系统的困境

系统往往是承载的业务越成功,越容易失败。因为系统会随着业务的发展,增加越来越多的特性和功能,使得系统复杂到没有一个人能全面理解,没有一个人敢去修改原有的功能或代码。

微服务的救赎

微服务提出以业务边界作为模块划分原则,每个模块独立进程。一个业务由很多独立的小业务组合而成,系统也是由独立的小系统组合而成,这样的好处是每个小系统都很容易被理解,一个大系统可以根据业务组合微服务,或者逐渐发展独立的微服务。

微服务救赎的代价

但是微服务架构真的降低了系统的复杂性吗? 其实并没有, 而且是增加了系统的总体复杂性!

微服务之间的连接更加复杂,网络通讯不可靠和性能损耗,协议匹配,接口对接和转换,版本协作,微服务注册和发现,编排和调度,分布式业务和数据一致性等等复杂性都是单体架构不需要考虑的。

微服务为了降低单个微服务的复杂性,导致整体系统的复杂性急剧增加。

如果单体架构根据业务进行模块划分,每个模块之间根据宿主语言接口进行交互,就像OSGi那样模块化/插件架构完全可以做到模块化开发。

那么为了降低系统复杂性,是不是放弃使用微服务? 答案既是肯定也是否定。

我们刚才发现微服务架构带来的复杂性,大多是附属性问题。对于本质性复杂性,微服务使用上下文界限实践,可以更好的隔离依赖业务概念的复杂性,从而降低单个微服务的复杂性。

利弊权衡

既然有得有失,我们是否需要做个权衡?

《没有银弹》的主张只说对了一半,10年内对于本质性问题确实是不会有十倍生产力的提高。但历史上来看,附属性问题是有十倍生产力提高的。 而我们在软件工程实践中,往往本质性问题和附属行问题混合在一起,我们需要不断的加深认识,区分两者,并相互改进。

微服务架构带来的附属性复杂性必须要有一个功能齐全的PaaS进行转移。

微服务推广初期(包括现在)所面临的很多问题,其实是缺乏一个功能齐全的PaaS,比如AWS/Azue,Rancher/OpenShrift,用以解决附属性问题。

所以我们不需要做太多的利弊权衡,因为PaaS日趋成熟,成本将降到几乎可以忽略不计。微服务架构利用PaaS对附属性问题的转移,降低一点点本质性问题的复杂性,也是非常价值的。只是发挥这种价值,需要掌握DDD设计实践,利用好上下文界限来降低单个微服务的本质性复杂性。

2、隐匿性

软件在没有应用到业务之前,各种信息和思考大多在每个人的脑海里,很难完全呈现和想象出来。客户只是模糊的知道自己想要什么,但并不知道要怎样的软件;项目经理有把握软件开发进度的能力,但不知道软件每个阶段后能长成什么样;业务分析员能把业务分析清楚但不能确认转变成最终软件会成为什么样;开发设计人员知道怎么做软件,但又不能完全理解业务需求。

单体架构系统的困境

单体架构中的各个模块隐藏在大系统的页面下,在交付之前对外界是不可见的。 更麻烦是单体架构往往是按技术维度进行分层设计,导致没有人能看清全貌,各自都想把事情做到最好,但组合起来却不是客户想要的东西。

微服务的救赎

微服务强调小、独立业务价值,独立进程独立部署交付,使软件尽快尽早得交付到最终用户手中,来交付和验证业务价值。

微服务架构并没有改变软件开发过程中的隐匿性,而是通过缩短从需求到交付这段软件开发周期,减少隐匿时间,来降低软件工程总体的隐匿性。

利弊权衡

听起来快速交付很好,但会有什么问题吗?

组织必须要具备自动部署持续交付能力。假如一个系统上线需要3个小时进行部署,如果我们要持续部署,每天都部署一次,那就需要每天拿出3小时做部署,我想这个成本是不能接受的。一个全自动化的持续部署平台是必须的,而且还需要保证每次交付都是高质量的,就需要做到全流程内建质量。

这里就引出另外一个问题,由于要求快速交付,就需要打通或模糊软件开发过程的需求、设计、实现、测试、验收、运维、运营等环节,对照以往按照单体架构组织的软件开发流程会发现打通这些过程是有生产力损耗的。比如可以专门做需求分析一个月,不用考虑开发实现,这样更加专注在需求分析当然效率更高了,我们为什么要拉通需求、开发、测试,使得各个环节不专注,生产效率反而下降呢?

3、配合性

在大型软件环境中,各子系统的接口必须协同一致。考虑到时间和环境的演变,要维持这样的一致性通常十分困难。

单体架构系统的困境

一个系统在最初开发的时候往往是最舒服的,虽然没有现成的可重用组件,但也没有沉重的历史包袱。假如系统从零开始做的话,头三个月开发会比较慢,因为需要搭建和熟悉一些开发、测试、部署基础设施,随着基础设施和公共组件的完善,接下来的半年到一年开发会加速,但是再往后开发速度又会逐渐降低。因为那些一开始提高开发效率的接口、共享表、依赖组件都变成了复杂网络缠绕在一起,变成了所谓的牵一发而动全身,改一行代码都不知道会影响到什么地方。重构也变得非常困难,因为需要相互配合的地方太多了,协同成本极速占据开发成本的比例。

微服务的救赎

既然一个系统在初步开发、规模不大的时候生产效率最高,要想使得生产效率维持在一个较高的水平,那就保持系统总是很小。这样因为系统本身很小,微服务系统的配合性问题总是在一个可控的范围内。比如微服务独立数据库表结构,那我们根据业务需要改表结构的时候就不需要去考虑会不会影响到其他业务,因为其他业务和这个表结构完全没关系。

我们区别看待微服务对外和对内的配合。刚才讨论的单体架构配合性问题都是对内的问题,但微服务架构因为把系统做小,从而把一些原本对内的配合问题变成对外的配合了,极大增加了对外配合性问题。

然而单纯从接口协同一致上来说,微服务架构非常糟糕。 单体架构的接口之间配合是相同的编程语言,基本上在编译时就能发现错误。而微服务的接口往往是远程服务,在开发时没法对齐。

利弊权衡

微服务控制了对内配合性问题,增加了对外配合性。版本依赖怎么管理、公共组件怎么共享、事务一致性如何协调都是让人纠结的问题。所以微服务的划分就变得非常重要,总体的指导思想是减少对外配合,把复杂的配合性问题留在微服务内部。

4、易变性

软件所应用的环境常是由人群、法规、硬件设备、应用领域等各因素汇集而成,而这些因素皆会快速变化。

单体架构系统的困境

单体架构往往需要将所有的模块都整合在一起才能发布,所有模块必须要步调一致。但需求的变化却是不同节奏的,单体架构系统只能强制的把对需求的变化响应放在一个时间点发布,进而使需求得不到及时响应。

单体架构也不能很好的响应性能变化的需求。比如某个模块的流量突然增加,或者需要大内存,单体架构只能为极少的模块增加整个系统的计算资源,又因为增加整个系统的计算资源成本很高、实施时间长,导致性能需求迟迟不能得到满足。

微服务的救赎

微服务要求独立进程,可以完全根据需求定制不同类型的计算资源,更精细化分类的利用内存、IO、CPU。因为小,可以更快水平扩展响应性能需求变化。

更关键是,微服务小,强调独立业务价值。根据康威定律,系统架构和组织架构相互影响,微服务小组需要是独立特性的全功能团队,面向最终用户需求直接对战。小团队直接面对客户需求做决策,所有信息和想法在小范围内快速交流,业务价值流动更容易可见,更快速的响应变化。

利弊权衡

微服务架构需要改变组织结构小团队充分授权、业务交付模式。

对于传统组织而言,这点是最难的,尤其是大公司往往采用层级组织结构,要求把权力下放到小团队,这会触动已有的权力结构不说,还会引起组织的不安全感。

微服务的交付模式也会挑战客户接受软件更新的习惯,这也是成功的传统企业面对传统客户需要面对的挑战。

结论: 微服务的终极价值

微服务架构解放小团队生产力,提高市场响应力。

微服务是颗子弹,需要PaaS作枪,瞄准的是快速变化的目标。

Share

Scala之父Martin Odersky访谈录

2016年3月,笔者有幸和诸多对Scala感兴趣的人一起,跟Scala的创始人Martin Odersky做了一次面对面的交流。下面是这次交流中的一些问题的整理,采用问答的形式,根据问答内容做了简单的摘要。

Mark_Odersky_photo_by_Linda_Poeng

提问者:我看到Spark Core里面有很多OOP风格的代码,这是为什么?

Martin Odersky:Spark的API设计是和Scala 集合类设计是一致的函数式风格,里面具体的实现为了追求性能用了命令式,你可以看到Scala集合里面的实现函数为了性能也用了很多var。

提问者:很高兴看到你将在Coursera上再发布两门Scala的课程。但我想问一下,怎么培训那些大学没有毕业的人用Scala?

Martin Odersky:这是个很有意思的问题,我们在Coursera上的学生绝大多数是大学毕业的。我现在还不知道针对大学没毕业学生的培训材料。但是有用Scala教10几岁孩子的教材,他们学得很好。

提问者:go语言有很严格的规范,但Scala没有,每个项目的代码风格都不一样怎么办?

Martin Odersky:对,go严格限制了程序员的选择,而Scala相信程序员自己会做出正确的选择。每个项目可以根据自己的情况制定合适的规则。

提问者:有没有推荐的Scala编码指导?

Martin Odersky:你可以用Spark的Scala编程规范,虽然有点保守,但比较适合有大量新人的项目。lihaoyi也写了博客来说明怎么样进行选择。

提问者:很不幸的是我们的项目上往往会有很多新人,我带了很多Scala项目,遇到的最大的挑战是如何保持代码简洁,能给些意见吗?

Martin Odersky:有两个原则:1. 尽量用能力弱的功能;2. 给中间步骤命名。

提问者:现在Scala除了大数据领域,还有其他哪些主要的应用领域?

Martin Odersky:Scala还在金融领域很流行,比如高盛,摩根斯坦利等。

提问者:现在很多创业公司喜欢用node.js, 比如Uber他们一开始用nodejs, 现在开始转向go,你怎么看?

Martin Odersky:用nodejs可以使得前后台一致,但长期维护成本会很高。沃尔玛加拿大用Scala,沃尔玛美国选择用nodejs,但后来沃尔玛美国也改成用Scala了。

提问者:但是很多初创公司可能活不到明天,他们不太需要考虑长期可维护性啊。

Martin Odersky:这也有道理,不过硅谷很多初创公司选择使用Scala。

提问者:Scala有没有不合适的应用领域?

Martin Odersky:非JVM的目前不行。还有一些非常靠近硬件而且对实时性可预测性能要求很高的应用也不是很适合。

提问者:2015年JavaOne Keynote讲到Java8使生产效率提升了15%, 那么Scala那些特性能使生产效率提升?

Martin Odersky:Java8这个统计数据很有意思,Scala相比Java生产率能提升2~3倍。

提问者:我们的项目代码看起来像Java,怎么变得函数式?

Martin Odersky:你可以多用map,filter,pattern match等,而少用循环和if判断。

提问者:有个谣言说一个twitter的VP说如果能重新选择他会重新考虑是否用Scala,还有LinkedIn好像也要退出Scala?

Martin Odersky:你说了这是个谣言,不是真的。这个话是一个从twitter跳槽的uber的工程师说的,而不是VP说的,他说如果你能忍受员工两个月的学习成本才能用Scala。LinkedIn确实是制定了从基础设施中退出Scala的决定,尤其是Kafka现在独立运作了。主要是因为Scala二进制不兼容造成的。而LinkedIn的应用程序将继续使用Scala。

提问者:Tasty是为了解决Scala二进制不兼容的问题,那会在2.12发布吗?

Martin Odersky:我们还需要时间,可能在2.12发布不了。

提问者Dotty什么时候能成为Scala默认的编译器?

Martin Odersky:我从三年前开始设计Dotty,现在刚刚有个可运行的初始版本,还需要几年才会成为Scala默认的编译器。

提问者:Dotty会带来一些新的功能,比如trait可以有参数,会是Scala 3.0吗?同时也会删除一些功能吗,比如抽象类?

Martin Odersky:Dotty会重新定义Scala,会是Scala 3.0,但这还需要几年的时间。是否删除抽象类是个艰难的决定,抽象类有它自己的作用,比如与Java兼容。并且抽象类和trait在语义上也有不同。

提问者:你在演讲中提到限制使用隐式转换,同时又提了typeclass,那隐式转换要怎么用呢?

Martin Odersky:限制使用implicit def。 隐式参数和隐式类是好的,可以使用implicit class。

提问者:大系统比较难维护怎么办?

Martin Odersky:有副作用的组件和隐含的全局状态会导致组件之间耦合,使得系统维护困难。

提问者:我问最后一个问题,最近MIT发表了用机器学习来编程的论文,你怎么看?

Martin Odersky:这个话题很有意思值得观察,不过不管怎么样机器还是得知道人要干什么。我们现在可以用机器学习来辅助编程,例如集成在IDE里面帮助程序员更快更好的编程。

Share