这个套系统算是非常完整的,由我自己全程设计构建的系统。其他几套系统多多少少是与同事合作之类的,并没有那么完整的经验。
不算大的一套东西,但是却的确学到很多,主要是关于数据库设计、设计api、代码结构设计、项目推进、项目时间和难度的预估、测试预估。
项目从拿到需求到积分系统的完成(包括对接现有支付模块,编写测试之类)其实耗时不多,大概在16个天,对账系统包括测试做了4天总工作日大概在20天。但是这个看似正常的时间,跟最开始估计的时间相差甚远。我在前期有很多加班包括周末加班的情况下才勉强能照着现在这个进度完成,实际上最初估没有对账系统的完成时间只有12天,中间差了4个工作日,算上加班的时间可能差了7个工作日。可能这就是不经常预估项目时间的人容易犯下的错误吧,对自己的编码效率莫名自信,殊不知里面其实有大量不可控因素影响进度。其中很大影响比重在于修改前面人写的支付模块的代码上,不仅需要大量时间阅读前面的人写的代码和思路,还需要把自己的逻辑加进去,这极花时间。所以估时间的时候一定要预留充足的时间,这个后面再提一下。
(一) 还是按顺序来吧,先说数据库设计,设计API,设计代码结构
花了大概两天时间设计了数据库,一共涉及到11张表。弄好了之后拉着leader和主管开了一个短会,我阐述了我的设计思路,然后拉着他们帮我看看设计是否存在问题,或者有没有地方有漏洞是我没有办法考虑到的。这里我其实设计了两张流水表,每当有一笔收入或者支出的积分,都会在支出和收入的流水表里面增加一条记录,但是最开始的时候,因为某些原因我可能需要update流水表里面的字段,但是leader告诉我流水表最好不要有update的操作,这样可能比较容易出错,流水表只往内记录,不更新,这样不会出问题。这点使得我开始从表稳定性去思考这个问题,觉得还是有一定道理。因为流水表最终在结算的时候可能用于对账,一旦这个表因为更新字段出现问题,那么对账就会出错,电商系统的对账出错的话。。。。。
找前辈帮忙看因为他们比我更熟悉系统,所以一定要拉他们帮自己看看,否则有些坑,或者以前弄的hack可能会影响到新的系统进行某些操作。做了一些改动,然后我们一致同意了一个决定,就是如果全部做好一起上线代码量超大最少2k行,可能完全没有办法review。毕竟要花时间去看一个2k行代码的项目,还是需要花费不少的时间。所以决定将项目拆成两块分批上线。由于构件积分的查询存储使用之类的东西是完全不会影响到现有系统的,所以可以单独上线,然后将接入现在的支付退款系统作为另外一部分进行上线。这样就拆开了现在逻辑和新构件系统的耦合,看代码上面也会变得稍微方便一些。
当时讨论完之后,leader让我最好当天的下午,或者第二天的早上将这套东西要提供给app的api定出来,大概需要哪些api。api定下来之后,写东西就可以按照api来依次实现功能了。
这个步骤真的是让我大受启发,在数据库设计完成之后,就设计到底要提供哪些功能出来,就能完成初步的api设计。这样想就可以安好想提供的功能依次编写代码了,也不容易漏掉什么东西。其实这里面最难的部分,就是将思路理清楚,能让自己知道究竟有哪些工作完成,什么先完成,什么可以后完成比较好。在设计完api和数据库之后我可能需要画一些图,和做一些笔记来辅助我思考这些问题才可以让我自己的思路变得更清晰。我自己的画拿了几张a4纸在上面大概画了写了一下有哪些api,名字大概叫什么,提供什么样的功能,可能会设计到的表之类。
最后这个chapter里面关于代码结构:
dao里面存放了各新建表的模型,由于使用orm所以使用到这些模型。
model里面存放了各种中间逻辑,包括调用dao里面的方法创建更新删除数据,拼接各类数据。
外面api提供了各功能的api函数,api层我只处理了入参,保证各入参的类型合法然后传给model对应的函数进行进一步的逻辑处理。
const里面存放了各种可能会使用到的常量。在设计常量存放的时候这次踩了一个坑,最好把有哪几个可能出现的常量类型分别建立一个类,在类下面写,而且最好提前分配好他们所属的数字区域。打个比方,我们可能有支出和收入不同的常量需求,千万不要写成这种:
class IncomeConst(object): INCOME_NORMAL_REVIEW = 1 # 正常评价获得积分 INCOME_REVIEW_BONUS = 2 # 好评获得的额外积分 INCOME_UNLOCK_ORDER = 5 # 订单积分解除锁定 INCOME_REFUND_ORDER = 7 # 退款退积分 class ExpenditureConst(object): EXPENDITURE_FRESH_MEMBER = 3 # 爱尝鲜购买 EXPENDITURE_LOCK_ORDER = 4 # 订单积分消费锁定 EXPENDITURE_OFFSET_CASH = 6 # 积分抵现
应该首先确定income里面占用的是1-1000的数字 那么expenditure就可以占用2-2000的数字 这样能保证同样类型的const是连贯的就像这样:
class IncomeConst(object): INCOME_NORMAL_REVIEW = 1000 # 正常评价获得积分 INCOME_REVIEW_BONUS = 1001 # 好评获得的额外积分 INCOME_UNLOCK_ORDER = 1002 # 订单积分解除锁定 INCOME_REFUND_ORDER = 1003 # 退款退积分 class ExpenditureConst(object): EXPENDITURE_FRESH_MEMBER = 2001 # 爱尝鲜购买 EXPENDITURE_LOCK_ORDER = 2002 # 订单积分消费锁定 EXPENDITURE_OFFSET_CASH = 2003 # 积分抵现
不要把自己搞得像个精神分裂一样,遇到了就往里加一项数字上涨一个。。。。简直不忍直视= =。
exception里面存放了各种可能会抛出的错误,统一继承自Excepition类
(二) 项目推进
项目推进的过程中,无非是按照前面设计好的东西按部就班的一个模块一个模块的写。其实中间也没有碰到什么特别坑爹的事情,只是把原先的两个上线步骤拆成了三个,因为发现前面其实虽然没有构建整套积分支付的东西,但是却有记录用户积分的东西,在用户评论商品之后会给用户记录积分的,这就造成了前面多多少少写了一些积分的东西,我需要把这些原有的东西分好类重新放回到积分新设计的积分模块里面去。这一步其实我在估时间的时候没有想到的,由于前面写的代码比较随便,导致我迁移起来很费劲,有非常多的依赖满天飞,多花了很多时间,而且是影响线上的东西不得不小心翼翼,测了又测。总结了一个经验,先从依赖最少的地方开始拆,拆完一块就测一块。这样一步一步的弄几乎不会出错。千万不要一连迁好几块的东西,最后再来一起测,那个时候要是再测出了问题,我相信改起来的难度非常大。你要依次去排查是前面哪个改动导致了这个问题,这几乎的是不可行的。
迁移的理想状态是,所有东西都有单元测试,如果没对的情况下,跑单元测试都会报错,你就能及时发现并切改动。现实是(好残酷的样子),如果没有单元测试,你可能需要稳健的一步一步来。当你把简单的东西都迁走之后,你会发现之前那些难以迁移的东西也变成容易迁的东西了。
(三) 项目进度预估,对项目时间包括测试部分的预估
就像第一部分谈到的,其实如果时间非常充足和从容,你可能有大把时间来按照我上面说的流程对关键部分进行仔细测试,甚至给每个地方都带上单元测试。现实是如果你自己估的项目时间过短,你可能没有时间来完善测试方面的事情。前提是你的公司里面没有专职QA,测试几乎需要你自己完成,这个时候,将测试时间估算进你项目进度显得非常重要。我这次的测试时间大概占完成项目时间的30%,这个结果很大部分取决于我还用了不少业余时间完成项目或进行测试,以及依赖一些以前同事编写的支付部分的测试,如果全部自己来的话我估计时间至少需要估完成项目时间的50%时间用于测试或者编写单元测试。也就是说如果你估计这个项目你15天可以写完,你可能大概需要额外的7天时间用于测试和修复测试出来的bug,以及自己对代码二次review。这样的进度才能保证你代码的质量,以及在上线之后不用提心吊胆是否会被客户端或者web端的同事找麻烦。
对时间方面的估算,没有几个项目的经历是肯定估不准的,在你发现在deadline之前完成不了项目的时候,一定要向自己的leader说明项目延期,以及因为什么原因导致了项目延期,并且尽快完成项目。所以对项目推进节奏的把控,可能严重影响项目质量,既不可以完全没有压力和时间上的deadline随意完成项目,也不可把项目时间卡得过于紧,因为中间除了我上面分析得问题,还又可能出现诸如你需要请假有事,中途任务的插入。
以上。