今天还是明天――一个人的软件工程

到底为什么要用软件工程,这个话题有些大,有时候实在搞不清楚别人是在考自己还是他们真的想了解,经验的微薄,使得每每被人问起的时候,手都不由自主的伸向那本《软件工程》而后又若有所失的放下它――项目中没有遇到困难,那书上所述并无法回答这个看似简单的问题。

而即便是勉强拿出自己的些许心得向大家解释之后,也往往得到一个让人无奈的结论:“我一个人做项目用不到软件工程”――实在不清楚目前这样的作坊式工程还有多少,既然现实无法改变,好,那我们今天就来说说这个问题――一个人的软件工程,当然这里使用了“软件工程”这个沉重的词汇,似乎有点哗众取宠之嫌,不过在没有找到合适的词之前,姑且先容忍我借用一些概念。

前提和事实

按一般习惯,描述一件事情,都应该有前提来约束,本文的前提如下:

1、             既然是一个人的软件工程,那么这个前提很简单:软件的开发完全由你一个人来负责(这种开发方式应该符合国内大多数软件公司的现状)。

2、             用户也并不清楚自己要什么。

3、             你的项目不是外包项目。

4、             你可以正常进行程序编码――起码会写程序吧。

有前提当然得有事实支撑:

1、             3个月后,程序员读自己的代码与读别人的代码并无两样。

2、             用户的需求是一定会变的。

3、             如果项目不考虑成本,就没有风险可言。

4、             代码完整度越高,其变更成本也越高。

5、             风险与需求变化量成正比,需求越不明确,风险越大。

6、             工作量一定的情况下(一般软件项目,工作量只会增加不会减小),降低风险会增加成本,反之亦然。

软件工程的本质

我们可以这样认为,今天的工作叫做成本,而明天的工作叫做风险,软件工程则是为了减少明天的工作,而在今天增加成本的方法学――即为明天而工作。

一般教条式的讲解,都将软件工程分为这几个阶段:分析、设计、编码、测试、维护。姑且不说这种拆分方式太过理想化,单单脱离本质的论述足以让人一头雾水――至少对于很多没有开发经验的人来说是这样――或者说他们只有听的份。所以,我们今天不这样去理解,而是只针对它最实际的目标来讨论,即成本和风险。

就像前面说的一样,成本就是今天的工作,而风险即是明天的工作――未来成本,这听起来似乎是一个简单的加减法:工作量一定,今天干不完可以明天干,保证进度就行了,何必今天去做那么多的事情呢。但我们不要忘记,软件开发是一个特殊的过程,随着项目完成度的增加,其变更成本会越来越大,那么基于这一点,如果今天的成本是1,那么明天做同样工作的成本就是NN>1)。

“明天的事情今天做”、“增加成本”对于我们的老板来说也许都是些心惊肉跳的字眼,这也是很多管理者从简甚至抛弃软件工程的原因,也许这种做法在项目前期根本感觉不到隐患的存在,相反老板(当然也包括程序员)会觉得事情进展的很快很顺利,但很快就会发现,随着需求的变动、人员的调整以及代码的增加,项目所剩的时间会越来越短――而更可笑的是,很多管理者把它归结为资源不足,甚至将其当作加班的理由。

其实如果我们一味的减少今天的工作――即成本,那么明天的工作会很多,这在开发界有个好听的名字叫做“技术债”。过于关注软件局部成本而忽视风险,无疑是在借高利贷――利息可以远远超过本金。笔者曾经使用3天的时间做完一个小型管理系统,期间用户修改了2次,交付后我便再也不愿意去碰那些代码――修改或重构这些代码的时间已经足够我重新编写两个同规模的系统了。

基于这些原理,对于实际开发的项目,尤其是一个人可以负责的项目,那我们的工作无非是两个:今天的设计和明天的变更。

好,说了这么多似乎不着边际的理论,各位也许已经头昏脑胀要扔西红柿了,确实,干巴巴的理论描述没有任何实际体验,着实让人难以下咽,那好,下面我就来重现一个大家都似曾相识的情形。

一个人的项目

一般来说,我们接到一个项目之后会忠诚的按照以下步骤来进行:先做需求分析,清楚用户要什么;然后根据用户的需求,做项目的整体设计;设计完毕,进行编码实现;等软件实现后提交给用户测试确认;用户测试完毕,认可之后,交付使用。

