2012年回顾
2013-01-07 16:35 康杜 阅读(354) 评论(0) 编辑 收藏 举报年终了,大家都忙着写年终总结。恰逢我负责开发的两个项目也接近尾声了,所以我也写下回顾作为以后工作的参考。同时在工作过程中,我有些心得和体会也想和大家分享一下。
领域驱动设计方法论
领域问题(Domain Problem)是我们构建的系统要解决的问题,比如我们做的这个B2C电子商务类系统,它要解决的问题领域有这些“认证”、“身份及组织”、“用户”、"商品"、“订单”、“交易”和“统计分析”等问题。
按照领域,我们把整个系统又垂直划分为多个子系统,比如:
IAM | Identity Authentication Management 身份认证子系统 |
SmartOrg | Smart Organization 角色、权限管理子系统 |
UserSphere | 用户管理子系统 |
eMarket | 商城管理子系统,包括商品管理、促销管理等等 |
OrderBook | 订单管理子系统,包括订单流程等等 |
eTrader | 交易管理子系统,包括和网银、支付宝、财付通等支付平台的交互 |
Analytics | 报表统计,包括定时任务的启动、运行 |
每个子系统都由两个模块组成:Frontend和Service。具体表现是Frontend是一个Maven的Web工程,会编译成WAR包;Service是一个普通的Maven功能,会编译成JAR包。
根据领域驱动设计的做法,在每个子系统的层次划分上,我们划分为4层,如下图所示
用户界面/展现层 |
负责向用户展现信息以及解释用户命令 |
应用层 |
很薄的一层,用来协调应用的活动。但它不包含业务逻辑。它不保留业务对象的状态, |
领域层 |
本层包含关于领域的信息。这是业务软件的核心所在。在这里保留业务对象的状态,对业务对象和它们状态的持久化被委托给了基础设施层。 |
基础设施层 |
本层作为其他层的支撑库存在。它提供了层间的通信,实现对业务对象的持久化,包含对用户界面层的支撑库,和外部系统集成支撑库等作用。 |
这种系统划分和层次划分的优点:
1) 子系统内聚性高;
2) 各子系统之间依赖关系分明,容易按照依赖关系划分任务(WBS), 并且按照敏捷迭代的方式进行系统演化,比如:身份认证子系统 -> 做角色、权限子系统 -> 做用户管理子系统 -> 商城管理子系统- > 订单管理子系统和交易管理子系统 -> 报表统计;
3) 开发人员由于负责具体的子系统更容易深入问题领域。由于专注某个领域,效率更高;
4) 开发团队形成提供服务、消费服务,容易形成团队协作的习惯。比如说userSphere-service.jar这个JAR包是程序员A写的, 这就要求他进行接口定义是更加严谨,以便程序员B的程序调用。因为程序间存在调用关系,所以要求团队成员之间要通力合作;
5) 层次的划分使得领域的代码和非领域的代码分开,让代码结构更加清晰。
我个人的体会是区分非领域问题(缓存、邮件、消息队列、静态化、与第三方系统的集成等),这些非领域的问题由项目的架构师去实现,提供便利让开发人员更专注地解决领域问题(项目的架构师应该不停地提供框架API减轻开发人员的工作量)。比如我们项目中的三个JAR包(framework-core, framework-web, framework-support)专门为开发者提供编程上的便利。
敏捷迭代开发
在系统开发上我们采用敏捷Scrum方法论指导开发,流程上和上图一样。需要特别说明的是
1) 在每个迭代的开始,我们会安排一个Planing meeting,在会议中我们把Sprint Backlog打印出来,每个与会者都对每个Blacklog做评估(全体评估)。全体评估有个好处是,帮助我们细化任务。
通常来说,一个User story就是一个独立的、符合INVEST原则的需求。为了实现一个User story,每个开发人员心中都有一个任务清单。换句话说,为了实现这个功能,我就要知道我要做什么事情,比如模型设计、Hibernate OR Mapping、单元测试、service方法实现、页面及Action还有集成测试等等。由于每个人对事务的理解不一样,所以每个人对任务的评估就有偏差。在这种情况下,我们一般找出对User story评分最低的和最高的进行任务阐述。通过这两个人的阐述,我们就全面地知道为了实现这个User story的功能,我们需要做哪些事情(Tasks)。特别提一点是,在两个人阐述完了之后,我们进行讨论的过程就是一个简单的分析设计的过程。举个例子,开发人员A说,为了实现发邮件的功能我会通过Velocity做邮件模板发送,所以我会多化半天时间;开发人员B说,需求上说邮件需要持久好,所以我设计一个邮件的模型等等。
在对任务评估完成之后,我们会做一个领域分析和设计(通过模型驱动的方式)。具体做法是,我们在所有本轮Sprint 的User story中找出所有的名词,把它们写到白板上,去除它们当中的同义词,画上它们之间的关系(聚合、组合、继承),然后找出都有领域模型上的动词,例如下订单(order place), 转账(account transfer)等等。通过这些分析,我们领域层的代码就清楚了。
2)在每个迭代的结束,我们会安排一个Retrospective meeting,在会议中我们做功能演示(通过QQ远程桌面把客户也加入演示中)。在演示中,我们往往能够发现User story的问题,或者实现上的问题。我们把这些问题记录在会议纪要中(meeting minutes),会后安排一定时间改,或者录入到缺陷管理工具中。更重要的是,我们列出我们Sprint中出现好的、需要坚持的工作方式,列出差的、需要我们改正的工作方式,列出3个具体可行的、立即采取行动的Action。
测试驱动开发
我们团队进行的测试驱动开发不是正儿八经的测试驱动开发,不是先写测试用例,为了让测试用例通过编写程序代码。先写测试用例的方式连我自己都不习惯,所以不在团队里面推行,只好作罢。但是我们做的了每个类都有测试用例覆盖。现在团队的开发人员已经喜欢测试用例了。写测试用例有这些好处:
1)提供开发效率--不用启动应用服务器,不用连接数据库(测试ORM我们用HSQL内存数据库);
2)防止代码衰退(Regression)--我每天都看Hudson上有没有失败的测试用例,如果有,说明有人改坏功能了
自动化
自动化测试环境部署
通过Hudson将SVN最新的代码更新到编译部署服务器,然后按照依赖关系进行编译,最后重新启动测试服务器。
QA每天早上看到的都是最新的系统,新功能在系统中得到体现,修改的bug也在系统中体现。
数据库更新自动化
在开发的过程中,我们往往会维护多个数据库,比如开发数据库和测试数据库。在日常的开发中,不可避免地要涉及到数据库结构的修改。我们在SVN的dbscript按照日期命名SQL脚本。然后再自动打包部署测试环境之前,
自动化数据库首先执行。这样测试数据库就和开发数据库一致了。做法写在这里了http://www.cnblogs.com/cando/archive/2012/03/13/2393659.html
很遗憾的是我们没有实现自动化功能测试。
技术上的进步
NoSql之CouchDB的使用,了解了B树,B+树
在商品详情页面中,商品咨询和商品评价访问量大,为了减少核心数据库的压力,我们采用NoSql的CouchDB保存商品咨询和评价的记录。CouchDB可以分布式部署,记录可以在不同的节点之间复制。
java.util.concurrent.ConcurrentLinkedQueue的使用
商品的点击率存放到ConcurrentLinkedQueue中,到达一定的数量或者是到达一定的时间的时候,系统调用存储过程,将数据更新到核心数据库。
java.util.concurrent.Excecutor的使用 --并发地和不同的系统交互
java.util.concurrent.locks.Lock的使用--JDK1.5使用Lock比synchronized性能更高些,但是JDK1.6相差不大
学习了解了MapReduce,Google File System和Hadoop等
后语
最后,说说我今年最大的体会--计算机技术在于知,更在于行。与诸君共勉!