依赖是否可以作为一个独立的衡量软件质量的标准?

这个争论的背景有点复杂。我就尽量简化了说。

遗留系统有一个自制的service locator。是一个静态函数:
[code]
public static Object newObject(Class interfaceOrDefaultClass, Class[] parameterTypes, Object[] arguments);
[/code]
使用起来是这样:
[code]
ImplFactory.newObject(MyInterface.class, new Class[]{int.class, String.class}, new Object[]{new Integer(1), "abc"});
[/code]
这个函数会根据一个properties文件的配置来寻找一个带有制定构造函数的实现或者继承MyInterface的类。
比如,如果配置文件里面配置了
[code]
com.mycompany.MyInterface=com.mycompany.MyInterfaceImpl
[/code]
而MyInterfaceImpl有这个构造函数:
[code]
public MyInterfaceImpl(int i, String s);
[/code]
那么,MyInterfaceImpl就会被使用。

而如果调用的时候用了一个缺省类,那么如果配置文件没有配置,就会使用这个缺省类,比如:
[code]
ImplFactory.newObject(DefaultMyInterfaceImpl.class, new Class[]{int.class, String.class}, new Object[]{new Integer(1), "abc"});
[/code]

这个自制的service locator无疑是非常原始,也是很难用的。为了准备向一个真正的ioc container过渡,我实现了一个dynamic proxy来封装ImplFactory。

使用起来如下:
[code]
MyInterface = serviceFactory.getMyInterface(1, "abc");
[/code]
使用者只需要把getMyInterface这个函数声明在ServiceFactory这个接口中,就可以直接使用getMyInterface()函数了。当然,这个serviceFactory是作为倚赖被注射进客户类的。以后,如果我们切换成了ioc容器,比如spring,只要增加一个dynamic proxy就行了,客户代码基本不用动。

我的同事(ImplFactory就是他亲手做的),对这个ServiceFactory不是太感冒。他认为这样做明显的好处就是一个语法糖,语法漂亮一点而已。而因为ImplFactory本身已经是个抽象,ServiceFactory又是包在ImplFactory外面的抽象,那么"abstraction on top of abstraction"就显得多余,或者说过度设计。我对这样一个在我看来毫无争议的问题有点不知道怎么说,不过我跟他说这样以后可以轻易地转移到别的ioc container上面,才说服了他。


ImplFactoryProxy具体怎么实现的,只要懂dynamic proxy的都会,我就不赘述了。


这个实现里面,有一个问题,就是怎么处理这个“缺省实现类”。在原来的代码里面,缺省实现类是硬编码在客户程序里的。而现在的用法里面,客户不能制定缺省实现类,所以这个信息需要额外提供给这个dynamic proxy。

我的做法仍然是注射,通过注射一个java.util.Map对象到这个ImplFactoryProxy类,来给这个类提供缺省实现信息。签名如下:
[code]
public class ImplFactoryProxy {
private final Map defaults;
ImplFactoryProxy(Map defaults) {
this.defaults = defaults;
}
...
}
[/code]

写好了ImplFactoryProxy之后,我面临的下一个问题是怎么得到这个Map。我的做法是通过ClassLoader.loadResourceAsStream()来读入一个存在当前package里面的properties文件,然后调用Properties.load(inputStream)来得到Properties,这个Properties对象自然就可以注射进ImplFactoryProxy了。

至此,希望你会说:没什么亚。大家都是这么做的。


不过,问题来了。
我的那个老资格的同事在review代码的时候看到这个ClassLoader.loadResourceAsStream,说:[b]这个不行,我希望你改成用我们的PropFactory框架。[/b]

话说,这个遗留系统有一个相当强大(或者说复杂?)的读取property的框架,这个框架除了一般的按照key读取value,还支持树形的property,也就是说,一个key可能对应一个子property map。(当然,还有其他功能)

用法是:
[code]
PropFactory.getInstance().getProperty("property file name").getPropertyValue("key");
[/code]

这样的代码充斥整个code base。


我对这个框架的态度是相当保留的。主要的原因是我认为大多的配置值应该通过注射,而不是主动地去找PropFactory框架要。这种PropFactory.getInstance()的代码使单元测试变得困难,而且加大了系统耦合,随便一个模块就要依赖于PropFactory。

