Category: 未分类

  • 葱白

    前些天 Kaven 写了一篇文章 “JavaScript大牛:Douglas Crockford“。过了几天,大牛 Douglas Crockford 跑过来看,真是仔细,不光看文章,还翻到下面的评论,对这句话产生了强烈的好奇心:

    不​​得​​不​​说​​,​​我​​葱​​白​​他​​。

    于是大牛就到处找翻译,Yahoo/Google 的翻译都很糟糕——你能想象有翻译软件能搞对这句话吗?令人惊讶的是,微软的 Windows Live Translator 竟然给翻译出来了!

    大牛显然是谦虚中有睿智,睿智中有自信,认定微软是正确的。

    我一位同学又试了一下这句网络语言:“我稀饭你”,结果它又翻译得不错——”i’m crazy about you”. 让我葱白一下微软!

  • return 一个空的集合,而不是 null

    想想几天前的天气,阳光明媚,万里无云,真是让人有辞职的冲动。到了这个小假期,似乎人间的幽怨又郁积起来,天地转入混沌,一篇迷茫。我决定窝在家里,学点东西。

    这个话题对于程序员来说是家常便饭,设计许多函数、方法的时候都会遇到。实际上这是极其基本、极其容易理解的一个问题,不过有些人还没有意识到,仍然随意乱写。拿 Java 举个最简单的例子:

    [code lang=”java”]
    public List getTopUsers(int limit) {
    if (limit < 1) {
    return null;
    }
    // …
    }
    [/code]

    这个例子里首先判断传入的参数 limit,如果它小于 1,那后面的工作就不需要了,这里用了 return null 来处理这种情况。这个方法可能在许多地方被调用,每次调用结束,都要判断一下返回值是不是 null,如果不是 null,才可以进行正常的处理。这是多么繁琐的事情。

    [code lang=”java”]
    // The tedious way:
    List topUsers = xxx.getTopUsers(limit);
    if (topUsers == null) {
    // …
    } else {
    for (…) {…}
    }
    [/code]

    推荐的做法是返回一个零长度的 List,这样调用该方法结束后,无需判断返回值是否为 null,直接对其进行循环。不过是 return new ArrayList(0) 吗?尽管这种返回情况几率不是太大,但是每次创建一个新对象总是让人很不爽。幸好,Java 的标准库设计者已经在 Collections 类中放了一个空的 List 常量 EMPTY_LIST,除此之外,还有 EMPTY_MAP, EMPTY_SET,真是贴心。我相信主要还是集合类自己的实现代码中有很多地方用到了它们。于是,我们把 return null 改成 return Collections.EMPTY_LIST.

    这里正好找到一个 Effective Java™ Programming Language Guide 的样章,讲的是 “Return zero-length arrays, not nulls”,基本上是一样的道理。Java 本身没有的空集合常量,我们可以自己定义嘛……事实上在我没有发现 Collections.EMPTY_LIST 的时候,我一直在自定义自己的 EMPTY_LIST 常量 🙂 不过注意一下该文中是怎么通过带参数的 List.toArray 方法去利用那个数组常量的,具体参考 Java 文档中的解释

    这是一个最基本的好习惯,让你的代码更整洁,而不会影响性能。鄙人还很弱,不过觉得一个优秀程序员的最基本素质是享受写代码的过程和代码本身,顺便享受其结果。

    这里有一本 NetBeans API 设计者写的 Practical API Design: Confessions of a Java Framework Architect,我比较希望读一下。不过这种书中估计不会讲本文这么小儿科的东西的。

  • 设想一下网络身份的高效管理及利用

    使用网络服务的目的,应该是利用它们高效、及时地交流有用的信息,获取和分享知识,能够结交到志同道合的朋友也是非常好的事情。

    前阵子有不少朋友加了我 Gtalk. 最近我也在不断地通过 Google reader 中朋友们的分享扩大自己订阅的范围,新加了不少优秀 blogger 的 RSS. 很多人会在 blog 上留下自己的 twitter 帐号,我如果发现有价值就会 follow. 另外 Fenng 当前正在进行他的每日推荐一位推友计划,也让我收获不少。

    问题

    现在一个比较烦恼的问题是,这些人在不同的网站有不同的身份,没有一种机制很好很方便地将它们关联起来。举个不太恰当的例子,Fenng 的 blog 叫做 “DBA notes“,而 twitter 账户名就是 Fenng. 当然了,Fenng 的名气比较大,一般不会搞混的,并且 blog 的 RSS 输出中也包含了作者名,所以说举这个例子不是太恰当。对于普通人,可能就很难讲两个账户关联起来。有时候在 twitter 上看到一条引人注目的 tweet,都想不起来这是谁,还得到他的 twitter 主页去看,如果上面有 blog 链接还好。有时候某人接连几个月没有更新 blog,猛然更新一下,在 Google reader 里是很陌生的感觉,假如 blog 里没有个 about 页面,说不定还真想不起来这是谁。对了,我也希望把 Flickr 的账户也关联一下。

    我虽然关注 web 发展比较多,但是真正在使用的服务还是很少的,现阶段主要也就是 Gtalk, Google reader, twitter. 那些重度 SNS 用户,可能同时在使用的还有 Facebook, LinkedIn… 一大堆,我就懒得列出来了,对于这些人来说,这么多种服务上的朋友们肯定重叠的几率特别大,但是到底有几个朋友的行踪是自己熟悉的呢?twitter 上有位朋友发了一句话,我希望能够以最快的方式知道他是谁,我以前对他的看法,他还在网络上其它什么地方发布有价值的信息。

    friendfeed 我用得不多,但是感觉它不能解决我的问题,我似乎没有选择的余地,要么订阅他的全部,要么什么都不要。目前我在 Gmail contacts 里整理了一些联系人,有的怕忘记,在 notes 字段里写一段描述。仅此,并不是很方便,我几个月可能用到一次。

    设想

    最近似乎老是听到有人谈 “CRM”,地铁里也时不时有哥们聊这个。我就很惭愧了,我知道它的字面意思,却不知道自己对它的理解在什么程度。这里我就以自己粗浅的理解来类比一下。商家需要管理客户的信息,要知道客户什么时候在自己这里消费,抛开隐私问题不谈,他们甚至想知道你在别的地方消费了什么,每天都在干嘛,从而提供更好的服务(也就是诱导再次消费,获取更多利润)。在线下交友的时代,朋友关系用脑子管理就行了。我知道邻居或者同事张三在哪儿工作,闲暇时间喜欢干嘛,过些天要到哪儿去旅游。然而通过网络结交的朋友(或者是关注的人,可能这一类更多),动辄数十上百,大脑就不够用了。于是我们是不是也应该模仿 CRM,来个网络关系管理呢?因为面对的就是网络,没有线下的流程,肯定会比 CRM 更流畅、更方便。

    其基础肯定是一个类似 Gmail contacts 的东西,传统的地址、电话号码也很重要。在这里应该可以给每个联系人关联其 Email, twitter, blog, facebook 等任意账户(链接),可以加自己的备注(以评论的方式最好,一条一条分开)。如果仅仅做到这一步,简直是太容易了,Gmail contacts 差不多已经是这样了。不知道是不是已经有这样的专门产品,我就懒得去找了。

    最关键的,是怎么让用户为这些朋友定义好的账户关联实时地发挥作用。我能想到的一些情景:

    • 查看邮件时,界面右侧可以显示发件人最近的 blog 更新、最新的 tweet
    • 在 Gtalk gadget 中聊天,可以显示为对方关联的信息
    • 查看某 twitter 用户首页,可以显示为对方关联的信息。甚至可以将 twitter 网站上的所有头像改造成 flickr 那样,悬浮并点击时获取数据。
    • 在 Google Reader 中阅读时,可以根据地址栏中的 feed url 获取关联的信息
    • Facebook, flickr, 只要是浏览器中可以访问的个性化服务,都可以加上上述的功能

    具体的实现方式呢,可以视情况而定。比如界面比较空闲的,可以直接显示一些详细信息(blog post, tweet, photos…)。像 Google Reader 这种满屏都是内容还嫌地方小,就应该找个地方显示一个小图标,点击之后再显示详细信息,具体显示什么,用户都可以定制。

    只要提供了 API,这些都不是难事。Greasemonkey 或者 Firefox addon 都可以比较方便的实现这些功能。

    也许现在已经有这样的产品,只是我太闭塞了没有发现?呵呵,如果没有的话,建议有空的人能够实现类似的东西。我的想法比较杂乱,不过也许将来我会整理一下思路,自己做这么个东西……

    在虚拟的网络中把握住现实的东西,才不会迷失自己。

  • Web 开发之基本功

    我感觉有些人学了 PHP 再学 ASP.NET 又学 J2EE,学了 struts 1.x 学 2.x,每学一种新的 web 开发技术都像是学一种完全陌生的技术一样。

    实际上这么多种语言、框架并存,各有各的优缺点。然而所有这些语言、框架的基石,都是 HTTP 协议。最起码的,一个 web 开发者要知道,它是无状态的 (stateless)。客户端向服务器发起请求,通常是 GET/POST 方式,服务器通常返回一个 HTML 文档,有时候就是随意一种格式(比如图片、二进制或者纯文本)。HTTP 协议需要特别注意的地方还包括缓存 (cache control) 以及跳转 (301/302) 等。

    我觉得,框架应该是归纳整理重复性的劳动,吸纳优秀的设计模式,而不是努力掩盖 HTTP 协议的本质。对 Web 开发者掩饰 web 的本质,是非常邪恶的一件事情。ASP.NET 就一直不遗余力地朝着这个目标发展,硬要把桌面程序的编程模式搬到 web 开发上来,Windows form、web form 的概念混为一谈,毒害了无数无辜的程序员。程序员接触到新的开发环境时,很可能到处碰壁,满地找牙(这个牙,可能就是 ASP.NET 给装的假牙——Event)。前段时间看了一下 Tapestry,发现该项目的老大有和 ASP.NET 类似的理念,按照他的说法,页面上的链接宁可在服务器端被 OnClick 处理一下然后 302 redirect,也不舍得直接指向实际的链接——声称这样更符合思维习惯。看到这个,我就明白了为什么 JavaEye 上有人惊呼,Tapestry 有点像 ASP.NET 啊,真好!说实话,看到这样的赞美,我就慌了。要 Tapestry 是我写的(假设而已,我现在还没这个能力),我就会反驳:“你才像 ASP.NET 呢!你们全家都是 ASP.NET!”.

    同志们,看清本质吧。web 开发真正的核心是 HTTP 协议,至于 Java 还是 C# 还是 PHP,它们只是服务器用来生成发送给客户端的那个 HTML 或其它格式的文档用的。尽管它们会影响到程序性能、开发速度等诸多方面,但是如果你连 HTTP 协议都不了解,即使使用的语言、框架再好、再高性能,也如同把一座钢铁大厦建在流沙之上。

    等了解了 HTTP 协议,再往上看哪种语言更适合 web 开发,哪个框架更好。否则就像是农民还没搞清楚土壤成分就随便种庄稼一样,收成是好不了的。

  • Google Reader 也有 twitter 功能

    google-reader-share

    点击 Google Reader 左侧栏最上面一块中的 “Your stuff” 链接,即可看到类似上图的界面。我这个截图是在点击了 “Show Options” 链接之后的情况,默认只有一个输入框,没有标题、tag. 这不就是 twitter 吗?呵呵。

    我是昨天才发现 Google Reader 还有这么一个功能,平常我也就点点 share 按钮,分享些自认为有用或有趣的东西。看到这个界面上那个 bookmarklet 了吧?使用它可以分享任意一个链接,即使它不在任何一个 RSS 中。

    另外 Google Reader 最近刚刚发布了 comments 功能,许多人欢呼雀跃,我却觉得没啥用处。虽然将某 item 的 comments 汇集到一起容易造成信息泛滥,但是分散在各个 share 中形不成规模,不利于思想的碰撞与融合,这样更不好。

    如果 Google Reader 能够像某些 RSS 阅读器那样让 blog 作者们 claim 自己的 RSS,然后看到所有在 Reader 中收到的评论,那是多么好的事情。我想许多读者也想在 Reader 中直接与作者交流,而不需跑到该 blog post 的页面。这牵扯的东西又太多了,如果这样,blog 的流量可能大减,等等。

    Reader team 的 blog post 说 “We have much more planned for this feature”,让我们拭目以待吧。

  • 用 Firefox 快速搜索

    本文分享一下我在 Firefox 中使用搜索引擎的经验,希望对朋友们有所帮助。

    se-bar

    Firefox 界面右上角的搜索栏可是我严重依赖的东西。我不会先打开 google.com 然后再输入关键字搜索。不管你在做什么,有东西要搜索的时候,只需按下组合键 Ctrl+E 或者 Ctrl+K,焦点就会定位到搜索栏,输入你的关键字,回车,搜索结果就列出了。你可能不希望搜索结果在当前页面打开,很简单,在 Ctrl+E/Ctrl+K 之前按下 Ctrl+T,新建一个 Tab 就可以了。还有一个更便捷的方式是不用事先新建 tab,输入关键字之后按 Alt+Enter,搜索结果会自动在新 tab 页打开 (Alt+Enter 同样适用于地址栏)。

    如何快速使用非默认搜索引擎搜索?

    点击搜索栏左侧的小按钮打开搜索引擎列表,然后点击最下面的 “Manage Search Engines…”,选中你需要使用的搜索引擎,然后点击右侧的 “Enter keyword…”,输入一个关键字,越短越好,一个字母就足够了,如下图所示:

    se-manage

    依我之见,默认的 Google 就不需要设置 keyword 了。keyword 有啥用呢?举个例子,我给 Wikipedia 的搜索引擎指派了关键字 “w”,那么在地址栏 (location bar) 输入 “w Java” 然后按下 Alt+Enter,就会在新 tab 打开 wikipedia 的搜索结果(实际上是直接 redirect 到 Java 词条的页面)。

    还不知道怎么快速定位到地址栏?至少有三个快捷键:Alt+D/F6/Ctrl+L

    搜索指定版本的 Java 文档

    比如 Java 6,可以到这个页面去安装对应的搜索引擎。安装之后给它分配一个关键字 “j”,就可以像上面说的一样快速搜索 Java 文档了。

    实际上安装的搜索引擎只是在你的 Firefox profile 文件夹的 searchplugins 子目录中保存了一个文件。一般的路径是:
    C:\Documents and Settings\[USERNAME]\Application Data\Mozilla\Firefox\Profiles\[PROFILE NAME]\searchplugins

    打开刚刚安装的 Java 6 文档的 search plugin 描述文件可以看到,它实际上是借助 Google 的 site search 与 “I’m feeling luck” 来实现的,搜索 url 的模板是:
    http://www.google.com/search?sitesearch=java.sun.com/javase/6/docs/api/?sourceid=Mozilla-search&btnI=I’m Feeling Lucky&q={searchTerms}

    看到这个,你肯定知道怎么自己创建其它版本 Java 文档的 search plugin 了。如果有多个版本,你可以分别指定j4/j5/j6作为关键字。

    假如没有这样的 search plugin,我想找 String 类的文档,得在 Google 中输入 “Java 6 String” 回车,然后再点击结果中的第一条。有了它,只需要在地址栏输入 “j6 String” 回车,String 类的文档页就直接打开了。

    各位还有什么可以补充的?呵呵。

    附:Firefox keyboard shortcuts

  • 收到了咔嚓鱼的免费杯子

    杯子是免费的,不过要5元运费。本来我也没太大兴趣做个印着照片的杯子,不过去年年底的时候买了个麦当劳的优惠卡,送一张咔嚓鱼的优惠券,可以免费得到一个拼盘照片马克杯,只需支付5元运费,还不错。这个杯子好像原价要三十多块呢。

    上周末我才打起精神翻看我的照片,从里面找了几张看起来还可以的——那么多照片,想找几张能拿出来看的,还真是不容易啊,由此说明,数码代替了胶片造成了照片平均质量的大幅下滑。

    大致的步骤:

    1. 首先上传要印在杯子上面的照片
    2. 然后按照优惠卡上的地址去输入优惠码
    3. 成功后就得到了优惠产品的链接
    4. 顺着链接点过去,选择照片,定制杯子样式,最后 checkout
    5. 在订单信息那一页下面有个填写优惠码的地方,比较容易迷惑人(如果优惠码填写在这里,是会报错的),实际上不要理会这个字段,空着它点击继续,在下一步结算的时候就可以发现咔嚓鱼已经把优惠计算进去了,最后账单总额是5元。

    然后就等着收杯子吧。我是15号下午订制,17号就收到了,速度很不错。而且包装也相当安全,里面是两块为马克杯量身定做的模具一样的细泡沫塑料,外面还有一层泡泡纸——这天下班回来的路上我就是靠挤爆泡泡消磨时间的,哈哈。

    杯子实际上也就放在那儿当个摆设,像我这么能喝水的人,那一杯还不够我一口喝……

    话说惠普为这个咔嚓鱼的推广真是费尽心机,免费冲洗,免费杯子,但是用户享受完免费的服务,还会接着去买东西吗?至少我没太大的需求。

  • Web framework 过度集成 JavaScript/Ajax

    前文提到 Matt Raible 在比较 Java web framework 的时候有一个重要的指标(他将之排在第一个):

    Ajax Support: Is it built-in and easy to use?

    与 JavaScript 有关的指标还有一个:

    Validation: How easy is it to use and does it support client-side (JavaScript) validation?

    我个人却觉得服务器端的框架不应该对 JavaScript/Ajax 如此高度地集成,它们毕竟是客户端的东西。程序员必须有清晰的概念,什么是服务器,什么是客户端,它们之间是怎么交互的。微软的 ASP.NET 做了一个很不好的表率,将 web 开发用 Windows 桌面程序开发的理念来进行,迷惑了不少程序员——就连官方翻译 “Form” 成中文也是“窗体”,真是不伦不类。而程序员需要深究其运行机制的时候,就不得不折腾 POSTBACK 那一坨屎了。Ajax 开始流行之后,微软又不失时机地在 ASP.NET 加入了 Ajax 的控件,广受那些喜欢拖拖拽拽像搭积木一样“编程”的程序员的欢迎——这就是 “The Microsoft way”.

    Ajax 从概念上讲是革命性的,但在技术角度上说,了解 JavaScript 再去掌握 Ajax,就好象学会了 Java 再去学集合类怎么用一样简单。Ajax 技术被炒得神乎其神,以至于大家的简历上不得不再加一条“精通 Ajax”,一部分原因可能就是框架的集成使其神秘化,并且使大批程序员不愿或不敢去看它的真实面目。真要问问 Ajax 异步更新的下面是怎么回事,估计 80% 的人不知道。

    在 Tapestry 5 解释其 JavaScript 集成的 wiki 页面中,开头就写:

    Modern frameworks, and perhaps none more aggressively than RoR, go a long way in removing the pains of JS from developing web applications. Tapestry 5 is no exception and even though it is currently in the beta stages, it has come along way in making JS transparent to developers (not to mention 3rd party libraries like tapestry5-components).

    从这段文字可以看出作者对 JS 的集成多么自豪。然而 making JS transparent, 可能吗?当然你以 demo 一下透明是多么的酷,多么炫。不过做一个框架出来不是 demo 用的,而是要为实际环境中的程序做基础。实际应用的时候,用户不可能像 demo 的那样顺利地完成任务,遇到问题的时候还是得去看 JavaScript 怎么执行的,Ajax 是怎么个机制,所以真正的透明是 100% 不可能的。我认为,本来很小很简单的一个技术被集成到 web 框架中,一定程度上增加了调试、调优的难度,得不偿失。

    另外,Tapestry 的表单验证做到了一处配置,客户端、服务器双重验证。这一点本来不错,但它用了一种比较花哨的方式来显示错误信息——在出错的字段上冒泡。而且这种方式在某些情况下会出问题。这一定是作者的个人喜好,demo 起来大家一定觉得很酷。但实际使用的时候,很大的概率是这种 UI 与应用环境的 UI 格格不入,你还得想办法 tweak.

    框架的目的应该是总结设计模式,减少重复劳动,而不是集大成于一身就好了。从这一点上说我倒是挺喜欢 struts 1.x 的,你完全可以控制作为响应发送到客户端的 HTML 代码。Tapestry 则不然,默认插入的 CSS,表单页面不可避免的 JavaScript……

    Matt Raible 的 presentation 中谈到如何选择框架的时候,有一句话 “Eliminate, Don’t Include“,我觉得不仅仅适用于如何选择框架,同样适用于框架的设计者如何选择 feature set.

  • Java web framework 之选择

    homer

    相比 PHP, Ruby, Python 等语言,用 Java 来做 web 开发面临着太多的选择。不过也许正因为 Java 的选择更多,所以才有更多的人选择 Java?这一点不能确定。来这里看看,光是持久层的 ORM 工具就有这么一大坨。当然这里面还是 Hibernate 为王,这个选择比较容易做。

    然而到了表现层,虽然框架不是那么多,但是选择起来可不容易。每个框架需要评估的方面至少包括性能、学习/开发速度、可维护性、用户群体 (community) 等。

    Matt Raible 曾经对 Java web framework 们做了比较 (PDF 下载,建议右键另存为),我觉得这个 presentation 可以从39页开始看。第43、43页的建议和 tips 非常有价值:

    • Don’t believe blogs and articles – 也就是说,该 presentation 39页之前的内容要谨慎对待 🙂
    • Try it yourself
    • Believe developers, not evangelists
    • Believe developers that are experienced with the framework and have used it in production
    • Beware of corporate interests – they can twist marketing
    • Books are a good sign

    如何选择呢?”Pick 2-3 frameworks for your type of application… and prototype! If prototyping is painful, switch.” 嗯,不要仅仅看各种派别的人整天在那争论孰优孰劣,虽然他们的争论很有价值,但是每个框架都有自己的优点和缺点,甚至有些优缺点是主观的。你选择的框架应该在你的项目环境(项目本身以及团队情况)中扬长避短,将优势发挥到最大。”You should try a framework before dissing it!”

    其实我是在考虑 struts 1.x 与 Tapestry 5 的取舍,所以才在网上到处逛。TheServerSide 上就有不少争论,那阵势跟 vim 和 Emacs,Windows 和 Linux 阵营之间的争吵差不多,只是多数人还没有上升到信仰的高度。直到看了这个 presentation 之后我才开始考虑,对,做个简单的 Tapestry 程序,不就一目了然了吗?一直犹豫不决是因为我对 Tapestry 太不了解了。

    在这个过程中,我很快知道了 Tapestry 如何加入到一个 web 项目中,它是怎么接管服务器收到的请求,请求处理的流程,表单验证,以及最后返回给客户端的 HTML 代码。REST like 的 URL,非常简单的配置文件(相比 struts),灵活的 component 都是我喜欢的特性;然而在我看来它对 JavaScript 的集成有点过分,绑定了 Prototype/script.aculo.us。

    回到 Matt Raible 的 presentation,他提出的比较标准中有一条是 Ajax Support (18页),Is Ajax support built-in and easy to use? 说实话,我非常不喜欢 JavaScript/Ajax 被集成到一个服务器端的框架中。(+) 本来我是想在这扯一大段的,不过想了想可以另外扯出一篇文章来凑数,哈哈。

    很可能我将选择 Tapestry 来开始新的项目,但我 90% 的可能不会使用其 Ajax component,另外 10% 的可能是它的实现真的很棒。

    struts 1 太老了,它之所以仍然流行是因为其庞大的用户群体。有些比较让人烦的问题,比如除了配置文件之外,其请求处理流程使得使用 oscache 这样的页面缓存变得不那么顺手。但是我非常喜欢它丝毫不入侵客户端这一点,它做了一个框架应该做的事情,不多也不少。webwork 过继给 struts 的 struts 2 我个人非常不喜欢,配置文件仍然是一大坨,非常之杂乱,action class 也很乱,也想将魔爪伸向客户端的 JavaScript(ajax taglib) 与 CSS(theme)——我可能存在误解,因为我仅有的 struts 2 经验是在别人的一个项目中帮忙,可能是团队成员的问题。

    不出意外的话 Tapestry 就是我的选择了,我将在这里分享自己的使用经验与心得。

    P.S. 我非常希望交几个 Java web 方面(甚至 PHP/Python/Ruby)的朋友,没事的时候请教一些问题,有意请联系我 Gmail/Gtalk: zhouqb (89.9% uptime guarantee during work hours)

  • Trac 与 Redmine

    Trac is an enhanced wiki and issue tracking system for software
    development projects.

    Redmine is a flexible project management web application.

    实际上 Redmine 应该是 Trac 的 clone,基于 RoR. 它们都是对项目开发、管理非常有帮助的系统,可不仅仅是 bugzilla +
    wiki,Timeline 这个 feature 将 bug tracking system, wiki,
    以及版本控制系统的最新动态整合起来,让你一眼看到项目的最新进展。

    我用 Trac 多一些,现在也在用,也更倾向于 Trac,而 Redmine 只是短暂地用过一段时间,下面简单地对二者的重要特性做一下比较。实际上
    python/ruby 我都不熟悉,所以下面的比较如有错误请多多指教 🙂

    svn 支持

    • Trac 只支持本机,通过 python 直接读取目录中的数据

    • Redmine 是通过正常方式(http/svnserve之类)访问,支持远程代码库,不过要实现在 timeline 中实时看到最新的代码
      commit 比较麻烦一点

    多项目支持

    • Trac 可以在 Apache 中配置某目录的子目录全部为 Trac project,但是实现它们之间的综合管理比较麻烦

    • Redmine 原生支持多项目,管理比较方便

    用户管理

    • Trac 和 svn 一样自己基本不实现用户认证机制,主要依赖 web server 或其它认证机制

    • Redmine 有完整的用户注册、登录及角色权限管理

    多语言支持

    • Trac 的 i18n 做得不好,据说有许多字符串直接写在代码里

    • Redmine 支持多语言较好,已经有许多翻译。不过根据我使用 Redmine 的经验,中文翻译质量一般

    甘特图、日历、ticket 进度、time tracking 这些特性都是redmine独有的。

    P.S. 建议大家看看 Fenng 的网站运维之道 之知识管理与积累

    http://trac.edgewall.org/wiki/TracMultipleProjects/ComprehensiveSolution