项目开发工作方法(需求调研角度)

本文描述项目开发的工作方法,侧重于如何在项目各个阶段,正确获取需求,保证需求不失控。

项目可按照如下阶段进行。

项目立项

前景分析、商务分析、需求概况获取、初步沟通等

  • 确认项目意向
  • 确认项目范围

调研

调研可分为两个阶段:

  • 业务调研:了解用户自身的情况,想解决的问题
  • 需求调研:了解项目的需求,确认我们的解决方案

两个阶段的目标可能互相有重叠,时间上也可能重复,不是先做一个阶段再做另一个阶段。只是侧重点不同,所以做了区分。

调研的主要形式是访谈、分析、记录。

业务调研

侧重了解用户的工作,想解决的目标。

目标:了解业务直到我们能承担项目范围内任何一个岗位的职责

对用户工作的了解,没有固定模板,需要具体项目具体分析。可重点根据以下几项内容进行调研:

  • 组织结构
  • 工作流程
  • 考核报表
  • 岗位职责

(参考文档《走出软件作坊》“文档知多少——设计文档编写方法”章节)

需要交付以下内容:

  • 访谈记录

时间、地点、人员、主题、结论

  • 用户一手资料

保留搜集到的,对项目有帮助的资料,要保持原样。

需要记录来源、名称、搜集时间、用途等内容。

以上内容,根据访谈会议、主题进行分组保存。一次会议应当解决一个或一组相关主题的内容。

需求调研

主要形式为:方案讲解、原型沟通

初期可能会有高端视角的方案讲解,后期大部分的时间都应该是做原型沟通。

原则:

  • 必须接触一手用户
  • 必须让一手用户获得实际的用户体验感觉

原型构建时技术选型的原则:要让用户有真实使用系统的感觉。所以:

  • 逐页翻ppt的方式不合适,因为用户感受不到页面跳转。

交付物:

  • 以会议或者主题为单位的方案、讨论结果、原型的迭代记录

需求分析

将调研阶段的成果系统化。

交付物:需求文档

需求文档的内容:

  • 项目背景
  • 需求概述(范围、功能分析、用户分析等)
  • 项目建模(这个名字有点故弄玄虚,我理解就是提供详略得当的抽象角度,让人几分钟就能大致了解项目要干什么)(核心流程图、核心用例、实体设计等)
  • 功能性需求(功能点拆分、各功能点描述、跨功能点流程描述)
  • 非功能性需求(质量要求、项目约束等)

关于上一章节调研阶段的方法是否掺杂了过多设计元素(比如原型图)的疑问:

那些只是与用户沟通的手段,目的是获取用户的全部想法。掺杂了设计元素带来的不利因素,可在需求分析阶段予以去除。

例如:

没有高保真原型的时候,用户会说,太难看了我不跟你们聊天,所以必须提供一个美观的样式,但是实际项目开发中,采用什么UI方案一定不会在这个阶段就确定下来。

在需求调研阶段,可以先“迎合”用户的想法,提供高保真原型,在需求分析阶段,根据获得的全部信息(用户提供的需求+用户对这个高保真原型UI的感觉+我们自身的技术评估),重新确认技术方案。

需求评估

每个功能点,除了要做什么内容的描述外,还应对其它因素做评估。现在想到的如下:

  • 可信度:某项目有些需求是完全由我们内部人员发挥出来的,标注一下可信度更有利于后续的工作。其余项目视情况决定是否需要
  • 优先级:紧急、一般、可选等。优先级会决定:项目历次迭代先做哪个需求、出现变动或者时间不够时会放弃哪个需求
  • 事务数:估算开发工作量,一个简单Action视作一个事务。或者采用其它基准评估也可以。不必要特别准确,不必要定义严格规则,在一个项目需求内标准统一即可。比如事务数为2的,不代表工作2人天,只是代表工作量大致上是事务数为1的功能点的2倍。

