当谈论Feature Team时我们在谈些什么?

当谈论Feature Team时我们在谈些什么

Part I: What and Why

“对手刚出了个新功能,这个功能咱们之前也讨论过,这次要做起来,要快,大约什么时候能上线?”

“得去找个人做需求和设计,还要约运营聊一下具体需求; 现在产品经理手头都有别的事,要等; 需求出来后评审,评审完开发,单开发工作量,目测三天差不多,但得找研发负责人要资源,现在不一定有,要等另外几个功能做完之后,现在每个人手头都好几件事。 这个功能同时涉及新的计费模式和账号体系,这两个模块是另外一个部门在维护,得出人对接,最终也要等他们的工作量预估和排期。”

什么是特性团队?

特性团队是跨专业的,面向最终用户交付完整价值的团队。

为了能够高效的完成工作,团队成员通常在一起面对面办公,紧密合作,专注的一起完成当前任务。

为了能够高效的完成工作,团队通常有一定的授权,能自组织的做出决策,并对结果负责

可能的话,他们会保持稳定,长期专注于相同领域的不同任务。

特性团队是新事物吗?

不是,特性团队早就出现在社会的各个角落,只不过有不同的名字。

第一个名字是公司。是的,几乎所有公司都经历了特性团队的形式,这就是每个公司的初创阶段。 在这个阶段,公司作为一个整体,几乎满足特性团队的每一个特点: 跨专业,面向最终用户交付完整价值,在一起面对面,专注,拥有全部的决策权,及承担全部后果。 也就是说,公司在人类社会中存在的历史即特性团队存在的历史。

第二个名字是全栈工程师。 历史上那些著名的个人软件,很多都是一个人努力的结果。 这一个人承担了设计研发测试营销运维,所有的一切。 这种个人软件研发的组织形式,几乎满足特性团队的每一个特点: 跨专业,面向最终用户交付完整价值,在一起面对面,专注,拥有全部的决策权,及承担全部后果。 也就是说,全栈工程师在人类社会中存在的历史即特性团队存在的历史。

公司和全栈工程师,是一根标尺的两端,是特性团队的两个极端,一个是范围最大的特性团队,一个是范围最小的特性团队。 实际运作中的特性团队,就在这根标尺上滑动,其范围介于公司和个人之间,另一个例子就是业务线/产品线

第三个名字是业务线/产品线。 业务线也是全功能的,面向最终用户,各种专业技能都具备; 业务线的员工不会去做别的业务线的事情,保持专注。 只要规模允许,同一业务线就在一起办公,面对面。 拥有较为自主的决策权,并对自己的业务结果负责。

所以问题来了,公司是最小的作战单元吗? 业务线是最小的作战单元吗? 顺着问下去,就会一直到全栈工程师,这确实是最小的作战单元。

所以特性团队其实是一种分形结构,存在于社会组织的各种尺度上

01

 

特性团队的高效,帮助公司度过初创阶段存活下来。 但可惜的是,大部分公司在后来的扩张过程中,却抛弃了这一高效的组织方式,真是一件奇怪的事。 那么公司扩张过程中,都采用了哪些组织方式?

特性团队之外的组织方式有哪些?

  • 职能团队(也叫专业团队,Discipline Team,Function Team),比如研发团队,测试团队,设计团队,运营团队,市场团队,销售团队。
  • 地域团队(Location Team),比如北京团队,南京团队,印度团队,欧洲团队
  • 组件团队(Component Team),比如计费团队,订单团队,支付团队

各有各的适用场景。 那特性团队的优势有哪些? 特性团队的应用场景有哪些?

特性团队的优势有哪些?

快速响应

其它团队组织形式如职能团队,组件团队等,每个团队都只负责价值链的一环,一个问题是容易造成上下游之间的博弈,如开发人员和产品经理,开发人员和测试人员之间旷日持久的争执。 特性团队将各种角色的人员组织在同一个目标下,可以使其上下同欲

其它团队组织形式如职能团队,组件团队等,存在沟通和决策瓶颈,比如所有问题都要经过职能部门 leader 协调,沟通是不必要的网状,特性团队将沟通收敛在团队内部,缩短决策周期,消除决策瓶颈,将极大减轻更高一级领导者的决策负担

用户价值导向

由于特性团队是围绕着产品特性,从用户角度建立的,也就天然使得团队更关注用户价值和市场价值。

其它团队组织形式如职能团队,组件团队等,每个团队都只负责价值链的一环,成员容易只关注自己相关的部分,另外一个问题是容易造成信息传递过程中的曲解,如开发人员,产品经理,测试人员,运营人员对同一个需求理解的不一致。 特性团队同地办公,可以随时面对面交流的特点,可以使信息尽可能保真

激发创新

特性团队需要对最终结果负责,以交付用户需要的价值为己任,这给了团队创新的紧迫感。 而一定范围的授权,又给了团队创新的主动性。 跨专业技能的融合,有了创新的土壤。 特性团队从以上方面,有助于激发创新。

落实责任

特性团队对用户负责,对结果负责,将有助于减少很多事情无人跟进,最终给公司带来损失的后果。

驱动学习

由于一个特性团队需要对某一特性负责,并且团队将坐在一起工作,这样的场景从多个方面驱动了个人和团队主动学习更多的知识:

  • 专业领域方面,由于个人与特性相关的专业领域关系更为明确,责任更强,从而促使员工再专业领域方面继续钻研以满足职责所需。
  • 横向扩展方面,由于一起工作的成员都是不同领域的专家,从而提供了一个很好的学习场景和氛围。
  • 部分情况下需要帮助其它专业的成员一起完成工作,或是阶段性接手其工作,这从实战中促进了其技能增长。

