Maven快速构建springmvc+mybatis项目

1. git clone https://github.com/chinageek/maven-archetype-templates.git

2. cd git/maven-archetype-templates/quickstart-springmvc-mybatis

3. mvn clean

4. mvn archetype:create-from-project

5. cd target/generated-sources/archetype

6. mvn clean install

7. mvn archetype:generate

8. Enjoy :-)

提高代码可读性的注释技巧

1. 逐层注释

为每个代码块添加注释,并在每一层使用统一的注释方法和风格。例如:
针对每个类:包括摘要信息、作者信息、以及最近修改日期等;
针对每个方法:包括用途、功能、参数和返回值等。
在团队工作中,采用标准化的注释尤为重要。当然,使用注释规范和工具(例如Java里的Javadoc)可以更好的推动注释工作完成得更好。

代码可读性 阅读详细 »

为什么程序员总是不能准确预估工作量

一个经验丰富的项目经理声称,他拿到程序员的时间估算以后,先将它乘以π,然后单位变为下一个时间数量级后,才能得到真正的值。即1天转化成3.14周。他过去因为程序员不擅长估算时间而吃尽了苦头。我创建了一个用来翻译程序员时间估算的表格,来尽量缩小估算错误。

 time

时间估算是困难的。每一个程序员都有一个现实的估计区间。低于这个区间的估计意味着(构件,测试,检查代码的)时间开销被低估了。超过这个区间的估计意味着这个任务太大而很难预估。

对于初级开发者来说,这个区间甚至都不存在。他们忽略(构件,测试,检查代码的)时间开销,同时困难的任务他们却又无法预估。我想说一个有经验的开发者应该在0.5至24小时将事情做完。超过24小时,就需要细分。这项工作应该在开发者的头脑中完成,然后总和到60小时。但是即使是有一些有经验的开发者也需要有利用管理时间块来思考。

同样重要的是明白:编程经验不等同于估算经验。一个不被包含在估算流程中的开发者将不会擅长估算。同样,如果实际的时间花费不被测量和用于与估算比较,那么将没有反馈来学习。

最后,每个程序员都应该具备估算的技能。为磨练这个技能,接手每个任务时,先决定你要做什么。然后在开始之前估算任务所需时间。最后测量实际花费时间,并与估算相比较。同样比较你实际完成的与计划完成的。这样你将会既提高你对一个任务包含细节的理解,同样也提高了你的估算技能。

Java方法不应超过15行

大多数人都会说,方法不能太长,但也不能定死,要具体问题具体分析。再追问一下,有人会说,不超过200行,100行,50行,30行都有。另有人说,面向对象风格的可以短些,面向过程风格的可以长些。也有人说,一个方法不超过一屏幕就行(姑且不论显示器大小,字体大小和分辨率问题)。

先摘录一段Martin Fowler《重构》P110-P111 中的一段话:

人们有时会问我,一个函数多长才合适?在我看来,长度不是问题,关键在于函数名称和函数本体之间的语义距离(semantic distance)。如果提炼动作(extracting)可以强化代码的清晰度,那就去做,就算函数名称比提炼出来的代码还长也无所谓。

说了直白点,函数名是干什么,函数体是怎么干。当2者不是那么能容易分辨出来时,就需要提炼出函数来,让代码更好懂。

既然大师都说了,长度不是问题了吗,那干吗还要追究函数长度规范呢?
其实大师讲的是对于懂得编程之道的人而言,不用关心长度,因为小函数是必然的结果。但在开发实践中,适当的函数长度限制值,可以给予我们警示,为什么这个方法写长了?哪里不对劲了?
对于这个问题我的回答是:Java函数不应超过15行。
为什么定这个数呢?
一方面,这个是基于多年开发实践的总结。15行其实已经是一个比较宽松的标准,开发人员稍加培训就可以实际贯彻,而符合这个标准的函数也能达到良好的可读性。

另一方面,这是基于对函数复杂度和代码行数之间关联关系的认识。
我采用一个简单的数学公式:

方法复杂度 >= 代码行数^2 (该公式参考于 gerald m. weinberg 《质量·软件·管理(第1卷)——系统思维》)

以下为了简化,只以最低增长方式,平方数进行计算。
以一个函数的行数,从1行到20行为例,见下图:

java

当函数行数到达10行以上,函数复杂度就开始大幅度攀升。
当代码行数达到20行时(复杂度400),其复杂度已经是14行时(复杂度 196)的2倍。
因此我将代码规范定在15行。

下面我们运行此公式,来分析一下提炼小函数的好处。
例如,有1个100行的函数,分解为11(含自身)个10行的函数。
原复杂度= 100^2=10000。
分解后复杂度= 11×(10^2)= 1100。
分解后的复杂几乎是分解前的 1/9,几乎降低了1个数量级。这就解释了为什么长方法分解之后,可维护性大幅度提高。