好,如果按照这个过程,说明你已经是一个合格的学生――对,是学生,刚刚毕业的学生水平不过尔尔,因为学校仅仅会教给你事情在一切顺利的情况下怎样去做――我想一个智商没有问题的人都能够做到,这是软件工程最基本的要求。

但事实并不是我们想象的那样,很多时候,一个人的项目很少按照这个过程走,理由很简单:不需要。即便是很多公司在强制进行规范化管理,但那份看似完整的配套文档早就在交付产品之前就失去意义了――它占用了我们太多的时间。

开始前的准备

无论多么多么急,对于一个项目来说,最先做的工作应该是要了解用户需要什么――这个时候,怎么去做似乎成了次要的。但是,基本上每次与用户的接触,我们都会或多或少的失望而归,“这个也许就是XXX那样吧”、“咳~你就看着做吧,跟XX差不多就行”、“这块应该是这样的吧”,这些让人头昏眼花的所谓需求,我想各位听得不会比我少。

的确,对于终端用户的项目,我们很难从他们口中得到非常准确的描述――摸石头过河应该是“客户就是上帝”这句话最好的借口了。没有办法,我们只能将希望寄托在马上就要进行的、激动人心的设计工作。

等等!没有计划么?传统的软件工程可是有分析和计划的啊。不过,那个声音似乎又响起来了“太耗费时间了”、“系统很简单,我们不需要”、“不清楚的时候我们可以问上帝”。

今天的工作

抛开一切繁文缛节,我们终于可以进行设计了!但现在,我们看得见摸得着的却只有今天了,那么今天的工作就是我们最最关心的――成本。既然工作总量不会减少,那我们只需按照理想的计划,做自己份内的工作就行了――我想,这一天的工作我们都能够保证,因为计划对于今天来说是合理的,甚至如果你的速度足够快,大可结余出时间来做别的事情。

但事情似乎并不会按照我们想象的那样发展,因为每天除了这些额定工作,我们还有更多的事情要做。

莫名的错误

或许在你拖着还没睡熟的身躯,刚刚要开始今天的任务的时候,却突然在代码中发现了一个错误,呜呼!更让人恼火的是,这个错误并不是昨天带进来的。

“哈!幸亏我每天都有备份”,我想大多数人都已经给自己留下了后路――现在的压缩软件都很方便,打个包完全是举手之劳。凭借直觉――对,现在能够依靠的只能是直觉――辗转于一个个拥有“规范”命名的压缩包中(或许其中还记录了这个备份都做过什么工作),去寻找这段代码是在什么时候诞生的。

值得庆幸的是,有很多强大的代码比对工具供我们使用,它们为我们节省了大量的时间――有时候,这些工作并不是有时间就能完成的。没用多长时间,我们就找到了错误的诞生地――或许我们还因为使用了折半查找的方法来提高速度,嗯,这是个好的开始。

陌生的代码

在我们因为找到错误代码的诞生地而欢呼之余,一阵冷汗随之而来,我们发现那段代码根本就没有注释,或者使用了大量的所谓的技巧来实现的,或许是一段冗长的意大利面条式代码,也或许是更让人恼火的事情:错误的注释!。哦对,之所以这样,是因为我们的时间有些紧,为了赶工才会这样做的;也可能是因为工作到太晚写出了一些混乱的代码。

不过这个时候,我们没有必要责怪自己的记忆力,也并不是老年痴呆的前兆,转战于如此庞大的代码结构中,或者“我的代码别人没法修改”是当前作坊公司一贯的作风。不过但我们却忽略了这样一个道理:3个月后,你也是“别人”。那么如果真的这样去想,3个月后我们仅凭代码就能发现它的错误已经非常不容易了――当然,发现和修改是两码事。

虽然修改可能如此之难,以至于早餐也即将变成午餐,但问题终归在我们的艰苦努力下解决了,值得庆祝。编译运行……我们可能发现了让人呛水的事情――同样的错误不只一处。

双胞胎?多胞胎?