从长期考虑,学习型组织的文化搭建对于企业的成长和改进都是非常有助益的。

激励员工

研究表明,当一个团队对一个完整的用户导向的工作单元负有端到端的责任时,员工将更有动力也更有成就感,而这恰恰是提高生产率和走向成功的一大关键。

特性团队应用场景是什么?

特性团队在很多场景下都有应用。

市场环境快速变化的场景

在变化速度快,充满不确定性的市场,对组织的要求是响应速度,并交付用户真正需要的功能,此时应尽可能缩短决策周期,尽可能消除沟通和执行中的等待,尽可能避免沟通中的信息失真。

特性团队快速响应用户价值导向的优点将帮助我们前进。

未知,需要探索创新的场景

有时我们面对一个全新的领域,以前的方案全都不工作,甚至用户是谁都不知道。 此时需要快速试错。 特性团队激发创新以及对结果负责的特点将帮助我们前进。

不把所有鸡蛋都放在同一个篮子里。 组建特性团队进行探索,激发个人潜能,保持组织的反脆弱性。

特性团队探索成功后,将会发展为新的业务线,子公司等。

组织扩展,整体决策机制存在瓶颈的场景

组织迅速发展壮大的一个常见现象,就是初创阶段的领导者和管理者成为决策瓶颈,领导梯队没有建立,难以应付市场的快速变化。 如果公司扩展新业务,则对新业务领域知识的缺乏也会影响决策效率。

通过将一定的决策权下放给特性团队,高层领导者和管理者可以从部分日常事务和业务细节中解脱出来,专注于更重要的事情。

需要集中兵力攻坚的场景

有时我们面对一个难题,需要多方合作,此时采用职能团队,组件团队,地域团队的组织方式都将大大减缓问题的攻克。 临时搭建跨专业的,全职的,在一起工作的特性团队将是在效率上唯一可行的办法

竞争激烈的场景

竞争激烈的环境通常融合了上述多个场景: 快速变化,不确定,需要集中兵力对战。 在这种场景下,每个交火点,都应该以特性团队来组织,慢必赔

责任缺失的场景,公共事务推动

当组织壮大后,不可避免的有些公共的责任分摊到每个内部子组织身上,但没有人整体负责。 长此以往,一些不紧急但重要的工作将被贻误。 组建特性团队,明确的赋权和赋责,将有力推动此类事情的解决。

需要持续打磨高品质产品的场景

只有持续的根据反馈调整设计,才会更有可能获得产品和技术洞见,商业洞见,从而打磨出高品质的产品。 职能团队将人力看做资源池的视角,容易使领域知识随着人员的轮换而流失。 特性团队通过长期的工作,可以深度挖掘领域知识,并使之固化在产品设计中,防止知识流失。

持续学习对成长至关重要的场景

如果组织未来的增长不取决于物质资源,而是成员的能力,组织的能力,那么拥有决策权和对结果负责的特性团队将是最好的练兵场。

如上,特性团队从结构上,为响应速度,创新,以及责任进行了优化,但也因此有它固有的问题。

特性团队有哪些固有问题?

围绕着特性团队有很多质疑,比如对人员能力的要求提高,成员归属感的减弱,考核和激励不好搞等。 这都不是特性团队的问题,特性团队只是让这些你本来并没有很好解决的问题暴露出来。 也就是说,这些问题之前就存在,但原来的组织方式掩盖了这些问题的严重性,其后果就是,虽然表面上风平浪静,但实际上组织效能并没有达到最优。

而特性团队作为一种组织结构,其固有的结构性问题只有三个: 概念一致性,人员利用率,及公共资源争夺

概念一致性

为了响应速度,特性团队按照端到端的价值链来组织团队,串起所有环节,这必然造成同一环节内部一致性的减弱。 比如不同特性团队负责的功能可能采用不同的交互方式,造成用户的学习成本,体验的破坏。

人员利用率

为了响应速度,减少依赖,特性团队要求成员保持全职,专注,避免异地办公。 这必然造成从全局来看,人员利用率可能达不到 100%。 这是由特性团队的价值观决定的: 响应速度高于人员利用率。 关注等待的事,而不是等待的人; 关注接力棒,而不是运动员。

公共资源争夺

业务线会争夺公司的公共资源,各特性团队会争夺业务线的公共资源。 这是结构性的,没有太好的办法。

对于这三类固有的结构性问题,无法依赖特性团队自身来消除,都需要特性团队之外的组织形态来帮忙。 而一类常见的形态就是决策委员会

  • 对于概念一致性来讲,决策委员会的表现形式可以是首席架构师,首席设计师等,也可以是架构委员会,设计委员会,定期或按需 review 设计问题。
  • 对于公共资源争夺来讲,需要高一级的决策机构,对于公司来讲,就是总裁办,由总裁办来协调各业务线的争夺,对于业务线来讲,也可以有自己的决策委员会来协调业务线内部各 FT 的问题。

特性团队的划分标准是什么?

顾名思义,Feature Team,按照 Feature 来划分。

这个回答不解决问题。 Feature 的粒度是多大? 其涵义可能很广,而其实现所涉及的技术栈深度又可能很深,那么边界在哪? 所以问题有两个,Feature 的广度和实现的深度。

Feature的广度

当我们谈到 Feature 时,更多的是面向最终用户的软件上的功能特性,比如下图:

02

 