可参考之前的文章( http://nonesuccess.me/?p=379

技术评估

调研阶段、需求分析阶段,都或多或少的需要项目架构师参与。最晚到需求分析阶段结束时,需要得出明确的结论,当前的需求方案是在技术上是可实现的。

架构设计

由项目架构师负责。

需要总结项目所有的技术要求,技术方案。

可参考公司项目架构模板。

开发、测试、发布、维护

按照正常流程工作即可。

不再明确区分设计、开发两个流程,项目管理的最小个体是独立开发人员,此人员应该具备拿到需求后,直到上线的所有环节的工作技能。

需求、设计阶段需要确认的各项内容,如果因为各种原因,不能提供,则至晚到功能交付时,提供以下内容:

  • 核心用例
  • 功能点
  • 实体模型设计
  • 流程图
  • 实体状态转化图

在此过程中:

敏捷开发

能确定敏捷开发一定是正确的方法论,但是1、细节我还没想太清楚 2、必须是传统开发流程训练得十分流畅的工作人员才能更好的接受敏捷,直接采用敏捷方法一般不会顺利完成工作。

所以只列举几个我能想到的要点:

  • 不必等上一个流程完全完成,就可以把已经成熟的部分进入下一个流程。比如某一组模块进行了需求分析,比较完善之后,就可以进入开发阶段
  • 尽一切可能,让实际用户早日使用系统,每天检讨:今天的成果让用户体验了吗
  • “用户而不是客户”:找使用系统的人,而不是付款的人
  • 欢迎需求变化
  • 验收测试驱动:做事之前先想好怎么验收,以验收标准驱动工作。比如做功能之前,先想验收过程是,古林街孟姐用系统成功发证,那么任意一次迭代中都要评估,我就是孟姐,我发证试试,成功了吗,有助于发现很多问题

需求变动

项目开发过程中,会因为我们想法变化、客户情况变化,发生需求变动。

变动时需要交付:

  • 新一版的需求文档(用各种形式标注或者备注发生了什么变动)
  • 需求变动文档:记录本次变动的内容,以及变动原因等其它需要说明的事

交付后,本次需求变动的内容可进入开发流程。

《项目经理应该知道的97件事》笔记(3)

11. 你们的问题,我不买单

在甲乙双方的合作中,想清楚不应该为甲方的问题买单不是个容易的事。但想清楚之后,怎样不落入另一个极端其实也不是个容易的事。

说了甲方的问题我不买单之后呢,把一切问题都推给甲方吗?那只好等着项目崩盘了。

谁的问题谁买单,但“明确到底是谁的问题”,应该明确这是乙方的责任。实现明确了,双方认可了,真正出现时才是甲方的责任;除此之外的一切情况,都应由乙方承担。

12. 如何发现优秀的IT开发人员

招聘是玄学,也是科学。

掌握正确的理论知识、熟悉业务领域、能应用、有沟通和社交能力,这些都是老生常谈。最打动我的一条是关于正确工作态度的理解:

  • 既有创造高端产品的热情,又接收项目的限制条件

成熟的必要条件总是少不了中庸二字。

13. 优秀与普通的天壤之别

用五倍的工资招一个人,让他干十个人的活,成本降下来,这是其一。

如无必要勿增实体,如有必要努力减少实体,少一个错的人,就少一个错的人给你挖坑,这是其二。

有没有魄力去分析一下到底谁优秀谁普通,万一你的项目就是个体力活,五倍的工资也只能出一倍的效率呢?这是其三。

其实说到底还是个问题域分解的问题,只有把问题域等价的拆分下来,才能知道什么是你需要的技能,谁是你需要的优秀人才。

14. 规模决定一切

一切的一切都源自于人类太笨,如果脑容量大到你能掌握每一行代码细节,什么问题都没了。

也不好说,毕竟还有机会成本在,还要在脑容量无限大上面加一条效率无穷高。

既然做不到,那就拆分吧,分而治之的核心在于,把项目拆分成规模足够小以至于能完全理解的模块,并且,这些模块怎样组合成整体也是个规模足够小的问题。

石猴是怎么当的美猴王?前面是水帘洞,你要“钻进去”、“寻个源头”、“出来”、“不伤身体”。

基本功还是在抽象能力的基础上能做等价的问题域拆分与合并吧,越来越发现,一支笔等于笔杆+笔芯+笔帽这件事,不是谁都能理解。

15. 记录工作流程,然后严格执行

有多少项目,连记录工作流程都做不到?

哪怕有份工作日志呢?

16. 剔除多余的工作流程

用添加检查流程的方式保证正确性,那谁去保证检查流程的正确性?

你以为你以为的就一定是你以为的吗?

你以为他以为的就一定是他以为的吗?

你以为他以为的就一定是你以为他以为的吗?

软件团队仍应该是核心+n个助理的模式。只对极为简单的、极为少量的信息共享并苛责每个人的理解是否到位。不想让其他人知道的信息,一定要保证其他人完全不知道。

 

 

java web开发框架功能点整理

完成一个crud类java项目的框架最小功能集

后端部分

MVC

基于Web的项目,MVC应该是其核心功能了。有以下问题需要解决:

  • 路由:
    解决什么样的请求交给哪个后端处理单元处理的问题。
  • data binding:
    解决把前端传来的数据(url path、字符串形式的键值对、Header中的信息、cookie中的信息等,必然是字符串)包装为Java可以使用的对象的问题。要实现的效果是,所有需求对于后端业务代码来讲都要是透明的,不要再有手动的转换过程。
    一般的MVC框架都有比较清晰完善的解决方案,但有些边角的需求,需要注意怎样实现更为简便。例如如想传入的信息是三个student,每个student都有name、id两个属相,那怎样才能在后端业务代码中直接得到一个List<Student>?
  • 模板引擎:
    解决怎样把后端的处理结果转换为html页面显示给前端的问题。
    首先解决转发给哪个模板,例如使用jsp作为模板引擎,后端处理单元就要做到可以控制跳转到哪个jsp文件。
    其次是数据显示,后端处理单元处理所得到的数据要转化为字符串然后放到html中的相应位置上。需要注意的事如何能透明的对相应数据做格式化显示,如所有日期类信息都以yyyy-MM-dd的格式显示,不需要在任何逻辑控制单元中做手动转换
  • Ajax/Json:
    越来越多的请求将以ajax的形式返回给前端。简单来说,需要解决的就是怎样把后端处理的结果透明的转换为Json数据的问题。MVC框架一般都有相应的解决方案,通过简单的声明就可以控制信息以Json形式返回。需要注意的是,Model如果不是纯粹的贫血模型,怎样控制每个字段(或get开头的函数)是否要转化为json发给前端。

 

DB

数据源管理

通过统一配置,方便的在程序的任何位置获取到数据源信息,以便于进行数据库操作。

事务管理

通过约定(每次http请求作为一次事务)或者声明式的方式进行事务管理,对逻辑代码透明。

ORM

Java Web世界中大部分的数据库操作代码都是针对某个Java模型的Crud,需要提供相应的方案进行操作。至少包括:

  • 主键查询
  • 条件查询(分页)
  • 插入
  • 通过主键更新
  • 通过主键删除

必要情况下,应支持对逻辑代码透明的插入、更新、删除时间记录,以及假删除操作。

batch

某段特定sql的执行,如初始化数据等。需要提供相应的工具类。

list

一般的项目都有无穷多的显示数据列表的功能,如果针对每个列表再去开发,工作量较大。最好用配置的方式统一支持。

框架级别功能

权限管理

对逻辑功能透明、操作级。

提供登录用户管理、操作鉴权等基本机制。

提供功能模块管理、用户管理、角色管理、角色权限管理等基本功能。

杂项工具

log

提供逻辑与物理相分离的日志记录工具。

DataUtils/StringUtils/……

项目中的各种Utils,一般找合适的开源库都能解决,没有必要重新发明一遍轮子。

前端部分

UI

基本框架

统一风格、字体字号、主页面结构(项目标题、logo)等。

页面载入中效果

UI部件

  • alert、confirm、prompt……、
  • 模态窗口(显示少量信息和显示完整页面
  • form控件:下拉列表、日期控件等……
  • 消息显示(浮动出现自动消失、固定可手动关闭、固定不可手动关闭等)
  • ……

登录页

  • 用户名密码输入
  • 子系统选择
  • 登录成功后跳转
  • 登录失败后的提示、重新输入

通用功能

  • 个人profile
  • 系统设置
  • 皮肤更换
  • ……

列表页

  • 列表显示数据
  • 查询
  • ……

表单页

  • 简单表单布局
  • 复杂表单布局
  • 各种表单控件在各种布局下的展示

信息展示页

文字与图片混合排版等

统计图表页

各类统计图表的展现与交互

 

 

 

 

oracle无法连接:shared memory realm does not exist

oracle各服务运行正常。

各服务重启后,情况不变。

重启服务器再重启oracle服务后,情况不变。

查资料,此错误可能是oracle异常关闭引起的。该服务器近期曾经异常关机过。

查看服务器情况,c盘空间已满,怀疑可能也是原因之一。清理c盘后情况不变。

运行:

sqlplus /nolog
connect / as sysdba
startup

报错

ORA-00119: invalid specification for system parameter LOCAL_LISTENER
ORA-00132: syntax error or unresolved network name ‘LISTENER_ORCL’

按照第二行的错误查询资料,查得:http://blog.csdn.net/lpftobetheone/article/details/11099785

按照此文章的过程解决。

用sqlplus /nolog登录sqlplus,再执行connect  / as sysdba,连接到空闲进程。

在以下路径找到spfileorcl.ora(与文章中不同):

…\product\11.2.0\dbhome_1\database

执行

create pfile from spfile=’…\product\11.2.0\dbhome_1\database\spfileorcl.ora’;

在同样路径下生成了initorcl.ora。用文本编辑器打开,修改*.local_listener=一行。

按照文章中的说明进行修改,不清楚hostname是什么,在tnsname.ora中查找。经过文件搜索,该文件的路径为:

…\product\11.2.0\dbhome_1\NETWORK\ADMIN

找到:

ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = Dev)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)

