gigix早年间与andyyehoo的论战
http://www.javaeye.com/topic/8007?page=1
andyyehoo:
比较一下下面的两段代码,说真的,虽然说Java效率低一点可以原谅,不过比较一下这两段代码的效率,真是..............虽然java效率比C低n个等级大家都接受了,可是不意味着就可以把系统效率丢到爪哇国去了啊
第一个是直接new一个对象,接着调用一个方法。
第二个是首先getApplicationContext,这个过程就首先不知道耗费多少了。然后是间接的getBean,创建一个对象。接着通过调用3个比reflaction更低效率的方法,设置各个参数,最后是调用。
纯粹的比较方法数,已经是第一个的3倍了,更不提每个方法的效率比第一个还慢多少。
当然,第二段的灵活性可能是高很多,但是这样的灵活性真的需要嘛?在大部分系统的大部分区域,我们需要大量的在EJB,JMS 或者 WEB SERVICE 里面切换嘛?
我们公司的答案不是,所以这个也是我们到现在还不普遍使用spring,而是部分使用spring的原因,也是spring的好处。系统小部分的灵活性需要非常高的部分,我们才利用spring的beanfactory功能,事务控制要求严格部分,才使用它的事务管理功能。但是绝大部分,我们不使用。可以说是刚柔并济吧,不灵活的部分是刚,灵活部分是柔,系统如果全部是柔的话,那就软绵绵无力了,如果全部是刚的话,那么就太脆而易断,作为一个真正实用的系统,刚柔还是按80/20原则的好。
引用
UserManager userManager = new UserManager();
String userIDRetured = userManager.addUser("John Smith")
引用
ServiceRequest bsr = this.getApplicationContext().getBean("businessServiceRequest");
bsr.setServiceName("User Services");
bsr.setOperation("addUser");
bsr.addRequestInput("param1", "addUser");
String userIDRetured = (String) bsr.service();
gigix:
andyyehoo 写道:
比较一下下面的两段代码,说真的,虽然说Java效率低一点可以原谅,不过比较一下这两段代码的效率,真是..............虽然java效率比C低n个等级大家都接受了,可是不意味着就可以把系统效率丢到爪哇国去了啊
第一个是直接new一个对象,接着调用一个方法。
第二个是首先getApplicationContext,这个过程就首先不知道耗费多少了。然后是间接的getBean,创建一个对象。接着通过调用3个比reflaction更低效率的方法,设置各个参数,最后是调用。
纯粹的比较方法数,已经是第一个的3倍了,更不提每个方法的效率比第一个还慢多少。
当然,第二段的灵活性可能是高很多,但是这样的灵活性真的需要嘛?在大部分系统的大部分区域,我们需要大量的在EJB,JMS 或者 WEB SERVICE 里面切换嘛?
你讲这么大一通,我说你纯粹扯淡。只要addUser方法里面访问一次数据库,你所有那些性能考量全都是白费。哪怕你节约一万次对象创建和方法调用,连接数据库的网络开销就足以让你的整个努力化为乌有。你也知道80/20原则,按照80/20原则,J2EE应用根本就不应该考虑性能问题,除非涉及到RPC和I/O操作。你在内存里优化得再好,如果由于架构上的原因多一次RPC调用,整个系统的性能立马就掉下来了。与其追求这种毫无价值的、微秒级的性能提升,我宁可追求全面的灵活性。
andyyehoo:
gigix 写道:
你讲这么大一通,我说你纯粹扯淡。只要addUser方法里面访问一次数据库,你所有那些性能考量全都是白费。哪怕你节约一万次对象创建和方法调用,连接数据库的网络开销就足以让你的整个努力化为乌有。你也知道80/20原则,按照80/20原则,J2EE应用根本就不应该考虑性能问题,除非涉及到RPC和I/O操作。你在内存里优化得再好,如果由于架构上的原因多一次RPC调用,整个系统的性能立马就掉下来了。与其追求这种毫无价值的、微秒级的性能提升,我宁可追求全面的灵活性。
addUser调用数据库的时间,大家都是一样的,为什么我不能考虑这里调优?
这样写,并不会多出一次数据库或者RPC的调用。除非是很复杂的部分,那么我会考虑局部使用。对于系统80%的代码,简单化处理是不会带来任何问题的。
J2EE应用根本就不应该考虑性能问题?那我所有字符串连接都用+好不好?我做一步catch一次exception好不好?我所有Java方法的调用都通过reflection进行好不好?“根本”这个词用得太过了。
"我宁可追求全面的灵活性",这个正是问题所在,过分的追求灵活性,将降低效率,我们必须在灵活性和效率中间取得平衡点。xxx说了“添加多一个中间层,可以解决大部分的问题”。中间层越多,当然灵活性约好,但是效率是低了。其实当然,效率这个东西是两头大,中间小的一个东西,最耗费时间的,往往是一开始的调用(用户点击传到处理层)和最后的调用(调用数据库,WEB service),但是这并不意味着,我们就可以无节制的,忽略中间的效率。
gigix:
andyyehoo 写道
addUser调用数据库的时间,大家都是一样的,为什么我不能考虑这里调优?
这样写,并不会多出一次数据库或者RPC的调用。除非是很复杂的部分,那么我会考虑局部使用。对于系统80%的代码,简单化处理是不会带来任何问题的。
你是真不明白呢还是故意抬杠?一次数据库操作或者RPC的速度是十毫秒级的,通常一个J2EE业务操作包括几次网络传输和几次数据库操作,也就是说在最理想的情况下一个业务操作的速度是百毫秒级甚至秒级的。我请问你,你要节省多少次对象创建、多少次方法调用才能把响应时间提升100毫秒?有个成语可以贴切地形容这种优化:杯水车薪。
andyyehoo 写道
J2EE应用根本就不应该考虑性能问题?那我所有字符串连接都用+好不好?我做一步catch一次exception好不好?我所有Java方法的调用都通过reflection进行好不好?“根本”这个词用得太过了。
你还真说对了。我所有字符串连接都是用+;我的业务对象外面有动态代理提供的AOP,也就是说所有方法调用都是通过reflection进行的;我的动态代理里面对异常全部做了包装,也就是说每个方法调用都有try...catch...的包裹。我得到的效果是什么?更清晰的代码,更优雅的架构,以及,更容易找到系统的性能瓶颈,更容易优化性能。有些事情也许你没有听说过,但不代表它不是真的。
andyyehoo 写道
"我宁可追求全面的灵活性",这个正是问题所在,过分的追求灵活性,将降低效率,我们必须在灵活性和效率中间取得平衡点。xxx说了“添加多一个中间层,可以解决大部分的问题”。中间层越多,当然灵活性约好,但是效率是低了。其实当然,效率这个东西是两头大,中间小的一个东西,最耗费时间的,往往是一开始的调用(用户点击传到处理层)和最后的调用(调用数据库,WEB service),但是这并不意味着,我们就可以无节制的,忽略中间的效率。
同样一个问题,我换另一个角度来问你:你要做多少次字符串连接,才能浪费100毫秒时间?你可以自己写个程序,对比一下StringBuffer.append和String.+的性能差距,看看需要多大的字符串才能让你损失100毫秒。如果你能告诉我这个结果,我一定很有兴趣知道。别忘了,100毫秒仅仅是一次普通J2EE业务操作整体响应时间的数十分之一而已。
andyyehoo:
引用:
你还真说对了。我所有字符串连接都是用+;我的业务对象外面有动态代理提供的AOP,也就是说所有方法调用都是通过reflection进行的;我的动态代理里面对异常全部做了包装,也就是说每个方法调用都有try...catch...的包裹。我得到的效果是什么?更清晰的代码,更优雅的架构,以及,更容易找到系统的性能瓶颈,更容易优化性能。有些事情也许你没有听说过,但不代表它不是真的。
lol: 我相信你的系统是这样的,但是不代表所有的系统都需要象你这样。对于很多中小型系统来说,如此优雅的架构并不都是必须的。
而且,你这样对开发的效率有影响,代码量又多啦,呵呵,对开发人员总体素质的要求也高了不少,公司的成本又高囖。 这些都是需要考虑的。:evil:
当然,我承认后一种方法的先进性和灵活性,但是,还是那个问题,不需要拿牛的杀鸡,而现在的市场,鸡还是比牛多一些。
gigix:这也是你的想当然。如果采用一个优雅的架构,普通程序员只需要编写面向对象的程序就足够了。他不需要考虑如何管理事务,他不需要考虑如何记录日志,他甚至不需要考虑如何获得和关闭数据库连接,而且他写的每个模块都可以从系统中摘出来单独测试。难道开发这样的程序会更慢、写更多的代码、对开发人员要求更高?相反,如果做太多代码级的优化,势必损害架构的优雅和灵活,会导致更多的重复代码,会使得各个模块耦合紧密而不能独立测试,那样的系统才是代码量更多、对开发者要求更高的。
我只举一个最简单的例子。你认为如果我们需要一个UserManager,那么就直接new UserManager()好了。但是这样一来,开发client代码的人就无法只测试他自己的业务逻辑,他的单元测试还必须同时兼顾UserManager的逻辑。我请问你,这是不是比写一个mock来测试自己这一个模块有更高的难度?一旦UserManager修改了实现,它的作者必须与所有使用者沟通,以保证这些人的单元测试不会失败,这是不是增加了工作量降低了开发效率?如果client代码能够这样写:
[code:1]
public class MyClass {
private UserManager _um;
public void setUserManager(UserManager um) {
_um = um;
}
public void doSomething() {
_um.doSomething();
}
}
[/code:1]
编写client的人不必考虑该创建UserManager的哪个实现类,也不必考虑如何创建,也不必关心这个对象的生命周期,也不用管它是本地对象还是RPC stub。难道这样写程序不是更轻松、代码量更少、对程序员的要求更低吗?
andyyehoo:
gigix写道:
这也是你的想当然。如果采用一个优雅的架构,普通程序员只需要编写面向对象的程序就足够了。他不需要考虑如何管理事务,他不需要考虑如何记录日志,他甚至不需要考虑如何获得和关闭数据库连接,而且他写的每个模块都可以从系统中摘出来单独测试。难道开发这样的程序会更慢、写更多的代码、对开发人员要求更高?相反,如果做太多代码级的优化,势必损害架构的优雅和灵活,会导致更多的重复代码,会使得各个模块耦合紧密而不能独立测试,那样的系统才是代码量更多、对开发者要求更高的。
在正规公司里面,分工明确的话,都是专人写好架构,普通程序员按照架构往里面填代码就是的啦。正常情况下,他也是不需要如何管理事务,记录日志,获得和关闭连接,每个模块也可以单独测试。
但是,程序调试出错的时候,他们也需要自己查看日志,考虑一下各方各面的因素才能调试,按照第二种写法,无疑,这些程序员的素质要相对高一些,考虑的问题更多一些,才能进行调试的。
gigix写道:
我只举一个最简单的例子。你认为如果我们需要一个UserManager,那么就直接new UserManager()好了。
这个是例子这么写的,需要灵活的部分,我们自然会用其它方法写。不过在最简单的情况中,我们是会这么写,更简单的情况,直接还调用静态方法,不会不给吧,呵呵
gigix:
andyyehoo 写道
这个是例子这么写的,需要灵活的部分,我们自然会用其它方法写。不过在最简单的情况中,我们是会这么写,更简单的情况,直接还调用静态方法,不会不给吧,呵呵 :lol:
别的不多说,就说这一件事好了。我要求所有程序员严格遵循“针对接口编程”的原则,每个组件必须提供一个接口和一个实现,获得组件必须以接口的形式、通过dependency injection获得。而按照你的说法,你要求程序员在提供功能时有时针对接口编程,有时针对对象编程,有时静态方法实现,也就是说你要求程序员清楚这三种设计的语义区别和利弊权衡。我想请问你,究竟是谁对程序员的要求更高呢?
andyyehoo:
引用
别的不多说,就说这一件事好了。我要求所有程序员严格遵循“针对接口编程”的原则,每个组件必须提供一个接口和一个实现,获得组件必须以接口的形式、通过dependency injection获得。
佩服佩服,没有程序员抗议嘛?
引用
有时针对接口编程,有时针对对象编程,有时静态方法实现,也就是说你要求程序员清楚这三种设计的语义区别和利弊权衡。
我们现在是这样,不过,这个好像是JAVA程序员的基本功吧,虽然现在很多程序员基本功不好,那样的话,还是我们要求高点,按照你那样写的话,都快可以机器产生代码了,呵呵,可以考虑开始向自动产生代码发展了。
不过嘛,还是那个问题,出了bug,你们调试还是比较困难点吧?
gigix:
andyyehoo 写道
引用
别的不多说,就说这一件事好了。我要求所有程序员严格遵循“针对接口编程”的原则,每个组件必须提供一个接口和一个实现,获得组件必须以接口的形式、通过dependency injection获得。 |
佩服佩服,没有程序员抗议嘛?
引用
有时针对接口编程,有时针对对象编程,有时静态方法实现,也就是说你要求程序员清楚这三种设计的语义区别和利弊权衡。 |
我们现在是这样,不过,这个好像是JAVA程序员的基本功吧,虽然现在很多程序员基本功不好,那样的话,还是我们要求高点,按照你那样写的话,都快可以机器产生代码了,呵呵,可以考虑开始向自动产生代码发展了。
不过嘛,还是那个问题,出了bug,你们调试还是比较困难点吧?
对象怎么创建、对象的生命周期怎么管理,这些都是跟业务没关系的infrastructure。让程序员可以不操心这些infrastructure,一心关注自己的业务逻辑,怎么会有人抗议?
你说“调试比较困难”,我就真的很怀疑你究竟有多少经验了。任何一个有经验的J2EE开发者都会知道,OOD做得越好,debug越轻松。OOD做得好,你才可能做出完备的单元测试,然后用单元测试快速锁定debug的范围。我们调试比较困难吗?我真的不知道该怎么回答这个问题,因为我已经好久没开过debugger了。
andyyehoo:
引用
你说“调试比较困难”,我就真的很怀疑你究竟有多少经验了。任何一个有经验的J2EE开发者都会知道,OOD做得越好,debug越轻松。OOD做得好,你才可能做出完备的单元测试,然后用单元测试快速锁定debug的范围。我们调试比较困难吗?我真的不知道该怎么回答这个问题,因为我已经好久没开过debugger了。
所指的bug,是指需要在spring的配置,aop搭建的事务控制,日志中穿梭寻找的bug,不过这个对于你来说应该是很熟了,所以没什么感觉了,一样快速锁定了。应该就是良好的架构使这定位个过程很快的。反正有固定步法的话,走7步和走5步差不多吧,呵呵。
gigix:
andyyehoo 写道
引用
你说“调试比较困难”,我就真的很怀疑你究竟有多少经验了。任何一个有经验的J2EE开发者都会知道,OOD做得越好,debug越轻松。OOD做得好,你才可能做出完备的单元测试,然后用单元测试快速锁定debug的范围。我们调试比较困难吗?我真的不知道该怎么回答这个问题,因为我已经好久没开过debugger了。 |
所指的bug,是指需要在spring的配置,aop搭建的事务控制,日志中穿梭寻找的bug,不过这个对于你来说应该是很熟了,所以没什么感觉了,一样快速锁定了。应该就是良好的架构使这定位个过程很快的。反正有固定步法的话,走7步和走5步差不多吧,呵呵。
这些事情更不需要debug,因为它们都在冒烟测试的范围内。只要一开始测试通过,你做了一件事以后变得不通过了,马上就可以知道是你刚才的改动造成了破坏。这里没有5步、7步的调试,只有1步:回退你上一分钟做的修改。
说起来,好象你也开始赞成:OOD和良好的架构才是真正重要的,而不是20毫秒的性能提升。
andyyehoo:
引用
说起来,好象你也开始赞成:OOD和良好的架构才是真正重要的,而不是20毫秒的性能提升。
:lol: 我一直的观点是,OOD和良好的架构当然很重要的,但是要根据项目选择合适灵活的架构,而不必全部采用最灵活的系统,而在这个基础上,“20毫秒的性能提升”,也是需要考虑的事情之一,而不可以完全抛之脑后。
突然想到A计划2成龙说的,我不能接受任何人,以国家民族利益的崇高名义,草菅任何无辜市民的生命。(记不太清,大概)哈哈,有点象