但软件的功能特性太多了,这样岂不是要分出很多特性团队?

这里引入一个”需求领域(Requirement Area)”的概念: 从客户角度考虑的相关需求的集合。 比如上图的”漂流瓶”,“摇一摇”,“附近的人” 就可以作为一个需求领域”交新朋友”来交给一个特性团队开发维护。

Feature 实现的深度 (当特性团队遇上微服务架构)

而每个功能的完整实现,通常涉及众多技术和模块,那么边界在哪? 比如”摇一摇”和”附近的人”,都要用到定位服务,朋友圈发照片也可以带地点,那么定位服务的开发是否放到某一个 FT 里? 还是单独的团队? 放到 FT 的话,放到哪一个 FT? 几乎每个功能都会涉及的数据存储,消息发送,放到哪?

回答这个问题,需要回到 FT 的初心: 最大化响应速度,最大程度减少依赖,降低沟通成本。 而在实现层面,依赖以及沟通成本,跟软件系统架构密切相关。

如果你的系统是大泥球,还没有所谓的定位服务,那么定位服务的开发应该放到第一个涉及定位服务的 FT 里。 即使你做了系统设计,单独划分了定位服务,但只要接口还不稳定,还需要跟使用方密切沟通,那还是应该跟第一个使用方在同一个团队中合作,在合作中打磨接口。 而一旦将服务接口打磨到一定的稳定程度,服务使用者只需要根据手册就能很好的把服务用起来,不需要跟服务的开发者有过多交流,那么服务团队就可以独立出来,就跟我们用到的第三方框架,第三方服务一样。

随着功能的深入,同一个服务的接口需要增加和演化,那么采取同样的过程: 只要接口还不稳定,服务开发人员就进入第一个使用方团队一起开发,稳定后撤出。

当划分 FT 时有多种选择时,有一个简单的实践原则来帮助判断: 看看不同的划分方式中,哪一种沟通成本更低,响应速度更快。 如果差不多,那就根据其它维度如概念一致性等选择即可。

特性团队难道不是按照业务目标来划分的吗?

那是特性团队的 KPI,而不是划分维度,因为业务目标和功能特性往往是多对多的关系,互相有交叉,难以在团队层面按照业务目标去划分,尤其是基础业务目标。

所谓基础业务目标,如活跃用户数,差评率,NPS 等,涉及所有功能,如果成立一个特性团队来做,将囊括组织内所有成员,这没有意义。 如果真要成立,那也主要是有团队成员盯着这方面的问题,将任务分解到各个真正的特性团队去完成。 但依然比不成立要好: 因为在很多组织中,很多公共的问题都没人跟进。

  • 基础业务目标应分解到各个特性团队共担,比如每个团队都需要关注跟自己功能相关的活跃用户数,差评率,NPS 等。
  • 特定业务目标对应特定需求领域的,那么按照需求领域划分和按照业务目标划分其实是一致的,没有区别。

特性团队对Leader的能力要求是什么样子的?

初创公司 CEO 的能力要求。

从前面的讨论,特性团队某种程度上,就是一个内部创业的公司,作为这个团队的 Leader,首先从责任上,需要对结果负责。 其次从能力上,需要整体的领导力,包括对业务的把握,对产品技术的理解,对团队的管理,都有要求。

上面说的是最高要求,包含了决策和执行两部分。

实际情况中,公司内部的支持一定程度上会降低对特性团队Leader决策能力方面的要求,更多的是需要其执行能力,根据分解下来的目标把事情搞定的能力。

特性团队对成员的能力要求是什么样子的?

初创公司员工的能力要求: 全局视角,把事搞定的能力,快速学习的能力

某种程度上,这并不是多特殊的能力要求,如果你的组织不需要员工具备这样的能力,组织日常的低效可想而知,应对快速变化的能力可想而知。

有哪些资源是可以在特性团队间共享的?

“全公司就几个设计师,几个DBA,这么多特性团队,怎么分?”

我们是否有必要为每个特性团队所需的每种技能都配备全职的人员? 人员利用率是特性团队的弱点之一,但不意味着我们不能做些什么。 我们可以主动规划一些共享资源,而避免付出无谓的人力成本。 这里的关键点在于分清哪些可以共享,哪些尽量不要共享。

可以共享的资源有几个特点。

  • 第一个是工作占比在整个链条中比例不高,比如 5~10%。
  • 第二个是所需技能有一定门槛,人员较为稀缺,成本较高。
  • 第三个是可直接使用其成果而无需频繁交流,每天都要交流的不合适共享。
  • 第四个是共享排期等待的起。

这几个条件需要同时满足,否则应该通过招聘和快速的能力培养来解决,而不是共享。 举个例子:

2007年的时候,我所在的团队正在进行一个开源的持续集成工具的开发。 团队的成员都对 Web UI 的各种界面样式和效果不精通,仅仅能使之功能正确,但很难看。 当时招聘和快速学习 CSS 都达不到要求,我们当时雇佣了一个这方面的专家作为 Contractor,他每周四上午来半天,跟我们一起工作,把我们攒了一周的样式和效果问题在两三个小时内全部解决。

通常公司的运维人员,DBA等,满足上面四个条件。 事实上对于有一定体量的互联网公司来讲,不建议招聘工作经验较为缺乏的运维人员/DBA。 这个岗位永远都应该是在其它地方经过历练的专家。

特性团队需要保持长期稳定还是根据任务打散重聚?

这个问题并不关键。 建议跟着产品/Feature/任务走,随需要自然扩张或自然缩减,不必刻意打散或保持。