将initorcl.ora中的内容修改为:

*.local_listener='(ADDRESS_LIST=(Address= (Protocol=tcp) (Host = DEV )(Port=1521)))’

保存退出,用这个pfile创建spfile:

SQL> create spfile from pfile=”…\product\11.2.0\dbhome_1\database\initorcl.ora’;

执行startup,启动成功。

至此,问题解决。

tomcat配置https记录

执行java bin目录下的keytool程序,生成证书

 

keytool -genkey -alias tomcat -keyalg RSA

 

输入信息后生成成功,会保存在User/niyuzhe/目录下。也可以使用参数指定生成目录。

 

在tomcat中配置https:

 

<Connector port=”8443″ protocol=”org.apache.coyote.http11.Http11NioProtocol”

maxThreads=”150″ SSLEnabled=”true” scheme=”https” secure=”true”

clientAuth=”false” sslProtocol=”TLS” keystoreFile=”C:\Users\niyuzhe\.keystore” keystorePass=”changeit”/>

 

其中keystorePass一项要与上一步输入的密码内容一致

 

重启tomcat后,就可以使用https访问网站了

 

在应用的web.xml中配置:

 

<security-constraint>

<web-resource-collection>

<web-resource-name>securedapp</web-resource-name>

<url-pattern>/*</url-pattern>

</web-resource-collection>

<user-data-constraint>

<transport-guarantee>CONFIDENTIAL</transport-guarantee>

</user-data-constraint>

</security-constraint>

 

则该应用下所有访问都会自动跳转到8443端口,使用https访问。

 

如果需要在eclipse中运行,可以在eclipse的servers中修改settings.xml

 

logback db

用slf4j+logback记录日志,之前是打到日志文件中。日志多了之后,又开始用logack的不同appender区分日志文件。最初的时候还比较实用,查阅日志很方便。但随每个开发者都随手新建一个自己的日志文件以便于自己查询方便,每次项目启动之后都会新建数十个文件,运行一周后,日志文件夹就会出现上千个文件。在缺乏必要的维护机制时,日志膨胀已经让阅读日志成为了一件很困难的事。

如果用logback的db appender,把日志进行结构化,也许会缓解这个问题。

在logback的配置文件中,创建以下appender:

<appender name=”DB” class=”ch.qos.logback.classic.db.DBAppender”>
<connectionSource
class=”ch.qos.logback.core.db.DriverManagerConnectionSource”>
<driverClass>com.mysql.jdbc.Driver</driverClass>
<url>jdbc:mysql://localhost:3306/logback_demo</url>
<user>root</user>
<password>admin</password>
</connectionSource>
</appender>

相应的配置都很好懂,按照需求进行配置进可以了。

logback不会自动建表,需要根据要求手工建立。建表语句在logback-classic.jar\\ch\qos\logback\classic\db\script下,提供了主要数据库各个版本的create sql。

主要的日志信息保存在logging_event表中,有名为arg 1、2、3的三个字段,对应输出log时替换log字符串中{}的参数。这几个字段会对日志的灵活格式化很有作用。只有三个,预计极端情况下会不够用,特别是写输出日志的代码时,没有考虑到参数组织的情况下。

有时间戳和event_id字段,可以保证日志的输出顺序是可查的。

 

有几个未解决的问题:

  • 还没有找到打印多层调用堆栈的方法。
  • 有些日志在控制台能输出,但到了数据库中就莫名其妙的没有了。
  • 没有找到能做ticket id的字段,因此无法对日志有效分类。比如设计日志时会用到这种策略,关于某个实体的每条处理过程,都必定在日志中包含“[moduleid=xxxx]”这样的字样。在发生错误时,根据出错的实体id,就可以找到这条实体操作的所有过程。但按照logback db的方案,除了全文检索外,没有找到有效的方法。
  • 没有看到自动分表的机制,日志的膨胀的问题不知如何处理,因此也不知道运行起来效率如何。

maven webjar构建方法

用maven管理项目构建过程后,java部分已经有了很好的工程实践。但web静态资源仍处于复制粘贴的阶段,比较混乱。

看了一些前端工程化工具,比如webpack。但毕竟不是专职做前端的人员,感觉上手还不是那么容易。后来就找到了maven webjar这个方案。

maven webjar的大致历史貌似是,servlet 3.0规定jar包中META-INF/resources文件夹下的文件,可以作为静态资源被引用。所以就有人把常见的web库用这种方式搞成了jar包,这样的话,web静态资源也能像Java库一样被直接引用了。这位大神的官网地址在:

http://www.webjars.org/

顺着这个思路,把自己项目需要用到的静态资源也打成jar包。参考了一下webjar.org上的打包方式,源文件还是放在了src/main/resources下,在pom文件中,将这个resource目录配置到META-INF文件夹下。

[xml]

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<targetPath>META-INF/resources/</targetPath>
</resource>
</resources>
</build>

[/xml]

比如我有public文件夹,下面有something.js文件。项目的结果为:

src/main/resources

-public

–something.js

打成jar包后,jar包的结果为:

some.jar

-META-INF

–resources

—public

—-something.js

依赖该jar的web项目,可以通过http://ip:port/[projectname]/public/something.js访问到这个静态文件。

 

maven & eclipse工程实践

maven & eclipse source folder

eclipse中,可以在项目所属文件夹下点击右键-》Build path-》Mark as  a source folder

标记了source folder之后,eclipse就会将这个文件夹下的代码文件视作Java文件,并且在编译、运行时,将相应的源文件添加到class path中。在使用基于eclipse机制的各项功能或插件时,会将这些文件复制到java编译结果应该放到的文件中。例如,使用eclipse的tomcat插件的run on server功能时,标记为source folder的文件夹,Java文件将会被编译为class文件并拷贝到对应运行时web工程的WEB-INF/classes下,其余文件也会被原样复制到这个文件夹下。

一般的Dynaminc Web Project,eclipse会自动的将src目录设置为source folder。使用eclipse maven插件创建的maven webapp项目,会将main和test下的java和resource目录设置为source folder。

eclipse的maven插件会偶尔出现问题,设置不正确,可以手动调整。在实际需要中,如果有更灵活的需求,也可以手工调整。

maven&eclipse webapp

在eclipse下的web项目,使用tomcat插件运行时,会根据一定的规则,将项目的各个文件部署成为一个java web标准格式的包,由tomcat运行。

可以在项目属性的Deployment Assemble中,设置部署规则。/代表部署后的项目根目录,WEB-INF/classes代表项目部署后的Java及资源文件所在目录,一般设置这两个目录的需求比较多。

如果项目运行时出现一些诡异的问题,例如找不到某个类,或者某个配置文件读取错误,可以在此处查看,是否没有设置正确部署逻辑。

maven聚合项目 & eclipse

在eclipse中,创建maven project,勾选create a simple project,packagint选择pom,就可以创建一个聚合项目。

创建子项目时,可以选择maven module,父项目选择刚才建好的父项目,就可以将此项目设置为刚才项目的子项目。两个项目的pom文件,eclipse都会自动处理。用这种方式创建的子项目,文件位置会默认放到父项目文件夹下。

这样创建之后,父项目的文件夹中实际上也包含了子项目的文件,那么在eclipse的workspace中,实际上在父子两个项目中都存在同样的文件。如果需要将这个项目提交到svn,那么只能在父项目上做操作。

如果是一个已经创建好并上传至svn的maven聚合项目,签出父项目的同时也会将属于父项目文件夹中的子项目签出来。此时,就不能再手动签出子项目了,而是应该通过import-》existing project into workspace的方式,选择父项目路径下的子项目文件夹,逐个将子项目import进来,这样就可以正常进行开发。

做svn操作的时候,两个项目也会存在一定的冲突,最好统一在父项目上做操作。

maven profile

项目的不同发布方式,可能会使用不同的配置项目或者打包方式。

如果配置文件的大部分相同,只有少量配置不同,可以使用filter功能替换。

如果配置文件的整体都不相同,就可以在不同的profile中配置不同的resource目录。网上的资料大多是在src/main/resources下建立文件夹,在通用的build配置中exlude出去,再在各个profile中重新定义。我一般用重新定义与resources同级目录的方式。

maven profile & eclipse

一般会有一个用于开发的profile,常用的名称是dev或者development。此profile对应的resources目录,需要在eclipse中设置为source folder,才能够在run on server时正常部署。

如果使用了filter功能,那么配置文件的内容会变成${xxx},在eclipse中直接运行就会出错。此时,需要在项目属性的Maven设置中,添加需要的Active Maven profiles。添加之后,eclipse就会在运行的时候使用这个profile,正确的替换变量。

 

 

 

 

eclipse按下ctrl假死情况的解决

在复制粘贴剪切保存的时候各种卡。网上查了一圈,发现是因为eclipse的代码跳转快捷键是ctrl+鼠标左键,在jsp编辑器中不知抽什么风,按下ctrl时候会做代码分析一类的事情导致编辑器直接卡住。

反正jsp中这个功能也用处不大,干脆关了。Window-》Perefrence-》General-》Editors-》Text Tditors-》Hyperlinking,把Jsp Editors中的内容全部去掉,问题解决。

贫血模式下有限富血的所谓proxy模式

为了代码简单,领域模型使用了纯粹的贫血模型,即只包括field定义和对应的get、set方法。(主要原因是当初是先定义数据库表,再用MybatisGenerator生成Java类,因此自己做修改很麻烦)

但是某些与领域模型密切相关操作,又比较适合以类似于富血模式的方式与领域模型绑定到一起。实现某种形式的绑定后,就天然了拥有了领域模型实例本身这个参数,会减少很多代码的复杂度。

最初的动机是:领域模型之间存在依赖关系,例如学生信息中可能存在班级信息的外键,而与之相关的几乎每个交互功能中都存在类似于“学生姓名和所属班级名称”这样的需求。在每个Controller中都写上一个查询方法,非常繁琐,即便是封装了service类,也至少需要在Controller中以某种形式定义一个承载的变量。而我们需要的仅仅是显示而已。

因此,就为这个领域模型配备了一个类,感觉上职责类似于代替这个类做一些事情,因此起名叫proxy。proxy实例要保存一个领域模型的实例,实现绑定。绑定后,就可以在proxy中直接使用,不需要再显式传递。

基类定义:

public ModelProxy(T model)
{
this.model = model;
}

与某Domain类相关联的proxy子类定义:

public DomainProxy(Domain domainInstance)
{
super(domainInstance);
}

领域模型中定义一个getProxy函数,返回与这个模型绑定的proxy类。

private transient DomainProxy proxy = new DomainProxy (this);

public DomainProxy getProxy()
{
return proxy;
}

而proxy类中的方法,命名模仿Java Bean模式:

/**
* 返回学生所有相关班级记录
*
* @return
*/
public List<Classes> getClasses()
{
。。。

}

