《代码之殇》(原书第2版)——第1章 项目管理失当 2009年5月1日

2009年5月1日:“一切从产品开始”


image

说我“老顽固”,但我相信产品决定一切。有个好点子还不够,光努力也不够,几近完成也不够,你必须得最终让产品面市。

微软的面试常常这样开始:“你都做过什么项目?”如果你最近没有什么成功案例,他们就会问:“为什么?”为什么?因为你不能提供产品你就不能向客户提供价值,你不把这次的任务完成,下一次你就不能接着干并不断提升水平,你没有客户你就没有客户回馈。

人们常常抱怨他们的升职机会及回报与他们的付出不符。我说:“是的,就应该是这样。”这样会影响产品质量吗?不,你已经为产品设了最低的质量标准并成功推出了产品;那么这样会影响创新吗?不,创新者通常最初冒着低收入的风险来获得与他们成果等价的高回报。

作者注:一些人报怨在微软对于创新思想并不给予丰厚回报。那是这些人并没有成功地使这些创新思想得以实现,能这样做的人已经成为我们机构及技术领军人物。

一切从产品开始。这点特别适用于服务(译者注:指软件抽象层,如SOA),我也将在接下来的内容里重点讨论此类话题。评论家们声称在这一个以服务为主导的新世界中,微软已经忘了怎么去开发这些产品了。可能吧,但是确切地说比起其他公司所认知到的,微软不是忘了怎么开发,而是根本没想到要开发这些产品。我们需要一些提醒及培训,特别当IT业转而面向服务的时候。

作者注:重在产品会导致死亡行军吗?不。相反死亡行军会拖延产品面市。就像我在“向死亡进军”中所说的:“死亡行军源于缺乏计划及勇气。”这对于理解服务的概念非常重要,在服务领域,产品要不断地推陈出新,这样才能保持长期成功。

作者注:顺便提一下,对于这句话:“比起其他公司所认知到的,微软不是忘了怎么开发,而是根本没想到要开发这些产品。”我受到了很多批评。这句话听起来有些傲慢,往往让人感觉微软并不愿听取一些关于开发新产品的意见。确实,IMWright很自大而且为此很自豪,就像他声称的,在我们最终赶上对手之前,微软并不想听取这些意见,我们之前很多的竞争者也不认为微软有快速并反复听取这些意见的相关记录。有些人可能会说,“那是因为我们公司的规模(足够大)。”但是我们并不是总这么强大。有些人会说,“这是我们的策略。”但是策略并不是无懈可击的,你必须以正确的方法在正确的时间开发正确的产品。这需要耐心并不断学习。

我为你提供了服务

根据评论家的说法,就提供服务这点,微软忽视或失去了多少呢?也许还不至于让你如此确信评论家的说法,但足够引起你的疑虑。让我们带着些许欣喜来消除这种疑虑与哀叹。

疑虑是:
 服务让你觉得什么都会变得不一样。
 服务注重数据,而套件产品注重功效。
 服务比起套件产品更关心安全性。
 服务在依赖性上存在严重问题。
 服务比起套件产品需要更高的质量以及更快的更新周期。

哀叹与欣喜是:

 服务不是只在单个客户端上运行的,它是存在于几百台机器上的。
 服务必须有自我扩展功能。
 服务容易变换,而不像套件产品那么难。
 服务能即时升级以迎合人们的需求。
 服务是实时的,多变的。
让我们拨开迷雾,从褐红鲱鱼开始。

那是什么味儿

服务面临的第一条褐红鲱鱼个头很大:“服务改变了一切。”就像我在“你的服务”(见第6章)所讲的:“完全不是那么回事。”就像其他所有产品一样,服务始终致力于帮助客户实现他们的目标,你得始终关注客户体验及他们所期望完成的目标,不然你就失败了。就是这样。

接下来的三条褐红鲱鱼是——注重数据、安全问题以及依赖性问题。虽然之前已经花了我们不少心思去理解这些问题,但这与实现套件产品是一样的。无论在软件客户端还是服务器端,为了使数据格式的变化不被客户发现,你必须避免这种情况发生;在现今,不能说你的计算机产品或服务足够强大而不会受到攻击——你必须保证它们的安全;最后,如果你认为客户端的外部依赖性不存在问题,你就不会需要过多的驱动程序。我不是说这些不是什么真正的问题——而是说,对于服务来说这些问题不新鲜也不特别。

最后一条褐红鲱鱼是再寻常不过的,服务实现与套件产品生产的不同之处在于其高可用性与互联网响应时间。看吧,套件产品经常会出故障或者当要正式使用它们的时候总要重启计算机,这样太糟糕了,出现像这样糟糕的事情已经有些时间了。服务同样要注重这样的质量要求,虽然很多服务产品也时常失败。