按照业界公认的理论,吭哧C和吭哧V(复制和粘贴)方法是速度最快的,发明这个功能的人或许应该获得诺贝尔工业奖,因此这一方法被众多程序员当作提高效率的法宝。我们应该也不例外,点两下鼠标就会出现一个复制品的功能简直太具有诱惑力了,不过,我们似乎还发现了它的一个致命缺陷――即便是错误,它也会原封不动的克隆一个。呜~那我们刚才发现的问题可能就是来自于此。

或许这对于我们来说也并不可怕,既然第一段代码已经修正,那么将它再克隆几次不就可以了吗?为了午饭,说干就干!

彩票式设计

匆匆吃完午饭,忐忑不安的跑回办公室――刚刚修改的代码还没有测试呢。编译、运行,出错。应该是(嗯,很流行的口头禅)刚才一时疏忽写错了代码。再经过一番调试,代码终于通过了――注意,是我们自己认为通过了。

之后又是一阵复制、粘贴,问题终于算是解决了,当然我们自己是这样认为的,别人问起,也只能回答:应该吧。这样的心安理得对于我们这个小项目来说已经足够了。或许到这里我们还不能彻底松口气,因为错误的来源是一个礼拜之前,那么这就意味着,自那天来的所有备份文件都需要修正这个错误――同样是传统的方法。而至于这些修改是不是都起作用了,呼!上帝才知道,我的时间不够去一一验证了,就当买了张彩票。

花了半天加上一中午的时间,嗯,还好,只用半天的时间就解决了发现的错误。我们终于可以在后面半天的时间里进行下一步的设计工作了――对于除错来说,这一天的设计工作简直太简单了,几乎用不了半天。

用户的实验田

午休时间应该也过了,我们应该打开设计要求,准备下一步的工作了。但就在此时,项目经理(这个名词似乎很流行,也很光亮,但我实在无法将其跟一个人的项目联系起来,或者它仅仅是某个词的文明用语:包工头)突然跑过来(对!他只带来了一张嘴),说用户传话过来(怎么感觉像那个?难道是我古装戏看多了?),他想在现有的系统上增加一些功能,但这些功能他只是想看看效果,如果效果好,就可以真正增加进系统――这种“无礼”要求也许已经让你暴跳如雷了,我们成了小白鼠!

不过仔细想想,我们不是一直在这样安慰自己吗?“用户就是上帝”,嗯,小白鼠就小白鼠了,而且实际上这个问题也不难解决,复制出一份工程文件来不就OK了?

项目经理继续说:用户要的功能并不仅仅这一个,他想试验的还有这个、这个、这个……。好吧,尽管来吧,反正几份都是同样的复制操作。

想不到,项目经理的话还没有完:“上周让你试验的那几个功能,用户比较满意,他要求把它们都加进来……”,如果不出意外,我们的头部会明显感觉到异样,甚至越来越怕看到那个采蘑菇的小姑娘。

“这根本没有在计划之中!”我们终于忍不住叫出来。但是事实就是这样,我们根本没有办法预知这些事情――确切的说是准确的预知。现在需要做的就是硬着头皮往上冲。

当晚餐的香味飘过来的时候,我们可能很幸运的将这些功能都集成在了一起――但仅仅是能用,能用而已。到底有多能用?没有人告诉我们。还好项目经理下班了,用户睡了……好吧!没人来打扰了,那就提提精神来做今天应该做的工作。

我想这种滋味,各位都或多或少或者一直在品尝着,办公室通明的灯光似乎只带来一个奢望:周末我一定要好好的睡个懒觉,我要报复加班的生活……

明天的工作

拖着疲惫的身躯回到床上,已经没有任何力气再去回忆一天的工作,只是期望明天的工作会有些变化,但事实却总是跟期望相反――外甥打灯笼,照旧。希望似乎是在更远的后天。

某天的工作

突然你在某天发现了跟往常不一样的事情――或许这会给你带来一丝新鲜感。

Ÿ           设计的功能根本不是用户想要的;

Ÿ           压缩包的备份数量已经到达了三位数;

Ÿ           数据结构需要变动,但逻辑已经写死在了SQL语句里;

Ÿ           一个月之前解决的问题又冒了出来;

Ÿ           新增加的功能只有部分能够使用;

Ÿ           想改动一处代码,却除了靠眼睛,没有任何理由告诉自己它带来的影响。

Ÿ           修改了1个错误,却带来了10个错误;