这样,就可以实现在jsp中直接使用链式el表达式,或者这些信息。

${domain.proxy.classes[0].name}

${domain.proxy.classes[0].proxy.teacher.name}

……

随着开发进行,proxy的内容不仅仅局限于辅助jsp显示。为了防止代码膨胀中造成的混乱,在实践中又总结出了以下一些经验:

Proxy层主要职责:

  • 封装算法:根据Model类一个或几个字段计算结果或判断真假,如根据生日返回育龄妇女年龄,根据生日判断育龄妇女是否符合退出育龄期的条件等。
  • 1-1或n-1的外键关系,即本Model类中有xxId是指向xx表的,则proxy中应有函数通过外键获取实例,返回值应该只有一个实例。
  • 1-n或n-n的外键关系,即某个类有modelId是指向本Model的,或者通过关联表存在多对多的关联关系,此时Proxy应有函数返回另外一个类的List

注:上述两个外键关系,不一定显式的在数据库中存在。也许表结构中没有直接的id存在的,但是按照业务逻辑,会有关联关系

proxy的设计原则:

  • Proxy负责以上各种函数结果的提供,在必要的时候提供对调用者透明的缓存机制
  • 但proxy不作用于model,不改变model的值,在数据库层有变动,model失效的情况下不负责对model的刷新。
  • Proxy层不提供任何直接或间接对数据有操作的方法。
  • 调用proxy的对象必须是从持久层select出来的有id的对象,手动new的对象不经过insert,不能getProxy。