??xml version="1.0" encoding="utf-8" standalone="yes"?>
首先Q写作促(j)q我们思考。程序员每天的工作,不论是学?fn)新知识新技术、理解Y仉求、阅M?文档、设计框架、还是实C务逻辑Q都M开思考。相信很多h都有q这L(fng)体验: 对于某个设计或知识点Q你以ؓ(f)自己x(chng)楚了(jin)Q但真要让你解释l别人听Q你又会(x)觉得无从下手Q几轮过后回惛_初,之前所看到和相信的不过是错觉,当你完整的向其他{qC遍之后,你才是真正x(chng)白了(jin)。其实这个道理和书桌上放一只橡皮鸭/填充玩偶(然后向它讲述你的x(chng))的做法是盔R的Q只不过写作本n不光整理?jin)思\Q还留下?jin)文档,同时Q写作的q程也是不断加深印象、提升信?j)的q程Q可谓一丑֤得?/p>
其次Q和写作一P~程的主要目的是与世界交,不论q个世界是指的机器的世界q是人的世界。要有效C机器世界交流Q你~写的代码必ȝ合一定的语法和范式,必须逻辑上讲得通,q样才有意义。而基本的写作训练可以让我们养成主动留意错别字、格式、拼写错误、逻辑错误的习(fn)惯。如C. A. R. Haore所_(d)我们宁要明显无错误的代码Q不要无明显错误的代码。这Ҏ(gu)癖是好程序员必须具备的修充R这也是Z么我看到有明显拼写错误的E序员简历时Q会(x)直接把他/她们拉黑。同样地Q我一直坚持认为,如果E序员写不出l构优良的纯文本文档Q那么我们也不必指望?她能够写Z雅的代码。除此之外,我们q可以再E微发散一? 开源项目那么多Q满类似需要的往(xin)往(xin)不止一个,Z么有的很成功Q有的却无h问|? d/灵魂人物的写作能力,不论是代码、文档、邮件还是PPTQ是很重要的分野。我怿Q改变(sh)界、媄(jing)响更多的人,是很多程序员梦寐以求的,而要做到q一点,M开写作?/p>
最后,写作通常是程序员的短板,亦即最Ҏ(gu)低成本高?sh)出的地斏V我一直很不喜Ƣh为地l不同专业背景的(chung)上文U和理科的标{,仿佛(jng)他们之间没有交集似的。这样做的最大问题在我看来是一方天然地觉得另一方的知识对自己没价|以至于Ş成了(jin)cM"写作是文U生的菜"?~程是理U才要学的东?{谬误。就我的观察Q计机U班?gu)n的同学,往(xin)往(xin)文字表达能力不够强,可能多少和这U心(j)理暗C有兟뀂如此明昄短板Q如果能够引起广大程序员体的重视,肯在写作上持l投入,效果一定是惊h的?/p>
代码是从guithub的gist上抄的,单改?jin)改Q原始代码见: http://gist.github.com/66925
q段代码解决的是l典的汉诺塔问题Q通过一根中柱,左׃64个大依ơ叠加的圆盘全部Ud到右柱,要求整个q程中每ơ只能移动一个圆盘,且每个圆盘只能独立占据一Ҏ(gu)子或是叠加在比自w更大的圆盘?sh)?/p>
单分析一下就知道Q这是一个递归问题(FP的英雄特?Q?/p>
很容易发C个patternQ那是UdN(N>1)个圆盘,可以通过以下三个步骤Q?/p>
在解释代码之前,先说说Scala的implicit隐式转换Q这是一个非常powerful的ideaQ当Scala~译器发现类型不匚wQ它不会(x)直接failQ而是试从代码中指定的,在scope内的implicit转换定义Q来替换问题对象或表辑ּ以满类型要求,当然Qؓ(f)?jin)避免歧义,同一时刻Scala需要找到唯一的一个满x(chng)件的implicit定义?/p>
我们的代码首先定义了(jin)一个取得友好类名的Ҏ(gu)Q不LI它Q然后定义了(jin)一个正整数的序列,也不LI它?jin),你只需要当作他们是正整数就好,接触qFP的同学应该对此类定义不陌生,接下来定义了(jin)如下3个支持implicit传入参数的方法:(x) 含义分别是:(x) 单说明:(x)Scala用[]表示cd参数Q区别于Java?lt;>Q另外,Scala的类型声明在变量/函数定义之后。Move[_,A,B,C]的含义是通过CQ从AUd圆盘到B?/p>
我们来模拟运行一下,Z(jin)演示效果Q用一个中{复杂的数目Q?个圆盘,从LeftUd到Right?/p>
run[_3,Left,Right,Center]Q对应Move[Succ[_2],Left,Right,Center]Q于是展开成三个MoveQ?/p>
Move[_2,Left,Center,Right]即Move[Succ[_1],Left,Center,Right] 然后l箋(hu)展开Move[_2,Left,Center,Right]和Move[_2,Center,Right,Left]Q得刎ͼ(x) Move[_1,Left,Right,Center] q个时候已l全部都匚wMove[_1,A,B,C]Q于是我们很Ҏ(gu)得到以下输出Q?/p>
Move from Left to Right 希望本文能带lScala初学者一些感性认识和启发?/p>
q些理由有它的道理,但是我们有必要仔l掂量掂?
def simpleName(m:Manifest[_]):String = {
val name = m.toString
name.substring(name.lastIndexOf('$')+1)
}
trait Num
final class Succ[Pre<:Num] extends Num
final class _1 extends Num
type _2 = Succ[_1]
type _3 = Succ[_2]
type _4 = Succ[_3]
case class Move[N<:Num,A,B,C]()
implicit def move1[A,B,C](implicit a:Manifest[A], b:Manifest[B]) : Move[_1,A,B,C] = {
System.out.println("Move from " + simpleName(a) + " to " + simpleName(b))
null
}
implicit def moveN[P<:Num,A,B,C](implicit m1:Move[P,A,C,B], m2:Move[_1,A,B,C], m3:Move[P,C,B,A]) : Move[Succ[P],A,B,C] = null
def run[N<:Num,A,B,C](implicit m:Move[N,A,B,C]) = null
case class Left()
case class Center()
case class Right()
run[_3,Left,Right,Center]
m1:Move[P,A,C,B],
m2:Move[_1,A,B,C],
m3:Move[P,C,B,A]
) : Move[Succ[P],A,B,C]
Move[_1,Left,Right,Center]
Move[_2,Center,Right,Left]即Move[Succ[_1],Center,Right,Left]
Move[_1,Left,Center,Right]
Move[_1,Right,Center,Left]
--------------------------
Move[_1,Left,Right,Center]
--------------------------
Move[_1,Center,Left,Right]
Move[_1,Center,Right,Left]
Move[_1,Left,Right,Center]
Move from Left to Center
Move from Right to Center
Move from Left to Right
Move from Center to Left
Move from Center to Right
Move from Left to Right
]]>
原文链接
http://www.reddit.com/r/programming/comments/63tnv/bruce_eckel_33104_im_over_it_java/c02qx55
不多废话Q直入正题:(x)
[l度一] Static vs Dynamic Typing
?rn)态类型和动态类型,区分的关键点为编译期或运行期定cdQ静(rn)态类型在~译期确定,动态类型在q行期确定?br />
?rn)态类型代?Java、Scala、Haskell
动态类型代?Ruby、Python、Erlang
[l度二] Strong vs Weak Typing
强类型和q型,区分的关键点行时是否自动转换C实际cd不符的类型:(x)强类型要求手工类型{换,q型自动{换?br />
强类型代?Java、Scala、Python
q型代?C、Assembly、JavaScript
[l度三] Latent (Implicit) vs Manifest (Explicit) Typing
隐式cd和显式类型,区分的关键点为是否要在源码中声明cdQ隐式类型不需要,昑ּcd需要?br />
隐式cd代表 Haskell、Erlang、Python
昑ּcd代表 C、C++、Java
[l度四](mi) Nominal vs Structural Typing
名义cd和结构类型,区分的关键点为类型判定是Ҏ(gu)标称q是Ҏ(gu)内容Q名义类型根据标Uͼl构cdҎ(gu)内容?br />
名义cd代表 C、C++、Java
l构cd代表 Haskell、Erlang、Python
关于JavaScript书籍的争论,L(fng)步如下网址Q?br />
1- |友Hax?炮蘪"?http://www.javaeye.com/topic/474725
2- 周爱?aimingoo)的MSNI间 http://aimingoo.spaces.live.com/blog/
3- 火星帔RJE办事处相兛_ http://mars.group.javaeye.com/group/topic/14325
]]>
在我们日常生zd工作中,其览含有中文的网站,时常?x)?f)q问题犯愁Q一些天生Unicode支持不到位的~程语言和Y件更是加重了(jin)q个现象。虽说已l是2009q了(jin)Q我们时不时q是能碰C些明显脑D的codeQ吐Z堆ؕ码,不论你用选什么字W集Q似乎都无法q原最初的中文。比?å·̔"Q或者同一个页面,无法用同一个字W集昄QQ何一U字W都臛_有一部分昄不正,不是q儿是那儿?br />
首先U普一下UTF-8。UTF-8是Unicode所有字W编码实CQ应用范围最q的一个,最大的特点是兼容ASCII码,在此基础上,通过1..4个byte来表C每一个Unicode字符。它是怎么做到的?其实很简单,看首个byteQ?br />00000000 ~ 01111111 : 0~127 (ASCII, 单个byte) 表示Unicode范围\u0000 ~ \u007F
11000000 ~ 11011111 : (2?打头Q所?个byte) 表示Unicode范围\u0080 ~ \u07FF
11100000 ~ 11101111 : (3?打头Q所?个byte) 表示Unicode范围\u0800 ~ \uFFFF
11110000 ~ 11110111 : (4?打头Q所?个byte) 表示Unicode范围\u10000 ~ \u10FFFF
除了(jin)单个byteq个caseQ其他情况下Q后l的byte均以10打头。这些打头的bitQ?0?10?110?1110Q都不作为具体编码的一部分参与真正Unicode~码的计。所?..4个byteQ其有效位数分别为:(x)7?1?6?1Q因此才有了(jin)\u007F、\u07FF、\uFFFFq样的(f)界|?个byte的空间还有富余?br />
有了(jin)q个基础知识Q我们就来具体看看这??字,是怎么被UTF-8表示的,以及(qing)Z么处理不当的代码?x)最l输?å·̔"?br />
"?字,用Unicode表示法,是\u5DF2Q按?个byte拆开成二q制表示Q?br />01011101 11110010
如果用UTF-8~码Q采?110???? 10?????? 10??????q个格式Q?号部分填入上q?1011101 11110010Q得?br />11100101 10110111 10110010 q样3个byte?br />
好了(jin)Q这个时候脑D代码出玎ͼ假如它不认识UTF-8Q那么他?x)看到这?个前后没有关联的byteQ在西欧Latin-1字符?即ISO 8859-1)中,它们分别表示"å"?·"?̔"q?个字W。如果把它们分别再按照UTF-8~码Q就成了(jin)Q?br />11000011 10100101 11000010 10110111 11000010 10110010
完美的UTF-8~码Q只不过Q这完全是假象,只能通过非常规手D|能恢复它原本的样子?br />
]]>
我本人对Chandlerq个目q不陌生Q之前出于对Python/wxWidget和开源本w的兴趣Q陆l用q几?.x的版本,一开始ƈ不是十分友好Q性能上也有问题,甚至?x)莫名的吃掉我机器上的数癑օQ或者上G?Q空间。后来的版本在性能和可用性上实提高?sh)(jin)不,但一直感觉这个项目缺必要的、以?qing)许多开源项目应有的momentum。Phillip J. Eby对Chandler开发h员(sh)懂Python的批评,当时我的印象也很深。而项目中出现的h物,包括Mitchell Kapor、Ted LeungQ也都在Chandlerq个范畴之外followq。其他细节包括:(x)Chandler和Cosmoq两个名U的由来、Chandler目l中x(chng)成员相寚w的比例、一些熟(zhn)的人物?qing)其观点QAlan Kay, Bill Joy, Frederick Brooks, Donald Knuth、Linus Torvalds, Ward Cunningham, Larry Wall, Guido van Rossum, Joel Spolsky, etc.Q、一些公司的分分和和以及(qing)人员?gu)动{等。感觉挺亲切的?br />
可能更重要、也更深ȝ原因是:(x)管书中一再提?There's no such thing as a typical software project, every project is different"Q我仍然深深的感觉到QChandler遇到的这些问题,其实也是我亲历的很多目的种U问题的一个羃影。对q些问题Q作者ƈ没有l出解决Ҏ(gu)Q其实谁也没有标准答案。Y件开发是一w常具有挑(xi)战性的工作Q也正是像我们这h热情、有涵养的专业h士生存的I间和h(hun)值所在?br />
]]>
我最感兴的是Burdenq一D:(x)Cunningham解释_(d)l常看到有些开发团队,他们快速的开发出软g产品推向?jng)场Q不断的往(xin)里面d新的Ҏ(gu),在这个过E中Q不断的学习(fn)Q但从不把学到的东西、ȝ的经验教训应用回去,q就像是从银行借贷Q但从不想着有一天需要偿q(是不是有点像是在说引发这ơ次贷危机的国人的消费?fn)惯和观念?Q,到最后,你所有的收入都将用于偿还利息Q你的购买力也将降ؓ(f)零。映回软g开发的语境Q如果我们在一个较长的旉跨度内,开发一个YӞ不断的增加featureQ但从不回过头去整理和重构,把对q个软g和这些特性的新的理解和认知写回去Q那么最l这个Y件、这些feature不再会(x)有Q何实际的价|对它们做M事,都将p来多的时间和_֊Q开发进度也因此下降ؓ(f)零?br />
]]>
Download: http://www.python.org/download/releases/3.0/
What's New:http://docs.python.org/whatsnew/2.6.html#python-3-0
]]>
Download: http://www.python.org/download/releases/2.6/
What's New: http://docs.python.org/whatsnew/2.6.html
]]>
(tng)2 (tng)
(tng)3 (tng)def (tng)mail(subject, (tng)body, (tng)attachment (tng)= (tng)[dir:".",files:[]]) (tng){
(tng)4 (tng) (tng) (tng) (tng) (tng)ant.mail(mailhost:"mail.com", (tng)mailport:"1025", (tng)user:"mailer", (tng)password:"123", (tng)subject:"${subject}") (tng){
(tng)5 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)from(address:"nobody@mail.com")
(tng)6 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)to(address:"nobody@mail.com")
(tng)7 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)message("${body}")
(tng)8 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)attachments() (tng){
(tng)9 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)if (tng)(attachment.files) (tng){
10 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)fileset(dir:"${attachment.dir}") (tng){
11 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)attachment.files.each (tng){
12 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)include(name:it)
13 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
14 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
15 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
16 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
17 (tng) (tng) (tng) (tng) (tng)}
18 (tng)}
19 (tng)
20 (tng)attachment (tng)= (tng)[dir:"/tmp", (tng)files:["some.properties","some.sql"]]
21 (tng)mail("Test (tng)mail (tng)message (tng)at (tng)${new (tng)Date()}", (tng)"This (tng)is (tng)a (tng)test (tng)message.", (tng)attachment)
22 (tng)
q个单的例子很好的展CZ(jin)如下GroovyҎ(gu):(x)
1- Groovy脚本可以不需要定义Q何classQ方法定义和实际调用也可以在一P十分手?br />2- 定义变量不需要指定类型,只要赋值即可,不过q行期依然是强类型?br />3- Ҏ(gu)参数可以有默认倹{?br />4- List和Map的构建直接在语义层面提供支持Q如[a:1,b:2]和[1,2]?br />5- GString使得我们可以方便的在String中引用变量甚x(chng)表达式,?${a.b.c}"?${new Date()}"?br />6- 逻辑判断在true/false基础上有所扩展Q[]Q?个元素的ListQ和null均做false处理?br />7- Closure支持Q方便我们在外围代码处“当场”指定处理逻辑Q省M(jin)大多数在Java中需要匿名内部类来处理的ȝ(ch)Q如attachment.files.each { .... }Q只有一个传入参数时Q可直接用it指代?br />8- 与ANT的无~集成,以及(qing)对Builder模式的良好支持,使得我们可以写出上述初看上去有些不可思议的代码?br />
P.S. 虽然Groovy自己已经bundle?jin)ANTQ可以直接用其中的l大多数功能Q不qؓ(f)?jin)调用ANT的mail taskQ还需要将ANT发行版中带有的ant-javamail.jar以及(qing)JavaMail API对应的jar包(可以从Sun|站下蝲Q加到classpath。如果你的JDK版本低于6.0Q还需要activation.jar?br />
]]>
(tng)2 (tng)
(tng)3 (tng)ant (tng)= (tng)new (tng)AntBuilder()
(tng)4 (tng)root (tng)= (tng)":pserver:cvsuser:password@10.10.10.1/cvsrepo/SampleProduct"
(tng)5 (tng)
(tng)6 (tng)def (tng)checkout() (tng){
(tng)7 (tng) (tng) (tng) (tng) (tng)ant.cvs(cvsroot:root,command:"checkout (tng)-A","package":".",dest:"cvsoriginal",compressionlevel:"9")
(tng)8 (tng)}
(tng)9 (tng)
10 (tng)def (tng)update() (tng){
11 (tng) (tng) (tng) (tng) (tng)ant.cvs(cvsroot:root,command:"update (tng)-A (tng)-d","package":".",dest:"cvsoriginal",compressionlevel:"9")
12 (tng)}
13 (tng)
14 (tng)def (tng)compile(project) (tng){
15 (tng) (tng) (tng) (tng) (tng)ant.javac(srcdir:"cvsoriginal/$project/src",destdir:"cvsoriginal/$project",target:"1.5",encoding:"GBK")
16 (tng) (tng) (tng) (tng) (tng)ant.copy(todir:"cvsoriginal/$project") (tng){
17 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)fileset(dir:"cvsoriginal/$project/src") (tng){
18 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)exclude(name:"**/*.java")
19 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)}
20 (tng) (tng) (tng) (tng) (tng)}
21 (tng) (tng) (tng) (tng) (tng)ant.jar(destfile:"build/$project.jar",basedir:"cvsoriginal/$project",manifest:"MANIFEST.MF") (tng){
22 (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)exclude(name:"src/**")
23 (tng) (tng) (tng) (tng) (tng)}
24 (tng)}
25 (tng)
26 (tng)// (tng)to (tng)actually (tng)call (tng)your (tng)target
27 (tng)checkout (tng)root
28 (tng)
代码更紧凑,与Java的集成更无缝。只需要简单的培训Q有Java基础的朋友就能上手,不必再额外学?fn)和习(fn)惯Ruby的语法,不用gem installQ也不用去monkey-patch个别文g来集成和打包Ant、Antwrap和JRubyQ只需要一个groovy-all-x.x.x.jar加上自己的脚本即可轻松搞定?br />
[2008-08-26 19:25:00 更新] l过实际环境试Q原来JRuby(1.1)+Antwrap需?4分钟完成的构建,改用Groovy(1.5.6)后,仅需?6分钟Q对于需要经常处理构建的目和品来_(d)q?分钟q是相当可观的?br />
]]>
然而,随着旉的推U,接触到的不同的东西越来越多,自己对不同问题的看法和解决问题的思\来成熟,Java虽然是全能型的语aQ也变得来无法满x(chng)常工作和׃的需要,在一些特定的场合Q也发别扭Q有时我甚至?x)怀念学生时代的Pascal/Delphi和后来的C/C++。回q头ȝ自己Q从刚入行时的Java fanboiQ到现在q样一个pragmatist和purist的结合体Q是多么有趣的{变?br />
在过ȝ2q多Q除?jin)Java?NETQ陆陆箋(hu)l接触到q有q简单用经历的~程语言Q有bash、PL/SQL、JavaScript、PHP、Perl、Ruby/JRuby、Scala、Python/Jython、Groovy{等Q不q都没有pȝ的学?fn)过Q基本就是拿来主义,什么好用用什么,解决手里的问题(sh)ؓ(f)丅R?br />
也许是工作性质的原因,日常要处理的非技术性Q务越来越多,留给具体~程的时间现在一天比一天少Q编E带来的乐趣和解x(chng)术问题带来的快感Q就昑־十分珍贵。所以我下定军_(j)一定要pȝ的学?~2U和Java/.NET不同的编E语a。一开始这个选择q不Ҏ(gu)Q我曄q?a target="_blank" title="http://twitter.com/laogao/statuses/853718837" >半调侃式的和一个朋友讲Q“Python, Ruby, Scala, Groovy, 一个都不能?/a>Q经q一D|间的权衡之后Q还是比较自然的作出?jin)最后的选择QPython和Groovy?br />
Pythonq个选择其实q不难,留意Pythonq门语言Q其实说h也有差不?q了(jin)Q它完全W合“和Java/.NET不同的编E语a”这个条Ӟ而且应用面很q,也十分成熟,功能也非常强大,加上大量现成的类库,能够胜Q很多不同cd的编EQ务。基本上q是一个不用Q何思想斗争的选择?br />
Groovyq个选择相对没有那么直接Q至在我真正用Groovy上手做一些东西之前,对它q没有特别的感觉Q甚臌疑它存在的h(hun)|因ؓ(f)有Jython和JRuby的选择Qؓ(f)什么一定要Groovy呢?到最q开始接触GroovyQ才逐渐?jin)解到它的出w(Groovy的作者受到Python的启发,不过后来Groovy发展的越来越接近RubyQ,和它在“兼容”Java代码的前提下为Java语言带来的巨大的表达力提升。对于有Java基础的h而言QGroovy十分Ҏ(gu)上手Q而且可以帮助我们化很多繁杂的dQ比如自动构建和自动化测试,而这正是我目前需要处理的?br />
最后简单说说其他几个落选的原因Q除?jin)时间有限之外?j)Q?br />bash - 目前掌握的基本够用,发现不够Ӟ完全可以用Python代替?br />PL/SQL - 基本很少使用?jin),偶尔需要维护,今后深入用的Z(x)也不多?br />JavaScript - 对“网”版的编E语a可能有天生的偏见Q尤其是作ؓ(f)Java fanboiQ当然对它“盗用”Javaq个名字是有意见的?br />PHP - 用的Z(x)很少Q而且q于quick&dirtyQ不是我喜欢的风根{?br />Perl - 虽然功能强大Q但是感觉语法有些terseQ不是很适应Q能处理的Q务,基本上Python也可以?br />Ruby - 语法和设计理念还是有一些认同,但是对Unicode的支持和部v环境的支持都q(sh)是很让h信服Q另外,拿孟岩的话说QRuby是一门魔q语aQ我不喜Ƣ过于魔qȝ东西Q而更?fn)惯具体直接的代码?br />Scala - 也是一门和Javaq_关系密切的语aQ不q有些“学院派”,函数式编E固然是亮点Q但短期内看不到太多的学?fn)h(hun)倹{?br />
所以,lg所qͼ最后再点一下题Q?8q秋季的学习(fn)计划是:(x)pȝ学习(fn)Python和Groovy?br />
]]>
http://code.djangoproject.com/wiki/VersionOneRoadmap
Ҏ(gu)q䆾U\图,今年7月,Django?x)推?.0的第一个alpha版本Q接下来?月会(x)有两ơbeta和一ơrcQ如果一切顺利的话,让许多h望眼Ʋ穿的Django 1.0有望于今年9月正式同大家见面?br />
]]>
主页: http://jruby.codehaus.org/
下蝲: http://dist.codehaus.org/jruby/
]]>
主页: http://jruby.codehaus.org/
下蝲: http://dist.codehaus.org/jruby/
]]>
1- 首先是准备PostgreSQL环境。有条g的话Q最好是找一台空闲的PCZ为测试服务器Q安装Linux或BSDQ然后从源码~译最新的PostgreSQL 8.3.0。编译时Q通过configure指定--with-perl?-with-python以支持PL/Perl和PL/Python。因为绝大多数Linux发行版都已自带Perl和PythonQ不必额外安装?br />
2- 如果是Windows环境Q又需要Perl和PythonQ则必须额外安装QPython的话Q可以方便的扑ֈ2.5 for Windows的安装包QPerl的话Q推荐ActivePerlQ相寚w?ch)一点,Z(jin)后面用到的一些便利的功能利加蝲QPerl版本量?.8.8?br />
3- 创徏数据库和用户。通过initdb初始化数据目录,配置postgresql.conf指定LIP、端口等{信息,配置pg_hba.conf指定讉K权限Q通过pg_ctl -D <数据目录> -l <日志文g> start启动postmasterQ然后createdb、createuser创徏数据库和用户。数据库建好之后Q就可以createlang -d <数据库名> [plperl|plperlu|plpython|plpythonu]开启PL/Perl和PL/Python。具体命令行参数可通过各命令加--help查看?br />
4- 安装PostgreSQL客户端pgAdminIIIQ最新版?.8.2Q有条g的话Q也可以下蝲源码自己~译?br />
5- 安装Oracle客户端,需要在PostgreSQL同一台机器,以便Perl用于q接数据库的DBI和Oracle驱动DBD::Oracle模块利安装。如果是Windows上的ActivePerlQ则可以通过ppm install DBD-OracleQ如果是Linux/BSDQ则可以通过CPAN来安装,如perl -MCPAN -e shellq入CPAN ShellQ通过install <模块?gt;或force install <模块?gt;安装DBI和DBD::Oracle?br />
6- 数据库的ULQ可以选择ora2pg来帮忙,目前的版本是4.7。ora2pg是一个用于读取Oracle数据库schema、数据,q生成PostgreSQL脚本或直接导入PostgreSQL数据库的Perl工具。用法很单,是通过.conf文g指定数据库连接信息包括NLS_LANG、需要导出导入的schema、table、view、data{等Q然后执行一个pl脚本。这是目前相Ҏ(gu)较成熟的一个方案,但是遇到schema复杂、约束较强的数据库,需要手工处理的地方q是不少。徏议不要直接写入PostgreSQLQ而是生成SQL脚本Q验证无误后再执行。ora2pg默认?x)把Oracle中名U的大写转换成小写,因ؓ(f)PostgreSQL在解析SQLӞ除非""括v来,默认都是转成写。schema、table、view、sequence、data{等Q基本用ora2pgQ加上一些手工调整即可搞定。至于function、stored procedure{,q是手工UdQ偷不得懒。除?jin)ora2pgQ其实也可以配置DBI-LinkQ将Oracle数据库挂到PostgreSQL数据库作Zl独立的"schema"Q然后用create table xxx as select ... from ...q样的语法来倒表和数据。PostgreSQL的contrib包也附带有一个dblinkQ不q是q接其他PostgreSQL数据库的Q如果需要连接非PostgreSQLQ?
q是考虑DBI-LinkQQ何可以通过Perl的DBI接口讉K的数据库Q都能linkqPostgreSQL?br />
7- 接下来就是Java应用本n?jin),我这ơ移的这个应用是Spring+iBatis架构的,很多SQL语句都是明文Q好在DAO层的基础部分(CRUD)的SQLMap是工兯动生成,且都是符合ANSI SQL92标准的,不需要修改即可用。其余的高查询SQLQ需要调整的地方不少Q一些常见的修改列D如下Q?br />
i. SELECT出来的columnQ包括子查询Q,如果有别名,必须加ASQ比?select null as some_column from some_table;
ii. PostgreSQL没有dual表,cMselect 0 from dual的语句,写成select 0卛_;
iii. DECODE函数需要重构成(case when some_column = 'some_value' then 'some_other_value' when ... then ... else 'some_default_value' end ) as some_column;
iv. NVL()函数QPostgreSQL中相对应的是coalesce()Q其实几乎所有主DBMS都支持coalesceQ包括OracleQ这才是标准写法;
v. 比较日期Q在PostgreSQL中,使用date_trunc('day', SOME_DATE) = date_trunc('day', #enteredDate#)q样的写法,其中'day'位置可选字D包括有year、month、week、hour、minute、second{等;
vi. SYSDATEQ对应到PostgreSQL是current_timestampQ可以根据需要用current_date;
vii. ROWNUMQ通常我们用ROWNUM都是Z(jin)限制查询出来的记录数QPostgreSQL没有q个关键字,需要改成在SELECT语句最后添?LIMIT语句Q如LIMIT 100;
viii. (+)q样的外q接写法需要调整ؓ(f)SQL标准?table1 [LEFT|RIGHT|FULL] OUTER JOIN table2 ON (...);
ix. CONNECT BY ... START WITH ... 递归查询可以参?http: //www.postgresql.org/docs/8.3/static/tablefunc.html 的connectby()函数.
最后再多提一点,PostgreSQL自带的过E语a是PL/pgSQLQ在PostgreSQL上写functionQ除?jin)用plpqsqlQ还支持sql、plperl(u)、plpython(u){等。如果你对SQL天生q敏Q看cMPL/pgSQL的代码都很吃力,别说是写?jin),你完全可以用你喜Ƣ的语言来表辑և数和存储q程的逻辑。有?jin)PL/PythonQ你q怕什么呢Q你几乎能做M事?br />
[更新 20080313] 把JDBC驱动的部分漏掉了(jin)Q移植Java应用Ӟ除了(jin)改SQLQ还需要拿PostgreSQL的JDBC驱动攑ֈclasspath下面Q如WEB-INF/libQ然后修Ҏ(gu)据库q接URLQ改成jdbc:postgresql://<ip>:<port>/<dbname>卛_?br />
[更新 20080323] ULschema和数据时Q比ora2pg更方便的一U方式是利用EnterpriseDB的Migration ToolQ将Oracle的JDBC驱动ojdbc14.jar拯到EnterpriseDB安装路径下的jre/lib/ext下后Q启动Developer Studio卛_建立Oracleq接Q选中schema后,可以通过右键Online Migrationschema、数据、函数包{等一ơ性通通导入EnterpriseDB。如果要l箋(hu)往(xin)"U?PostgreSQLU,从EDB做backupQ然后到PostgreSQL下做restoreQ这样会(x)丢掉函数包,因ؓ(f)毕竟EDB在PostgreSQL基础上做?jin)相当改造以和Oracle兼容Q不q函数包之类q是手工UL较稳妥?br />
]]>
http://www.eweek.com/c/a/Application-Development/Sun-Hires-Python-Experts/
管Sun官方的说法是他们?x)更多的应用和扶持native版的PythonQ相信一直饱受冷落的JythonQ也多少?x)从中受益吧?br />
]]>
?a target="_blank" title="http://www.aygfsteel.com/sean/archive/2008/01/27/178036.html" href="/sean/archive/2008/01/27/178036.html">之前一随W?/a>也提到过Q和其它在JVM中运行的动态语a如Jython、JRuby不同的是QGroovy对于有Java基础的h们来_(d)学习(fn)曲线几乎是^的,上手很快Q如果你同时也熟(zhn)Spring和Hibernate{,那么Grails更是不二之选?br />
官网: http://grails.codehaus.org/
Release Notes: http://grails.org/1.0+Release+Notes
下蝲: http://grails.codehaus.org/Download
]]>
官方声明: http://www.postgresql.org/about/news.918
Release Notes: http://www.postgresql.org/docs/8.3/static/release-8-3.html
各版本功能对? http://www.postgresql.org/about/featurematrix
下蝲: http://www.postgresql.org/ftp/
]]>
http://java.dzone.com/news/java-groovy-few-easy-steps
如果你对当下动态语a的现状有所?jin)解Q那你多半已l知道能在JVM中运行的动态语aQ远不止Groovy一U,那么什么理׃(x)让你选择Groovy而非Jython、JRuby或者其他类似的语言呢?W者认Z要还是编码习(fn)惯和风格QGroovy是这些语a中最接近Java的。Jython和JRuby都是从其他成功的动态语a"UL"q来Q带有明昄Python、Ruby语法特征和习(fn)惯。选择Jython或者JRuby的朋友,我想大都是原本就有Python或者Ruby的基Q舍不得Python和Ruby的一些很方便的语法和~码风格/?fn)?哲学Q或者干脆就是ؓ(f)?jin)将Python和Ruby世界的一些框架引入到Java中,或者说是让Python/Ruby应用能够更好的利用Javaq_已有的资源。如果你在动态语a上没有这斚w的需求,只是Z(jin)让你的Java应用更动态,选择Jython或者JRuby只能是凭I增加学?fn)难度。要知道QPython和Ruby都是很有特点、很有个性的语言Q其实Java又何不是)(j)Q要从Java的思维和哲学,转向Python/Ruby的思维和哲学,q不是那么容易做到和做好的?br />
]]>
Django是用Python实现的一个基于MVC的web应用框架Q类似Ruby世界的Ruby on
Rails。如果你是通过Google搜到q篇文章Q那么说明你已经对Django有所耳闻Qƈ且愿意了(jin)解更多Django相关的信息。我在这里就不多?
话Ruby vs Python或者Rails vs DjangoQ直奔主题?br />
在写q篇文章Ӟ最新的CPython版本?.5.1QDjango版本?.96Q如无特别说明,本文所有介l和CZ均以此环境ؓ(f)准?br />
0- 在开始之前,首先当然是安装一个基本能用的开发环境?br />
如果你的操作pȝ是Linux或者其他类UnixpȝQ很可能已经预装?jin)PythonQ可以在命o(h)行执行python -V查看Python版本。如果你是Windows操作pȝQ或者想试不同版本的PythonQ那么可以到http://www.python.org/下蝲相应的安装包q行安装?br />
有了(jin)Python以后Q到http://www.djangoproject.com/下蝲DjangoQ解压以后,cd到解压出来的目录Q执行python setup.py install?br />
Z(jin)能够做出一个基本的多层web应用Q还需要安装一个数据库Q如果没有特别喜好和偏向Q推荐PostgreSQLQ可以在http://www.postgresql.org/扑ֈ合适的版本下蝲和安装?br />
我们q缺一个数据库驱动Q在http://www.initd.org/pub/software/psycopg/可以扑ֈ用于q接PostgreSQL的psycopg2Q安装方法类似Django?br />
1- django-admin.py startproject
所有环境OK以后Q我们开始动手把玩DjangoQ首先找一个干净的目录,执行
$ python django-admin.py startproject hello
上面q行命o(h)?x)新Z个hello子目录,包含以下文gQ?br />
__init.py__: 表示该目录存放PythonE序
manage.py: 提供Django目相关的管理操?br />
settings.py: 相当于该Django目的全局讄
urls.py: 用于配置URL映射Q基本上是通过正则表达式指定不同URLq应的viewҎ(gu)相应
2- manage.py runserver
x(chng)我们已经搭v?jin)一个基本的Django目框架Q执?br />
$ python manage.py runserver
命o(h)行会(x)提示?000端口q行一个开发用的web serverQ{到浏览器?a href="http://localhost:8000/" target="_blank">http://localhost:8000/卛_看到It worked!的提CZ息。你也可以指定端口号Q方法是python manage.py runserver XXXX?br />
3- settings.py
接下来我们做一个完整的从model/数据库到view/template的例子。修改settings.py:
DATABASE_NAME (tng)= (tng)'hello' (tng)# (tng)Your (tng)db (tng)name
DATABASE_USER (tng)= (tng)'postgres' (tng)# (tng)Your (tng)db (tng)user
DATABASE_PASSWORD (tng)= (tng)'********' (tng)# (tng)Your (tng)db (tng)password
DATABASE_HOST (tng)= (tng)''
DATABASE_PORT (tng)= (tng)''
INSTALLED_APPS (tng)= (tng)(
(tng) (tng) (tng) (tng)'django.contrib.auth',
(tng) (tng) (tng) (tng)'django.contrib.contenttypes',
(tng) (tng) (tng) (tng)'django.contrib.sessions',
(tng) (tng) (tng) (tng)'django.contrib.sites',
(tng) (tng) (tng) (tng)'hello', (tng)# (tng)Our (tng)new (tng)project
) (tng)
4- models.py
新徏models.py:
from (tng)django.db (tng)import (tng)models
class (tng)Book(models.Model):
(tng) (tng) (tng) (tng)isbn (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.SlugField(maxlength=20)
(tng) (tng) (tng) (tng)title (tng) (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.CharField(maxlength=200)
(tng) (tng) (tng) (tng)author (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.CharField(maxlength=200)
(tng) (tng) (tng) (tng)description (tng)= (tng)models.TextField(blank=True,null=True)
(tng) (tng) (tng) (tng)published (tng) (tng) (tng)= (tng)models.DateTimeField(default=datetime.now)
执行下面的命令测试数据库脚本的生?
$ python manage.py sql hello
应该看到如下输出l果:
BEGIN;
CREATE TABLE "hello_book" (
"id" serial NOT NULL PRIMARY KEY,
"isbn" varchar(20) NOT NULL,
"title" varchar(200) NOT NULL,
"author" varchar(200) NOT NULL,
"description" text NULL,
"published" timestamp with time zone NOT NULL
);
COMMIT;
认无误后可以通过下面的命令提交到数据?
$ python manage.py syncdb
光?x)要求我们创Z个管理员账号Q如果暂时不打算做admin面Q可以蟩q?br />
5- views.py
model有了(jin)之后Q接下来我们可以开始画视图?jin)。由于篇q和旉有限Q我仅简单介l一下Django的templateQ然后实C个最基本的图书清单页面?br />
首先定义图书清单的URLQ在urls.py?
urlpatterns (tng)= (tng)patterns('hello.views',
(tng) (tng) (tng) (tng)(r'^hello/books/$', (tng)'book_list'),
)
新徏templates目录Q然后新建books.html:
<head>
<title>{{ (tng)title|escape (tng)}}</title>
</head>
<body>
<h2>{{ (tng)title (tng)}}</h2>
<table (tng)border="1">
(tng) (tng)<tr><th>ISBN</th><th>书名</th><th>作?/span></th><th>出版日期</th></tr>
(tng) (tng){% (tng)for (tng)book (tng)in (tng)books (tng)%}
(tng) (tng)<tr>
(tng) (tng) (tng) (tng)<td>{{ (tng)book.isbn (tng)}}</td>
(tng) (tng) (tng) (tng)<td>{{ (tng)book.title (tng)}}</td>
(tng) (tng) (tng) (tng)<td>{{ (tng)book.author (tng)}}</td>
(tng) (tng) (tng) (tng)<td>{{ (tng)book.published (tng)}}</td>
(tng) (tng)</tr>
(tng) (tng){% (tng)endfor (tng)%}
</table>
</body>
</html>
新徏views.py:
from (tng)django.shortcuts (tng)import (tng)render_to_response
def (tng)book_list(request):
(tng) (tng) (tng) (tng)title (tng)= (tng)'Book (tng)List'
(tng) (tng) (tng) (tng)books (tng)= (tng)Book.objects.all()
(tng) (tng) (tng) (tng)return (tng)render_to_response('books.html', (tng){'title' (tng): (tng)title, (tng)'books' (tng): (tng)books})
修改settings.py:
(tng) (tng) (tng) (tng)'/opt/PROJECTS/Django/hello/templates/',
)
我们手工造一些数据之后,可以通过http://localhost:8000/hello/books/讉K我们用Django实现的这个简单页面了(jin)?br />
6- What's next
通过上面的简单介l,怿哪怕是初次接触Django的朋友,也能够对Django有一个初步的认识。其实Djangoq不隑֭Qƈ且随着学习(fn)的深入,你一定能发现更多的惊喜,不论是来自Django本nQ还是Python?qing)其庞大的第三方cd?br />
如果有时_(d)试一下Django的admin pagesQ即为我们的model提供自动化、网化的增删改查操作。启用方法如下:(x)
修改models.py (增加class Admin):
from (tng)django.db (tng)import (tng)models
class (tng)Book(models.Model):
(tng) (tng) (tng) (tng)isbn (tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.SlugField(maxlength=20)
(tng) (tng) (tng) (tng)title (tng) (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.CharField(maxlength=200)
(tng) (tng) (tng) (tng)author (tng) (tng) (tng) (tng) (tng) (tng)= (tng)models.CharField(maxlength=200)
(tng) (tng) (tng) (tng)description (tng)= (tng)models.TextField(blank=True,null=True)
(tng) (tng) (tng) (tng)published (tng) (tng) (tng)= (tng)models.DateTimeField(default=datetime.now)
(tng) (tng) (tng) (tng)class (tng)Admin:
(tng) (tng) (tng) (tng) (tng) (tng) (tng) (tng)pass
修改settings.py和urls.pyQ加入admin支持:
[settings.py]
(tng) (tng) (tng) (tng)'django.contrib.auth',
(tng) (tng) (tng) (tng)'django.contrib.contenttypes',
(tng) (tng) (tng) (tng)'django.contrib.sessions',
(tng) (tng) (tng) (tng)'django.contrib.sites',
(tng) (tng) (tng) (tng)'django.contrib.admin',
(tng) (tng) (tng) (tng)'hello',
)
(tng) (tng) (tng) (tng)(r'^hello/books/$', (tng)'book_list'),
(tng) (tng) (tng) (tng)(r'^hello/admin/', (tng)include('django.contrib.admin.urls')),
)
Note:
# Z(jin)成功q行admin pagesQ需要首先执行python manage.py syncdb admin以创建django_admin_log表?br />
# 如果前面跌?jin)创建管理员步骤Q简单的Ҏ(gu)可以删掉auth_user表,然后python manage.py syncdb重徏?br />
按照我们urls.py的配|,admin pages可以通过http://localhost:8000/hello/admin/讉K。Enjoy!
]]>
{一{,在你考虑转向Maven或者真正卷赯子开始研IANT Task的API之前Q先听我向你推荐Ruby/JRuby。相信我Q也许这才是你真正需要的?br />
在我看来构徏脚本最主要的要求是表达能力和控制能力,表达能力是我们应该能够很方便的告诉它我们要它做什么,而控制能力是我们告诉它如何去做,除了(jin)必要?
构徏命o(h)的参数、依赖关pM外,它应该能够理解我们其他一些特D要求。在目相对单时QANT的XML格式?脚本语言"能够比较好的表达构徏者的?
求,臛_比纯Java的方式更加简单清晎ͼ于是几乎从它诞生之日成为Java领域当仁不让的头h建工兗但是ANT也有它不够用的时候,其在控制能
力上Qؓ(f)?jin)实现实际用中来复杂越来越_的对构徏q程和出的要求QANT的用者们开始对ANTq行扩展Q最具媄(jing)响力?非官?扩展可能是
antcontrib?jin),很多实际Java目的构建文件中我们都能够找到它的媄(jing)子。但是一堆taskdef?variable>
]]>
Linux版的Eclipse默认使用GTK+2.0的控Ӟ所以在默认的情况下Q会(x)和其他GTK应用E序Q如OpenOffice.orgQ一L(fng)Z
U不够密实的感觉。当?dng)q和GNOME的设计哲学不无关p,不过q不是本文主旨,׃深入讨论?jin),q入正题讲讲如何调整Eclipse?wi)状列表的显C密
度?br />
ZGTK+2.0的程序在启动时会(x)到用L(fng)home目录找GTK+2.0的配|文Ӟ即~/.gtkrc-2.0QUbuntu下默认没有这个文Ӟ需要我们自己创建。打开你习(fn)惯的~辑器,加入如下代码Q?br />
style "eclipse" {
(tng) font_name="Sans 8"
(tng) GtkTreeView::vertical-separator=0
(tng) GtkTreeView::horizontal-separator=0
}
class "GtkTreeView" style "eclipse"
重启Eclipse应该p看到效果?jin)。如果你惛_得更dQ对所有常用的GTK+2.0控g都开刀的话Q可以这样写Q?br />
style "gtkcompact" {
(tng) font_name="Sans 8"
(tng) GtkButton::default_border={0,0,0,0}
(tng) GtkButton::default_outside_border={0,0,0,0}
(tng) GtkButtonBox::child_min_width=0
(tng) GtkButtonBox::child_min_heigth=0
(tng) GtkButtonBox::child_internal_pad_x=0
(tng) GtkButtonBox::child_internal_pad_y=0
(tng) GtkMenu::vertical-padding=1
(tng) GtkMenuBar::internal_padding=0
(tng) GtkMenuItem::horizontal_padding=4
(tng) GtkOptionMenu::indicator_size=0
(tng) GtkOptionMenu::indicator_spacing=0
(tng) GtkPaned::handle_size=4
(tng) GtkRange::trough_border=0
(tng) GtkRange::stepper_spacing=0
(tng) GtkScale::value_spacing=0
(tng) GtkScrolledWindow::scrollbar_spacing=0
(tng) GtkExpander::expander_size=10
(tng) GtkExpander::expander_spacing=0
(tng) GtkTreeView::vertical-separator=0
(tng) GtkTreeView::horizontal-separator=0
(tng) GtkTreeView::expander-size=8
(tng) GtkTreeView::fixed-height-mode=TRUE
(tng) GtkWidget::focus_padding=0
}
class "GtkWidget" style "gtkcompact"
]]>
JRuby can save Swing
JRuby cannot save Swing
Groovy can save Swing
挺有的Q推荐大家有I一诅R?br />
]]>
真正让XML发光的用途是什么?写配|文Ӟ数据交换Q数据存储?
]]>
今天dq篇文章Q原来和我想?/a>一?/a>Q不qDROq个提法的提法比我提炼的要更好,呵呵?br/>
]]>
在很多开发团队,大家l常在一赯论具体的技术和设计Q这很有必要Q有时也不可避免。但是也许Joel Spolsky说的对,软g设计很难Q但是比设计软g更难的,是同整个team一赯计Y件。做技术的Q对于自׃(jin)解、掌握、做q、尝试过的东西,对于自己熟?zhn)和信ȝ东西Q多多少有些偏袒,而对于新的、自׃?jin)解、不熟?zhn)的东西,则难免?j)存疑虑。这难怪很多设计讨Z(x)最l很难达成一致。这个时候,要么由技术上的最高权威直接拍板,定下来是什么就是什么,要么分歧双Ҏ(gu)多方各自陈述Q然后由目外部的实体进行独立仲裁?/p>
我看好开源框Ӟ其是那些经q考验q泛被采用的框架Q因为相比自制框Ӟ它们有着更大的优ѝ?/p>
如果你用Firefox或Operaq且看到?a href="http://www.aygfsteel.com/sean/archive/2007/01/25/96060.html" target="_blank">上一随W?/a>?abbr title="What You See Is What You Get">WYSIWYGq一个词Q你可以看到它下面是用一串点标注出来的,如果你鼠标?zhn)停在上面Q会(x)有工hC?What You See Is What You Get"。HTML源代码是:
<abbr title="What You See Is What You Get">WYSIWYG</abbr>
可惜微Y的IEq不能正renderq个tagQ尽它是标?X)HTML的一部分?/p>
http://www.garrettdimon.com/archives/aspnet-vs-front-end-architecture
该文作者细C(jin)他在使用ASP.NETq行开发的q程中遇到的6点不爽的地方Q主要都集中在前台架构上Q包括大量内联的风格标签、不同浏览器生成不同面代码、失败的标记设计、缺乏语意一致性、服务器端label和客L(fng)label的脱节、服务器端ID和客L(fng)IDp{等。尤其当你想使用标准的CSSQ构建数据结构和表现分离的清晰页面时QASP.NET的一些默认的内部处理可以让你对ASP.NETZq样做完全无语。比较有的是本文后面的回复Q其中有不少与楼d病相怜的|友Q还有来自微软员工的为ASP.NET辩护的声韟?/p>
我一直对MS在很多设计思\和决定上?j)存疑虑Q不明白Z么MS是要自成风格搞自己那一套蹩脚的所?规范"?标准"Q似乎在鼓励大家follow一个ƈ不清晰、多有些杂无章的设计架构Q其实ؓ(f)?jin)方便它实现更cool?abbr title="What You See Is What You Get">WYSIWYG开发工兗就拿今天来_(d)本来我们目定义好所有模块都按BO和UI分开QBO里面的类和UI里面的类各施其责Q原则上UI依赖BOQ而不是反q来Q按照我的理解和期望QW(xu)indows.Forms命名I间应该是由UI层来依赖Q而非BO层。很昄Q因为我们的form都放在UI层,肯定是依赖Windows.Forms?jin),而我们尽可能把所有业务逻辑代码攑ֈBO层。但是ؓ(f)?jin)?f)时实C个文本文件Ş式的logQ因为我们的业务逻辑代码都在BO层,所以ؓ(f)?jin)记录有意义的logQ我们的log逻辑自然而然只能攑֜BO层。但是一个基本的获取E序q行路径的方法属于System.Windows.Forms.Applicationc,让我们不得不using System.Windows.Froms。这其实q好Q我们也怸应该强求Windows.Forms一定就是只针对UI上的应用。问题是你每天都在面对类似的情况Q每天都或多或少在和.NET API和框架其他部分在打架Q当你?NET的API旉久了(jin)Q自然而然你就被它带到它的那一套思\中,你的设计也就自然而然跟着它走?jin),业务逻辑和UI逻辑交织在一P当你回过头来x(chng)层次理清理顺已经成ؓ(f)Mission:Impossible。因为抛开MS推荐的方式,自己实现一套自认更清晰的架构,相较"官方"的blueprint设计Q代价实在有些高?/p>
所以虽然我没有真正开发过ASP.NETQ尤其是2.0版,但我很能理解他们遇到的尴?/p>
String str = ...
if ("".equals(str)) {}