而我在我的dynamic proxy中不使用PropFactory,除了上面的原因,还有以下几点:
1。我要的就是一个简单的key-value map。根本不需要PropFactory提供的那么多功能。
2。Properties, ClassLoader.loadResourceAsStream都是标准jdk的东西,用起来也不难。而且我也做了一个IOUtils类来封装这部分代码:
[code]
IOUtils:
Properties loadProperties(ClassLoader loader, String resourceName);
[/code]
3。我这个dynamic proxy相当的self contained。它基本上和现有的遗留系统除了ImplFactory没有任何其它关联。我也不希望引入任何不必要的依赖。

但是,显然,这些观点在同事那里是站不住脚的:
1。不管你需不需要额外的功能,你直接调用这个api就好了。又不需要额外写代码。
2。项目中大家都使用PropFactory来读取配置。如果大家你写一个ajoo way of reading property,他写一个bjoo way of reading property,那不是乱套了?这样做破坏了一致性,增大了团队协作的难度。
3。依赖就依赖了,有什么关系?这个几乎是公司内部的事实标准了。大家都这么用,还是头回听说有人对这个依赖有问题的。
4。如果不用PropFactory,谁能保证你的代码就在任何情况都工作?这个项目的build process, deploy process都很复杂,难以预测你这个代码在nightly build甚至在生产环境中也会工作。


对此,当然我是不同意的。我认为,ClassLoader.loadResourceAsStream几乎是工业界的标准,相比于一个公司自制的标准,我还是更倾向于相信被无数人证明工作的业界标准。
而且,试图让PropFactory包打一切也是不现实的。最起码,你用的commons logging, log4j等等开源库,都不可能依赖于你自己写的PropFactory,它们只能使用ClassLoader。所以这个一致性从一开始就不存在。
最后,我认为“一致性”在项目中被错误解读了。打个比方,项目中大家一致都是用jsp,但是我不认为当只需要一个servlet或者甚至一个静态的html的时候,我们也必须要为了一致性通过jsp来绕一圈生成这个servlet或者html.


经过争论,我还是做了妥协,只要我可以注射Map,你非要用in house framework而不是业界标准来读文件,也罢。

于是我的方案变成:
[code]
new ImplFactoryProxy(PropFactory.getInstance().getProperty("defaults.properties").toProperties())
[/code]
这个toProperties()是PropFactory框架提供的一个函数,可以把我们inhouse的IProperties转换成java.util.Properties。

最终面向用户的接口(在没有采用ioc容器的情况下,只好还是允许客户代码主动取得ServiceFactory实例。)是:
[code]
public class ServiceFactoryUtil {
public static ServiceFactory getServiceFactory();
}
[/code]
这个类负责调用PropFactory.getInstance(),并且提供singleton服务以避免重复读取properties文件。


这几乎是我可以接受的底线了。


但是,同事仍然不满意。他最喜欢的是我不去注射Map,而是在ImplFactoryProxy内部直接调用PropFactory。这个在我来说是不可考虑的。

当然,他也退了一步,同意我的注射方式。但是认为我不应该注射java.util.Map,而应该注射IProperties。

同事的理由:
1。这样可以避免一个toProperties()调用。别人读代码的时候,可以不会纳闷“为什么这里要这么做?”。
2。java.util.Map这个接口太肥大。我需要的其实就是一个get(),最多加上keySet()和containsKey(),用一个java.util.Map不合适。


而我反对使用IProperties,理由是:
1。IProperties不是标准接口,我宁愿以来jdk标准接口。毕竟熟悉java.util.Map的比IProperties多多了吧?即使IProperties是在公司内部被“一致”使用。
2。没人会纳闷为什么要调用toProperties()。如果这都要纳闷,那么整个遗留系统的那数万行的代码就没法读了。
3。如果说java.util.Map不是最小接口,IProperties也不是。它也有一些我不需要的函数。
4。整个公司从来没有人用注射的方式来使用IProperties。大家都是PropFactory.getInstance()这样从头调用的。难保注射IProperties不会出什么问题。(比如,同步问题?后来,虽然同步问题没法验证,我确实发现了IProperties不支持Serializable,致使我的ServiceFactory也不能Serializable。这样类似的问题,如果真是采用了IProperties,还不知道会不会陆续向外蹦呢)。

最终,因为我是这个功能的开发者,还是以我的意见为主了。但是我并没有说服同事。在争论过程中,让我深感郁闷的是,我的“减小依赖”的论点根本不为同事接受,似乎在他们看来“依赖”并不能作为一个理由。而我也发现要把减小依赖和他们接受的DRY,unit test等原则直观地联系起来不太容易。

那么,你是怎么看这个问题的呢?
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值