也就无怪乎有同学表示维护1000行以上的函数,有种生不如死的感受。

 

项目经理是干什么的

项目经理

小M是一名毕业于名牌大学软件专业的研究生,在学校中随导师参加过一些国家级的科研项目。毕业后,小M如愿加入某知名IT公司。

为了适应管理要求,该公司已经引进并实施了“项目型”管理模式,企业内按行业划分成事业部,项目是事业部最基本的业务运作单位;各事业部内设专职的项目经理,项目经理对项目的全过程负责,因此是公司最重要的基层管理角色之一。

小M觉得,项目经理受人尊重、令人羡慕。不仅羡慕他们每次完成一个项目回到公司后受到英雄般的欢迎,跟公司高层可以面对面直接沟通,还有老客户、老同事经常寄来的土特产。就拿小M的顶头上司事业部总经理S总来说,原来是做技术的,后来成了项目经理,之后连续做了几个大项目,就成了领导眼里的“红人”,在客户那里也有很高威信。现在,年纪轻轻已经成了一名总经理,独立负责了公司的一大块业务。

项目经理也是公司的稀缺资源。由于公司的项目技术性比较强,需要既懂得IT技术又具备项目管理技能的人才,因此鼓励技术人员转型做项目经理。小M觉得自己符合项目经理的要求,但是,做一名项目经理是个严肃的职业选择,在进入亮丽的光环之前,首先需要弄清楚,项目经理是干什么的?

于是,小M找到了S总,谈了自己的想法,希望得到S总的指导。S总热情接待了小M,并回答了小M的问题。

小M首先问:“S总,请问项目经理是个什么样的角色呢?”

S总说:“项目经理是公司委派的负责实现项目目标的个人,是公司授权的项目负责人,是项目的直接组织者和领导者。项目经理对外代表公司与客户和分包单位进行联系,处理合同有关的商务事宜;对内全面负责项目的实施。一些企业中由职能经理代替项目经理,项目经理是兼职和客串的角色。这种兼职的项目经理实际上并不承担上述职责。”
小M接着问:“那项目经理的具体职责是什么呢?”

S总说:公司里的项目经理的职责有三个方面:

1.对项目全过程进行组织和管理,按预期交付项目的成果;
2.管理客户关系,以取得客户对交付的成果及过程的最满意评价;
3.管理项目团队,使之高效而又愉快地工作,并获得最满意的工作体验。
也就是说,一个合格的项目经理必须同时做到 ‘按预期交付成果’、‘让客户满意’、‘让员工满意’

小M又说:“那IT项目经理的主要任务是什么呢?”

S总说:

第一,支持售前过程。IT项目一般比较复杂,交付风险比较大,需要在合同中约定工作范围、进度计划,要估算成本和人力资源。项目经理近距离地了解需求、资源等约束,制定的项目实施方案才会切实可行。参加售前过程不仅有助于项目经理深入了解客户需求,也可以帮助客户了解项目经理的能力。有的时候,客户会因为相中‘项目经理’而促成合同的签订,甚至要求将锁定某位项目经理作为合同的条件。

第二,负责项目交付。签订合同之后,项目经理负责围绕预期目标、遵循确定的规范执行项目。项目经理不仅要制定思路清晰、考虑周密的计划,还要调集资源、委派任务,推进计划的执行;过程中,还要及时处理出现的问题,定期向有关人员汇报进展,保证在规定的时间和预算内交付项目成果。

第三,完成项目收尾。完成交付成果之后,要将成果移交给客户,确保客户可以稳定地使用系统。然后,将后续服务移交给服务部门,确保客户得到持续的服务保障。项目经理交付的成果直接决定客户满意度、影响客户是否愿意付款,因此公司里还要求项目经理负责完成收款工作。

第四,管理干系人的关系。一个IT项目可能涉及投资方、客户、分包单位、合作伙伴,甚至可能包括政府、社会等各方面的关系;面对的‘客户’也不是一个人,而是一个群体。项目经理作为各方的桥梁和纽带,要随时处理各方信息,保持密切沟通,解决矛盾冲突,只有这样才能让‘客户’满意。

第五,管理项目团队。由于项目团队的临时性,项目经理需要花费很大的精力寻找合适的资源,优化资源配置,建立合理的组织结构,确定清晰的职责分工。项目过程中还需要通过各种措施进行团队建设,打造高效团队。”

从这些工作任务的性质来看,项目经理是项目的推动者,也是关系的协调者。 阅读详细 »

maven中的dependencyManagement与dependencies关系

dependencyManagement 中的 dependencies 元素只表明依赖项版本的优先选择,并不影响项目的依赖项。所以Parent POM的有dependencyManagement 中的 dependencies 元素不会自动的加到child的dependencies 列表里。只有child里有同样的dependencies 时,才会被parent中dependencyManagement 中的 dependencies 元素所影响(主要是版本信息)。

