我们使用的是BUG管理系统来管理开发任务。这并不要紧,谁说BUG管理工具只能管理BUG。我们只需要解决我们的问题而已。当然,我们管理真正BUG的系统是另一套,只不过我们使用的是同一个工具而已,我们当然不会把BUG和任务混在一起。
来自需求管理系统中的需求,来自BUG管理系统的BUG,都会被业务开发组长来评估,根据自己团队当前每个人的工作量来适机添加、定优先级、分配任务、调度任务。也根据这个任务分配,哪些任务超期了,哪些任务完工了,哪些任务还没有开工,哪些任务正在进行当中,来判别开发人员的开发进度和工作量。
业务开发组长也会每日主动向研发部经理报告进度,简要说明一下现有问题和解决思路。进度列表,当然是从工具中导出的,列明今日关闭的任务,还没有关闭的任务。这样,研发部经理一思考:项目已经开始了这么多天,还有这么多任务没有完成,到期能不能完成,他就会思考是不是要做些调整。
对于项目进度,不管客户是不是需要必须在XX月XX日之前上线,我们都会设立一个项目最终结束的日期。而不能让项目随波逐流。
这个最终的项目开发结束日期,并不是由业务开发组长排脑门想出来的。
我在以前的文章中就有介绍。业务开发组长负责功能点清单整理、功能优先级划分、详细功能说明书编写。而且每编写一块就开始分配任务给开发人员。
在业务开发组长划分完功能优先级以后,因为每个功能的复杂性都差不多,如果某个功能复杂,就会再被拆分。业务开发组长就能预估出一个大概的项目开发周期。根据以往的团队经验,也能预估出给集中测试时间和集中文档测试打包发布的时间。这样,整个软件什么时候能最终出来,业务开发组长是有个预估的。如果一个团队是新组建的,每个人的能力还不清楚,预估就会有偏差,需要磨合才能得到经验值。如果磨合,我也会在以后讲到。
在实际分配开发人员的时候,就是根据这个总目标完成时间来倒推时间的。这个倒推出来的,有一个每个功能的完成时间周期,而项目经理对于某个特定的开发人员的能力预估也有一个时间,而开发人员自己对完成这个功能自己也有一个预估时间。开发人员怕完不成任务被追究,往往会把完成时间往后放1/3时间,甚至有人想偷懒干自己的活,会更多出自己预估时间一倍,也就是说自己觉得3天能完成,就说6天才能搞定。当然,业务开发组长也不是吃素的。业务开发组长也是开发出身,到底难度多大心里有数。而且业务功能就是业务开发组长设计的,如何实现,会遇到什么难点,自己一清二楚。而且天天管这帮开发人员,谁能力高低谁想偷懒,天天在一个办公室,谁不知道谁。所以,每个任务的时间,都会是业务开发组长在开发人员自己预估的时间基础之上进行调整,获得一个开发人员和业务开发组长都能接受的任务时间段。然后根据每天的进度报告来随时调整这个时间,让开发进度尽量能现实,而不是计划前就定好实际工作中就不能改。
对于项目进度的保证,还必须有一个条件,就是:我们不允许开发人员在客户现场开发,我们更不允许开发人员和业务开发组长不在一起。
开发人员在客户现场,往往开发进度和功能需求变更容易受客户控制,致使开发团队做的计划和设计都被客户视为扯淡的东西。开发人员不满客户的做法,但在现场又没有办法,只好敷衍答应开发权且应付。本来一个理性的设计,被客户自己自以为是的好做法而推翻。软件什么扩展性啊,兼容性啊,都被扔在了一边。来客户现场,就要听这个特定客户的,你必须口对口服务这个特定客户,你如果和他讲其他客户怎么办,他才不管呢,反正他付了你的钱,在你眼中他必须是你唯一的客户。(客户和女人一样,都希望是男人眼中唯一的女人,但现实的是,世界上都很多女人,而且很多女人都差不多,都要求她所对应的那个男人必须唯一)
另外,开发人员在客户现场开发,就无法实现每日构建每日测试。开发,是个团队配合的事情。一个软件,并不是开发人员就能全部完成的(许多老板都这认为有开发人员就行)。缺少了测试,质量就无法保证;缺少了文档,产品就是光秃秃的软件。而许多老板还认为测试和文档可以在代码编写完后可以做,真是对软件质量如何保证一无所知。
我们也不允许开发人员和业务开发组长分离。因为在开发当中,设计文档又不是代码,机器运行完就一种结果。每个业务开发组长的文档水平有高低,每个人的思考思路也不同。我们经常会遇到一个现象,就是用邮件、MSN沟通老出误会,而且由于不及时调整,误会越来越大,后来干脆气愤的直接打电话。而打电话呢,有时还不行,你问他理解了么,他说理解了,你根本看不到他的表情,你猜测不到他是真理解了还是假理解了。你以为他理解正确了,他也以为自己理解正确了。你问他进度,他说没有问题。开发出来了,测试人员又有自己的理解,到底这三者理解的是不是一个东西,谁都没个准。只有业务开发组长和团队一起工作在一起,每天能看到实际的软件,能面对面和每个人交流反馈,才不至于代码开发完毕才一看不行。有许多刚当上业务开发组长的朋友,往往和手下搞的很僵硬。手下认为他一天三变,频繁推翻自己的代码,很气愤。而业务开发组组长认为手下的理解能力低,多次讲都讲不清楚,还跟自己顶嘴,还不如自己去开发代码省事。完了,又回到程序员了。
我也同样不允许团队出现多种技术。多个技术,会让团队成本升高,每个人都得会多种技术。而我们做企业管理软件,要想上升赚钱,必须大规模一般员工团队低成本开发,这是我和老板都认同的一种思路。所以,我们必须使用最常用最普通的技术。除非没有办法。我曾经有一个手下,怕自己跳槽没有竞争力,于是老学习流行技术。PHP火的时候,他就学PHP。Ruby火的时候,他就学Ruby。如今网游和嵌入、通信、无线很火,他就开始学C。手机开发火的时候就学J2ME。而且他还想有实际的开发经验,以在应聘中说自己拿这门技术做过什么。于是他想尽办法在项目中要引入这些技术。说:用.net,我没法保证性能和稳定性,所以我必须使用VC++。??唬谁呢?大家都是开发出身,这个借口未免太可笑。
我也不允许团队使用最新技术。我们只使用最合适的技术。我们不要客户为不需要的新技术而买单。客户的水平只能管理了SQLSERVER这样的数据库,我们就决不使用Oracle。如果客户要求在unix上运行,我们就使用JAVA开发。我们谨慎的评价和引入框架,都在核心围绕客户能不能简单维护,我们有没有显著好处,我们面临最棘手的问题能不能很好解决。如果只能解决我们不怎么紧急的问题,如果只能解决我们通过人工或管理就能解决的问题,我们就不引入。一切的一切,都围绕速度、成本、质量在寻找解决方法。
我们也采取了每日构建每日测试,来保证软件的进度和质量。不每日测试,哪到什么时候才测试。到那个时候测试,会不会出现其他什么不可控的问题,我们都说不清。这种对未来的恐惧,让我们需要把风险控制到最小,到天,而且到今天。今天关闭的任务,明天一测试,就知道问题大不大。有问题的,必须由测试人员登记BUG系统,并且业务开发组长根据目前情况适机把BUG修复当作一项任务来添加。
我们也采用了版本管理工具。版本管理工具不仅可以使我们对比源代码差异,找回历史版本,随时打包更新版本,分支每个客户的定制需求,还可以是我们的一个工作的体现。大家经常会听到这样的话:不知道开发部这帮家伙在干吗?是不是故意利用我不懂代码在偷懒。
我们到底在干吗?我们能否证明。有的时候确实是,一个问题三两天都解决不了。我们真的不好意思说我们三天就做了一个功能。我们如果解释这般技术难题为什么为什么,老板更是没有兴趣听,他认为你在嘲弄他不懂开发技术故意拿技术问题来骗他。
我们能如何证明呢?能拿一些大家都能理解的方法来证明自己呢?所以,我想到了文档数量和尺寸大小,想到了BUG数量,想到了任务数量,想到了需求数量,想到了开发进度报告,想到了版本发布次数,想到源代码归档容量和源代码行数。
一个项目开发结束,任务数300多,BUG数量400多,文档尺寸70多M,项目历次讨论开会纪要30M,项目历次方案提交20多M,开发进度报告100多份,帮助文档100多M。这些都能量化都能看得见的东西,让老板觉得确实做了许多事。
我们曾经有一个客户,嫌10万块钱买了一张光盘,觉得贵死了。说地摊上一张才5块,你卖我10万。我们于是就把所有的帮助文档都打印了出来,600多页,装订成3本书,印刷好封面交给他。然后把软件装在一个很精美的木制盒子里,客户笑的很开心,把盒子和手册都郑重其事的放在了IT部门的柜子最上面。我想,软件是由代码组成的,确实不容易让客户理解其中的艰辛和付出,所以客户并不认可我们的付出。能拿客户可以理解的方式去讲明白就是解决方法。我一贯遵守的原则就是:要么解决问题,要么闭嘴。如果你想不出解决方法还抱怨影响团队情绪,那么滚蛋,这种人就是团队的毒药。
过去,我们讲了业务开发组长如何履行功能设计的职责的一些方法,今天,我们又介绍了业务开发组长在任务分配、软件进度、软件质量保证、工作量化的一些心得,这就是一个开发组组长的份内之事。希望能给被提上开发组长的朋友一些启发,不要把自己定为一个写代码的头儿,那样你不符合国内现状,国内的开发组组长就需要做这些事情。外国怎样怎样那是外国的事情,你也享受不到,这是中国。要么去做,要么老老实实继续当个程序员。
27、沙场秋点兵
前几个月,公司旁边的写字间又搬进一家公司,好似也是做软件的,而且好像是刚成立的公司,程序员们天天加班,神情很年轻,头发很油,穿着大背心大裤衩人字拖,男的女的都有,经常站在通道里成群的吸烟,或者干脆席地而坐围成一堆开会,都不下食堂吃饭,都订盒饭,中午晚上都是如此,我经常晚上下班,看见他们不时有人捧着一个盒饭从办公室走出来把吃完的饭盒扔进垃圾筒,不知道他们会工作多晚。
近来发现,他们开始有人正常下班了。他们也很少聚在一起抽烟开会了。通道里有的只是单个的人在打电话,声音很低,神情普通。偶尔看见他们在外面通道里开会,也是个个神情紧张或肃穆或很累或木然或沉默。
我想起了一句话:Boy,Slowly,Slowly。
新的产品,新的梦想,大家都很希望能够把多年积累的知识都用上去,做一个业界一飞冲天的产品。但是,这这个新的团队呀。
我想起了我刚出道的时候。我现在仍然很庆幸我能经历一个产品的从萌芽规划到实现到销售到规模销售的整个过程,让我看到了一个产品是如何成长起来的,在成长过程中会遇到哪些问题,是如何克服的。很多程序员没有这样的机会,往往一出道,就加入了一家运行N久的公司,团队是现成的,产品是现成的,自己就是做维护开发而已,没有完整经历一个产品生命周期。所以一旦遇到新开发一个产品的时候,就很茫然,不知道如何下手,而且心情很激动,过去一直维护别人的代码了,很多弊病想推翻重做都不行,现在终于自己可以一展身手了,这回要把自己的想法都加进去,不能留有遗憾,不能重蹈覆辙。于是扑入了自己全部的心血,就连睡觉也不踏实,每日心情澎湃。但时间不长,两个多月,各种问题就都来了。新技术、新团队、新产品,一切都是新的,很多交叉出现的问题让解决异常困难,团队也出现了烦躁,看淡,疲惫的情绪,大家想尽快结束,但开发才到中间,正是关键攻坚要命的时候。
我刚出道的时候,加入了一个新成立的研发中心,才成立四个月,我是第六人。产品还在规划当中,团队还在建设当中,技术还在学习摸索当中。
当时的技术总监做了两件我现在也认为很对的事情:一、他让所有人阅读上一代产品的源代码,整理上一代产品的功能,并且得出上一代产品的功能所映射的客户业务流程。并且要求指出上一代产品业务流程中的漏洞和矛盾。二、他让大家通过改造源代码来学习新技术。
他不仅仅让大家整理业务,还要画出来详细的流程图,整理出详细的数据结构。然后安排集中会议让大家讲,讲的时候,以流程图为主,走到哪一步,就进入软件界面讲解,并且讲明背后的数据存取到底是处理了哪些字段标志, 表之间是怎么关联的,到底从哪些表中取出来,表结构设计的有什么不合理的。
这次没讲明的,这次提问没有确切答案的,下次继续讲,而不仅仅是讲一回。我发现,很多团队缺乏这种不断追根到底的魄力。总是虎头蛇尾,第一次讲的很起劲,讲的期间出现了自己也没有理解透的东西,领导只是安排下去再去研究一下,但就没有了下文。自己下去了看了一下,认为找到了答案,但就没有再次校验的机会了,于是最应该细究的地方被这样放过了。我们知道,编写程序,往往是最细节差异的地方最容易出现问题,而且很少能被测试到,而且维护代码的程序员往往不清楚这块是干什么的,一旦出现问题很难阅读懂。
技术总监还让我们改造源代码。但这个也是有目标的,就是把控件都修改成一个统一的体验风格,没有DB的控件,就去寻找。寻找到了,就把这部分代码摘出来,然后形成我们自己的控件包,力求不要为了一个小小的控件,就安装整个的控件套件包。实在寻找不到,就自己开发控件。
学习新技术,我认为这种方法是最好的一种方法。我现在也是这样指导我的下属的。
学习新技术,为了怕误导,一是阅读官方的例子,如JAVA的宠物店或.NET的宠物店。但我后来我明白了,不能这么学。因为本来就对新技术陌生,一开始入主的就是这样的代码,那么以后的编写程序的风格就往往会像这些例子一样。其实,我们编写业务应用程序,并不需要这样的架构风格,也不需要秀那么多代码模式。照猫画虎把我们画的很累,还扭转不了已经固有的思维。我们不需要这种看上去很美的代码。
学习新技术,第二种方法就是找一个网上开源的什么系统,如某些新技术尝鲜者做了论坛系统或什么什么管理系统。但这种方法也有个弊病,就是他自己写的代码有他自己的风格,而且他还处于尝试期,写这个东西可能是他为了学习这个技术,而非目标是开发这个管理系统。本来咱们对于新技术就是一张白纸,这下被他带到沟里去了。
学习新技术,第三种方法就是阅读这个新技术本身的源代码。可惜本来就对新技术不熟悉,而新技术本身的源代码更是复杂,看的云里雾里,吃力看不到进展,欲想放弃。
所以,学习新技术,最好是学习基于新技术的第三方的外国开源源代码。他们对新技术理解快理解深入,他们应用新技术不是为了尝试新技术或者秀新技术,他们是为了完成他们的一个实用产品。我们当时为了摘出某个控件,几乎阅读了那个控件套件包的所有源代码,并且理出了源代码的结构思路,否则我们无法确定我们遗漏了什么,会不会有BUG。
但是,现在回过头来看,方法是对的,时机却是错的。
我们是新团队、新产品、新技术,很多我们尚未了解清楚的,我们却把我们学习新技术后得到的控件应用到了我们以后的正式产品中,并且作为基础应用。这给以后的发展带来了几乎是灾难性的打击,我最后费了好大的劲才算把基础重构并且稳定住,否则基础崩盘了,上面的应用就不可收拾了。
所以,我现在都是尽量限制使用新技术。也就是说,不会让新产品、新团队、新技术这三个新都同时出现,风险太大了。而且坚决不使用新技术作为基础技术。
我们还犯了一个错误,就是正式开发的时候,我们一上手就开发基础框架。大家都知道一个系统的基础框架的重要性。但是我们却用刚刚学会的新技术开发我们以后业务模块都要深度依赖的基础框架。我想起了某公司一套战略性的大型产品的开发:用的是新技术JAVA,大家都还是新团队,做的也是新产品,全体程序员都已经封闭开发了,居然有人提出了一套自己也未经过商业规模应用验证的基础框架,并且自己实现了一个小DEMO。大家一看这个小DEMO非常有思想,就决定让整套产品线都应用这套基础框架。
我想象他们的痛,和我很神似。所以,我现在如果面临新产品、新团队、老技术,我都不会让大家一上手就开发基础框架。
去年,我就面临了一个老团队、老技术,但是是全新一代产品的开发。
具体情况是这样的,经过几年发展,我们的现有产品渐渐老化,所以决定要开发新一代的产品。上一代的产品是C/S结构,而且是适合单客户使用的。这次,我们要开发B/S结构,而且是适合集团客户使用的。
让上一代产品的开发团队继续维护上一代产品。让新一代开发由新的开发团队去执行。所以,我们就招聘了新的团队(当时公司对开发新产品有不同的利益冲突团体,还没有达成一致,招聘新团队既有为新一代产品开发做准备的目的,也有其他的目的,造成这支新团队的打造过程中往往出现两种极端:要么好几个人都管,要么三不管)。刚开始并没有去动手设计与开发新一代系统,而是为客户定制开发了一两个其他IT项目。所以说还算接触了客户行业,大家彼此在一起工作也快八个月了,算是一个老团队。
但是这支团队对客户、对现有的产品并不深刻了解,虽然我给团队多次讲解过业务,也让大家分析学习现有产品,阅读现有产品的说明书,根据新的业务模式也组织大家一起分析业务设计功能、编写功能设计说明书,但理解上确实还不够令人满意,大部分人还是似懂非懂。遗憾的是,在老板的规划下,新一代的系统开发必须启动。
如果这时候开发基础框架,大家根本不理解以后这个基础框架之上要编写什么样的应用代码,那么这个基础框架就会变成形式,以后的应用代码怎么都觉得这个基础框架没什么用,用起来也是格格不入,不像是螺丝对螺母那样合缝。
所以,我先安排团队开发了系统管理工具。这是个没有具体业务的,而且通用的,而且也是基础框架的一部份的开发工作。但是,由于系统管理工具,涉及到了新的组织结构模式,新的权限控制模式,这是大家不太熟悉的。而且编码架构风格和他们以往的开发不太一样。所以开发起来也是疑问不断,需要实时复查代码,实时解答问题。
终于开发完毕,我们开了一个总结会。大家都总结了对这次开发的体会,并且讨论出来以后再遇到这样的问题要如何解决,每个人的分工和人员配合流程再次确定,功能和功能的用意再次给大家讲了一次,对于新的编码架构风格再次讲了一次好处和用意。大家都说:如果在开发前就把这些讲清楚了,那么开发就不会遇到这么多问题了。我说:开发前我就是这么讲的,但是大家都不理解。这次经历过来了,就明白了。
接下来该怎么办?
我说:重新开发一次系统管理工具。时间为期十个工作日。
大家都啊了一声。干吗要重新开发,好不容易开发出来就这么废了?
我对大家说了我的经历,我说:系统管理工具是基础框架的一部份,是以后用户很常用的工具,而这个工具却是我们在不清晰不熟练的阶段开发的,我们如何能把这么重要的基础功能交付给客户呢?尤其以后这个工具要和需要系统结合,这个工具的数据结构目前还无法支撑以后的众多连接,你们也看到了许多遗憾,我们不能一起步就是个瘸子。
大家又问:那过去的代码我们还能用么?
我说:你们自己看需要。我既不赞同你们尽量使用过去代码,也不赞同全部重新编码。如果你们想把一个有残疾的代码上改造成一个优秀的代码,我说不可能,过去的很多缺陷会牵绊着你。你为了保留过去的代码,你就会向过去妥协,而把丝丝缺陷带了进来。每个人每个功能都留了一点点小尾巴,那么所有开发的功能总和出来的缺陷就是一个大问题。所以大家自己看着办,先重新写,需要用的时候自己就COPY出来。
果然,理解了清晰的功能和功能用意的程序员,开发起来很快,毕竟都写过一次系统管理工具了,也是老技术、老团队了。半个月完成工作。
我问:上一次你们编写的系统管理工具代码用了多少?
他们回答说:不到20%。明白了思路,重写起来很快,反正没有什么高难度技术。本来想COPY旧代码,发现老有关联,摘不干净,还不如重新写一个来的快。
我说:好。咱们下一步就实现一个咱们系统中最简单的也是比较边缘的一个业务子系统。在开发中大家重点发现需要什么公共功能,咱们都提炼出来,就会形成咱们的基础框架的一部份。
这个简单的业务子系统开发了出来,我又开了总结会。
大家这次都发言热烈:我现在终于发现了系统管理工具和业务子系统之间的关联关系了,他们有很多代码能够共用。由于这次开发业务简单,而且经过上次系统管理工具的开发,开发方法和代码方法都已经熟悉,对于系统管理工具的认识也深刻了许多,所以这次我开发业务系统的时候,还顺便把过去的系统管理工具的代码进行了重构,发现了不少可以共用的部分。我发现,这些基础代码总结了出来之后,好像系统管理工具也是从这些公共代码基础之上开发出来的一个特殊的业务子系统了,所有子系统都依赖这个基础代码框架。过去本来系统管理工具的风格和业务子系统不一致,这次重构,一下子都统一了。
我笑的很开心,似乎我过去的心结终于可以解开了。
28、代码那些事儿
这个是讲软件研发过程管理的系列,目标人群是那些身处研发管理位置或想成为研发管理的人。所以我不希望这个系列中出现代码,也不希望出现和某种技术密切相关的代码技巧。
但是没有办法,软件开发过程管理,有个很重要的一环,就是软件代码编写。不编写代码,说的天花乱坠,管理做的再扭,也成为不了软件。
最近blog好友到了上限,所以无法加入好友了。于是就加入了N多QQ网友。大多数刚出道一两年,还有不少在校学生,希望认识并聊聊,要和我聊设计模式、OO、SOA,还有人建议我去看看OO和UML的书籍。
我确实没有阅读过OO的书籍,我不是一个死钻牛角尖的人。我只是有什么问题,就去找解决问题的方法,能解决我的问题就OK,而不在乎我用的正不正宗,也不在乎我用的是不是OO。可能它是OO的外壳,但是它实质上可能是伪OO,我也不想去深究和区分什么是正宗OO,什么是伪OO。反正能解决我的问题就行。
我首先遇上的问题是代码大流水的问题。一个代码3000多行,数不清的if..else。我实在无法分析出这个代码到底实现了什么功能,它复杂的就像一把瑞士军刀,如果军刀里面能出来一支小手电也觉得不奇怪。这段代码我想它就是这样。我想写这段代码的人一定是在学校做惯了《图书馆管理系统》,一个程序文件中实现了所有的功能。
所以,经历了痛苦,我就一直要求手下的开发人员,一个函数代码行数不能超过一个屏幕。如果超过一个屏幕,就需要来回滚动。一滚动,就容易把思路滚动的走神,乱了,还得回到上面去重新理逻辑。
这种规定,直接导致了一个后果,函数太多了。但是函数间是有关系的。有时候突然需要增加一个参数,但是此函数已经被其他代码调用了,于是为了省事不改动其他代码(当然,他可能已经忘了再哪些地方都调用到了),他就定义了一个全局变量,在函数之间传。
新的问题有出来了,全局变量的问题。代码在他一个人手里还好说。被维护了好几手,新手对日益复杂的代码已经不太容易理出头绪,但修改任务是有时间限制的,只能在现有理解水平上工作。这位新手看到这个全局变量的命名,感觉是自己能用的到,就用了,还给赋了值。意向不到的事情发生了,数据库中进了错误的数据,怎么来的,不知道,看代码,处理的都正确,代码没有问题,也不知道怎么出现的。
于是禁止大家使用全局变量,能藏到多低的可见级别就藏的多深。但是仍然问题依旧。
于是,我们就把这个全局变量封装成属性,给它赋予读和写的函数。不管有多少个地方调用了它,有谁给它乱赋值,这里掐源头,都做好日志和异常保护校验。
把所有函数,能变成私有的就变成私有的,需要公共供其他人调用的谨慎的放出来。放出来的函数,一定要做好参数的校验,什么空指针,什么没有初始值,什么非法参数值的,尤其是临界值上下边界,都在门口就挡住,根本不往下执行进行业务处理,否则走的越远引起的问题越大。
而且要求每个函数都要做好自己的内存保护工作,自己函数内创建的就要在函数内释放。每个函数要做好异常处理和日志记录。
这样,一个样子像OO的类产生了。它可能只遵守了OO所提了封装,它却没有实现OO所提的继承和多态。所以它可能是个伪OO,但它确实解决了我们的问题。
封装了类之后,又一个问题产生了。几个类之间不知怎么的,总是你中有我,我中有你,互相调用了。就好像左右手互搏,弄不好就会把自己给捆起来。
为了堵住这个问题,规定只能单向依赖,如果发现你必须调用另一个类,另一个类也需要调用这个类,就以一个类为主,另一个类开放事件。这也许就是控制反转,AOP的需求吧(我并没有深入研究AOP,我只记得控制反转这个词,好像是为了解决相互依赖关系问题)。“Don't call us, we'll call you”。
但是代码稳定性的问题仍然没有很好解决,测试组也找出了许多BUG,但是一到客户那里运行,还是出了不少BUG。怎么自己运行的时候找不到呢?
于是,我们在版本测试的时候、第一个版本小规模放给典型客户的时候,都加了断言。一旦软件出现问题,就立即记录日志,并进行软件中断,而不让错误继续错乱的不按我们预想的代码流程走下去。很多年前,我就惊讶于某公司的软件的质量,怎么折腾操作都没有问题,我常常给我的手下拿这个例子来反衬大家的代码质量。直到我有时随便乱点,居然软件中断退出了,报了一个错误号,我一下子想通了,它用了断言。断言阻止了错误的继续扩散,不让恶果之鞭长袖善舞。于是,我要求开发人员经常性使用断言,很多过去悄然发生的错误,测试员只运行可执行程序无法捕捉到,现在都能明确的捕捉到,在测试阶段就尽可能的消灭了那些过去无法明示的BUG。
我过去领导过架构组。架构组的人在2002年的时候,疯狂迷上了UML和设计模式,人手一本《COM本质论》和《设计模式》。我手下有一个新手,就处处是类,处处是抽象,处处是封装,处处是分离,尽量使代码高内聚低耦合。但是这样的的代码太麻烦,他花费了大量的时间,他看自己的代码赏心悦目,别人看他的代码云里雾里,不阅读懂《设计模式》就按照常规理解业务的思路去阅读他的代码根本阅读不懂,不知道他为什么这样写代码,怪异的很。本来,这位想达到可维护性,可阅读性,却真正的失去了可维护性、可阅读性。这和我前几天看我的朋友周爱民写的《大道至简》中写到:有人希望拿UML去统一用户和软件设计者。殊不知UML有多难理解,而UML设计者却认为UML可以描述一切。就这个道理,要理解你的代码还要去读懂《设计模式》,这要求太高了吧。
所幸这位新手自己都每次写的累,慢慢的也就懒了,觉得确实需要分离的时候就分离,觉得没什么必要的就懒得做了。用他自嘲的话说就是:被磨平了。其实,依我看,他现在这个代码状态才是刚刚好,即照顾了设计扩展,又照顾了实用。真正的纯OO,纯设计模式,可能只存在于教学和科学,而不在于我们的商业软件开发。我们作为商业开发,强调的是叫座的基础上叫好,所以折中方案是必须的,客户和我们自己两相宜就OK,是否符合正宗,就不在我们的商业开发管理范畴了。
这位新手还写了大量的注释。在每个源代码文件头都写上几月几号,XX创建的,这个原代码文件主要是干什么的,还画蛇添足的写上版权所有,公司名称。好像这个代码要开源,或者可能会被其他公司窃取了好表明公司版权。甚至每个函数都写了注释,每个参数是什么意思,每个参数可能出现的值代表什么意思,都写的一清二楚。久而久之,也懒的维护了。代码改动了,参数扩展了,参数状态值有了变化,注释说明却没有跟着改动,让后来看代码的人老误解,还不如不写这些注释。
我告诉他:做事不能走极端。要么全写注释,要么不写注释,都是不对的。我只在我认为要小心的地方,或者我自己都觉得很难理解懂的地方我才写注释。否则,我自己都可能会过段时间理解错了。如果某段代码我看看就能看懂,我就不写注释了。咱们做企业管理软件,深入技术又没有,只要代码能把复杂的业务处理描述的逻辑思路清晰就OK。虽然说理解能力不同,我能快速理解了的未必有新手能够理解,但是你看看我的代码你就明白了。
这位新手去看我的代码去了。我的代码几乎没有什么难度技术,但代码也是看上去很舒服。他发现了以下几个关键点: 1 代码风格统一,从命名含义,到大小写,到缩进,都一致。每个源代码文件都一致,确实出于一人之手。许多程序员,光自己的代码就有好几种风格,有时心情好,有时心情不好,有时头脑清醒,有时没有休息好,有时敷衍,有时画蛇添足,有时急躁,从代码就能看出来。而我的代码就像稳定运行每天如一日的机器,好似每个源代码都是在同一天敲的。这就叫发挥稳定。这几天要开奥运会了,运动员天天重复练同一个动作,把每个环节都练的精益求精,其目的就是为了在大赛紧张的压力下也能发挥稳定。人在压力下,非常容易发挥失常。如果人老处于这种压力下训练,那么大赛就像平常一样了。
2我的代码居然能看出业务流程。函数数量均衡,不像他的代码函数太多,跟踪跳转的很累,也乱了头绪。函数长度也正好在可理解阅读范围内。而且有一个流程控制函数,把流程处理环节串了起来。细深入跟踪某一环节,又发现了更细的流程。每个函数都看起来简单,但整体来看,却实现了复杂的功能。他问我是怎么做到的?我说,我的心中只有业务,业务和代码,我认为只是英语和汉语的区别,表达的是同一个思路。而在你心中,业务是DOC上的文字,代码是你的技术表现,你老需要把业务和代码映射拧在一起,我则不需要。业务流程如何,我的代码流程就是如何。
3由于我的程序都是小函数组成的,都有明确报错,所以错误很容易找到,即使出错,也扩散不大,都是小bug,对系统整体没有大影响。
他还对我的开发方法不理解,问我为什么要让大家从后台往前台开发,他很不习惯这种方法。他过去开发都是先用开发工具拖拽控件画出界面,然后一个按钮一个按钮的处理业务代码,需要什么字段就在数据库里设计什么表加什么字段。
我问他:你为什么要这样做?
他说:我不理解需求,无法凭空想象,只能先画出来界面,然后有了直接感觉后就在开发中理解业务,边开发边理解。
我问他:那你以前有详细设计说明书没有?
他说没有。
我又问他:那你以前有人单独设计数据库和开发业务处理中间件组件么?
他说没有。
我说,问题就在于此。你没有详细设计说明书,所以你看不到一个形象的东西,而咱们现在至少有PPT画的业务界面,也有输入要求说明,也有数据增删改查说明,也有业务描述说明。而且数据库,一个中大型应用,性能、稳定性、可扩展性,都在于数据库的设计和中间件的设计,如果每一个程序员都要从数据库设计到中间件组件开发到前端客户端开发,那么要想保证这个软件的统一整体质量,那有多难。每个程序员需要懂得多少的技术知识才能达到统一的质量要求。所以,让不同技术高度的人做不同难度的事情,把重要的事情掌握在高素质的人的手中,这样质量就不会跑偏到哪里去。企业管理软件,不外乎是数据的增删改查。数据库的视图和存储过程,已经屏蔽了复杂的表之间的关系,提供了统一的业务实体视图和业务实体的增删改操作。这样中间件组件就容易处理业务实体间的流程,到了客户端,就只剩下数据的输入和输出了,真正成了终端。
我还经常进行代码复查工作。发现有人的代码出现坏迹象,我就让他整改重构自己的代码。否则,定了规范,光喊口号让大家遵守规范又不检查又不惩罚,谁爱遵守规范?
在代码复查的时候,我经常能发现思路局限、想法绕弯、实现缺乏扩展性可变性、缺乏优化、判断有遗漏有风险的代码。我都一一给他们指出,并且告诉更好的方法应该是如何如何。
很多网友都问到如何培养开发人员、培训开发人员、提高开发人员技术。我过去所在的公司是每个周五都不定期召开技术培训会。但是慢慢的也流于形式了。我个人感觉,技术培训会是个好事,但最终达到的效果可能是加强了团队的凝聚力和和谐力,有利于团队建设,但是技术提高,并没有给开发人员在实际工作中有应用。因为大家听了也就听了,会一散实际工作中仍然照旧自己的思维习惯,很难落实下来。
通过代码复查,这就是真真实实的代码,这就是大家最实在的工作成果和天天接触的东西,很有真实性,不脱离,有针对性。通过这种方法,达到了大家对自己日常写代码的技术技能的提高。这就是我对程序员的培训方法。
管理是什么?有网友老跟我讨论企业管理、企业文化、盈利模式、执行力、忠诚度。我不是很喜欢这些空洞抽象的主题,讨论完了也无法解决实际细节问题。而企业的运作,恰恰在于每一步的成功,最终汇合成最终目标的实现,没有脚下的每一步前进,再好的设想也是空想。
管理,就在细节当中。
代码高手,也在于细节当中。
质量、进度、成本、目标、折中,这就是核心。写代码,做管理,道理一样。
29、风语者
我们公司开始也是没有测试的。
公司是创业公司,我空降的时候连卖什么东西都不确定。公司的创业仅仅出于老板对原公司的一口气,觉得还不如自己单干快活,公司要成为什么公司,可能想法很多。咨询?培训?认证?通信?数据挖掘?我从老板的书架上找到过这些书。但是真正卖什么?卖这不好卖,卖那不好卖。误打误撞就进了软件这一行当,但软件这行是否可以持续走,是否要持续走,老板还不确定,如果卖的不好就不做软件了,改做别的,现在是生存阶段,就顾不了许多了,有项目就接上。上面有老板关系搞定,下面有老实的干活人努力加班,项目也就过得去。
没想到,软件这条路,居然走下去了,还接了一个大活儿,安装的点很多,涉及的用户很多,从海南到新疆,从深圳到山东枣庄。
公司发动了所有实施顾问来测试,只有他们通过,才能去实施。
实施顾问大多来自刚刚毕业的应届毕业生,对企业管理,对软件,对行业领域,都一无所知。对测试更是一窍不通。
测试并没有分工,每个人都测试软件。也没有什么测试方法,也没有什么测试计划,也不知道该测什么。反正也是对软件不了解,就当是深入学习软件吧。
开始并没有测试报告,大家发现问题,就用电话或QQ或邮件,把问题发给开发人员。谁认识那个开发人员,就发给那个开发人员,如果不认识一个开发人员,就发给老板了。报告中尽是不好用,不能用的词汇。但什么功能不好用,是怎么操作导致不好用,不好用的具体表现是什么,都没有。
老板急眼了,怎么这么多问题。
我说有五个原因: 1很多问题都是每个人都反映了,其实只有一个问题,只不过大家没有分工,都测试,于是都报告 2不少人见一个问题发一个邮件,所以看起来很多。 3有的人测试只是随便乱点乱输入,咱们软件还没有做这种破坏性操作兼容防范。 4不少人不了解功能,不了解行业,不了解业务,本来是对的,按他的理解是错的 5有些人偷懒,今天发的是这些问题反馈,后天又是同样
我说,基于现状,我给大家一个测试方法: 1分工测,几个人测试一块功能 2不全部测,只测试那些很常用的重点功能 3不要电话、QQ、邮件来报告给单独的开发人员,给我一个人发就可以了,我来判断衡量安排。也不要随时报告。每天下班的时候来统一发送,由各个测试小组的负责人来汇总自己组内的测试,并且把重复的问题合并掉 4每个测试小组的每天的测试报告要连续在一起,不要今天发今天的测试EXCEL,明天是明天的测试EXCEL,这样没有连贯性 5每个问题,要标好功能模块,有测试人,有测试版本号,有测试时间,有测试操作过程,有测试输入数据,有报错截图 6先测试正常的数据输入,正常的操作流程,是否能全部流程走通,是否数据保存正常,是否保存后的数据还能正确的取出来。那些临界条件测试先不要做。对于功能不易操作、界面不好看、起的窗口标题是否得当,字体是否加粗这些需求不要提。咱们目前阶段的重点是测试问题,不要把需求和找问题混在一起。
方法执行下去,问题少了许多。
前几天大家还在抱怨这样的软件简直是烂软件,让他们拿给客户,肯定会被客户打死。
现在呢,才几天功夫,实施顾问已经觉得可以去实施了。
这就是有方法和没方法的区别。
第一批客户的实施终于启动了,实施顾问奔向了全国。
到了真实的客户那里,才发现自己的测试,自己对软件,对业务的理解是多么的肤浅。过去发现的问题原来都是小儿科,真正复杂的问题根本没有测试到。给客户一讲解,客户一问,发现原来很多功能细节没有理解,不知道怎么给客户解释。于是纷纷打电话回来问。而能回答的人只有我,我成了接线生。
我当然不能成为接线生。我一方面仍然要求他们按照过去的测试问题报告流程和方法来报告实施现场中发现的问题,另一方面我自己写了FAQ给实施顾问发出去。但是实施顾问仍然问,一个问题重复的问。我说你看FAQ的第XX行。他说他看了,但没看明白(其实是对客户业务不了解,所以也不明白功能)。我就给他再解释。经过多次解释,我也了解了实施顾问的理解思路和理解层次,于是不断修正FAQ,使FAQ1.0、FAQ1.1.1这样不断发布,几乎天天发布。我现在回过头来想,帮助文件写的好不好,不能你说你自己已经写的很明白了傻瓜才看不懂,不要这样认为,这样根本不解决问题。唯一的方法就是用户理解能力有多低,你就要把帮助写的有多低,让他理解是目的,要不你还能怎样呢,就这样的人,问题还得解决。