关于互联网响应时间,在10多年前引入Windows Update后,这个问题就出现了。如果你认为这些补丁不过是修补一下安全问题,就不会引起太多关注。不管是服务还是套件产品,不断增加的客户体验问题在客户向我们提供报告之后如果能快速地得以解决,这样对于客户来说他们感觉会非常棒。

然而,不是说逐日逐月地、渐近地提升客户体验就行了。不管服务还是套件产品都需要典型的、打包完整的升级包来为客户提供突破性的价值。Facebook不想像Vista一样逐步地升级为Windows 7,从而也使自己逐步升级为Twitter。因此,你必须关注客户真正要实现的是什么,而有些时候这些改变不是那么迅速的。

作者注:了解发布产品的最好途径就是早发布,常发布。要让每个程序的“构建”都是可发布的“构建”,每天构建,且每星期至少对整个系统重新构建一次。定期发布技术预览版及测试版。定期发布将使产品逐步更新修复。早发布,常发布,生命在于运动。

译者注:褐红鲱鱼,在18~19世纪的不列颠海域,鲱鱼被用做一种鱼饵,在那个年代没有冷藏技术,一般用盐腌制或烟熏后保存,烟熏后的鲱鱼就呈褐红色并有一种刺鼻的味道从而迷惑猎物。

这里有太多问题了

然而,并不是所有与产品实现相关的问题都适用于服务实现,还有心态、过程管理及团队协调需要你特别处理。

首要的是,服务在分散于全球的多个数据中心上的成千上万台计算机上运行。有时候它们的功能与数据会有重复,有时候又不一样。通常,它的规模程度与可靠性亦步亦趋,这样会暴露出设计与同步性问题,很多书籍已经对此做过相关介绍(再读一次这些书也不会有什么新发现);其次比较严重的问题是调试与部署问题。

为什么调试一项服务这么困难?计时问题可谓是在多台机器、多个处理器的多个线程上的杀手。哎呀!然而,这还不是最要命的。

在你调试一个问题的时候要做的第一件事是什么?分析栈,对吗?对于服务来说,栈分散在服务器与响应方之间,这使它几乎不可能跟踪一个特定的用户行为。好消息是,有一个工具可以有助于将分布于各个计算机间的行为进行关联;而坏消息是,这同样还不是最棘手的问题,最棘手的问题是你总是在一个实时的环境中调试,你得不到符号、断点或者逐步跟踪代码中每一步的能力。

至此,让我们回顾一下。调试服务意味着在没有栈的、没符号的或在动态代码中没有断点的多台机器上调试繁琐的计时问题。只有一种解决方案——使用测试设备,有很多这样的设备,这样的设备是从一开始就针对某种服务设计好的,它预先考虑到了你以后将在一个无法进行栈跟踪、没有符号、没有断点的动态机器上调试。

他们增长得太快了
解决调试问题给我们带来了另一个重大困难——部署问题。部署应该是完全地自动化及轻便的。就拿安装程序时文件复制来说,要快速地复制文件,就意味着不用注册,不用用户干预,甚至不用指导用户干什么。

为什么部署需要这么快速又简单?有两个原因:
你正在将软件安装在运行着的、遍布全世界的成千上万的机器上。安装必须在无须人为干预的过程中进行,稍有复杂就会引致失败。记住,在1 000台机器上花五分钟就是三天半的时间。最好不要出什么问题。

服务器的数量需要根据负载量动态增加或减少。不然,你就是为了满足高要求而在浪费硬件、浪费电源、浪费制冷以及带宽。因为你的规模决定于负载,它会随时变动。当负载变动的时候,你就需要自动且迅速地扩充系统。

令人庆幸的是,有Azure可以为你在部署时分担重担(所以用这个就可以了,不用另外再开发类似工具),不过,你还是需要设计好你的服务以便于安装时快速复制文件。

人生太无常

有很多问题你可以预测,但不能预测的呢?服务在时刻不断地变化着。有些服务固定不变,它们保持着你的数据(像Facebook及eBay),而有些服务却不会(像搜索引擎及新闻)。稍稍几分钟的宕机就会让你失去数千的客户,数据损坏或丢失可能让你失去上百万的客户。他们马上会换地方,我们的竞争对手会很高兴地接受他们。这是把双刃剑,你必须努力去招揽新客户并留住他们。

当你升级你的服务时,客户就会马上体验到最新版本的功能,而不是要过好几年。如果有一个bug在一个客户的上千次体验中发生一次,那么意味着这个bug也会在几千个客户身上发生(大数定律)。这样你就必须及时解决此类问题或者进行事务回滚。不管怎样,到星期五再更新服务绝对是个坏主意,而是应随时有个应急回滚按钮以应对不测。