Ÿ           用户需要知道这个答案:你凭什么说自己的系统已经满足我的要求,而且没有任何错误?

Ÿ           ……

交付期限越来越近,棘手的问题却越来越多,这些所谓的新鲜感告诉我们,事情似乎已经糟糕到无可救药的地步了,我们开始抱怨用户的要求有多不合理、老板的压榨有多么的狠、程序员是多么的难当、技术是多么的难搞,甚至我们开始憧憬做管理和做业务远比做技术要好。我们错在哪里呢?我们一直辛勤的努力,一刻也没有停歇为什么还是这样的结果呢?

一些建议

由于时间和本人水平的限制,我只是简单的描述了几个具有代表性的细节问题――不要小看这些细节,它们极有可能是堤之蚁穴。

能够坚持读到这里的各位,也许已经隐隐约约在其中找到了自己的影子,甚至有的人会说这是自己的翻版;当然,也会有一些朋友已经解决了这些问题――这是我们最希望看到的结果。问题暴露了,我们并不是搬只马扎来隔岸观火,一起来总结一下其中的经验,或者借来别人的经历对下一个项目给出一些建议,也算是我们的项目没有白白的受尽创伤。

那么,我想这个时候最应该先做的事情就是抛弃“一个人的项目不需要软件工程”的想法,因为它自始至终都在阻碍我们的进程――这个想法让你只关注今天的成本而忽略了明天的风险。通过这个相对典型的项目,我们至少可以认识到以下几点:

Ÿ           抛弃“提高效率就是加紧干活”的观念;

Ÿ           无法预知不等于无法准备,也不等于无法减轻由此带来的影响;

Ÿ           今天的额外成本来自于昨天的风险,而且这个转换超过了11

Ÿ           用户的需求变化应该可控,最起码也是在一定的阶段相对稳定;

Ÿ           注重代码注释的规范性,为方便别人阅读而写代码;

Ÿ           对于代码的变更应加入版本管理机制,记录每次变更的日志;

Ÿ           为变化而设计,明天的事情今天做;

Ÿ           建立完善的单元测试环境,使代码的更动有硬性保障;

Ÿ           避免使用复制粘贴式代码重用,应使用模块化设计;

Ÿ           需求、设计、编码可以以任何速度进行,唯独除错才会耗费时间;

结语

业界有大师语:任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码,才是优秀的程序员。那么对于一个软件系统来说,我们的工作就不仅仅是让机器正确执行这么轻松了。优秀的设计与蹩脚的设计唯一区别,就在于前者是向人展示它要干什么。而软件工程之于设计(对于一个人单打独斗的项目,设计应该是我们的绝大部分工作),正是保证了这一点。

由于经验微薄、水平有限,本文所述也许仅仅是井中窥天,无缘于大雅之台,但实望以粗糙的个人感受让各位少走些弯路。

标签:
文章分类 FK Coding, 一张窗户纸
5 条评论在 “今天还是明天――一个人的软件工程” 上
  1. 呆呆 说道:

    实话说,写的不错!
    多写点建议,感觉有点欠缺!
    不太丰满

  2. zhmnsw 说道:

    说实在的,这篇文章上来之前我也考虑了再三,仅仅记录了自己曾经摔过的跟头,至于建议,生怕半瓶子水的水平而让大家混淆视听,实不敢妄加指点,因此后节的建议仅仅提了些比较抽象的想法。<br />另外,一个很抽象的学科,本是仁者见仁智者见智,仅仅把现实摆出来让大家看清,对于我来说就已经很是欣慰了。

  3. 匿名用户 说道:

    软件工程就是先学工程在学软件

  4. a6233593 说道:

    嘉宾再次留下了他金牌会员般的足迹。

  5. yvfish 说道:

    Great,赞一个先。
    对入门提高中的程序员有较大帮助。

zhmnsw 进行回复 取消回复

电子邮件地址不会被公开。 必填项已用 * 标注

*

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

点赞
如果您觉得很赞,我将非常乐意接受虚拟币的捐赠,以示您对我的肯定。

比特币钱包地址:
1PqpqA8FyH3NbfCrbcRd1YxQk3LEsSEYDV
莱特币钱包地址:
LRTdmovGGVEHCKWz7JdL9aiB7VZkuNycJf
站点勋章
网站统计