上一个Sprint总结会中,组内有人提出很多需求为什么会变化,这样搞的开发人员多累啊。为什么一开始就不采取最后决定的方式去做,还一定要折腾下呢。恰好最近看了小道消息一篇关于试错的推文,很是感触。
这点上我承认在沟通管理上没有及时发现组内成员的情绪,而且也没充分让开发人员参与到整体设计过程中,让他们缺少对整体的认识,也没很好的调动他们的积极性。
但是,就是在为什么一开始就不采取最后决定的方式去做这点上,我没法赞同的更多了。的确,需求上的改动,是因为经验,或是能力的问题,或是组织环境要求或是,更或是客户有了新的想法。开发人员就觉得你很脑残啊,为什么不早发现,早你干嘛去了。
对于这个问题,首先我觉得不少人混淆了“试错”和“错误”两个事情。而修改功能过程中,都会出现新的问题,而且在代码走查中,发现了很多代码不够健壮,比如通过连接获取信息只获取一次而没有设定超时时间循环获取导致出错,这些都会引入BUG。所以,功能修改的时候发现修改难度过大,那就得先看看自己做的事情是否不够严谨,自己设计的是否不够周全。
有些偏题,回到主题上,每个人也都无法一次就找到正确的方式,乔布斯也是在不断的试错。特别是项目组走的是敏捷开发道路,一般都是简单实现,之后扩展,就是在不断的重构,如果完全拒绝修改、更正。
之所以开发人员会产生误解,主要我觉得是问题反馈的对象的问题。基本上领导、评审人员、客户都是将问题反馈给我,而开发人员又没想去了解这些反馈,甚至在评审会议上打瞌睡觉得事不关己。总之试错是为了让产品更好,能不断进步。如果一个软件完全不用修改,那是因为他没人会去用,没有反馈的问题。
========分割线=========
之前两片基本上把Maven部署和Helloworld的过程以及过程中可能出现的问题都说到了。这篇就来说说Maven的依赖。
[b]依赖类型[/b]
Maven会用到的依赖基本就是5种,compile,test,provided,runtime,system
1.compile:编译依赖范围,默认使用该范围。编译、测试、运行都有效
2.test:测试依赖范围。支队测试的classpath有效。例如Junit,greenMail。
3.provided:对编译和测试有效,对运行无效,常用于容器提供了的运行环境。例如servlet-api,容器以提供,所以只需要编译和测试有效即可。
4.runtime:运行时依赖范围。例如jdbc驱动,编译和测试并不需要,只需要使用JDK提供的JDBC接口即可。
5.system:系统依赖范围,依赖Maven仓库意外的依赖。
例如
[b]依赖的传递[/b]
项目中,其实经常会出现这种情况,应用了某个Jar包,然后使用时候报错缺少某个类,这就是因为缺少了该jar包所依赖的jar包的原因。例如工程A依赖了,spring-core,spring-core依赖commons-logging,那A依赖spring-core时候依旧传递的依赖了commons-logging。
##传递依赖的范围
假设A依赖B,B依赖C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围,如下图,最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间交叉单元格表示传递性依赖范围。
[table]
| Tables | compile | test | provided | runtime |
| ------------- |:-------------:| -----:|:-------------:| --------:|
| compile | compile | X | X | runtime |
| test | test | X | X | test |
| provided | provided | X |provided | provided|
| runtime | runtime | X | X | runtime |
[/table]
注意:X代表不依赖
[b]依赖冲突的调解[/b]
有两个原则,第一原则是路径短优先原则,第二原则是先声明者优先
##路径短优先原则
依赖调解的第一原则是:路径最近者优先。
A ->B->C->X(1.0)
A ->D->X(2.0)
这样A会传递性依赖X(2.0)
##先声明者优先原则
赖调解的第二原则是:先声明者优先。
当路径长度相同时候,第一原则已经不能解决问题了,Maven2.0.9以后版本就有了第二原则,声明在先者有效。
A ->C->X(1.0)
A ->D->X(2.0)
这样A传递性依赖了X(1.0),因为他是先声明的。
[b]可选依赖[/b]
可选依赖不被传递。例如下例,B有一个持久层工具包依赖,他依赖了两种数据库驱动,这两种特性只需要选择一种,这种传递性依赖是不会给传递的,需要在A项目中另外依赖数据库驱动依赖。
正常情况不应该使用可选依赖,可选依赖一般是项目有多个特性,在面向对象设计中单一原则意指一个类应该只有一项职责。
[b]排除依赖[/b]
有的时候传递性依赖的依赖包还处于不稳定版本,或者传递性依赖包因为版权问题不存在于中央仓库,这时候需要引入其他等价的依赖包。
所以需要排除依赖,然后自己在配置文件中再引入相应的依赖包。
[b]归类依赖[/b]
有时候,像Spring框架,当更新依赖时候,需要更新一片的依赖关系,这时候一个一个去修改过于麻烦,不如定义一个常量,更新时候手动修改一个就好了。
可以在pom.xml文件中的project标签下,定义
然后引入依赖时候,在version 中使用 ${ springframework.version }即可。
[b]依赖优化[/b]
##依赖列表
mvn dependency:list命令可以列出当前所有依赖(包括直接和传递)的列表,以及范围。
##依赖树
mvn dependency:tree命令可以层次化的列出所有依赖,可以从书中看出依赖传递的关系。
##依赖分析
mvn dependency:analyze命令可以分析当前依赖,包括哪些依赖被import却没引入,哪些引来引入了但是没加入编译。有时候可以用来删除一些没用的依赖,但是不能直接删除,比如sprint-core是Spring的必须依赖,但是会提示没加入编译,但是他又是Spring框架必须的。
Unused declared dependencies 后的内容 : 项目中未使用的,但显示声明的依赖
Used undeclared dependencies 后的内容:项目中使用到的,但是没有显示声明的依赖。
这点上我承认在沟通管理上没有及时发现组内成员的情绪,而且也没充分让开发人员参与到整体设计过程中,让他们缺少对整体的认识,也没很好的调动他们的积极性。
但是,就是在为什么一开始就不采取最后决定的方式去做这点上,我没法赞同的更多了。的确,需求上的改动,是因为经验,或是能力的问题,或是组织环境要求或是,更或是客户有了新的想法。开发人员就觉得你很脑残啊,为什么不早发现,早你干嘛去了。
对于这个问题,首先我觉得不少人混淆了“试错”和“错误”两个事情。而修改功能过程中,都会出现新的问题,而且在代码走查中,发现了很多代码不够健壮,比如通过连接获取信息只获取一次而没有设定超时时间循环获取导致出错,这些都会引入BUG。所以,功能修改的时候发现修改难度过大,那就得先看看自己做的事情是否不够严谨,自己设计的是否不够周全。
有些偏题,回到主题上,每个人也都无法一次就找到正确的方式,乔布斯也是在不断的试错。特别是项目组走的是敏捷开发道路,一般都是简单实现,之后扩展,就是在不断的重构,如果完全拒绝修改、更正。
之所以开发人员会产生误解,主要我觉得是问题反馈的对象的问题。基本上领导、评审人员、客户都是将问题反馈给我,而开发人员又没想去了解这些反馈,甚至在评审会议上打瞌睡觉得事不关己。总之试错是为了让产品更好,能不断进步。如果一个软件完全不用修改,那是因为他没人会去用,没有反馈的问题。
========分割线=========
之前两片基本上把Maven部署和Helloworld的过程以及过程中可能出现的问题都说到了。这篇就来说说Maven的依赖。
[b]依赖类型[/b]
Maven会用到的依赖基本就是5种,compile,test,provided,runtime,system
1.compile:编译依赖范围,默认使用该范围。编译、测试、运行都有效
2.test:测试依赖范围。支队测试的classpath有效。例如Junit,greenMail。
3.provided:对编译和测试有效,对运行无效,常用于容器提供了的运行环境。例如servlet-api,容器以提供,所以只需要编译和测试有效即可。
4.runtime:运行时依赖范围。例如jdbc驱动,编译和测试并不需要,只需要使用JDK提供的JDBC接口即可。
5.system:系统依赖范围,依赖Maven仓库意外的依赖。
例如
<dependencies>
<dependency>
<groupId>javax.sql</groupId>
<artifactId>jdbc-stdext</artifactId>
<version>2.0</version>
<scope>system</scope>
<systemPath>${java.home}/lib/rt.jar</systemPath>
</dependency>
</dependencies>
[b]依赖的传递[/b]
项目中,其实经常会出现这种情况,应用了某个Jar包,然后使用时候报错缺少某个类,这就是因为缺少了该jar包所依赖的jar包的原因。例如工程A依赖了,spring-core,spring-core依赖commons-logging,那A依赖spring-core时候依旧传递的依赖了commons-logging。
##传递依赖的范围
假设A依赖B,B依赖C,我们说A对于B是第一直接依赖,B对于C是第二直接依赖,A对于C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围,如下图,最左边一列表示第一直接依赖范围,最上面一行表示第二直接依赖范围,中间交叉单元格表示传递性依赖范围。
[table]
| Tables | compile | test | provided | runtime |
| ------------- |:-------------:| -----:|:-------------:| --------:|
| compile | compile | X | X | runtime |
| test | test | X | X | test |
| provided | provided | X |provided | provided|
| runtime | runtime | X | X | runtime |
[/table]
注意:X代表不依赖
[b]依赖冲突的调解[/b]
有两个原则,第一原则是路径短优先原则,第二原则是先声明者优先
##路径短优先原则
依赖调解的第一原则是:路径最近者优先。
A ->B->C->X(1.0)
A ->D->X(2.0)
这样A会传递性依赖X(2.0)
##先声明者优先原则
赖调解的第二原则是:先声明者优先。
当路径长度相同时候,第一原则已经不能解决问题了,Maven2.0.9以后版本就有了第二原则,声明在先者有效。
A ->C->X(1.0)
A ->D->X(2.0)
这样A传递性依赖了X(1.0),因为他是先声明的。
[b]可选依赖[/b]
可选依赖不被传递。例如下例,B有一个持久层工具包依赖,他依赖了两种数据库驱动,这两种特性只需要选择一种,这种传递性依赖是不会给传递的,需要在A项目中另外依赖数据库驱动依赖。
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<option>true</option>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4.701.jdbc3</version>
<option>true</option>
</dependency>
正常情况不应该使用可选依赖,可选依赖一般是项目有多个特性,在面向对象设计中单一原则意指一个类应该只有一项职责。
[b]排除依赖[/b]
有的时候传递性依赖的依赖包还处于不稳定版本,或者传递性依赖包因为版权问题不存在于中央仓库,这时候需要引入其他等价的依赖包。
所以需要排除依赖,然后自己在配置文件中再引入相应的依赖包。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>2.5.6</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId> commons-logging </groupId>
<artifactId> commons-logging </artifactId>
<version>1.1.0</version>
</dependency>
[b]归类依赖[/b]
有时候,像Spring框架,当更新依赖时候,需要更新一片的依赖关系,这时候一个一个去修改过于麻烦,不如定义一个常量,更新时候手动修改一个就好了。
可以在pom.xml文件中的project标签下,定义
<properties>
<springframework.version>2.5.6</ springframework.version>
</ properties>
然后引入依赖时候,在version 中使用 ${ springframework.version }即可。
[b]依赖优化[/b]
##依赖列表
mvn dependency:list命令可以列出当前所有依赖(包括直接和传递)的列表,以及范围。
##依赖树
mvn dependency:tree命令可以层次化的列出所有依赖,可以从书中看出依赖传递的关系。
##依赖分析
mvn dependency:analyze命令可以分析当前依赖,包括哪些依赖被import却没引入,哪些引来引入了但是没加入编译。有时候可以用来删除一些没用的依赖,但是不能直接删除,比如sprint-core是Spring的必须依赖,但是会提示没加入编译,但是他又是Spring框架必须的。
Unused declared dependencies 后的内容 : 项目中未使用的,但显示声明的依赖
Used undeclared dependencies 后的内容:项目中使用到的,但是没有显示声明的依赖。