程序员的五个阶段

第一阶段:编码机器

这是最低级的阶段,程序员拿到详细设计文档,上面连许多方法接口都定义好了。重构一些代码,写一些实现,调用一些既定的API,然后花许多时间在各种各样的场景测试上面。从做的工作上看,这都不能算程序员,最多,只是编码技巧卓越的码农而已。因为它几乎扼杀了一切创造力,但是这很常见,比如在一些对日外包公司,就是如此。

过程

第二阶段:独立的实现者

程序员得到的只是粗略的设计文档,也许注明了外部接口的清单,还有框架和基础设施的API,需求已经澄清清楚,接下去要做的就是发挥聪明才智把软件实现设计好,把代码写好,测试通过。这项工作可以在安静和独立的环境中完成,因为没有什么是不够明确的,那些本不清楚的部分,项目经理、架构师和产品经理已经搞定了。这样的环境下可以诞生许许多多OO设计优秀、代码清晰简洁的程序员,但是这始终只是在做一个残缺的项目而已。很多程序员新手都是从这个阶段开始的,但是程序员如果只会代码层面的设计、编码和测试,并不能算一个完整的程序员,也许连一半都算不上。

第三阶段:项目沟通者和管控者

程序员要和需求工程师,甚至客户澄清需求,分析可行性;需要自行分析设计项目中的技术难点;参与决定和管理迭代周期和计划表;组织和参与项目组内运作跟踪会议。编码以外的事情会占用一些时间,这些时间大多来自沟通的成本。如果说,前两个阶段还未能明显看出沟通的重要性的话,那么到这个阶段,一个不能良好沟通的程序员,将成为项目组运转的瓶颈。国内至少有一半的软件公司的程序员做项目应该处于这个阶段。 阅读详细 »

JVM之heap和stack的区别

Heap(堆)

Stack(栈)

JVM中的功能

内存数据区

内存指令区

存储数据

对象实例

基本数据类型, 指令代码,常量,对象的引用地址

1. 保存对象实例,实际上是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在stack中)。

对象实例在heap中分配好以后,需要在stack中保存一个4字节的heap内存地址,用来定位该对象实例在heap中的位置,便于找到该对象实例。

2. 基本数据类型包括byte、int、char、long、float、double、boolean和short。函数方法属于指令.

"Java 的堆是一个运行时数据区,类的对象从中分配空间。这些对象通过new、newarray、anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。"

“栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。 ”

可见,垃圾回收GC是针对堆Heap的,而栈因为本身是FILO – first in, last out. 先进后出,能够自动释放。 这样就能明白到new创建的,都是放到堆Heap!

OO的五大原则

 

 
OO的五大原则是指SRP、OCP、LSP、DIP、ISP
1. SRP(Single Responsibility Principle 单一职责原则) 
所谓单一职责,就是一个设计元素只做一件事。
2. OCP :开闭原则
“对变更关闭;对扩展开放”。
3.LSP——里氏替换原则 
4.DIP 依赖倒置原则 
依赖倒置(Dependence Inversion Principle)原则讲的是:要依赖于抽象,不要依赖于具体。 
5.ISP 接口隔离原则 
使用多个专门的接口比使用单一的总接口要好。
 

web.xml 中的listener、 filter、servlet 加载顺序及其详解

一、概述

1、启动一个WEB项目的时候,WEB容器会去读取它的配置文件web.xml,读取<listener>和<context-param>两个结点。

2、紧接着,容器创建一个ServletContext(servlet上下文),这个web项目的所有部分都将共享这个上下文。

3、容器将<context-param>转换为键值对,并交给servletContext。

4、容器创建<listener>中的类实例,创建监听器。

二 、 load-on-startup

load-on-startup 元素在web应用启动的时候指定了servlet被加载的顺序,它的值必须是一个整数。如果它的值是一个负整数或是这个元素不存在,那么容器会在该servlet被调用的时候,加载这个servlet 。如果值是正整数或零,容器在配置的时候就加载并初始化这个servlet,容器必须保证值小的先被加载。如果值相等,容器可以自动选择先加载谁。

在servlet的配置当中,<load-on-startup>5</load-on-startup>的含义是:

标记容器是否在启动的时候就加载这个servlet。

当值为0或者大于0时,表示容器在应用启动时就加载这个servlet;

当是一个负数时或者没有指定时,则指示容器在该servlet被选择时才加载。

正数的值越小,启动该servlet的优先级越高。

三  、加载顺序

首先可以肯定的是,加载顺序与它们在 web.xml 文件中的先后顺序无关。即不会因为 filter 写在 listener 的前面而会先加载 filter。最终得出的结论是:ServletContext -> listener -> filter -> servlet 阅读详细 »