保持长期有好处。 出于稳定性的考虑,磨合成本的考虑,熟悉之后配合更高效的考虑,”成员归属感”的考虑,你可能会选择保持长期的团队。 这没问题,但依然要关注新鲜血液的注入,以及老成员正常的轮换。

事实上你对长期团队的偏爱并不是特定于特性团队的,即使其它的团队形态,你也会因为上面那些理由倾向于长期。 因此你的选择与特性团队无关。

事实上其它的团队形态,如职能团队,地域团队,你都没办法短期,也因此不得不长期,从而享受不到短期团队的好处。

而特性团队根据面向用户的Feature组队的特点,反而提供了另外一种灵活性,让成员有机会接触更广阔的业务和知识,接触其他的成员,从而更全面。

It’s up to you。

封闭开发算特性团队吗?

可以认为团队在封闭期间的组织形态较为接近特性团队,所有相关的人都关在一起,最小化对外界的依赖,此时效率较高。

当我们谈论封闭开发时,并不是所有封闭都是晚上不能回家的那种,更多的是在公司找个大点的会议室,团队搬进去一起工作,还是正常上下班。 所以这也是一件很奇怪的事: 如果认为封闭是高效的,为什么日常不采用这种方式呢? 包间不够? 大厅里的桌子也可以啊。

FTO(FT Owner) 和 PO(Product Owner) 的关系是什么?

范围不同,其它都一样,如果你的组织是产品研发组织的话。

  • Feature 是从 Product 分解下来的,因此一般 PO 的负责范围比 FTO 要大一点。
  • 如果你的 FT 负责一个完整的产品,那么 FTO 就是 PO。

还是像在 特性团队是新事物吗? 一节中解释的,FT 存在于社会组织的各种尺度上,因此,FTO 也就是 CEO,GM,PO。。。

PO是甲方的,FTO是乙方的,如果你的组织是IT服务组织的话。

对于PO这个角色进一步的解释,请参见: Scrum: 死马? (一) 三种角色

FT 成员的汇报关系是怎么样的?

每个组织不一样,各有各的实际情况。 回到初心,FT 是为了提高响应速度,如果 FT 成员直接汇报给 FTO 有助于提高响应速度,那么可以选择让成员汇报给 FTO。 如果你有其它的约束,那你需要综合考虑。

FT 对于提高响应速度的假设,建立在全功能带来的沟通成本的降低上,赋权带来的决策瓶颈的减少上,专注带来的无谓等待的避免上,并不直接建立在汇报关系上。 如果你的组织,赋权需要借助汇报关系来完成,那就可以设计对应的汇报关系。

Share

学习的逻辑 3:三人行必有我徒

今天谈学习中常见的两个观念上的障碍。

障碍一

在 Z记 做精益软件度量的培训时,有学员反馈,说老师你讲的不错,内容挺好,就是感觉你之前在这方面做的不多。

这类评价我是坦然接受的,除了对那个学员有点小担心,其实自己心里甚至还有点小得意:没经验的情况下还有人觉得讲的不错。你可能会说,靠,果然咨询师都是骗子。你要真这么认为我也没办法,但我对你也会有跟对那个学员同样的担心。下面我来解释一下。

我觉得从学员的角度来讲,讲师的背景和资历,甚至能力,是不需要关注的。你只应该关心课程内容对你有没有用,有没有帮助,有没有启发,有没有学到东西。你可以做出对讲师的判断,但不要让它影响你的学习。你甚至应该有意识的剥离讲师背景对你的影响,尤其是那些可能让你产生盲从心理的背景和资历。很多背景和资历,是特意强调的,目的是增加权威性,让学员更易于接受课程内容。你自己想想,难道你会因为一个人背景显赫就完全相信他的话吗? 如果不会,那么相应的,你会因为一个人背景不明就完全否定他的观点吗? 也不会。因而既不要轻信,也不要轻视。一句话,不要因人废言

因人废言更常见的表现形式是你不喜欢一个人,讨厌一个人,因此他/她说的话你全部不屑一顾。。。这样损失的是你自己,对你讨厌的人来说,没有任何损伤。其实你更应该师夷长技以制夷,客观的吸收点别人的长处没什么坏处,知己知彼,是占便宜的事。

这是今天要谈的第一个障碍。为了更好的学习,请不要因人废言。一句话有没有道理,跟说话的人是否是专家,没有关系。跟你是否喜欢他/她,也没有关系。保持空杯,保持怀疑,关注自己的收获,关注自己的利益,思辨的接受。我以前写书评总是说作者怎样怎样,书怎样怎样,其实更应该写的,是从书中学到了什么,对你的影响是什么。

虽然教练不必是最好的球员,但作为讲师,应该尽可能传播经过自身验证的知识。这意味着讲师必须是所讲授内容的专家。讲解其它自身认可但没有充分验证的知识,是退而求其次的选择,此时讲师扮演的更多的是 google 的角色,告诉学员有这样一些知识,这样一些他人的经验,而无法进行更深入的讨论。收到学员对自身经验的反馈,要认真考虑如何更好的服务学员。

障碍二

第二个障碍跟第一个障碍一脉相承。易于因人废言的人,对自己也特别没信心,难以通过分享,辩论来检验自己的认知。障碍是这样子的:

学习的逻辑:知识经济学 中提到了要分享,可人家都是高手,我刚学到的知识,对周围的人来说都是小儿科,分享是浪费别人的时间,怎么破?

