没有良好设计和管理的产品,必然会遇到困境。也许这个困境只需要简单办法就能够通过,也许这个困境将使你不得不从起点重新开始。
我们的排版软件,在中期阶段正是遇到了很大的困境。当前期开发很是顺利,甚至已经有版本在用户处实施,使用后,这个困境就像开快车时进入了一个死胡同,让我有崩溃的感觉,也直接导致我产生了退却之意。
那么我到底碰到了哪些困境呢?
困境一:版本和配置管理
首先遇到的是版本和配置管理的困境。也许我们的项目经理也是新手,在软件开始发布版本后,当用户提出某个问题后,项目经理会在解决这个问题后就向用户发布更新的程序。但是,却没有做任何记录。当时并没有使用任何配置管理工具(连VSS都是这之后才开始采用的)。要知道,排版软件并不使用数据库,所有用户编辑的信息,都如同WORD一样,是使用数据文件形式存储的,而糟糕的是,这个数据文件形式就是VC中的序列化产生的文件。
由于数据结构经常性的变动,导致数据文件的序列化函数经常性的变动,也导致了不同版本数据文件不能向下兼容,因为本身就没有充分考虑版本问题。
因此,当上海的某用户电话告知新的程序无法读取先前制作的排版文件,而先前的版本已经都被替换掉后,我们两个程序员被紧急的调往上海进行解决,也促成了我第一次的飞机之旅。虽然我们连夜一直奋战到天亮,但还是由于水平有限,没有能够解决这个问题(实在是形成的版本太多,根本就不知道用户的排版文件中的数据结构了)。
通过这件事,我想以后作为一个项目管理者,或者作为一个程序员,对于你负责的一个项目,或者是一段代码,时刻要意识到版本的重要性。也许,从现在看来,有很多方法可以避免这种困境的产生。
比如,产品版本发布不能随意,每次发布都需要有唯一的版本号。
比如,对于用户,也要有版本的管理,对于一个用户使用的版本历史,都要可回溯;
比如,对数据结构的版本管理。对应与其它系统,可能就是数据库版本的管理。当然,不同的是,数据库毕竟还是可以打开进行查看数据项。
比如,还有很多其它更多更好的办法。
通过这个困境,对我的影响是,在以后的项目开发中,使用VSS,CVS和SVN等多种工具进行版本的管理,包括源代码,设计文档,安装程序等等;另外,学会了在工程中的Readme.txt中记录版本的变迁及What’s new;在Version中定义程序的版本号和时间;在源代码中增加更多的代码更新标签;以及在安装程序中定义安装程序的版本信息。
困境二:面向对象设计和编码
对于程序员来说,更关注的是自己的代码。作为很多计算机系毕业的大学生来说,对于面向对象这个概念早已是滚瓜烂熟,甚至于《设计模式》等书都已是熟读千遍。而实际,大多是纸上谈兵,对这个词并没有充分的理解,往往一开始编码时,会不知所措。
这个我并不是危言耸听。就我的经历,曾经指导过几个新人,初用VC时(其实都是自称使用过VC的),我都会出几个作业给他们做。因为我认为光看书本不练习是无法深入的。其中有个题就是画图形,我只要求是直线和矩形。结果所有人都是直接在视图类的OnDraw和鼠标事件中直接进行所有的操作,根本就没有考虑,是否要进行一定的封装,使得代码更加独立和易扩展;也没有考虑到程序运行的效率。
很不幸,大学刚毕业时,我也是属于这个群体,甚至于更差,因为我还没有用过VC,对面向对象也没有什么个人的理解。因此,随之而来的代价也是不小。由于开始时比较顺手,代码模块也不大,几乎所有的操作都在视图类完成,虽然也写了一些类,但实际上,从现在看来,只是一些数据类,并没有封装其动作,而所有的动作都在视图类完成了。这么做的结果,是导致视图类无限制的膨胀。到我碰到困境时的情况是,我们四个新人,每人写的视图类的部分各有一个cpp文件,另外还包括一个主文件,放置鼠标事件等公共部分,整个视图类代码行数有三万行左右。
也许就算这样,很多的软件也能扛下去,但我很不幸,遇到困境了。用户要求对所有图形都增加旋转功能。于是,我乱了。由于整个类结构没有进行很好的设计,甚至于一个鼠标点击事件都有上千行代码,要增加一个旋转功能简直是工程量浩大,因为我无法确定对多少代码有影响,很容易出现东堵西漏的局面。
这个困境对我来说非常致命,导致我的心情极差,兴趣降到了最低点,对自己的能力也是更加的怀疑。
当然,若干年以后,这个困境对我来说却是一笔很大的财富,使我对面向对象有了自己的理解,对于模块开发形成了自己的一套思路。这感觉就像不会骑自行车时,觉得人能在自行车上不倒下来,真是神奇;而从不会骑自行车到会骑自行车,那其实就是一刹那的感觉,那个感觉很美妙。但为了收获这一刹那的感觉,你可能要付出的是很多次的摔倒。区别是,有些人摔倒一次,就找到了这种感觉,而有些人,也许摔倒一次,就不再碰自行车了;也许摔倒了不计其数次,却一直没有找到那种感觉。
我觉得面向对象这个东西,也是这样。不是老师在课堂上讲一讲,你就算会的。必须亲自去体验,甚至于付出一些代价,你才能真正的驾驭它。
在CSDN回复问题时,经常看到有些网友告知别人用全局变量等方法去解决问题。但其实很多都是缺乏面向对象的概念,只注重解决眼前的一个小问题,其实这些都是你实践的好机会,但却都被你放弃了。
困境三:变更管理
这个困境,导致了我对整个软件失去了信心。其实事情说起来很简单,在排版软件中,有个环境常量,表示数值的精度。由于先前确定的精度到后来发现不够,因此就乘以了10。但问题正是由此而来。
自从改了数值以后,软件总是出现奇奇怪怪的错误,原先没有问题的地方,都会莫名其妙的出BUG,郁闷之极,进行调试,发现问题居然出在整型溢出。原来有些算法中,用到了诸如三角形的平方和开根号等,在开根号之前的平方和出现了溢出。因为之前的环境常量使用的是整数,比如把最小精度0.01毫米计为1,那么所有整型的长度值记录的就是0.01的倍数值。原来没有乘10时,所有计算量都在有效范围内(因为排版的杂志也好,报纸也好,大小都不会超出32位整型);但乘以10后,由于有些进行的是平方和,因此等于扩大了100倍,所以会出现溢出现象。
数值的溢出可以说是很难通过阅读代码来查出的,因为很多溢出都是在算法中的一些中间变量产生的。更为担心的是,很可能很多溢出会潜藏起来,也许一天,也许一年都不会暴露,因为它是需要一定的条件才会触发的;而且即时出现问题,也是很难进行调试的,因为溢出大多是在算法中的中间过程产生的临时变量,而且程序也不会出现崩溃,只是最终的运算结果不正确。因此要定位很困难。
所以,在做一些变更前,一定要自己推敲会有哪些影响,或者哪些模块会被涉及到。所有涉及到的地方都应该进行评估,以及在完成后进行必要的测试。
可以说,这个困境,使我对这个软件失去了信心。也对我第一次跳槽产生了很大影响。当然,我第一次跳槽并不是完全因为它,而是由一个更重要的原因。
也许,大家还有其它更多更多的方法,都可以避免困境,走出困境,但重要的是,我们不要等到困境发生时才想起这些。希望大家都能够找到属于自己的方法来避免困境。我也会在后续的章节中给大家介绍我的方法,也许不是最好的,但却是我自己的。