五一期间一直在写代码,现在看来是个错误的选择。我本以为尽管是一个训练软件工程的项目,然而把程序完成仍然是十分必要的,甚至是最重要的。如果系统都没能按计划完成,那这个项目谈何成功呢。于是,我们决定利用五一期间的长假完成一些代码,主要是我负责的界面部分。为什么从界面开始,因为之前写过一个原型系统,对这个系统的轮廓已经略知一二;另一方面,更重要的是,我们还没有进行详细的设计。设计只是表面的,比如确定了RMI,确定了门面模式,确定了最简单的单控制器机制等等,然而一个核心是内部的方法、属性都没有具体定义,尽管有些可笑的是完成了数据库的初步设计。一切,都有些荒唐,至少顺序上是的,也许是我个人有些急功近利了,想早点完成这个事情,毕竟我们还有别的课要上,软件工程不是我们本学期的全部。当时的想法是:我写写界面,边写边进行类的设计,然后逐渐明确数据库设计方案,然后列出方法簇给负责数据库的拍档去完成内部逻辑。换句话说,所有的接口都是边写界面边确定的。这样做是完全错误的,本以为可以缩短时间,哪知道在我向其他人解释这些接口的时候费尽周折,以至于我自己都很难描述清楚某个方法究竟是做什么用的。这时我才渐渐明白为什么一定要先确立接口,这是大家共同的语言,有了接口,有了明确的子系统划分,大家可以舒适地并行开发。然而现在,我们的情况更像是流水线开发,我做出一个界面,扔几个方法给数据库那边去完成功能。可事实上我在逐渐往后开发时总是不免的又会修改前面的设计,越改越乱,这才造成了数据库那边的编码困难。核心是什么,核心是分析设计不充分,甚至可以追述到需求的不充分。比如确定一个订单,我们只是简单地提到了要有这个订单,然而订单具体包括哪些项目我们没有明确下来,而是打算留到后面的分析设计去完成。我们之所以敢于这样是因为这是一个学生项目,没有真正的客户,我们甚至可以随心所欲地更改需求,只要可以方便我们实现。于是,为了省事,我们将许多稍显麻烦的工作留到了后面,一次一次往后拖,逐渐的,越发混乱。
现在想来,我们应当在需求阶段就明确界面元素(事实上原型系统应当更加完善),这样我们对所有的事情可以达成统一,不至于在后面找实体类时东挑西拣迟迟不能决定。我们的功能或者说范围定义太过模糊,我们没有确定一个明确的问题陈述(导师的推荐项目题中给了一个明确的Statement作为客户的代理,可以据此进行需求分析)。也就是说,我们还不大清楚这个系统到底应当完成什么,然后,一切却开始了。幸好这个项目美其名曰一个迭代的开发过程,我们可以逐步修改我们的需求分析,直到在问题域和我们的能力之间达到平衡,或者说是妥协。其实现在,因为时间关系我们已经放弃了接近1/3的功能,这个数字可能还会继续扩大,最后可能可以真正实现的部分只是一个很小的子集。导师的话提醒了我们:重要的是把整个流程走一遍,真正做出什么东西来并不重要。
我们显然没有追上预定进度,这完全是因为不恰当的提前进入了编码阶段。不过比起导师制定的一些里程碑底线还是绰绰有余的。我们的评审工作得到了肯定,选用经典文档模版收到了称赞。助教提了一些意见,的确,我们在用例分析时犯了些严重的错误:用例,是面向用户的,能够为用户提供有意义结果的动作序列。我们表示了一个用例叫做数据库管理,然后其他所有的用例都include了这个用例,我们为之得意洋洋。然而,我们忽视了这个数据库管理对于用户而言是不可见的,或许它不适合作为单独的用例出现,尽管它的确是有意义的动作序列。在分析阶段将它提取出来建立一个分析包或许是一个合适的选择。同样的,我们在书写需求规约的Action时,写的太过简单,千篇一律。其实Action或许是需求文档中最重要的一个部分,它就代表了这个动作序列,尽可能的详细对于后面的分析设计是极为有利的,可以避免不一致性。
我们几乎跳过了分析阶段,直接进行的设计和编码,对于小的系统,这样做并非不可行,然而带来的不利后果就是可能会产生不少模糊,对一些概念可能会出现不一致,对需求的理解是不详尽的,不充分的。寻找分析包和分析类本身对于理解这个系统是极为有用的,甚至超过产生的制品。寻找分析类是有趣的过程,我们在后面补分析文档的时候体会到了这一点。其实看着一个个包被提取出来相当有成就感,我们对系统的理解逐步深入,各个模型逐渐细化,随之再进行设计编码一定相当轻松。可惜,我们没有忠实执行这个过程,导致我们的设计过程相当艰辛,最终产生了一个“万能类”Controller,处理几乎所有的功能请求。这是很多书上提到的经典反例(特别是三大巨头写的《统一软件开发过程》),很有趣,这个大反例就出现在我们身上。不过这个系统的确相当简单,似乎没有必要将这个控制器再拆减了。即使设计阶段作了拆减,相信我们实现的时候一定会再把它们合起来。
编码真的成为了最没有意思的事情,绘制UML图是那么有趣,编码显得那么枯燥。其实写代码的成就感来源于解决问题的挑战性,一旦完成了设计,就表明所有的功能都是理论上已经实现了的,这样写代码就成了例行公事,哪里还会有成就感而言。尽管对于如期交付是有益的,不过可以想象程序员的生活有多么枯燥和乏味。说到写代码,其实对于这样的小型系统,两三个人负责就可以了,更多的人参与其中,花在交流和协调上的时间远远超过人员增加带来的速度提升。当然,这与我们对接口的定义不清有关,与我们的编码能力和表达描述能力有关,不过对于学生项目,参与编码的人越少越好。事实上,一个小组中,真正有能力编码的又能有几个人呢。
管理方面有一些新的收获,凡是一定要以身作则,比如迟到这件事,起初我要求大家讨论会不能迟到,然而我自己却迟到了几次,说出的话自然没有说服力了。后来自己来得早了,大家自然也相互配合。很多朋友说一个真正的项目经理,应当学会尊重组员,是请求他们做事,而不是要求他们做事。是的,一方面,大家是朋友、同学,不是也绝没有上下级的关系,大家合作的努力完成这个实践,仅此而已。大家更应当学会享受这个过程,能学会些东西更好,重要的是相互熟悉,相互合作,培养这种精神,培养合作的精神,培养这种努力的意志。毕竟,现在学的东西以后能用到的很难说有多少,然而思想上的是能伴随一辈子的,理念和思路值得花时间去研究。
最近的讨论会越来越少,毕竟,进入编码阶段要讨论的事也没有多少,我们更多的讨论仅仅是聚在一起吃吃夜宵,相互交流一下进度,分配一下后面的任务,仅此而已。似乎一切都变得有些轻松,毕竟,大局已定,距离最后的提交已经很近了,大体已经有了定论,需要提交的文档基本已经完成了雏形,评审之后就可以了,我们即将收工。因为对于系统本身的实现不很关注,我们不会将更多的时间花在上面,这意味着后面我们将没有太多的事情可以做。也许一切就要这样结束了。
我们这个周末会有个聚会,算是大家忙了两个月,轻松一下,大家一块儿唱唱歌吃吃饭,调节一下。如果可能的话,为后面几天的编码和测试工作开个好头,大家都能精力充沛的做好收关工作。其实最近的一个月,因为编码的关系,过得并不开心,没有能享受软件工程带来的快感和愉悦,确实,写代码是枯燥的。我们在饶有兴趣进行了一个多月的新事物尝试之后,好奇心淡了,实质的任务多了。前一个月,我们会为了一次评审而欢呼雀跃,那是多么有意思的一件事;现在,我们为了应付助教参与的一次评审而焦头烂额,准备大量的文档已经成为习惯,每天每个人都在和文档打交道。满脑子的英文使得我们已经无暇顾及别的事情,是该好好休息了。都说战线不能拉得太长,两个月对于初涉这个领域的我们而言,是有些长了,有些单调和乏味。我们总是时常后悔将项目的范围定得这么大,然而一切已经于事无补,我们能做的只有在烂摊子上继续走下去,把这件事做做好,问心无愧就可以了,我们不愿意这个实践是被我们“糊”过去的。
不得不提一下人,人的因素对软件工程有多重要已经无需再提,每个人的能力是有差别的,我想组长在安排任务上应当有些考虑。固然大家争取平分所有的任务,然而不是每个人都能够胜任自己的工作,能力强的理所当然可以接受更多的工作。这不是对他的不公平,这不会招致他的反对,这是对他的一种信任,我想每个强手都会乐于接受挑战。组长对于几乎所有的事情都应当有所过问,干预的程度可以不同,但是一定要准确的知道每个人当前在做什么,未来一周要做什么,没有这个度,项目的进度将相当可怕。有时候,订立截止日期是有道理的。一味的放任可能造成进度的拖沓,适当的严厉和所谓“独裁”可以挽救这个项目,然而如何平息大家的不满就需要自己做功课了。