且不说反馈是学习的唯一途径,分享其实是为了获得反馈,是帮助自己而不是造福众生。就先当它是为众生福祉,你也无需担心其他人不需要。下面我来解释一下。

有句话叫三人行,必有我师。而这句话有一个完全等价的表述,就是三人行,必有我徒。因为师徒必然是同时出现,互为定义的。不存在没有徒弟的老师,也不存在没有师父的徒弟。因此,如果你认同三人行必有我师的话,自然也就明白三人行必有我徒,总会有人从你的分享中获得有价值的知识。分享带有分享者自己的经历和视角,没有两个人的视角会完全相同。只要周围不都是因人废言的人,总有人会结合你的视角得出新的洞见。

这是今天要谈的第二个障碍,为了更好的学习,不要有过多敬畏之心。三人行必有我师这句话几千年来不知道妨碍了多少真正的学习,真是贻害千年。与之相伴的另外一个常见的表达是互相学习。互相学习也是一个错误的表达,为了能够互相学习,我们必须互相传授

有个古老的寓言说天堂和地狱各有一口大锅煮着美味的汤,众人围坐在锅边每人手持一把勺子,而勺柄太长超过胳膊的长度以至于无法喂到自己嘴边。地狱的人只能挨饿,天堂的人却在互相喂食而得以饱餐,而这种意识和行为上的差别也正是他们在地狱或天堂的原因。抛开其它意义不说,它宣扬的也是互相给予才是生存之道。

这个障碍其实可以很简单的破除,就是降低分享和传授的门槛。不要一提到分享和传授,就想到PPT,投影仪,济济一堂的听众。没那么复杂,分享就是聊天。当你有一个想法的时候,随机碰到谁,就跟他/她聊,听的懂正好可以给你反馈,听不懂正好逼迫你寻找一种更容易理解的表达。而且要不止一次的聊,不止一个人的聊,聊多几次,你会发现你的想法更完整了,一些新的点涌现了。一个副作用是,在周围人的眼中,你变成了一个健谈的人 🙂

Action

结合前面两个障碍,我们可以得出为了更好的学习,可以有以下Action:

  • 不再评价别人,而是关注自己所学。在豆瓣上写书评时,也不再写作者写的怎么样,而是写书的内容对自己的影响。
  • 庆祝失败,庆祝被反驳,被反馈,因为你终于知道了以前不知道的东西。 20岁时跟40岁时对同一个没有明确答案的问题持相同的看法,是很可悲的一件事情,意味着你在此事上没有成长。
  • 互相传授,三人行,必有我徒。
Share

给你1000辆车, 你能否改善北京交通?

复杂系统 vs. 线性系统

一堆小石头一个个砸不死人,合成大石头则不然

北京的环路有很多入口. 一个现象是入口处, 主路上车速变慢, 过了入口, 车速逐渐恢复. 如果你觉得车多是拥堵的原因的话, 就很难解释这个现象. 因为入口之后的车是要比入口前的车多的, 因为有车进来了却没有车出去, 但入口之后的车速却是更快的.

入口处和入口过后, 其实是两个系统. 前者是复杂系统, 后者是线性系统.

人们期望路上有一万辆车和一辆车时享有同样的通行效率,这类系统称之为线性系统,车辆相互之间彼此独立,互不影响. 现在的城市道路及交通规则的基础假设是交通系统是线性系统, 因此道路以及交通规则并不会随车多车少而动态的变化.

然而这个假设是不成立的.

交通系统实际表现出来的特性是某个阈值过后, 路网性能急剧下降. 实际的结果是, 这种下降可以严重到让大批车辆速度接近于零. 这就是严重拥堵. 具有这类特点的系统, 是非线性系统. 这类系统产生的原因, 是系统内部每个个体之间存在着相互作用, 而这些作用可以指数传播, 相互增强. 一辆车运动轨迹的变化, 无论是刹车还是并线, 都会影响周边的车辆做出反应, 而这反应通常也是刹车降低速度或紧急并线, 于是引发连锁反应.

所谓解决拥堵问题, 就是尽量让交通系统保持线性, 其手段只能是减少车辆间的相互作用, 没有其它方式.

车多, 路窄, 当然是车辆间相互作用增多的原因. 那么减少车的数量, 增加路的宽度, 不就可以治堵了吗? 这也是政府采取的措施, 限号, 修路. 然而前者是惰政, 后者有各种限制, 成本也高.

之所以说是惰政, 是因为车多路窄只是引发相互作用最表面的原因, 而不是最直接的原因. 关键不是车的数量和速度, 也不是车道数量和宽度, 而是变化, 车道由宽变窄, 车速由快变慢的次数. 10公里的路, 如果开头5公里是4车道, 中间变为3车道, 那它还不如一开始就是3车道来的畅通. 除去车道数量的自然变化, 任何一辆车的并线, 刹车, 都是一次变化.

然而变化也不是最直接的原因. 如果后车不需要因为前车的变化而改变自己的速度和方向, 那么变化就不会传播, 系统间的个体就可以保持独立, 互不影响, 系统就还是线性系统, 一万辆车就可以和一辆车时享有同样的通行效率.

所以关键是如何让后车无需对前车的变化做出响应.

降低车速当然是选项之一, 但怠速时也有急刹和剐蹭, 起步时也可以追尾, 并且畅通的衡量标准不就是速度嘛, 把速度降得过低来换取相互作用的减少, 是本末倒置.

那么手段就剩下了一个, 就是保持车距.

