String[][] projects = new String[10][3]; 这是个二维数组的声明。遍历的时候遍历前面那一维。 Project[] projects = new Project[10]; 这是个对象的数组。遍历的时候就是按照一般一维数组的方法来遍历。 List projects = new List(); 这是个类似于容器的东西了。遍历的时候,可以使用Iterate遍历器来遍历,也可以按照数组的方法来用FOR循环遍历。但跟前两个不同的是,这个中间不存在NULL,也就是是连续的,直到最后一个才出现NULL。因为这个特性,可以实现删除操作。
TABLE之中,tr是纵着排列,td是横着排列,掌握了这个就可以很快的写好HTML页面的风格。
在CSS里面,几种大的标签。 前面没有符号的那是默认的,也就是页面中不需要声明便对应使用的。前面加#号的,在DIV后面需要加id=“”来调用。一般是用来控制格式什么的。 前面加.(点)的,在页面里的DIV后面需要用class调用。这个可以控制页面中DIV的位置排版什么的。感觉上跟#的没什么区别。
连接数据库的方法便是调用很简单的语句。几乎是套路。 Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/elearning?useUnicode=true&characterEncoding=GB2312"; //这是地址,elearning是数据库名。之后用?连接user这个表单(TABLE)名。后面的部分就是设置编码格式了。 String username = "root"; String password = "123456"; //上面的是数据库的用户名和密码。 conn = DriverManager.getConnection(url, username, password); 这条语句将数据库连接上了。 之后写UserDAO。向数据库之中写入数据,也就是调用数据库的SQL语句。用特定的方法就可以完成。
session和request就是设置了一个共享区,将数据放进这里来进行传递
使用session和request传递和获取数据的时候遇到了问题。 首先就是,根据获取的数据来判断是否登录的时候,如果前面页面没有设置session,那么便会出错。 然后,如果获取到的信息是空,那么就应该用if-else来控制语句的执行,否则会出错。 再然后,考虑了一下用户名是否重复的问题,发现需要将数据库设置成姓名唯一才行。当然,需要在UserDAO中加入一些语句来判断SQL语句执行的结果,来给用户返回正确的信息。
配置struts2环境。需要的5个JAR包: commons-logging-1.0.4.jar freemarker-2.3.8.jar ognl-2.6.11.jar struts2-core-2.0.11.jar xwork-2.0.4.jar web.xml里面过滤器的配置: struts2 org.apache.struts2.dispatcher.FilterDispatcher struts2 /* struts.xml: /test/t1.jsp /test/t2.jsp 页面action响应以及相应的跳转。,遇见这种,配置文件什么的都很多的情况下,应该仔细仔细再仔细。一个小小的符号可能都将导致程序运行异常。而且,对于每一个文件的修改和编辑的顺序十分重要。应该循序渐进才行。 文件名一定要很正确。这个很关键。很多同学因为一点点小小的失误而导致浪费了大量的时间来排错。 页面跳转的时候,一定要注意文件的路径,相对路径和绝对路径。一定要区分好并且写对。
实现Action接口可以帮助开发者更好地实现Action类。Action接口的定义: public interface Action { //下面定义了5个字符串常量 public static final String SUCCESS = "success"; public static final String NONE = "none"; public static final String ERROR = "error"; public static final String INPUT = "input"; public static final String LOGIN = "login"; //定义处理用户请求的execute抽象方法 public String execute() throws Exception; } 如此,当需要定义Action类时,只需implements Action,并实现抽象方法,返回的时候可以直接调用常量。 导入Struts 2的标签库,可以避免使用JAVA代码来切换,同时可以使用丰富的UI元素。 使用是只用s后面加很多属性,就可以丰富页面,使代码简洁。 extends ActionSupport 可以处理封装的对象。 用来封装表单。其中,如果将username和password封装在一个User类中的话,就要以这种形式调用。
如果想将struts.xml模块化,可以使用include语句来包含其他文件。 校验方法可以使用 @Override public void validate() { if(null == this.username||"".equals(this.username)){ this.addFieldError("username", "please input name"); } if(null ==this.password||"".equals(this.password)){ this.addFieldError("password", "input pass"); } } 其中,以下的返回。 this.addFieldError("msg.hello", "名子不对");//前面引号是用来指定在哪个标签出现这种提示 this.addActionError("处理动作失败!"); this.addActionMessage("提交成功"); 同时,在execute()中返回的应该是“input”,这样会返回到页面的对应标签处。 应该注意的是,如果是出execute之外的方法,应该使用validateShow()等 validateXxx()来命名。同时在struts.xml对应的class后面要添加method=“”来调用自定义的方法。
当在include中调用其他的struts.xml模块的时候,为了防止action的名字冲突,可以使用namespace,定义在package中,同时在JSP中调用action的时候,在前面加上a1/login.action,要加上“namespace/” 当在Action中使用不同的方法时,要在struts中的action中添加method=""来定义。而对于相对繁琐的时候,可以使用通配符*来完成。 通配符*的用法: 在struts中 /{1}UserSc.jsp> >//其中1代表第一个通配符 在JSP中 <> <> <> 文件目录有 addUserSc.jsp delUserSc.jsp queryUserSc.jsp *的作用显而易见。而后面的{1}则表示的是第1个*的内容。 result中不光可以跳转到页面,可以定义type使其直接调用action方法。用chain跳转时,是要用 >来定义跳转的action,支持值传递。而如果是使用redirectAction的时候,就成客户端跳转,没有值传递了。 在Action中设置session等的方法: ActionContext context; Map session; context = ActionContext.getContext(); session = context.getSession(); session.put("user", u);
使用implements ModelDriven的时候,可以不用填写SET GET方法。例如,implements ModelDriven 在其中定义Users u; 不用写这个u的SET 和GET方法。 可以使用注解result的方法。在方法名上面。 @Result(name="success",value="/userSuc.jsp") //单个 @Results({@Result(name="success",value="/userSuc.jsp"), @Result(name="error",value="/userSuc.jsp") }) 要在web.xml中填入 actionPackages com.action//com.action是action类所在的包名 使用注解技术可以脱离struts.xml,还可以如此定义名字空间,在类的上面@Namespace(value="/test") 设置session的详细方法。 Map request;//一次请求有效 Map session;//页面都有效,只要浏览器不关 Map application;//关了也有效 ActionContext context; context= ActionContext.getContext(); request=(Map)context.get("request"); session=context.getSession(); application=context.getApplication(); request.put("req","123"); session.put("ses","123"); application.put("app","123"); 要编写注销的时候,可以使用session.clear()方法清空session
CMM 只是标准,不是具体的软件开发过程。SEI 为了与 CMM 配套设计有 PSP(Personal Software Process):个体软件开发过程 和 TSP(Team Software Process):小组软件开发过程 发明 UML 的 3 位软件科学家设计了 RUP(Rational Unified Process ):Rational 统一软件开发过程 在我看来 PSP/TSP 和 RUP 都属于重量级的软件开发过程。 那么哪些开发过程属于轻量级的(敏捷)软件开发过程呢?有以下这些: XP(Extreme Programming):极限编程 Scrum: Crystal Methodologies:水晶方法 FDD(Feature-Driven Development):特征驱动开发 AM(Agile Modeling):敏捷建模 ASD(Adaptive Software Development):自适应软件开发 DSDM(Dynamic System Development Model ):动态系统开发模型 特点有: 1.小版本发布。 在敏捷开发中,不会出现这种情况,拿到需求以后就闭门造车,直到最后才将产品交付给客户,而是尽量多的产品发布,一般以周、月为单位。 这样,客户每隔一段时间就会拿到发布的产品进行试用,而我们可以从客户那得到更多的反馈来改进产品。正因为发布频繁,每一个版本新增的功能简单,不需要复杂的设计,这样文档和设计就在很大程度上简化了。 又因为简单设计,没有复杂的架构,所以客户有新的需求或者需求进行变动,也能很快的适应 2.Test-Driven Development,测试驱动开发,它是敏捷开发的最重要的部分。实现任何一个功能都是从测试开始,首先对业务需求进行分析,分解为一个一个的Story,记录在Story Card上。 然后两个人同时坐在电脑前面,一个人依照Story,从业务需求的角度来编写测试代码,另一个人看着他并且进行思考,如果有不同的意见就会提出来进行讨论,直到达成共识,这样写出来的测试代码就真实反映了业务功能需求。接着由另一个人控制键盘,编写该测试代码的实现。如果没有测试代码,就不能编写功能的实现代码。先写测试代码,能够让开发人员明确目标,就是让测试通过。 3.Continuous Integration,持续集成。在以往的软件开发过程中,集成是一件很痛苦的事情,通常很长时间才会做一次集成,这样的话,会引发很多问题,比如build未通过或者单元测试失败。敏捷开发中提倡持续集成,一天之内集成十几次甚至几十次,如此频繁的集成能尽量减少冲突,由于集成很频繁,每一次集成的改变也很少,即使集成失败也容易定位错误。一次集成要做哪些事情呢? 它至少包括:获得所有源代码;编译源代码;运行所有测试,包括单元测试、功能测试等;确认编译和测试是否通过,最后发送报告。 当然也会做一些其它的任务,比如说代码分析、测试覆盖率分析等等。 开发人员的桌上有一个火山灯用来标志集成的状态,如果是黄灯,表示正在集成;如果是绿灯,表示上一次集成通过,开发人员在这时候获得的代码是可用而可靠的;如果显示为红灯,就要小心了,上一次集成未通过,需要尽快定位失败原因从而让灯变绿。在持续集成上,使用的产品CruiseControl 4.Refactoring,重构。相信大家对它都很熟悉了,有很多很多的书用来介绍重构,最著名的是Martin的《重构》,Joshua的《从重构到模式》等。 重构是在不改变系统外部行为下,对内部结构进行整理优化,使得代码尽量简单、优美、可扩展。 在以往开发中,通常是在有需求过来,现在的系统架构不容易实现,从而对原有系统进行重构;或者在开发过程中有剩余时间了,对现在代码进行重构整理。但是在敏捷开发中,重构贯穿于整个开发流程,每一次开发者check in代码之前,都要对所写代码进行重构,让代码达到clean code that works。值得注意的是,在重构时,每一次改变要尽可能小,用单元测试来保证重构是否引起冲突,并且不只是对实现代码进行重构,如果测试代码中有重复,也要对它进行重构。 5.Pair-Programming,结对编程。在敏捷开发中,做任何事情都是Pair的,包括分析、写测试、写实现代码或者重构。Pair做事有很多好处,两个人在一起探讨很容易产生思想的火花,也不容易走上偏路。还有很多事都是Pair来做,比如Pair学习,Pair翻译,Pair做PPT。 6.站立会议。每天早上,项目组的所有成员都会站立进行一次会议,由于是站立的,所以时间不会很长,一般来说是15-20分钟。会议的内容并不是需求分析、任务分配等,而是每个人都回答三个问题: 1. 你昨天做了什么? 2. 你今天要做什么? 3. 你遇到了哪些困难? 站立会议让团队进行交流,彼此相互熟悉工作内容,如果有人曾经遇到过和你类似的问题,那么在站立会议后,他就会和你进行讨论。 7.较少的文档。 其实敏捷开发中并不是没有文档,而是有大量的文档,即测试。 这些测试代码真实的反应了客户的需求以及系统API的用法,如果有新人加入团队,最快的熟悉项目的方法就是给他看测试代码,而比一边看着文档一边进行debug要高效。 如果用书面文档或者注释,某天代码变化了,需要对这些文档进行更新。一旦忘记更新文档,就会出现代码和文档不匹配的情况,这更加会让人迷惑。而在敏捷中并不会出现,因为只有测试变化了,代码才会变化,测试是真实反应代码的。 这时有人会问:代码不写注释行吗?一般来说好的代码不是需要大量的注释吗?其实简单可读的代码才是好的代码,既然简单可读了,别人一看就能够看懂,这时候根本不需要对代码进行任何注释。 若你觉得这段代码不加注释的话别人可能看不懂,就表示设计还不够简单,需要对它进行重构。 8.以合作为中心,表现为代码共享。 在敏捷开发中,代码是归团队所有而不是哪些模块的代码属于哪些人,每个人都有权利获得系统任何一部分的代码然后修改它,如果有人看到某些代码不爽的话,那他能够对这部分代码重构而不需要征求代码作者的同意,很可能也不知道是谁写的这部分代码。这样每个人都能熟悉系统的代码,即使团队的人员变动,也没有风险。 9.现场客户。 敏捷开发中,客户是与开发团队一起工作的,团队到客户现场进行开发或者邀请客户到团队公司里来开发。如果开发过程中有什么问题或者产品经过一个迭代后,能够以最快速度得到客户的反馈。 10.Automated Testing ,自动化测试。 为了减小人力或者重复劳动,所有的测试包括单元测试、功能测试或集成测试等都是自动化的,这对QA人员提出了更高的要求。他们要熟悉开发语言、自动化测试工具,能够编写自动化测试脚本或者用工具录制。自动化测试包括Selenium开源项目。 11.Adaptive Planning,可调整计划。 敏捷开发中计划是可调整的,并不是像以往的开发过程中,需求分析->概要设计->详细设计->开发->测试->交付,每一个阶段都是有计划的进行,一个阶段结束便开始下一个阶段。 而敏捷开发中只有一次一次的迭代,小版本的发布,根据客户反馈随时作出相应的调整和变化。 敏捷方法 我们常常看到书中讲,程序员拿到一个用户故事后,怎么计划,怎么分解,怎么写单元测试,怎么小步前进,怎么持续集成。这是典型的程序员视角。 事实上,敏捷方法分为三部分,敏捷项目管理,敏捷需求分析,敏捷软件开发。上述提到的完全是敏捷开发中的实践,很多人了解到的敏捷,只是敏捷的三分之一。 (1)敏捷需求分析 在敏捷的团队中,作一个敏捷程序员确实是非常舒服的事情。从程序员的角度来看,只需要选择一张他感兴趣的故事卡片,了解清楚该卡片的需求,开始从功能测试写代码,等通过了所有测试就完工。基本上不需要考虑太多的事情,非常轻松愉快。但程序员向谁去问清楚需求?故事卡片是怎样写出来的呢?让我们来关注开发前发生的事情。 实践充分表明,敏捷过程并不是没有需求分析,而是把需求分析过程分散到整个开发的过程中,让开发和需求分析并行进行。这就是敏捷方法实施成功的秘诀之一。而商务分析师在这个过程中,起到了纽带和桥梁的作用,是一个团队不可缺少的角色。 商务分析师 了解敏捷过程的人都知道,Kent Beck在XP过程中提到了现场客户,如果一个敏捷团队能够有现场客户,这当然是最棒的事情。但多数情况下,客户都是很忙碌的,很难全力投入到软件开发过程中。这时候,我们就需要商务分析师这个角色,来充当客户的角色。 我在ThoughtWorks的团队中担任的就是商务分析师这个角色。商务分析师最重要的职责就是与客户交谈,了解和分析需求,将其制作成用户故事并将需求转述给程序员。同时,商务分析师也要代替客户负责功能验收测试。 商业价值是商务分析师关注的最终目标。 用户故事 用户故事的作用有两个,一个是作为进度跟踪的依据,一个是作为与人交谈的备忘录。用户故事卡片并不是很精确的需求,因此不需要把事情描述的非常清楚。将需求的详细分析推迟到实现前夕来完成,这是敏捷需求分析的精华所在。任何提前做好的东西都会导致浪费,敏捷过程提倡足够就好,避免浪费。 不少人对用户故事和用例的区别感到疑惑。用户故事的作用是备忘功能,而不是文档。而用例需要详细的描述其操作步骤,以及每个异常路径,因而起到了文档的作用。用户故事是可见的商业价值,而不是功能描述。每个用户故事的粒度和工作量都相差不多,这和用例有很大的区别。用户故事是小粒度的,可测试的,可见的,并且是有价值的。 迭代 每个迭代内分析好恰好足够下一个迭代开发的需求,就是商务分析师每个迭代的主要工作内容。商务分析师的需求分析工作在上一个迭代完成,包括需求的了解,分析,评估和排列优先级。 在每个迭代开始的时候,由商务分析师主持召开迭代计划会议,在会议上向所有的程序员解释这个迭代要完成的用户故事,然后由程序员自由提问,知道他们能够获得足够开始实现该功能的信息。 功能验收测试 在程序员完成一个用户故事后,商务分析师还要来代表客户做功能验收测试,查看是否完成了预计的功能,是否有程序员还没有想到的异常情况。如果存在问题需要退回给程序员继续完成。这在一定程度上保证了系统完成的需求不偏离客户的要求。当然,更多的测试还需要QA来完成。 (2)敏捷项目管理 项目经理 用户故事的跟踪和管理是由项目经理来进行 (3)敏捷软件开发 程序员拿到一个用户故事后,怎么计划,怎么分解,怎么写单元测试,怎么小步前进,怎么持续集成。这是典型的程序员视角。 敏捷项目启动的关键点 1) 强调客户参与与决定权,客户对启动时的Product Vision负主要责任,而不是我们项目组自己根据自己的分析或臆断来拟定一份“项目任务书”; 2) 启动时更强调项目过程中活动的计划(沟通计划,迭代计划等),而非仅强调生命周期的整体计划; 3) 强调沟通,尤其是与客户的沟通,客户与项目组共同管理整个项目过程;而非我们自己初期就确定什么时候必须开始、什么时候必须结束; 4) 启动初期的产物仅出必要的文档产物,什么有用要什么,而非传统中一个项目启动一定伴随一堆文档产物和浩荡的启动会。 敏捷建模的价值观 AM的价值观包括了XP的四个价值观:沟通、简单、反馈、勇气,此外,还扩展了第五个价值观:谦逊。 沟通. 建模不但能够促进你团队内部的开发人员之间沟通、还能够促进你的团队和你的project stakeholder之间的沟通。 简单. 画一两张图表来代替几十甚至几百行的代码,通过这种方法,建模成为简化软件和软件(开发)过程的关键。这一点对开发人员而言非常重要-它简单,容易发现出新的想法,随着你(对软件)的理解的加深,也能够很容易的改进。 反馈. Kent Beck在Extreme Programming Explained中有句话讲得非常好:“乐观是编程的职业病,反馈则是其处方。”通过图表来交流你的想法,你可以快速获得反馈,并能够按照建议行事。 勇气. 勇气非常重要,当你的决策证明是不合适的时候,你就需要做出重大的决策,放弃或重构(refactor)你的工作,修正你的方向。 谦逊. 最优秀的开发人员都拥有谦逊的美德,他们总能认识到自己并不是无所不知的。事实上,无论是开发人员还是客户,甚至所有的project stakeholder,都有他们自己的专业领域,都能够为项目做出贡献。一个有效的做法是假设参与项目的每一个人都有相同的价值,都应该被尊重。 敏捷建模的原则 敏捷建模(AM)定义了一系列的核心原则和辅助原则,它们为软件开发项目中的建模实践奠定了基石。其中一些原则是从XP中借鉴而来,在Extreme Programming Explained中有它们的详细描述。而XP中的一些原则又是源于众所周知的软件工程学。复用的思想随处可见!基本上,本文中对这些原则的阐述主要侧重于它们是如何影响着建模工作;这样,对于这些借鉴于XP的原则,我们可以从另一个角度来看待。 核心原则: 主张简单. 当从事开发工作时,你应当主张最简单的解决方案就是最好的解决方案。不要过分构建(overbuild)你的软件。用AM的说法就是,如果你现在并不需要这项额外功能,那就不要在模型中增加它。要有这样的勇气:你现在不必要对这个系统进行过分的建模(over-model),只要基于现有的需求进行建模,日后需求有变更时,再来重构这个系统。尽可能的保持模型的简单。 拥抱变化. 需求时刻在变,人们对于需求的理解也时刻在变。项目进行中,Project stakeholder可能变化,会有新人加入,也会有旧人离开。Project stakeholder的观点也可能变化,你努力的目标和成功标准也有可能发生变化。这就意味着随着项目的进行,项目环境也在不停的变化,因此你的开发方法必须要能够反映这种现实。 你的第二个目标是可持续性. 即便你的团队已经把一个能够运转的系统交付给用户,你的项目也还可能是失败的--实现Project stakeholder的需求,其中就包括你的系统应该要有足够的鲁棒性(robust ),能够适应日后的扩展。就像Alistair Cockburn常说的,当你在进行软件开发的竞赛时,你的第二个目标就是准备下一场比赛。可持续性可能指的是系统的下一个主要发布版,或是你正在构建的系统的运转和支持。要做到这一点,你不仅仅要构建高质量的软件,还要创建足够的文档和支持材料,保证下一场比赛能有效的进行。你要考虑很多的因素,包括你现有的团队是不是还能够参加下一场的比赛,下一场比赛的环境,下一场比赛对你的组织的重要程度。简单的说,你在开发的时候,你要能想象到未来。 递增的变化. 和建模相关的一个重要概念是你不用在一开始就准备好一切。实际上,你就算想这么做也不太可能。而且,你不用在模型中包容所有的细节,你只要足够的细节就够了。没有必要试图在一开始就建立一个囊括一切的模型,你只要开发一个小的模型,或是概要模型,打下一个基础,然后慢慢的改进模型,或是在不在需要的时候丢弃这个模型。这就是递增的思想。 令Stakeholder投资最大化. 你的project stakeholder为了开发出满足自己需要的软件,需要投入时间、金钱、设备等各种资源。stakeholder应该可以选取最好的方式投资,也可以要求你的团队不浪费资源。并且,他们还有最后的发言权,决定要投入多少的资源。如果是这些资源是你自己的,你希望你的资源被误用吗。 有目的的建模.对于自己的artifact,例如模型、源代码、文档,很多开发人员不是担心它们是否够详细,就是担心它们是否太过详细,或担心它们是否足够正确。你不应该毫无意义的建模,应该先问问,为什么要建立这个artifact,为谁建立它。和建模有关,也许你应该更多的了解软件的某个方面,也许为了保证项目的顺利进行,你需要和高级经理交流你的方法,也许你需要创建描述系统的文档,使其他人能够操作、维护、改进系统。如果你连为什么建模,为谁建模都不清楚,你又何必继续烦恼下去呢?首先,你要确定建模的目的以及模型的受众,在此基础上,再保证模型足够正确和足够详细。一旦一个模型实现了目标,你就可以结束目前的工作,把精力转移到其它的工作上去,例如编写代码以检验模型的运作。该项原则也可适用于改变现有模型:如果你要做一些改变,也许是一个熟知的模式,你应该有做出变化的正确理由(可能是为了支持一项新的需求,或是为了重构以保证简洁)。关于该项原则的一个重要暗示是你应该要了解你的受众,即便受众是你自己也一样。例如,如果你是为维护人员建立模型,他们到底需要些什么?是厚达500页的详细文档才够呢,还是10页的工作总览就够了?你不清楚?去和他们谈谈,找出你想要的。 多种模型.开发软件需要使用多种模型,因为每种模型只能描述软件的单个方面,“要开发现今的商业应用,我们该需要什么样的模型?”考虑到现今的软件的复杂性,你的建模工具箱应该要包容大量有用的技术(关于artifact的清单,可以参阅AM的建模artifact)。有一点很重要,你没有必要为一个系统开发所有的模型,而应该针对系统的具体情况,挑选一部分的模型。不同的系统使用不同部分的模型。比如,和家里的修理工作一样,每种工作不是要求你用遍工具箱里的每一个工具,而是一次使用某一件工具。又比如,你可能会比较喜欢某些工具,同样,你可会偏爱某一种模型。有多少的建模artifact可供使用呢,如果你想要了解这方面的更多细节,我在Be Realistic About the UML中列出了UML的相关部分,如果你希望做进一步的了解,可以参阅白皮书The Object Primer -- An Introduction to Techniques for Agile Modeling。 高质量的工作.没有人喜欢烂糟糟的工作。做这项工作的人不喜欢,是因为没有成就感;日后负责重构这项工作(因为某些原因)的人不喜欢,是因为它难以理解,难以更新;最终用户不喜欢,是因为它太脆弱,容易出错,也不符合他们的期望。 快速反馈.从开始采取行动,到获得行动的反馈,二者之间的时间至关紧要。和其他人一共开发模型,你的想法可以立刻获得反馈,特别是你的工作采用了共享建模技术的时候,例如白板、CRC卡片或即时贴之类的基本建模材料。和你的客户紧密工作,去了解他们的的需求,去分析这些需求,或是去开发满足他们需求的用户界面,这样,你就提供了快速反馈的机会。 软件是你的主要目标. 软件开发的主要目标是以有效的方式,制造出满足project stakeholder需要的软件,而不是制造无关的文档,无关的用于管理的artifact,甚至无关的模型。任何一项活动(activity ),如果不符合这项原则,不能有助于目标实现的,都应该受到审核,甚至取消。 轻装前进.你建立一个artifact,然后决定要保留它,随着时间的流逝,这些artifact都需要维护。如果你决定保留7个模型,不论何时,一旦有变化发生(新需求的提出,原需求的更新,团队接受了一种新方法,采纳了一项新技术...),你就需要考虑变化对这7个模型产生的影响并采取相应的措施。而如果你想要保留的仅是3个模型,很明显,你实现同样的改变要花费的功夫就少多了,你的灵活性就增强了,因为你是在轻装前进。类似的,你的模型越复杂,越详细,发生的改变极可能就越难实现(每个模型都更“沉重”了些,因此维护的负担也就大了)。每次你要决定保留一个模型时,你就要权衡模型载有的信息对团队有多大的好处(所以才需要加强团队之间,团队和project stakeholder之间的沟通)。千万不要小看权衡的严重性。一个人要想过沙漠,他一定会携带地图,帽子,质地优良的鞋子,水壶。如果他带了几百加仑的水,能够想象的到的所有求生工具,一大堆有关沙漠的书籍,他还能过得去沙漠吗?同样的道理,一个开发团队决定要开发并维护一份详细的需求文档,一组详细的分析模型,再加上一组详细的架构模型,以及一组详细的设计模型,那他们很快就会发现,他们大部分的时间不是花在写源代码上,而是花在了更新文档上。 补充原则: 内容比表示更重要.一个模型有很多种的表示方法。例如,可以通过在一张纸上放置即时贴的方法来建立一个用户界面规格(基本/低精度原型)。它的表现方式可以是纸上或白板上的草图,可以是使用原型工具或编程工具建立和传统的原型,也可以是包括可视界面和文本描述的正式文档。有一点很有意思,一个模型并不一定就是文档。它们通常作为其它artifact的输入,例如源代码,但不必把它们处理为正式的文档,即使是使用CASE工具建立的复杂的图表,也是一样。要认识到一点,要利用建模的优点,而不要把精力花费在创建和维护文档上。 三人行必有我师.你不可能完全精通某项技术,你总是有机会学习新的知识,拓展知识领域。把握住这个机会,和他人一同工作,向他人学习,试试做事的新方式,思考什么该做,什么不该做。技术的变化非常的快,现有的技术(例如Java)以难以置信的速度在改进,新的技术(例如C#和.NET)也在有规律的产生。现存开发技术的改进相对会慢一些,但也在持续的改进中--计算机产业属于工业,我们已经掌握了其中的试验基本原理,但我们还在不断的研究,不断的实践,不断的改进我们对它的了解。我们工作在一个变化是家常便饭的产业中,我们必须通过训练、教育、思考、阅读、以及和他人合作,抓住每一个机会学习新的处事之道。 了解你的模型.因为你要使用多种模型,你需要了解它们的优缺点,这样才能够有效的使用它们。 了解你的工具.软件(例如作图工具、建模工具)有各种各样的特点。如果你打算使用一种建模工具,你就应当了解什么时候适合用它,什么时候不适合用它。 局部调整. 你的软件开发方法要能够反映你的环境,这个环境包括组织特征,project stakeholder的特征,项目自身的特征。有可能受其影响的问题包括:你使用的建模技术(也许你的用户坚持要看到一个细节的用户界面,而不是初始草图或基本原型);你使用的工具(可能你没有数字照相机的预算,或是你已经拥有某个CASE工具的license);你遵循的软件过程(你的组织采用XP的开发过程,或是RUP,或是自己的过程)。因此你会调整你的方法,这种调整可能是针对项目的,也可能是针对个人的。例如,有些开发人员倾向于使用某一类工具,有些则不用。有些人在编码上花大力气,基本不做建模,有些则宁可在建模上多投入一些时间。 开放诚实的沟通.人们需要能够自由的提出建议,而且人们还应该能够感受到他们是自由的。建议可能是和模型有关的想法:也许是某些人提出某部分新的设计方法,或是某个需求的新的理解;建议还可能是一些坏消息,例如进度延误;或仅仅是简单的工作状况报告。开放诚实的沟通是人们能够更好的决策,因为作为决策基础的信息会更加准确。 利用好人的直觉.有时你会感觉到有什么地方出问题了,或是感觉什么地方有不一致的情况,或是某些东西感觉不是很对。其实,这种感觉很有可能就是事实。随着你的软件开发的经验的增加,你的直觉也会变得更敏锐,你的直觉下意识之间告诉你的,很可能就是你工作的关键之处。如果你的直觉告诉你一项需求是没有意义的,那你就不用投入大量的精力和用户讨论这方面的问题了。如果你的直觉告诉你有部分的架构不能满足你的需要,那就需要建立一个快速技术原型来验证你的理论。如果你的直觉告诉设计方法A要比设计方法B好,而且并没有强有力的理由支持你选择某一个方法,那就尽管选择方法A。勇气的价值就已经告诉你,如果未来证实你的直觉是错的,你也有能力来挽救这种情况。你应该有这种自信,这很重要。
数据库的设计很重要,一定要在对全部功能都很了解和熟悉的情况下来设计使用。然后就是架构,使用的是典型的MVC架构。DBMS----DAO--JAVABEAN---SERVLET---JSP/HTML----WEBBROWSER。这种架构很简单,但相对来说有些庞大,对于项目的组织结构需要控制。
经过实践证明,Scrum 方法用于开发要求快速、灵活,且生命周期短的需求还是很给力的。 关于启动 Scrum 方法的套路就不再赘述了,都是经典的东西。下面总结一下独特的经验(大家鼓掌): 在 sprint planning meeting 上定好本次迭代(迭代即 sprint,之于Scrum的意义不解释)的计划,计算出总“人天”和这次迭代的总“工作日”,画出 burn down 图,burn down 图对于把控 sprint 的进度、及时发现进度和阻碍方面问题是有帮助的。 可以考虑加入“投入程度 ”这个指标调节个人的“人天”数,如果有需求之外因素,例如技术变革啥玩意干扰的话。 为方便管理和估算,最小的估算时间单位为 0.5人天 ,比这个还小的粒度或忽略或归并。 一般最大的任务单位为 5人天 ,即一个工作周的时间。我认为一个任务工作量的估算超过这个数字就不适用 Scrum 敏捷的特征了,这时候要么拆解,要么直接回归经典软件工程的“人月神话”得了。 在白板上建立 next 域 和 紧急任务 域 是非常重要的。前者可以确保你不会丢失因为种种原因而未排入本次 sprint 的需求任务;后者用于处理不可避免的紧急任务(一般是老大从战略角度压下来的,非计划的),这也能让管理者清楚的看到计划为何 delay 或为何要加班。 在 sprint 过程中,如果发现因为需求不明确而无法进行的任务,请立即归入 next 域(不要犹豫,因为开发不明确的需求犹如盲人摸象,返工成本绝对够任何人喝一壶的),这样可有效的避免浪费时间,可敦促需求人员完善设计,且不会丢失需求。——如果这种情况多了,burn down 图会很快燃尽,Scrum master 能够及时提醒 Scrum owner 提高需求和设计的质量。 对于临时插入的任务,重要且紧急 的立刻排入 紧急任务 域,立刻打断 sprint 计划,不惜代价开始搞,因为你已经将此任务识别为重要且紧急。——如果这种情况多了,白板上的反映为 紧急任务 域密密麻麻,而此段时间内,burn down 图将呈一条水平线。这是因为计划任务被大量紧急任务打断,而无法“燃烧”,这时候,插入临时任务的人就应该思考了?为什么那么多事情都没有计划! 对于临时插入的任务,重要且不紧急 的进入 next 域,走下次 sprint。这样即可以给这些重要的任务一个应有的地位,也不会打乱现有的计划。我们要尽量按计划做事,否则再好的计划也没有人会执行鸟。 除此之外的任务,开发人员还用考虑么?需求人员懂的。 每天的晨会可以方便大家的互相了解情况,及时的发现并解决一些问题,隐藏的很深的 Block 一般在这个时候会被识别出来。 周期再短的 sprint,也会有开发人员先行完成所有计划任务,这时候可以尝试把此人拿去和某些未完成关键任务的人去玩结队编程或同级评审(peer review)。这也可应付突发情况,例如,即使某个关键人物得了病,sprint 也不至于完蛋。 对于任务完成(done)的定义就是:随时可以上线 。因为毕竟要上线还是需要一个“良辰吉日”——所有的相关需求都OK才行。 每个 sprint 结束后,最好有一天间歇的时间整理总结。一个 sprint 紧接着一个 sprint 容易使人疲劳。 对于需求人员(包括 Scrum owner)由于经验不足,在 sprint planning meeting 提出的需求过小,而 sprint 开始后需求频繁变更或扩大化导致技术人员对任务评估不足的情况。可以有下面3个解决步骤: 需求文档化。即执行CMM方法的需求管理模块,严格跟踪需求变更,需求必须文档化。需求变更可以,但是要有标记、可追溯。需求文档纳入配置管理。 识别:需求变更需要一部到位的。在达成需求扩大的共识后,把扩大的需求单独拆出,放到“紧急任务”域中。前面已经说了这在燃尽图上会体现出来,导致“燃不尽”,让问题暴露出来! 识别:需求变更可以分段优化的。在当前 sprint 中留出扩展接口,需求变更作为新需求扔到 next 域里,归入下一个 sprint。还是那句话,尽量按照计划来,这是个原则。 当然还要遵循“紧急/不紧急”的原则,可以这样理解:sprint 计划是 Scrum master 和 Scrum owner 签订的“合同”,合同不能篡改。而对于合同的增补和裁剪是允许的,但需要记录在案、有案可查。 “团队凝聚力”是 Scrum 的核心要素之一,如果一个团队同心协力完成了多个 sprint,团队成员就会变得非常紧密。他们会学会如何达成团队涌流(group flow,请参见 http://en.wikipedia.org/wiki/Flow_%28psychology%29 ),生产力会提升至难以置信的地步。不过要达到这个地步需要花上一定时间。如果不断变换团队组成,你就永远无法得到强悍的“团队生产力”。所以,如果你确实想要重新组织团队,请先考虑一下后果。这是个长期变化还是短期变化?如果是短期变化,最好考虑跳过这一步。如果是长期变化,那可以干。 互联网行业的开发非常适应 Scrum 的特点,因为周期短、变化多、交付快……。Scrum 本身是一种思想方法,不同的项目对其需要有不同的实现和裁剪,通过不断的迭代(sprint),找到最合适自己的实践。