写软件,很多时候都让我感觉很矛盾,经常顾此失彼。写的太灵活了,项目时间不够,写的不灵活,客户一反馈,改的又很惨。
以前想看看什么设计模式的,可是,看不太懂,感觉懂了,也不知道怎么用。复习复习了什么软件工程,什么瀑布模型,简直就不太
搭边。最近写了一个中文分词系统,里面我懂了不少东西,希望和大家分享。
这个分词系统,和普通的分词系统差不多。就是一篇文章,用一定的算法把词切开了,还有可能要计算关键字,词频。tf idf 等等。
接到这个项目时,我就想要好好写这个软件。初期的准备也很足,现在运行了一段时间,需求也改过一些,个人感觉还不错。
1. 划分模块的原则。我的一个原则是,事情能够大事化小,小事化了,软件也一样,必须把问题划分成几块。对结构化设计 和 面向对象设计,说实话,
都没有仔细去理解过,我的一个个人原则是,按照功能快。先粗略划分。
比如,分词,我把这个分为:
1. 字典模块
2. 计算最有可能的分词结果
3. 词性标注
4. 分词接口
基本上就是按照需求的流程图来划分。
这样划分,也不是说,四个部分 都是独立的。开发四个独立的模块。
1. 确定每个模块的接口:
1.1 调用关系
1不调用其他的模块
2 要调用1
3 要调用 1
4. 要调用2,3
这样看来,字典是做基础服务的,在第一层。
2,3 是 中间层。
接口在第三层。只有这里是用户能直接访问到的。
这样大概的关系就出来了,下面要看看每个模块要提供什么功能,或者说接口。
确定的方法很简单,从第三层的接口就老板要的功能了。然后,倒推到第二层的接口。再从第二层,倒推字典的接口。
2. 基本的接口出来了,就是要实现每个模块。
当然,这只是脑子里面的设计,不是直接独立的去实现每个模块。我的习惯还是从 数据结构 + 算法
的角度去设计。构造出算法,然后,设计数据结构。
3. 实现一个公用类库
在设计的时候,发现,很多数据结构 是可以重复使用的,很多函数和具体的业务逻辑无关。我把这些公共的东西都放到第0层。
这一层的东西,和具体的业务逻辑无关,主要是实现一些数据结构。
比如,排序链表啊,排序队列等等。这个类库,估计以后以后的项目也能用。
4. 实现第0层, 实现第一层,然后是第二层,第三层。这保证,在开发的每一个时刻都能测试。
基本上是这样设计的,当然其中也存在很多问题:
1. 老板希望尽快的看到效果,也就是第三层要尽快的出来,但是,按照我们的想法,第三层不可能这样快就出来。因为这是最后的一步。
我开发的时候,是这样的原则:测试阶段,效率,性能问题暂时先不考虑过于充分,但是,核心的算法一定要实现。这样就大大加快了开发的
进度。比如,字典查找树的问题,为了尽快的出来效果,我采用者的设计方法如下:
主要的想法是,对外的都是一个字典的接口,具体实现可以有多种。就像你可以用SQL 查询MYSQL 也可以查询MSSQL。要实现一个复杂的查找树,比如b树,进行查询还是要点时间的,但是,你用个数组,然后用二分法查找,几乎半天时间就可以搞定了。
测试阶段,可以用数组。效率低很多,但是不会影响分词的效果,开发时间也快。
发布阶段,写好b树查找,加入新系统,系统的效率就马上上去了。
开发中的 N-short Path 问题,在测试版本里面,我也采用了一个简单的算法(N^2 速度),很快就实现出来了。
也就是说,有简单的算法,越简单越好,效率不要优先考虑。但是,要为以后更换算法,预留空间。
这样,老板在两个星期内就看到了测试版本,虽然速度非常慢,一篇文章要1s钟,但是,基本效果有了。这时,老板就会有新的需求了,想法也就会改了,一般你做出个东西,
老板的需求才会越来越明确。所以,测试阶段的开发周期要很快,结构要够灵活。
2. 要不要加入自己的想法?很多时候,你可能突发奇想,或者仔细考虑后,还有些1%的可能性会发生的问题,建议做好备忘录,在测试版本出来以后再做调整。
3. 业务逻辑尽量分离。下面的结构是我经常用的结构,一个抽象类,或者一个接口。然后,下面一些子类。这些子类代表各种情况,或者代表不同的算法。基类里面我一般放些通用的,和具体业务逻辑无关的类,到了,子类里面才加入业务的逻辑。但是,我面试的大多数人的作品,很多就是要牵一发而动全身的。一个需求改下来要改好几处。
4. 是不是什么都要统一起来?很多人,特别是像我这样数学类出身的程序员,都喜欢把所有的东西统一起来,把任何类都写的很通用。就想物理定律一样,什么样的问题都能解决。把项目当类库来写。其实这样的东西要适当。毕竟,我们做的是一个项目,里面有一些人为的很特殊的需求。很多,情况也不可能发生。
5. 不要用太多的技巧。 很多人,经常用些什么位运算啊,非常复杂的表达式。其实,这没有必要。平平淡淡才是真。
总之,写代码不能太过,不能太不灵活,也不能太灵活。适可而止。
软件要有一种层次感。同时,接口的概念要深入每行代码。
写了三年代码了,就这次,感觉写了一点结构比较良好的代码。
以前想看看什么设计模式的,可是,看不太懂,感觉懂了,也不知道怎么用。复习复习了什么软件工程,什么瀑布模型,简直就不太
搭边。最近写了一个中文分词系统,里面我懂了不少东西,希望和大家分享。
这个分词系统,和普通的分词系统差不多。就是一篇文章,用一定的算法把词切开了,还有可能要计算关键字,词频。tf idf 等等。
接到这个项目时,我就想要好好写这个软件。初期的准备也很足,现在运行了一段时间,需求也改过一些,个人感觉还不错。
1. 划分模块的原则。我的一个原则是,事情能够大事化小,小事化了,软件也一样,必须把问题划分成几块。对结构化设计 和 面向对象设计,说实话,
都没有仔细去理解过,我的一个个人原则是,按照功能快。先粗略划分。
比如,分词,我把这个分为:
1. 字典模块
2. 计算最有可能的分词结果
3. 词性标注
4. 分词接口
基本上就是按照需求的流程图来划分。
这样划分,也不是说,四个部分 都是独立的。开发四个独立的模块。
1. 确定每个模块的接口:
1.1 调用关系
1不调用其他的模块
2 要调用1
3 要调用 1
4. 要调用2,3
这样看来,字典是做基础服务的,在第一层。
2,3 是 中间层。
接口在第三层。只有这里是用户能直接访问到的。
这样大概的关系就出来了,下面要看看每个模块要提供什么功能,或者说接口。
确定的方法很简单,从第三层的接口就老板要的功能了。然后,倒推到第二层的接口。再从第二层,倒推字典的接口。
2. 基本的接口出来了,就是要实现每个模块。
当然,这只是脑子里面的设计,不是直接独立的去实现每个模块。我的习惯还是从 数据结构 + 算法
的角度去设计。构造出算法,然后,设计数据结构。
3. 实现一个公用类库
在设计的时候,发现,很多数据结构 是可以重复使用的,很多函数和具体的业务逻辑无关。我把这些公共的东西都放到第0层。
这一层的东西,和具体的业务逻辑无关,主要是实现一些数据结构。
比如,排序链表啊,排序队列等等。这个类库,估计以后以后的项目也能用。
4. 实现第0层, 实现第一层,然后是第二层,第三层。这保证,在开发的每一个时刻都能测试。
基本上是这样设计的,当然其中也存在很多问题:
1. 老板希望尽快的看到效果,也就是第三层要尽快的出来,但是,按照我们的想法,第三层不可能这样快就出来。因为这是最后的一步。
我开发的时候,是这样的原则:测试阶段,效率,性能问题暂时先不考虑过于充分,但是,核心的算法一定要实现。这样就大大加快了开发的
进度。比如,字典查找树的问题,为了尽快的出来效果,我采用者的设计方法如下:
主要的想法是,对外的都是一个字典的接口,具体实现可以有多种。就像你可以用SQL 查询MYSQL 也可以查询MSSQL。要实现一个复杂的查找树,比如b树,进行查询还是要点时间的,但是,你用个数组,然后用二分法查找,几乎半天时间就可以搞定了。
测试阶段,可以用数组。效率低很多,但是不会影响分词的效果,开发时间也快。
发布阶段,写好b树查找,加入新系统,系统的效率就马上上去了。
开发中的 N-short Path 问题,在测试版本里面,我也采用了一个简单的算法(N^2 速度),很快就实现出来了。
也就是说,有简单的算法,越简单越好,效率不要优先考虑。但是,要为以后更换算法,预留空间。
这样,老板在两个星期内就看到了测试版本,虽然速度非常慢,一篇文章要1s钟,但是,基本效果有了。这时,老板就会有新的需求了,想法也就会改了,一般你做出个东西,
老板的需求才会越来越明确。所以,测试阶段的开发周期要很快,结构要够灵活。
2. 要不要加入自己的想法?很多时候,你可能突发奇想,或者仔细考虑后,还有些1%的可能性会发生的问题,建议做好备忘录,在测试版本出来以后再做调整。
3. 业务逻辑尽量分离。下面的结构是我经常用的结构,一个抽象类,或者一个接口。然后,下面一些子类。这些子类代表各种情况,或者代表不同的算法。基类里面我一般放些通用的,和具体业务逻辑无关的类,到了,子类里面才加入业务的逻辑。但是,我面试的大多数人的作品,很多就是要牵一发而动全身的。一个需求改下来要改好几处。
4. 是不是什么都要统一起来?很多人,特别是像我这样数学类出身的程序员,都喜欢把所有的东西统一起来,把任何类都写的很通用。就想物理定律一样,什么样的问题都能解决。把项目当类库来写。其实这样的东西要适当。毕竟,我们做的是一个项目,里面有一些人为的很特殊的需求。很多,情况也不可能发生。
5. 不要用太多的技巧。 很多人,经常用些什么位运算啊,非常复杂的表达式。其实,这没有必要。平平淡淡才是真。
总之,写代码不能太过,不能太不灵活,也不能太灵活。适可而止。
软件要有一种层次感。同时,接口的概念要深入每行代码。
写了三年代码了,就这次,感觉写了一点结构比较良好的代码。