设想一个场景, 如果现在马路上的车, 都跟前车保持着几十米的车距, 那么即使有入口汇入, 有前车刹车, 有旁车并线, 有车道减少, 后车也可以有充足的时间和空间, 从容缓慢的调整, 从而消弭变化带来的影响, 消弭变化的传播, 让系统尽量保持线性.

保持车距, 那么路网的瓶颈就算一次只容许一辆车通过, 大家也可以在速度无需降得太低的情况下依次并线通过.

然而并没有什么办法让所有人都保持车距, 所以此路不通.

所幸我们还有其它办法.

大堵 vs. 小堵

事故地点过后, 总是一路畅通

减少车辆间的相互作用, 还有另外的方式. 相互作用以指数传播, 其强度取决于传播轮次及范围. 如果我们能将整个大的路网, 切分成一些小的路网, 小路网之间保持彼此独立互不影响, 那我们就能控制相互作用的强度, 即对外表现的拥堵程度. 一句话说, 就是化大堵为一堆小堵. 切分路网的手段就是每隔一定距离, 就有几辆车, 刻意的保持跟前车的车距, 来制造一个自然的隔离带.

所以如果你有1000辆车, 可以这么用: 北京五环的长度是98.58公里, 算100公里. 可以每隔1公里, 就安排10辆车, 分布在三四条车道上, 一会排成个S, 一会排成个B, 其实排成啥无所谓, 关键是要遵守下面的行驶规则:

  • 保持与前车的车距下限是100米
  • 保持自身车速上限是50公里
  • 当有前车刹车旁车并线打破上述规则时, 要从容调整为重新满足上述规则, 避免急刹车

这样整个五环, 就被分成100小段, 很难形成大的拥堵瓶颈, 就可以一直保持相对畅通. 所谓给我1000辆车, 我就能改善北京交通.

附录: 那些导致拥堵的行为和设计

  • 应急车道行车, 碰到摄像头并线躲避, 影响后车
  • 应急车道行车, 碰到出口并线躲避, 影响后车
  • 转弯不提前并线, 顺着直行车道跑到前面撅着屁股加塞. 撅着屁股影响本车道后车, 加塞影响转弯车道后车
  • 互不相让, 路口双方向叉死, 谁都走不了
  • 限速路段超速, 导致前面出口处迅速堆积大量车
  • 匝道过短, 红绿灯排队时排到主路
  • 左转直行共用红绿灯
  • 先入后出但入口出口距离过近, 往外并线的和往里并线的互相影响 …

注: 另请参阅<<复杂系统 I: 自组织和全局优化的代价>>

Share

环境无关的环境

本文转载自:http://www.infoq.com/cn/articles/thoughtworks-practice-part7

软件开发过程中常常需要搭建各种环境:开发环境、测试环境,集成构建环境等等。一个不可复制的环境是低效的根源,它引起的常见问题比如:

  1. 产品只能在你的机器上编译通过
  2. 产品在你机器上运行正常, 可在测试环境中总是出错
  3. 新加入一个项目成员,需要一天时间来为其建立开发环境
  4. 把测试环境和集成环境迁移到另外一台服务器上花了几天时间

这些问题的原因以及解决方案,在最新出版《The Productive Programmer》(卓有成效的程序员)中,Neal Ford给出了详细的介绍。我们列举几种细化的方案,作为书中提到的“间接”、“规范性”等原则的实践。

试图解决的问题:环境的各个部分散落在不同角落,不是少了这个就是少了那个,或不同机器上版本不一样;环境配置依赖全局环境变量或属性,硬编码的绝对路径等。

 目标:机器环境虽然各有各的不同,但依然有可能创建一个“环境无关的环境”。

1. 使用相对路径代替绝对路径

关键是如何获得当前路径,如何确定根路径,如何确保目录结构。

获得当前路径

  1. Windows和Unix都有内置的环境变量来表示当前路径,分别是%cd%$PWD
  2. Windows批处理脚本中,还可以使用%~dp0%获得脚本所在路径
  3. 而在Unix Bash 脚本中,则可以使用“pwd”,即获得pwd命令的输出
  4. Makefile中, 也可以获得shell命令的输出, 比如this_dir = $(shell pwd)
  5. Ant脚本中, 内置的basedir属性缺省代表的是脚本文件所在的路径

%cd%%~dp0%的区别:

  1. %cd%是脚本运行时的当前工作路径,与脚本所在位置无关
  2. %~dp0%则相反,是脚本所在路径,与运行时的工作路径无关

举例来说,有如下内容的D:\project\run.bat

echo %cd%
echo %~dp0%

如果在D:\盘根目录下运行project\run.bat,则输出如下

D:\>project\run.bat
D:\
D:\project\

一般来说%~dp0%%cd%更常用

下面是一个环境无关的makefile的例子(只列出了变量定义部分):

PROJ_ROOT=$(shell pwd)
INCLUDE += $(PROJ_ROOT)/include
LIB += $(PROJ_ROOT)/lib

当然也可以根本不定义变量表示当前路径,而直接以相对路径的形式引用子目录,和通过“..”来引用父目录及兄弟目录,然而显式的变量定义提供了一层间接,你可以通过多种方式覆盖它的缺省值,从而适应不同的环境。参见后面的“缺省值 + 用户自定义属性”。

确定根目录

如果总是需要引用某个根路径的话,则可以使用环境变量来定义根路径(参见后面的环境变量)。其实相对路径配合固定的目录结构,大大削减了对显式定义根路径的需求。

前面makefile的例子可以改写如下:

ifeq "$(origin PROJ_ROOT)" "undefined"
PROJ_ROOT = You_should_firstly_specify_$${PROJ_ROOT}_in_your_environment_or_by_command_line
endif