最后,应该认识到服务是实时的、变化着的事物。你可能会想,因为服务器是我的,是在我的构想中设立并配置的,那是一个可控的环境——那只是在你把机器开关打开之前。一旦服务器开始运行,这些都变了。内存使用在变动,数据及其布局在磁盘上也会变化,网络流量发生变化,系统负载也发生变化。服务像条河流而不是块石头,你不能刻舟求剑。必须随时关注它们,为使你生活得更轻松,要始终谨记五“重”自动化——重试、重新开始、重启、重新镜像、重置机器(虽然重新替换有时需要人为干预)。

面对这些让人心烦的事,客户们很期望得到一些宽慰。一个理想的方法是建一个“点子检测”平台,因为你可以看到客户的不同看法并看看他们日常关注的是什么;同时应具备这样的能力:马上加以改进并在以后找出会间歇性诡异发生的bug(谨记五“重”方针)。

返璞归真

现在你明白了。围绕客户及其目标的传统的稳健代码编写方式是发人深省的。

然而,如果缺少成果面市,这些什么也不是。要成功就要先有成果。是的,我们的质量标准已经有所提升,我们不是要王婆卖瓜,所以我们需要定期改进客户体验质量,不管是长周期还是短周期的;我们必须通过互联网、PC、电话去实践体验。我们必须服务好客户,让他们开心从而使他们更靠近我们。这是个长期的过程,但千里之行始于足下。

2009年9月1日:“按计划行事”


image

我的大儿子会开车了。但也为我的生活平添两份担忧:一是我已渐感年老,二是颇为我的儿子担心。为了减轻这第二种担忧,我和我的妻子设了一个强制性的禁令:我的儿子如果回家晚了,他必须先给家里打个电话。有一天,他回家晚了20分钟又没事先通知,我们生气了,我的妻子愤怒是因为他晚了20分钟,而我愤怒是因为他没事先打电话通知。

为什么我的儿子没有打电话说要晚点回家?因为,跟我妻子一样,他只把注意力放在计划上。在回家之前,(不打电话)他可以避免纷争。他说:“我已经尽我所能早点赶回家了”——为此都好几次违反交通规则。但我的儿子没有明白要点,规矩的目的是想减少风险,而他对此做出的反应是增加了风险。

软件工程师也经常这么干。从一个开发计划开始,非人所愿的问题就随之发生,然后他们就延期交工。为了避免纷争,他们往往并不向项目经理提及延迟的事,而是匆忙赶工,牺牲质量,草率应付计划,所有这些都使工程陷于不可控也不透明。其结果跟项目经理所料恰恰相反,而那些项目经理是严格按部就班执行计划的。为什么?因为多数项目经理及工程师不能区别这两种计划——兑现承诺及风险控制。

作者注:我很喜欢这个专栏,它囊括了关键性及基础性的问题,虽然这些问题通常被误解。我希望我的家庭、我的朋友、我的同事及我的团队都读一读。

谁懂事物具有两面性,谁又不懂?
的确,有两种类型的时间表及项目管理技术。
兑现承诺。你向客户或者合作伙伴做了承诺,你必须遵守承诺按时保质完成任务。要按时。

风险管理。工作有关键性及期望性之分。人们或许会做出错误的选择从而产生问题,你必须善于进行风险管理以保证关键性工作的完成。

这两种项目时间表及项目管理技术往往会被搞混,为什么?

它们通常同时发生。承诺贯穿于整个工程项目。但它是由许多个小任务组成并需要风险管理。
两者都有时间表。不同的是向客户承诺的计划时间表不可精确确定,但所有人及事情又为其所驱使。而风险管理的时间表可以有很多监测点以保证其踪迹可寻。

它们都可称为计划。很多人不知道二者的区别。

人们所被告诫的往往只是承诺。当适龄儿童入学后,他们就因为有时间表及规矩显得中规中矩。当他们日后学习了项目管理,就只知道甘特表及里程碑,而把风险管理抛在脑后。

风险管理往往是自我学习的过程,是非正式的。只有一小部分人真正学习过风险管理,大多数人只是在大学里为应付大工作量的任务才向同僚们效仿了一下。我们不是将所有事情及时完成,而是成立工作组,只关注关键性工作,以及极力减少有损我们评分的可能。

不能很好理解这些道理的惨痛结果是导致可怕的决策、可悲的工程实施以及计划失败。你必须知道二者的区别以及将正确的计划应用到相应的问题上。让我们从兑现承诺开始。

这是你唯一承诺的事
“兑现承诺”是跟他人合作的基本准则,也是多数商业行为的准则。在需要内部相互依赖、外部相互信任的情况下,如果产品没有按工程日期安排及时到位,你们的工作就无法协调进行。因为承诺是前后关联的,你必须及时完成承诺之事,不然你就会面临惨重失败。

