??xml version="1.0" encoding="utf-8" standalone="yes"?>
enhanceInteractionOnElements();
});
function helper_methods() {
}
file = "#{params[:controller]}/#{params[:action]}.js"
File.exist?("#{RAILS_ROOT}/public/javascripts/#{file}") ? javascript_include_tag(file) : ""
end
this method will look for js file for a particular page. And in you layout file, add one line in the head sectin:
That's it. Whenever you request an action of a particular controller, it will find and include the PE js files automatically. Now we've very very primitive support of PE in Rails framework now.
]]>
Ok, let's start from the 'Hello World in Compiler Construction' —?Expression Evaluation
2
3 class ExpressionGrammar < Aurum::Grammar
4 tokens do
5 ignore string(' ').one_or_more # <= a
6 _number range(?0, ?9).one_or_more # <= b
7 end
8
9 precedences do # <= c
10 left '*', '/'
11 left '+', '-'
12 end
13
14 productions do # <= d
15 expression expression, '+', expression {expression.value = expression1.value + expression2.value} # <= e
16 expression expression, '-', expression {expression.value = expression1.value - expression2.value}
17 expression expression, '*', expression {expression.value = expression1.value * expression2.value}
18 expression expression, '/', expression {expression.value = expression1.value / expression2.value}
19 expression '(', expression, ')' do expression.value = expression1.value end # <= f
20 expression _number {expression.value = _number.value.to_i}
21 expression '+', _number {expression.value = _number.value.to_i}
22 expression '-', _number {expression.value = -_number.value.to_i}
23 end
24 end
If you has any experience with other compiler compiler/parser generator, you probably could understand what happens above quite easily. Instead of explaining things like token, character class, and production, I'd like to emphasise some Aurum conventions:
Now, let's find out how we could use this expression grammar. You could use the helper method as below(it will recalcuate lexical table and parsing table for every call, could be quite slow):
or use the lexical table and parsing table to create your own lexer & parser:
2 parser = Aurum::Engine::Parser.new(ExpressionGrammar.parsing_table(:expression))
3 puts parser.parse(lexer).value
At the end of this post, I'd like to give another grammar example coming from Martin Fowler's HelloParserGenerator series:
2
3 Item = Struct.new(:name)
4
5 class Catalog < Aurum::Grammar
6 tokens do
7 ignore enum(" \r\n").one_or_more
8 _item range(?a,?z).one_or_more
9 end
10
11 productions do
12 configuration configuration, item {configuration.value = configuration1.value.merge({item.value.name => item.value})}
13 configuration _ {configuration.value = {}}
14 item 'item', _item {item.value = Item.new(_item.value)}
15 end
16 end
17
18 config = Catalog.parse_configuration(<<EndOfDSL).value
19 item camera
20 item laser
21 EndOfDSL
22
23 puts config['camera'].name
P.S.:The post is based on the developing version of Aurum(0.2.0). You could get it from the svn repository.
P.S.P.S.: There is a more complicated example in the examples directory, a simple Smalltalk interpreter. Have fun:)
]]>
Aurum是一个用Ruby实现的LALR(n) parser generatorQ是的,又是一个parser generatorQ,不过它和其他一些广泛应用的parser generator相比略有不同的:
1.Aurum的主要目标之一Q是化external DSL的开发(其是ruby external DSLQ?br />
2.Aurum采用增量LALR(n)法Q而不是通常的LALR(1)。这意味着Q?br />
a.不必׃LALR(1)能力的限Ӟ而改写语法,很多在LALR(1)中冲H的语法在LALR(n)中可以比较自然地表达?br />
b.׃识别能力的增强,可以处理一些比较复杂的语法Q比如COBOL(LALR(2)或LALR(3))Q比如一些简化的自然语言(LALR(3+))?br />
c.处理能力接近Generalized LRQ却快很?br />
d.比vFull LALR/LR(n)Q增量算法生成的语法表更?br />
3.Z化external DSL实现的考虑QAurum支持语法重用?br />
4.Aurum采用Ruby internal DSL作ؓ语法声明的元语言Q可以利用Ruby丰富的测试框Ӟ有效地对~译Q解释/分析器进行测试?br />
5.正如名字所暗示的,AurumQGold的化学名Uͼ的一部分灉|来自GOLD parsing systemQ它支持独立于q_和语a的编译器开发?br />
好,闲话说Q看一个例子,~译原理中的Hello World —?表达式求|
2
3 class ExpressionGrammar < Aurum::Grammar
4 tokens do
5 ignore string(' ').one_or_more # <= a
6 _number range(?0, ?9).one_or_more # <= b
7 end
8
9 precedences do # <= c
10 left '*', '/'
11 left '+', '-'
12 end
13
14 productions do # <= d
15 expression expression, '+', expression {expression.value = expression1.value + expression2.value} # <= e
16 expression expression, '-', expression {expression.value = expression1.value - expression2.value}
17 expression expression, '*', expression {expression.value = expression1.value * expression2.value}
18 expression expression, '/', expression {expression.value = expression1.value / expression2.value}
19 expression '(', expression, ')' do expression.value = expression1.value end # <= f
20 expression _number {expression.value = _number.value.to_i}
21 expression '+', _number {expression.value = _number.value.to_i}
22 expression '-', _number {expression.value = -_number.value.to_i}
23 end
24 end
如果怽对之前有用过compiler compiler或者parser generator的话Q应该能看个七七八八吧。我大概解释一下:
a.q里定义了文法空白,也就是被lexer忽略的部分,在通常的语a中,是空格回车换行之cȝ字符Qstring是用于定义lexical pattern的helperҎQ出了string之外Q还有range, enum和concatQ;ignore是一个预定义的说明指令,表示若文本匹配给定模式则该文本会被lexer自动忽略Q其格式为:
ignore pattern {//lexical action}
b.此处为lexical token声明Q所有lexical token必须以_开_其格式ؓQ?br />
_token_name pattern {//lexical action}
q里其实是一个简略写法,{h?br />
match pattern, :recognize => Q_token_name
c.此处符优先U声明,支持?右结合运符Q无l合属性运符开发中Q;每一行中所有运符h相同优先U;比它下一行的q算W高一个优先。比如在q个例子中,'*'?/'h相同优先U,但是?+'?-'的优先别高?br />
d.此处法规则声明,所使用的symbol主要有三U,nonterminal(写字母开?Qterminal(其实是lexical tokenQ以_开?和literal(字符串常?Q其中所有literal都会被自动声明ؓ保留字?br />
e.此处定义了一条文法规则(加法Q,以及对应的semantic action。在semantic action中可以直接通过symbol的名字来获取值栈中的对象。如遇到同名symbolQ则按照出现序q行~号卛_?br />
f.其实q个没啥Q只不过׃我们使用的是Ruby DSLQ所以有时候不能都用{}Q需要do endQ这是一个例子?br />
最后测试一下实际中如何使用定义好的语法Q用helper methodQ注意由于分析表没有~存Q每ơ都会重语法表Q仅仅适用于debug mode。)
puts ExpressionGrammar.parse_expression('1+1').value
或者通过分析表自己构造lexer和parser
lexer = Aurum::Engine::Lexer.new(ExpressionGrammar.lexical_table, '1+1')
parser = Aurum::Engine::Parser.new(ExpressionGrammar.parsing_table(:expression))
puts parser.parse(lexer).value
最后最后,l另外一个例子,是Martin Fowler Blog上的HelloParserGeneratorpd中所用的语法Q?br />
2
3 Item = Struct.new(:name)
4
5 class Catalog < Aurum::Grammar
6 tokens do
7 ignore enum(" \r\n").one_or_more
8 _item range(?a,?z).one_or_more
9 end
10
11 productions do
12 configuration configuration, item {configuration.value = configuration1.value.merge({item.value.name => item.value})}
13 configuration _ {configuration.value = {}}
14 item 'item', _item {item.value = Item.new(_item.value)}
15 end
16 end
17
18 config = Catalog.parse_configuration(<<EndOfDSL).value
19 item camera
20 item laser
21 EndOfDSL
22
23 puts config['camera'].name
P.S.:本文是根据Aurum0.2.0写成的,你可以从rubyforge的svn上得到它?br />
P.S.P.S.: 在exmaples目录里有一个更复杂一些的例子Q是一个简单的Smalltalk解释器?br />
]]>
2 -export([start/2]).
3
4 start(N, M) ->
5 Pid = create_process(self(), N - 1, M),
6 time(fun() -> Pid ! start, loop(Pid, M) end).
7
8 time(Fun) ->
9 statistics(wall_clock),
10 Fun(),
11 {_,Time} = statistics(wall_clock),
12 io:format("Run : ~w s ~n", [Time/1000]).
13
14 create_process(Pid, 0, _) -> Pid;
15 create_process(Pid, N, M) -> create_process(spawn(fun() -> loop(Pid, M) end), N - 1, M).
16
17 loop(_, 0) -> void;
18 loop(Next, M) ->
19 receive
20 Message -> Next ! Message,
21 loop(Next, M - 1)
22 end.
23
24
有意思是它还有一个第二问Q让你用另外一U熟悉的语言实现同样的功能,发送同样多的消息,也把旉记录下来Q然后写一blog来publish你的l果。其实,大家心知肚明Q这Ulightweight process啊,message passing concurrency啊都是Erlang的强,而且实测l果也着实颇为恐怖,一般也没那闲心拿别的东西来陪衬一把了QArmstrong同学自己实现了一个Java versionQ效率大U能差到癑ր吧Q。不q还真有那写不信邪的老大Q?a >用stackless python实现了同Lring benchmarkQ发现比erlangq快...后来修改代码Lio操作QErlang倒是比stackless python快些Q但也只是一些而已?br>
]]>
应用Seleniumq行Web试往往会存在几个bad smellQ?br>1.大量使用name, id, xpath{页面元素。无论是功能修改、UI重构q是交互性改q都会媄响到q些元素Q这使得Selenium试变得非常脆弱?br>2.q于l节的页面操作不Ҏ体现为的意图Q一D|间之后就很难真正把握试原有的目的了Q这使得Selenium试变得难于l护?br>3.对具体数据取值的存在依赖Q当个别数据不再合法的时候,试׃p|Q但q样的失败ƈ不能标识功能的缺失,q得Selenium试变得脆弱且难以维护?br>
而这几点直接衍生的结果就是不断地d新的试Q而极地去重构、利用原有测试。其实这C是正常,单元试试写多了,也有会有q样的问题。不q比较要命的是,Selenium的执行速度比较慢(相对单元试Q,随着试逐渐的增多,q行旉会逐渐增加C可忍受的E度。一l意图不明难以维护的Selenium试Q可以很L地在每次build的时候杀?0分钟甚至2个小时的旉Q在下就有花2个小时坐在电脑前面等?50个Selenium试q行通过的悲惨经历。因此合理有效地规划Selenium试显得格外的q切和重要了。而目前比较行之有效的办法Q往大了_可以叫domain based web testingQ具体来Ԍ是Page Object Pattern?br>
Page Object Pattern里有四个基本概念QDriver, Page, Navigator和Shortcut。Driver是测试真正的实现机制Q比如SeleniumQ比如WatirQ比如HttpUnit。它们懂得如何去真正执行一个web行ؓQ通常包含像clickQselectQtypeq样的表C具体行为的ҎQPage是对一个具体页面的装Q它们了解页面的l构Q知道诸如idQ?nameQ?classQxpathq类实现l节Qƈ描述用户可以在其上进行何U操作;Navigator则代表了URLQ表CZ些不l页面操作的直接跌{Q最后Shortcut是helperҎ了,需要看具体的需要了。下面来看一个超U简单的例子——测试登录页面?br>
1. Page Object
假设我们使用一个单独的Login Pageq行dQ那么我们可能会登录的操作装在一个名为LoginPage的page object里:
2 def initialize driver
3 @driver = driver
4 end
5
6 def login_as user
7 @driver.type 'id=', user[:name]
8 @driver.type 'xpath=', user[:password]
9 @driver.click 'name='
10 @driver.wait_for_page_to_load
11 end
12 end
login_as是一个具有业务含义的面行ؓ。在login_asҎ中,page object负责通过依靠idQxpathQname{信息完成登录操作。在试中,我们可以q样来用这个page objectQ?br>
2 page.login_as :name => 'xxx', :password => 'xxx'
3
不过既然用了rubyQ总要用一些ruby sugar吧,我们定义一个onҎ来表N面操作的环境Q?br>
2 page = page_type.new $selenium
3 page.instance_eval &block if block_given?
4 end
之后我们可以用page object的类名常量和block描述在某个特定页面上操作了:
2 login_as :name => 'xxx', :password => 'xxx'
3 end
4
除了行ؓҎ之外Q我们还需要在page object上定义一些获取页面信息的ҎQ比如获取登录页面的Ƣ迎词的ҎQ?br>
@driver.get_text 'xpath='
end
q样试也可表达得更生动一些:
2 assert_equal 'Welcome!', welcome_message
3 login_as :name => 'xxx', :password => 'xxx'
4 end
当你把所有的面都用Page Object装了之后,有效地分离了测试和面l构的耦合。在试中,只需使用诸如login_as, add_product_to_cartq样的业务行为,而不必依靠像idQnameq些具体且易变的面元素了。当q些面元素发生变化Ӟ只需修改相应的page object可以了Q而原有测试基本不需要太大或太多的改动?br>
2. Assertation
只有行ؓq够不成试Q我们还要判断行为结果,q进行一些断a。简单回一下上面的例子Q会发现q有一些很重要的问题没有解冻I我怎么判断d成功了呢Q我如何才能知道真的是处在登录页面了呢?如果我调用下面的代码会怎样呢?
2 on LoginPage {}
因此我们q需要向page object增加一些断a性方法。至,每个面都应该有一个方法用于判断是否真正地辑ֈ了这个页面,如果不处在这个页面中的话Q就不能q行M的业务行为。下面修改LoginPage使之包含q样一个方法:
2 include Test::Unit::Asseration
3 def visible?
4 @driver.is_text_present() && @driver.get_location ==
5 end
6 end
在visible?Ҏ中,我们通过对一些特定的面元素Q比如URL地址Q特定的UIl构或元素)q行判断Q从而可以得之是否真正地处在某个面上。而我们目前表达测试的基本l构是由onҎ来完成,我们也就理成章地在onҎ中增加一个断aQ来判断是否真的处在某个面上,如果不处在这个页面则不进行Q何的业务操作Q?br>
2 page = page_type.new $selenium
3 assert page.visible?, "not on #{page_type}"
4 page.instance_eval &block if block_given?
5 page
6 end
7
q个Ҏ秘地返回了page对象Q这里是一个比较tricky的技巧。实际上Q我们只惛_用page != nilq个事实来断a面的流转,比如Q下面的代码描述d成功的页面流转过E:
assert_equal 'Welcome!', welcome_message
login_as :name => 'xxx', :password => 'xxx'
end
assert on WelcomeRegisteredUserPage
除了q个基本断言之外Q我们还可以定义一些业务相关的断言Q比如在购物车页面里Q我们可以定义一个判断购物R是否为空的断aQ?br>
2 @driver.get_text('xpath=') == 'Shopping Cart(0)'
3 end
需要注意的是,虽然我们在page object里引入了Test::Unit::Asseration模块Q但是ƈ没有在断aҎ里用Q何assert*Ҏ。这是因为,概念上来讲page objectq不是测试。之包含一些真正的断言Q一则概忉|乱,二则Ҏ使page object变成针对某些场景的test helperQ不利于以后试的维护,因此我们往往們于将断言Ҏ实现Z个普通的q回gؓboolean的方法?br>
3. Test Data
试意图的体C仅仅是在行ؓ的描qCQ同栯有测试数据,比如如下两段代码Q?br>
2 login_as :name => 'userA', :password => 'password'
3 end
4 assert on WelcomeRegisteredUserPage
5
6 registered_user = {:name => 'userA', :password => 'password'}
7 on LoginPage do
8 login_as registered_user
9 end
10 assert on WelcomeRegisteredUserPage
试的是同一个东西,但是昄W二个测试更好的体现了测试意图:使用一个已注册的用L录,应该q入Ƣ迎面。我们看q个试的时候,往往不会兛_用户名啊密码啊具体是什么,我们兛_它们表达了怎样的测试案例。我们可以通过DataFixture来实现这一点:
2 USER_A = {:name => 'userA', :password => 'password'}
3 USER_B = {:name => 'userB', :password => 'password'}
4
5 def get_user identifier
6 case identifier
7 when :registered then return USER_A
8 when :not_registered then return USER_B
9 end
10 end
11 end
在这里,我们测试案例和具体数据做了一个对应:userA是注册过的用P而userB是没注册的用戗当有一天,我们需要将d用户名改为邮q时候,只需要修改DataFixture模块可以了Q而不必修改相应的试Q?br>
2
3 user = get_user :registered
4 on LoginPage do
5 login_as user
6 end
7 assert on WelcomeRegisteredUserPage
当然Q在更复杂的试中,DataFixture同样可以使用真实的数据库或是Rails Fixture来完成这L对应Q但是M的目的就是ɋ试和测试数据有效性的耦合分离Q?br>
2 case identifier
3 when :registered then return User.find '.'
4 end
5 end
4.Navigator
与界面元素类|URL也是一cL变且难以表达意图的元素,因此我们可以使用Navigator使之与测试解耦。具体做法和Test Data怼Q这里就不赘qCQ下面是一个例子:
2 on ProductDetailPage do
3 .
4 end
5. Shortcut
前面我们已经有了一个很好的基础Q将Selenium试与各U脆׃意图不明的元素分d了,那么最后shortcut不过是在蛋糕上面最漂亮的奶油Ş了——定义具有漂亮语法的helperQ?br>
2 on LoginPage do
3 assert_equal 'Welcome!', welcome_message
4 login_as user
5 end
6 assert on WelcomeRegisteredUserPage
7 end
然后是另外一个magicҎQ?br>
2 words = identifier.to_s.split '_'
3 eval "get_#{words.last} :#{words[0..-2].join '_'}"
4 end
之前的测试就可以被改写ؓQ?br>
should_login_successfully given :registered_user
end
q是一U结论性的shortcut描述Q我们还可以有更behaviour的写法:
2 on page_type do
3 assert_equal 'Welcome!', welcome_message
4 login_as @user
5 end
6 end
7
8 def login_successfully
9 on WelcomeRegisteredUserPage
10 end
11
12 def given identifer
13 words = identifier.to_s.split '_'
14 eval "@#{words.last} = get_#{words.last} :#{words[0..-2].join '_'}"
15 end
最后,试׃变成cM验收条g的样子:
2 given :registered_user
3 login_on LoginPage
4 assert login_successfully
5 end
Mshortcut是一个无兛_坏,只关乎想象力的东西,情挥洒Ruby DSL?D
l论
Selenium是一个让人又爱又恨的东西Q错误地使用Selenium会给整个敏捷团队的开发节奏带来灾难性的影响。不q值得庆幸的是正确C用Selenium的原则也是相当的单:
1.通过脆弱易变的面元素和测试分dQ得页面的变化不会Ҏ试生太大的影响?br>2.明确指定试数据的意图,不在试用用Q何具体的数据?br>3.一切可能,明确地表辑և试的意图,使测试易于理解?br>
当然Q除了遵循这几个基本原则之外Q用page object或其他domain based web testing技术是个不错的选择。它们将会帮助你更容易地控制Selenium试的规模,更好地^衡覆盖率和执行效率,从而更加有效地交付高质量的Web目?br>
鸣谢
此文中涉及的都是我最q三周以来对Selenium试q行重构时所采用的真实技术。感谢Nick Drew帮助我清晰地划分了Driver, Page, Nagivator和Shortcut的层ơ关p,它们构成我整个实늚基石Q感谢Chris LeishmanQ在和他pairing programming的过E中Q他帮助我锤gRuby DSLQ还有Mark Ryall和AbhiQ是他们W一ơ在目中引入了Test Data FixtureQ得所有h的工作都变得单v来?br>
]]>
Which Programming Language are You?
p.s. q个可能不准...因ؓ李默同学竟然是Lisp...怎么可能...
]]>
1. IEC61970 Metadata: Electricity Power Trading System
当时刚上班,team里有一个Doamin知识很厉害的清华的博士,毕业的论文就是电力市场,而清华又是国家引入IEC61970的五家之一。所以他很超前的把这两个东西l合在一P做成了一个系l。说实话Q刚了解IEC61970的时候,我是相当的震撼的Q有赶上那时候MDA风气刚vQIEC61970又是同时MOF(Meta Object Facility)和RDF basedQ华丽得不行。一下子我就变成了一个MDA guyQ一个metadata guy...以至于,在BJUG最初的2q里QMDA/MOF/Metadata成ؓ了主旋律...
2. IEC61970 & CWM(Common Warehouse Metamodel) & Office Plugin : Data Warehouse Integration System
q是q今为止Q我最不愿意回忆的一个项?..因ؓOffice Plugin...动辄蓝屏的遭遇让我心有余?..q是一个backend是J2EEQfrontend?Net的office插gpȝQ主要是报表...两边都用CWM作ؓ数据l一的Ş?..基本上做C半我的意志就崩溃?..
3. DB Migration/Refactoring : Jyxpearl
q个目...是李默同学的U房最爱,从大学一直做了很久,改版无数?..当时没有q么行的好词,什么DB Migration啊,DB Refactoring啊,那时候我们统U导数据...我导了好多会...基本上线一回导一?..时至今日...李默同学L不无得意的说Q你看,你DB Migration的能力就是我培养?..
4. JMI(Java Metadata Interface) & Eclipse RCP : Multi/Rich Client ERP Product
q个team其实挺华丽的Q老栾的品经理,李默是开发经理,资深行业专家(人家实际做过生U长QMRPIIQERP都是人家玩剩下的)老齐做需求,俺是ArchitectQ还有动物园里的猪Senior DevQ我认识Z工能力W一交互设计能力W一的米c_做UI和交互。由于当时看了netbeans和sun的官方JMI实现得太玩具。我们决定从自己的JMI实现开始,pȝl构要求多客LQwebQrcp都要...所以是轻http协议的b/sQc/s。结构还是不错的Q过E李默和我当然是敏捷了。似乎一起都完美的时候,是要坏菜的时?..企业事业部解散了...
5. Java Communication & Eclipse RCP : IC Card Reader
上面那个目解散之后Q我跟李默赋闲在Ӟ有不忍心打扰政府Q自谋生路找的项?..q个目要用IC卡读卡器Qؓ了锻炼我们的Eclipse RCP能力Q我们决定用eclipse rcp来做。于是问题就出来?..IC卡怎么办?google一把发现天无绝Z?..Java有一个Communication包,可以q接serial port...不过当时tricky的是...我的本子没有串口Q我们买了一个串口到usb的{换器...发现Ҏ不能?..于是只好跑到李默家用他华丽的台式机(q厮当年誓言旦旦的说Qlaptop太慢Q一定要用台式机Q东借西借搞了个2G RAM SATAQL意,q是伏笔Q的机器Q。我当时p得,Java的这个东西基本就是充数的Q貌似完全没有h用过Q文档啥的都特少...只能自己摸烦。在l历了无数次p|之后Q终于成功了。在showcase那天的上午,我最后实验了d什么的Q都没问题。兴高采烈的把jar拷到优盘上,刚插到usb口上...只见一道闪?..机器黑了...据李默后来分析是L烧了...我说没事Q拿上硬盘,土一点也不媄响showcase。李默说...q个...SATA?..q不行?..我绿...此后很长旉Q我都怀疑是我跟李默同学范冲Q超U项目杀?..
6. RDF, Semantic Web, SparQL : Ontology-Relationship DB Mapping
q是在一家公司做产品Q当时我元数?MDA领域颇有U篏...跟这家公司做得类|p来负责研发本体到关系数据库的映射...兼带在D2RQ的基上实C个SparQL查询语言。怎么?..听上d华丽?..到现在我都认为,q个目是我最有潜力的牛皮Q不定那天web x.0了,我也老了Q我可以拉着朋友的手去吹牛b?05q我做semantic web,O/R mapping知道不?Ontology啊,你们啊,sometime too simple"...不过估计q一天还早得很呢
7. Agile Domain Specified Language : Goodhope
q个也是李默同学有䆾的项?..话里的敏捷DSL实践...不过说实话,也有点X...
]]>
Customer collaboration over Contract negotiation
敏捷软g开发,是要以一U更合理的共赢的合作关系Q代替以前畸形的采购式的合约关系。ؓ什么合U关pd是畸形的Q我们来看看合约双方的处境?br />
首先软g团队斚w承担了过多的风险Q业务变化,改代码!Q商业抉择{换,改代码!Q凭啥你甲方的缘故非要我承担额外的成本?你说我冤不冤Q冤Q但是h家甲方也冤!Qh家花了大把的银子Q拿C堆不能用的YӞ你要是硬件h家还能{手卖炚wQ,像你要砍树别hl你把铲子,你要U树人家l了你把锯。搁你,你也不愿意。且不说博弈Q就双斚w有心把事情做好,按合同来Q甲方不qԌ不按合同来,乙方不干Q最后变成“有心杀贼无力回天”,大家一h扯皮{二期算了。lose-loseQ没有赢家?br />
那么合作的关pL什么呢Q合作的关系好比你去subwayC明治Q面包你自己选,要什么肉你来挑,蔬菜QcheeseQ酱汁你也自q着办。技术我来,口味你选。技术失败我负责Q口味不合适你负责。你做你的强Ҏ来我的强,最l大安高兴兴嘻d哈不吵不闹,作出一可口午。这是时候,生关系变了Q我不是你的冷冰冰的供应商,你也不是我邪恶的客户Q我们是拴在一根子上的蚂蚱。成功是我们的,p|也是我们的。荣׃共,携手q肩。听着有点耳熟Q没错,SaaS。敏捷宣a早就说了QCoC啊。从供应商变成服务商Q从服务商变成战略合作伙_q是在给软g企业指出路,新的生关系已经在其中了?br />
如果看不清敏Lq个Ҏ革命点,以ؓq是开发方法的打闹Q那么敏h本实施不成。这话一般我不敢说的Q程序员自发实施敏捷Q只在一U情况下可能成功Q大企业的IT部门。再赶上个强力的IT领导Q自家h嘛,有什么不好谈的。一来二去,成功了Q看看C3Q说白了不就是IT部门和业务部门?Q但是,如果是做目的公司,你营销手段不改变,敏捷׃可能成功。你的客戯你不是合作关p,你通过敏捷增加质量Q符合性质量)的工作就不会被h可,那么׃能成为投资,只能是成本。当成本增加C可承担的时候,敏捷׃了了之了。ؓ什么好多h说老板没有响应Q旧的生产关pM敏捷Ҏ是负担?br />
说道q里Q说一下以敏捷d的ThoughtWorks。其实很多h都以为ThougtWorks只有Ҏ论咨询,没错我们是有Ҏ论咨询,但是也有业务模式咨询Q客户业务模式不改变Q他怎么能彻底敏Pq点大家不可不查啊?img src ="http://www.aygfsteel.com/raimundox/aggbug/107375.html" width = "1" height = "1" />
]]>
#!/usr/local/bin/ruby
require 'rss/1.0'
require 'rss/2.0'
require 'open-uri'
require 'rubygems'
require 'blinkenlights'
SUCCESS = 'success'
def read_rss source='http://cruisecontrolrb.thoughtworks.com/projects/CruiseControl.rss'
content = ''
open(source) do |s| content = s.read end
rss = RSS::Parser.parse content, false
rss.items[0].title.include?(SUCCESS) ? all_ok : alarm
end
def all_ok times = 50
BlinkenLights.open { |lights| times.times {lights.random} }
end
def alarm times = 50, invertal = 0.0
BlinkenLights.open { |lights| times.times {lights.flash invertal} }
end
while true
read_rss
sleep 5
end
make sure to have sufficient permissions to access the device, or you could simple run it as super user.
]]>
I - Independent
N - Negotiable
V - Valuable
E - Estimable
S - Small
T - Testable
我个得,q个ȝ虽好Q但不免分散注意。要我说Q想把握好User StoryQ只用把握两个就够了Negotiable和Valuable。那么首先要定什么是Negotiable的。User Story有一个流传广泛的书写形式Q?br />
As <role>, I'd like to <action>, so that <benifit/value/goal>.
Z更好的获取storyq有很多最佛_践,比如personas, 比如business process modelingQ其实这些全是糖衣炮弹,As, I'd like to都是噱头Q就是ؓ了把用户忽悠晕了Q然后图I匕现直取商业h值和目标。一旦商业h值确定下来,role, action都是可以negotiable。比如李默之前在文章里D的用L录的例子Q输不输用户明密码?可以商量嘛!是不是只有注册用户可以n受个性服务?可以商量嘛!关键是用h要什么,至于怎么实现q些到头来都是可以商量的Q都是Negotiable。只有客L商业价值是不能商量的,也没的商量。h值没有了Q目标不存在了,q个User Story也就没用了,商量啥?重写一张就好了?br />
因此user story又有另外一个名Uͼ叫requirement placeholder。就是客户h值的"立此存照"。至于具体需求,那么到iteration plan meeting上是商量吧,看看当时什么样的Ş式(功能Q才是最W合用户需要。到此,其实大家可以看出来了Quser story重点׃再How上,而是在Why上的。有了whyQ且可NegotiableQ把握了_Q你是按用例来写需求又有何妨涅Q?br />
有了valuable和negotiable的想法垫底,在看看基于user story的初步计划制定——也是有名的prioritization——就Ҏ理解多了。用h据每张卡的h|自行比较作出军_Q大体场景就跟向仙许愿一栗?br />
仙Q我可以满你一个愿望?br />我:我要荣华富贵Q!Q?br />仙Q哦Q荣华富贵,那么要不要爱情涅Q?br />我:恩,q个...那我要忠贞的爱情好了Q!
仙Q哦Q忠贞的爱情Q那么要不要健康q_呢?
我:?...
repeat 无数ơ,最l我要了一件过冬的皮猴...
]]>
]]>
上图是著名的Ron Jefferies ModelQ可以看到XP最佛_践被划分成了一个一个的圆圈Q而pair, TDD, refactor和simple design位于中心。这q不是说q四个实践就是xp的核心。jefferies model每一圈代表了xp实践q程中的不同x点,最中心的是dev视角Q其ơ是team视角Q最外层是交付/理视角。每圈上的最x间多都有些紧耦合Q放开其他的不Ԍ我们专门说说dev圈,pair programing, tdd, refactor和simple design?br />
q四个实践里只有simple design最虚也最重要。有一个问题已l被问过无数ơ了Q“到底多simple的design才叫simple”。我Ҏ也有一个近乎刻板的回答Qteam里所有h员都能够理解的design是simple的。一旦立了标准,q四个实늚M关系׃下子清晰h——simple design是这四个实践的核心,其他三个实践都是它服务的?br />
首先做出一个设计,最单的判断标准是是否可测Q一个不可测的设计基本上可以认ؓ无法实现Q于是TDDxsimple design的质量保证又是simple design的直觉验证?br />
refactor是ؓ了得到好的代码,那么什么是好的代码Qsimple design!!!q里有h不同意了Q有只是要易于修改和扩展Q可是扩展和修改也要别h看得懂才行啊...simple design是v码的要求嘛。实际上QXP中的refactor是朝着simple design的方向重构过ȝQ也是朝着所有h都能理解的代码refactorq去的。插一句题外话Qؓ啥说好的架构的不是设计出来的呢?因ؓ好的架构臛_应该是simple design的,而simple的概忉|和h员相?..所以当你极能事show off你的pattern知识之后Q得到复杂设计根本就不可能是好的架构。时ȝ讎ͼ架构是妥协啊...
最后,pair programming是simple design的实际检验!Q!因ؓ即便是最复杂的设计,只要是你自己惛_来的Q你都觉得它单无比,里面充满了直白且显而易见的理由。可惜不q的是,我们要的单,是对team里所有h的简单。如果你的pair不能理解你的设计Q那么说明你的设计复杂了;如果你们两个人懂Q但是swith pair的时候,换过来的Z懂,说明你的设计复杂了。pair programming(以及他那Ҏ让h忽略的子实践switching pair)是验simple design的过E。pair programing + refactor是时刻保证simple design防止q渡设计反攻倒算的过E。pair programming + refactor + tdd是团结在以Deming同学built quality in的质量大旗下Q坚定地与过渡设计做斗争的过E。据我观察,x有用pair programming的团队中Q少一半simple design成了口号Q而这一半中Q至又有一半最l放弃了xp攑ּ了敏PZ前带q的团队有q样?..默哀一下)。深ȝ教训啊,我们来高g下:"pair programming是检验simple design的唯一标准Q??br />
最后说一下pair programmingl济学,q多的假设我׃讲了。单说一点,有哪一位上班的8时从来不上msn/yahoo/qq{im?有哪一位上班从来不上论?不回?不发邮g?以我pair的经验来看,pair programming的过E中Q两个h几乎不会用imQ几乎不会逛论坛。你不好意思呀Q毕竟不是你一个h的机器,毕竟是两个h的时_毕竟你也不愿意给同事一U懒散的印象吧?收回的这么浪费的旉Q至顶得过另外一个h的工作时间了吧?
]]>
W合性质?br />20世纪40q代Q符合性质量概念以W合现行标准的程度作量依据,“符合标准”就是合格的产品质量Q符合的E度反映了品质量的水^。比如说我做一个杯子,没什么特别的要求Q也不是我神l质的艺术作品,是普普通通的一个杯子,那么需要高矮长短,大小胖瘦Q等{一q质量属性,我做好了可以拿着质量标准来对比,一眼就可以看出那里Z什么问题。通过是否W合q些标准判断产品h相应的质量?br />那么软g的质量理是不是符合性质量呢Q我个h觉得不属于。虽然我们一样可以拿出各U各L标准Q比如故障率Q比如bug数等{。但是这些标注都满不一定是好的软gQ比如我写一个helloworldQ虽然他可以没有bug。但是却发挥不了M的作用。这L软g属于“高质量”的废品。正如n辛梅评h斚w`渐,“你不讨厌,但是毫无用处。”,昄毫无用处的Y件不会是真正高质量的软g?br />
适用性质?br />20世纪60q代Q适用性质量概念以适合֮需要的E度作ؓ衡量的依据,从用的角度定义产品质量Q认量就是品的“适用性”。是“品在使用时能够成功满用户需要的E度”。质量涉及设计开发、制造、销售、服务等q程QŞ成了q义的质量概c适用性质量的例子也很多,比如我买了一件Givenchy西服Q我q真C一ӞQ但是一时又没有特别正是的场合(目前q真没有什么正式的场合Q,于是我一天四牛排(其实只有一)Q于是就吃胖了,qg华丽的Givenchyq不上了。那么这件衣服从W合性质量来_是优质品Q但是从适用性质量来_却不是一个高质量的品——因为我I不上。还有一句话Q叫甲之熊掌乙之砒霜。也是适用性质量的标准体现?br />那么软g的质量是不是适用性质量呢Q我个h觉得QY件的质量臛_是适用性质量。YӞ其是定制YӞ企业软gQ就是量体裁衣。Y件的基本质量是要在用户使用的过E中发挥价|支撑客户的业务发展?br />书上_从“符合性”到“适用性”,反映了h们在对质量的认识q程中,已经开始把֮需求放在首要位|。但是它没说怎么才能做到把客户需求放到首要位|。我看光靠文档是堆不出来的,光考说说也是不行的。这个后面讲Q戴明同学比我讲得好?br />
满意性质?br />20世纪80q代Q质量管理进入到TQM阶段Q将质量定义为“一l固有特性满求的E度”。它不仅包括W合标准的要求,而且以顾客及其他相关Ҏ意ؓ衡量依据Q体现“以֮为关注焦点”的原则。这个的最典型的例子是麦当劻I他所有的店铺从风格到食物都保持在同一水^Q你无论在那里Q都可以得到一定的购物体验。也构成了寚w当劳的满意性质量的验证。这个Y件上也是有例子的Q内举不必亲QThoughtWorks大多数项目都可以辑ֈ“满意性质量”,呵呵谁让Z是consultant涅?br />我隐U觉得满意性质量应该是一个过E的质量Q而不仅仅是Y件的质量Q但是目前没有好的想法,暂且按下不表?br />
卓越质量
......下略100字。个得大多数软gq没有达到适用性质量,大多是过E也都没有达到满意性质量,卓越质量先不说了吧?br />
MQ我们大体的认ؓ软g质量主要是适用性质量v码是不会错的。那么怎么才能辑ֈq个质量标准涅?俺是做Y件的Q质量管理还是看看Deming同学怎么说吧Q不q他老h家的14ҎL发生变化。我也只好断章取义,说说一个敏捷开发h员眼中的14原则Q?br />
1. 持之以恒地改q品和服务 Create constancy of purpose for improvement of product and service
q个很明昑֘Qsmall releaseQ快速发布,每次发布都是对品的持箋改进?br />
2.采用新的观念 Adopt the new philosophy
敏捷?..
3.停止依靠大规模检查去获得质量 Cease dependence on mass inspection
q个q有另一个说法,build quality in。TDDQQA/BA全程参与Q都是build quality in的好Ҏ?br />
4.l束只以h为基的采购习?End the practice of awarding business on the basis of price tag alone
q个...貌似是说请咨询吧...
5.持之以恒地改q生产和服务pȝ Improve constantly and forever the system of production and service
q个是敏捯E的持箋改进Q对应的实践大家可能比较陌生——Restrospective!!!
6.实行岗位职能培训 Institute training on the job
Pair ProgrammingQLearning Lunch敏捷从来都不~Z学习的机会,q你有没有学习的动力了?br />
7. 建立领导力企业管?Institute leadership
敏捷团队的终极目标,自组l团队,的管理是也?br />
8. 排除恐惧 Drive out fear
XPW一原则Q勇气,不要恐惧?br />
9. 打破部门之间的障?Break down barriers between staff areas
只有开发团队的敏捷不是真正的敏P敏捷说到底,是将软g的供求关pM合约型{为合作型Q本来就要是大破障碍。而且障碍不打_很隑ְ敏捷实施到底。这也是很多同学试敏捷p|的原因,仅仅以ؓ敏捷是技术层面上的事情,其实不是。从q个角度来所Q敏h法的是深刻而震撼心늚变革Q有些h...?..敏捷在十?..
10. 取消对员工的标语训词和告?Eliminate slogans, exhortations, and targets for the work force
恩,什么激?00?..闭开?..见鬼d...不过restrospective的结果是要写在白板上的,准备时刻改进。自我表扬和自我批评Q算不上训词吧?br />
11.取消定额理和目标管?Eliminate numerical quotas for the work force. Eliminate management by objectives
很多人都问过我,pair programming了之后,技校怎么办?嘿嘿QDeming同学已经说了Q这L考核不要也Ş?br />
12 消除打击员工工作情感的考评 Remove barriers that rob the hourly worker of his right to pride of workmanship. Remove barriers that rod people in management and in engineering of their right to pride of workmanship
敏捷团队的自我评价很单,360度,׃你几乎跟所有h都pairq,如果所有h都不说你?..q已l是rp问题了,׃是打击这么简单了...
13 鼓励学习和自我提高?Encourage education and self-improvement for everyone
同前QPair ProgrammingQLearning Lunch敏捷从来都不~Z学习的机会,q你有没有学习的动力了?br />
14 采取行动实现转变 Take action to accomplish the transformation
每次restrospective之后必须定出ҎQ以实践改进。而诸位如果想实施敏捷又觉得难于说服领带,不妨拿Deming同学说说事,q位大老的杀伤力q是曼大的,其你老大是MBA的话
]]>
1. data centric object model Active Record
delphi之所以成功,在于它看准了大部分商用Y仉是数据库核心的,qؓ之设计一套相应的框架, delphi的核心就是围l数据库q行开?李维同学的borland传奇里写道,当时之所以v名字叫DelphiQ就是因taking to Oracle)。而rails也很好的在新时代(Web时代)把握了相似的核心点——content是web的核心,以及数据库数据到content的映是动态web的核心。因此它没有采用所谓的更加严肃的ORM技术。而是依然使用了delphi时代的active recordQ但是进行了object装Q。如下代码示范了ruby和delphi在active record实现上的怼
Ruby
end
x8x = Person.new :name => 'x8x'
x8x.age = 15
Delphi
begin
people.Table = 'people';
people.InsertRecord('x8x');
people.First;
people.FieldByName('age') := 15;
end
可以看出QDelphi的数据库味道更浓一些,而ruby则更多用了对象的视角(我记得在98q前后(我变成oo狂热分子之后Q,在写delphi的时候我基本上不会直接用Table对象了,而是做一些简单的装Q用business object代替直接的数据库对象。但是最后由于和delphi的uilgl合的不好而放弃)。但是active record的pattern是一致的?br />
2. DB(resource)-aware UI component —?Action View
Delphi另一个ؓ人称道的地方是DBQAware的UIlgQ像TDBLabel, TDBMemoq有至今仍位人称道的TDBGridQ极大的化了UI的开发。不q说到底Q仍然是Delphi数据库核心策略的延箋。同Prails的view helper也是db核心的。text_field之类的可以自动感知active record的内容和错误?br />
?br />
nameLabel.DataSource = peopleTable;
nameLabel.Field = 'name';
nameLabel.Label = 'Name';
抛开Desktop和web的差异,也可以算是大致相当吧?br />
3. Simple Component Model —?Plan Object as Component
Delphi是基于组件开发,q且是非常成功的一个组件模型。基本上有经验的delphiE序员,都会在开发过E中抽象几个VCL component出来化自q开发。一斚w是DRY_Q另一斚wDelphi单的lg模型使得q样做的代h非常的小。Delphi的组件基本上是一个对象,重构的过E中修修Ҏ成lg了。rails其实有类似的机制Q而且更简单直接,更符合web时代的胃口,一个对象外加一个helper可以成Z个UIlg。与此同时railsq有另外一个天然的同盟——Ruby DSL。把以前Delphi需要用UI设计器的地方都用Ruby DSL代替了。这一Ҏ我最q在用rails做曹老师华丽的RedSaga的时候推行DSL geekM时发现的。比如现在我有这样一个tiny DSL用以定义portletQ?br />
in controller
name 'administration'
title 'Administration'
tabs do
Projects :controller =>'projects', :action => 'list'
end
end
in view
q种描述/configuration block风格的dsl与delphilg的初始化非常怼Q或者可以说Q只有语法上的差异而无思\上的差异Q当然delphi可以借助IDE而不是语a来指定这些,但是q个做法是没有生产力的)?br />
Label =
Name = .
Tabs[0].Controller =
Tabs[1].Action =
end
rails和delphiq种轻量的组件模型,使得构徏lgQ复用组件的代h。因此可以极大的提高开发效?我至今仍记得Q?1q前后接了一个DelphiU活Q客戯求Office XP菜单风格Q我找了一个XPMenu的控Ӟ直接仍上去,自己的代码一行没改,菜单Office XP?..)?br />
MQDelphi的效率要素Rails大部分都学走了,最后简单ȝ一下rails在delphi基础上的发扬Q?br />
1. 用ruby而不是object pascal。语法上更灵zȝ?br />2. Object Model on top of ActiveRecordQ比起Delphi可以跟好的用OO开发?br />3. lg模型更简?br />4. CoCQ这个就不说?br />5. expressive Ruby DSL
最后最后,说一下Delphi for PHPQ做得很华丽。但是UI部分我不是很喜欢?br />
]]>
Cross compiling,
reading psp documents, reading ruby source code, hacking ruby source
code, cross compiling... after 3 days hard working, finally, I managed
to make the following ruby script(which is listed in the book
<Programming Ruby>) running on my PSP:
def say_goodnight(name)
"Good night, #{name}"
end
puts say_goodnight("PSP")
Bingo~~~! Ruby goes entertainment!!!!
btw : my ruby-psp patch could be found here:
https://rubyforge.org/tracker/index.php?func=detail&aid=8134&group_id=426&atid=1700
make sure you have psp-gcc and toolchain installed on you PC, and 3.03-OE/1.5 fireware on your PSP.
]]>
It will highlight the text field but put nothing in it. I read the Watir source codes, and found an interesting code segment:
2 sleep @ieController.typingspeed # typing speed
3 c = value[i,1]
4 #@ieController.log " adding c.chr " + c #.chr.to_s
5 @o.value = @o.value.to_s + c #c.chr
6 fire_key_events
7 end
The above codes show how Watir simulates typing.If it doesn't work well with chinese characters, There must be something wrong with Ruby string. The first order of business is to figure out how Ruby string works for Chinese string.
2 puts chineseString.length
3 for i in 0..chineseString.length-1
4 puts chineseString[i, 1]
5 end
result will be:
Does Ruby, which is now capturing all java programmers' love, use 8bit char instead of unicode? Holy fuck!
I made a simple patch for the issue after I woke up from a short coma.
2
3 module Watir
4 module Cn
5 class IE <Watir::IE
6 def text_field(how , what=nil)
7 return TextField.new(self, how, what)
8 end
9 end
10
11 class TextField < Watir::TextField
12 def doKeyPress( value )
13 begin
14 maxLength = @o.maxLength
15 if value.length > maxLength
16 value = suppliedValue[0 .. maxLength ]
17 @ieController.log " Supplied string is #{suppliedValue.length} chars, which exceeds the max length (#{maxLength}) of the field. Using value: #{value}"
18 end
19 rescue
20 # probably a text area - so it doesnt have a max Length
21 maxLength = -1
22 end
23
24 Cn.characters_in(value) {|c|
25 sleep @ieController.typingspeed
26 @o.value = @o.value.to_s + c
27 fire_key_events}
28 end
29 end
30
31 def Cn.characters_in(value)
32 index = 0
33 while index < value.length
34 len = value[index] > 128 ? 2 : 1
35 yield value[index, len]
36 index += len
37 end
38 end
39 end
40 end
I submitted this patch to Watir tracing systsem,and zipped codes could be found here:
http://rubyforge.org/tracker/index.php?func=detail&aid=3232&group_id=104&atid=489
]]>
myBrowserWindow := Browser new openEditString:#Hello.
myBrowserWindow setLabel:'System Browser'; bounds: (Rectangle left:20 right:600 top:20 bottom:400).
my3DIDE := Wonderland new.
my3DIDE getDefaultCamera getMorph bounds: (Rectangle left:20 right:800 top: 20 bottom: 600).
my3DBrowser := my3DIDE makePlaneNamed: 'System Browser'.
my3DBrowser setY:50; turn:#right turns:0.38;
setProperty: #adjustToTexture toValue: true;
setTexturePointer: myBrowserWindow;
setProperty: #activeTexture toValue: true.
Try it and have fun!
]]>
]]>
btw: I'm a believer in Peter Coad's Color Modeling approach, all the following tips are modeled in the approach. I recommend you the greate book 'Java Modeling in Color with UML' if you'd no idea about the Color UML.
1. Annotating Description with @Embeddable, and the Thing it describe with @Entity
Take Product and ProductDescription for example.
In hiberante, we could make the ProductDescription as an embedded persistent object of Product via the component tag.If the ProductDescription should be embedded in another object, we've to declare it once more.
Things become more convenient in JSR 220, because non-transite fields, whose class is annoated with @Embeddable, are treated as embedded persistent objects automatically, we'd have fine-grained persistent objects without long-winded config file.
2.Avoiding Database Field in Domain Model Using @AttributeOverride
It's claimed that Annotaton could simplify development, but considering the cost of hard-coding mapping information in source codes I prefer some other complicated ways.It's too ugly to write code like following.
It's sucks but could be avoided.
We could separate the domain model and the persistent model by inheritance.Although we could do the same thing in hiberante too, we have to provide lots of configuration files.Once more we'd have hierachical persistent objects without long-winded config file.
3.Avoiding Database Primary Key in Domain Model
In most O/R mapping framework, we are always asked to give a primary key or identifier to our domain model, and we are suggested using meanless identifier instead of domain-specified identifer.It's kinda of Domain Pollution.Although we couldmake the domain model more clearer via inheritance, it's pointless for common usages.
Fortunately, we HAVE TO separate domain model and persistent model(as above mentioned), so that we can throw this bad habit away conviniently :D
Conclusion
After two hours walking around JSR220 persistent API, I figured out that JSR220 mixed ugly into convenience... and it's quite easy to write ugly codes in jsr220...so that we've to insist on using OO and the convenience jsr220 provided to make our domain model as clear as possible.
Although JSR220 is more ugly than hibernate, we could get clearer domain model in jsr220 rather than hibernate, because we could not stand the unly in jsr220...weird way to make us keeping more OO...cool isn't it...
First of all, I should admit that I'd never thought about this question before, becasuse I think hankering after consistent concepts is some nature of us. The question enlightens me to thinking deep. Here are my points.
1.Complexity
Inconsistent concepts bring complexity.I'll give two examples.
First one is something in Lisp. Lisp has a very simple computing model called λ Calculation. There are three elements in this computing model: Function, λ Operator and · Operator. λ Operator picks up free variable from the function, and · Operator applies the variable with a concrete value. The whole evaluation-application thing is what we called symbolic algebra in math.For example, if we've a function whose expression is x + y.
Since Lisp is kinda implementation of λ Calculation in computer, we could do the same thing in Lisp (and its dialects).
or we could use some syntax sugar
Most of things in Lisp are focus on evaluation, and the evaluation should be done in a simple consistent way: evaluating, applying value and then returning the value without any change to enviroment. It is the very same way that we do something in math.
But variable assignment was introduced to Lisp, so some functions which change enviroment instead of simple evaluating came to Lisp.For example:
That bad function changes value of symbol 'z' while evaluating x + y. It is the variable assignment which breaks the consistent concepts. The consistent concepts suggests that function should do and only do evaluation. We must find a more complicated computing model to replace the simple elegant mathematical one.Here inconsistent brings complexities in computing model.
The other example comes from Java. Java is considered to be an object-oriented programming language with single root type system. Conceptually speaking, everything should be an object.But for some perfermance reason, Java has some primitive types (such as int, double, float etc.) too.Those primitive types introduced a algebraic world which paralleled to the object world, and broke the consistent concepts.Althought Java has some wrapper classes for those primtive types, they are not enough for filling the gulf between object and algebra.
We could use new Integer(3) to represent 3 in object world, but we could not simply translate
to
Algebraic calculation and object message sending are totally different. Although we could do that in Java 5, it also has lots of differences.Auto-boxing treats object as primitive instead of operator overloading in C++ which treats operator as object message sending.So in my opinion, auto-boxing in java5 is awful. Assginments and storage of primitive type and object have lots inconsistent semantics too. This inconsistent would bring complexity when we use Collection API(Remember Primitive Collection in Commons Collection Project? )
2. Side-Effect
The mainly cause of side-effect is putting some inconsistent concepts together. I'll also give two examples.
First example is the well-known side-effect in functional programming, which is caused by mixing Von-Nouma-style-things into λ Calculation. There are lots of discussion about this topic in functional programming community.It's meanless to repeat that again.
Second example comes from half-blooded object-oriented languages, for we'll find both object-oriented things and procedure-oriented things in these languages, and it'll be much more easier to write code in procedural way instead of object-oriented way.For example, we'd write code like this:
and then in some codes, we could do the conditional execution as follows
In Smalltalk, everything is Object, so that the code above means sending a message named '>' to an Integer object, whose value is 4, with an Integer object parameter. And '>' would return a Boolean object, and then we sent a message named 'ifTrue' to it. This is a typical usage of State Pattern. Here are the equivalent Java codes.
which could be translated in Java like this:
That's quite simple(some dynamic languages on JVM ,e.g. Groovy, do the same thing), but it indeed brings some profound changes to my thought.
First, considering that 'if'Q?/SPAN>'for' and 'while' are no longer pre-defined keywords, we could define our own control structures. For example, we could define Order has its own way to do something.
Taking no account of performance and semantic speaking, there is no difference between the code above and undermentioned:
More fancy, we could define a new test structure like this:
So we could have programmable control structure in Smalltalk ( something like we do in Lisp via continuation:) ), and define our own DSL easily.That's the amazing lightweight syntax feature in Smalltalk!
Second, we could get full capability of Von Nouma Style Programming Language via pure OO concepts.We could construct software in consistent OO concepts.
I began my adventure in Object technology by using C++ in 1995, and then I chose Java as my main working language. All my experiences about OO come from half-blooded OO language.So that for a long time, I thought Object-Oriented Programming is a big patch to imperative languages. The imperative languages are desgined to record the sequence of instruments which are used to manipulate the computer, so they are lack in semantic, and poor in abstraction. Though the Object technology introduces a successful type system and provides some abstraction mechanism, I still feel sucks to program in inconsistent concepts, because I should be careful about keeping programming more in OO-style rather than in procedural-style(something like Domina Model or not, sucks!).
Once I accused Object-Oriented Methodology of all the fault, I blamed imperfection on Object-Oriented Methodology.But now, I found out it's only because that I have little talent and learning in OO, it turned out to be my fault, I should say sorry to Object-Oriented Methodology.