INCLUDE += $(PROJ_ROOT)/include
LIB += $(PROJ_ROOT)/lib

保证目录结构的固定,自然是使用配置管理系统。

2. 使用配置管理系统(版本控制系统)

这是一个“规范性”或者“标准化”的问题。配置管理系统不只是放源代码的,只要有配置管理需求或配置管理能带来好处,或需要有唯一的官方来源,都可以使用配置管理系统来管理;环境的配置文件,环境本身,都可以置入配置管理之下。有些公司的版本控制系统只放源代码,连测试代码都分开另放,耗费很多精力来维护源代码之外的文档。

  1. 强制使用配置管理可解决固定的目录结构的问题
  2. 使用配置管理还可以解决丢三落四的问题
  3. 自然也可以解决所用工具版本不一致的问题

这里有几个常见的问题:

  1. 大型的系统软件如何处理,比如JDK、VC++编译器等,是否也需要置入版本控制:这个基本不用,如果对其特定的版本有需求,可在脚本中加入检查其版本的逻辑,不满足则提示并退出即可
  2. 依赖的大量二进制库如何处理:如果有必要可使用依赖管理工具如Maven,Ivy 等,而用于存放依赖的本地仓库依然应该置入配置管理,哪怕不用其版本控制功能,而只是利用其官方来源/备份存档等好处
  3. 必须放在特定位置的文件如何处理,比如某个文件必须放在/etc目录下:这个文件还是可以放在配置管理下的目录中,而在/etc下创建符号链接来指向它;并提供脚本来干这件事。

3. 环境变量

必要时使用环境变量来引用环境。全局的环境变量可用作缺省值,在脚本中覆盖它(基本上,这是“用户自定义属性”的一个实例)。

4. 缺省值 + 用户自定义属性

这是创建“环境无关的环境”的核心机制。无论如何,环境要在不同机器上部署,总会需要修改某些配置,以适应宿主机器。然而前面我们提到,所有配置都已置入版本控制。如果我们直接修改,则每个环境中都会存在未提交的本地修改。这是我们不希望看到的,因为当我们升级配置并更新到所有部署时,可能会产生冲突。这里其实是两个层面的问题:

  1. 提供一种机制,当环境与缺省配置不一致时,允许用户修改
  2. 用户修改的文件应避免与官方文件更新的冲突

先说第一个。

缺省值当然可以直接定义在脚本或配置文件中。而多数常用的脚本和配置系统都提供了用户定义属性覆盖缺省值的机制。比如:

  1. Windows批处理:set path=my_extra_path;%path%
  2. Bash:export PATH=my_extra_path:$PATH
  3. Ant:
    <property file="user.properties"/> <!-- user.properties 中可定义任何后面引用到的属性,以覆盖其缺省值-->
    <property name="src.dir" path="${basedir}" /> <!-- 定义"src.dir"的缺省值-->
  4. CruiseControl:
    <property name="src.dir" value="." /> <!-- 定义"src.dir"的缺省值-->
    <property file="user.properties"/> <!-- user.properties 中可定义任何后面引用到的属性,以覆盖其缺省值-->
  5. 注意Ant的属性是只读的,先入为主。CruiseControl的属性则是后发制人。
  6. Makefile则可以直接在命令行覆盖文件里面定义的缺省属性。如覆盖前面例子中的PROJ_ROOT
    make PROJ_ROOT=/home/mike/project

再说第二个。

有一个很简单的解决办法,就是把用户自定义属性置入单独的文件,并且不要把它提交到版本控制系统中(一个理由是这一部分相对整个组织来说,不存在也不需要唯一的官方来源)

前面例子中的user.properties就是一个用户自定义属性文件,只存在每个用户自己的机器上,不在配置库中。在Windows和Bash脚本中也可以类似处理:

  1. Windows: call user_env.bat
  2. Bash: source ./user_env.sh . ./user_env.sh

随之而来的一个问题是,这个用户相关的文件应该放在何处。这里其实约定好就可以了,比如当前路径,根路径,甚至user的home路径都可以。

参考借鉴

  1. 至此,这套东西在不同的机器上部署时,只要从版本控制系统中check out出来即可使用了。更进一步,还可以提供脚本,即生成器,自动探测用户的环境,来生成全套配置,类似Rails生成应用框架那样。
  2. 其实,这是一个规范性或标准性的问题。Neal Ford 在《卓有成效的程序员》中,用一章的篇幅详述了各种解决方案,包括配置管理,符号链接等。除此之外,他还建议可以/应该使用虚拟机来统一项目组的开发环境等。参见《卓有成效的程序员》第五章。
  3. 另请参阅《CruiseControl Enterprise 最佳实践 (3) : Configuring CruiseControl the CruiseControl way》,是创建环境无关的持续集成环境的实例。

相关阅读

[ ThoughtWorks实践集锦(1)] 我和敏捷团队的五个约定

[ ThoughtWorks实践集锦(2)] 如何在敏捷开发中做好数据迁移

[ ThoughtWorks实践集锦(3)] RichClient/RIA原则与实践(上)(下)

[ ThoughtWorks实践集锦(4)] 为什么我们要放弃Subversion

[ ThoughtWorks实践集锦(5)] “持续集成”也需要重构

[ ThoughtWorks实践集锦(6)] Mock不是测试的银弹

Share

学习的逻辑 2: 职业半山腰

galaxy