假如你女儿的生日快到了,你承诺说将给她买一款她喜欢的新游戏,如果别人承诺了游戏出品时间而又没完成,你会是什么感觉呢?在开发者、厂商、销售商以及你之间是手手相传的链条,所有这些都及时到位才能确保在你女儿生日的时候让她开心。

当然,这对基于Web的产品来说是相对容易的,但是在团队及部门间相互关联的过程中还是会产生同样的问题。承诺并交付产品才使信任得以建立,及伙伴关系得以维系,失信则相反。虽然很多软件项目只需要很少或根本就没有团队协作,而运作大型成熟的项目通常就需要守信以及其他项目管理技术。

作者注:为了有助于做出承诺,一个公司通常使用库存、保留余地以及其他风险管理的形式为实现承诺的每一步骤提供保障。这就是风险管理的精髓。你使用正统的项目管理方法确保整体目标的承诺得以履行,而使用风险管理确保履行承诺过程中的每一个步骤无恙。

你不认为那是一种风险吗

风险管理是关于如何确保关键性工作得以完成的论题,即便是在一个极易变动的环境里。Scrum及Feature Crews就是两个在软件开发中比较突出的例子,它们关注于风险管理,确切地讲,风险意味着你不能高效地将有价值含量、高质量的产品提供给客户。

就像我在第1篇专栏“开发时间表、飞猪和其他幻想”中提到的那样,开发计划及测试计划都在风险管理之列。所有的标志性日期都是降低风险的检测点,但只是仅有的几个跨团队的同步检测点(标志性里程碑)才是向客户承诺的要点。

什么才是风险管理的重点、先后次序以及其表现状态,这还没有确切的说法。只要注意什么是重要的,先把重要的做好并在条件改变的时候跟踪其状态就可以了。注意,紧盯着细节工作日程安排并不重要,你在规定的时间以规定的质量完成最关键的任务才是重要的,其他的可以不用太在意。

这就是为什么你要告诉你的工程师,就像我告诉我的儿子一样:“是否按时回家并不重要,告诉我们你不能按时回家了才是重要的。”如果你知道风险的存在,你只要管好这些风险就可以了,工作时间表只不过用来提醒你计划需要更改了。

当然,你不能过了向客户承诺的时间(一个标志性里程碑)而将关键性任务一直向后拖延,就像我的儿子不能在外超过凌晨1点钟,不然我们将没收他的驾照。禁令应事先设置,它防止了可能发生的这种灾难,这就是禁令应具有的功效。

作者注:有很多众所周知的风险管理技术。这里顺便列出几个在软件开发中用得到的(好几个在前面的专栏提到过):

开几次常务会议,15分钟左右,谈谈进展情况、未来的期望及目前遇到的一些难题(称为Scrum迷的Scrum会议)。

为所分配的任务做个备案(在缺乏经验的人与富有经验的人合作的情况下)。
留点余地——安排些额外的时间以备不测(就我个人而言,我向来不喜欢这种方法;我宁愿为任务列一个优先次序表也不愿有面面俱到的想法)。
轻在承诺而重在成果——也可以说是量力而行。

留有退路——始终谨记为有风险的任务设个预案,比如削减功能模块或重新使用老版本。
平衡风险——当事务发生变化时,通过增加或移除风险始终使你的项目保持在一种常态:有点担心但并不恐怖。比如,如果一个团队成员的父母过世了,你的风险就增加了,所以你必须削减具有风险性的功能模块或重新将那项艰巨的任务分配给一个高级工程师。

选择一个正确的工具

所以,当你开始对一个计划付诸实施之前,先等一下,思考一下计划都有什么。其中是否有一连串的约定时间及产品需要交付?或者有哪些不同优先级的重要任务你需要跟踪监视并防止其错过的?

就比方说我儿子回家的禁令,不夸张地说,那就是我不容许他破坏的任务。因此,我们需要风险管理以及需要及时关注其状态的重点,而不是说关注什么时候回家这样的事。这样的模式很适用于大多数软件开发项目。你只是想你的工程师及时告知你情况,这样如果他们延时了,你可以进行调整。太精细是不必要的,而且会适得其反。

然而,如果你跟多个团队及合作伙伴实施一个大型项目,那么在一定级别的层次上,你们相互间的承诺及同步是很重要的。在这个层次的时间表上都是一个个里程碑以及经典的项目管理工具。

不要将高层次的工作计划与低层次的任务相混淆,如果你对待低层的相互间约定像对待高层的一样,你的工程师就会抄近路并快速赶工,你可能就会导致他们破坏整个关键性任务,从而破坏了你高层的客户合约,风险管理也就无从谈起。你在合适的层次使用合适的方法,你一晚上都会睡得很好的。

作者注:更多关于传统项目管理技术与敏捷项目管理技术组合的话题,参见下一专栏“敏捷的团队合作”。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值