<<学习的逻辑: 知识经济学>>中介绍了基础的逻辑. 本文是其姊妹篇, 进一步从不同角度来阐述.

我该学什么? 这是一个错误的问题

这个问题可以有很多出发点. 今天讨论基于的假设是对工作方向的迷惘, 即不知道自己下一步努力的重点是什么, 但又不想时光虚度, 总觉得该学点什么, 又不知从何学起.

想学习是好的, 但考虑下面这种场景. 你走进领导的办公室说: “我要加薪, 因为我参加了两个培训, 看了三本书”. 你觉得领导会答应吗?

再考虑第二种场景. 你走进领导的办公室说: “我要加薪, 因为我搞定了两个项目, 解决了三个问题”.

显然第二个场景比第一个更可能一点. 因此我们应该关注的, 是我可以有什么样的贡献, 什么样的产出, 而不是我应该学习哪些知识. 你的身价是由你表现出来的知识决定的, 不是你掌握的知识决定的. 就算我们的目标是学习, 让自己更强大, 一条更具可操作性的途径是以终为始, 先设定自己想做成什么事, 再反推需要什么样的知识.

另外一个类似的思考角度是, 你希望别人怎么介绍你.

  • 一种是这位是xxx, 他这一生看了很多书, 学富五车.
  • 一种是这位是xxx, 他是 yyy 产品的设计者 / zzz 书的作者…

你更希望是哪一种?

你对世界的认识和世界对你的认识都只能通过你可观测的行为来进行. 你的老板, 你的同事, 他们不可能知道你都看了啥想了啥学到了啥, 他们只能看到你说了啥做了啥. 换句话说, 你是个黑盒, 外在的行为定义了你. 如果你所知所学不能反映在外在行为上,则你的内部状态不会对世界产生可观测的影响. 也就是说, 如果你学了某些知识, 但行为没有任何变化, 那跟没学是一样的. 从这一点上,你的行动, 你的产出才是你知识和智慧的反映,所谓知行合一.

所以我该学什么, 是一个不恰当的问题. 更合适的问题是: 我该做什么, 我该对外界产生什么样的影响?

这里的讨论是在工作的上下文中, 不涉及哲学和宗教, 人生意义等.

有时忙得要死, 有时无所事事? 其实无关时间

有没有过几件事找过来, 你不知道该接哪个的情景, 最后只好只要时间排的过来就都接了, 结果搞的自己过载? 而有时忙完手头的事, 发现没什么可做的, 只好无所事事上上网?

有人会求诸于时间管理. 但其实原因不在于你的时间管理技巧, 而在于你根本就没有明确的目标, 无论是短期的还是长期的, 尤其是长期的. 没有目标, 时间管理就没有依据.

没有目标, 你就排不出优先级. 当一堆任务涌过来的时候, 你就不知道哪个对你重要, 哪个不重要, 哪个必须做, 哪个可以不做. 当你有多个项目可以去做的时候, 你不知道该挑哪一个, 该拒绝哪一个. 没事的时候, 你也不知道该看啥学啥.

有个项目可以练习你的产品设计能力, 另外一个可以出国练几个月英语, 还有一个当下最火热也是公司未来方向的大数据项目, 而你只能选一个, 你会选哪个? 你业余时间打算看本书, todo list 里面有三本, 但时间只够你看一本, 你如何决定该看哪一本?

比如你觉得要去学iOS开发, 是时代潮流, 可为什么不去学习智能硬件呢? 你觉得要去学数据结构和算法, 往基础知识层面走, 可为什么不去学习操作系统, 数据库原理呢?

不是从目标分解下来的学习任务, 更像是随机的碰运气, 恰好碰对的可能性很小.

一旦确立了真正的目标, 这些问题就不再是问题, 就不会时忙时闲, 也不会选择恐惧, 因为你知道忙时拒绝那些对目标没什么帮助的工作以削峰, 而闲时主动补充对目标有帮助的知识而填谷; 最契合目标的就去做, 无关紧要的就拒绝.

不善交际, 没有话题? 其实无关性格

周围总是有资深的人, 但你跟他们在一起的时候, 想要聊些什么, 又不知从何聊起. 有人会求诸于社交技巧. 但其实根本的原因还在于你没有明确的目标. 没有目标, 也就没有深入思考, 因此也就没有问题. 跟周围同事, 业界大牛聊的时候, 仅仅是泛泛而谈, 止于人云亦云, 网上遍地都能找到的一些讨论. 并且你也不会主动挑起话题, 因为你没问题嘛.

一旦有了目标, 在你向目标前进的时候, 一定会碰到很多具体的, 实际的问题. 此时你会主动去找资源, 找人聊, 也会聊的比较深入, 比较有成效. 你会突然变得积极主动, 谈笑风生起来.

同时你会发现, 几乎每个人身上, 你都可以学到你关心的知识. 所谓当学生准备好时, 老师自然会出现.

什么都会, 但又都不突出, 通才? 其实是学霸综合症

李敖有段时间一三五学法语, 二四六学德语, 别人问他哪一门强, 他说要看是星期几问. 与此类似, 你要问我有什么特长, 擅长什么, 那要看我当时是在哪个项目. 做过很多项目, 什么都知道点, 但依然没什么擅长, 当时在做啥, 就相对擅长啥. 但这并不能称之为通才, 仅仅是善于快速入门而已.

究其原因, 还是没有目标, 只知低头干活, 不知抬头看路, 转来转去都离原点不远. 最慢的步伐是徘徊.

以终为始. 反馈是学习的唯一途径. 输入只是娱乐, 输出才是学习.

Share