制造开源软件

如何成功运营自由软件项目

Karl Fogel


题词

这本书献给我的两位好朋友,我不可能忘掉他们:Karen Underhill和Jim Blandy。

目录

前言
为什么写这本书?
谁应该读本书?
资料来源
致谢
免责声明
1. 介绍
历史
私有软件和自由软件的兴起
“自由”还是“开源”
现状
2. 起步
从你所拥有的开始
选择一个好名字
有一份清楚的使命陈述
声明项目是自由软件
特性和需求列表
开发状态
下载
版本控制和Bug跟踪访问
沟通渠道
开发者指南
文档
输出和屏幕截图实例
包装主机
选择许可证并应用
“可以做任何事情的”许可证
GPL
如何为你的软件应用许可证
设置风格
避免私下讨论
防无礼于未然
实践明显的代码评审
将一个封闭项目开放时,对于改变的影响要格外敏感
通告
3. 技术基础设施
一个项目需要什么
邮件列表
垃圾邮件防护
身份和头管理
伟大的Reply-to辩论
归档
软件
版本控制
版本控制词汇表
选择一个版本控制系统
使用版本控制系统
Bug跟踪
与邮件列表交互
Bug跟踪的预过滤
IRC / 实时聊天系统
机器人(Bots)
归档IRC
RSS供稿
Wikis
网站
包装主机
4. 社会和政治的基础架构
慈善独裁者
谁可以成为一个慈善独裁者?
共识为基础的民主(Consensus-based Democracy)
版本控制意味着你可以放轻松
如果无法达成共识,那么表决!
何时表决
谁进行表决?
民意调查与表决
否决权
写下所有的内容
5. 金钱
参与的类型
长期雇佣
作为一些个体出现,而不是一个整体
公开你的动机
钱不能让你可爱
契约
评审和接受变更
资助非编程活动
质量保证(也成为专业测试)
法律建议和保护
文档和可用性
提供主机/带宽
市场营销
记住你正在被注视着
不要痛击竞争开源产品
6. 交流
人如其文
结构和格式
内容
基调
识别无礼
面容
避免常见的陷阱
不要发表无目的的文章
多产VS非多产的线索
主题越软,辩论越长
避免圣战
“吵闹的少数派”效应
刺儿头
处理刺儿头
案例学习
处理成长
归档的显著使用
编制法律的传统
Bug跟踪系统中无对话
公开性
声明安全漏洞
7. 打包、发布和日常开发
版本号
版本号组成部分
简单策略
奇偶数策略
发布分支
发布分支的技巧
稳定发布版本
发布所有者独裁
变更表决
打包
格式
命名和布局
编译和安装
二进制包
测试和发布
候选发布
宣告发布
维护多发布线
安全发布
发布和日常开发
计划发布
8. 管理志愿者
从志愿者中获取最多
委派
赞扬和批评
防止割据
自动化率
将每个用户当作潜在的志愿者
像分担技术任务一样分担管理任务
补丁管理员
翻译管理员
文档管理员
问题管理员
FAQ管理员
转化
提交者
选择提交者
收回提交权限
部分提交权限
休眠提交者
避免神秘
荣誉
分叉
处理分叉
初始一个分叉
9. 许可证,版权和专利
术语
许可证的方面
GPL和许可证兼容性
选择一个许可证
MIT / X Window System License
GNU General Public License
那BSD许可证呢?
版权分配和所有权
无为而治
贡献者许可证协议
版权转移
双许可证模式
专利
深入资源
A. 自由版本控制系统
B. 自由Bug跟踪系统
C. 为什么我要关注车棚的颜色?
D. 报告bug的样例指导
E. 版权

前言

为什么写这本书?

在聚会上,当我告诉别人我写自由软件时,人们不再是一副茫然的表情。他们会说,“哦,开源软件—就像linux?”我使劲地点头:"对!我就是做那个的。"不再被凉在一边的感觉真好。要在过去,下面的一个问题通常会是这个:“你靠那个怎么挣钱?”为了回答他们,我必须概述开源软件的经济学:有一些组织对某个特定软件的存在感兴趣,但他们不需要卖拷贝,而是确保这些软件能够免费获得并且有人维护,能够作为工具而不是商品使用。

然而之后的问题不再总是同钱有关。开源软件[1]的商业案例不再是如此神秘,许多的非编程人士已经了解到—或至少不再惊奇—确实有一些人被雇佣全职做开源。于是,我越来越频繁地被问到的第二个问题是:“那么,开源软件是怎么运作的?

我手头没有现成的满意的答案,更困难之处在于当我试图给出一个时,我意识到它是一个多么复杂的题目。运行一个自由软件项目完全不同于商业运作(想像一下必须时常同大部分你从未谋面的志愿者们商讨产品的特性的情景! )。由于某些原因,也和传统的非盈利组织不同,也不同于一个政府。与上述事物有许多相似性,但我渐渐得出了一个结论,自由软件是独一无二的。有许多事情可以与之比较,但没有一个与之完全等同。实际上,即使对于自由软件项目可以“运行”的假设也是一种引申。一个自由软件项目能被开启,并且会受到对此感兴趣的团体的强烈影响,而且它的资产不属于任何一个个人或团体,会源源不断从某些地方冒出对此感兴趣的人,所以它不会被—任何人—单方面地终止。每个人都有无限的权利,每个人又都没有权利。它形成了这样一种有趣的动态平衡。

这就是我要写此书的原因。自由软件运动已经进化出了一种独特的文化,一种信奉个人能够让软件做任何事情、自由为中心信条的思想,这种自由的结果并不是让每个人对代码各行其事,而是是狂热的合作。实际上,在合作中竞争也是自由软件运动中最有价值的技巧之一。管理这样的项目就是处理一堆庞大的合作关系,在这里个人能力不仅是和他人一起工作,而且包括通过一条崭新的合作方式对软件做出实际的贡献。这本书试图描述实行这种方式所需要的技术。它不会包含全部,但却是重要的起步。

优秀的自由软件本身就是极有价值的目标,我希望那些在本书中寻找创造成功软件方法的读者能够得到满意的答案。除此之外,我想传达那种纯粹的快乐,来自同充满活力的开源软件开发团队的合作,来自通过开源软件所鼓励的直接方式与用户的交流。成为一个成功的自由软件项目的一分子是有趣的,这才是驱动整个系统运转的终极动力。

谁应该读本书?

这本书是为那些着手开始一个开源软件项目,或已经开始但想知道现在该做什么的软件开发人员和经理们准备的。对那些打算加入一个开源软件项目,但是又没有经验的人,此书也是有所裨益的。

读者不必是程序员,但应该知道软件工程的一些基本概念,比如源代码、编译器和补丁。

无论是作为用户还是开发者,都不必具备开源软件的经验。那些之前在自由软件项目中工作过的人也许会发现这本书中的某些部分太浅显了,可能会想跳过这些章节。由于读者群的背景各有不同,我特别对各章节作了清楚的标示,以便读者可以适时跳过那些他们已经熟悉的内容。

资料来源

此书中的很多原始材料都是来自Subversion项目(http://subversion.tigris.org/)的五年工作。Subversion是一个从零开始的开源版本控制系统,目的在于替代CVS成为开源社区版本控制系统事实上的选择。这个项目由我的雇主CollabNet公司(http://www.collab.net/)在2000年初发起,感谢上帝CollaNet从一开始就正确理解如何将它作为一个分布广泛的合作性项目来运作。从一开始我们就吸收了很多的志愿者,现在这个项目有50多名开发者,其中只有少数是CollabNet的雇员。

在很多方面Subversion都是开源软件项目的一个典型例子,最终我在上面花费的精力远超出我最初的预想。另一方面也是出于便利:无论何时我需要一个现象的样本,我的脑海里便会立即浮现出Subversion中的一个实例。但这也事关验证。虽然我不同程度地参与了其他几个开源项目,并且会和很多的朋友和相关的人交谈,但我很快就发现,当写成文字时,所有的断言都需要经过事实的检验。我不想仅仅根据我读到的它们公开邮件列表上列出的文档而对事件发表意见。如果有人想用以上的方式尝试Subversion,我知道,她大约只有50%的正确率,而另外50%是错误的。因此,当需要从一个我没有直接参与的项目找寻灵感或者实例时,我会找一个我信任并且了解内情的人,让他来说明项目的真实情况。

虽然过去5年我一直在做Subversion,但我从事自由软件行业已有12个年头了。因而,其它一些项目也对本书有所影响:

  • 自由软件基金会(Free Software Foundation)的GNU Emacs文本编辑器项目,我在其中维护了几个小的软件包。

  • Concurrent Versions System (CVS)版本控制系统是我在1994–1995期间与Jim Blandy全力投入的一个项目,此后,我只是断断续续地参与这个项目的工作。

  • Apache软件基金会(Apache Software Foundation)的开源软件项目集,尤其是Apache可移植运行库(Apache Portable Runtime (APR)和Apache HTTP服务器。

  • OpenOffice.org 办公软件项目,Sleepycat软件公司的Berkeley Database项目,以及MySQL数据库项目;我个人并未参与这些项目的开发,但曾经对其进行关注,并在一些案例中与其开发人员进行过交谈。

  • GNU Debugger(GDB)项目(同上)。

  • Debian项目(同上)。

当然,以上并不是一个完整的名单。正如多数的自由软件程序员一样,我不定期地追踪自由软件行业中许多不同的项目,以对行业的整体情况有全面的了解。在此,我不一一列举所有的项目,但在书中会适时提及。

致谢

写作本书所耗用的时间是我原来设想的四倍,而在写作期间,无论我身在何处,总感觉到脑袋上仿佛悬挂着一台大三角钢琴。没有以下众人的帮助,我便不可能完成本书的写作而仍然保持精神正常的状态。

本书的编辑,O'Reilly出版社的Andy Oram是一个作家梦寐以求的编辑。他不但谙熟自由软件行业(书中的许多题目是他建议的),而且具有一种非凡的才能,那就是知道对方想说什么,而且帮助对方找到最佳的表达方式。能与Andy合作是我的荣幸。在此,我也要感谢Chuck Toporek,是他将本书的写作提议及时传给了Andy。

Brian Fitzpatrick在我写作本书的时候审阅了全部的内容,这不但使本书更完善,而且在我只想从电脑屏幕前面逃走,躲到世界上任何一个其它角落时,是Brian鞭策我继续写作。Ben Collins-Sussman和Mike Pilato也经常询问写作的进程,而且总是乐于讨论那一周我正在写作的任何题目,有时候那样的讨论需要进行很长时间。在我写作稍有懈怠的时候,他们也会注意到,并善意地加以提醒。谢谢你们,伙计们。

在我撰写本书的同时,Biella Coleman正在完成她的博士论文。她了解每天坐下来写作意味着什么,她既是鼓舞我写作的榜样,又能倾听我写作的苦衷。更能以一双人类学家的慧眼观察自由软件运动,给我提供了一些想法和参考资料,用于本书的写作当中。另一位人类学家Alex Golub那时候也在完成他的博士论文,而且他本人涉足自由软件行业,他在本书刚开始写作时给我提供了大量的支持,对我有极大的帮助。

Micah Anderson似乎从未因自己写作大部头而有压迫感,这真是令人憎恨而又妒忌的鼓舞,与他的友谊和交谈给了我很大的帮助,而且(至少有一次)他为我提供了技术上的支持。多谢你,Micah!

Jon Trowbridge和Sander Striker既给予了我鼓励也提供了具体的帮助—他们在自由软件行业中丰富的经验为本书提供了我不可能在别处找到的素材。

我要感谢Greg Stein,不仅因为我们之间的友谊和他适时的鼓励,更因为他向Subversion项目表明定期地代码评审对建设一个编程社区是一项多么重要的工作。我也要感谢Brian Behlendorf,他巧妙地告诫我们进行公开讨论的重要性;我希望这一原则贯穿了本书的始终。

感谢Benjamin “Mako” Hill和Seth Schoen与我进行的有关自由软件及其政治方面的若干谈话;感谢Zack Urlocker和Louis Suarez-Potts在百忙之中抽空接受我的采访;感谢Slashcode名单上的Shane允许我引用他的帖子;感谢Haggen So提供的有关制作完成的主页之比较,那极其有帮助 。

感谢Alla Dekhtyar、Polina以及Sonya给予我永不倦怠及耐心的鼓励。我真高兴我不必在我们的晚间聚会上提早告辞(或更确切地说,恋恋不舍地告辞)而回家去写“那本书”。

感谢Jack Repenning给予我的友谊、交谈、以及他固执地拒绝接受不费力气的错误分析,而不遗余力找寻正确答案的决心。我希望他在自由软件开发以及自由软件行业中长期而丰富的经验在本书中得以体现。

在本书写作期间,CollabNet极其慷慨地允许我采用一个灵活的工作日程,而当我需要的时间远远超出原先预计的时候,他们没有抱怨。我并不完全了解管理层在做这样的决定时考虑的个中细节,但我猜想Sandhya Klute,而后是Mahesh Murthy,均参与了这项决定—我在此感谢他们两位。

整个Subversion开发团队在过去的五年是我灵感的源泉,本书中描述的绝大部分内容都是我与之共事所得。由于人数众多,我在此不能一一列举他们的姓名,但是我恳请各位读者, 假如你有一天偶遇一位Subversion的开发人员,请为他买一杯他最爱喝的酒—我本人肯定要那样做。

我曾多次与Rachel Scollon胡言乱语,叙说写书的进程,而她总是乐于倾听,并且能够设法使问题大而化小。那对我有很大的帮助—多谢。

(再次)感谢Noel Taylor,他一定十分不解,为何我在上次频频抱怨之后又决定写第二本书,然而,Noel给予我的友谊,以及他领导之下的Golosá合唱团使我的生活即使在最忙碌的时节依然有音乐和好友相伴。我还要感谢Matthew Dean和Dorothea Samtleben,我的好友以及因我而饱受折磨的音乐合作伙伴,在我多次无法与之排练的时候,他们总是给予我极大的理解。Megan Jennings总是给予最大的支持,并对一个她并不十分熟悉的题目表现出真诚的兴趣—这对一个缺乏信心的作家来说无异于一剂定心丸。多谢了,我的老友们!

本书有四位学识渊博而又兢兢业业的评审者:Yoav Shapira、Andrew Stellman、Dayanum Srinivas和Ben Hyde。假如我能全部采纳他们提出的极好的建议,本书无疑将更加完善。但由于时间的限制,我不得不有选择性地加以采纳。即便如此,本书的改进仍然十分显著,任何遗留下来的错误都应由我本人承担。

我的父母Frances和Henry一如既往地给予我大力的支持,与上一本书相比,这本书没有那么多技术专业名词,因而我希望他们觉得这本书读起来容易一些。

最后,我要感谢我的两位挚爱好友,Karen Underhill和Jim Blandy。在写作本书期间以及在过去的七年里,Karen给予我的友谊和理解对我来说意味着一切。没有她的帮助,我是不可能完成本书的写作的。Jim对我来说也是一样,一个真正的朋友,一个计算机行业中的王者之王,是Jim将我带入自由软件行业,正如一只鸟给予飞机飞行的灵感。

免责声明

本书中所表达的想法和观点均属我本人。它们并不一定代表CollabNet或是Subversion项目的看法。



[1] 术语“开源”和“自由软件”在此处的上下文中本质上是同义词。有关他们的更多讨论参见第 1 章 介绍中的““自由”还是“开源””一节

第 1 章 介绍

大部分自由软件项目是失败的。

人们总不太喜欢听太多失败的故事,只有成功的项目才能吸引我们的注意力。林林总总的自由软件的总数是惊人的[2],尽管只有一小部分的项目成功了,但这仍然只是那些广为人知的项目的一部分。有太多的项目由于不为人知,即使失败了我们也不会听到。我们无法用一个确定的时间点来宣判一个项目的死刑,人们只是停止工作无所事事。即使我们知道一个项目的最后一个变动是何时添加的,但是在当时那些做这些工作的人通常并不知道这会是最后的晚餐。我们甚至无法明确地定义何时一个项目才算是断气了。是停止活动6个月之后?是用户数量停止增长并且人数还少于开发者的数量时?当一个项目的开发者发现他们只是在重复别人的工作,而决定放弃项目,然后他们决定加入另一个项目,并且在项目中使用之前的一些工作成果?原先的项目死亡了,或者只是搬了一次家?

因为是如此复杂,得出一个精确的失败率是不可能的。但是十多年以来流传于SourceForge.net或是用Google搜索得到的开源运动传闻,都指向同一个结论:这个比率是非常高的,也许能达到90–95%。如果把那些虽然存活但是内忧外患的项目算在内,这个比率还将更高,这些项目通常仍然生产可执行的代码,但已不再是开发者的乐园了,要么是无法尽其所能的快速和互相依赖的作出进展了。

这本书的目的旨在说明如何避免失败。它不仅演示了如何才是正确的做事方法,而且告诉你错误出在何处,以便你及时发现和纠正错误。我希望在读过此书之后,你不仅能对如何避免开发过程中的常见陷阱有丰富的技术储备,而且对如何使一个成功的项目得到成长和维护有深入的了解。成功不是一场零和游戏,此书也不是教你如何在竞争中获胜或是领先的。相反,运作一个开源项目的重要部分就是流畅地同关联项目合作。在更高的层次上,每一个成功的项目都为在世界范围内自由软件的成长作出一份贡献。

如果说导致自由软件项目失败的原因类型与私有软件是相同的,那是令人诱惑的。实际上,在自由软件内不会有诸如建立在不切实际的需求上的垄断,含混不清的规范,可怜的代码管理,设计阶段不足等等笼罩在传统软件工业上的幽灵。有关这些主题的书已经是汗牛充栋,我不打算重复。我想做的是描述自由软件独有的问题。当一个自由软件项目开始运转,最常见的问题是开发者(或是经理)难以识别开源软件开发过程中的独特问题,尽管他们可能已经在那些闭源软件的常见问题上摔打了多年。

一个最常见的错误就是急于从开源的形式本身获得好处,但这是不切实际的。一纸开放许可证不会一下子让成群的活跃开发者自愿地把他们的时间交给你的项目,将一个原本问题多多的项目开源也不能自动地修正这些问题。实际上很可能相反,与不开源相比,开放一个项目短期内会带来一系列全新的复杂问题和代价。开放意味着要让完全陌生的人读懂代码,建立一个开发网站和邮件列表,通常还会第一次需要写文档。这些事情的工作量是相当大的。当然如果有开发者表示出了兴趣,在他们为你的项目带来好处之前回答他们的问题也是一个额外的负担。如同开发者Jamie Zawinski回忆Mozilla项目早期的混乱状况所说地:

开源的确行,但它绝不是万能药。我对你的忠告是:你不能指望在一个垂死项目上洒一点"开源的精灵魔粉"就能让所有事情奇迹般地运转起来。做软件是困难的。问题不会那么简单。

(来自http://www.jwz.org/gruntle/nomo.html

一个相关的错误是对展示和打包的轻视,特别是当一个项目顺利运转时总认为这些以后再做不迟。展示和打包有很多的目的,所有的一切都是为了减低进入的门槛。使项目对那些后来者有吸引力意味着编写用户和开发者文档,建立为新来者提供信息的网站,尽可能自动化软件的编译和安装工作,以及其他。很不幸,很多程序员认为与编码相比,这些工作都是次要的。导致这种情况的原因有很多。首先,他们感觉这些都是附加作业,因为对熟悉项目的这部分少数人来说,它的益处是显而易见的,反之亦然。毕竟这些编写代码的人并不真需要打包。他们知道如何安装,管理和使用这些软件,因为代码就是他们编写的。其次,展示和打包所需要的技术通常和写代码完全不同。人们总是倾向于专注自己所擅长的,即使另外的工作能对整个项目起到事半功倍的作用。 第 2 章 起步将详细讨论展示和打包,并且解释从项目的一开始就确定这些工作的优先地位的重要性。

接下来的一个谬误是认为开源几乎或完全不需要项目管理,或者照搬商业开发的那一套管理模式也能在开源中做得很好。在一个开源项目中,管理总是不起眼的,但在成功的项目中,它通常在幕后起到推动的作用。一个简单的心理试验就足够显示其原因。一个开源项目由来自四面八方的程序员组成—一群臭名昭著的自由独立思想者—他们中的大部分人从来没有互相见过面,为这个项目工作只是出于他们的个人目标。心理试验能很简单地预测如果没有管理,在这样一个团体中会发生什么。除非发生奇迹,否则他们很快就会四分五裂。事情不会如我们希望的那样自己运转。管理偶尔会相当活跃,但是大部分时候是非正式的,微妙的,低调的。只有一件事情能把开发者团结在一起,就是他们相信团队合作比单干能做得更多。因此最重要的管理目标是确保他们继续相信这一点,做到这点需要设定交流的标准,需要让能干的开发者不会因为个性而受到排斥,总之要使项目成为开发者的留恋之地。我们将在后面讨论这些工作需要的具体技术。

最后还有一种类型的问题也许我们可以称之为“文化引导失败”。十年之前,甚至五年之前,谈论自由软件运动的整体文化都还为时过早,但现在不是了。一种清晰的文化正在慢慢浮现,虽然它不是一个整体—如同很多地域约束的文化,易于产生内在的异议和派别—但它有一个基本的一致的核心。大部分成功的开源项目展示了这个核心中的部分或全部特质。他们奖励符合这种文化的行为,惩罚相反的;他们创造了一种鼓励计划外的参与氛围,甚至不惜中心协调时间的代价;他们对粗野和礼貌的概念与流行观念有本质上的区别。最重要的是,长期的参与已经内化了这些标准,所以他们能够对将要发生的举动能大体上取得共识。失败的项目通常显著的背离了这个核心,尽管并非本意,但通常是因为没有对建立合理默认行为方式达成共识。这意味着一旦问题出现,由于参与者缺乏通过弥补分歧而对问题做出反馈的现成文化储备,形势会迅速恶化。

此书是一本实用的指南,而不是一篇人类学论文或是史书。然而了解今天的自由软件文化的起源对任何一个实际的建议都是必要的基础。一个理解这种文化的人能在开源世界任意驰骋,即使遇到很多的各地风俗和方言,仍然可以自信和有效地参与。相反,一个没能很好理解这种文化的人将会在组织或是参与一个项目的过程中处处遇到困难和意外。由于自由软件的开发人员的数量仍然在飞速增长,其中有很多人属于后一种情况—这多半是一种新近加入的文化,并且会持续一段时间。如果你自认为是其中的一员,下一节为你在以后将在本书或是互联网上遇到的讨论提供了背景材料。(另一方面,如果你已经在开源中工作了一段时间,你也许早已了解了这段历史,你可以选择跳过这一节。)

历史

软件分享自从软件诞生的那一天起就出现了。在计算机工业的早期,厂商认为竞争的优势在于对硬件的创新,因此并不太认真把软件当成商业资产看待。这些早期机器用户许多都是科学家或是技术人员,他们有能力自己修改和扩展随机附送的软件。有时用户不仅将补丁反馈给厂商,而且分发给相似机器的其他用户。厂商经常允许甚至鼓励这么做:在他们眼里,无论是哪一种渠道,对软件的改进都使得机器对其他的潜在消费者更有吸引力。

虽然今天的自由软件文化在很多方面都和早期相似,但是有两点重要的不同。首先,当时几乎没有硬件的标准—那是一个计算机设计创新的黄金时代,但是繁多的计算机架构也意味着所有的事情都无法同其他的兼通。因此,为一台机器编写的软件一般无法在另一台上工作。在一种特定的架构或是架构族上程序员需要专门的知识(今天程序员更多的是学习一种编程语言或是语言类型的专门知识,他们对他们的专业知识能移植任何一台遇到的机器上非常自信)。因为个人的专门知识总是针对一种特定类型的计算机,这些专门知识的积累能让计算机对他们以及同事变得越来越有趣。这就是为什么厂商对让特定机器的代码和知识尽可能广的得到传播感兴趣的原因。

其次,当时没有互联网。虽然当时对分享的法律约束比今天少,但却有更多的技术约束:也就是说,和说话相比,把数据从一个地方移到另一个地方是笨重不便的。在一些公司和实验室里员工之间,可以通过一些不错的小型的局域网共享信息。但当一个人想同不限地点的所有人分享时,问题依然存在。克服这些问题的途径很多。有时独立的团体之间会互相联系,通过邮局寄送磁盘或是磁带,有时厂商扮演了补丁的中心情报交换所的角色。厂商还会帮助在大学里的早期计算机开发者,那里的气氛是鼓励知识传播的。但是数据传输所必须的物理媒体意味着分享总会遇到阻力,和(实际上的或是组织上的)距离成正比的阻力。现在这种广泛的,几乎没有阻力的分享,在那时还是不可能的。

私有软件和自由软件的兴起

随着工业的成熟,接连发生了一系列相关的变化。众多硬件设计中的赢家逐渐清晰起来—有技术优势的赢家,有行销优势的赢家,或是两者结合的赢家。与此同时,被称为“高级”语言的编程语言的发展意味着一个用某种语言写成的程序能够转移到(“编译”)另一种类型的计算机上运行。硬件厂商不会忽视这其中的含义:现在客户无须再把自己捆绑在一种特定的计算机架构上就可以开展一个大型的软件工程项目。随着各类计算机的性能差异日益变小,以及低效率设计的消失,硬件成了厂商为未来利润率下降的唯一指望。原始的计算能力成了一种可替代的产品,而软件成为差异化优势。销售软件或至少将它视为硬件销售不可分割的一部分,看起来是一种不错的策略。

这意味着厂商必须开始更严格地在他们的代码上强制执行版权。如果用户之间继续简单地分享和修改代码,他们可能会独立完成一些改进,现在被供应商当成“附加价值”用来销售。更糟的是,分享代码可以落入竞争对手的手里。讽刺的是,这一切都发生在互联网即将破壳而出之时。就在无障碍的软件分享在技术是终于成为可能时,计算机行业内发生的变化则使它在经济上无法受到欢迎,至少计算机公司的观点是如此。供应商手段强硬,要么拒绝客户访问自己机器上的源代码,要么是通过保密协议使方便的共享成为不可能。

有意识的反抗

虽然无障碍代码分享的世界正在慢慢凋零,但至少有一名程序员的心中保持着清醒。理查德·斯塔尓曼(Richard Stallman)在70年代和80年代早期一直为麻省理工学院的人工智能实验室工作,那里是代码分享黄金时代的黄金圣地。人工智能实验室有很强的“黑客精神”,[3]那里的人对分享为系统做出的任何改进有狂热的爱好。正如斯塔尓曼后来写到的:

我们没有把我们的软件称为“自由软件”,因为那时这个术语还不存在,但它确实是。无论外面的大学或是公司来的人来索要程序,我们都很高兴这么做。如果你看到在用的一个少见还有趣的程序,你总可以要求看源代码,所以你能读它,修改它,或者用拆取部分写一个新程序。

(来自http://www.gnu.org/gnu/thegnuproject.html

1980年之后不久工业界发生的变化最终影响到了人工智能实验室,斯塔尓曼周围伊甸园式的社区坍塌了。一家创业公司挖走了很多实验室的程序员去开发一个操作系统,这个系统同实验室正在开发的非常相似,但使用了独占许可证。与此同时,人工智能实验室购买了带有私有操作系统的新设备。

斯塔尓曼见一叶落而知秋:

那个时代的现代化计算机,比如VAX或68020都有自己的操作系统,但都不是自由软件:为了得到一份能运行的拷贝,你甚至得签署一份保密协议。

这就是说使用一台计算机的第一步是承诺不帮你的邻居。一个互助的社区是被禁止的。私有软件的拥有者定下了规矩,“如果你和你的邻居分享了,你就是强盗。如果你想要改变,来祈求我们做吧。”

此时,他性格中的怪僻萌动了,他决定反抗这种趋势。他既不想继续留在人去楼空的人工智能实验室,也不想在一家新公司里写代码,因为他写出的代码会被锁在保密箱里,最终他从实验室辞职,随后创建了GNU项目和自由软件基金会(FSF)。GNU[4]的目标是开发一个完全自由和开放的操作系统和配套的应用软件,它们的用户永远不会阻止去破解或是分享它们的修改。本质上他是要重建人工实验室内被摧毁的那些东西,但是这一次是在全世界的规模上,并且还要避免导致人工实验室的文化被动摇破裂的那些弱点。

除了新操作系统的工作,斯塔尓曼还设计了一套确保他的代码无限自由的版权许可证。GNU通用公共许可证(GPL)是法律博弈中的奇招:它声明允许无限制地复制和修改代码,同时拷贝和派生产物(即修改版本)必须在原始版本的相同许可证下发布,不得附加限制。实际上,它用版权法去达到一个同传统版权法相反的目的:取消对软件分发的限制,它阻止任何人,甚至是作者本人对此的限制。对斯塔尓曼来说,这要比简单地把他的代码分发到公共领域好得多。因为在公共领域,一份实际的拷贝有可能被包含在一个私有程序中(这样的事情我们在使用宽松的版权许可证的代码中听到很多了)。虽然这种包含不会在任何方面减弱原始代码的持续可用性,但它意味着斯塔尓曼的努力可能会帮助敌人—私有软件。GPL为自由软件提供了一套保护机制,因为它阻止了非自由软件利用GPL许可证下代码的优势。GPL同其他自由软件许可证关系的详细讨论在第 9 章 许可证,版权和专利

在很多程序员的帮助下──其中有些是认同斯塔尓曼的思想体系,有些只是为了能看到自由软件的代码──GNU项目开始发布操作系统中最重要组成部分的自由替代品。因为计算机硬件和软件已经高度的标准化了,使用GNU替代其他的非自由操作系统成为可能,许多人也这么做了。GNU文字编辑器(Emacs)和C编译器(GCC)特别的成功,它们获得大量忠实的拥护者,这不是因为其理想主义的基础,而是因为其技术价值。约在1990年GNU已经生产了一个自由操作系统的大部分,除了内核—实际负责引导计算机、管理内存、磁盘和系统其他资源的部分。

不幸的是,GNU项目选择的内核设计要比预想的更难实现。随后的延期使得自由软件基金会没能及时地发布一个彻底的自由操作系统。这缺失的部分最终由一个芬兰的计算机科学系的大学生Linus Torvalds补完,在遍布全世界的志愿者的帮助下他用更加保守的设计完成了一个自由内核。他将其命名为Linux,当把内核同GNU项目的现存软件组合在一起,结果就是一个完全自由的操作系统诞生了。第一次,你不再需要任何的私有软件来启动和使用你的计算机。[5]

这个操作系统上的很多软件都不是GNU项目的产物。实际上,GNU不是唯一的开发自由操作系统的团体(例如,当时最终发展为NetBSD和FreeBSD的代码已经开始编写)。重要的不仅仅是自由软件基金会产出的代码,而且是它们的政治修辞。把自由软件当成一个目标而并非一种手段讨论,让那些对此并没有政治意识的程序员们很为难。即使那些并不认同自由软件基金会的程序员也不得不面对这些问题,只要他们处于不同的位置。自由软件基金会通过在他们的代码上附带有关GPL和其他文字的信息,成功地扮演了鼓动家的角色。随着他们的代码广泛地被分发,思想也随之流传。

意外的反抗

在自由软件运动的早期还发生了很多其他事情,其中很少有如斯塔尓曼的GNU项目般清晰的思想体系。其中一个最重要的是伯克利软件发行版(Berkeley Software Distribution,BSD)一个Unix操作系统的重新实现—这个项目可以一直追溯到1970年代晚期AT&T公司内由加州大学伯克利分校负责的一个松散的私有研究项目。BSD并没有什么要程序员们联合起来并且共同认可的政治信条,他们通过高度分散地开发方式从零开始重写了Unix命令行工具和代码库,最终是操作系统内核本身,这一切的大部分都是由志愿者完成的,用天才和热情实践了这个信念。BSD项目成了非意识形态的自由软件开发的主要例子,并且他们为那些在开源世界继续保持活动的开发者提供了训练场地。

另一个合作开发的重镇是X Window System,一个由MIT联合其他有兴趣为客户提供窗口系统的硬件厂商在80年代中期开发的自由的网络透明的图形计算环境。和私有软件恰恰相反,X许可证故意允许在自由核心之上建立私有扩展—每一个成员都需要机会加强默认的X发布,这样就会获得了超越其他成员的竞争优势。X Windows[6]自身是自由软件,但其主要目的是为了平衡商业利益竞争中的差距,对终结私有软件的统治没有丝毫的诉求。还有一个早于GNU项目很多年的例子是TeX,Donald Knuth的自由排版系统。他使用的许可证允许任何人修改和分发代码,但如果未能通过一个非常严格的兼容性测试,则不允许冠以"TeX"的名称(这是自由许可证的“商标保护”的一个例子,更多的讨论在第 9 章 许可证,版权和专利)。Knuth并非对软件应该是自由还是私有的问题有什么意见或是其他诸如此类的目的,他需要一个更好的排版系统是为了完成他真正的目标—一本计算机编程的书—当书完成了,没有理由不把他的系统公之于众。

虽然没有列出每一个项目和每种许可证,但还是可以确信,在1980年代末,出现了许多基于各类许可证的项目。许可证的多样性反映了动机的多样性。即使是一些选择GNU GPL的程序员也没有和GNU项目同样强烈的意识形态动机。尽管他们很享受为自由软件工作,但是许多开发者并不把私有软件视作社会恶魔。确实有些人是受到道德冲动的驱使要去消灭“囤积软件”(斯塔尓曼对非自由软件的称呼)的世界,但其他人更多的是出于对技术的狂热,或对能和志同道合者合作感到愉悦,甚至简单地出于人类对荣耀的渴望。大体上说,这些不同的动机并没有造成冲突。部分原因是和其他的创造性活动如散文和视觉艺术不同,软件必须通过半客观测试才能成功:它必须能运行,去除绝大部分的bug。这自动地给了一个项目的全部参与者一个共同的背景,一个理由,一个无需为除了技术以外的问题担心的协同工作的框架。

开发者们还有另一个团结互助的原因:自由软件世界生产了很多质量非常高的代码。要么是令最接近的非自由对手都望尘莫及,要么是可以匹敌,或至少价廉物美。虽然也许会有一些人是出于严格的意识形态的背景才使用自由软件,但绝大部分人是因为它更出色才使用自由软件的。在这些人中,总有一定比例的人乐意将自己的时间和技术贡献出来帮助维护和改进软件。

这种产出优秀代码的趋势并非是普遍的,但在全球的自由软件项目出现的频率越来越高。这引起高度依赖软件质量的商业公司的关注。其中的许多发觉他们其实早已经在日常的操作中使用自由软件,只是并没有意识到(管理层并不总是能意识到IT部门做的每件事)。公司开始在自由软件项目中扮演越来活跃和公开的角色,他们向自由软件的发展捐助时间和设备,有时甚至是直接的资助。在最好的情形下,这些投资能获得数倍的回报。这些赞助商只需要为少数全职投入的专家级程序员支付工资,获得的回报却包括了无偿的志愿者和领取其他公司薪水的程序员的全部工作成果。

“自由”还是“开源”

随着商业世界越来越多的关注自由软件,程序员们面临新出现的问题。首先是单词“自由”本身。第一次听说“自由软件”(free software,在英语中free既有自由的意思,也有免费的意思)这个词的时候,许多人都错把它理解成“免费软件”。确实大部分的自由软件都是免费的,[7] 但不是所有的免费软件都是自由的。例如在1990年代的浏览器大战中,为了抢占市场份额,网景和微软都无偿地发布他们的网络浏览器。这些浏览器都不是“自由软件”。你无法得到源代码,即使得到了也没有权利修改和再发布。[8]你唯一能做的是下载一个运行文件,然后运行。这些浏览器的自由不会比从商店里购买的盒装软件更多;它们只是有较低的价格。

围绕自由一词发生的混乱,很不幸地完全是由于英语本身的多义性造成的。大部分的其他语种对“免费”和“自由”明确地区别对待(例如在罗曼斯语中gratislibre的差别对听众而言是一清二楚的)。但英语是互联网事实上的桥梁语言,所以一个英语的问题在某种程度上来说即是每个人的问题。围绕自由一词的误解是如此之广,以至于最终自由软件程序员们发明了一个公式来应对:“It's free as in freedom—think free speech, not free beer。”但一遍又一遍的解释还是让人厌倦。许多程序员认为,即使加以解释,对自由的岐义正在阻碍公众对这种软件的理解。

但实际的问题更复杂。free一词承载了一个无可避免的道德内涵:如果自由是它自身的最终目标,它同自由软件是否被更多人接受,是否能从商业中赚取更多的利益无关。这个动机唯一的光明面从根本上说既不是技术也不是商业,而是道义。此外,“free as in freedom”的定位也迫使那些既想在生意的某一方面支持实用的自由程序,而另一方面又继续推销私有软件的公司陷入前后矛盾的境地。

本已陷入身份危机的社区又迎来了这些困境。如果说自由软件运动有一个总体目标的话,那些实际上写自由软件的程序员们并不都为了同一个目标而工作。甚至于从一个极端走向另外一个极端的观点会引起误解,因为我们会错误地以为只有两种极端的观点,而实际上存在着多层次的看法。然而,如果我们忽略其间的细微差别,他们都可以被归入两类信念。一个团体追随斯塔尓曼的观点,认为共享和修改的自由是最要的事,因此如果你不再谈论自由,你就忽略了核心问题。另一些人认为软件本身才是最重要的因素,并且对公开地宣布私有软件本质上是坏的而感到不舒服。部分的,但非全部自由软件程序员相信作者(或是雇主,如果是有偿工作)应该有权利控制分发的条款,选择何种条款不应该受到道德的审问。

在很长时间里这些分歧并不需要认真对待,但自由软件在商业世界里的快速成功使得这些问题无法再回避。1998年一群程序员结成一个团体,也就是后来的开源促进会(Open Source Initiative,OSI)[9]创造了开源一词来替代“自由”。OSI认为“自由软件”不仅有潜在的岐义,而且“自由”一词本身就是一系列问题的根源。运动本身需要一个在商业世界里的营销程序,而谈论道德和社会公益在公司董事会里是不受欢迎的。用他们自己的话说:

开源宣言是自由软件的一个营销程序。用务实的基础推动自由软件远比慷慨激昂大谈理想有用得多。成功的本质没有变,失败的象征和看法已经变了。 ...

需要告知大多数技术人的不是开源的概念,而是名字。为什么我们不再像从前那样称之为“自由软件”呢?

一个直接的原因是“自由软件”一词容易以一种导致冲突的方式被误解。 ...

但真正更名的原因是营销上的。我们现在想打入商业世界。我们有成功的产品,但在过去我们的定位是可怕的。自由软件一词被商人们误解了,他们把这种描述理解成反商业主义,甚至更糟,贼。

主流公司的CEO和CTO们绝不会买"自由软件"。但如果我们保持非常相似的传统,人还是那些,相同的自由软件许可证,只是换了一个“开源”标签的话?他们会买。

一些黑客觉得这很难相信,但那是因为他们的技术化思维已经僵化,被条款所束缚,不能理解当你推销某样东西时形象有多重要。

做营销时,外表是很现实的问题。我们打算用什么样的形象来消除同公司打交道的障碍,和我们的行为,我们的信念,我们的软件同样重要。

(来自http://opensource.feratech.com/advocacy/faq.phphttp://opensource.feratech.com/advocacy/case_for_hackers.php#marketing

通过上面的文字我们可以一窥争论的冰山一角。它提到了“我们的信念”,但是巧妙地回避了这些信念到底是什么。对有些人呢,这种信念也许是认为开放的开发过程将产出更好的代码,对其他人也许是认为所有的信息都应该共享。他们用到了“贼”一词(据推测是)影射非法的复制—许多人反对这一点,认为如果原持有人随后仍然保留原件就不能视作贼。这里有一个明显的暗示说自由软件运动被错误地划入了反商业主义,但它小心翼翼地回避了这种归类是否有现实依据的问题。

其中没有一条可以说明OSI的网站是自相矛盾或是误导的。确实没有。相反,这个例子表明了OSI所主张的,正是自由软件运动所缺少的,也就是好的营销,此处的“好”指的是“能在商业世界生存”。开源宣言给许多人带来他们一直寻找的—一套将自由软件作为开发的方法论和商业策略而不是道德圣战的语汇。

开源促进会的出现改变了自由软件的面貌。它将长久存在的矛盾摆上了桌面,迫使运动承认与外部一样,其自身内部同样有派系斗争。由于大部分的项目都包括了来自两个阵营的程序员,加上一些很难明确归类的参与者,如今二者都已经找到了共同的基础。这不意味着人们从不谈论道德动机—例如,有时人们会讨论传统的“黑客精神”的流失的问题。但是很少有自由软件/开源开发者在一个项目中公开地质疑他人的基本动机。作出贡献远比贡献者本身重要。如果有人代码写的不错,你不会问他们到底是出于道德原因还是因为雇主付给他们工资或是为了在推荐信上添加砝码,或其他什么原因。你从技术角度评估贡献,从技术角度反馈。甚至Debian这样毫不讳言政治的组织(他们的目标是提供一个100%自由的操作环境),也已经不再那么严格的对待集成非自由代码和同目标不一致的程序员共事了。

现状

当运作一个自由软件项目时,你不必在日常工作中谈论沉重的哲学命题。程序员不会要求项目中的其他人和自己在所有事情上能够看法一致(那些这一点上坚持的人很快就会发现他们无法在任何项目内工作)。但是你必须了解“自由还是开源”之争的存在,部分原因是避免谈论引起部分开发者抵触的事情,部分是因为理解开发者的动机是管理一个项目最好的方法—有时,是管理一个项目的唯一方法。

自由软件是一种有关选择的文化。你必须首先理解为什么人们会参与其中,才能成功地运作一个项目。强制是不管用的。如果一个项目让人不高兴了,他们会立刻转移到另一个项目。自由软件的独特之处还在于志愿者社区的投资强度。大部分内部的人从来没有和另一个参与者面对面地交流过,只是在高兴时捐助一点时间。通常人类用来互相结识并结成牢固的团体的渠道被压缩成了一条细管:在键盘上打字然后通过电缆传输。因此,形成一个有凝聚力和专注力的组织需要花上很长时间。相反,在首次接触的五分钟内流失一个潜在的开发者是非常容易的。如果对一个项目没有良好的第一印象,新来者很少会给予第二次机会。

关系的无常性,或者是潜在的无常性,也许是面对一个新项目时最让人畏惧的一点。如何才能使这些人尽可能长时间的呆在一起做一些有用的事?这个问题的答案足可以用本书剩余的篇幅来说明,但如果必须用一句话来回答,会是这样:

人们应该能感到他们同一个项目的联系和对它的影响力是直接同他们的贡献成正比的。

没有哪类开发者或是潜在的开发者应该感到自己由于非技术原因而被区别对待。特别是项目的赞助商或是领取报酬的开发者在这一点上要特别小心,这一点将在后面的第 5 章 金钱详细讨论。当然,这不是说如果没有公司赞助商的话就可以高枕无忧了。钱只是能影响项目成功的许多因素之一。还有诸如语言的选择、许可证的选择、何种开发过程、设立何种类型的基础架构之类的许多其他因素。在良好的基础上开始一个项目是下一章的主题。



[2] SourceForge.net,一个著名的代码存放站点,截至到2004年4月中旬,总共有79225个项目注册。虽然这只是选择使用SourceForge的项目数量,但已经非常接近互联网上全部自由软件项目的数量了。

[3] 斯塔尓曼的“黑客”指的是“喜欢程序并且喜欢用它炫耀聪明的人”,不是近些年来的新含义“非法进入计算机的人。”

[4] “GNU's Not Unix”的缩写,扩展后短语中的GNU其实是同一意思。

[5] 从技术上来说Linux不是第一个。在Linux之前不久已经有了一个能在IBM兼容机上运行的自由操作系统,386BSD。然而386BSD的启动和运行还不太稳定。Linux的飞速发展不仅因为它是自由软件,而是因为安装之后你有更大的几率能启动计算机 。

[6] 正式的称呼是“X Windows System”,但实际中人们通常称之为“X Windows”,因为三个单词太繁琐了。

[7] 发放自由软件的人可以收取一定的拷贝费用,但是由于他无法阻止受领者去免费地再发放,价格还是会很快接近于零。

[8] 网景Navigator浏览器的源代码最终1998年在一个开源许可证下发布,成为后来的Mozilla网络浏览器的基础。参见http://www.mozilla.org/

[9] OSI的主页http://www.opensource.org/

第 2 章 起步

有关自由软件是如何发起的经典模型是由Eric Raymond提出的,在一篇今天已广为人知的有关开源开发的论文《大教堂和集市》中,他写道:

每一个好的软件都始于挠到一个开发者的痒痒处。

(来自http://www.catb.org/~esr/writings/cathedral-bazaar/

注意Raymond并没有说只有当某些开发人员心里痒痒之后才会导致一个开源项目的诞生。相反,他是说只有当程序员对解决某个问题产生了个人兴趣之后,才能产生优秀的软件;这一点同自由软件的联系在于,大部分自由软件项目的最初动机都是始于一个人的痒痒处。

这仍然是大部分项目的动因,但自从1997年Raymond写下这些话之后这种现象正在慢慢减少。今天我们有了一些组织—包括盈利性的大企业—从零开始大型的,集中式管理的开源项目。单个的程序员为了解决一个个人问题敲出一些代码而最后意识到可以有更广泛地应用的例子仍然是许多新自由软件的源头,但不再是唯一的故事。

然而Raymond的观点仍然是真知灼见。关键在于软件的生产者对它的成功有直接的兴趣,因为是自己用。如果软件没能达到期望的目标,那些编写它的个人或是组织会在日常工作中感到不满。例如,OpenAdapter项目(http://www.openadapter.org/),这是一个由德累斯顿·克莱沃特投资银行(investment bank Dresdner Kleinwort Wasserstein)发起的一个用于集成不同财经信息系统的开源框架,就很难说是始于哪个程序员的个人痒痒处。它始于一个组织的痒痒处。这些痒痒处直接来自这个组织和他们的合伙人的经验,因此如果这个项目没能减轻这些痒痒症,他们立刻能够感觉到。这种情形产出了优秀的软件,因为形成了一个良性的循环。程序不是为了卖给其他人而编写的,不是为解决他人的问题。它是为解决某个自己的问题而编写的,之后再同其他的人分享,足可以把问题想像成疾病,而程序是分发的药物,用来彻底地消灭传染病。

本章是关于如何将一个自由软件项目介绍给全世界,但是其中的很多建议听起来会很像一个卫生组织在分发药物。两者的目标的确非常相似:你要弄清楚药品的作用,把它发放到需要的人手中,并确保那些人知道如何使用它。但对一个软件,你还需要诱使那些接受者加入研究计划来改进“药物”。

自由软件的发布是一项双重任务。软件既要满足使用者,也要满足开发者。这两种需求不一定是冲突的,但是会为项目初期的展示增加复杂度。其中有些信息对两者都有用,有些只是对其中一类有用。对两种信息都应该依照展示的比例原则:描述的详细程度应该同读者在该阶段所应该花费的时间和努力程度相对应。更多的努力应该带来更多的回报。当这种关系发生偏差时,人们有可能很快失去信任并且停止投入精力。

这一点的必然结果就是形象的重要性。程序员们对这一点总是嗤之以鼻。对本质超越形式的热爱成了他们职业自豪感的一部分。所以毫不意外,许多程序员表现出对营销和公关工作的厌恶,同样,职业图形设计师往往也对程序员们的产品感到惊恐万状。

这是一个遗憾,因为有时候形式就是本质,并且项目的展示就是这种情形之一。例如,浏览网页的人对一个项目的第一观感就是来自网站的外观。这种观感的形成要早于任何一种实际的内容之前—包括文字和链接。不管这看起来多么不公平,人们无法不形成一个即时的第一印象。网站的形象向读者传递了一个信号,即网站的展示是否经过了精心安排。人类对检测心思的投入有着极为敏锐的感觉。我们中的大多数人都能在一瞥间看出一个网站是随便拉起来的还是经过认真思考的。这是你的项目展现出信息的第一步,它所建立起来的印象将对整个项目的后续部分施加影响。

因此,尽管本章的大部分篇幅谈论的是你应该用什么样的内容开始你的项目,但别忘了外观和感觉同样重要。因为项目的网站同时为使用者和开发者两类人服务的,相应的投入也要透明和有针对性。虽然这不是一本讨论网页设计的专著,但是当网站是为多种类型的读者服务时,有一条重要原则是值得一提的,在点击一个链接之前用户应该对它的去处有一个大概的了解。例如,当看到“用户文档”的链接时,明显应该是链接到用户文档,而不是开发者文档。运作一个项目一方面是为了提供信息,但同时也是提供舒适。当用户和开发者们正在犹豫要不要加入时,你应该在预期的地方用一套肯定性的标准来使他们安心。它表明项目有统一的管理,已经预估到了人们可能提出的问题,并且致力于在只花费提问者最少的精力的前提下来解答这些问题。通过显现这种充分准备的氛围,该项目发出了一个信息:“如果加入,你的时间不会被白白浪费,”而这正是人们想听到的。

但首先环顾四周

开始一个开源项目之前,给你一个重要的告诫:

一定要找找看是否有一个现存的项目已经做了你想做的。有很大的几率有人早于你已经解决了你想解决的问题。如果他们已经解决了它,并且在一个自由许可证下发布了他们的代码,那今天你就没有必要重新发明轮子了。当然有例外:如果是为了练习才开始一个项目,那现有的代码对你没用;或者你脑中的计划非常特别,你肯定不会有其他人有同样的想法,那你也不妨试试看。但总的来说没有理由不先看一看,而收获总是很大。如果常见的互联网搜索引擎发现不了什么,试试在http://freshmeat.net/(一个开源项目的新闻站点,有关它的更多介绍将在后面提到)和http://www.sourceforge.net/上找找看,同时自由软件基金会有一个自由软件的目录在http://directory.fsf.org/

即使你找不到跟你的想法一模一样的项目,你也许能找到十分接近的,然后加入这个项目为它增加功能比你自己从零开始一个项目要更有意义。

从你所拥有的开始

你环顾了四周,没找到真正适合你的软件,因而决定开始一个新的项目。

现在应该做什么呢?

开始一个自由软件最难的部分是将个体的设想转化传达给公众。你或是你的团体也许对要做的事情已经十分明了,但是将这一目标清楚地传达给世界还需要付出一番努力。然而,那是必须花时间做的事情。你和其他的创建人必须决定你们项目的作用—也就是说,划定项目的范围,做什么,不做什么—然后撰写一份项目任务陈述。这部分通常不太难,但有时候能暴露出一些有关项目本质的臆想,甚至于分歧,那也没关系,现在解决这些问题总比拖到以后好。下一步就是将项目打包展示给公众, 而那纯粹是单调乏味的工作。

之所以这样说是因为打包的工作就是把大家都已经知道的东西组织和编辑成文件—这里所说的“大家”指的是到目前为止参与项目工作的人。因此,对于那些做这项工作的人来说,没有什么立竿见影的好处。他们并不需要一个README来了解整个项目的概况,也不需要一个设计文件或是用户手册。他们不需要仔细排列好的,与非正式而又普遍采用的软件源码发布方式相一致的代码树形图。对他们来说,无论代码怎么安排都没问题,因为他们已经对此十分熟悉,只要源码能够运行,他们就知道怎么用。甚至于,项目最根本的设计设想没有做成文件对他们来说也是无关紧要的;因为他们对那一方面也很熟悉了。

然而,新参与的人需要这些东西。好在他们并不是在一开始就需要全部的资料。在一个项目公之于众之前,你不必提供每一个有关的细节。在一个理想的世界里,每一个新的开源软件项目在开始的时候就具备了一个详细的设计文件,一套完整的用户手册(对已经计划好但还未实施的特性有特别的标识),漂亮地而又可移植地打好了包的代码,并且还可以在任何电脑系统平台上运行等等。然而在现实当中,做好上述各项工作是非常耗费时间的,可是一旦项目启动之后,这些工作可以指望一些自愿人员协助完成。

重要的必须做好展示这一步,以便新的参与者能够顺利通过开始时因对项目不熟悉而造成的障碍。设想自举过程中的第一步,就是将项目启动所需的能耗降到最低点。我听说过人们用切入能耗这个词来形容这一开端:即一个新的参与者在收获之前所必须付出的能量。一个项目的切入能耗控制得越低越好。你的首要任务就是将切入能耗降低到能够鼓励人参与项目工作的水平。

以下各小节分别描述了开始一个新项目的一个重要的方面。排列顺序大致是按照一个新的访问者将遇到的情形安排的,当然你在实际操作时可以不按照这个顺序进行。你可以将它们看作是一个检查列表。当你开始一个项目时,只要一一检查,确保每一步骤都做到了,或者在你省略某一部分时,至少你对将来可能出现的后果有把握就行了。

选择一个好名字

设想你是另外一个人,恰好听说过你的项目,或者是是在搜索一个软件来解决某个问题时碰巧看到了你的项目。他首先看到的是项目的名字。

一个好名字不会自然而然地使你的项目成功,而一个不好的名字也不会终结你的项目—当然了,一个真正糟糕的名字也许会,但是让我们首先假定谁也不会迫不及待地让自己的项目失败吧。确实,一个不好的名字会延缓他人接受该项目的速度,要么是因为人们不会认真对待它,要么是因为人们很难记住它的名字。

一个好名字:

  • 告诉人们有关项目性质,或至少名字与性质是明显相关联的一些概念,这样人们看到名字时就知道了项目能做什么,那么人们以后便很容易想起这个名字。

  • 便于记忆。在此,我们必须承认英语实际上已成为网络默认语言这一事实。“便于记忆”就意味着“便于能阅读英语的人记忆”。例如,某一非英语发音的双关语对于该语言之外的许多能阅读英语的人来说是很难理解的。要是这个双关语特别精彩并且令人难忘,那或许值得一试;但必须记住,这个名字在许多人的脑海里并不会产生在母语人士身上所有的效果。

  • 不与另一个项目重名,也不侵犯任何商标权。这既表现职业美德,也是良好的法律意识。你要避免制造身份混乱。即便没有不同的东西重名的现象,我们现在要搞清楚网络上已有的东西已经很不容易了。

    在前面“但首先环顾四周”一节里提及的资料有助于你发现是否另一个项目已经采用了你正在考虑的名字。免费的商标搜索见http://www.nameprotect.org/http://www.uspto.gov/

  • 尽可能成为.com.net、以及.org顶级域中的一个域名。你应该选择其中的一个,或许是.org吧,作为项目正式的网址;而另外两个网址都转发到前一个,这还可以防止其他人用项目的名字制造身份混乱。即使你打算将项目放在其它的网站空间上,(见“包装主机”一节),你仍然可以注册自己项目的域名,而转发至你存放项目的主页上。对用户来说,使用一个容易记忆的URL是十分有帮助的。

有一份清楚的使命陈述

人们找到了项目的网页之后,下一步就要看一份简短的项目描述,即使命陈述,以便(在30秒之内)决定他们是否对该项目有兴趣并获取更多信息。因此,这份使命陈述必须放在首页显著的位置,最好是紧贴着项目名字的下方。

使命陈述必须具体,紧凑;而最重要的是简短。以下是一个很好的例子,来自http://www.openoffice.org/

创建一个以社区为基础,领先的国际化办公室套件,能够在所有主要的平台上运行,并借基于API和XML文件格式的开放组件,提供对所有功能和数据的接入性。

这份使命陈述仅仅用了简短的几句话,通过大量依赖读者已有的知识明白无误地传达了所要传达的信息。 “以社区为基础”表明该软件不受任何一家大公司控制其开发;“国际化”指的是该软件允许人们在本地及多种语言环境下工作;“所有主要的平台”说的是该软件可移植到Unix,苹果和视窗操作系统。其余的文字则说明开放接口以及易读的文件格式都是该软件目标中重要的组成部分。这份使命陈述并没有在字面上告诉读者它旨在成为微软Office的开源替代品,但是人们从字里行间便能看出它的含义。乍一看,这份使命陈述似乎有些空泛,但实际上界定得相当明确:“办公室套件”对那些熟悉这个软件的人来说是非常具体的东西。在此,读者已有的知识(这里指的是读者有可能对微软Office软件的了解)又一次用来把使命陈述变得简洁明了了。

一份使命陈述的性质不单单是由它所描述的软件决定的,而在一定程度上得看是由谁来写的。例如,OpenOffice.org使用"以社区为基础"这个词是很有道理的,因为这个项目最初是由Sun Microsystems发起,而至今仍主要是由这家公司赞助的。在其使命陈述中使用"以社区为基础"这几个字,Sun表明它对一些担心该公司有可能试图垄断开发这一软件的忧虑是有敏感度的。这样的处理方法,即表明对一个有可能出现的潜在的问题有意识,就给将来完全避免这个问题的出现奠定了很好的基础。话又说回来,如果项目并非由一家大公司赞助,那或许根本不需要这样的词语;说到底,社区开发已经成为今天的模式了,因而没有理由要特别将那样的词语写在使命陈述中。

声明项目是自由软件

看过使命陈述之后仍对项目有兴趣的人自然想要了解更多的情况,或许要看一看用户文件和开发人员文件,最终可能下载一些东西。但在做这些事情以前,他们要确定这是一个开源项目。

网站的首页必须清清楚楚地写明这是一个开源项目。这看起来好像无需加以强调,但是你会惊讶有多少项目忽略了这一点。我见过不少自由软件网站,其首页不但没有说明该软件是在哪一个自由许可证下发布的,而且根本没在首页表明这是一个自由软件。有时候这一至关重要的信息被次要地放在了下载页,或是开发人员页,或是其它的一个需要多点击一次鼠标才能看到的一个地方。在一些极端的例子中,网页上哪儿都找不到自由许可证—只有下载软件打开之后才能看到。

别犯这个错误。这一忽略有可能让你失去许多潜在的开发人员和用户。务必在首页,也就是使命陈述的正下方,声明该项目是“自由软件”或是“开源软件”,并注明确切的许可证。有关选择许可证的快速指南,见本章后面的“选择许可证并应用”一节,而有关许可证问题的详细讨论见第 9 章 许可证,版权和专利

至此,我们假想中的访问者已经决定—或许在随后的一分钟之内—他打算至少再花5分钟的时间研究一下这个项目。下面几个小节要描述他在之后的5分钟里将遇到的情形。

特性和需求列表

你应该列出一个简短的清单,说明软件支持的各种特性(如果某些特性还未完成,也可以列出,但是在旁边注明计划中”或“建设中”),以及运行该软件所要求的系统环境。列这份清单时,你只要设想一个人请你简短地介绍这个软件的特性/需求是什么。通常,那只是按照逻辑对使命陈述作进一步的扩充。例如,使命陈述可能写的是:

创建一个全文索引器并配备丰富API的搜索引擎,用于编程人员搜索大批量文本文件。

特性和需求清单将列出更详细的内容,对使命陈述的范围加以说明:

特性:

  • 搜索纯文本,HTML和XML文件

  • 字或词搜索

  • (计划中)模糊匹配

  • (计划中)增量更新索引

  • (计划中)索引远程站点

需求:

  • Python 2.2或更高版本

  • 足够的硬盘空间以储存索引(大约原文件大小的2倍)

有了这样的信息,读者便能很快地决定这个软件是否适用于他们,也可以考虑是否以开发人员的身份参与其中。

开发状态

人们总是希望了解一个项目的状况。对新的项目,他们想知道项目的承诺和现实之间存在着多大的距离。对成熟的项目,他们想知道维护得如何,新发布的频率怎样,以及对Bug报告反应的及时性等等。

要回答这些问题,你应该建立开发状态页,列出项目的近期目标和需求(例如,需要具备某方面专长的开发人员)。开发状态页也可以列出过去发布的记录,其中包含特性清单,以便访问者了解项目是如何定义“进展”的,并根据这一定义了解项目进展的速度。

别因为你的项目看起来没准备好而感到害怕,也不要向夸大开发状态的诱惑妥协。谁都清楚软件是分阶段开发的产品;你不必觉得难以开口说出:“这是仍带有Bug的alpha软件,它可以运行。而且至少有时候能正常工作,但你使用这个软件就得自己承担风险。”这类语言不会吓跑你在这个阶段需要的开发人员。然而,对于用户来说,最糟糕的事情莫过于在软件准备好之前就吸引用户。一旦冠上了稳定性差或是Bug多多的名声,软件就很难再正名了。采取保守的策略对长远的目标是非常有益的;软件的稳定性超出用户的预期总比达不到用户的期望好得多,而给用户惊喜就会给产品带来最佳口碑。

下载

应该可以以标准格式下载软件的源代码。在一个项目刚起步时,二进制(可执行的)软件包不是必要的,除非该软件的构建和依赖要求相当复杂,以至于仅仅运行该软件就需要大量的人力投入。 (如果情况是那样的话,该项目也将很难吸引开发人员的参与!)

发行机制应该尽量做到方便,标准化以及清楚无误。假如你要根除一种疾病,你分发的药物不会是需要一种非标准化的注射器来操作的吧。同样的道理,软件应该与标准化的构造和安装方法相一致;一个软件距离标准化越远,用户和开发人员放弃该软件并且一头雾水地离开的可能性就越大。

那听起来是显而易见的道理,但是许多项目往往等到很晚的时候才动手解决标准化安装程序,因为他们总是告诉自己这一步什么时候都可以做:“等到代码接近完工的时候再来解决这些所有的问题吧。”殊不知在拖延完成软件建设和安装程序这类枯燥工作的时候,他们实际上是在推迟完成代码的时间—因为他们让一些本来可以为软件编程做贡献的开发人员失去了兴趣。最糟糕的是,他们根本就不知道他们失去了那些开发人员,因为那是一连串无果而终的一个过程:某人拜访了一个网页,下载了软件,试图参与构建,失败了,放弃而离开了。除了拜访者本人以外,谁会知道发生了这一切?项目参与者中谁也不会意识到某位拜访者的兴趣和良好意愿在悄无声息中便被扼杀了。

枯燥但具有高回报的工作应该尽早完成,而通过良好包装便能够大大降低进入项目障碍的工作显然是具有很高的回报率的。

当你发布一个可以下载的软件包时,至关重要的一点是给予这一次发布一个独一无二的版本号码,以便人们对两次发布加以比较,从而了解哪些东西被替代了。有关版本编号的详细讨论见“版本号”一节,而构建和安装程序标准化的详细内容见“打包”一节以及第 7 章 打包、发布和日常开发

版本控制和Bug跟踪访问

下载源码软件包对于只想安装和使用软件的人来说足矣,但对于想要解决bug问题或增加新特性的那些人就不够了。尽管每夜源代码快照会有些帮助,但是对一个活跃的开发社区来说,仍然不够细致。人们需要实时进入最新的代码系统,而能够实现这一点的途径便是使用版本控制系统。如果一个人在匿名情况下便可以获取受版本控制的代码,那就意味着该软件对用户和开发人员昭示:项目正努力为人们的参与创造条件。要是你不能马上提供版本控制,也应该出一个声明,告知人们你会尽快那样做。有关版本控制的基础架构详见第 3 章 技术基础设施中的“版本控制”一节

对于项目的Bug跟踪系统来说,也是同样的道理。Bug跟踪系统之所以重要不只因为它对开发人员十分有用,而且对关注项目的人来说是一种标志。在许多人看来,一个可以进入的Bug数据库是一个项目是否严肃认真的重要标志之一。再者,数据库中的Bug数量越多,项目看起来越好。这听起来似乎有悖常理,但是请记住Bug数量的记录实际上取决于三个因素:软件中存在的Bug绝对数量,使用该软件的用户人数,以及用户记录新发现的Bug的方便程度。在这三个因素当中,后两个比前一个重要得多。任何具有一定规模和复杂性的软件基本上都存在一定数量有待被发现的Bug。真正的问题是,一个项目在记录和优先解决Bug问题方面做得有多好?如果一个项目有一个较大而又维护得很好的Bug数据库(意思是bug问题得到及时地回应,重复bug被合并等等),那么这个项目就会比那些没有Bug数据库,或者Bug数据库里空空如也的项目给予人们更好的印象。

当然,如果你的项目刚刚起步,那么Bug数据库里就只有为数不多的Bug,而对此你也没有什么办法。但是如果在开发状况页强调项目仍处于初创期,且人们看到bug数据库里大多数的文档都是近期建立的,他们便可以由此推断出该项目仍然有良好的解决,也就不会因为看到相对较低的已经记录的Bug绝对数量而产生不适当的警觉。

请注意Bug跟踪系统的用途不止追踪软件的Bug,而且也用来跟踪扩展请求,文档变更,待解决的任务,以及其它一些问题。运行一个Bug跟踪系统的详细内容见第 3 章 技术基础设施中的“Bug跟踪”一节,所以在此我就不赘述了。重要的是,Bug跟踪一定要显示出来,而且要确保项目的首页上便能看到这一点。

沟通渠道

项目的访客通常都希望知道如何能联系上参与项目的有关人员。提供邮件列表地址、聊天室、IRC频道、以及任何其它形式的论坛,以便其他参与项目的人同样可以联系上。告诉人们你和项目的其他有关人员都在邮件列表上,因而人们便知道他们有途径将回馈传递给开发人员。你在邮件列表上并不意味着你承诺回答所有的问题,也不等于你要满足所有人提出的有关特性的要求。长远来看,大多数用户或许根本从不参与论坛,然而,如果他们知道他们需要的时候可以那样做,那对他们就是一种欣慰。

在项目开发初期,没有必要将用户论坛与开发人员论坛分开。更好的办法是让所有与软件有关的人员在“同一间屋子”里进行交谈。在早期使用软件的人当中,开发人员与用户之间的界线通常很模糊;不是没有界线,但是开发人员与用户之间的比例在项目早期远远高于后面的阶段。尽管我们不能假设每一位早期与项目有关的人都是想要介入软件开发的编程人员,但是我们可以肯定他们至少很有兴趣地关注项目发展中进行的讨论,并了解项目发展的方向。

由于本章只讨论项目的初建,所以在此我们只要说明有必要建立以上所说的交流论坛就行了。稍后,在第 6 章 交流中的“处理成长”一节,我们将讨论在什么地方以及如何建立这样的论坛,及可能需要的协调和其它方面的管理,另外,在时机成熟的时候,如何分离用户与开发人员的论坛而避免造成无法逾越的鸿沟。

开发者指南

如果有人考虑参与项目,她会寻找开发者指南。与社会性文档相比,开发者指南通常没有很多的技巧:只需要解释开发者之间,以及与用户之间如何交互,以及如何最终完成任务。

这部分的细节可以看第 4 章 社会和政治的基础架构中的“写下所有的内容”一节,但开发指南的基本元素包括:

  • 与其它开发者交流论坛的链接

  • 报告Bug和提交补丁的指导

  • 说明进行开发的方法—项目是仁慈专制、还是民主的、还是其它。

对于“专制”这里没有任何轻蔑的含义。如果存在一个开发者对所有变更拥有否决权,这完全没有问题。许多成功的项目以这种方式进行。关键是项目能够说出来它的做法。一个假装民主的独裁会让人厌恶;如果独裁者只要有能力并被信任,一切都会很好。

完整的开发者指南实例可以看http://svn.collab.net/repos/svn/trunk/www/hacking.html,或者是更加关注管理和参与精神,而较少关注技术事务的http://www.openoffice.org/dev_docs/guidelines.html

为程序员提供单独的软件指导的问题会在本章后面的“开发者文档”一节讨论。

文档

文档非常必要。需要有一些用户可以读的内容,即使它非常基本和不完整。在初期这样做确实是一件“苦差事”,经常成为新开源项目的第一个失败之处。提出使命声明和特性列表、选择一个许可证、概述开发状态—这都是相对的小任务,完成后通常可以不必返回继续工作。而另一方面,文档永远没有真正的结束,这可能也是人们总是延迟开始文档的一个原因。

一个隐伏的事实是,文档对于编写者的功用与阅读者的功用是相反的。对于初始用户来说最重要的是基础文档:如何快速配置软件,软件如何工作的概述以及一些常规操作的指导。而这些通常是编写者所非常熟悉的内容—以至于很难从读者的角度看问题,因而他们不会费力去表述一些非常明显而不值一提的步骤。

对这个问题没有神奇的解决办法。必须有人坐下来写好内容,然后交给普通的用户来验证它的质量。使用简单和容易编辑的格式,例如HTML、纯文本、Texinfo或一些XML的变种—便于在激励下可以轻型和快速的作出改进。这不仅是为了消除最初作者进行增量改进所带来的代价,也是为了希望修改文档的新加入者。

一个保证基本初始文档完成的方法是预先限制其范围。这种方法至少不会让我们感觉是在完成一个开放结尾的任务。一个经验是它必须达到下面的最低标准:

  • 告诉读者他们所需的技术技能。

  • 清楚和完整的描述如何配置软件,并在文档的开头部分告诉用户如何运行确认安装成功的诊断测试或简单命令。启动文档有时候比使用文档更重要。一个人投入到软件安装和开始的努力越多,她就越有可能持续的搞明白没有很好文档描述的高级功能。当人们放弃时,他们会很早就放弃;因此,在早期阶段,例如安装时,需要最多的支持。

  • 提供一个普通任务的教程式的实例。很显然,不同任务的例子越多越好,但是时间有限,最好还是选择一个任务并完整的完成它。一旦人们看到这个软件可以使用,他们会开始探索其他需要的功能—如果你足够幸运,他们会自己补充文档。这将会让我们到下一点...

  • 标示文档中未完成的部分。通过向读者展示这些不足,可以实现你与他们观点的联盟。你的移情作用可以使他们恢复信心,不必为确定什么是项目最重要的事情而挣扎。这些标示不需要承诺填补这些空白的期限—它等于是合情合理的公开征集志愿者。

最后一点更广泛重要,也更实际,并可以应用到整个项目中,而不仅仅是文档中。开源领域中一个都知道的问题就是项目规范。你不必夸大项目的这种短处,你只需小心冷静的识别出需要这种规范(说明文档、Bug跟踪数据库或邮件列表讨论中都可以)的场景。就项目而言,没有人会视其为失败主义,也不会认为这是对在特定日期完成的承诺,除非项目明确作出这种承诺。因为使用软件的所有人都会发现这种不足,他们最好能在心理上做好准备—然后项目就有了解决这些问题的坚实知识。

文档的可用性

在两个地方必须有文档:在线(直接在网站上),以及软件可下载分发版本(见第 7 章 打包、发布和日常开发“打包”一节)中。它必须以可浏览的形式在线,因为通常人们会在第一次下载软件之前首先阅读文档,以决定是否下载。但是也必须和软件配套,因为原则上下载中必须包括使用软件包的所有必须内容。

对于在线文档,要确定有一个指向包含完整文档的(请在链接旁注明"monolithic"或"all-in-one"或"single large page",以提醒人们知道需要更长的下载时间)单独HTML页的链接。这是因为人们经常会在整个文档中寻找特定的词汇或短语。通常是他们已经知道他们在找什么;只是记不住具体的章节。对于此类人,最郁闷的就是遇到一个目录页面、然后是指导页面、然后是安装指导等等。当页面是如此琐碎时,浏览器的搜索功能将变得毫无作用。分页的样式适合那些知道他们所需章节,或是从头到尾阅读的人。但这不是访问文档的常规方式。通常是某人已经熟悉了软件,返回来搜索特定的词汇或短语。如果未能提供一个单独的、可搜索的文档会让他们活的很辛苦。

开发者文档

开发者文档主要为了帮助程序员理解代码,从而修改和扩展软件。这与更关注社交性而不是技术性的开发者指南有些许不同。开发者指南告诉程序员如何与代码本身打交道。为了方便,这两个文档通常会整理为一份文档(例如前面提到的http://svn.collab.net/repos/svn/trunk/www/hacking.html),但是这不是必须的。

尽管开发者文档可能很有用,但也没有为了它而影响发布。只要原始作者还在而且愿意,就可以回答关于代码的问题,一开始这就足够了。实际上,反复回答相同的问题是编写这个文档的动力所在。但即使文档还没有写,坚定地参与者也依然会设法以自己的方式处理代码。驱使人们花时间研究代码基的原因是他们发现这些代码对他们有用。如果人们相信这一点,他们就会花时间去搞明白;如果他们不相信,再多的开发者文档也留不住他们。

如果你有时间为一个读者写文档,那还是写给所有用户吧。所有用户的文档,和开发者文档有同样的效果;为软件工作的程序员一定对如何使用也非常熟悉。之后,当你看到程序员反复询问相同的问题时,你就应该为他们编写单独的文档。

一些项目使用wiki作为初始文档,甚至作为他们主要的文档。在我的经验里,只有文档是被少数认可文档的组织方式和包含内容的成员编辑时,才能正常工作。更多细节在第 3 章 技术基础设施“Wikis”一节

输出和屏幕截图实例

如果一个项目包含图形化的用户界面,或者生成图形和其他特别的输出,那么就应该将这些样例放到项目网站上。如果是界面,那应该是截图;对于输出,可以是截图或只是文件。但是为了迎合人们立刻满足的需要:一个单独的截图比大段描述文字和邮件列表的唠叨更让人信服,因为截图是软件能正常工作的不容争辩的证据。它可能充满bug、可能难于安装、可能文档不全,但是截图是一个人投入足够的精力,可以使之运行的证据。

还有一些东西需要放置到网站中,如果你有时间,或者如果出于某种原因而显得特别合适:一个新闻页、一个项目历史页、一个相关链接页、站点搜索特性和捐赠页等等。开始时这些都不是必要的,但将来要一直留意。

包装主机

有一些站点为开源项目提供免费的主机和基础设施:web站点、版本控制、bug跟踪、下载区、讨论论坛和定期备份等等。具体细节站点之间各不相同,通过使用这些站点,你可以免费得到基础服务。但是很明显你也同时放弃了通过用户经验,来进行细化控制的能力。主机服务决定了站点运行的软件,也控制了或至少影响了项目站点的感观。

第 3 章 技术基础设施“包装主机”一节是包装主机优缺点的详细讨论,也有提供这种服务的站点列表。

选择许可证并应用

这部分是关于选择许可证的快速粗糙指南。阅读第 9 章 许可证,版权和专利可以理解不同许可证的法律含义细节,以及这些许可证如何影响人们将你的软件与其他自由软件混合的能力。

确实有大量可供选择的许可证。其中大多数我们这里不必讨论,因为他们通常是为了满足公司或个人的特定法律需求,不会适合你的项目。我们会限制为大多数常见的许可证;大多数情况下,你会从其中选择一个。

“可以做任何事情的”许可证

如果你能够接受你的项目代码会潜在的使用到私有程序中去,可以选择MIT/X-样式的许可证。这是一些最小许可证中最简单的一种,只保留署名版权(实际没有限制拷贝)并指明代码没有任何保证。细节见“MIT / X Window System License”一节

GPL

如果你不希望你的代码在私有程序中使用,可以使用GNU的通用公共许可证。GPL可能是当世最广泛公认得自由软件许可证。在本质上是一个巨大的优势,因为许多潜在的用户和贡献者已经对此许可证十分熟悉。更多细节看第 9 章 许可证,版权和专利“GNU General Public License”一节

如何为你的软件应用许可证

一旦你选择了一个许可证,你必须在项目首页注明。你不必引入许可证的实际文本;只需要提供许可证的名称,并提供到完整许可证文本的链接。

这告知公众你希望软件按照何种许可证发布,但是对于法律目的还不足够。这个软件本身必须包含许可证。一个常见的做法是将许可证全文保存到一个叫做COPYING(或LICENSE)文件中,其中包含了许可证的全文,然后还要注意在每个源文件的开头,注明版权日期、所有者和许可证,以及何处可以找到版权全文。

这个模式也有许多变种,所以我们这里看一个实例。GNU的GPL说可以在每个源文件的开头放置如下的提醒:

Copyright (C) <year>  <name of author>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

并不是说随程序收到的许可证拷贝在文件COPYING中,而是它通常放置在那个地方(你可以在上面的声明中直接注明位置)。这个模板给了获取许可证版权的地理地址。另一个常见的方法是提供包含许可证的网页链接。只要使用你的判断并指出你认为版权能够永久保存的位置,也可以是你项目网站的某个位置。一般来说,你在每个源文件放置的通告不会和上面这个完全一样,只需要其包含版权持有者和日期,以及版权的名称,并明确指明完全许可证的位置即可。

设置风格

我们已经覆盖了配置项目时的大多数一次性任务:选择一个许可证,安排初始的网站等等。但是开始一个新项目时最重要的方面是会变化的。选择一个邮件列表地址很容易;而保证列表的对话不走题且有效率则完全是另一回事情。如果项目经过多年的关闭,内部的开发,重新开始时开发过程将会改变,你需要准备开发者来应对这种变化。

第一步是最难的,因为未来管理的先例和预期都没有设置。正式的规则还没有带来项目的稳定性,而是由开发过程中共享的难以稳定的团体智慧带来。也许有已经写好的规则,但通常是通过难以预料的,不断进化的协议来引导项目。写好的规则不能定义其描述的项目文化,即使后来也是近似而已。

这里是如此解决问题的一些原因。成长和高转化率不会像一般人想象的那样损坏社会规范的积累。只要变化不要快,就有时间让新来者学会如何做事,在他们学会之后,他们自己就会来加强这种方式。考虑一下数世纪以来儿童歌曲的发展。现在孩子们演唱的歌曲和几百年前有大致相同的韵脚,即使现在的孩子从来没有生活在那个时代。小点的孩子听到大点的孩子唱歌,然后当他们长大了,他们又会在更小的孩子面前演唱。孩子不是故意参与这个传递程序,当然,这些歌曲的传承确实是因为有规律和重复的传递。自由软件项目不会以世纪(我们还不能知道)作为测量的时间刻度,但是变化和传递非常类似。转化率更快,不管怎样,必须以更活跃和慎重的传递投入来作为补偿。

人们通常会期望和寻找社会规范的事实,会成为这种努力的辅助。这也是人类的做法。在任何以共同努力统一的团队中,加入者都会凭直觉寻找可以将自己标记为团队一部分的行为。尽早设定先例的目标是让这些“组内”行为对于项目发生作用;一旦建立,多半会生生不息。

通过特定实例,你可以设置好的先例。这不必是一个完整的列表,但是通过尽早设置这样的协作情绪的方法,可以大大的帮助项目。从物理上讲,每个开发者都在自己的房间独立工作,但是你可以设法让他们感觉是在一个房间一起工作。他们这样的感觉越多,就会在项目上花费更多的时间。我选择了这些例子,因为这些实例来自Subversion项目(http://subversion.tigris.org/),而我从一开始就参与并观察了这些实例。但是这不仅仅对Subversion有效;大多数开源项目中都会遇到类似的情形,这是开个好头的好机会。

避免私下讨论

即使你已经将项目公开,你和你的创始人也会经常希望通过私下讨论来解决困难的问题。这在项目的开始阶段尤其明显,因为此时需要做出许多重要的决定,而只有少量志愿者能够胜任。你会发现公开讨论的明显缺点:邮件对话本身的延迟性,需要保留足够的时间来达成一致,处理自以为是的幼稚的志愿者(每个项目都有;有些将来会成为明星贡献者,而有些会永远保持幼稚),也就是那些不能理解你为什么只希望解决问题X,而X明显是大问题Y的子集的人。秘密决定并使之成为既成事实,或者至少成为联合和有影响力的投票集团的坚实推荐,确实非常有吸引力。

不要这样做。

尽管公开讨论可能很笨重,但是从长远来看这样做更合适。私下里做出重要的决定就像是将贡献者排斥出项目一样。没有重要的志愿者会愿意呆在这样一个由秘密委员会做重要决定的环境里。此外,公开讨论也会从其副作用中获益,无论是多么短暂的技术问题,一经发起都会一直讨论下去:

  • 讨论有助于训练和教育新开发者。你不知道有多少双眼睛在关注着讨论;即使大多数人不会参与,仍然可能有很多人在静静的跟踪,收集软件的信息。

  • 讨论会训练如何向不熟悉软件的人们解释技术问题。这种技巧需要练习,你不能从已经知道你所知道的人那里获得这种练习。

  • 之后,讨论和结论将会一直存放在公共归档中,可以保证以后的讨论不会回到同样的步骤中。见第 6 章 交流“归档的显著使用”一节

最后,很有可能某个人会提出一个你从想到过的好主意,给对话带来真正的贡献。很难说这有多大的可能;这仅仅由代码的复杂程度和需求的专业程度决定。但是如果允许我使用轶事作为证据,我会证明这样做比直觉所期望的结果更好。在Subversion项目,我们(创始人)相信我们面对的是一组深入而复杂的问题,为此我们痛苦思考了几个月,我们很明确的怀疑在新建立的邮件列表中的会有任何人做出真正的贡献。所以我们选择了一条比较懒惰的方式,开始通过私下邮件讨论技术想法,直到项目的一个观察者[10]嗅出了问题,并要求将讨论公开。眨了眨眼我们这样做了—后来的结果让我们十分惊讶,我们很快便获得了许多有见地的回复和建议。大多数情况下人们提供的想法都是我们从来没有想到的。结果是邮件列表中一下子多了许多非常英明的人;他们只是在等待正确的诱饵。可以肯定地是公开讨论比私下讨论会保持更长的时间,也能得到更多的产出,花费额外的时间是值得的。

我们不必把问题总结为:“团结就是力量”(我们已经见过许多更成功的团队),但可以确认的是有一些事情适于在团队中完成。首先是有了大量的审阅;其次是快速产生大量的想法。想法的质量由其所针对的思想决定,当然,在你用挑战性的问题刺激他们之前,你无法判断这些思考者是那种人。

当然,也有许多讨论必须在私下进行,通过此书我们会看到这种例子。但是我们有一个指导原则如果没有保持秘密的原因,那就公开进行。

要想使之发生,我们需要行动。仅仅保证自己所有的通告公开是不够的。你也需要劝说其他人放弃不必要的私下讨论。如果某个人尝试开始没有必要的私下讨论,你要义不容辞的立刻进行恰当的元讨论。在你将讨论成功的引入公开场所之前,不要对原始主题做出任何回复,或者去确定私下进行是否必须。如果你一贯如此,人们会很快会意,并开始首选公开论坛进行讨论。

防无礼于未然

从项目的一开始,你就应该保持论坛中粗鲁和无礼行为的零容忍。零容忍不是指技术上的实质强制。当有人侵犯其他用户,你不需要将其从邮件列表中删除,或因为其无礼的回复而收回其回复权限。 (理论上讲,可能最终你必须诉诸这类行动,但应该是其他方法失败之后才采用—这需要清晰的表述,而不应该是项目开始的情况。)零容忍指的仅仅是决不漏掉任何此类坏行为。例如,有人发布的技术回复中掺杂了对某一个项目开发者的个人偏好的攻击,首先你应该紧急回复来指明这种个人偏好的攻击,并指出作为技术问题本身,应该只包含技术内容。

不幸的是这并不很容易,更普遍的是,建设性的讨论演变为破坏性的论战。人们会在邮件里谈事情,而永远不会面对面谈论。讨论的主题只是放大了这种效果:在技术问题中,人们经常感觉对大多数问题有一个唯一的答案,而对此答案的异议只能被解释为无知或愚蠢。某人技术提议的愚蠢与某人本身的愚蠢不算太远。实际上,有时候很难说出技术争论和人身攻击从哪里开始,这也是激烈回复或惩罚不是好主意的一个原因。相反,当你发现此类事件发生,你应当回复来强调保持友善讨论的重要性,而不要指责任何人是故意为害。可惜这种“软规则”回复有点像幼儿园老师教导学生学习好的行为:

首先,请减少带有个人倾向的回复;例如,称J的安全层设计对“计算机安全基本原理的幼稚和无知”。这样说对错都有可能,但是无论何种情况,我们都无法进行讨论。J真心诚意地提出意见。如果存在Bug,请指出来,我们会进行修正并得到新的设计。我确定M对于J并无人身攻击,但是措辞是不合适的,我们会努力保持事务的建设性。

现在,对于这个建议。我认为M所说的是正确的...

因为此回复的不自然,会有显著的效果。如果你对于坏的行为保持一贯的行动,而不是要求攻击方进行道歉和承认,这样就让人们可以自由的冷静下来,而在下一次能够表现的更有礼貌一点—他们会的。这样做能成功的诀窍是不要将元讨论作为主题。它必须放在一边,成为回复主要部分的简短序言。通过顺便提及指出“我们这里不是这么做的”,然后转移到真正的内容,这样你就给了人们一些可以回复的话题。如果有人抗议他们不应该受到你的责难,只需要拒绝讨论这个问题。除了不回复(如果你认为他们只是精力过剩,不需要回复),也可以说你为反应过度而道歉,而且在邮件中很难感到这种微妙之处,然后回到主题。绝不在任何时候要求一个人为不合适行为作出承认,无论是公开还是私下的。如果他们选择随自己的意愿进行道歉,那样很好,但是要求他们那么做只会导致怨恨。

总体目标是将好的礼节视为“团队内”的行为。这可以帮助项目,因为开发者会由于论战而流失(即使是他们喜爱和希望提供支持的项目)。你可能甚至不知道他们为什么离开;有些人可能一直潜伏在邮件列表,考虑到加入到项目需要的厚脸皮,就会决定放弃加入。保持论坛的友善是一个长期生存策略,在项目还比较小的时候,这很容易。一旦这成为了文化的一部分,你就不是唯一提升这种文化的人。所有人会一起维护。

实践明显的代码评审

促进开发生产率的一个最好的办法就是让人们互相察看代码。需要一些技术基础设施来进行有效的支持—特别是提交邮件应该开启;更多细节见“提交邮件”一节。提交邮件的作用就是每当有人提交了源代码的修改,就会发送一封包含日志信息和变更差异(见“版本控制词汇表”一节差异(diff))的邮件。 代码评审是在代码来到时对提交邮件进行评审,寻找Bug和可能的改进的实践。[11]

代码评审同时满足多个目标。这是开源世界的同级评审中最明显的一个例子,直接促进维护软件的质量。软件的每一个Bug都是提交进来的,而且没有被发现;因此,关注的眼睛越多,将会带入越少的Bug。但是代码评审也有非直接的目标:它确认了人们所真正关心的东西,因为很明显一个人不会去花时间评审他不关心的功能。当人们知道会有人花时间评价他的工作,他们就会倾尽全力。

评审必须是公开的。即使有时我与其他开发者坐在同一个物理房间,我们中的一个做出了提交,我们也尽量不在房间中进行口头评审,而是将其发送到开发邮件列表。所有人会从看到发生的评审获益。人们紧跟着评论,有时会在其中发现瑕疵,即使没有发现,这也会一直提醒他们评审是一个预期的,有规律的活动,就像刷盘子和割草坪。

在Subversion项目,开始时并没有建立有规律的代码评审实践。无法保障所有的提交会得到评审,尽管如此,还是会有人在看到感兴趣的代码块时看一下修改。一些小Bug确实能够,也应该被发现。一个叫Greg Stein的开发者,从以前的工作知道代码评审的重要性,决定通过评审每个单独提交到源代码库的每一行来设立一个范例。每当有人提交,邮件列表就会紧跟着出现Greg的邮件,解剖这次提交,分析可能的问题,偶尔还会赞扬一下聪明的代码。很快,他就发现了其他人会略过而不会注意的Bug和非最优的代码实践。更深刻的是,他从没有抱怨他是唯一评审所有提交的人,尽管这样做占用了他很多时间,但是他确实一有机会就会盛赞代码评审。不久之后,其他人,包括我也开始了有规律的提交评审。我们的动机是什么?不是Greg有意识的让我们为此感到羞愧。而是他已经证明代码评审是值得花费时间的方法,它的贡献与编写新的代码不相上下。一旦他证明了这一点,它就成为预期的行为,以至于如果一个提交者发现没有人对其提交有任何反应,他会感到担心,甚至会在列表中讯问是否有人愿意花时间为其评审。不久之后,Greg得到一个工作,他也没有更多时间为Subversion工作,结束了有规律的评审。但是之后,他的习惯深深影响了我们,似乎这样做是天经地义的。

从第一个提交就开始评审。差异评审中最容易检查出来的问题包括安全漏洞、内存泄露、注释不足或API文档问题、位偏移错误、调用/被调用不匹配以及其他在较小的上下文就能发现的问题。然而,即使这类未能将重复的模式抽象到一处的较大规模问题,在经过有规律的评审后也可以被定位出来,因为对以前差异的记忆提醒了对当前差异的评审。

不要担心你未能发现任何需要回复的内容,或者你不是很清楚代码的每个部分。通常几乎每一次提交都会要说什么事情;即使你没有发现任何事情可以提问,你还是可能发现一些事情可以对其称赞。最重要的是让每个提交者清楚,他们所做的事情都正在被关注和理解。当然,代码评审不能让程序员逃脱在提交之前评审和测试他们所做变更的责任;人们不应该依靠代码评审来捕捉本应该他自己捕捉的问题。

将一个封闭项目开放时,对于改变的影响要格外敏感

如果你开放一个已存在的项目,其中已经有了许多习惯于在封闭源代码环境下工作的活跃开发者,你必须确保每个人理解正要发生的重大变化—你必须设身处地的为他们着想。

想象一下他们面对的情形:以前,所有的代码和设计决定都是由一组程序员做出,他们对软件有差不多相等的熟悉程度,而且都是从同一个管理中接受相同的压力,而且清楚其他人的长处和弱点。现在你让他们将代码暴露给随机的陌生人监视,而他们只会根据代码形成判断,而不会考虑造成这种决定的商业压力。这些陌生人会询问很多问题,这些问题让已有的开发者发现无论如何为文档苦干,仍然不足(不可避免的)。最关键的是,这些新来者是未知的,未露面的实体。如果你的一个开发者已经感觉到他的技艺不够安全,想想一下当新来者指出他所写代码的Bug时的严重性,更严重的,在他的同事面前。除非你有一个拥有完美编码员的团队,这是不可避免的—实际上,对于每一个人开始都会发生这种情况。这不是因为他们不是好程序员;只是因为任何超过一定规模的程序都会有Bug,而同级评审可以发现一些此类Bug(见本章前面的“实践明显的代码评审”一节)。而此时,新来者开始本身并没有受到同级评审的支配,因此他们在熟悉项目之前不能贡献代码。对你的开发者,感觉指责正在到来,绝不会离开。因此,要小心这些老手的人心散了。

防止发生这种情况的最佳方法是警告每个人即将发生的情况,告诉他们开始的不适是完全正常的,鼓励他们一切都会好起来的。有一些警告应该在私下发生,在项目开放以前。但是你也会发现如果在公共列表中提醒人们会有好处,告诉他们这是项目开发的新方式,需要一段时间来调整。你能做的最好的事情是通过实例进行引导。如果你看到你的开发者无法回答足够多的新手问题,那么只要告诉他们回答更多也于事无补。也许他们对于何种问题需要保证回复没有太好的感觉,或者他们对于如何排定代码工作和新的外部沟通交流负担的优先级没有感觉。让它们参与进来的方法是你自己参与进去。作为一个公开邮件列表,确保在那里回答一些问题。当你没有回答某个问题的技能时,要明确的交给能做的开发者—然后观察确保有回答或至少是一个回应。当然现在还是有长期开发者进行私下讨论的诱惑,因为他们一贯如此。请确定你已经订阅了可能发生问题的内部邮件列表,并且告知他们此类讨论应该立刻公开。

对于开放的封闭项目,还有一些其它的长期关注。第 4 章 社会和政治的基础架构探索了混合付费和未付费开发者的技巧,第 9 章 许可证,版权和专利讨论了当公开的私有代码基包含其它组织编写或“拥有的”软件时所必须承担的法律义务。

通告

一旦项目可以展示了—不必完美,只要能看—就可以将其通知给世界了。这是一个非常简单的过程:来到http://freshmeat.net/,在顶端的导航栏点Submit,然后输入你的新项目的通告。Freshmeat是一个大家关注新项目通告的地方。你只需要在那里用项目新闻抓住一些眼球,就会众口相传。

如果你知道某个邮件列表或新闻组会对你的项目合题或感兴趣,那么请在那里通告,但请注意,一个论坛只有一个通告,将人们引向项目本身的论坛,进行后续的讨论(通过设定Reply-to头)。这种发布一定要简短扼要:

To: discuss@lists.example.org
Subject: [ANN] Scanley全文索引项目
Reply-to: dev@scanley.org

这是关于Scanley项目的一次性公告,Scanley是一个包含丰富API的开源全
文索引和搜索引擎,主要为程序员提供对于大组文件的搜索服务。Scanley
现在是可运行的代码,正在进行活跃的开发,征集开发者和测试者。 

主页: http://www.scanley.org/

特性:
   - 查找纯文本、HTML和XML
   - 单词和短语查询
   - (计划) 模糊匹配
   - (计划) 增量更新索引
   - (计划) 索引远程网站

前提条件:
   - Python 2.2或更高
   - 包含索引的足够空间 (大约原始数据的2倍大小)

更多信息,请访问scanley.org。

谢谢,
-J. Random

(有关后续发布版本,以及项目其他事件的通告建议,请看第 6 章 交流“公开性”一节。)

对自由软件世界是否应该以一个可执行的代码作为开始,以及在设计/讨论阶段就进行公开是否有益还存在着争议。我过去认为从一个可执行的代码开始是非常重要的因素,这是成功项目和玩具的重要区别,慎重的开发者只会加入有一定事实的软件。

但也有例外。在Subversion项目,我们从设计文档、一组核心的感兴趣和紧密联系的开发者、许多热闹的介绍和能运行的代码开始。完全出乎我的意料,项目从一开始就获得了活跃的参与者,当我们可以运行什么时,已经有不少志愿开发者已经深入参与进来。Subversion不是唯一的例子;Mozilla项目也是从不能运行的代码开始,现在成为了成功和流行的web浏览器。

面对这种证据,我必须回过头来看可运行代码是启动项目必要条件的断言。可运行程序仍然是成功的最重要基础,一个好的经验法则是直到可以运行再开始公告项目。然而,有一些环境下,尽早通告是有意义的。我想这时起码要有完成良好的设计文档,或其他代码框架—当然,这也许需要根据公共反馈调整,但是要有一些实际的东西,比好的意图更确切地东西,让人们可以动动牙齿。

无论你何时通告,不要指望立刻有一大堆志愿者会到来。通常情况下,通告的结果是得到很少随意的询问,以及一些人加入你的邮件列表,除此之外,一切如常。但随着时间的流逝,你会逐渐发现代码贡献者和用户参与的增加。通告仅仅是播下种子。消息的传递需要很长时间。如果项目持续回报参与者,这个新闻就会传播,因为人们喜欢分享他们所发现的好东西。如果一切都好,指数级交流网络的动力会慢慢将项目改变为复杂的社区,你不必再知道每个人的名字,也不必跟踪每一次对话。下一章我们将讨论在这个环境下如何工作。



[10] 我们这里不是为了还债,而是实践我前面讲的说教:这位观察者的名字是Brian Behlendorf,他指出了除隐私原因以外,保持所有讨论公开的普遍重要性。

[11] 无论如何,这是开源项目常见的做法。在更集中式的项目中,“代码评审”也也意味着许多人坐在一起,一起察看打印的源代码,寻找特定的问题和模式。

第 3 章 技术基础设施

自由软件项目依赖于选择性捕获和信息集成的技术。对这些技术的使用越是熟练,并说服别人去使用这些技术,你的项目就越成功。随着项目的成长,这一点愈发正确。好的信息管理系统应该能够防止开源项目在布鲁克法则的重压下崩塌[12] ,也就是说向一个已经延期的项目增加人力,只能使项目延期更多。佛雷德·布鲁克观察到,项目的复杂性同参与人员数量的平方成正比。当项目中只有少数几个人时,大家可以容易的互相交谈,但当有上百人参与时,不可能让每个人都能知道别人正在做什么。如果说优秀的自由软件项目的管理是让每个人都感觉是在同一个屋子里共同工作,很明显问题在于:当在一间拥挤的房间内,在同一时刻每个人都想发出声音,会发生什么?

这不是一个新问题。在现实中的拥挤房间中,解决方案是会议程序:我们需要正式的指导规则:包括如何在一个大型团队中进行即时的讨论,如何保护重要的异议不会在一片“我也是”的回复中淹没,如何形成小组委员会,如何识别出何时作出决定等等。会议程序的一个重要组成部分是指明团队如何同它的信息管理系统互动。有些评论“为了被记录”而存在的,有些则不是。记录本身经常是被直接处理的,不能根据字面意义去理解,而是代表了团队已经确立达成共识。记录并非一成不变,为不同的目的会有不同的形式。它可以包括个人会议记录、每次会议的完整记录、摘要、议程及其注解、委员会报告,来自未出席通信者的报告,活动项目列表等等。

因为互联网并不是一个真实的房间,所以我们也无须担心去复印诸如让部分人在别人讲话时保持安静之类的议会程序。但当它和信息管理技术接合时,一个运作良好的开源项目就会是打了兴奋剂的会议程序。由于开源项目中的交流都是通过书写方式完成的,由此发展出了复杂的系统:为了恰当导向和标记数据;为了避免会造成误解的重复;为了储存和检索数据;为了纠正错误和废弃的信息;以及为了在发现不相关信息的新关系时进行关联。开源项目中的活跃参与者已经将掌握了其中的很多技术,并且经常为了确保信息被正确的导向而进行复杂的手工任务。但是所有的努力都是依赖于复杂的软件支持。交流媒体应该尽可能地依靠自身完成发送、标签和记录工作,应该确保人尽可能方便地得到这些信息。当然在实际中,在整个过程中的很多方面还是需要人的干预,并且重要之处在于软件使得这种干预也是方便的。但总得来说,如果人能确保首次进入系统时信息的导向和标签都是正确的,软件应该被配置成可以充分利用这些元数据。

此章中的建议都是非常务实的,都是基于明确的软件和使用模式的经验。但这里不仅仅是教授实用的技术。而是通过许多小范例来演示一种总体态度,这种态度可以最大程度的促进你项目中的好的信息管理。这种态度包含了技术技巧同人力技巧的结合。并且技术技巧是关键,因为当新的需求出现时,信息管理软件总需要配置,以及一定量的持续维护和调整(例如,关于如何处理项目成长的讨论参加本章后面的“Bug跟踪的预过滤”一节)。人力技巧也是不可或缺的,因为人类社区也需要维护:如何利用这些工具的优势有时候不是立刻就很明显,在有些项目案例中甚至有冲突的习惯(例如,参见“邮件列表”一节中的关于在外发的邮件列表通告中设置Reply-to头的讨论)。应该鼓励项目相关的每一个人在正确的时间、正确的地点尽自己的职责来保持项目信息组织的良好。贡献者参与的程度越深,就越能预期她能学习更复杂和专业的技术。

信息管理没有现成的解决方案。有着众多的不确定因素。你可能好不容易才把所有事情都按照自己的意愿完成配置,并且社区的大多数人参与进来,但随着项目的成长让某些实践不能扩展。或者本来你的项目正在稳步发展,技术基础架构也能使开发者和用户的社区关系融洽,但突然某些人出现,发明了一个全新的信息管理服务,很快新来的会质问为何你的项目不用它—例如很多在维基(参见http://en.wikipedia.org/wiki/Wiki)发明之前建立的自由软件项目就正面临这一问题。很多问题需要决断,比如权衡生产信息的方便性还是消费信息的方便性,或者权衡花在配置信息管理软件上的时间与其为项目带来的益处。

小心过度自动化的诱惑,请自动化那些真正需要人们关注的东西。技术基础架构是重要的,但推动一个自由软件项目运转的是参与的人的意愿—用智慧的方式表达的意愿—通过人的参与。技术基础架构只是为人门达到这个目标提供便利。

一个项目需要什么

大部分开源项目至少提供了最低限度的标准工具用于管理信息:

网站

主要是一个集中将项目信息发布给公共的单向渠道。网站也可以作为其他项目工具的管理界面使用。

邮件列表

通常会是项目中最活跃的通讯手段,是“可记录的媒介”。

版本控制

让开发者可以方便地管理代码的变更,包括回复和“变更转运”。让每一个人能看到代码的变化。

Bug跟踪

使开发者可以追踪他们正在工作的内容,互相协调,以及计划发布。让每个人都能查询Bug的状况并且记录特定Bug的信息(例如重现方法)。不仅能用于对bug的追踪,而且能用于任务、发布和新特性等等。

即时聊天

一个可以快速和方便的进行讨论和问答的地方,缺点是并不总是能完整地归档。

这个工具集中的每个工具满足了不同的需要,但它们的功能都是相关的,这些工具必须能协同工作。下面我们将检验它们怎样做到这一点,而最重要的是如何让人们使用它。网站将放在最后讨论,因为它更多的是扮演其他组件黏合剂的角色,而不是工具本身。

通过使用包装主机你也许能避免很多选择工具和配置的头疼事,包装主机是一个提供预包装,模板化的网页区域,以及可运行一个自由软件项目的所有工具的服务器。关于包装主机优缺点的讨论可以看本章后面的“包装主机”一节

邮件列表

邮件列表有如项目交流的面包和黄油。如果用户在除了网页之外的地方浏览,最有可能是项目的某一个邮件列表。不过在体验邮件列表本身之前,他们将接触邮件列表的界面—也就是加入列表(“订阅到”)的机制。由此带来了邮件列表的#1法则:

不要试图手工管理邮件列表—让软件来做。

放弃这一点充满诱惑,开始时就设置软件来管理邮件列表看起来有些小题大做了。手动管理小型低流量的邮件列表似乎是理所当然的:你只需设置一个指向自己的订阅地址,然后当有人向其发送邮件,你把他们的邮件地址加入(或是删除)一个保存了所有地址的文本文件中。还能比这更简单的吗?

问题在于,人们所期望的好的列表管理并非是如此简单。它不仅只是按用户的需求订阅或是退订而已。还包括防止垃圾邮件,提供发送邮件列表摘要而不是每条信息都发送的的形式,通过自动应答机提供标准列表和项目信息,以及许多其他事情。一个由人监控的订阅地址只能支持最小数量的简陋功能,而且在可靠性和反应速度上也不如软件。

现代化的列表管理软件至少提供了以下这些特性:

同时通过邮件和网页订阅

当用户订阅一个列表时,她应当能立即收到一条表示欢迎的回复,告知她订阅了什么,下一步该如何使用邮件列表软件,并且(也是最重要的)告知如何退订。当然,这个回复还应该能被定制地加入诸如项目的站点,常见问题和回答等项目的特定信息。

可选择摘要或是每个信息单独发送的订阅模式

选择摘要模式,订阅者每天会收到一封包含当天所有列表活动的邮件。对那些并不紧跟列表,不会参与讨论的用户,摘要模式更合适他们,因为这允许他们在任何时刻一次检索所有的主题,避免了随机时间到来邮件的分神。

审核特性

在邮件发送到整个列表之前的“审核”是检查邮件以确保:a) 不是垃圾邮件,以及b) 符合主题。审核必须有人参与,但软件能很大程度的使之变得容易。后面还有关于审核的更多内容。

管理界面

不管一些其他的作用,这个特性至少能让管理员轻松地进入列表并删除一个废弃的地址。当一个订阅者的地址开始自动地对每一封列表邮件发出“我已不在这个地址”的回复时,情况就变得非常紧急了。 (有些邮件列表管理软件甚至能依靠自身捕获这种情况,并自动完成退订。)

邮件头处理

许多人在自己的电邮客户端中设置了精密的过滤和回复规则。为了利用这些优势,邮件列表管理软件能为这些人添加和处理某一种标准的邮件头(更多详细内容参阅下面)。

归档

发往被管理列表的所有邮件都会被保存,并且能够通过网页访问;有些邮件列表软件以可插入的形式提供外部归档工具如MHonArc(http://www.mhonarc.org/)的接口。就像第 6 章 交流“归档的显著使用”一节所讨论的,归档很重要。

所有这些的要点是为了强调邮件列表管理是一个复杂的问题,已经耗费了许多思考,而且大多数已经被解决。你确实无须成为一个专家。但你应该知道,虽然其中大部分已被解决,但总还有进步的空间,在运作一个自由软件项目的过程中列表的管理将一次次地占据你的注意力。下面我们将回答几个有关邮件列表配置的最常见问题。

垃圾邮件防护

这些话从动笔到出版的这段时间里,因特网上的垃圾邮件问题很可能又严重了一倍—或至少给人的感觉是如此。有那么一段时间,就在不久之前,当时可以完全无须任何的垃圾邮件防护措就能运转一个邮件列表。偶尔会有那么几封,只能构成小小的烦恼。好日子已经一去不复返了。现在如果邮件列表没有垃圾防护措施,很快就会被乱七八糟的邮件淹没,以至于不可用。必须实施垃圾防护。

垃圾防护分为两种类型:防止垃圾邮件出现在你的邮件列表中,防止你的邮件列表成为垃圾制造者地址收割机获取新邮件地址的一个源。前者更重要,所以我们首先研究。

过滤邮件

垃圾邮件防护有三种最基本的技术,大部分的邮件列表软件都会提供,最好能串联使用:

  1. 只自动允许来自列表订阅者的邮件。

    只要使用就有效,因为通常只需要在邮件列表软件的配置中做一点小小的改动,所以只需要很少的管理投入。但注意,那些不能自动认可的邮件不能简单地销毁了事。相反,必须传递给审核程序,有两个原因。首先你希望允许非订阅者的邮件。仅仅想问一个问题或是提供建议的人,不应该只为了发一封邮件而需要订阅整个列表。其次,有时甚至订阅者都有可能从非订阅时用的地址发出一封邮件。邮件地址不是鉴别人的可靠方法,它不该被如此对待。

  2. 通过垃圾过滤软件过滤邮件。

    如果邮件列表软件允许(大部分是),你能用垃圾过滤软件来获得过滤后的邮件。由于在垃圾制造者和过滤器编写者之间进行着一场永不停息的军备竞赛,自动垃圾过滤从来不是也永远不会是完美的。然而,它可以大大减少进入审核队列的邮件数量,因为更长的列表需要更长的人工处理时间,一定程度的自动过滤总是有益的。

    这里没有空间来详细地介绍垃圾过滤的设置。你应该查阅你的邮件列表软件的文档(见本章后面的“软件”一节)寻求答案。列表软件通常会有一些内置的垃圾防护功能,但也许你想要添加一些第三方的过滤器。推荐两个我有良好体验的软件:SpamAssassin (http://spamassassin.apache.org/) 和SpamProbe (http://spamprobe.sourceforge.net/)。这并非是对众多的其他开源垃圾过滤器的不敬,其中的一些显然也是非常好的。只是这两个是我曾经亲身使用过的,并且它们让我很满意。

  3. 审核。

    由于不是列表订阅者的原因而未能自动许可的邮件,就会根据设置进入垃圾过滤软件,最后一个阶段将是审核:邮件将被发送到一个特殊的地址,那里会有人来检查和决定是许可还是拒绝。

    许可一个邮件有两种形式:你可以只是这一次接受它,或你可以告诉列表软件为这一封邮件同一发送者以后的所有邮件开绿灯。为了减少以后的审核负担,你很可能会选择后者。具体如何许可在不同的系统之间有很大的差异,但是通常的形式是向一个特殊的地址发送一条带有命令“accept”(代表这一次许可)或是“allow”(允许这次以及以后的邮件)的回复。

    拒绝通常只需简单的忽略所审核的邮件即可。如果列表软件没有收到确认有效的邮件,它不会让邮件通过并出现在列表上,所以简单地扔掉审核邮件就能达到目的。有时你还有其他选择,返回“reject”或是“deny”命令来杜绝以后来自同一个发送者的邮件进入审核程序。但这么做通常没什么意义,因为大部分需要审核处理的都是垃圾邮件,而垃圾邮件制造者不太会从同一个地址两次发出垃圾邮件。

确保审核被用在过滤垃圾邮件和明显是和主题无关的消息上,比如有时会有人意外地在一个错误的邮件列表中发送了邮件。审核系统通常给你一个直接同发送者联系的途径,但是不要用这种方式来回答属于邮件列表本身的问题,即使那些答案就在你的头脑之中。如果这么做了,将会剥夺项目社区了解人们正在问那些类型问题的具体形式,剥夺它们自己回答问题或者获得答案的机会。邮件列表审核除了严格确保列表中没有垃圾和同主题无关的邮件,没有其他了。

归档中的地址隐藏

为了防止你的邮件列表成为垃圾邮件发送者的地址源,一个常见的技术是混淆用户的邮件地址,例如通过替换

jrandom@somedomain.com

jrandom_AT_somedomain.com

jrandomNOSPAM@somedomain.com

或一些类似的明显的(对人类来说)加密。因为垃圾邮件地址收割器通常会遍寻网络—包括你的邮件列表的网络归档—它们会查找包含“@”的字符串,对地址加密是为了让人们的邮件地址对垃圾邮件发送者来说不可见或不可用。这对防止垃圾邮件发送者将邮件直接发送到邮件列表本身无用,但它可以防止直接发送到用户个人地址的垃圾邮件的增加。

地址隐藏可能存在争议。许多人很喜欢,如果你的归档不能自动支持,他们会很惊讶。还有些人认为这样太不方便了(因为人们需要在使用之前转化地址)。有时候用户断定这样做不能产生预期的效果,因为收割器理论上可以弥补任何不变的加密模式。然而,有一个实验证据可以证明地址隐藏有效的,见http://www.cdt.org/speech/spam/030319spamreport.shtml

理想情况下,邮件列表软件为每个订阅者提供选择的机会,通过特别的yes/no头,或者通过订阅者列表帐户的参数选择设置。然而,我不知道有哪个软件提供了每订阅者或每邮件的选项,因此现在列表管理员必须为所有人作出决定(假定归档程序已经提供了这些特性,就不存在这个问题了)。我倾向于适度使用地址隐藏。一些人对于将自己的邮件发布到网页上或其他收割器可能会搜索的地方会非常小心,他们会因为邮件列表归档暴露它们关心的内容而感到失望,归档用户中的地址隐藏带来的不便是轻微的,因为如果你希望联系某个人,将混淆的邮件地址恢复非常容易。但是最后还是要牢记,这是一场军备竞赛:在你阅读到本文的事以后,收割器可能已经得到了进化,能够识别大多数常见的隐藏形式,我们可以想一些其他形式。

身份和头管理

列表订阅者经常希望将来自列表的邮件存放到特定的目录,能够和其他邮件区分开。他们的邮件阅读软件可以自动检查邮件的。这个头是在邮件的顶部,用来指明发送者、接收者、主题、日期和其他邮件相关的东西。某些头是众所周知的,而且是必须有的:

From: ...
To: ...
Subject: ...
Date: ...

还有一些是可选的,尽管也是标准的头。例如,邮件不必有

Reply-to: sender@email.address.here

头,但大多数情况下都有,因为这可以保证接收者(当作者必须从一个不能接收邮件的地址发送邮件的时候这特别有用)能够联系到原作者。

一些邮件阅读软件提供了基于主题头模式的易用界面,可以用来过滤邮件。这导致人们会要求邮件列表为所有的主题提供自动前缀,所以他们可以设置的阅读器查找前缀并自动将文件归入正确的文件夹。如果原来的作者是这样写:

Subject: Making the 2.5 release.

但是列表中显示的邮件会是:

Subject: [discuss@lists.example.org] Making the 2.5 release.

尽管大多数列表管理软件提供这个选项,但我强烈反对开启这个功能。因为这个问题可以通过更自然的方式轻松解决,而且主题字段消耗的空间也太多了。有经验的邮件列表用户通常会扫视每天的列表邮件的主题,然后决定阅读和/或回复哪些邮件。主题中前置的列表名称会使得主题的正式内容脱离屏幕,无法看到。这混淆了人们赖以决定是否打开邮件的信息,从而减弱了邮件列表的整体功能。

我们不会处理主题头,而是让你的用户利用其他标准的头,以To头说起,可以用来说明邮件列表名称:

To: <discuss@lists.example.org>

任何可以过滤主题的邮件阅读器一定也能轻易的处理To。

还有一些其它的邮件列表期望的可选但标准的头。根据这些头过滤比利用“To”或“Cc”头更加可靠;因为这些头是邮件列表软件本身为每个邮件添加的,一些用户会依赖他们的出现:

list-help: <mailto:discuss-help@lists.example.org>
list-unsubscribe: <mailto:discuss-unsubscribe@lists.example.org>
list-post: <mailto:discuss@lists.example.org>
Delivered-To: mailing list discuss@lists.example.org
Mailing-List: contact discuss-help@lists.example.org; run by ezmlm

绝大部分是自解释的,更多解释可以看http://www.nisto.com/listspec/list-manager-intro.html,或者如果你觉得不够详细,正式的规范可以看http://www.faqs.org/rfcs/rfc2369.html

如果你有一个名为“list”的邮件列表,请注意这些头是如何暗示的,然后你也有了管理地址“list-help”和“list-unsubscribe”。除此之外,用来加入的“list-subscribe”和接触列表管理员的“list-owner”也非常常见。取决于你所使用的管理软件,也可能会设置一些其它的管理地址;文档应该会有详细介绍。通常情况下,每个新用户在订阅时都会收到自动的“欢迎邮件”,其中会完整解释所有的特别地址。你可能有这个欢迎邮件的一份拷贝。如果你没有,可以问其他人获取一份拷贝,这样你就知道当你的用户到来时,他们会看到什么。手中有一份拷贝,你就可以回答邮件列表功能的问题,更好一点,可以放置到网页上。这样当有人丢失了自己的指导并询问“我如何从列表退订时?”,你就可以将URL发送个他。

一些邮件列表软件会在每个邮件的底部追加退订信息。如果有这个选项,请打开它。这样只会导致每个邮件有一段额外的行,在一个无害的位置,可以帮助你节省很多时间,减少了给你,或者更坏的情况,给邮件列表发邮件询问如何退订的人数!

伟大的Reply-to辩论

在前面的“避免私下讨论”一节,我强调了保持在公共论坛讨论的重要性,谈论了如何防止私下邮件讨论的一些主动措施,除此之外,本章将会讨论如何设置项目交流软件来更好的做这件事。因为如果邮件列表管理软件提供了一个方法来自动导致讨论保持在列表中,你会认为开启这个功能是显而易见的选择。

好的,有时候也不是如此认为。尽管有这个特性,但是它却有严重的Bug。问题是无论你是否在邮件列表管理中使用这个功能都会成为最热的辩论—诚然,这不大可能成为你城市里的晚间新闻那样的论战,但它会在自由软件项目中一次次的爆发。下面,我将描述这个特性,提供两方面的主要论点,提出我能作出的建议。

这个特性本身非常简单:如果你愿意,邮件列表软件可以在每个邮件中自动设置转向到邮件列表的Reply-to头。也就是无论原来的发送者设置了什么Reply-to头(或者他们没有设置),当邮件列表的订阅者看到邮件时,它的头将会包含列表地址:

Reply-to: discuss@lists.example.org

从表面上看非常好。因为实际上所有的邮件阅读软件会注意到Reply-to头,这样当任何人回复邮件时,他们的回复都会自动来到整个列表,而不仅仅是邮件的发送者。虽然回复者仍然可以手工修改回复的地址,但重要的是缺省的回复会指向列表。这是通过技术鼓励协作的完美实例。

不幸的是,也有一些缺点。首先是找不到回家的路问题:有时候原来的发送者会把“真正的”邮件地址存放到Reply-to字段,通常是某种原因他们不能通过发送邮件的地址接收邮件。一直从同一个地址读取和发送的人们不会有这种问题,甚至会惊讶有这种情况。但是对于有特别的邮件设置,或者不能设置他们所看邮件的From地址(或许因为他们在工作时发送,而且不能通过IT部门修改配置)时,使用Reply-to可能是保证回复能够收到的唯一方法 。当此类人在未订阅的邮件列表中发送邮件时,她的Reply-to设置就成为了关键信息。如果列表软件覆盖了它,她可能就看不到回复了。

第二个可以预期的缺点,从我的观点看是Reply-to处理最有力的反对论点。大多数有经验的邮件用户会习惯于两个回复的基本方法:reply-to-allreply-to-author。所有现代的邮件阅读软件对于两个动作都有单独的按键。用户知道如果是回复到所有人(也包括列表),他们会选择reply-to-all,如果是私下回复到作者,他们应该选择reply-to-author。尽管你希望鼓励人们尽可能回复到列表,但确实有情况回复者需要有权利私下回复—例如,他们希望和邮件的原作者说一些机密的事情,可能不适合出现在公共列表中。

现在考虑一下如果列表覆盖了发送者的Reply-to时会发生什么。回复者点reply-to-author,希望向原发送者私下发送一个邮件。因为那是他所预期的行为,所以就可能不会小心查看新邮件的接收地址。他编写了他的私人的、机密信息,可能会说一些对列表中的人来说很尴尬的内容,并点击发送键。出乎意料的是,几分钟之后他的信息出现邮件列表中!诚然,他应该仔细查看接收字段,对于Reply-to头不要有任何设想值。但是作者几乎会肯定将Reply-to设置为他们的个人地址(更确切地说,他们的软件做了设置),许多资深的邮件用户都会期望这样。实际上,如果一个人直接将Reply-to设置为其他地址,他通常会邮件的正文提及这一点,这样人们就不会为回复所发生的事情感到惊讶了。

因为可能出现的严重后果,我的观点是保证列表管理软件决不要碰Reply-to头。这是一个使用技术来鼓励协作的实例,但是对我来说有潜在的危险副作用。然而,在论战的另一面也有强有力的论据。无论你选择何种方式,你都会在列表中看到有人问你为什么不选择另一种方式。因为你肯定不希望这成为邮件列表中的主要讨论,所以最好准备好回应,诸如此类结束讨论而不是鼓励讨论。请确认你不是坚持认定你的决定,也就是无论是哪个,它都应该明显是唯一正确和明智的选择(即使你认为那是一个事实)。相反,指出这是一个老争论了,两方面都有好的论点,没有能够满足所有用户的选择,因而你只是做出了你能做出的最佳决定。有礼貌的告知不要再炒冷饭了,除非有一些独特的新内容,然后不必再参与讨论并希望它能够自然死亡。

有些人会建议开展一个投票。如果你愿意你可以这样做,但是这个情况下我不认为这是一个满意的解决方案。对于某个人因为出人意料的行为模式的惩罚是巨大的(不小心的将私有邮件发送到公共列表),而对于所有其他人的不便是相对轻微的(偶尔需要提醒某人回复到整个列表而不仅仅是你),多数票是什么并不清楚,即使能得到多数票,少数者应该承担这样的危险吗?

这里我没有涉及问题的所有方面,仅仅包含了看起来最重要的。完整的讨论,请看这两篇权威的文档,当人们遇到争论时经常会引用它们:

无论你偏爱上面的哪一条,我不认为此问题有所谓的“正确”答案,也会很乐意参与到设置Reply-to的许多列表。最重要的事情是你尽早确立一种方式,之后再也不要陷入到争论之中。

两个幻想

将来有一天,有些聪明人会在邮件阅读器实现一个reply-to-list键。它可以使用前面提到的一些自定义的列表头来指出邮件列表的地址,然后会将回复仅指向到邮件列表,同时消除所有的其他接收地址,因此,无论如何大多数都是订阅列表的地址。最终,其他邮件阅读器也会采用这个特性,整个争论也就可以偃旗息鼓了。(实际上,Mutt邮件阅读器已经提供了这个特性。[13]

一个更好的解决方案是让每个订阅者自己选择是否进行Reply-to处理。如果希望经过Reply-to处理(自己与他人的邮件),可以要求,而如果不希望,则可以设置为Reply-to不变。然而,我不知道有任何列表管理软件提供这个每订户基础的设置。我们还是只能使用全局设置。[14]

归档

运转列表的软件都有自己特定的设置邮件列表归档的技术细节,超出了本书的范围。当选择归档时,请考虑这些特性:

立刻更新

人们经常会引用在上个小时所做的发布归档。如果可能,归档器必须能够立刻归档每个发布,这样发布出现在邮件列表时,它也就出现在了归档中。如果没有这个特性,至少应该将其设置为每小时更新一次。 (默认情况下,一些归档器会每夜更新,对于一个活跃的邮件列表这有点太滞后了。)

引用稳定性

一旦一个信息已经归档到特定URL,它应该在相同的可访问URL,并尽可能的永远保持。即使归档重建,从备份中恢复,或者其他修正,任何已经公开的URL应该保持相同。稳定引用可以让Internet上的搜索引擎能够索引归档,可以方便用户查找答案。稳定引用重要的另一个原因是因为邮件列表经常会在Bug跟踪(参考本章后面的“Bug跟踪”一节)或其他项目的文档中被引用。

理想情况下,邮件列表应该能够包含一个信息归档的地址,或者至少在分发到接收者的信息头上有URL的信息特定的部分。这样人们就有了信息的拷贝,已经知道了归档的位置,而无须实际访问归档,这样做很有用,因为任何操作都需要花费网络浏览器的时间。我不知道是否有邮件列表软件实际支持这个特性;不幸的是,我用过的都不行。然而,这是我要寻找的(或者,如果你正在写邮件列表软件,这应该是一个可以考虑实现的特性)。

备份

如何备份归档必须相当清楚,而恢复方法也不能太难。换一句话说,不要把归档器当作黑盒子。你(或者你项目中的某个人)应当知道信息存放在什么地方,以及如何在必要时从信息存放处重新生成归档页。这些归档是珍贵的数据—失去了它们,就像失去了项目集体记忆中美好的一部分。

线索支持

应该能够从任意单独的信息进入原来信息所归属的线索(一组关联的信息),每个线索必须拥有自己的URL,与线索中的其他信息区分开来。

可搜索性

一个不支持搜索的归档器—针对信息内容、以及作者和主题—接近于无用。注意某些归档器只是将此工作交给了诸如Google的第三方搜索引擎。这是可以接受的,但是直接的搜索支持通常会更加易于调整,例如我们可以指定搜索匹配的是主题行还是正文。

上面是一个技术检查列表,可以帮助你评估和设置归档器,本章后面将讨论如何让人们利用归档器来使项目获益,特别是在“归档的显著使用”一节

软件

这里是一些可以进行列表管理和归档的开源工具。如果你的项目主机已经有默认的设置,你可能无法决定一个工具。但是如果你必须自己安装一个,这些是可以选择的。我实际使用过的包括ailman、Ezmlm、MHonArc和Hypermail,这并不是意味着其他工具不好(当然可能有其他一些工具只是我碰巧没有找到,所以不要把这当作完全的列表)。

邮件列表管理软件:

邮件列表归档软件:

版本控制

一个版本控制系统(或修订控制系统)是跟踪和控制项目文件变更的技术与实践的组合,包括源代码、文档和网页。如果你以前从来没有使用过版本控制,那你最好赶快找一个有经验的人加入。现今,所有的人都希望你的项目源代码存放在版本控制下,如果不使用版本控制,人们将会轻视项目。

版本控制如此广泛的原因是因为它实际上能帮助运营一个项目的所有方面:内部开发者交流、发布管理、Bug管理、代码稳定性和试验开发投入,以及对某个变更所属开发者的归因和授权。版本控制系统为这些领域提供了一个集中的协调力量。版本控制的核心是变更管理:识别对项目文件的每一个不相关的变更,使用元数据例如变更的日期和作者来注解每个变更,之后无论使用什么方法,任何人询问时,重放这个事实。这是一种变更为信息基本单元的交流机制。

这个部分不会讨论使用版本控制的所有方面。它是如此包罗万象,我们不得在本书不时的提及。因此,我们会通过促进协作开发的方式,专注于版本控制系统的选择和设置。

版本控制词汇表

如果你没有用过版本控制,本书不会教你如何使用,但是如果没有一些关键术语,我们就无法讨论。这些术语独立于任何特定的版本控制系统:它们是网络交互的基本名词和动词,将会在本书剩下的部分广泛使用。即使这个世界上没有版本控制,变更管理的问题也会存在,这些术语为我们简明的讨论这些问题提供了一种语言。

提交(commit)

对项目做出一个变更;更正式的,以此方式在版本控制数据库存储一个变更,可以成为项目以后发布的一部分。 “提交”可以作为名词或动词。作为名词,从本质上讲可以看作是“变更(change)”同义词。例如:“我刚刚为报告的Mac OS X上的服务器宕机Bug提交了一个修订。Jay,你能评审一下提交并看一下我有没有误用内存分配吗?”

日志信息(log message)

每次提交所附的注释,描述了提交的性质和目的。日志信息是任何项目最重要的文档:它是单个代码变更的高度技术语言与特性、Bug修订和项目进展这类更面向用户的语言的桥梁。本节的后半部分,我们会关注将日志信息发布给适当读者的方法;另外,第 6 章 交流“编制法律的传统”一节将会讨论鼓励贡献者填写简明和有用日志信息的方法。

更新(update)

请求将其他人的变更(提交)和项目的本地拷贝进行组合;也就是将你的拷贝“保持最新”。这是一个非常常见的操作;大多数开发者每天都会多次更新代码,因此,可以确认他们运行的代码与别人的相同,因此他们看到一个Bug,他们可以确信它还没有被修正。例如:“嗨,我发现索引代码一直会丢掉最后一个字节。这是一个新的bug吗?”“是的,但已经在上周修正了—更新一下,一定是好了。”

版本库(repository)

一个存放变更的数据库。一些版本控制是集中式的:有一个单独的主版本库,会存放项目的所有变更。也有一些分布式的系统:每个开发者都有自己的版本库,变更可以在版本库之间任意交换。版本控制系统跟踪了变更之间的依赖关系,当需要发布时,确认一部分变更集进入发布。集中式还是分布式的问题也是一场不朽的软件开发圣战;也要防止落入在你的项目列表中讨论这个问题的陷阱。

检出(checkout)

从版本库获取项目拷贝的过程。一个检出通常会产生一个叫做“工作拷贝”(看后面)的目录树,可以从这个目录将变更提交回原来的版本库。在一些分布式的版本控制系统,每个工作拷贝本身都是一个版本库,变更可以推出(拖入)到任何愿意接受的版本库。

工作拷贝(working copy)

一个包含项目源代码文件或者网页及其他文档的开发者的私有目录树。一个工作拷贝也可能会包含由版本控制系统管理的元数据信息,可以说明工作拷贝所对应的版本库,以及所展现文件的“修订版本(看后面)”等等。通常情况下,每个开发者都有自己的工作拷贝,他可以在其中进行变更以及测试,并提交。

修订版本(revision), 变更(change), 变更集(changeset)

一个“修订版本”通常是一个特定文件或目录的具体化身。例如,如果开始时一个项目有一个文件F,修订版本是6,然后如果有一个文件对文件F提交了一个变更,那么就会产生F的修订版本7。一些系统也使用“修订版本”,“变更”或“变更集”来引用作为一个逻辑概念的一组变更。

这些术语在不同的版本控制系统可能有不同的技术含义,但是大意基本相同:他们提供了一个方法可以精确的描述一个文件或一组文件历史中的精确位置(比方说,恰恰在一个Bug修正之前或之后)。例如:“她在修订版本10修正了那个”或者“他在文件foo.c的修订版本10修正了那个。”

当一个人在不指定特定修订版本的时候谈论一个文件或一组文件时,通常假定是指最近的修订版本。

差异(diff)

变更的文本化展现。一个差异显示了哪些行发生了怎样的改变,以及围绕上下文两侧的几行。一个已经熟悉代码的开发者通常可以阅读区别,并理解变更完成的事情,甚至定位Bug。

标签(tag)

一组特定修订版本的文件的标签。标签通常用来保存人们感兴趣的项目快照。例如,为每个公开发布使用标签,这样人们就可以从版本控制系统获取发布对应的文件/修订版本。常见的标签名称有Release_1_0Delivery_00456等等。

分支(branch)

项目的一个拷贝,在版本控制之下,但却是孤立的,所以分支上的变更不会影响项目的其他部分,或者相反,除非你故意将变更“合并”过去(看后面)。分支也被称为“开发线(lines of development)”。即使当一个项目没有明确的分支,开发也可以被认为是发生在“主分支”,也称为“主线”或“主干(trunk)”。

分支提供了一个将开发线隔离的方法。例如,一个分支可以用来进行对于主干不够稳定的实验开发。或者一个分支可以用来稳定新的发布。在发布过程中,有规律的开发可以继续不受干扰的在版本库的主线进行;与此同时,在发布分支,除非经过发布管理员的确认,不允许任何变更。通过这种方式,让发布不必干扰正在进行的开发工作。关于分支的详细讨论见本章后面的“使用分支来避免瓶颈”一节

合并(又名搬运)(merge, a.k.a. port)

用来将变更从一个分支搬运到另一个。这包括从主干合并到分支,或者相反。实际上,这是最常见的合并类型;在两个非主分支之间搬运变更的情况很少见。关于此类合并的更多信息可以看“信息单一性”一节

“合并”也有另一种相关的含义:也就是当两个人对于同一个文件作出没有交叠的变更时,版本控制系统所作的事情。因为两个变更没有互相干扰,当一个人更新其拷贝中的这个文件(已经包含他自己的变更)时,其他人的变更会自动合并进去。这非常常见,特别是当多个人编辑同一代码时。当两个变更确实交叠了,结果就是“冲突”了;看下面。

冲突(conflict)

当两个人希望对于代码的同一个地方作出不同的修改时。所有的版本控制系统会自动监测到冲突,并至少让一个人意识到他们的变更与其他人的冲突了。这依赖于解决(resolve)冲突的人,以及与版本控制系统解决的交流。

锁定(lock)

对于某个文件或目录进行排他变更声明的方法。例如,“我现在不能对网页文件提交任何变更。似乎Alfred已经锁定了所有文件,因为他要修改背景图片。”不是所有的版本控制系统都提供了锁定能力,它们并不都需要使用锁定特性。这是因为平行,同时开发是行为准则,而将人们锁定在文件之外违背了这个思想。

需要锁定才能提交的版本控制系统,我们称之使用锁定-修改-解锁模型。而其他的我们称之为拷贝-修改-合并模型。两种模型的一个完美的深入解释和比较可以看http://svnbook.red-bean.com/svnbook-1.0/ch02s02.html。通常情况下,拷贝-修改-合并适合于开源开发,在本书讨论的版本控制工具都支持这个模型。

选择一个版本控制系统

在写本文的时候,自由软件世界中两个最流行的版本控制系统是并行版本系统CVShttp://www.cvshome.org/)和SubversionSVNhttp://subversion.tigris.org/)。

CVS已经存在很长时间了。大多数有经验的开发者已经熟悉了它,它或多或少满足了你的需要,而且因为它已经流行了很长时间了,你可能不会陷入它是否为正确选择的争论。CVS有一些缺点。它不支持简单的引用多个文件的变更;它不支持版本控制下的文件重命名和拷贝(这种情况下如果你需要识别出项目开始后的代码树,会非常头痛);它对合并的支持很弱;它处理大文件和二进制文件不佳;以及在操作很多文件时操作会非常慢。

CVS的这些Bug都不是致命的,所以它一直非常流行。然而,最近几年Subversion逐渐被人们所接受,特别是在新创建的项目中。[15]如果你新开始一个项目,我推荐Subversion。

在另一方面,因为我参与了Subversion项目,我的客观性有理由值得怀疑。在最近几年,许多新的开源版本控制系统已经出现。附录 A, 自由版本控制系统列出了所有我知道的,大体上根据流行性排序。就像列表说明的,决定使用何种版本控制系统可能成为一项终身的研究项目。有可能你也会省掉选择的过程,因为你的主站已经做出了选择。但如果你必须做出选择,请咨询那些有经验的人,然后选择一个并使用起来。任何稳定的产品状态的版本控制系统可以实现;你不必担心会做出灾难性的错误决定。如果你无法下决心,那就Subversion吧。它学起来相对简单,在近几年里还应该保持标准的地位。

使用版本控制系统

这一部分的建议不针对任何特定版本控制系统,它们都应当可以简单的实现。详细信息请参考特定系统的文档。

版本化所有的东西

不要仅仅将项目的源代码纳入到版本控制下,也应该包括网页、文档、FAQ、设计注释和任何人们希望编辑的内容。让他们与源代码尽量接近,在同一个版本库树中。任何值得写下来的信息都应该纳入版本控制—也就是任何可能会变更的信息。不会发生变更的东西都应该归档,而非版本化。例如,一个邮件一旦发布,就不会变更;因此,将其版本化没有任何意义(除非它成为一个较大的、进化文档的一部份)。

在一个地方版本化所有的东西的原因非常重要,这样人们只需要学习一种提交变更的方式。例如,经常是一个贡献者开始编辑一个网页或者文档,然后接着做一些代码变更。当项目对于所有的提交使用相同的提交方式时,人们只需要学习一次。一起版本化所有的东西也意味着随着文档的更新,新特性可以一起提交,而代码分支时也是对文档分支等等。

不要将生成的文件置入版本控制。那些应该不是可编辑的数据,因为它们是程序方式由其他文件产生的。例如,一些构建系统根据模板configure.in文件产生configure。为了改变configure,我们需要编辑configure.in,然后重新生成;因此,只有文件configure.in是“可编辑文件。”只版本化模板—如果你也版本化结果文件,人们在对模板进行修改后会不可避免的忘记重新生成它,结果的不一致会导致无休止的混淆。[16]

所有可编辑数据必须存放在版本控制下的规则也有一个不幸的例外:Bug跟踪。Bug数据库保存了大量的可编辑数据,但是因为技术原因不能将数据存放在版本控制系统。 (一些跟踪工具有一些原始的版本控制特性,然而,独立于项目的主版本库。)

可浏览性

项目的版本库应该能够通过web浏览。这不仅是意味着浏览最新修订的能力,也包括回到过去查看早先的版本,查看修订之间的区别,以及阅读针对特定变更的日志信息等等。

可浏览性非常重要,因为它是一个轻量级的项目数据门户。如果不能通过web浏览版本库,那一个人如果希望检查特定的文件(例如,看一下某个bug修正是否已经进入代码),他必须在本地安装版本控制客户端,这会让一项只需要两分钟的任务变成一项半小时或更长的任务。

可浏览性也暗示了浏览文件特定修订版本的标准URL,以及任意给定时间最近的修订。在技术讨论或向人们指明作为证据时这非常有用。例如我们不会说“关于调试服务器的提示,可以看你工作拷贝中的www/hacking.html”,而会说“关于调试服务器的提示,可以看http://svn.collab.net/repos/svn/trunk/www/hacking.html,”给定一个会一直指向hacking.html最新修订的URL会更好。因为它不会导致混淆,也避免了用户是否有最新工作拷贝的问题。

一些版本控制系统包含内置的版本库浏览机制,而其他一些依赖于第三方的工具实现。这类工具有ViewCVShttp://viewcvs.sourceforge.net/)、CVSWebhttp://www.freebsd.org/projects/cvsweb.html)以及WebSVNhttp://websvn.tigris.org/)。第一个工具可以支持CVS和Subversion,而第二个只支持CVS,而第三个只支持Subversion。

提交邮件

对版本库的每一次提交应当能够产生一个邮件,包含谁做出修改的、何时作出的修改、修改的文件和目录以及为什么修改。邮件必须发送到专注于提交邮件的特别邮件列表,在邮件列表中能够同普通人的邮件区分开来。必须鼓励开发者和其他感兴趣的参与者订阅这个提交列表,这是从代码级别来跟踪项目的最有效方法。除了同级评审(见“实践明显的代码评审”一节)这一明显的技术益处,提交邮件帮助我们建立了一种社区意识,因为他们创建了一个共享环境,在其中人们可以对其他人也可见的事件(提交)作出反应。

设置提交邮件的具体方法依赖于你的版本控制系统,但通常有一些脚本或其他工具可以完成这个工作。如果你在寻找过程中遇到困难,可以查一下钩子(hooks)的文档,特别是post-commit hook,CVS中也称作loginfo hook。Post-commit钩子大意上就是对提交做出自动化的响应。这个钩子会由每个提交出发,并提供关于提交的所有信息,你可以自由的使用这些信息做任何事情—例如,发送一个邮件。

通过预先包装的提交邮件系统,你可能会希望修改一些默认的行为:

  1. 一些提交邮件程序会在邮件中包含实际的区别,而不是提供在web上使用版本库浏览系统查看变更的URL。虽然提供URL非常好,这样后面就可以引用这个变更,但是在邮件本身中包含区别同样非常重要。阅读邮件已经成为人们的例行的一部分,如果变更的内容在提交邮件中,开发者可以立刻进行评审,不需要离开邮件阅读器。如果他们需要点击一个URL来评审变更,大多数人就不会作了,因为需要开始一个新动作,而不是延续一个已发生的动作。此外,如果评审者希望询问变更的某些事情,可以直接选择带原文回复并注解区别,这样就不必访问网页并辛勤的从web浏览器拷贝粘贴到邮件客户端。

    (当然,如果区别非常大,诸如大片的新代码正文添加到了版本库,那么省掉区别而只提供URL就比较有意义。大多数提交邮件程序可以自动执行这种限制。如果你的不支持,那包含区别也没有关系,只是偶尔会有些大邮件,比完全没有区别更好。便利的评审和回复是协作开发的奠基石,是否存在十分关键。)

  2. 提交邮件必须将Reply-to头设置为普通的开发邮件列表,而不是提交邮件列表。那是因为,当有人评审一个提交并撰写了一个回复,这个回复应当自动转向到人们的开发邮件列表,也就是通常人们讨论技术问题的地方。有这么几个原因。首先,你希望将技术讨论保持在一个邮件列表中,因为这也是人们所期望的情况,而且这种情况下只需要搜索一个归档。其次,有一些感兴趣的参与者可能没有订阅提交邮件列表。第三,提交邮件列表把自己当作一个监视提交的服务,而不是用来关注提交偶尔进行技术讨论。订阅提交邮件列表的人除了提交邮件没有订阅其他东西;通过那个列表发送其他内容违反了隐含的契约。第四,人们经常写程序来阅读提交邮件列表并处理结果(例如为了显示一个网页)。这些程序预备好了处理一致格式的提交邮件,但与人写的邮件不匹配。

    请注意这里设置Reply-to的建议与本章前面“伟大的Reply-to辩论”一节中说的并不矛盾。对于信息的发送者来说,设置Reply-to非常正常。在这个情况下,发送者是版本控制系统本身,它设置Reply-to是为了说明回复的合适地方是开发邮件列表,而不是提交列表。

使用分支来避免瓶颈

非专家的版本控制用户有时候会担心分支与合并。这可能是CVS流行性的副作用:CVS对于分支和合并的接口和我们的知觉不太一致,所以很多人学着完全避免此类操作。

如果你周围有很多这类人,立即下决心战胜所有恐惧,并花时间学会如何分支和合并。它们不是什么困难的操作,一旦你习惯了,对于项目获取更多的开发者这日益重要。

分支非常有价值,因为它将一项稀缺的资源—项目代码的工作空间—变得充足。一般情况下,所有的开发者在同一个沙盒一起工作,建设同一座城堡。当某个人希望添加一个新的吊桥,但是不能确认其他人是否正在工作,分支使她被隔离到一个角落并做出尝试成为可能。如果这种投入成功了,她可以要求其他开发者检验这个结果。如果所有人认可结果,他们可以告诉版本控制系统将吊桥从分支城堡移动(“合并”)到主城堡。

很容易看到这项能力是如何帮助协作开发的。人们需要自由尝试新问题的感觉,而无须担心干扰其他人的工作。同样重要的是,当为了完成bug修正或发布稳定化(见<第 7 章 打包、发布和日常开发“稳定发布版本”一节“维护多发布线”一节),代码需要从日常的开发中分离出来时,所花费的时间数倍于无需担心跟踪一个移动目标的情况。

不受限制的使用分支,并鼓励其他人也这样做。但是要确保任何特定分支只保持必要的最短时间。任何活动分支都会让社区分神。即使不是在分支工作的人也需要对此有所了解。这种了解是应该的,当然,对于分支的提交应该能和其他提交一样发送提交邮件。但是分支不应该成为分割开发社区的机制。除了很少的例外,大多数分支最终必须合并回它们的主干并消失。

信息单一性

合并有一个推论:不要将同一个变更提交两次。也就是一个修改只进入一次版本控制系统。变更的修订(或一组修订)可以在其进入版本控制系统之后拥有唯一标示。如果它需要应用到还没有应用过的分支,那么它应该从最初的入口点合并到其他目标—而不是直接提交相同的文本,这样虽然对代码的效果是一样的,但会导致我们无法进行精确的记录和发布管理。

这个建议对于不同版本控制系统的实践效果不尽相同。在一些系统,合并是特殊的事件,从根本上与提交不同,并包含他们自己的元数据。而另外一些系统,合并的结果就像其他变更一样是提交到了系统,所以区别“合并提交”和“新变更提交”的主要方法是使用日志信息。在合并的日志信息中,不会再重复原始变更的信息。而只是指明这是一个合并,并提供原始变更的修订版本,以及一段说明其效果的文字。如果有人希望看到完整的日志信息,她应该参考原来的修订。

避免在提交之后再重复日志信息的原因非常重要,因为日志会在提交后被修改。如果变更日志在每个合并目标中重复,那有朝一日她修改了最初的信息,而那些重复还是会保持错误—混淆就会持续下去。

同样的原理也适用于撤销一个变更。如果一个变更从代码中撤销,那么这个撤销的日志信息也应该仅仅是指明撤销的是哪些特定的修订版本,而不是描述撤销过程中实际变更的代码,因为变更的内容可以通过阅读原来的日志信息和修订获得。当然,修订版本日志信息也应当说明恢复变更的原因,但它不应该从原始变更日志信息复制任何东西。如果可能,回到原来的变更日志信息,并指明它已经撤销了。

前面所说的都暗示了你应该使用一致的语法来引用这些修订版本。这不仅仅在日志信息中有益,在邮件、Bug跟踪和其他地方也同样重要。如果你使用CVS,我建议使用“path/to/file/in/project/tree:REV”,其中的REV就是CVS的修订版本好吗,例如“1.76”。如果你使用Subversion,修订版本1729的标准语法是“r1729”(文件路径不是必需的,因为Subversion使用全局修订版本号)。在其他系统中,也都有一些表达变更集的标准语法。无论对你的系统合适的语法是什么,鼓励人们使用它们来引用变更。对变更名一致的表达方法可以帮助项目更简单的纪录(在第 6 章 交流第 7 章 打包、发布和日常开发我们将会看到),而且因为许多纪录是由志愿者完成的,它应该尽可能的简单。

第 7 章 打包、发布和日常开发“发布和日常开发”一节也有介绍。

授权

大多数版本控制系统提供了控制特定人可以从版本库特定子区域提交的特性。根据这个原理,当人们手握锤子时,就开始到处找钉子,许多项目开始恣意使用这种特性,小心的为每个人只赋予他们被确认的权限,而不能在任何其他地方提交。 (看第 8 章 管理志愿者“提交者”一节来确认何人可以在何处提交。)

执行这样严格的控制可能会有一些害处,一个宽松的政策也足够好。一些项目会简单得使用一个荣誉系统:当一个人被赋予提交权限,即使只是版本库的一个子区域,他也会收到一个可以在项目所有地方可以提交的密码。他们只是被告知要在自己的区域提交。请记住这里没有真正的危险:在一个活跃的项目里,所有的提交会被审核。如果有人在不被允许的地方提交,其他人会发现这一点并说出来。如果这个变更需要被回退,很简单—因为所有地变更都在版本控制之下,只需要回退。

这种宽松的方法有许多好处。首先,当开发者扩展了他们的活动范围(如果他们一直在项目中,这是一个通常的情况),赋予更宽泛的权限无需额外的管理工作。一旦作出了这样的决定,这个人就可以立刻在新区域提交。

第二,扩展可以以一种更细致的方式实现。通常情况下,区域X的提交者如果希望扩展到区域Y,他会通过发表对Y的一个补丁并寻求评审开始。如果对区域Y有提交权限的人看到这个补丁并确认,他可以直接让提交者直接提交这个变更(当然也要在日志信息中提及评审者/确认者的名字)。这样,这个提交就会成为实际编写变更者的作品,无论从信息管理角度还是审计角度这样都更好。

最后,可能是最重要的,使用荣誉系统来鼓励互相尊重和信任的氛围。给一个人对某一区域的访问权限是对他们已经完成技术准备的证明—这是说:“我们已经看到了你已经具备了对某一领域做出修改的专业知识,那就继续吧。”但设置严格的授权控制则是暗示:“我们不仅仅确认你专业知识的限制,而且我们对你的目的也保持怀疑。”如果可以避免的话,你一定不愿意做出这样的评价。将一个人引入为项目的提交者是将其引入互相信任循环的机会。好的方法是给他们比期望所能发挥作用更大的权力,然后告诉他们是否保持在规定的限制内完全依赖于他们自己。

Subversion项目按照荣誉系统的方式已经运作超过4年了,在写作时包含了33个完全的和43个部分提交者。系统实际强制的只是提交者和非提交者的区别;更细的划分只由人为控制。但是我们从来没有遇到故意在领域外提交的问题。只是有一两次由于对个人提交权限范围的误解造成的错误,而且都能够迅速和亲切的得到解决。

很明显,当自律的方式不够实际时,那你就需要严格的授权控制。但这种情形非常少见。即使当有几百万行的代码,以及数百或上千的开发者时,对于任何给定模块的提交,也必须经过模块上工作的人们的评审,而且他们可以识别出提交者是否得当。如果没有有规律的提交评审,那么项目恐怕就会遇到比没有授权系统更大的问题了。

归纳起来,不要在版本控制的授权系统上花费太多时间,除非你有特别的原因。复杂的授权系统不能带来实际的好处,依赖人为控制有更多的优点。

当然,上面所说的并不意味着限制本身不重要。项目不应该鼓励人们在不够格的地方提交。此外,在很多项目中,完全(无限制)的提交访问有一个特别的状态:它隐含了项目范围问题的投票权。提交访问的政治方面将会在第 4 章 社会和政治的基础架构“谁进行表决?”一节详细讨论。

Bug跟踪

Bug跟踪是一个宽泛的话题;贯穿本书会讨论此问题的各个方面。尽管这里我们要着重于配置和技术因素,但是首先要从一个策略问题开始:Bug跟踪系统中应该包含哪些信息?

术语Bug跟踪很有误导性。Bug跟踪系统也通常会用来跟踪哪些初始与结束状态不同,包含可选的中间状态,并在生命周期中积累信息的问题,例如新特性请求、一次性任务以及被动性的补丁。由于这些原因,Bug跟踪也被称为问题跟踪(issue trackers)缺陷跟踪(defect trackers)制品跟踪(artifact trackers)请求跟踪(request trackers)以及问题票跟踪(trouble ticket systems)附录 B, 自由Bug跟踪系统包含了一个此类软件的列表。

在本书中,我会继续使用“Bug跟踪(bug tracker)”这个名称,因为大多数人这样称呼,但我会使用问题(issue)来称呼Bug跟踪数据库中的单个条目。这让我们可以把用户遇到的(Bug本身)正常或不良行为与跟踪系统中Bug的发现、诊断和最终解决的记录区分开来。请牢记,尽管大多数问题与实际的Bug相关,我们也可以用其来跟踪其它类型的任务。

典型的问题生命周期如下:

  1. 某人发起了一个问题。他提供了摘要,初始描述(如果合适则包含重现方法;如何激励好的Bug报告请看第 8 章 管理志愿者“将每个用户当作潜在的志愿者”一节),以及其它跟踪系统要求的信息。项目可能对发起人一无所知—Bug报告和特性请求既可能来自用户社区,也可能来自开发者。

    一旦发起,这个问题就进入了打开(open)状态。因为还没有作出任何行动,一些跟踪系统也将其标示为未验证(unverified)未开始(unstarted)。它还没有分配给任何人;或者在某些系统中将起分配给一个冒牌用户来表示其还没有真正的分配。此刻,它存在于一个保留区:这个问题已经记录,但是还没有成为项目关注的一部分。

  2. 其他人读到这个问题,并做出回复,或许会再向发起者询问来澄清一些问题。

  3. Bug得到重现(reproduced)。这可能是其生命周期中最重要的一个时刻。尽管bug还没有修正,但发起者之外的人重现这个事实可以证明这个bug的真实性,此外,可以确认原发起者通过报告真实的bug为项目做出了贡献。

  4. Bug得到诊断(diagnosed):它的原因得到确认,如果可能,会对修正这个bug所需的工作量做出评估。请确认这些内容会在问题中得到记录;如果诊断人要离开项目一会儿(对于志愿开发者这很普遍),其他人应该能够接手。

    在本阶段,或者前一个阶段,开发者可以“获取”问题所有权并将其分配(assign)给自己(第 8 章 管理志愿者“明确区分调查和指派”一节详细描述了分配过程的细节)。问题优先级(priority)也可以在本阶段设置。例如,如果某个问题严重到足以影响下一个版本的及时发布,则需要尽早标示出来,跟踪系统必须能够使其突出显示。

  5. 问题纳入解决的日程(schedule)。纳入日程并不是意味着规定一个解决的日期。有时候只是决定未来的那个版本(下一个版本不是必须的)必须解决这个bug,或者这个bug将会阻碍哪些特定版本。如果很容易修正,也可以取消纳入日程这一步。

  6. Bug得到修正(任务完成、或应用了补丁、或者其他类似的事情)。变更或者变更集必须记录在问题的回复中,其后是问题被标注为解决(resolved)而得到关闭(closed)

这个生命周期有许多变种。有时候一个问题再发起之后很快就会关闭,例如发现它不是一个bug,而只是部分用户的误解。随着项目获得了越来越多的用户,就会带来更多无效的问题,开发者会用日益缺乏耐心的回应来关闭这些问题。要尝试预防这后一种趋势。这对谁都没有好处,每个案例中的每个单独用户对于此前的无效问题没有任何责任;统计学的趋势只是从开发者而不是用户的视点有效。 (在本章后的“Bug跟踪的预过滤”一节将会看到减少这种无效问题的技巧。)另外,如果不同的用户反复经历同样的误解,这或许意味着软件的某方面需要重新设计。如果有一个问题经理监视着bug数据库,就会很容易发现这种模式;见第 8 章 管理志愿者“问题管理员”一节

生命周期的另一种常见变种是问题在步骤1之后直接以重复(duplicate)状态关闭,重复是某人发起了一个项目已知的问题。重复不仅限于开放的问题:它也可能来自已经修正的bug重现(这个称为衰退(regression)),无论何种情况最佳的解决方式是重新打开最初的问题,并将新的报告复制到最初的问题中。Bug跟踪系统应当能够双向保持联系,这样重复的重现信息中就可以在原问题中看到,反之亦然。

开发者关闭这个问题的第三种情况是他们认为已经修正了问题,只是让原报告者拒绝这个修正并重新打开它。这通常仅仅是因为开发者不能访问重现bug的环境,或者因为他们不能通过报告者的再现描述测试这个修正。

除了这些情况,不同的跟踪软件也有一些其它小的生命周期细节。但基本的生命周期是相同的,生命周期本身并不特定于开源软件,只是暗示了开源项目如何使用他们的bug跟踪系统。

就像步骤1暗示的,跟踪系统和邮件列表或网页一样,是项目的门面。任何人可以发起一个问题,任何人可以浏览当前打开的问题列表。由此我们也能推断我们无法知道有多少人在等待给定问题的进展。而开发社区的规模和技巧限制了问题解决的速率,项目至少应该知道每个出现的问题。即使问题会缓慢小时,一个回复也会鼓励报告者保持参与,因为她能感觉到有人已经为其所作的事情登记(请牢记填写一份问题远比发一封邮件更麻烦)。此外,一旦开发者看到一个问题,它就进入了项目的意识中,也就是开发者会查看此问题的类似情况,或者会与其他开发者讨论,等等。

及时反应的需求意味着两件事:

  • 跟踪系统必须能够连接到邮件列表,这样问题的每个变更,包括初始的填写,都会导致描述发生情况的邮件。这些邮件列表通常与正规的开发列表不同,因为不是所有的开发者会希望接收自动bug邮件,但是(就像提交邮件)Reply-to头应该设置为开发邮件列表。

  • 填写问题的表单一定能够捕捉开发者的邮件地址,这样她可以联系到更多信息。 (然而,它不应当要求输入报告者的邮件地址,因为一些人喜欢匿名报告问题。匿名访问的重要性可以看本章后面的“匿名和参与”一节。)

与邮件列表交互

请确保bug跟踪系统不会成为讨论论坛。尽管让人参与bug跟踪很重要,但从根本上它不适合实时讨论。更应该将其当作归档,组织证据和其他讨论(通常发生在邮件列表)的引用。

做出这种区别有两个原因。首先,Bug跟踪系统的使用比邮件列表(或者实时讨论论坛)更加笨拙。这不是因为bug跟踪系统都没有好的用户界面设计,而是因为它们的界面设计用来捕捉和展示分离的状态,而不是自由流动的讨论。第二,不是每个参与到特定问题讨论的人都必须注意bug跟踪系统。优良的问题管理(见第 8 章 管理志愿者“像分担技术任务一样分担管理任务”一节)是让每个问题被恰当的人注意到,而不是让所有的开发者监视所有的问题。在第 6 章 交流“Bug跟踪系统中无对话”一节,我们会关注确保人们不会脱离合适的论坛而陷入在bug跟踪系统内讨论的问题。

有一些bug跟踪系统可以监控邮件列表并自动记录关于已知问题的邮件。他们通常是通过在邮件列表中,将邮件标题出现的问题标示号码作为特殊字符串来识别问题;开发者学着在他们的邮件中包含这类字符串来触动跟踪系统的注意。Bug跟踪系统可以保存整个邮件,或(更好一点)只是记录邮件在邮件列表归档中的链接。无论何种方式,这是一个非常有用的特性;如果你的跟踪系统有这个功能,要确保在开启它的同时提醒人们利用这个特性。

Bug跟踪的预过滤

大多数问题数据库最终会遭遇相同的困境:由好心但没经验或消息不灵通用户所发起的重复和无效问题的洪流。与这种趋势斗争的第一步通常是在bug跟踪系统的前页放置一个显著的提醒,解释如何知道一个bug是否确实是bug、如何查找bug是否已经被发起、以及如果依然认为是新bug时如何有效的报告。

这会暂时减少噪音,但是当用户数增加后,问题还是会出现。每个单独的用户都不应该因此被谴责。即使他们的第一个bug报告没有用处,你还是要鼓励他们保持参与并在以后提出更好的问题。同时,项目需要保持问题数据库的垃圾越少越好。

这两件事可以最大程度的防止这些问题:请确认监视bug跟踪系统的人有足够的知识,能在问题无效或重复时关闭它,而且能够要求(或强烈的鼓励)用户在填入跟踪系统前确认他们的bug。

第一种技术看起来被广泛使用。即使项目有巨大的问题数据库(例如,Debian在http://bugs.debian.org/的bug跟踪系统,目前有315,929个问题)也是这样安排的,这样某人进入时就能看到所有的问题。不同的问题类别可能是不同的人。例如,Debian项目包含了一组软件包,这样Debian就能够自动路由每个问题到合适的包维护者。当然,用户有时会把问题类别搞错,这样一开始问题就会发送到错误的人,而他可以再将其转向到其他人。然而,最重要的事情是负担被分担了—无论用户在填写的时候是对是错,问题监视的任务还是会在开发者之间分配,所以每个问题都能够得到及时的回复。

第二种技术应用的没有那么广泛,可能因为它很难被自动化。本质思想是每个新问题都是经过伙伴处理后进入到的数据库中。当用户认为他发现了一个问题,他就会被要求在邮件列表或IRC频道中对其进行描述,然后得到某个人对其是bug确认。尽早引入第二双眼睛可以防止许多虚假的报告。有时候第二方可以识别出这个行为不是一个bug,或者已经在最近的发布中被修正。或者她可能由于类似症状bug而感到熟悉,而且可以通过给用户指明老的问题来防止重复的填写。通常仅仅是询问用户“你查找过bug跟踪系统以确定这个问题是否已经报告过了吗?”许多用户不会想到这个一点,如果有人期望,你可以愉快的为他们查找一下。

这种伙伴系统确实可以保证问题数据库的清洁,但是也有一些不利的地方。许多用户无论如何也要独立发起问题,对为发起新问题而寻找伙伴的指南看不到或者视而不见。因此,还是需要有志愿者关注问题数据库。此外,因为许多新报告者不理解维护问题数据库的难度,对他们忽略指南的行为进行过于严厉的斥责是不公平的。所以志愿者必须保持警觉,联系如何反弹未经搭档处理的问题给报告者。目标是训练每个报告者在未来使用伙伴系统,这样就有一个日益增长的能够理解问题过滤系统的用户池。当看到一个未经伙伴系统处理的问题时,理想的步骤是:

  1. 立刻回复问题,礼貌的感谢用户的填写,但是向他们指出伙伴系统的操作指南(当然应该在网站的显著位置)。

  2. 如果问题是明显有效而且没有重复,想办法证明它,使之开始正常的生命周期。毕竟,报告者没有被告知伙伴系统,所有浪费工作量关闭有效的问题是没有意义的。

  3. 否则,如果问题不是很清楚的有效,关闭它,但是要求报告者在得到伙伴的确认后重新打开它。当他们这样做时,他们应当放置一个确认邮件列表线索的引用(例如一个邮件列表归档的URL)。

请记住尽管系统会逐渐改善问题数据库的信/噪比,但是不会阻止误填的发生。完全防止误填的唯一方法是关闭bug跟踪系统,只开放给开发者—治愈几乎永远比疾病本身更坏。应当接受无效问题的清理是项目日常维护的一部分,并努力得到更多的人们来帮忙。

第 8 章 管理志愿者“问题管理员”一节也有介绍。

IRC / 实时聊天系统

许多项目使用互联网多线交谈IRC)提供实时聊天室,作为用户和开发者互相提问并得到及时答复的讨论场所。即使你可以在你的服务器运行IRC服务器时,也不必为此事麻烦。而应该象其他人一样:在Freenode(http://freenode.net/)运行你的IRC频道。Freenode给了你足够的权利来管理你项目的IRC频道,[17]可以让你摆脱维护IRC服务器这类无意义的麻烦。

首先要选择一个频道名称。最明显的选择是你的项目名—如果在Freenode存在,就使用它。如果不存在,可以选择一个与项目名接近的名称,尽可能的易于记忆。在你的项目网站上将频道广而告之,这样期望快速提问的访问者可以立刻看到它。例如,Subversion主页上显著放置的方框中所出现的:

If you're using Subversion, we recommend that you join the users@subversion.tigris.org mailing list, and read the Subversion Book and FAQ. You can also ask questions on IRC at irc.freenode.net channel #svn.

一些项目有多个频道,每个子主题一个。例如,一个频道关注安装问题,另一个是使用问题,还有一个是开发聊天,等等。 (第 6 章 交流“处理成长”一节讨论了如何划分多个频道)。当你的项目还年轻时,应该只有一个频道,所有人在一起讨论。之后,随着用户到开发者比率增加,也就有必要分开单独的频道。

人们如何知道所有的已有频道,以及在哪个频道讨论?他们何时交谈,如何知道当地的习惯?

答案是通过设定频道主题告诉他们。[18]频道主题是每个用户在进入频道时看到的一些信息。可以给每个新人一份快速指南,指出更进一步的信息。例如:

You are now talking on #svn

Topic for #svn is Forum for Subversion user questions, see also
http://subversion.tigris.org/. || Development discussion happens in
#svn-dev. || Please don't paste long transcripts here, instead use
a pastebin site like http://pastebin.ca/. || NEWS: Subversion 1.1.0
is released, see http://svn110.notlong.com/ for details.

内容很扼要,但是它告诉新人所必需知道的东西。它精确的说明频道的目的,提供了项目的主页(如果某人是游荡近来,而并非从项目网页过来),提及相关的频道,并给出一些指导。

机器人(Bots)

许多面向技术的IRC频道有一个非人的成员,叫做机器人(bot),它可以对特定的命令返回信息。通常情况下,这个机器人就像频道中的其它成员一样,命令是通过谈话传递给的机器人。例如:

<kfogel> ayita: learn diff-cmd = http://subversion.tigris.org/faq.html#diff-cmd
<ayita>  Thanks!

这是告诉机器人(以ayita登入了频道)记住以特定的URL回答“diff-cmd”的提问,现在其他用户可以向ayita讯问,并获取diff-cmd的信息:

<kfogel> ayita: tell jrandom about diff-cmd
<ayita>  jrandom: http://subversion.tigris.org/faq.html#diff-cmd

通过速记法可以得到同样的结果:

<kfogel> !a jrandom diff-cmd
<ayita>  jrandom: http://subversion.tigris.org/faq.html#diff-cmd

准确的命令集和行为方式各不相同。以上的例子来自ayitahttp://hix.nu/svn-public/alexis/trunk/),通常在freenode的#svn运行着一个实例。其它机器人包括Dancer(http://dancer.sourceforge.net/)和Supybot(http://supybot.com/)。请注意,运行机器人无需服务器的权限。一个机器人就是一个客户端程序;任何人可以设置一个并监听特定的服务器/频道。

如果你的频道一次次的得到同样的问题,我强烈推荐你设置一个机器人。只有一小部分频道用户会获得需要处理机器人的专业技能,而这些用户会回答不成比例的大部分问题,因为机器人可以帮助他们有效率的回复。

归档IRC

尽管可以将IRC频道发生的任何事情都归档,但这不是必要的。IRC对话名义上是公开的,但是许多用户认为这是非正式的,半私密的对话。用户会对语法不是很在意,而且经常会表达意见(例如,关于其它软件或其他程序员),这些都不是他们希望永久保存归档的。

当然,有时候摘要必须能够保存。大多数IRC客户端可以在用户要求的情况下记录对话到一个文件,如果不能,人们也可以仅仅是将对华拷贝和粘贴到固定的论坛(经常是bug跟踪系统)中。但是不加区分的归档所有内容会让某些用户不悦。如果你需要归档所有的事情,请确认你已经在频道主题明确说明,并给出了归档的URL。

RSS供稿

RSS(Really Simple Syndication)是一种将元数据新闻摘要发布给“订阅者”(那些自己说明对某些摘要感兴趣的人)的机制。一个给定的RSS源通常被称作供稿(feed)而用户的订阅界面被称为供稿阅读器供稿聚合器。例如RSS Bandit和eponymous Feedreader两个开源RSS阅读器。

这里没有更多的空间解释RSS的技术细节[19],但是,你应当意识到两件事。首先,供稿阅读软件是由订阅者选择的,这个阅读软件会用来监控他的所有供稿 — 事实上,这正是RSS的主要卖点:订阅者选择一种界面使用他的所有供稿,而每个供稿只需要将精力集中于分发内容。第二,RSS现在是独一无二的,用的如此之多以至于很多人都不知道他们正在使用它。在世界范围内,RSS看起来像网页上的一个小按钮,标签上写着“Subscribe to this site”或“News feed”。你在按钮上点击,自此之后,你的供稿阅读器(可能是嵌入在你主页上的一个小应用)会根据自动从站点更新。

这意味着你的开源项目应当提供RSS供稿(注意,很多包装主机站点 — ,见“包装主机”一节 — 恰恰提供)。确保不要每天发布过过多的内容,以至于订阅者感到龙蛇混杂,找不到重点。如果有太多的新闻事件,人们会忽略供稿,甚至会激怒订阅者取消订阅。理想情况下,项目应该分开供稿,一个用来做较大的声明,另一个对应每一个邮件列表等等。在实践中,很难做好:不仅对访问项目网站的访问者和管理员都会造成界面混淆。但至少项目应该在首页提供一个RSS供稿,用于发送重要的声明和安全提醒。[20]

Wikis

一个wiki就是允许任何访问者都可以编辑或扩展其内容的站点;术语“wiki”(来自夏威夷词汇,意思是“快”或“非常迅速”)也用来特指支持这种编辑功能的软件。Wikis在1995年发明,但它们的流行是从2000或2001年开始的,一定程度上由维基百科(Wikipedia,http://www.wikipedia.org/)的成功推动,维基百科是以wiki为基础的自由内容的百科全书。可以把wiki看作介于IRC和网页之间:wikis不会实时发生,所以人们可以仔细考虑并润色他们的贡献,但是他们也可以很容易的添加,比正规的网页需要较少的界面操作。

wikis还不是开源项目的标准配置,但是可能很快就会。因为它还是相对新的技术,人们还在实验使用它的多种方式,这里我只提供一些劝诫—在本阶段,更容易分析wiki的误用,而不是他们的成功。

如果你决定运行wiki,需要花费很多力量在保持清洁的页面和可视化的布局上,这样访问者(也就是潜在的编辑者)才可以凭直觉知道如何提供贡献。同样重要的是,在wiki上发表这些标准,这样人们可以访问这些指导。经常是,wiki管理员成为幻想的牺牲品,他们相信因为大群访问者各自为站点添加高质量的内容,所以这些贡献的组合也是高质量的。但那不是网站工作的方式。每个单独的页面或段落可能单独看来不错,但是如果在一个没有组织的或迷惑的整体中它就不是了。wikis经常遇到的困境有:

  • 缺乏导航原则。一个组织良好的站点可以让访问者永远知道自己在哪里。例如,如果页面设计良好,用户会凭本能说出“目录”和“内容”区域的区别。wiki的贡献者也会尊重这种区别,但是这要求以这些区别作为开始。

  • 信息重复。wikis经常会变得有很多页面讨论相似的内容,因为每个单独的贡献者不会注意到重复。这可能部分由于缺乏前面提到的导航原则,人们可能无法在预期的地方找到重复的内容。

  • 不一致的目标读者。当有许多作者时,某种程度上这个问题是不可避免的,但是如果存在关于创建新内容的编写指南时可以减少这种情况。如果能够首先就做出贡献作为实例也非常好,这就成为标准被理解。

对所有这些问题的一般解决办法完全相同:有编辑标准,不仅仅是发表出来,而且要让编辑页包含它。通常情况下,wikis会放大原始材料中的所有缺陷,因为撰稿者会模仿任何眼前的模式。不要期望设置了wikis就会发现所有的事情来到恰当的位置。你还需要编写好例子,这样人们可以将其作为遵从的模板。

一个运行良好的闪耀实例是维基百科,尽管可能是部分因为它的内容(百科条目)本身就适合wiki的格式。但是如果你深入维基百科,你会发现管理员为合作提供了非常完整的基础。有关于如何编写新条目,如何维护合适的视角,做何种编辑,避免怎样的编辑,争议编辑解决过程(涉及许多步骤,包含最终的裁决)等问题的大量文档。他们也有授权控制,如果某个页面反复成为不当编辑的目标,他们会锁定它,直到问题解决。换句话说,他们不只是在网站上抛出了几个模板就希望坐享其成。维基百科能够成功是因为它的创建者仔细思考过如何让几千陌生人调整他们的写作来实现共同的梦想。虽然对于自由软件项目,你可能不需要同样级别的准备,但是其精神值得模仿。

关于wiki的更多信息可以看http://en.wikipedia.org/wiki/Wiki。另外,第一个wiki还活得很好,包含了许多运行wiki的讨论,在http://www.c2.com/cgi/wiki?WelcomeVisitorshttp://www.c2.com/cgi/wiki?WhyWikiWorkshttp://www.c2.com/cgi/wiki?WhyWikiWorksNot有许多不同的视点。

网站

从技术角度上看,对于设置项目网站没有可以多说的:设置网站服务器并编写网页都是相当简单的任务,大多数需要说的重要事情如布局和安排已经在前面的章节提过。网站的主要功能是为项目提供一个清新和友好的概况,并组合其他工具(版本控制系统、bug跟踪系统等等)。如果你没有设置网站的技能,通常不难能找到有能力的人乐意帮助你。虽然如此,为了节省时间和工作量,人们通常会选择一个包装主机站点。

包装主机

使用包装站点有两个主要的好处。首先是服务器容量和带宽:他们的服务器通常位于非常宽的管道上。无论你的项目多么成功,你都不会用完你的磁盘并消耗完网络带宽。第二个好处是简单。他们已经选择了bug跟踪、版本控制系统、邮件列表管理器、归档程序以及其他运行一个站点所需的所有东西。他们已经配置好了工具,并且会小心的备份其保管的所有数据。你不需要作出任何选择。你所需要的只是填写表单,点击按钮,你就立刻得到了一个项目网站。

这些是很明显的益处。坏处当然也有,你必须接受他们的选择和配置,即使有时候不同的方式更适合你的项目。通常情况下,包装主站可以通过特定较少的参数进行调整,但是你永远无法得到细致的控制,就像你自己搭建站点并对服务器有完全管理权限时的那样。

这里的一个完美例子是对生成文件的处理。特定项目网页可以是生成的文件—例如,有系统可以保持FAQ数据为易于编辑的原格式,而不是HTML、PDF、和其他可以生成的展示格式。本章后的“版本化所有的东西”一节会有解释,你不会希望版本化这些生成格式,而只要保存原文件。但是当你的网站存放在其他人的服务器上,就不能设置一个自定义的钩子,当原格式文件变更时,来生成在线的HTML版本的FAQ。唯一的解决办法是也版本化生成的格式,这样,它们才可以在网站上展示。

也可能有更大的后果。你可能无法控制你所展示的内容。一些包装主站允许你自定义网页,但是站点的缺省布局通常是通过许多蹩脚的方法完成。例如,一些SourceForge上的项目拥有完全的自定义主页,但仍然将开发者指向他们的“SourceForge页面”来获得进一步信息。SourceForge页面是项目的主页,使得项目不能使用自定义主页。SourceForge页面包含到bug跟踪、CVS版本库、下载等链接。不幸的是,SourceForge页面也包含了太多外来的噪音。顶上有一个广告条,通常是一个图像动画。左面垂直布局的是项目中的某人感兴趣的一些相关链接。右侧可能是另一个广告。只有中央才是项目特定的材料,甚至让访问者无法确定下一步应该点击什么。

SourceForge设计的每个方面后面,无疑有一个好的原因—从SourceForge的视点是好的,例如广告。但是从每个项目的视点,结果可能不是一个理想的网页。我不是要招惹SourceForge;类似的关注会在许多包装主站出现。关键是代价。你省去了运行项目站点的负担,但是要接受其他人运行它的方式。

你唯一可以决定的是哪个包装主站适合你的项目。如果你选择了一个包装站点,可以保留将站点转移到你自己服务器的选项,通过使用自定义域名作为项目的“主地址”。你可以将URL转向到包装主站,或者你在公共URL上有完全自定义的主页,只在复杂功能时才将用户转移到包装主站。只要确保这样安排,如果之后你希望使用不同的主机方案,项目地址不需要改变。

选择一个包装站点

最大最著名的主机站点是SourceForgesavannah.gnu.orgBerliOS.de这两个站点提供了相同或类似的服务。一些组织,例如Apache Software基金会Tigris.org[21]也会为开源项目提供免费主机,但要符合他们的目标和他们社区已有的项目。

Haggen So对于各式包装站点有一个完全的评估,作为他的博士论文研究的一部分,Construction of an Evaluation Model for Free/Open Source Project Hosting (FOSPHost) sites。结果在http://www.ibiblio.org/fosphost/,还可以看非常易读的比较图http://www.ibiblio.org/fosphost/exhost.htm

匿名和参与

一个不仅是包装主战,而且许多其他地方也能看到的问题是对于用户登录功能的滥用。这个功能本身很简单:站点允许每个访问者自己通过用户名和密码注册。此后他就保存了一份用户信息,项目管理员可以为用户赋予特定的权限,例如,提交版本库的权利。

这非常有用,实际上这也是包装主站的一个好处。问题是有时候有一些附加给注册用户的任务本应该由未注册访问者执行,特别是如在bug跟踪系统发起问题和对已有问题进行回复。如果对此类活动要求输入登陆用户名,项目就为这类快速方便的任务设置了障碍。当然,人们希望可以联系到输入数据的人,但只要保留一个输入邮件地址(如果她愿意)的字段就够了。如果一个新的用户发现一个bug,并希望报告它,她会被在输入bug之前被要求填写帐户信息惹恼。她可能会放弃发起这个bug。

用户管理的好处被过高估计了。但是如果你可以选择哪些动作可以匿名完成,请确保不仅只有所有的只读动作对于未登陆用户是允许的,也包括一些数据条目动作,特别是在bug跟踪系统,可能的话还有你的wiki页。



[13] 在本书出现后不久,Michael Bernstein告诉我:“也有一些Mutt之外的其他客户端实现了reply-to-list功能。例如,Evolution的一个快捷键有这个功能,但不是一个按钮(Ctrl+L)。”

[14] 写到这里,我已经发现至少有一个列表管理系统提供了这个特性:Siesta。请看这篇相关的文章:http://www.perl.com/pub/a/2004/02/05/siesta.html

[16] 对于版本化configure的不同意见,可以看Alexey Makhotkin的文章,在http://versioncontrolblog.com/2007/01/08/configurein-and-version-control/的“configure.in and version control”。

[17] 没有要求或期望你能够为Freenode捐献,但是如果你或你的项目能够负担,请考虑贡献一下。他们在美国有一个免税的慈善团体,提供有价值的服务。

[18] 使用/topic命令设定频道主题。IRC频道中的所有的命令以“/”开头。如果你不熟悉IRC的使用和管理,可以看http://www.irchelp.org/;而http://www.irchelp.org/irchelp/irctutorial.html是一份完美的教程。

[20] 荣誉应当属于有功之人:这一部分并出现在本书的第一次发布版本中,但是Brian Aker的博文"Release Criteria, Open Source, Thoughts On..."提醒了我RSS对开源项目的作用。

[21] 免责生命:我由CollabNet雇佣,它是Tigris.org的赞助商,我经常会用Tigris。

第 4 章 社会和政治的基础架构

有关自由软件,人们经常问到的第一个问题是:“它能行吗?如何保持项目一直运行?谁来做决定?”我一直对关于知识界精化、合作精神、代码会说话此类的平淡回复无法感到满意。事实是这个问题很难回答。知识界精化、合作精神和运行代码只是其中的一部分,但它们对于解释日复一日的项目运转贡献不多,对于如何解决冲突什么也没说。

本章尝试展示支持成功项目的共同结构。 “成功”不仅仅指的技术质量方面,而且也包含了运行健康状况和生存性。运行健康状况是指项目将新代码和新开发者吸收进来,并对到来的bug负责的持续能力。生存性是项目独立于任何单独参与者或赞助商而存在的能力—考虑一下如果项目所有的创始成员离开后项目继续运作的可能性。技术成功不难实现,但是如果没有健壮的开发者基础和社会基础,一个项目就不能处理由初始的成功带来的成长,或者有魅力个体的离开。

获取此类成功有很多方法。有些涉及正式的管理结构,通过哪些争论被解决、新开发者被邀请加入(有时是离开)和计划的新特行等等。还有一些涉及不太正式的结构,但需要更有意识的自我克制,来产生一种人们可以依赖的正直氛围,作为事实上的管理形式。两种方式都产生相同的结果:一种由来已久的永恒感觉,由所有参与者都充分理解的习惯和程序作为支撑。这些特性在自我组织的系统中甚至比集中控制的系统更重要,每个人都知道一个坏苹果可以毁掉一桶,即使只是一会儿。

分叉能力(forkability)

能将开发者绑定在一个自由软件项目中的必需组成部分,能让他们在必要时愿意作出妥协,是代码的分叉能力:也就是任何人可以使用一个拷贝并使之成为一个竞争项目的能力,被称为分叉。怪异的是自由软件项目的中分叉可能性具备比实际的分叉更大的动力,很少会发生。因为分叉对于每个人都不好(第 8 章 管理志愿者“分叉”一节会解释详细原因),分叉的威胁越大,越期望的人就越会妥协去避免它。

分叉,更确切说是分叉的可能性,是自由软件项目中没有真正独裁者的原因。考虑到在一个特定开源项目中听到某人被称为“独裁者”或者“暴君”是多么常见,这看起来是一个令人惊讶的断言。但是此类暴政是特别的,与一般意义上的字面理解非常不同。想象一下一个国王的臣民可以在任何时候复制整个王国,并搬过去按自己满意的规则统治。这与国王无论如何做,臣民都无法离开的情况是多么的不同?

这也是为什么即使项目不是完全按照民主方式组织时,在实践中,重要决定还是通过民主方式产生。可复制性暗指了分叉能力;分叉能力暗指了意见一致。也可能是每个人都希望与一个领袖不同(最有名的例子是在Linux内核开发中的Linus Torvalds),但那是因为他们选择如此,以一种非愤世嫉俗和非邪恶的方式。暴君没有项目的定身法。所有开源许可证都有一个关键特性,也就是在代码如何变更或使用上没有给任何组织更多的权力。如果一个独裁者突然开始做了一个坏的决定,就从此不得安宁,紧接着就是造反和分叉。除非,当然,很多时候不会到这一步,因为独裁者会首先妥协。

但仅仅因为分叉能力放置了一个上一个人在一个项目中发挥多少力量的上限,并不意味着项目的管理方式没有太大的区别。你不会希望每个决定都是某人要考虑分叉后的结果。那样会让人迅速疲倦,丧失真正工作的能量。下面两个小节会仔细检查组织项目平稳做出大多数决定的不同方法。这两个都是极端理想的例子;许多项目会处于中间状态。

慈善独裁者

慈善独裁者模型这一称号确实名副其实:最终的决定权完全取决于一个人,因为其人格和经验的力量,他被认为可以明智的运用这个权力。

尽管“慈善独裁者”(BD)是这个角色的标准术语,但是更应该将其视为“社区认可的仲裁者”或“裁判者”。通常来说,慈善独裁者并不会作出所有的、甚至大多数的决定。一个人很难拥有在项目所有领域中都能做出正确决定的专业技能,毕竟,如果对于项目的方向没有任何影响,有价值的开发者也不会在此停留。因此,慈善独裁者通常不会非常的独裁。相反,他们会尽可能的让事情在讨论和实验中顺其自然。他们自己也会参与讨论,但是作为某领域的普通开发者,他们一般会尊重拥有更多专业知识的领域维护者。只有当明显无法得出结论时,而且大多数成员期望有人能够指导作出决定,并让开发继续时,他们才会采取坚定的立场并说“这是我们前进的路。”避免使用命令作决定是所有成功慈善独裁者共同的特征;也是他们设法保持这个角色的一个理由。

谁可以成为一个慈善独裁者?

成为一个BD需要许多特性的组合。首先,要对自己在项目中的影响有经过充分磨练的敏感性,这样可以保证自我约束。在一个讨论的早期阶段,一定不能过于确定的表达自己的意见和结论,以至于让别人觉得继续发生分歧毫无意思.人们应当能自由的放飞思想,即使是愚蠢的想法。BD也会不可避免的屡屡发表愚蠢的意见,所以这个角色也必须具备认可和承认自己作出错误决定的能力—尽管这是一个所有优秀开发者都应该具备的能力,但如果她要长期呆在一个项目,这一点特别重要。但区别是BD无法无视其信誉的长期损害。但资历尚浅的开发者不必如此谨慎,所以BD必须对批评或反对决定的语句小心措辞,对于词汇的分量十分敏感,不仅是技术上的,还包括心理的。

BD的技术技能需要超越项目中的所有人。但她对于自己的代码工作必须足够精通,也必须能够理解考虑中的所有变更的讨论,但这还不够。BD的位置并不是通过恐怖的编码技巧获取或保持的。重要的富于经验和全局的设计感觉—不必是根据要求生产好设计的能力,只需要有识别好设计的能力,无论是什么来源。

慈善独裁者经常是项目的创建者,但这只是一种关系,而不是原因。这类特性让一个人能够成功的开始一个项目—技术能力、说服别人加入的能力等等—也都是BD所需要的。当然,创建者开始就自动有了相关的资历,在成为慈善独裁者的方法中,是所担心的阻力最小的。

请记住,潜在的分叉会以两种方式出现。一个BD可以和其他人一样分出一个项目,确实有些人已经这样做了,这是因为他们觉得要将项目带领到大多数项目成员不希望的方式中。因为可分叉的能力,慈善独裁者是否有项目主服务器的root权限(系统管理员特权)并不重要。人们有时候会将服务器的控制能力当做对于一个项目的权力根源,但实际上这毫不相干。将某服务器上某人的提交密码添加或删除的能力只会影响存放在那个服务器上的项目拷贝。对于此权力的长期滥用,无论她是BD或其他人,都会致使开发转到其他服务器上。

无论你的项目是否存在一个慈善独裁者,或能够在一个较弱的集中式系统下运行良好,都十分依赖于谁在承担这个角色。作为一个普遍的规则,通常对每个人来说谁是BD非常的明显,然后就会如此继续。但是如果没有明显的BD候选者,项目通常会使用分散的决策过程,这就是下个小节所描述的。

共识为基础的民主(Consensus-based Democracy)

随着项目的成长,通常会从慈善独裁模型转为更开放的民主系统。这不一定是源于对某个BD的不满,借用一个生物学的隐喻,可以简单的认为团队基础的管理更加“进化稳定”。每当一个慈善独裁者引退,或尝试将决策责任更均匀的分配出去,这就是团队选定一个新的非独裁系统的好机会—也就是要建立一套宪法。团队可能错过了第一次机会、或者第二次,但是最终会这样做;一旦做了,这个决定就不太会反转过来。常识解释了原因:如果某个N位成员的团队给某个人特殊的权利,也就意味着有N - 1位成员都愿意降低自己的个人影响。人们通常不愿意这样做。即使他们这样做了,所产生的独裁统治仍然是有条件的:团队推举了BD,团队也可以罢免BD。因此,一个项目的领导权一旦从某个魅力个人转移为更正式的团队为基础的系统,就很少会走回头路。

这类系统的工作细节有很大的区别,但是有两个共同的元素:首先,团队大多数时候在达成共识的情况下工作,其次,在无法达成共识时有一个正式的表决机制。

共识仅仅意味着每个人都能够接受的一种协议。它不是一种含混的状态:当有人提出某个共识已经达成,而且没有人提出反对意见,我们说一个团队对某个问题达成了共识。当然,提出共识的人应当详细说明共识的内容,如果不是显而易见的话,还要说明后续的动作。

一个项目的大多数对话是关于技术主题的,例如修正bug的正确方法、是否添加某个特性、以及文档接口有多严格等等。共识为基础的管理之所以可以工作正常,是因为它无缝的混入了技术讨论当中。在一个讨论的最后,通常是确定方向的协定。某些人会创建一个结论帖,作为所作决定的总结,同时也是隐含的共识提议。这也给了某人最后一次机会说“等等,我对此并不同意。我们应该再讨论一下。”

对于小的有争议的决议,这种共识的提议是隐含的。例如,当一个开发者本能的提交了一个bug修正,提交本身就是一个共识提议:“我料定我们都认可这个bug需要修正,而这就是我做的修正。”当然,开发者不会真的这么说;她只是提交修正,而项目中的其他人无需表明立场,因为沉默代表了认可。如果有人提交的结果没有导致共识,结果就是项目会象这个变更没有提交一样进行讨论。这个方法可以正常工作的原因请看下一个小节。

版本控制意味着你可以放轻松

如果项目源代码已经纳入版本控制,这意味着大多数决定都可以轻易的取消。一个常见的情况是某人自以为提交了一个别人会喜欢的变更,但实际上并不如此。通常始于反对者对于遗漏某个预先讨论的道歉开始,当然,如果反对者在邮件列表归档中没有发现此类讨论的纪录,可以省略这一步。另一个方法是,变更是否已经提交没有理由影响我们讨论的基调。所有的变更都可以回退,至少在引入依赖的变更之前都没有问题(例如,在移除原来的变更后会破坏新代码)。版本控制系统让项目有能力收回错误或仓促判断的后果。这也释放了人们,使他们对于做任何事情之前所需要的反馈可以相信自己的直觉。

这也意味着达成共识的过程不需要非常正式。许多项目跟着感觉处理。小的变更可以直接引入,而无需讨论,或者只需要通过最少的讨论来点头确认。对于重要的变更,特别是有可能造成大量代码不稳定的变更,人们应当需要等待一两天才能达成共识,不应当因为某人没有足够频繁的检查邮件,而将其排斥在对话之外。

因此,当某人相信他知道应该做什么,他应当继续前进和完成它。这不仅仅适用于软件修正,也可以用于网站更新、文档变更和其他任何不会引起争议的事情。通常情况下,需要进行回退操作的情况很少,应当根据实际情况处理。当然,不应当鼓励人们刚愎自用。正在讨论和已经生效的决定会造成一定的心理差异,即使它在技术上是可逆的。人们一直认为动力等同于行动,相对于回退变更,人们更情愿在开始的时候阻止它。如果开发者滥用这个事实,过于快速的提交有争议的变更,不管怎样,人们可以也必然会抱怨,会将开发者置于更严格的标准,直到事情改进。

如果无法达成共识,那么表决!

不可避免的,一些争论无法达成共识。当打破死锁的所有其他方法都已经失效,最后的方案就是表决。但是,在表决之前,一定要理清表决的选项。这里一切又重演了,技术讨论的正常过程会混合项目决策程序的偶然发现。此类需要表决的问题通常会很复杂,具有多方面的问题。在所有此类复杂讨论中,需要有一两个人扮演诚实的中间人的角色:定期发布各种论点的摘要,并保持对于分歧(和一致意见)核心论点的跟踪。这些摘要可以帮助每个人评估所做工作的进展,并提醒每个人还需要解决什么问题。如果需要表决,这些摘要也可以作为表决表格的原形。如果诚实中间人的任务完成的好,当时机成熟就可以发布表决的可信请求,而团队会希望使用以他们对于此问题的摘要为基础的表决表格。中间人自己也可以参与辩论;只要他们可以理解并公平的表示其他人的观点,不会因党派观点而影响以中立地态度总结辩论的状态,就没必要让他们脱离争论。

表决的实际内容通常不应当是有争议的。当表决时刻到来,分歧通常会归纳为一些包含可识别的标签和简短描述的关键问题。偶尔某个开发者会反对表决本身的形式。有时候他的考虑是有道理的,例如,一个选项被遗漏了或描述的不够精确。但是还有一些时候,开发者仅仅希望避开这个表决,因为他知道表决不会得到自己期望的结果。如何处理此类蓄意阻挠可以看第 6 章 交流“刺儿头”一节

要记住指明表决系统,因为有许多不同的类型,人们很容易错误的假定使用某个步骤。大多数情况下的较好选择是同意表决(approval voting),也就是每个表决者可以选择多个中意的选项。同意表决易于解释和统计,也不会像其他方法那样,它只有一轮表决。关于同意表决和其他表决系统的更多细节可以看http://en.wikipedia.org/wiki/Voting_system#List_of_systems,但是要避免陷入使用何种表决系统的长期辩论(因为,当然你会发现你陷入了使用何种表决系统选择表决系统的辩论!)。同意表决是正确选择的一个原因是任何人都很难反对—作为表决系统它足够公平。

最后,公开引导表决。没有必要对公开讨论的事务进行秘密或匿名的表决。让每个参与者在项目邮件列表中发布自己的表决,这样每个观察者都可以自己检查结果,而且所有的内容都会记录到归档中。

何时表决

最难的事情是决定何时开始表决。通常情况下,很少会进行表决—是其他方法都失败后的补救方法。不要将表决当作解决争辩的重要方法。它不是。它可以终结讨论,也会结束关于此问题的创造性思考。只要讨论还会继续,就有可能会有人得出所有人满意的解决方案。这经常令人吃惊:活跃的争论可以产生关于问题的新方法,也会得出使每个人都满意的提议。即使没有出现新的提议,通常采纳某种妥协也比举行表决要好。经过妥协,每个人都或许会有点不高兴,但是表决过后,有些人会开心,还有些人会失望。从政治视角,前一种状态更可取:至少每个人都会感到为自己的不快萃取了一定的价值。他会不满意,但其他人也一样。

表决的主要优点是最终可以解决问题,这样每个人都可以继续前进。但是通过数人头,而不是通过有理性的对话解决问题,导致每个人得出相同的结论。开源项目中的人越有经验,就会越发现他们越不会急于用表决解决问题。相反,他们会尝试考察以前未考虑的解决方案,或者对以前计划的方法进行较大的妥协。有许多技术手段可以防止过早的表决。最明显的方法是说“我觉得还没有准备好开始表决,”然后解释为什么还不行。另一个方法是要求进行非正式(无约束力的)的举手表决。如果结果明确倾向到一边,就会让某些人立刻更希望进行妥协,以避免正式的表决。但是最有效率的方法是简单的提供一个新的方案,或者一个较早建议的新视点,所以人们可以重新审视问题,而不是简单的不断重复同样的论点。

在某些很罕见的情况中,每个人都认为所有折中的解决方案都比任何一个非折中方案要差。当这种情况发生时,表决就会有较少的异议,不仅仅因为它能够得到一个高人一等的解决方案,而且是因为这样不会导致所有人对结果感到不高兴。尽管那样,表决也不应该匆忙进行。导致表决的讨论可以教育全体选民,所以过早的结束讨论会降低结果的质量。

(要注意前面所说的表决建议不适用于第 7 章 打包、发布和日常开发“稳定发布版本”一节中描述的变更包含表决。此时,表决更像是一种交流机制,一种在变更评审过程注册某人参与的方法,这样每个人都可以说出对于一个变更收到了多少评审。)

谁进行表决?

有了表决系统就会出现一个全民选举的问题:谁应该表决?这有可能成为敏感的问题,因为它强制项目正式识别出一些更应该参与的人,也就是比其他人更有判断力的人。

最好的方法是采用已存在的划分,提交访问,并为他们附加表决特权。在提供完全和部分提交访问的项目中,部分提交者是否可以表决的问题,很大程度上取决于部分提交访问被赋予的过程。 如果项目自由处理,例如,在版本库中维护许多第三方贡献工具的方法,那时就应当澄清部分提交访问只是关于提交,而不是表决。相反的暗示自然也成立:因为完全提交者有提交特权,他们应当不仅仅是程序员,而且是全民选举的成员。如果某人在邮件列表中有分裂或破坏倾向,那么要小心将其加为提交者,即使这个人在技术上非常娴熟。

表决系统本身应当用来选择新的提交者,包括完全和部分提交者。但这是一个不太常见的需要注意保密性的情况。你不能为一个潜在的提交者在公共邮件列表表决,因为不能伤害候选者的感情(和荣誉)。相反,通常的方法是某个现有的提交者在只包含提交者的私有邮件列表中发布一个私有邮件,建议给某人附加提交权限。其他提交者可以自由发表意见,他们清楚讨论是私下进行的。通常没有异议,因而没有表决的必要。在等待几天之后,确保每个提交者有机会回应之后,提议者通知候选者并赋予其提交权限。如果存在异议,因而出现其他问题的讨论,可能会导致表决。因为这个过程需要开放和坦白,所以发生讨论的事实应当完全保密。如果被考虑的人知道事情的进展,然后没有提供提交权限,他可能认为他已经在表决中失败,会感到受到伤害。当然,如果某人明确的要求提交权限,没有其他的选择,要么同意,要么拒绝。如果是后者,应当尽量的有礼貌,并使用清晰的解释:“我们喜欢你的补丁,但是还没有看到足够的补丁,”或者“我们感谢你的补丁,但是在实际使用之前需要相当大的调整,所以我们觉得现在还不能放心给你提交权限。我们希望下一次会有些改观。”请记住,你所说的会是一个打击,这要看个人的自信心水平。应当从他们的角度想想如果你看到那些邮件的感觉。

因为添加新提交者不是那种一次性决定,会有后续的结果,某些项目会有表决的特殊要求。例如,他们会要求提议至少获得n个肯定的表决,而且没有否定的表决,或半数以上的赞同票。精确的参数并不重要;主要的思想是在添加提交者时需要让团队小心处理。类似的,或更严格的,特别的需求也可以应用到选举移除提交者上,尽管很希望那永远没有必要发生。关于添加和移除提交者的非表决方面的信息可以看第 8 章 管理志愿者“提交者”一节

民意调查与表决

对于特定类型的表决,有时候扩展选民会很有用。例如,如果开发者只是不能确定哪种界面符合人们实际使用软件的方式,一个方法就是询问项目邮件列表中的所有人进行表决。这更应该叫做民意调查而不是表决,但是开发者可能将结果视为有约束力的。在任何民调中,要确保参与者可以附加选项:如果某人对于民调问题想到了更好的选项,她的回应会成为最重要的民调结果。

否决权

某些项目允许一种特殊的表决类型,称为否决权。否决权是一种开发者停止仓促或考虑不够充分变更的方法,至少希望每个人能够再进行一些讨论。考虑到否决权介乎于强烈反对和阻挠之间。它确切的含义对于每个项目都不尽相同。有些项目让否决很难被逾越;有些则允许经过强制的更多讨论延迟后,被普通的多数投票替代。任何否决必须伴随完整的解释;任何没有这类解释的否决都应当被认为是无效的。

否决权会带来对其的滥用。有时候开发者会急迫的通过否决权来为自己的论点加重砝码,而真正需要的是更多的讨论。你可以通过自己对于否决权的勉强使用来防止对于否决的滥用,并有礼貌的警告某人太过频繁的使用否决权。如果必要,你可以提醒团队,否决权只在团队也认可的时候有效—毕竟,如果很明显大多数开发者希望X,那么就应该采纳X。否决的开发者要么自己让步,要么让团队决定削弱否决权的作用。

你可能会看到人们写了一个“-1”来表示否决。这种方法来自拥有高度复杂表决和否决过程的Apache软件基金会,具体内容可以看http://www.apache.org/foundation/voting.html。Apache标准也传播到了其他项目,你可以看到他们的习惯在开源世界的许多地方以不同的面貌出现。从技术上讲,即使根据Apache标准,“-1”也不是表示正式的否决,而只是一种表达否决或强烈反对的非正式方法。

类似于表决,否决权也可以是追加的。如果有问题的变更已经提交,行动已经执行(除了一些不可挽回的事情,例如新闻发布),不应该以此为理由反对一个否决。另一方面,如果否决在事情发生几周后才出现,它也不会被重视,而且这种情况根本不应该发生。

写下所有的内容

有时,项目中的许多广为流传的惯例和协定变得非常重要,你需要记录下来。为了保证这种文档的正统性,要清楚的表明这些内容基于邮件列表的讨论,并已经形成协定开始生效。随着你的编写,应当引用邮件列表归档中的相关讨论,对于任何不能确定的要点,要重新询问并确认。文档中不应当包含任何出其不意的东西:它不应当是协议的来源,而只是对于协议的描述。当然,如果它足够成功,人们会开始引用它来作为自己权利的来源,但是这只是说明它精确的反映了团队的整体意愿。

这是第 2 章 起步“开发者指南”一节暗示的文档。当然,当项目还非常年轻时,你无法依靠项目的历史来规划指导方针。但是随着开发社区的成熟,你可以调整这些语言以反映实际的内容。

不要尝试全面。没有文档能够涵盖参与一个项目所需的所有事情。许多项目演进出的习惯是永远不会说出来的,永远不会明确提出来,即使是所有人遵循的。还有一些内容则明显太过简单,无需提及,只会分散人们对于重要内容的注意力。例如,没有必要写下指导方针如“在邮件列表中要有礼貌,要互相尊重,不要激烈的争论”或“要写清楚的、可读的和无bug的代码。”当然,这些事情都是人们希望的,但是因为没有想像到他们可能不会渴望得到的东西,所以没有价值去提及。如果人们在邮件列表中过于粗暴,或编写了充满bug的代码,不会因为项目指导方针没有说,他们就会继续下去。这种情形出现时就会需要被处理,不会因为预先的劝诫就会好起来。另一方面,如果项目有关于如何写好代码的指导方针,例如关于使用何种格式记录API的规则,那么这个指导方针就应该尽可能的写完整。

决定将什么内容纳入文档的最好方法是以新来者所经常询问的问题,以及资深开发者最经常的抱怨为基础。这不是说一定要变成一个FAQ表单—很可能需要一个比FAQ所能提供的更连贯的叙述结构。但是它必须遵循事实为根据的原理,记录问题实际发生的地址,而不是好像你预期会出现。

如果项目是一个慈善独裁者所有,或者有拥有特殊权利的官员(总裁、主席或其他),那么继任程序也应当制定成法律形成文档。有时候,这仅仅是BD因故突然离开项目并简单的指定继任者。通常情况下,如果有一个BD,那么只有BD可以离开并提名继任者。如果有竞选的成员,那么文档就应该描述从中取出第一名的提名和选举程序。如果原来没有程序,那么在编写应该在邮件列表中达成共识。人们有时候可能对于等级结构十分敏感,所以主题应当敏感的达到这个目标。

可能最重要的事情是表明规则是可以商量的。如果文档中规定的习惯变得束缚了项目,要让每个人想到这是一种对于团队意愿的生动反映,而不是挫折和堵塞的来源。如果某人养成了每当遇到妨碍自己的规则都要求重新考虑规则的习惯时,你不需要一直与其辩论—有时候沉默是最好的策略。如果其他人认可这种抱怨,他们会插话,也就是意味着某些事情很明显需要改变了。如果没有其他人认可,人们就不太会响应,那规则还是会保持不变。

两个指导方针的好例子是Subversion的hacking.html文件,在http://svn.collab.net/repos/svn/trunk/www/hacking.html,以及Apache软件基金会管理的文档,在http://www.apache.org/foundation/how-it-works.htmlhttp://www.apache.org/foundation/voting.html。ASF是真正的一组软件项目,合法的组织成一个非盈利公司,所以它的文档倾向于描述管理程序,而不是开发惯例。他们也值得阅读,因为他们代表了许多开源项目积累的经验。

第 5 章 金钱

本章仔细检查了如何为自由软件环境带来资金。这不仅仅是在自由软件中被支付工资的开发者的目标,也是他们的经历,那些需要理解开发环境社会动态性的人的目标。在接下来的章节中,假定收件人(你)是被付费的开发者,或者是管理这类开发者的人。对于二者的建议基本相同;如果不同,有意的读者可以从上下文中分清。

对自由软件开发来说,公司投资已经不是一个新的现象。许多开发被非正式的资助。当一个系统管理员写了一个网络分析工具来辅助她的工作,然后把它发布到网络,接受来自其他系统管理员的bug修正和特性贡献,这就产生了一种非正式的合作组织。这个合作组织的资金来自系统管理员的薪水,而它的办公室空间和网络带宽是捐助的,尽管是通过其所工作的默默无闻的组织。这个组织从投资中获益,当然,尽管开始时他们不会意识到这一点。

现在的一些变化是这种力量已经更加正式。公司已经观察到开源软件的好处,在他们自己的开发中直接参与其中。开发者也更能预期真正重要的项目至少能获取到捐助,甚至可能是长期的赞助。而金钱的出现并没有改变自由软件开发的基本动力学,它已经极大地改变了发生事情的范围,无论是从开发者的数量来说,还是每个开发者贡献的时间。对于项目的组织,以及参与者的交互也有影响。这个问题不仅关于金钱如何花费,也关于如何测量投资回报。他们也关于管理和过程:公司层级指挥结构和自由软件项目中半集中的志愿者社区能够以相近的生产率工作?他们认可“生产率”的含义?

财政支持通常会受到开源开发社区的欢迎。它可以减少项目面对混乱势力的弱点,这一点经常让项目在起飞之前就被清除,因此它可以让人们更希望给软件一个机会—他们感到正在一项至少会再干6个月的工作上花费时间。毕竟,可靠性从来都是最有感染力的因素。假定IBM支持了一个开源项目时,人们就会更容易设想这个项目不会失败,而他们的因此所自发的投入反而会去实现这个会成为事实的预言。

然而,资金也会带来控制的感觉。如果处理不好,金钱会让项目分裂为圈内和圈外开发者。如果未付酬的志愿者感到设计决策或特性添加仅仅是由出价最高者决定的,他们会转而投向那些感觉更像是由知识精英管理的,不象是为了某个他人利益进行未付酬劳动的项目。他们绝不会在邮件列表中公开抱怨。相反,随着志愿者逐渐不再努力被重视,来自外部的声音也会越来越少。小规模活动的吵闹还会继续,会以bug报告和偶尔的小修订形式出现。但是再也不会有任何大规模的代码贡献和来自外部的设计讨论参与。人们意识到他们是如何被期望的,而且也会按照这个预期行事。

尽管需要小心的使用金钱,并不意味着不能购买影响力。大多是可以的。技巧是不能直接购买影响力。在一个直接的商业交易中,你使用金钱交换你所需要的。如果你需要添加一个特性,你签署一个协议,为此付款,然后它就会被实现。在开源项目,不会如此简单。你可以与某些开发者签署协议,但是他们需要欺骗自己—和你—如果他们保证你付费的工作会被开发社区接受,仅仅因为你为此付了费。这个工作只应该根据事实,以及与社区对于此软件的长远规划的符合程度来完成。你可以对这个长远规划发表意见,但你不应该是唯一的声音。

所以金钱不能购买影响力,但是可以购买导致影响力的东西。最明显的例子是程序员。如果雇佣了好的程序员,他们逗留了足够长的时间,以获取社区中的软件经验和信誉,那么他们就可以使用其他成员一样的方式影响项目。他们会有一个投票,或者如果人数太多,他们会有投票集团。如果他们在项目中受到尊重,他们会有超越投票的影响力。被支付的开发者没有必要掩盖他们的动机。毕竟,每个希望修改软件的人都有自己的目的。你公司的原因并不比其他人的缺乏道理。只是给与公司目标的砝码取决于代理人在项目中的状态,而不是公司的规模、预算或商业计划。

参与的类型

开源项目被资助有许多不同的原因。这个列表中的条目并不互斥;通常一个项目的财政支持会出自这里的多个,甚至全部的动机:

分担负担

拥有相关软件需要的不同组织经常会发现他们在重复投入,包括在内部重复编写类似的代码,以及从私有供货商购买类似的产品。当他们意识到事实真相后,这些组织会集中他们的资源,并创建(或加入)到一个开源项目,并为他们的需要调整。好处是明显的:开发的代价被分担了,而对所有人利益则增长了。尽管这个场景凭直觉应该大多数是非盈利组织所做的,但是即使对于盈利竞争者也具有战略意义。

例如:http://www.openadapter.org/http://www.koha.org/

提高服务

当一个公司出售的服务依赖于某个开源程序,或因为某个开源程序而更加具有吸引力,很自然这个公司会有兴趣保证程序能够活跃的维护着。

例如:CollabNet对于http://subversion.tigris.org/的支持(免责声明:是我的日常工作,但是也是这个模型的完美实例)。

支持硬件销售

计算机和计算机组件的价值和之上的软件直接关联。硬件销售商—不仅是整机销售商,还包括外围设备和芯片制造商—都发现让高质量的自由软件运行在他们的硬件上对客户来说非常重要。

暗中削弱竞争者

有时候公司支持特定的开源项目作为对竞争者产品的暗中破坏,无论竞争产品本身是否开源。争夺竞争者的市场份额通常不是参与开源项目的唯一原因,但却是一个因素。

例如:http://www.openoffice.org/(不,这不是OpenOffice存在的唯一理由,但是这个软件至少部分的回应了微软的Office)。

市场营销

让你的公司与流行的开源应用联系在一起,是简单而且好的品牌管理。

双重许可证

双重许可证会为希望将软件作为自己私有软件的一部分进行销售的客户提供传统私有许可证,同时为开源范围使用的客户提供自由许可证(见第 9 章 许可证,版权和专利“双许可证模式”一节)。如果开源开发者社区是活跃的,软件可以广泛领域获得调试和开发的好处,尽管公司仍然保持支持一些全职程序员的特许权。

两个著名的例子是MySQL,相同名称数据库软件的制造商,以及Sleepycat,提供Berkeley数据库的发布和支持。他们都是数据库公司并不是巧合。数据库软件通常会集成到应用中,而不会直接交给用户,所以非常适合双重许可证模型。

捐赠

一个广泛使用的项目有时可以获得可观的捐助,包括来自个人和组织的,只需要有一个在线的捐赠按钮,或者有时通过销售诸如咖啡杯、体恤和鼠标垫之类的品牌商品等等。小心一点:如果你的项目接受捐赠,在得到之前要计划好如何使用这些钱,并在项目网站中注明。在实际花费之前保留,可以让关于如何分配钱的讨论变得十分顺利;但不管怎样,如果有明显的分歧,最好把它找出来,这还是很学术的东西。

投资者的商业模型不是它与开源社区如何联系的唯一因素。二者的历史关系也很重要:这个公司开始了这个项目,或者它联合了现有的开发力量?在这两种情况下,投资者都需要赢得信誉,但是,不令人意外,在后一种情况下需要的更多。组织需要对项目的未来有清晰的目标。公司希望保持领导地位,或仅仅是成为社区的一个声音,从而能够引导而不必控制项目的方向?或者它只是希望有一些提交者,能够修复客户的bug并能够不费吹灰之力的将变更置入公共版本?

当你阅读后面的指导方针时要留意这些问题。他们可以应用到自由软件项目中的此类组织参与,但每个项目都是一个人类环境,因此没有完全相同的。在某种程度上,你需要跟着感觉演奏,但是遵从这些原理会增大结果符合你想法的可能性。

长期雇佣

如果你正在管理开源项目中的程序员,要尽量保持足够的时间,这样他们才能获得足够的技术和政治技能—最少也需要几年时间。当然,没有项目,无论是开源还是闭源,都可以从轮换程序员中获益。新来者搞清楚窍门需要的时间在不同环境下各不相同。但是在开源项目中的代价更加巨大,因为离开的开发者不仅带走了他们的知识,也带走了社区中的他们的地位和其中建立的人际关系。

开发者已经积累的信誉不能够传递。一个新来的开发者不能继承来自离开者的提交权限(可以本章后面的“钱不能让你可爱”一节),如果新的开发者还没有提交权限,在获得这个权限之前它只能提交补丁。但是提交权限只是所失去的影响中最容易度量的表现。一个长期的开发者也知道邮件列表中所有以前达成和未达成一致的讨论。一个新的开发者,没有这些对话的记忆,也许会再次发起某些讨论,这会损失在组织中的信誉;其他人会奇怪为什么“他们什么也记不住?”新的开发者也对项目特性没有太多政治感觉,所以也不能象老手一样迅速和平滑的影响开发方向。

通过指导契约的程序来训练新手。新的开发者第一天就可以与公共开发社区直接交流,从bug修正和清理任务开始,这样他们可以逐渐熟悉代码基并在社区获取声誉,尽管此时他们还不能在设计讨论中蹦出火花。一个或多个有经验的开发者应当一直负责解惑的任务,阅读新手在开发列表中的每一篇帖子,即使是经验丰富的开发者通常不会注意的内容。这可以帮助团队在新手搁浅之前定位潜在的暗礁。私下的幕后鼓励和忠告也会非常有益,特别是当新手不习惯大量的代码平行同级评审的时候。

当CollabNet雇佣新的开发者为Subversion工作时,我们会坐在一起为新人找一些打开的bug来练练手。我们会讨论解决方案的技术要点,并让至少一个有经验的开发者来评审(公开的)新开发者的补丁(也是公开的)。我们通常不会在主开发列表公开之前查看这个补丁,虽然,如果情况特殊,我们可以如此。重要的是,新开发者经历公开评审的过程中,在熟悉代码基的同时,也需要习惯于接受来自完全是陌生人的批评。但是我们会调整时机,保证我们的评审会在补丁发出之后立刻出现。这样列表中出现的第一个评审就是我们的,这可以帮助我们确立其他评审的基调。它也可以加强一个概念,也就是这个新人需要认真对待:如果其他人看到我们花时间提供详细的评审,并包含完整的解释和归档中合适的参考,他们会意识到正在进行一种培训,并意味着一个长期的投资。这可以帮助他们对那个开发者保持正面的态度,至少会花费更多的时间回答问题和评审补丁。

作为一些个体出现,而不是一个整体

你的开发者必须力求在项目的公共论坛中以一个单独的参与者出现,而不是一个单独的公司。这不是因为作为一个公司出现本身固有的一些负面含义(好的,或许有一些,但那不是本书所讨论的)。而是因为开源项目的结构配备只能处理个人实体。一个单独的贡献者可以讨论、提交补丁、获取信誉、表决等等。而一个公司不能。

此外,因为分布式的行为方式,你避免了对于刺激性中央集权的敌对。让你的开发者在邮件列表中意见并不一致。鼓励他们经常评审他人的代码,尽可能的公开,就象他们是任何其他的人。阻止他们象一个集团一样表决,因为如果你这样做,其他人就会感觉到,根据一般的原理,一定有一个有组织的力量在控制他们。

实际的非中央集权和假装的是有区别的。在特定环境下,让你的开发者协同一致会非常有用,而且如果必要还必须在幕后进行协调。例如,当发出提议时,让许多人尽早跳出来表示认可,得出正在达成共识的印象会有助于提议的进展。其他人会感到提议的动量,如果他们反对,他们需要阻止这个动量。因此,人们只会在有好的原因时才会提出反对。如果能够慎重对待反对意见,这样的精心安排也没有错。私下协议的公众表现不会因为经过预先的协调而变得不够诚实,只要他们没有用这个方法来扼杀反对意见就不会有太多害处。他们的目的仅仅是阻止那些喜欢保持个性的人提出反对意见;更多相关内容可以看第 6 章 交流“主题越软,辩论越长”一节

公开你的动机

尽可能公开你的组织的目标,不要因此而让商业秘密妥协。如果你希望项目能够获得某个特定的特性,例如你的客户要求这个特性,那么就应该在邮件列表中坦率的说出来。如果客户希望保持匿名,实践中这种情况很多,至少要询问一下客户是否愿意以未命名的方式使用他们的实例。开发社区对于你为什么这样做的原因了解越多,就会对你提议的事情越感到舒服。

这与直觉背道而驰—得到容易甩掉难—知识就是力量,你的目标别人知道的越多,他们就越有可能超越你的控制能力。但是那种直觉在这里并没有错。通过公开支持这个特性(或是bug修正或其他任何东西),你已经亮出了底牌。现在唯一的问题是你能否成功的引导社区来分享你的目标。如果你仅仅是表明你需要它,而不能提供任何表明原因的切实例子,你的论点就会很脆弱,而人们会开始猜疑其隐藏的动机。但是如果你能够提供现实的场景来展示为什么提议的特性是重要的,就可以有力的影响辩论的效果。

为了看清楚这样做为什么有效,考虑另外一种选择。关于新特性或新方向的讨论会非常耗时和烦人。人们提出的论点经常会变成“我个人希望X,”或曾经流行的“根据我多年作为软件设计师的经验,对用户来说,X是极端重要的/一个无用的花边功能不会让任何人满意。”可以预料到,现实用例的缺乏不仅不会缩短或缓和这种辩论,而会扯得离实际用户体验越来越远。如果没有一些增补的力量,那么最终的结果很可能需要由口才最好、坚持最久或地位最高的人决定。

对于有许多客户数据的组织,你有机会提供这种增补的力量。你可以作为无法达到开发者社区的数据的信息管道。不必因为那些支持你愿望的信息事实而感到窘迫。大多数开发者个人没有他们所写软件如何使用的广泛经验。每个开发者都会按照自己的怪异方式使用软件;只要有其他的使用模式,她就会凭直觉并臆断之,而且事实上,她们知道这一点。通过提供包含可观用户数量的可信数据,你就象为整个公共开发社区提供了氧气。只要你提供的例子是正确的,他们就会狂热的欢迎它,就会推动事情往你希望的方向发展。

关键是提供正确的例子。不要因为你要应付大量需要某特性(或以为他们需要)的用户,就坚决要求你的特性,也就是你的解决方案必须实现。相反,你必须将你最初的帖子关注于问题,而不是一个特定的解决方案。详细描述你的客户遇到问题的细节,尽可能提供你已经完成的分析,以及你能想到的可行性方案。当人们开始考虑不同方案的效果时,你可以继续通过提供数据来支持或反对她们的意见。你在心里可以有一个特定的解决方案,但是不要在开始单独提出来以期望获得特殊的考虑。这不是欺骗,这只是标准的“诚实代理人”的行为。毕竟,你的真正目标是解决问题;一个解决方案只是达到目标的一种方法。如果你选中的解决方案确实更好,其他开发者最终会识别出来—她们会出于自愿的跟进,肯定比你通过威逼她们实现更好。 (当然,也有可能她们找到了更好的方案。)

这不是说你不能说出你看好某个方案。但是你必须耐心的查看你所做的分析反复成为公共开发列表的中心。不要在列表中说“是的,我们试过这种方式,但是因为原因A、B和C,它是行不通的。当你彻底了解它后,解决它的唯一办法是...”问题不是它听起来很傲慢,而是让人觉得你对此问题已经研究了许多未知的(但是,人们会假设有很多)分析资源,只是一切都在门后面。它让人觉投入的精力白费了,或许已经做出了决定,而公众都不是有利害关系的人,这是招致怨恨的好方法。

自然,知道你自己在某个问题上所投入的力量,而这些知识从某种意义上来说是一种劣势。它让你的开发者处于和邮件列表中的其他人些许不同的心理空间,减弱了开发者从那些普通人的视角看待这个问题的能力,这些普通人没有像开发者那样考虑过这个问题。你越早能够让所有人用与你相同的术语考虑问题,这种差距就会越小。这种逻辑不仅适于个人技术情形,而且适用于更广泛的让你的目标尽可能清晰的授权。未知总比已知的更不稳定。如果人们理解了为什么你希望你所希望的,即使他们不认可,在与你交谈时也会感到舒服些。如果他们不能指出何事让他们愤怒,他们会假定最坏的情况,至少有时候。

你不能宣传所有的事情,当然,人们也不会期望你如此。所有的组织都有秘密;或许会因为利益,但是没有利益也会如此。如果你必须发起这样一个过程,而无法揭示任何原因,那就提供你在这种不利条件下最好的论点,并接受你将不会在讨论中获得你期望影响力的后果。这是让你不必为开发社区支付薪水的一个折衷手段。

钱不能让你可爱

如果你的项目有付费的开发者,一定要尽早设置钱可以购买什么东西的指导方针。这并不意味着你需要每天在邮件列表中说明两次来重申你的高尚和不腐的本性。你只需要在恰当的时机放松由钱导致的紧张。你不需要从一开始就假设存在这种紧张;你只需要说明有这种可能性。

一个完美的例子就是Subversion项目。CollabNet在2000年开始了Subversion,从一开始它便是项目主要的投资者,为多个开发者提供薪水(免责声明:包括我)。项目开始后不久,我们雇佣了另一个开发者Mike Pilato,参与开发工作。此时,编码工作已经开始。尽管Subversion还处于早期阶段,但已经有了一个开发者社区和许多基本的规则。

Mike的到来突现了一个有趣的问题。Subversion已经有了开发者如何获得提交权的政策。首先,他需要在开发邮件列表中提交一些补丁。当有了足够的补丁后,其他提交者看到新贡献者知道自己所做的事情,某人就会提议他直接提交(这个提议是私下的,就像“提交者”一节所描述的)。如果提交者们同意,其中的某人就会邮件通知新的开发者,并为他设置直接提交访问项目版本库的权限。

CollabNet是专门为Subversion项目雇佣了Mike。他们已经对他足够了解,对于他的编码技巧和在此项目所作的准备毫无疑问。此外,志愿者开发者已经与CollabNet雇员有了非常好的关系,看起来如果我们直接在雇用Mike当天就赋予他权限也不会有什么反对意见。但是我们知道我们正在设置一个先例。如果我们按命令给Mike提交权利,我们会说CollabNet有权无视项目的指导方针,只是因为它是主要的投资者。这种行为的害处未必立刻显现出来,它会导致非付费开发者逐渐感到被剥夺了投票权。其他人自己赢得他们的提交权利—而CollabNet只需要花钱买。

所以Mike赞成象其他志愿开发者一样,在没有提交权限的情况下开始了在CollabNet的雇佣工作。他在公共列表中发布补丁,在其中可能会受到,实际上也确实受到了所有人的评审。我们在列表中也说过我们是故意这样做的。经过Mike数周的扎实活动,某人(我不记得是否是CollabNet开发者)提议给他提交权限,而他被接受了,当然,我们知道他会被接受。

那种类型的一致性会让你确信钱不可以买到一切。这种确信是技术讨论中珍贵的流通货币:可以免于以后让某人的动机被怀疑。在辩论最激烈时,人们有时会寻找非技术的方式来赢得战斗。项目的主要投资者,因为涉足较深并且显然会对项目采取的方向十分关注,会展示出比大多数人更广的目标。通过从一开始就一丝不苟的遵守项目方针,投资者就可以获得和所有人一样的影响力。

(Danese Cooper的blog上http://blogs.sun.com/roller/page/DaneseCooper/20040916有关于提交权限的类似故事。Cooper是Sun Microsystem的“开源Diva”—我相信这是她的官方头衔—在她的blog中,她描述了Tomcat开发社区让Sun在控制提交权限时对Sun的人员和非Sun的人员一视同仁。)

创始人对所有人使用相同规则的需要意味着慈善独裁统治模型(见第 4 章 社会和政治的基础架构“慈善独裁者”一节)在投资面前有一点难于实施,特别是独裁者为主要的投资方工作的情况。因为独裁有一些规则,投资者很难证明遵守了社区标准,即使事实如此。这确实不是不可能;只是需要项目领导者既能够从投资方也能够从外围开发者的视角看待事物,并依此行动。即使那样,也最好能在后口袋有一个非独裁管理的提议,准备好在社区的不满扩散时掏出来。

契约

在自由软件项目中的契约需要小心处理。理想状况下,你希望一个承包者的工作被社区接受并打包进入公共发布版本。在理论上,谁是承包者并不重要,只要他的作品足够好并满足项目的指导方针。理论和实践一般也是一致的:一个通过贡献好的补丁展示自己的完全陌生人通常能将代码置入软件当中。问题是,一个完全的陌生人很难为非琐碎的改进或新的特性贡献好的补丁;一个人必须首先和项目的其他人进行讨论。讨论的时间不能精确预测。如果承包者根据小时付费,你最终可能会付出超过预期的费用;如果他是通过总费用支付,那么他最终会做出超过承受能力的工作。

这里有两种方式。较好的一个方法是根据以前的经验,对讨论过程的长度做出一个有根据的推测,并要考虑到出错的延误,并根据这些信息完成契约。这也有利于尽可能的将问题分离为许多小的独立的区块,增加每个区块的可预测能力。另一个方法是为每一个发布的补丁单独契约,然后将补丁的被接受当作公共项目一个独立的事件。这样编写契约就可以很容易,但是只要你依赖这个软件,或至少在这个补丁或对应功能进入主线的这些时间里,你必须承担维护单个补丁的责任。当然,即使是你中意的方法,契约本身不能要求代码必须可以接受补丁,因为那会包含出售一些不能销售的东西。 (如果项目的余下成员不希望对这个特性提供支持?)然而,契约可以要求真诚地投入以获得社区接受的机会,也就是在社区认可的情况下被提交到版本库。例如,如果项目编写了代码变更的标准,契约可以参考这个标准并指明作品必须达标。在实践中,这通常会超出每个人期望的方式。

最好的策略是雇佣项目的一个开发者—最好是提交者—作为承包者。这可以看作是购买影响力的一种形式。但是并不是表面上那样的不道德。一个开发者对于项目的影响力主要取决于他的代码质量和与其他开发者的交互。他作为承包者完成特定工作的举动并不会提升他的状态,当然也不会降低,尽管这样会让人们对他更加仔细的审视。大多数开发者不会因为返回不当或广泛反对的新特性而让自己的长期位置经受风险。实际上,当你雇佣一个这样承包者时,一定程度上你会得到,或者说一定会得到一些关于哪些变更会被社区接受的忠告。项目的优先级也会得到些许转变。因为优先级只与哪个人有时间完成哪个任务有关,当你为某人的时间支付时,会导致他们工作的优先级提前一些。这是经验丰富的开源开发者都理解的一个事实,至少他们中的某些人会将精力投入到承包者的工作上,仅仅因为它看起来将要完成,所以他们希望去帮助正确完成。或许他们不会编写任何代码,但是他们还是会讨论设计并评审代码,这些都非常有用。出于以上原因,承包者最好是那些已经参与到项目的人。

这样立刻凸显了两个问题:承包协议必须是私密的吗?如果不是,你应当为你在社区中造成的不安而感到担忧吗?你为某些开发者提供了承包合同,为什么不是其他人呢?

如果可以,最好将合同公开。否则,承包者的行为与社区中的其他人相比会看起来有些奇怪—或许他突然对一些过去从未表现出兴趣的特性展示出了不可理解的高优先级。当人们询问其原因时,他怎样才能避免说出他是根据合同编写代码,同时回答的让人信服。

与此同时,你和承包者都不应该表现的仿佛其他人应当把你的安排看得过重。我见过一些承包者招摇着进入开发列表,自认为他们的留言应该被更加郑重的对待,仅仅因为他们是支付薪水的。那种态度也是对于项目其他人的一种信号,承包者看重合同这件事—而不是合同导致的代码—本应当是重要的事情。但是从其他开发者的视角,只有代码有意义。在任何时候,注意力应该保持在技术问题上,而不是谁给谁付薪水的细节。例如,Subversion社区的一个开发者用一种优雅的方式处理承包。当在IRC讨论他的代码变更时,他会在旁白(通常是在私有备注,一种IRC privmsg,发送给其他提交者)中提及他是被支付薪水完成特定bug或特性。但是他也一直表现出无论如何他都会作出那些变更的印象,并很高兴金钱可以让他完成那些工作。他可以表露客户的身份,也可以不表露,但是无论怎样,他没有详述合同。他关于此事的备注只是一个对于如何完成工作的另类技术讨论的修饰。

那个例子也展示了开放承包合同带来益处的另一个原因。会有多个组织为开源项目资助承包,如果他们都知道其他人的目标,他们可以更好的调配资源。在上面的例子中,项目最大的创建者(CollabNet)没有以任何方式参与这种计件承包,但是当知道有人为某些bug修正提供资助时,CollabNet便将其资源转向到了其他bug上,从整体上大大提高了项目的效率。

其他开发者会憎恨这些因为薪水而为项目工作的人吗?通常情况下不会,这些得到支付的人都是社区值的尊敬的成员。没有人会期待承包工作会公平的分发给所有的提交者。人们理解长期关系的重要性:从事承包的不确定性会导致一旦你发现某人值的信赖,你就不太会只是因为公平性而找其他人。可以这样想一下:你第一次雇佣时,不会有抱怨,因为你必须选出某人—不能雇佣所有人不是你的错。此后,当你第二次雇佣此人时,那只是常识:你已经了解了他,上一次是成功的,为什么要承担不必要的风险?因此,只雇佣一个或两个人,而不是将工作分散开,这是非常自然的。

评审和接受变更

社区对于承包工作的成功也非常重要。他们为较大变更所投入的设计和评审过程不能只是事后处理。不应该把它当作工作的一个部分,并且完全交给承包者。不要把社区的仔细审查当作需要克服的障碍—而应该把它当作一个免费的设计委员会和QA部门。可以从攻击性的追逐中获益,而不仅仅是忍受。

案例研究:CVS密码认证协议

1995年,作为合伙人中的一个,我为CVS(并行版本系统,见http://www.cvshome.org/)提供支持和改进。我的搭档Jim和我,当时在非正式的维护着CVS。但是我们没有仔细考虑如何与已有的,主要是志愿者的CVS开发社区处理关系。我们只是假定他们会发送补丁,我们会应用补丁,那样就会一切正常。

那时,网络化的CVS还只能通过如rsh的远程登录程序完成。在CVS访问时使用与登录相同的密码显然存在安全风险,许多组织因此而放弃。一个主要的投资银行雇佣我们来添加一个认证机制,这样他们就可以使用网络CVS安全的连接远程办公室。

Jim和我得到这个契约并坐下来设计新的认证系统。我们面临的问题非常简单(当时美国对于加密算法代码有出口控制,所以客户知道我们无法实现较强的加密),但是因为我们没有设计这种协议的经验,我们还是作出了许多对于专家来说非常明显的错误。如果我们能够花时间写下提议并交给其他开发者评审,这些错误可以很容易的被发现。但是我们没有这样做,因为我们当时没有把开发列表当作可以利用的资源。我们认为人们将会接受所有我们提交的东西,而且—因为我们不知道我们所不知道的—我们不愿意在众目睽睽之下工作,例如频繁发布补丁,在一个特殊的分支作出较小、简单和易消化的提交等等。最后的认证协议并不是很好,当然,一旦建立起来,就很难在改进了,因为兼容性的考虑。

问题的根源是缺乏经验,我们可以轻易的认识到我们需要的知识。问题是我们对志愿者开发社区的态度。我们将对变更的接受当成了跨越障碍,而不是变更可以被改进的一个过程。因为我们很自信我们所做的任何事情都几乎会被接受(事实也是如此),所以放弃了让其他人参与的努力。

很明显,当你选了一个承包者,你一定希望他拥有此工作的正确技术技能和经验。但是,同样重要的是要选择一个拥有与社区其他开发者有建设性交流历史的人。你得到的不仅仅是一个人,也是一个代理人,他将会构建一套专业技能网络以确保他是以健壮和可维护的方式完成的工作。

资助非编程活动

编程只是开源项目的所有工作的一部分。从项目志愿者的视角,这是最明显和迷人的部分。很不幸,这意味着其他活动,例如文档、正式测试等等,是可以忽略的,至少与私有软件相比,投入了更少的精力。公司组织有时可以弥补这件事,通过投入一些他们内部软件开发时的基础架构到开源项目。

在公司内部过程和公共开发社区之间的转换是成功的关键。不过这种转换也不是轻而易举的:通常二者并不是一场接近的比赛,这种区别只能通过人为干预连接起来。例如,公司会使用与公共项目不同的bug跟踪系统。即使使用相同的跟踪软件,其中存放的数据也会大不相同,因为一个公司需要的bug跟踪与自由软件社区完全不同。位于某一跟踪系统的信息在映射到另一个系统时,必然要删除机密部分,从另一个方向来说,则是要添加。

本小节余下部分关于如何构建和维护这种联系。最后的结果必定是开源软件运行的更加平滑,社区会认可公司对于资源的投资,也不会感到公司掌控事情往自己的目标发展有什么不适合。

质量保证(也成为专业测试)

在私有软件开发中,一般都有一组人专注于质量保证:寻找bug、性能和扩展性测试、接口和文档检查等等。作为一般的原则,此类活动一般不会被自由软件项目的志愿者社区积极的追求。部分原因是很难为测试之类的不起眼工作找到志愿者,也因为人们总是假定他们有一个大的用户社区,可以给项目好的测试覆盖,以及性能和扩展性测试,也因为志愿者经常无法使用必要的硬件资源。

有很多用户等价于有许多测试者的假设并不成立。诚然,有时候分配测试者在普通环境中进行基本功能测试有一点用处:bug会在用户的日常操作中迅速被发现。但是因为用户只是期望把事情完成,他们不会有意识的开始探索程序未知的最新功能。此外,当他们在一个简单的场景发现了一个bug,他们经常悄悄的实现这个场景,而不会去报告这个bug。大多数没有意识到,你的客户(驱使进行软件开发的人)对于软件的使用模式会与普通用户的使用模式在统计学上有显著的不同。

专业的测试团队可以迅速发现此类bug,和他们在私有软件时一样容易。真正的挑战是将测试团队的结果以有用的形式反馈给公众。在内部测试部门中,通常有自己报告测试结果的方法,也需要使用公司特定的术语,或与特定客户和他们数据集相关的专业知识。这种报告对于公共bug跟踪并不适合,一方面是因为其格式,另一方面是因为机密性。即使你公司的内部bug跟踪软件与公共项目相同,仍然需要对此问题发生的公司特定的评论和元数据变更进行管理(例如,提升某个问题的内部等级,或者设定其为特定客户进行解决)。通常情况下,这些注释是机密的—有时候他们甚至不会展示给客户。但是即使没有机密,他们对于公共项目也没有意义,因此公众不想因此分散注意力。

核心bug报告本身对于公众非常重要。实际上,来自测试团队的bug报告会比普通用户的报告更有价值,因为测试团队是在为发现问题进行探测,而普通用户不是。因为你不太可能从任何其他来源获取这样的bug报告,你一定希望将其保留并发布给公众。

为此,如果他们愿意,或者可以将内部测试报告的问题转化到公共跟踪系统中,QA部门可以在公共问题跟踪系统中归档问题。转化仅仅意味着使用不涉及用户特定信息(重现的处方会使用用户数据,当然要假定用户对此认可)的方式描述bug。

推荐让QA部门在公共跟踪系统直接填写问题。这样会让公众对你公司的投入更加感激:有用的bug报告和技术贡献一样会增加你的组织的信誉。这样也给了开发者一个与测试团队直接交流的渠道。例如,如果内部QA团队监控着公共问题跟踪系统,一个开发者可以为一个可量测bug(开发者没有资源自己测试)提交修正,并为该问题提交一个说明询问QA团队查看该修正是否起到了预期的效果。也许会遇到一些开发者的抵制;最好情况下,程序员会把QA当作必要的魔鬼。通过发现显著的bug,填写复杂的报告,QA团队可以轻易的达到这个目标;另一方面,如果他们的报告甚至没有来自普通用户社区的报告质量高,那么让他们与开发团队直接交流也没有什么意义。

无论哪一种方法,一旦公共问题已经存在,原来的内部问题就应当在技术内容中引用公共问题。管理层和有薪开发者根据需要,或许可以继续关注包含公司特定注释的内部问题,但是使用公共问题可以让所有人看到对应的信息。

你应当会预期有额外的成本。维护一个bug的两个问题,将会比一个时耗费更多的工作。好处是,将有更多的程序员将会看到这个报告,并且能为这个解决方案作出贡献。

法律建议和保护

公司,无论是盈利或非赢利,恐怕是唯一在自由软件中将精力投入到法律问题上的实体。单个开发者通常理解多种开源许可证的微妙,但他们没有时间和资源去对版权、商标和版权法进行详细研究。如果你的公司拥有法律部门,可以通过否决代码的版权状态来帮助项目,并可以帮助开发者理解可能的版权和商标问题。如何帮助的具体形式将会在第 9 章 许可证,版权和专利讨论。主要是确保法律部门和开发社区的交流,如果发生这种交流,主要是因为完全不同的双方都有相互的渴望。在偶然情况下,这两组人会互相讨论,每一方会假定拥有另一方没有的领域特定知识。一个好的策略是在中间设定一个联络,在任何需要的时候进行转化。

文档和可用性

文档和可用性都是开源项目著名的软肋,尽管我认为,在文档方面,自由和私有软件的差距被夸大了。然而根据经验,大多数开源软件缺乏一流的文档和可用性研究。

如果你的组织希望为一个项目弥补这个差距,最好雇佣一些不属于项目常规开发者,但可以与开发者进行有效率交流的人。不雇佣开发者有两个原因:首先,你不会从项目带走开发时间;其次,距离项目过近的人通常不是编写文档或研究可用性的最佳人选,他们很难从外部视角观察软件。

然而,从事该工作的人还是有必要与开发者进行交流。找到的人需要拥有与编码团队交流的技能,但不必对软件过于专业而无法移情于普通用户。

一个中等用户很可能是编写好文档的合适人选。实际上,本书发行第一版后,我收到开源开发者Dirk Reiners的一封电子邮件:

关于金钱::文档和可用性的一些意见:当我们要花一些钱
并决定我们最需要的是编写初学者教程时,我们雇佣了一
个中级用户。他刚刚经历了系统的入门,所以能够记住问题
,但是因为已经通过问题,所以他知道如何描述问题。这样
他就可以编写一些只需由核心开发者进行少量修正的内容,
同时还是会覆盖开发组会认为‘非常明显的’而遗漏的内容。
他的案例甚至更好,随着他的工作,引入了许多用户(学
生)进入系统,所以他组合了许多人的经验,有时候某些事
看起来只是好运当头,恐怕不是在任何情况下都有效。

提供主机/带宽

对于不使用包装主机的站点(见第 3 章 技术基础设施“包装主机”一节),提供服务器和网络连接—以及更重要的系统管理帮助—会是重要的辅助。即使这是你的组织为项目所做的唯一工作,也是一种获取公共关系回报的适度有效的方法,尽管,它不会带来任何对于项目方向的影响。

你可能会在项目主页发现一个广告条或致谢,用以感谢提供主机的公司。如果你通过设置主机,让项目网址位于公司域名之下,那么单纯通过URL你就获得了额外的联系。这会导致大多数用户认为软件与你的公司有关,即使没有在开发中作出任何贡献。问题是,开发者也会意识到这种关联的趋势,会对项目位于你的领域感到不适,除非你能贡献出除带宽以外的更多资源。毕竟,现在有很多存放主机的地方。社区会最终感觉到这种隐含信用分化与主机带来的便利并不相配,并将项目带到别的地方。所以,如果你希望提供主机,要这样做—不但要计划投入更多,更要细心的考虑声明投入多少。

市场营销

虽然大多数开源开发者不愿意承认,但市场推广确实有用。好的营销活动可以为开源产品创造良好的氛围,即使此时顽固的编码者因为一些无法说明的原因,对于软件还没有清晰肯定的思路。这里我不会讨论一般意义的市场营销的军备竞赛动力学。所有参与到自由软件的公司最终都会发现自己需要考虑如何营销自己、软件或他们与软件的关系。下面是在进行这种努力时如何避免落入陷阱的建议;请看第 6 章 交流“公开性”一节

记住你正在被注视着

为了让志愿开发者社区一直站在你一边,非常重要的一点是不要说任何不能确定正确的事情。作出任何声明前要仔细审核,并要为公众提供独立检查该声明的方法。独立事实检查是开源项目的主要组成部分,它不仅仅适用于代码。

很自然,没有人会建议公司作出未验证的声明。但是在开源活动中,通常会有不可思议的大量拥有专业技能的人去验证声明—这些人也都有高速的宽带接入和足够的社会联系,可以用一种危险方法发布他们的发现,他们一定会这么干。当Global Megacorp化工的工厂污染了河流,只有经过训练的科学家可以验证,他们也会受到Global Megacorp科学家的反驳,让公众抓耳挠腮而不知如何考虑。而另一方面,你在开源世界中的行为不仅是可见的和可记录的;也很容易被许多人独立的检查,得出他们自己的结论,并口头传播这些结论。这种交流网络一直都在;那是开源操作的本质,他们可以用来传播任何信息。如果不是不可能,反驳通常很困难,特别是当某人所说的是正确的。

例如,如果你们确实这么做了,可以称你的组织“资助了项目X”。但是,如果大多数代码是外人写的,不要称自己为“X的制造者”。相反地,如果任何人都可以看到版本库只有少量代码变更来自于组织之外,不要声明已经有了一个深入参与的开发者社区。

不久之前,我看到一个知名计算机公司的一次声明,说明他们以开源许可证发布了一个重要的软件包。当最初的声明发出之后,我看了一下他们的公共版本控制版本库,发现其中只有三次修订。换句话说,他们只是做了一次代码的初始化导入,之后没做什么事情。此事本身没有什么好担心的—毕竟,他们只是做了声明。没有理由期待会立刻发生大量开发活动。

不久之后,他们作出另一次声明。下面是将名称和数字替换后声明:

我们很高兴的宣布经过Singer社区严格的测试,Linux和Windows版本的Singer 5已经做好生产使用的准备。

很想知道是什么社区进行的“严格测试”,我回到版本库去看最近的变更历史。项目还在修订3,很明显,他们没有发现任何一个值得在发布前修订的bug。考虑到社区测试一定是记录到了其他地方,接着我检查了bug跟踪系统。发现刚好有6个开放的问题,其中四个已经打开了几个月。

当然,这是乞丐的信仰(不可信)。当测试者在一个大型和复杂的软件上认真推敲一段时间,他们一定会发现bug。即使bug的修正不会进入即将到来的版本,人们还是希望有一些版本控制活动会作为测试过程的结果出现,或至少是一些新的问题。很显然,在开源许可证声明和第一次开源发布声明之间没有发生任何事情。

重点不是说这个公司在社区测试问题上说了谎。我不知道他们到底做了没有。但是他们很明显是在欺骗。因为,无论是版本控制版本库还是问题跟踪系统,都没有任何迹象来说明所谓的严格测试曾经发生过,这个公司要么不要过早的声明,要么提供一些测试结果的明确链接(“我们发现了278个bug;点击此处看详细内容”)。后一种方法可以让任何人迅速掌握社区活动的级别。就像前面说的,我只有了几分钟就确定了这个社区测试的真相,它没有在任何常见的地方留下痕迹。那样不会花费太多力气,我确信我不是唯一保持疑惑的人。

当然,透明性和可验证性也是准确信用的重要部分。关于这些内容可以看第 8 章 管理志愿者“荣誉”一节

不要痛击竞争开源产品

要忍住不要发表关于竞争开源软件的负面意见。可以做的是提供负面的事实—也就是通常在一些好的比较图表上可以轻易确定的断言。但是最好避免不太严格的本性的负面特征,有两个原因。首先,这样会点燃论战而脱离有建设意义的讨论。其次,更重要的,在你的项目的一些志愿开发者会转向为竞争项目工作。开始并不是很明显:项目都在同一个领域(这也是为什么他们会竞争),拥有专业技能的开发者会在任何可以发挥专业才能的地方作出贡献。即使没有直接的开发者重叠,也很可能你的项目的开发者会与关联项目的开发者相识。他们维护建设性的个人关系的能力会被负面营销信息所束缚。

在开源世界中,痛殴闭源产品中的竞争者是可以广泛接受的,特别是如果这些产品是微软制造。个人来讲,我为这种趋势感到悲哀(虽然如此,这种直接基于事实的比较没有任何错误),不仅仅是因为这样很粗鲁,也因为这样很危险,让一个项目开始相信它自己的夸夸其谈,并忽视竞争者实际上可能更加优越的方式。通常情况下,可以仔细观察市场声明的效果,因为这也会发生在你自己的开发社区。人们可能因为市场美元的支持而丧失客观性,无法看清自己软件的真正力量和弱点。一个很可能出现的情形,某个公司的开发者会公开展示自己对于某个市场声明的无辜,甚至是直接在公共论坛。很明显,他们不应当直接跳出来否决市场营销信息(除非它事实上是错误的,尽管人们希望此类事情能够尽早被捕获)。但是他们可能会一次次的取笑这种行为,这也是将开发社区的其余部分带回地球的一个方法。

第 6 章 交流

将代码写清楚的能力或许是开源环境中最重要的一项技巧。从长期来看,这不仅仅取决于编程天赋。即使是优秀的程序员,如果没有好的沟通技巧,在同一时间也只能完成一件事,即使如此也很难让其他人注意。但一个糟糕的程序员如果善于交流,则可以协调并说服许多人做很多事情,对于项目的方向和动力起着重要的作用。

无论从哪个方向看,编写好代码的能力和与其他人交流的能力看起来毫不相关。编码能力和描述技术问题的能力则有一些关系,但是描述技术问题只是项目交流中很小的一部分。更重要的是移情到其读者的能力,可以像其他人那样去看待自己的文章和回复,可以让他人以同样的客观性看待自己的文章。同样重要的是发现某种媒介或交流方法不再有效,这或许是因为它并没有随用户数量的增多而扩展,然后花时间去解决它。

在理论上很明显—但因为开源软件开发环境的受众和交流机制引起的混乱,在实践中的非常困难。一个给定的想法必须在邮件列表中作为bug跟踪系统的注释或代码的说明发布出来?当在一个公共论坛回答一个问题时,应该如何假定读者的知识水平,只是为咨询问题的“读者”解答,而是为所有会看到回复的读者?如何让开发者与其他用户保持建设性的联系,而避免陷入特性请求、虚假的bug报告和一般的聊天。如何知道一个媒介达到了容量的限度,你该如何做呢?

针对这些问题的解决方案都只能是部分的,因为任何特定方案都会随项目结构的成长或变化而废弃。他们也经常是专门的方案,因为他们需要随机应变。所有的参与者需要意识到交流在何时,如何陷入困境,并立刻参与到解决方案中去。帮助人们完成这件事是管理开源项目的重要任务。本小节后面的部分会讨论如何引导你自己的交流,以及如何在项目中为所有人维护交流机制的优先级。[22]

人如其文

考虑如下情况:因特网上别人对你的了解都来自你所写的东西。你或许是一个富有才华、敏锐和领袖气质的人—但是如果的你的邮件散漫且没有组织,人们会以为你也是这样。或者也许你是一个散漫和无组织的人,但没人会知道这一点,只要你的文字能够清晰且言之有物。

在写作上的投入回报巨大。长期自由软件黑客Jim Blandy说过这样一个故事:

回到1993,我为自由软件基金会工作,正在为GNU Emacs的19版本进行beta测试。我们每周都会发布一个这样的beta版本,人们会进行测试并回馈我们bug报告。有一个我们都不认识的人,但是完成的工作很好:他的报告总是十分清晰,并能让我们直接找到问题,而且当他自己提供修正时,也几乎都是正确的。他是顶尖人物。

现在,在FSF可以使用其他人编写的代码之前,我们会让他们准备一些文书工作,将该代码的版权利润赋予给FSF。完全获得陌生人的代码是处理法律灾难的好办法。

所以我给这个家伙发了一份表单,说,“这里是我们需要的一些文书工作,你签署这一份,让你的雇主签另一份,然后我们就可以开始提交你的修正。非常感谢。”

他回复了一封信息说,“我没有雇主。”

所以我说,“很好,那就让你的大学签署它并发回来。”

不久,他又回复了,并说,“很好,实际上,我已经30岁了,与父母一起住。”

因为那个小孩并没有像30岁的人那样写东西,所以没有人知道他的情况。下面也是让你的写作能够带来良好印象的一些方法。

结构和格式

不要像编写手机短信那样编写所有的东西。要使用完整的句子,每个句子首字母要大写,也要根据需要分段。在编写电子邮件和其他内容时这一点最重要。在IRC或类似的短命论坛上,忽略大小写或压缩形式的常见短语也无所谓。只是不要把这个习惯带到更正式,会持久化保存的论坛中。邮件、文档、bug报告和其他会永久保存的东西,必须使用标准语法和拼写,并有一致的叙事结构。并不是因为任何事情都有遵循任意规则的内在特性,而是因为规则并不是任意的:他们演化成现在的形式是因为可以让文本更可读,因此你应该遵循这些规则。可读性是令人向往的,并不是因为这样人们就能够理解你所写的,而且是因为这样可以让你看起来像是人们可以花时间进行清晰交流的人:也就是值得人们关注的人。

对于个别的电子邮件,有经验的开源开发者会使用特定的约定:

只发送文本邮件,而不应该是HTML、富文本或其他格式,因为有许多只支持文本的邮件阅读器。将每行列长格式化为72。列长不要超过80,80已经成为事实上的标准终端宽度(也就是会有人使用更宽的终端,但没有更窄的)。通过将列数设置为小于80,可以为其他人回复中的引用字符留出空间,从而不必让文本强制换行。

使用真正的换行。一些邮件程序可以使用一种假的换行,可以让你编写的邮件在没有实际换行时显示出来有换行。当邮件发送以后,邮件不会有你所以为的换行,他们会非常难看的出现在某些人的屏幕上。如果你的邮件程序使用假换行,应该找一个恰当的设置,可以在编写邮件时显示真换行。

当包含屏幕输出,代码片段或其他格式化文本时,需要清晰的处理缩进,这样可以轻易的区分你的叙述和引用的内容。 (当我开始撰写此书时,我没有想过编写这些建议,但是当在许多开源邮件列表中看到了很多人混合文本和其他资源,以至于无法区分开时,我改变了注意。这样的效果很让人灰心。这让他们的文章很难被理解,很明显也让这些人看起来有点混乱。)

当引用其他人的邮件时,可以直接在合适的位置插入你的回应,如果需要可以在不同的位置,然后删节那些在你的邮件不使用的部分。如果你需要为全文进行评述,可以写在顶部(将你的回应置于引用的邮件文本之前);否则,请首先引述原邮件的相关文本,然后紧跟你的回应。

小心构建新邮件的主题行。这是邮件中最重要的一行,因为它可以让项目中的其他人决定是否进一步阅读。现代邮件阅读软件可以将相关信息组织成一组线索,并不仅仅是根据共同的主题,而且可以根据其他头(有时并不显示)。它遵循了如下原则,如果线索转移到另一个主题,你可以—也必须—根据回复修改主题行。由于其他邮件头,线索的完整性得以保全,但是新的主题可以帮助人们获知主题已经转移。同样的,如果你确实希望开始一个新的主题,那么可以发布一个新的邮件,而不是对现有邮件修改主题并回复。否则,你的邮件会仍然分组到你所回复的线程中,因此会让人们不知道讨论的内容已经改变。再次,惩罚不仅仅是所浪费的时间,也会使你使用交流工具的信用受损。

内容

组织良好的邮件会吸引读者,但是内容可以留住他们。当然,没有可以确保好内容的固定规则,但是有一些可以让其更像的原理。

让事情对你的读者更简单。任何一个开源项目都有大量的信息,不能期望读者熟悉所有的东西—事实上,不可能期望他们知道如何熟悉。所以要尽可能让你的文章以尽量便利的形式提供给读者。如果你能够额外花费几分钟在邮件列表归档中找出特定线索的URL时,从而减少读者寻找的麻烦,这样做非常值得。如果你可以花费5到10分钟为复杂的线索总结一个结论,从而为人们理解你的文章提供一个上下文环境,那么一定要去做。可以这样考虑这件事,项目越成功,在任何论坛中的读者-作者比率越高。如果你的文章被n个用户看到,那么随着n的增大,扩展额外的努力节约其他人的时间就越值得。随着人们看到你将自己置于这个标准之下,他们也会在自己的交流中与此匹配。理想情况下,会带来项目整体效率的提升:当人们在n个人和一个人这样努力做出选择时,大家会选择前者。

不要使用夸张法。在线发布中的夸大是经典的军备竞赛。例如,一些报告bug的人会担心开发者不会投入足够的注意力,所以他们将其描述为严重的、会中断他(以及他的所有朋友/同事/亲戚)使用该软件的问题,而实际上只是一般的不适。但是夸大并不限于用户—程序员也会在技术讨论时也这样做,特别是当问题是关于他们不认可的某种口味而不是正确性时。

“这样做事会让代码完全不可读。 与J. Random的建议相比,这是维护的梦魇。”

当措辞不是如此尖锐,同样的感情也会变得更强

“这样也可以工作,但是出于可读性和可维护性的考虑,并不是理想的方式,我认为。J. Random's的建议避免了这类问题,因为它...”

你不可能完全消灭夸大,一般来说也没有必要。与其他形式的交流问题相比,夸大并不是对所有人都有害—他只会伤害夸大者。接收者也会做出相应的抵消,每次都会让发送者损失自己的信用。因此,为了你自己在项目的影响力,请使用温和的方式。只有这样,人们在会在你真的需要表达强烈观点时重视你。

编辑两次。对于任何超过中等长度段落的信息,请在你第一次认为完成之后再从头到尾检查一遍。这是所有参加过写作课程的人会得到的忠告,但是在在线讨论中格外重要。因为在线写作的过程很容易变得非常不连贯(在编写信息的过程中,你需要回头检查其他邮件,访问特定的网页,或者运行某个命令捕获调试信息等),这样很容易让你失去叙事的感觉。不连贯编写的信息,而且在发送以前也不检查通常会被认为会让他们的作者懊恼(或者这样某人会希望)。花时间检查你发送的内容。你的内容组织的越好,就会有越多的人去阅读。

基调

在写过几千条信息后,你一定会发现自己会趋向于简洁。这看起来是大多数技术论坛的标准,在本质上没有任何错误。在社会交流中不可接受的简洁程度则是自由软件黑客的默认程度。下面是我在一个邮件列表中发表的关于自由内容管理软件的文章,完全引用:

您能更详细的说一下所遇到的问题吗?
可能是:

您使用什么版本的Slash?你能说出原始信息吗。
你是如何编译的apache/mod_perl源?

你尝试过发布在slashcode.com的Apache 2.0补丁吗?

  Shane

就是简洁!没有问候,没有他的名字以外的签名,整个信息本身只有一系列尽可能紧凑的疑问句。其中的一个祈使语句是隐含的对原始信息的批评。虽然如此,我还是很高兴看到Shane的邮件,并没有因为其简洁而把他当作一个大忙人。事实仅仅是他们在询问问题,而不是忽略我的问题,意味着他愿意在这个问题上花更多的时间。

读者能够对这种方式作出正面的反应吗?这不是必须的;这取决于人和上下文。例如,如果某人刚刚承认她犯了一个错误(例如写了一个bug),而你根据以前的经验知道这个人容易不安全,那么你仍会编写一个紧凑的回复,你应当确信其中包含一些考虑其感受的内容。你的回复可能很简短,只有工程师对于形式的分析,和你想的一样简洁。但是在最后,应该指明你的简洁不应该理解为冷漠。例如,如果你要建议如何正确的修正某个bug,应该签署“好运,<这里是你的名字>”指明你希望他们做好工作而不会发疯。一个笑脸或其他符号表情通常也足够安抚你的对话者。

也许像关心参与者所说事情的表面一样关心其情绪有一些古怪,但是认真的说,情绪影响生产力。由于其他原因情绪也非常重要,但如果仅出于功利原因,我们也能发现不快乐的人会写出糟糕的软件。因为大多数电子媒介的本性所限,通常没有关于人们情绪的明显线索。你应该根据这些猜测:a)大多数人在那种形势下的感觉,b)你在以前的交流中对参与者的了解。一些人采用更简单的态度,仅根据表面处理事情,如果没有参与者直接说出自己的感受,则别人没有义务像他已经说出那样去对待她。我不会选用这个方法,有如下一些原因。首先,人们在真实生活中并不是这样处事的,为什么要在线上这样?其次,因为所有的互动发生在公共论坛,人们会比私密情况下更加控制自己的感情表达。更精确的说,他们通常希望对某人直接表达感情,例如感激和愤怒,而不是直接的内部情绪,例如不安和骄傲。当知道其他人会关注到他的心理状态时,大多数人会工作的更好。通过在细微线索上投入注意力,你可以在大多数时候猜到问题,并且能够鼓舞人们比原来更深入地参与。

我不是说,你的角色是团队治疗师,一直通过触及别人的情绪来帮助每个人。但是通过对于个人行为长期模式的观察,即使你们从来也没有面对面,也会获得像单个人之间的感受。而且通过对于自己文章基调的敏感性,你会为自己对于其他人情绪的影响力感到吃惊,最终会使项目受益。

识别无礼

开源文化的一个定性特征是对于何为无礼的特色定义。下面叙述的习惯不只是出现在开源软件开发,也不只是在一般软件—在数学、严密科学或工程纪律中也并不陌生—自由软件,由于其跨领域性,并有不断涌入的新来者,许多不熟悉这种环境的人将要面对这些习惯。

我们先从无礼开始。

技术批评,即使很直接且没有铺垫,也不是无礼的。实际上,这可以看作是一种谄媚:批评者在说话,说明目标值得重视,值得花时间研究。可以说,平静只是简单的忽视某人的文章,花费更多时间批评它则是更多的赞美(当然,除非批评升级到了非理性的攻击或其他形式的明显无礼)。

迟钝、朴实的问题,例如前面Shane的对我的邮件,也不是无礼。在其他环境下这种提问会看起来有些冷酷,玩弄文字或甚至是嘲弄,通常是有意的严重行为,而且除了尽快释放出信息,没有隐藏的日程表。著名的技术支持问题“你的电脑插电了吗?”是经典的案例。支持者确实需要知道你的电脑是否插电,经过一段时间的这类工作,他已经厌倦了在问题前点缀一些有礼貌的奉承(“请原谅,我只是要问一些问题以排除一些可能性。有一些可能很基础,请暂时忍受一下我...”)。 此刻,他没有再做任何铺垫,只是直接问:到底插电了没有?类似的问题会一直在自由软件邮件列表中被问起。目的不是冒犯接收者,而是快速排除大多数明显的(或许也是最常见的)解释。理解这种行为并作出响应的接收者会因为大度的态度获得成功。不能正确反应的接收者也不会受到谴责。这只是文化的冲突,不是某人的过错。要和蔼的解释你的问题(或批评)没有隐藏的含义;只是希望让(或传递)信息尽可能有效率,无他。

那么怎样是无礼?

详细的技术评论一种形式的谄媚,同理,如果不能提供高质量批评也可以看作是一种冒犯。我不是说仅仅忽略某人的工作,是提议、代码变更、新问题添加或任何事。除非您之前明确的承诺会有详细的反应,不做任何反应也没有错。人们只会假设你没有时间回答。但是如果你反应,就要用心:花时间真的去分析,提供合适的实在例子,在以前的归档中发掘相关的文章等等。或者如果你没有时间花费这种精力,但仍需要写一些简短的回应,然后在信息中公开说明缺陷(“我知道有一个对应的问题,不过我没时间去搜索,对不起”)。主要是认识到文化标准的存在,通过履行承诺或公开的告知缺乏时间实现。无论何种方式,标准都会被加强。即使不能达到标准,不要在同一时间解释为什么你没有达到,这样做好像是说这个主题(以及那些参与者)不值得你花费时间。更好地是通过简洁而不是懒惰展示你的时间的价值。

也有一些其他形式的无礼,当然,但是大多数并不只存在于自由软件开发,而且常识足够引导你避免他们。如果你还没有看,可以看第 2 章 起步“防无礼于未然”一节

面容

人脑中有一块专门负责识别面容的区域。它被非正式的称为“梭型面容区域”,其能力大多来自天生,而不是学习得到。因为识别单个人是至关重要的生存技巧,所以我们演化出了专门的硬件负责这个工作。

互联网基于的交流从心理上说有些古怪,因为需要许多无法用自然,原始的方法识别对方的人,进行紧密的合作:首先是面部识别,也有声音和姿势等。为了弥补这种不足,可以在所有地方使用一致的屏幕名称。他应该是你邮件地址的一部分(@之前的部分),你的IRC用户名,你的版本库提交名,你的问题跟踪用户名等等。这个名字就是你的在线“面容”:一段可以同你的真实面容起到同样效果的标识字符串,尽管他不是,但至少模拟了内置在电脑的硬件。。

屏幕名称应该是你真实姓名的直觉(例如我的是“kfogel”)展示。在一些情况中,会伴随你的完整名,例如在邮件头中:

From: "Karl Fogel" <kfogel@whateverdomain.com>

实际上,这个例子有两件事。就像前面提到的,屏幕名称用直觉方式匹配真实姓名。但是,真实姓名是真实的。而不是某种修饰的名称:

From: "Wonder Hacker" <wonderhacker@whateverdomain.com>

Paul Steiner有一副著名的卡通,刊登在1993年6月5日的纽约客,里面是一条狗登录到了电脑终端并阴险的与另一个人交谈:“在因特网上,没人知道你是一条狗。”这类思想的背后是自我夸大,这些有些俏皮的在线标识的人给了他们自己—好像被叫做“Wonder Hacker”真的是神奇黑客了。但是事实没有改变:即使没人知道你是条狗,你还是条狗。一个幻想的在线标识不会打动读者。相反,他们会认为你只是形象而没有本体,或者仅仅是你是不安全的。在所有的交流中使用真实姓名,或者因为某些原因需要匿名,那么就请起一个完全像真名的名称,并一直用下去。

为了保持你的在线面容的一致,有一些方法可以让他更吸引人。如果你有正式的头衔(例如”博士“、”教授“和”导师“),不要炫耀,除非与对话内容相关,最好不要提及。作为一般的黑客之道,特别是自由软件文化,认为这些头衔是多余和不安全的标志(例如叫兽和砖家)。当然,如果这些头衔是作为标准的签名出现在每封邮件,不要把这个当作支持你在讨论中位置的工具—这种尝试必定事与愿违。你需要尊敬人的家伙,而不是尊敬这些头衔。

说到签名区:要保证短小有意义,或者更好的情况是没有签名区。避免大段的法律免责声明出现在每个邮件的结尾,特别是当他们表达的感情与自由软件项目的参与精神不匹配时。例如,如下是我参与的一个公开邮件列表中的某个用户每个文章都会出现的的经典流派:

IMPORTANT NOTICE

If you have received this e-mail in error or wish to read our e-mail
disclaimer statement and monitoring policy, please refer to the
statement below or contact the sender.

This communication is from Deloitte & Touche LLP.  Deloitte &
Touche LLP is a limited liability partnership registered in England
and Wales with registered number OC303675.  A list of members' names
is available for inspection at Stonecutter Court, 1 Stonecutter
Street, London EC4A 4TR, United Kingdom, the firm's principal place of
business and registered office.  Deloitte & Touche LLP is
authorised and regulated by the Financial Services Authority.

This communication and any attachments contain information which is
confidential and may also be privileged.  It is for the exclusive use
of the intended recipient(s).  If you are not the intended
recipient(s) please note that any form of disclosure, distribution,
copying or use of this communication or the information in it or in
any attachments is strictly prohibited and may be unlawful.  If you
have received this communication in error, please return it with the
title "received in error" to IT.SECURITY.UK@deloitte.co.uk then delete
the email and destroy any copies of it.

E-mail communications cannot be guaranteed to be secure or error free,
as information could be intercepted, corrupted, amended, lost,
destroyed, arrive late or incomplete, or contain viruses.  We do not
accept liability for any such matters or their consequences.  Anyone
who communicates with us by e-mail is taken to accept the risks in
doing so.

When addressed to our clients, any opinions or advice contained in
this e-mail and any attachments are subject to the terms and
conditions expressed in the governing Deloitte & Touche LLP client
engagement letter.

Opinions, conclusions and other information in this e-mail and any
attachments which do not relate to the official business of the firm
are neither given nor endorsed by it.

对于只想偶尔询问一个问题的人,如此巨大的免责声明虽然有点傻,但是没有任何永久的伤害。但是,如果某人希望活跃的参与到项目中,这个法律的陈词滥调会开始一个更潜在的影响。它会释放出两个潜在的破坏性的信号,这个人对于自己的工具没有完全的控制权力—他陷入了某个公司的邮件系统,这个系统会在每个邮件结尾添加讨厌的信息,而他无法绕过—其次,他对自己参与的自由软件活动只有有限或没有任何组织支持。诚然,组织明显没有禁止他在公共列表发表文章,但可以让他的文章看起来明显的不受欢迎,仿佛泄漏机密信息的风险必须排在第一位。

如果你所在的组织坚持对所有外发邮件添加这种签名区,应该考虑申请一个免费邮件帐号,例如,gmail.google.comwww.hotmail.comwww.yahoo.com,然后作为你在项目中的地址。

避免常见的陷阱

不要发表无目的的文章

在线项目中一个常见的陷阱是认为你需要回复所有的东西。你不必如此。首先,一般会有太多你无法同时跟踪的线索,至少是经过它开始的几个月后。其次,即使你已经决定参与,人们说的大多数话都无需回应。开发论坛都会不同程度的由下列三类信息占据:

  1. 提出重要事物的信息

  2. 提出对他人曾经说过的话表示支持或反对的信息

  3. 总结信息

上述信息并不是必定需要一个回应,特别是当你根据到目前为止的线索,很确定其他人会说出以前你说过的话时。 (如果你担心别人也使用这个策略,而落入等待-等待的循环,不必如此;几乎总会有某人愿意跳出来解决问题。) 回复应该由明确的目的激发。首先要问自己,是否知道所期望的完成的任务?其次,是否如果没有你的话,这个事情就无法完成。

在线索中发出你的声音的有两个理由,包括a) 当你在提议中发现了一个瑕疵,你怀疑你是唯一看到它的人,另外b) 你发现他人之间错误交流,并且知道你可以通过澄清文章修正它。通常在邮件中仅仅表明对某人工作的感谢或者只是说“我也是!”,因为读者可以立刻确认此类文章无需任何回应或进一步的动作,所以当读者达到邮件的最后一行,一个干净的结束符合他的心理需求。但是即使到了此时,说话之前也要再三考虑;一定要让别人觉得你说的太多而不是太少。(在忙碌的邮件列表中工作的更多想法的第二部分请看附录 C, 为什么我要关注车棚的颜色?

多产VS非多产的线索

在忙碌的邮件列表中,你有两个诫命。第一,很明显,要指出哪些需要关注,哪些需要忽略。第二,要避免产生噪音的方式:不仅仅是你希望自己的文章保持较高的信噪比,你也希望这些信息可以刺激其他人也保持同样的信噪比,或者干脆不发表文章。

为了展示这是如何发生的,考虑一下事情发生的上下文。非多产的线索的特征是什么?

  • 发生的争论是在重复,仿佛发布者认为没有人听说过。

  • 随着赌注的缩小,夸大和连累的升级。

  • 大部分评论来自做过很少事情或没做过事情的人,而能帮助完成事情的人则保持沉默。

  • 大多数想法的讨论都没有作出明确的提议。 (当然,任何有趣的想法都是从不清晰的远见开始;重要的问题是之后的方向。讨论是否将远见变得更具体,或者分裂为更小的远见,副远见和本体论的争论?)

不要因为某个线索开始不够多产而认为它是浪费时间。它可能是一个重要的主题,正因为他非常棘手所以难以做出进展。

将线索引向有用而不是蛮干是一项艺术,仅仅是告诉人们不要浪费时间,或者告诉他们在没有形成建设性的内容前不要说话并没有用。你或许可以在私下这样想一想,但是如果你大声的说出来就会成为一种冒犯。相反,你必须促成进一步进展的条件—给人们一条路,一条可以将结果导向期望的路,而无需发出指挥命令。这样的基调将会大为不同。例如,这样很不好:

这个讨论已经跑的漫无边际了。我们可以暂停这个主题,直到某人能够提交一个补丁实现这些建议吗?没有理由继续反复说同一件事情。代码比单词更有力,伙计们。

然而这样很好:

线索浮现出了多个提议,但都没有完成所有的细节,至少还不足以形成表决。然而现在我们也说不出新东西了;只是在反复重复以前说过的东西。此时,为了进一步的讨论,最好提供提议的完整规格或补丁。然后我们至少有明确的动作可以做(即对规格达成一致,或应用和测试补丁)。

第二种方法与第一种方法完全相反。第二种方法不会让你与他人发生联系,也不要指责他们将讨论带入了螺旋。无论你在之前是否参与到线索的讨论,都要说是“我们”,因为即使你一直在线索中保持沉默,线索的结果也有你的份。它描述了为什么线索到了乌有之地,这样做并没有轻蔑或判决的含义—它只是不带感情的对事实的描述。最重要的,它提供了一个行动的正面课程,这样人们就不会感觉到讨论被关闭了(对于他们可以被诱惑去造反的限制),而会感到获得了一个方法可以将对话带入更有建设性的水平。这是人们自然会期望遇到的标准。

你不会一直希望让线程进入更有建设性的水平—有时,你只是希望它赶快离开。文章的目的只是从中选择一个,放弃另一个。如果你能断定线索离题太远,而且没有能实际上完成你所建议的步骤,那么你的文章会有效的终止线索,而且不需要这样做。当然,没有关闭线索的安全方法,即使有,你也不会希望去使用。但是询问参与者在作出可见的进展和停止讨论之间做出选择则是完美可防卫的,如果可以圆滑完成的话。然而,还是要小心永久的平息线索。一些纯理论的讨论可能会十分多产,取决于主题,而且如果过快的要求解决也会扼杀创造过程,也会让你看起来不够耐心。

不要期望线索会立刻停止。在你的文章之后,还是会有些文章,一方面因为邮件是排队传递的,另一方面是因为人们想说最后一句话。不必为此担心,你不用再说一遍。只需要让它逐渐消失或不消失,这取决于具体的情况。你不可能有完全的控制;另一方面,你可以期望在大量线索的统计上有显著的效果。

主题越软,辩论越长

尽管讨论会在任何主题上缓慢前进,但是随着主题技术难度的降低,缓慢前进的可能性就越高。毕竟,技术难度越大,能够理解的参与者也就越少。这些参与者更有可能是最有经验的开发者,他们已经参加过无数次这样的讨论,知道如何才能与每个人达成共识。

因此,如果技术问题易于理解或容易得出自己的意见,或者是诸如组织、公开性和资金的软主题,就很难达成共识。人们可以永远参与到这种辩论中,因为这事没有门槛,没有决定(甚至在之后)正确或错误的明确方法,而且因为等待其他讨论者结束是一个成功的策略。

对于长期的主题,讨论的数量与主题的复杂度成反比的原理,被非正式的称为Bikeshed效用。这里是Poul-Henning Kamp为BSD开发者作出解释的著名文章:

这是一个很长的故事,或者说是一个老故事,但它实际上很短。C. Northcote Parkinson在20世纪60年代初编写了一本叫做“Parkinson定律”的书,包含了许多管理动态性的真知灼见。

[...]

这些例子中包括自行车棚,另一个更重要的组件是核电站,我猜这描述了本书的年龄。

Parkinson展示了如何进入董事会,并得到建造花费几百万,甚至几十亿美元核电站的许可,但如果你希望建造自行车棚,则会陷入无休止的讨论。

Parkinson解释了这是因为核电站太大、太贵和太复杂了,人们无法掌握,所以不会去尝试,转而会假设某人会在需要时检查所有的细节。Richard P. Feynmann在他的书中提供了一些关于洛斯阿拉莫斯(美国新墨西哥州中北部一个无法人地位的社区,位于圣菲市西北。1942年被选作核研究基地,生产了第一批原子弹。从1947年至1962年原子能委员会统治着这个城镇。)的有趣而且非常到位的例子。

另一方面是自行车棚。所人都可以在周末建一个车棚,而且还有时间看电视上的比赛。所以无论准备的多好,无论你的提议是多么的有道理,人们会抓住机会展示他在做自己的工作,他正在关注,他就在这里

在丹麦,我称之为“配置你的指纹”。它关于自尊和声望,关于能够指向某事并说“这里!我那样的。”这是政客的典型特征,但是现在很多人都会这样。想想湿水泥中的足迹。

(他的完整文章也十分值得阅读。请看附录 C, 为什么我要关注车棚的颜色?,以及http://bikeshed.com。)

任何参加过团队决策的人都会知道Kamp所说的东西。然而,通常还是不可能说服每个人避免喷刷自行车棚。最好你能指出这是一个必然存在的现象,并在你发现它时,说服高级开发者—这些文章拥有最高权重的人—尽早丢下他们的刷子,或至少不要添加噪音。自行车棚喷涂的聚会永远不会完全消失,但是你可以通过在项目文化中传播这个现象的知识让这种事变得时间更短,频率更低。

避免圣战

一场圣战是一场争论,经常但不会一直是相对的小问题,一般不会通过辩论得到解决,但是有人会充满热情的继续辩论,期望他们一方会获胜。圣战并不与自行车棚完全一样。人们粉刷车棚通常是突然跳出来的意见(因为他们可以),但是他们不必强烈的感觉必须如此,并且以后会表达其他的意见,互相矛盾的意见,以展示他们理解问题的所有方面。而另一方面,在圣战中,理解对方则是示弱的表现。在圣战中,每个人认为有一个唯一正确的答案;他们只是不认可是什么。

圣战一旦开始,通常就不可能让每个人都满意。在正在进行的圣战中指出这点并没有好处。每个人都已经知道。不幸的是,但是对于通过连续的讨论能否解决争论这一问题,是圣战并不认可的一个常见特性。从外部看来,很明显没有一方可以改变另一方的意见。而从内部看,则认为另一方太过蠢笨,也没有想清楚,但是经过足够的恫吓则能回心转意。现在,我没有说在圣战中永远没有正确的一方。有时确实有—在我参加的圣战中,真理当然永远属于我这一边。但是没有关系,因为没有算法可以令人信服的描述某一方是正确的。

人们试图解决圣战的一个常见的,但是不能令人满意的方法是说“我们的讨论已经浪费了过多的时间和精力!我们能不能把它忘掉?”这样有两个问题。首先,时间和精力已经投入,不可能收回了—现在唯一的问题是还有更多的力量吗?如果某人感觉更多的讨论会结束这个问题,那么继续就还有意义(从他们的角度看)。

另一个要求这件事必须丢弃的问题是这通常等同于允许某一方打破现状,通过无为宣布胜利。在某些情况下,现状无论如何是不能接受的,每个人都认为需要作出决定,必须有所行动。为每个人丢弃这个主题通常比任何人放弃论点更坏。但是因为这种两难可以平等的应用到所有人,所以仍有可能永久结束辩论。

那么你应当如何处理圣战?

第一个回答是,做好准备避免其发生。看起来并不是完全没有希望:

你可以预期到一些标准的圣战:可能关于编程语言、许可证(见第 9 章 许可证,版权和专利“GPL和许可证兼容性”一节)、回复处理(见第 3 章 技术基础设施“伟大的Reply-to辩论”一节)和一些其他主题。每个项目可能都有自己的圣战,长期开发者会很快熟悉。停止圣战,或者减少其危害的技巧在大多数地方都是相同的。即使你肯定你属于正确的一方,可以试着寻找一些方法展示自己对对方的同感,并理解另一方的论点。通常问题是在圣战中的每一方都尽可能高的建筑自己的墙,而使其他见解看起来是完全的愚蠢,放弃或改变思想的行动在心理学上变得不可忍受:这样做不仅仅是承认错误,而是必然并且会一直错下去。将这种承认变得可口的方法是展示你的不确定性—精确的展示你理解他们的辩论,发现他们至少很敏感,即使最终并不是令人信服。作出为回应姿态留出空间的姿态,通常情况会得到改善。也许你不会得到期望的技术结果,但是你可以避免对于项目士气的非必要相关损害。

当圣战不可避免时,尽早决定你要关注多少,并乐意公开放弃。当你这样做,你可以说你正在退出,这场圣战毫无价值,而不要展示出挖苦,并且不要利用这个机会对对方的辩论做最后一次攻击。只有优雅的去做才能有效的放弃。

编程语言的圣战有些特殊,因为虽然其本身的高技术性,然而很多人感觉自己有资格参与其中,因此结果可能取决于项目编码编写较好的部分的语言。最好的解决方案是尽早选定语言,由初始的有影响的开发者引入,根据你最舒服的语言,而不是因为其优于其他语言而使用。不要将对话退化为经典的编程语言比较(通常是当某人因为某些原因提出Perl。);那是死话题,你应该明确的拒绝涉及。

关于圣战的更多历史背景,可以看http://catb.org/~esr/jargon/html/H/holy-wars.html,Danny Cohen的论文普及了这个术语,http://www.ietf.org/rfc/ien/ien137.txt

“吵闹的少数派”效应

在所有的邮件列表讨论中,都有一些少数派不断用大量冗长的邮件血洗列表,给人存在大量异议的印象。有些像filibuster(一种议会程序,阻挠议案的通过),但是这种广泛异议的幻想更加强大,因为它分割了任意数量的不连续文章,大多数人无法跟踪何人在什么时间说了什么。他们会产生主题存在严重争议的直觉印象,并等着小题大做的平息。

中和这种效应的最好方法是明确指出并提供证据证明这种异议的数量与认可的数量相比是微不足道的。为了增大这种差距,你或许会希望私下调查大多数时候会保持沉默,但是你怀疑是认可大多数的人。不要说这些持异议者是故意夸大这种印象。他们一般不会是故意,即使故意,指出来也没有策略上的好处。你只需要指出双方实际数字的比较,人们就会认识到他们对于形势的直觉与现实不符。

这个建议并不是只能应用到具备明确支持和反对位置的问题。它可以应用到所有小题大做的问题上,但是如果大多数人认为讨论的问题不是一个问题时,则不是这么清楚。如果经过一段时间,你认为这个问题并不值得行动,并且看到它无法获得更多的吸引力(即使有了大量的邮件),你可以公开评论其没有吸引力。如果“吵闹的少数派”正在工作,你的文章就会像一缕清风。大多数人对于这个讨论的印象都会有一些阴郁:“好象是发生了一些大事,因为有很多文章,但是我看不出有什么进展。”通过解释讨论的形式使其显得比实际上更加吵闹,你给其新的面貌,人们可以重新修订自己对于发生问题的理解。

刺儿头

在电子论坛对付刺儿头并不比在现实中容易。这里“刺”不是“无礼”。无礼的人很讨厌,但不一定难对付。本书已经介绍了如何处理他们:在第一时间回复无礼行为,之后,选择忽略他们或者同其他人一样对待他们。如果他们继续无礼,他们会让自己更加不受欢迎,并在项目中毫无影响力,所以这是他们自己的问题。

真正的问题不是完全无礼的人,而是那些操弄或滥用项目进程,消耗他人时间和能量,而不会为项目带来任何利益的人。这些人经常会寻找项目规程中的楔点,而释放在其他地方无法获得的影响力。这比单纯的无礼更加狡猾,因为其导致的行为或损害都不是随意的观察者能够发现的。一个经典的案例是filibuster,某人会一直声称讨论的事情还没有准备好解决,并一直提供更多的解决方案,以及对旧方案的新视点,而实际上是他感到会达成共识或投票,而他可能无法保持领先。另一个例子是当一个辩论无法达成一致,但是团队尝试至少理清异议并为所有人制作一份以后可以参考的总结时。蓄意阻挠者知道总结会导向他不期望的结果,所以会通过反对合理的建议或引入意料之外的新条目来夸大问题的复杂性,试图延迟总结。

处理刺儿头

为了中和这种行为,我们需要理解从事这种行为的心理。人们并不是有意识的这样做。没有人会在早晨起床并对自己说:“今天,我会处理规程表单,从而成为恼人的蓄意阻挠者。”相反,这种行为经常是出于希望在项目互动和决策中发表意见的半偏执的情绪。有些人感觉自己没有被重视,或者(更严重的情况)认为存在一个针对自己的阴谋集团—其他项目成员决定成立一个排他的俱乐部,而他不是其成员。然后作为辩护,在他的思想中,认为按照字面意思遵循项目的规则,并参与到项目规程的正式处理中,从而让所有其他的人可以重视他。在极端的例子中,某些人甚至会认为自己正在为拯救项目而孤军奋战。

不是所有的人在同一时间可以看到这种攻击,某些人可能会完全看不到,除非提供了强有力的证据。这意味着中和它需要大量的工作。说服自己它的发生并不足够;你也需要配置足够的证据说服他人,并使用考虑周到的方法分发这些证据。

考虑到有大量的工作,最好不要容忍太长时间。考虑到它的寄生性,但只是温和的疾病:感染时并不会对项目造成过大的损害,药物反而可能有严重的副作用。然而,如果损害变得无法容忍,就应该采取行动。从收集见到的模式的记录开始。确保包含对公共归档的引用—这是项目保留这些记录的原因,所以你也可以利用它们。一旦建立了好的案例,开始与其他参与者的私下对话。不要告诉他们你所观察的;相反,首先要询问他们所观察的。这恐怕是你最后一次收集他人对于麻烦制造者行为未过滤反馈的机会;一旦你开始对此事的公开讨论,意见就会分化,没人会记得过去对于此事的想法。

如果私下讨论表明至少有其他人也发现了这个问题,则是时候行动了。你应当十分小心,因为很容易给这些人机会让你显得对他们不够公平。无论你做什么,不要指控他们因为偏执狂恶意滥用项目的规程,或者任何你怀疑他们的事情。你的策略是必须保持合理性和对于项目整体利益考虑,以改良个人的行为或使之离开作为目标。取决于其他开发者,以及你与他们的关系,首先在私下里获取同盟者是一个优势。或者如果不是;则只能会暗中的破坏,如果人们认为你正在从事一项不当的政治诽谤活动。

要牢记,尽管是另外一个人具有破坏性,但如果你不能支持你的公开指控,那么就会看起来是那个破坏者。请确保你拥有足够多的实例来描述你所说的,并在直接说出的情况下尽可能的保持礼貌。你可能无法说服有问题的人,但只要能说服所有其他人就足够了。

案例学习

我只记得一次,在10年的自由软件工作中,事情变得太坏,以至于我们必须要求某人停止发布文章。更常见的情况是,他并不是无礼,只是希望更有益。他只是不知道何时发布何时不发布。我们的邮件列表对公众公开,但是他发布的太频繁,在许多不同的主题中提出问题,成为了社区的噪音问题。我们已经和蔼的告诉他在发表文章前对文章多做一点研究,但是没有效果。

最终有效的策略是如何根据中立、定量的数据构建强大案例的完美案例。我们的一个开发者研究了一些归档,然后将如下信息私下发送给了一些开发者。冒犯者(在列表中的姓显示为“J. Random”)在项目中的历史不多,没有贡献任何代码或文档。然而他是邮件列表中第3活跃的用户:

From: "Brian W. Fitzpatrick" <fitz@collab.net>
To: [... recipient list omitted for anonymity ...]
Subject: The Subversion Energy Sink
Date: Wed, 12 Nov 2003 23:37:47 -0600

In the last 25 days, the top 6 posters to the svn [dev|users] list have
been:

    294  kfogel@collab.net
    236  "C. Michael Pilato" <cmpilato@collab.net>
    220  "J. Random" <jrandom@problematic-poster.com>
    176  Branko Čibej <brane@xbc.nu>
    130  Philip Martin <philip@codematters.co.uk>
    126  Ben Collins-Sussman <sussman@collab.net>

我可以说这些人中的5位会在不久的将来将Subversion带到1.0。

我也必须说我们中的一位也在消耗另外5人的时间和精力,更不用说整个
邮件列表,因而(虽非故意)也延缓了Subversion的开发。我没有做线索分析
但是通过vgrep我的Subversion邮件,我发现此人的每个邮件都会被上面5人中
的2人回复过。

我觉得有必要做一次根本的干预,即使我们会吓跑前面提到的这个人,和蔼
和友好的方法被证明没有效果。

dev@subversion是辅助进行版本库控制系统开发的邮件列表,而不是一个团队
心理治疗会议。

-Fitz,尝试从堆积了3天的svn邮件中费力前行

尽管一开始还不明显,但J. Random的行为是滥用项目规程的典型案例。他不会像filibuster一个表决那样明显,但是他利用了邮件列表中成员自我评审的政策。我们依赖每个个体的判断。因此,我们没有规程资源可以处理某人是否没有或没有练习这种判断。没有可以让某人指出并说某个家伙违反的规则,但每个人知道他过于频繁的文章已经成为一个严重问题。

Fitz的策略是专横的事后回想。他收集了定量的证据,然后谨慎的将其首先发送给那些在任何过激行动中都会对支持起关键作用的人。他们认可有必要采取行动,最后我们在电话上联系了J. Random,直接描述了这个问题,告知他停止发表文章。他从未真的理解原因;如果能够理解,他可能会尝试首先进行合适的判断练习。但是他认可停止发布文章,邮件列表又变得可用了。这个策略可以发挥作用的部分原因或许是我们可以限制其发表的隐含威胁,我们可以通过软件的审核功能来防止垃圾邮件(看第 3 章 技术基础设施“垃圾邮件防护”一节)。但是我们能够让该选择作为备用的原因是Fitz已经从关键人物那里收集了必要的支持。

处理成长

开源世界中成功的价值很重。随着你的软件的流行,搜寻信息的人也会急剧增加,而能够提供信息的人则增长的慢很多。此外,即使比率能够保持平衡,在大多数开源项目中处理交流也依然存在基础扩展问题。以邮件列表为例。大多数项目有一个一般用户问题的邮件列表—有时,列表的名称是“users”、“discuss”、“help”或其他。无论名称是什么,列表的目的相同:为人们获取问题的答案提供一个场所,同时其他人可以观看并通过观察这种交换(假设的)获取知识。

这种邮件列表可以在数千用户和每天几百文章的情况下工作良好。但之后不久,这个系统就会出现问题,因为每个订阅者看到的文章会超过单个订阅者每天可以处理的数量,这个列表成为了其成员的负担。想象一下,如果微软有一个针对Windows XP的邮件列表。Windows XP有数亿的用户,如果仅有千分之一的用户在24小时内有问题,那么这个假设的列表每天也会有数十万的文章!不可能有这种列表,因为不可能有人会一直订阅它。问题不仅仅限于邮件列表;同样的逻辑也可以应用到IRC频道,在线讨论论坛,以及所有从单个人获取问题的团队。其暗示并不吉利:大规模并行支持的普通开源模型不能扩展到支配全世界的级别。

当论坛达到临界点时并不会发生爆炸。只有一个静悄悄的负面反馈效果:人们会取消列表的订阅,或者离开IRC频道,或者不再去咨询问题,因为他们无法去听所有的噪音。因为有越来越多的人作出了理性的选择,论坛的活动会看起来一直处于可管理的级别。但是,它精确的处于可管理级别是因为理性的(或仅仅是有经验的)人会去寻找其他地方获取信息—而缺乏经验的人会留下来继续发表文章。换句话说,随着项目的成长,如果仍使用未扩展的交流模型,那就会产生询问和回答的平均质量逐渐下降的副作用,感觉就好象新用户比原来更呆了,但实际上并不是如此。只是高人口论坛的收益/花费比变得更低,自然那些有经验的人会开始在其他地方寻找答案。根据项目的成长调整交流机制包含两个相关的策略:

  1. 识别出论坛特定部分,甚至整个论坛正在经历有限制的增长,将这部分分割为新的更专业的论坛(也就是说不要让坏的拖累好的)。

  2. 确保有许多自动的信息来源,并组织有序、更新及时和易于查找。

策略(1)通常并不难。大多数项目有一个主要论坛开始:一个一般的讨论邮件列表,会包含所有的特性构想、设计问题和编码问题。项目的参与者都会在这个列表上。经过一段时间,整个列表就会很清晰的进化为基于不同主题的子列表。例如,一些线索很明显是关于开发和设计;而另外一些是诸如“如何完成X?”的用户问题;或许还有第三类关于如何处理bug报告和增强请求的主题;等等。对于每一个个体,或许会参与到许多不同的线索类型,但是这些类型之间没有过多的重叠。他们可以划分到不同的列表,而不会造成严重的割据问题,因为这些主题极少会跨越主题的边界。

实际上这种分割是两步骤的过程。你创建新的列表(或者IRC频道,或任何其他的东西),然后你要花必要的时间有礼貌的唠叨和提醒人们使用新的更合适的论坛。后一个步骤会持续几周,但是最终人们会明白。你只需对所有发送到错误目标的人解释这个问题,然后因为大家都看到得到,人们就会被鼓励例行公事一样去帮助解决。当然,提供一个所有列表的指南网页也非常有用;你的回复可以直接引用网页,然后作为奖励,接收者会在发表文章前通过指南学习到一些东西。

策略(2)是一个持续的过程,会伴随项目的一生,需要许多参与者。当然,它部分依赖于是否拥有及时的文档(第 2 章 起步“文档”一节),并能够指引人们去观看。但不仅仅如此;这个小节的后面会详细讨论这个策略。

归档的显著使用

通常来说,开源项目中的所有交流(除了一些IRC的对话)都应该归档。归档应该公开且可搜索,并要具备引用的稳定性:也就是一旦信息记录到了特定的地址,就可以永远使用这个地址。

尽可能多的使用那些归档,越显著越好。即使你知道某个问题的答案就在你的脑中,但如果你知道归档中有一个包含此答案的引用,那么请找到并展示出来。每次你使用公开可见的方式完成,有些人就会知道归档,并会在其中寻找答案。另外,通过引用归档而不是重写建议,可以加强对于复制信息的社会标准。为什么同一个答案会出现在不同的地方?当可以找到答案的地方还比较少,人们就更可能会记住地址并再次查找。精心放置的引用也可以帮助改进搜索结果的质量,因为他们可以加强目标资源在互联网搜索引擎中的权重。

当然有时复制信息也有意义。例如,在归档中已经有了一个来自别人的回应说:

看起来你的Scanley索引开始fronbnicated。为了unfrobnicate,可以按照如下步骤:

1. 关闭Scanley服务器。
2. 运行Scanley的'defrobnicate'程序。
3. 启动服务器。

然后,几个月之后,你看到另外一篇文章显示某人的索引变得frobnicated。你搜索归档并发现了上面这个较早的回复,但是你认识到它遗漏了一些步骤(或许是因为误解,也可能是因为软件在那篇文章之后发生了改变)。最经典的方式是发表一篇新文章,更完整的指导,并明确的废弃较早的那篇文章:

看起来你的Scanley索引已经变得frobnicated。我们在7月份看到过这个问
题,而且J. Random在http://blahblahblah/blah发布过一个解决办法。下面
是根据J. Random的指导unfrobnicate你的索引的方法,有一些扩展:

1. 关闭Scanley服务器。
2. 成为通常运行Scanley服务器的用户。
3. 作为该用户,在索引上运行'defrobnicate'程序。
4. 手工运行Scanley,并查看索引是否工作。
5. 重启服务器。

(在理想的世界,可以为原来的文章附加一个注释,说明有较新的信息,并指向新文章。然而,我不知道有什么归档软件支持“废弃”特性,或许因为在不违反归档逐条的归档完整性的情况下实现有一点狡猾。这是设置一个专门的网页回答常见问题的另一个原因。)

归档可能经常被用来查找技术问题的答案,但是他们对于项目的重要性不仅如此。如果说项目的正式指南的法定法律,那么归档就是不成文法:所有决策如何制定和如何得出的记录。对于任何重现的讨论,从归档搜索开始是义不容辞的。这允许你从当前状态、期望的目标、举反证和发现你没有想到立场的摘要开始讨论。另外,其他参与者会期望你已经做了归档搜索。即使之前的讨论没有结果,在你重新提出这个主题时也要指出它们,这样人们就可以自己看到a) 讨论没有结果,并且b) 你做了功课,那么现在说一些没说过的话吧。

将所有的资源视为归档

之前的所有建议不只是能应用到邮件列表归档。零散的信息都位于稳定,便利和可查询的地址,这必须成为项目所有信息的组织原则。我们以项目FAQ为例进行研究。

人们如何使用FAQ?

  1. 他们希望在其中查找特定的单词和短语。

  2. 他们希望进行浏览,获取信息,而不是去寻找特定问题的答案。

  3. 他们希望诸如Google之类的搜索引擎可以知道FAQ的内容,所以可以搜索到FAQ条目。

  4. 他们希望在FAQ中直接为其他人提供特定项目的引用。

  5. 他们希望为FAQ提供新的材料,但是注意到添加比查询回答要少许多—FAQ更多的是阅读,而不是编写。

第1点暗示我们FAQ一定要以文本格式存在。第2和第3点暗示FAQ应当以HTML格式存在,第2点也说明HTML必须针对可读性进行设计(即你会希望控制起观感),而且必须有目录。第4点意味着FAQ的每个条目都赋予了一个HTML命名的Anchor,一个用户可以到达页面特定位置的标记。第5点说明FAQ的源文件必须用便利的方法存在(见第 3 章 技术基础设施“版本化所有的东西”一节),并使用易于编辑的格式。

格式化FAQ只是如何让一个资源可以展示出来的例子。同样的属性—直接的咳嗽索性、主要搜索引擎的存在性、可浏览性、引用稳定性和(合适的地方)可编辑性—可以应用到其他网页、源代码树和bug跟踪系统等等。只是在不久之前大多数邮件列表归档软件才认识到了这些属性的重要性,也是邮件列表倾向于本身具备这些功能的原因,其他格式或许需要维护者花费更多的经历(第 8 章 管理志愿者讨论了如何在多个志愿者间分担负担)。

编制法律的传统

随着项目的日积月累和复杂化,每个新来的参与者必须吸收的数据量大增。那些伴随项目很长时间的人能够根据以前的经历认识到和发明项目的习俗。他们会本能的意识到积累了大量传统,并会为新来者的大量过失而感到惊讶。当然,问题不是新来者的质量降低了;而因为他们面对的是比以前更多的积累负担。

一个项目积累的传统取决于他们交流和保存信息的方法,以及他们的编码标准和其他技术备忘录。我们已经看了两种标准,分别在第 2 章 起步“开发者文档”一节第 4 章 社会和政治的基础架构“写下所有的内容”一节,也都有各自的例子。本小节关注的是如何在项目进化中保持指南的及时性,特别是关于如何管理交流的指南,因为这些指南会随着项目规模和复杂性的成长发生最显著的变化。

首先,关注人们陷入混淆的模式。如果你看到同样的情形屡次发生,特别是发生在新参与者身上时,就是需要记录指南的机会了。其次,不要厌烦反复说同样的话,也不要表现出对说这些话的厌烦。你和其他项目老兵都需要经常的重复自己;这是新手到来时不可避免的副作用。

每个网页、每个邮件列表信息和每个IRC频道必须考虑广告空间—不是商业广告,而是自己项目资源的广告。你所放置的内容取决于会观看它的人口统计数据。一个针对用户问题的IRC频道,其中通常是那些从未与项目交互的人—通常是只安装了软件,需要立刻获得问题答案的人(毕竟,如果他们可以等待,他们可以发送到邮件列表,整体上他将会花费较少的时间,尽管那样会需要更长的时间得到回答)。人们通常不会在IRC频道作出永久投资,他们会露面,询问问题,然后离开。

因而,频道的主题必须针对那些希望立刻寻找软件技术回答的人,而对那些以长期方式参与项目的人,社区交流指南或许更合适。下面是真正忙碌频道的处理方式(第 3 章 技术基础设施“IRC / 实时聊天系统”一节):

你现在位于#linuxhelp

关于#linuxhelp的主题请阅读
http://www.catb.org/~esr/faqs/smart-questions.html &&
http://www.tldp.org/docs.html#howto 询问问题之前 | 频道规则
在http://www.nerdfest.org/lh_rules.html | 升级到内核2.6.x
请看 http://kerneltrap.org/node/view/799 
 | 内存读可能性: http://tinyurl.com/4s6mc ->
更新到2.6.8.1或2.4.27 | 哈希算法灾难: http://tinyurl.com/6w8rf
| reiser4放出

在邮件列表中,“广告空间”是追加在每封邮件后的小注脚。大多数项目会在这里放置订阅/取消订阅的指导,也可能是项目主页或FAQ的链接。你或许会认为所有订阅列表的人都会知道如何做,很可能是—但是会有更多不是订阅者的人会看到邮件列表信息。一个归档的文章会被链接到许多地方;实际上,某些文章最终会变得家喻户晓,有远多于列表订阅者的阅读者。

格式化可以产生明显的区别。例如,在Subversion项目,我们在第 3 章 技术基础设施“Bug跟踪的预过滤”一节中描述的使用bug过滤技术,取得了有限的成功。经验不足的人会一直发起许多虚假的bug报告,每当发生这种情况,档案管理员必须像他之前的500人那样对此有足够的认识。某天,我们的某个开发者终于忍无可忍,对那些不阅读问题跟踪系统指南的倒霉用户开始发火,另一个开发者则决定这种情况不应该再发生了。他建议重新调整问题跟踪首页的布局,这样最要的部分,也就是在提交之前必须在邮件列表中讨论bug的命令,将会使用较大和粗体红色字体,亮黄色背景,页面居中突出显示处理。我们这样做了(你可以在http://subversion.tigris.org/project_issues.html看到结果),结果是虚假问题的录入率大大降低。我们依然会得到虚假的问题,当然—我们一直会—但是比例显著降低,甚至是在用户数大增的情况下。结果不仅是bug数据库中的垃圾大大减少,而且那些响应问题的人也得到了好情绪,也就更容易在面对罕见的虚假bug时保持友好。这样不仅改善了项目的形象,也改善了志愿者的心理健康。

仅仅是写出指导方针的课程对于我们来说还远远不够。我们也必须让最需要的人看到这些东西,它们的状态要像介绍材料一样格式化处理,这样对项目不熟悉的人们也可以立刻清晰明了。

静态网页不是发布项目习惯唯一的维纳斯。一定数量的的交互政策(友情提示的感觉,而不是冷冰冰的手铐脚镣)也是必需的。所有的同级评审,甚至第 2 章 起步“实践明显的代码评审”一节描述的提交评审,都应该包括对于人们是否遵守项目规范的检查,特别是与交流习惯相关的。

Subversion项目的另一个例子:我们在版本控制版本库设定了“r12908”表示“修订版本12908”的习惯。小写的“r”前缀很容易输入,又因为它只有数字的一半高度,所以与数字在一起时非常易于识别。当然,设定了习惯并不意味着每个人都会一直以正确的方式使用它。因而,每当有这样包含日志信息的提交邮件时:

------------------------------------------------------------------------
r12908 | qsimon | 2005-02-02 14:15:06 -0600 (Wed, 02 Feb 2005) | 4 lines

Patch from J. Random Contributor <jrcontrib@gmail.com>

* trunk/contrib/client-side/psvn/psvn.el:
  Fixed some typos from revision 12828.
------------------------------------------------------------------------

...某些提交评审者就会说“顺便说一句,请使用‘r12828’,而不是修订版本(revision)12828引用过去的变更。这不是卖弄学问;重要的是自动解析和人类阅读。

通过遵循一般的原理,包括对常见实体的权威参考方法,以及必须放之四海皆准参考方法,这个项目输出特定的标准。这些标准使得人们可以编写工具用更有价值的方式展现项目交流—例如,一个格式为“r12828”的修订版本可以在版本库浏览工具中被转化为可用的链接。但是如果修订版本写成“revision 12828”,则这项工作将会难许多,一方面因为链接会在换行处分隔,另一方面也因为限制不足(单词“revision”会经常单独出现,一组数字也会单独出现,而他们的组合“r12828”则只意味着修订版本号码)。类似的,同样的关注面也适应于问题号码,FAQ项目(提示:在命名的Anchor和ID属性描述的,使用命名锚点的URL)等等。

即使对于没有简短和权威形式的实体,也要鼓励人们提供一致的关键细节信息。例如,当引用到一个邮件列表信息时,不要只给出发送者和主题;请也给出归档URL信息的ID头。这样可以让那些虽然自己也有邮件列表拷贝(人们有时会保存离线备份,例如在旅行中使用笔记本时)的人,能够明确无误的定位到正确的信息,甚至无须访问他们自己的归档。发送者和主题并不足够,因为一天里同一个人可能为某一个线索发表过许多文章。

项目愈大,愈是需要这类一致性。一致性意味着人们会在所有的地方,看到被以相同的方式遵循的模式,这样他们知道自己也需要遵循这些模式。作为回报,减少了回答问题的必要。拥有几百万读者的负担并不比仅仅一个更大;扩展性的问题源于一定比例的读者开始提问了。随着项目的成长,必须依靠增加信息的密度和可访问性,才能减少这种比例,这样人们才能更容易的找到答案,而无需提问。

Bug跟踪系统中无对话

对于积极使用bug跟踪系统的项目,要小心它变成讨论论坛,虽然邮件列表可能更好。通常情况下,它总是很无辜的开始的:某人评论了某个问题,例如提出了一个解决方案或部分补丁。另一个人注意到这个,认为这个方案有些问题,所以附加了另一个评论指出这个问题。第一个人再次回应,对问题作出补充,就这样一直继续下去。

这样做的问题是,首先,bug跟踪系统用于讨论时非常的笨拙,其次,其他人可能不会投入关注—毕竟,他们希望在邮件列表中进行开发讨论,这也是他们查找问题的地方。他们可能没有订阅问题变更列表,即使订阅了,也不可能紧跟所有的变化。

但是这个过程中到底何时出了差错?是不是那个人将自己的解决方案附加到问题时—她是不是应该发布到列表中?或者是当第二个人直接回复这个问题,而不是在列表回复时。

这里没有正确的答案,但是有一般的原理:如果你仅仅是为问题添加数据,那么请在跟踪系统中操作,但是如果你想发起一次对话,那么请到邮件列表。不是每次都能判断出是哪种情况,但是你要作出最佳的判断。例如,当你提交的补丁会包含反对的解决方案时,你应当会预期有人会对此发出质疑。所以,即使你会自然的为该问题附加这个补丁(假定你不希望或者不能直接提交修改),也应当选择将其发布到邮件列表。有一定的可能性,整个交流最终会有得出结果,某一方可能会说应该不仅仅是追加数据,而应该开始一场讨论了—在本小节开头的例子中,也就是第二个回复者,他认识到了补丁的问题,预测到将会有真实的交流发生,因而应该通过更合适的媒介完成。

用数学模拟来说,如果根据信息显示问题将会很快收敛,那么直接在bug跟踪系统中发布;如果看起来将会发散,那么邮件列表或IRC频道将会是更好的地方。

并不是说在bug跟踪系统中不能有任何交流。例如,向原报告者询问重现的步骤细节就一般是一个很容易收敛的过程。人们的回应并不是提出新的问题,而仅仅是澄清已经记录的问题。没有必要分散邮件列表的注意力;并不一定要通过小心跟踪系统中一系列的评论实现。同样的,如果你认为这个bug是误报的(例如,根本就不是一个bug),你只需要在问题中说出来。甚至指出解决方案中的些许缺陷也没有问题,只要该缺陷不会影响整个解决方案。

另一方面,如果你会在bug的范围或软件正确行为方式方面,指出哲学问题,你肯定会认为将有其他开发者参与。讨论也许会发散一段时间,那么请在邮件列表中完成。

如果选择了邮件列表,就一直要在问题中保存到邮件列表讨论的链接。对于查看问题的人,能看到对应的讨论是非常重要的,即使问题本身不是讨论的场所。发起这个线索的人会发现有点牵强,但是开源从根本上说就是一种撰写-回应的文化:让成千上万的人读起bug来更容易,远比三五个编写者的麻烦重要的多。

如果可以让读者更便利,可以将重要的结论或总结从邮件列表中粘贴到问题中。一个常见的习俗是开始一个列表讨论,在问题中附加讨论线索的链接,然后是讨论结束的时间,粘贴最终的总结(以及包含总结信息的链接),这样浏览此问题的人就可以轻松的看到已经得出的结论,而无需点击到其他地方。需要注意的是,这里不存在重复数据的问题,因为归档和问题回复都是通常是静态的,不会改变的数据。

公开性

在自由软件中,在纯内部讨论和公开联系声明之间通常有一个相对平滑的连接。这部分因为目标读者一直不明:因为大多数文章都是公开可访问的,项目无法控制整个世界对此的印象。某人—假设是slashdot.org的一个编辑—可能为谋篇文章带来几百万的读者,而本来没人认为它会被项目之外的人看到。这就是开源项目生活的世界,但是在实践中,这种风险通常很小。通常情况下,项目希望公开化的声明就会得到最大的公开化,只要你能用正确的机制指出其对外部世界的新闻价值。

对于主要的声明,通常会有4或5个主要分发渠道,所有的声明最好尽可能同时发出:

  1. 你的项目主页可能是项目中被看得最多的页面。如果你确实有主声明,请在此放一个夸张的广告。这个广告一定是一个简短的概要,可以链接到有更多信息的新闻稿。

  2. 同一时间,你的站点一定也要有一个“新闻”或“新闻发布”区,可以详细写明声明。新闻稿的部分目的是提供一个单独的权威“声明对象”,这样别的站点可以用来链接,所以要以此为依据确保其结构:要么每个发布一个网页,或每个是一个博客条目,要么其他种类可以被链接的实体,同时与同一区域的其他新闻稿区分开来。

  3. 如果你的项目有RSS供稿(见“RSS供稿”一节),请确保声明也会出现在这里。这也可能在你创建新闻稿时自动发生,取决于你是如何设置的站点。

  4. 如果声明是软件的新版本,请更新http://freshmeat.net/中的项目条目(关于首次创建条目请看“通告”一节)。每当你更新Freshmeat条目时,该条目就会出现在Freshmeat当日的变更列表中。这个变更列表不仅仅会在Freshmeat本身更新,也会出现在许多被很多人关注的门户站点(包括http://slashdot.org)上。Freshmeat也会通过供稿提供相同的数据,所以即使那些没有订阅你的项目供稿的人,也会通过Freshmeat看到声明。

  5. 向你的项目声明邮件列表发送一个邮件。这个列表的名称应当是“announce”,例如announce@yourprojectdomain.org,因为现在这已经成为了标准的习惯,而且列表的管理者一定要说明该列表的内容很少,仅用于主要的项目声明。大多数此类声明都是关于软件的新版本,但是偶尔也会其他事件,例如本章后面说的募集资金激励,发现安全漏洞(见“声明安全漏洞”一节),或者项目方向的重大转移,也会发布到这里。因为内容很少,只用于重大事件,所以announce列表通常是项目中订阅最多的列表(当然,这意味着你不要滥用它—发布之前一定要小心)。为了防止其他人,甚至是垃圾邮件发出声明,announce列表应该一直需要审核。

要力争在所有的三个地方同时作出声明,越接近越好。人们在邮件列表中看到声明,而在主页或新闻发布区上没有对应的内容时就会感到困惑。如果你能将各方面的(邮件、网页等等)修改排队,并依次发出,你可以将这种时间差控制到最小。

对于不太重要的事件,你可以省略上面的某个发布出口。根据事件的重要程度,该事件还是会被外部世界注意到。例如,软件的一个新版本是主要事件,而设定下一次发布的日期,即使有些新闻价值,也不会比发布本身更重要。设定日期值得我们在日常邮件列表(而不是声明列表)中发一个邮件,以及更新项目时间线或网页状态,但仅此而已。

然而,你还是会在网上的其他地方的讨论中看到日期。在你的列表中的潜伏者仅仅会听,而不会说任何事,并不一定在其他地方也是沉默的。口碑会造成广泛的传播;你必须考虑到这一点,使用这种方式构建更小的声明,鼓励信息传递的精确性。特别的,你期望引用文章一定要在明确的在引用部分出现,就像你在写正式的新闻稿。例如:

仅仅是进度更新:我们计划在2005年8月中旬发布Scanley的2.0版本。你可以检查http://www.scanley.org/status.html的更新。新特性是正则表达式搜索。

其他特性包括: ...也会包含其他bug修正,包括 ...

第一段很简短,仅提供了最重要的信息(发布日期和主要新特性),以及访问进一步新闻的URL。如果某人的屏幕仅出现这个段落,也完成的足够好了。邮件的余下部分可以省略,不会损失内容的要点。当然,有时人们会链接整个邮件,但是更常见的,他们只会引用一小部分。假设后一种的可能性,你所做的也让他们的工作更容易,此外也因为所引用的内容获得了更多的影响力。

声明安全漏洞

安全漏洞的处理与其他类型bug报告有所不同。在自由软件中,公开透明的工作方式通常几乎是宗教信条。只要你愿意,标准bug处理过程的每个步骤都是可见的:最初到来的报告,实现确认的讨论以及最终的修正。

安全bug则有些不同。它们会危及用户数据,甚至是用户的整个电脑。如果公开讨论这个问题,就是将其公示天下—包括那些会恶意利用这个bug的人。甚至仅仅是有效率的提交一个修正宣布bug的存在(会有潜在的攻击者看到公开项目的提交日志,有系统的查找变更,以便在以前的代码中获取安全问题)。大多数开源项目都为公开性和秘密性的冲突准备了相同的处理步骤,基于如下的基本指导方针:

  1. 在发现修正之前,不要公开谈论bug;然后在宣布bug的同时立刻提供修正。

  2. 尽可能迅速的完成修正—特别是如果项目外的某人报告了这个bug,因此你知道至少有一个项目外的人能够破解这个漏洞时。

在实践中,那些原理会导致一系列标准化的步骤,将会在下面的小节描述。

接收报告

很明显,人们需要从任何人那里接收安全报告的能力。但是不能用常规的bug报告地址,因为那样所有人都会看到。因此,可以设定一个接收安全bug报告的邮件列表。这个邮件列表一定不要有公共可读的归档,而且必须严格控制其订阅权—只有长期可信的开发者可以在列表上。如果你需要为“可信的”作出正式的定义,可以规定为“所有提交过两年及以上的人”,或类似的,避免偏袒。这将会是处理安全bug的团队。

理想状态下,安全列表不应该是垃圾保护的或需要经过审核的,因为你不会希望仅仅因为在周末没有审核者而造成重要的报告被过滤掉或者被延迟。如果你使用自动垃圾邮件保护软件,可以尝试使用较高的容忍设置;允许部分垃圾邮件通过总比漏掉一个报告要好。当然,为了列表的效率,你应当将列表的地址广而告之;但是因为它没有审核,或者只有轻微的防垃圾设置,一定要确保要有邮件地址隐藏的变化,就像第 3 章 技术基础设施“归档中的地址隐藏”一节所说的。幸运的是,地址隐藏不需要将地址变的难以识别;举个例子,可以看http://subversion.tigris.org/security.html,以及该网页的HTML源代码。

默默的开发修正

当接收到报告时,在安全列表上要怎么做?首要任务是评估问题的严重性和紧急性。

  1. 漏洞很严重吗?它会造成使用该软件的计算机被恶意攻击接管吗?或者说,是否仅仅会泄漏他们文件大小的信息吗?

  2. 破解这个漏洞很简单吗?攻击可以脚本化,还是需要环境相关的知识、有意识的猜测甚至运气?

  3. 向你报告了这个问题?当然,这个问题的答案不会改变漏洞的本性,但你可以以此判断有多少人了解此事。如果报告来自于项目自己的开发者,你可以松一口气了(也就一口),因为你可以相信他们不会告诉别人。另一方面,如果是来自类似anonymous14@globalhackerz.net的邮件,你最好立即行动。尽管这个好人提醒了你,但你无法知晓她告诉了多少人,或者她还会等多少时间去破解正式安装系统中的这个漏洞。

请注意,我们这里讨论的范围仅仅是紧急极端 紧急之间。即使报告来自于一个已知的、友好的来源,网上的其他人也可能早就发现了这个bug,只是没有报告。唯一不紧急的情况是,bug在本性上不会严重的影响安全。

另外,“anonymous14@globalhackerz.net”的例子并不可笑。你可能真的会从隐形身份的人那里得到bug报告,根据他们的词汇和行为,你无法判断他们是否站在你一边。这没有关系:如果他们向你报告了安全漏洞,他们会觉得理应得到好的回报,你应当友好的回应。感谢他们的报告,给他们一个发布修正的时间或截止时间,并与他们保持联系。有时,他们会给一个日期—那是将在该日期公布bug的威胁的暗示,无论当时你是否已经准备妥当。这看起来像是一种权利的欺凌游戏,但是更像是一种预先的免疫行动,因为之前有对许多令人失望的迟钝的软件制造者,没有将安全报告认真对待。无论如何,你不能对他视而不见,毕竟,如果bug很严重,他拥有的知识会给你带来很大的麻烦。友好的对待这种报告者,希望他们也能投桃报李。

另一个安全bug的常见报告者是安全专家,一些长期审核代码并钻研软件漏洞的人。这些人通常精通两个领域—他们不仅会接收,也会发送报告,可能比你项目的大多数开发者都多。他们也通常会为修正某个漏洞设定公布于众的截止日期。截止日期也许可以讨价还价,但是这取决于报告者;截止日期已经成为安全专家唯一认可可靠方法,可以让组织迅速的定位安全问题。所以,不要认为截止日期很野蛮,这是久经考验的传统,这样做有足够的理由。

当你知道了严重性和紧急性,你就可以开始修正了。有时,需要在优雅和速度之间做出权衡;这也是为什么在开始前要首先确认紧急性。当然,也要保证讨论仅限于安全列表用户,原始的报告者(如果她希望加入),以及所有因技术原因必须参与的人之间。

不要提交修正到版本库。在公开之前,请一直用补丁的形式。如果你准备提交,即使采用了无辜的日志信息,也会让某些人注意到并理解此变更。你永远无法知道谁在关注你的版本库,以及他们感兴趣的原因。关闭提交邮件可能会有些用;但是毕竟提交邮件序列本身会让人起疑,而且数据已经进入了版本库。只应该以补丁的形式完成所有的开发,并保持补丁在私密的地方,也可以是一个单独的独立版本库,只有知晓此bug的人能够知道。 (如果你使用分布式的版本控制系统,例如Arch或SVK,你可以在完全版本控制下完成这个工作,只需要保证外来者无法访问此版本库。)

CAN/CVE号码

你或许看到过随安全问题出现的CAN号码CVE号码。例如看起来类似“CAN-2004-0397”或“CVE-2002-0092”。

两种号码都代表了相同类型的实体:在http://cve.mitre.org/上维护的“常见漏洞和曝光”列表中的一个条目。这个列表的目的为所有已知的安全问题提供标准化的名称,这样每个人都可以在讨论时使用唯一的标准化的名称,并提供一个可以查找更多信息的中心地点。 “CAN”和“CVE”的唯一区别是前者代表了候选条目,还未经CVE编辑委员会认可,而后者则是经过认可的条目。 然后,两种类型的条目都对公众可见,条目的编号不会随着认可而改变—仅仅是“CAN”前缀替换成了“CVE”。

CAN/CVE条目本身并不包含bug的完整描述,以及如何防范的信息。相反,它只会包含一个简短的摘要,然后是到参考和外部资源的列表(例如邮件列表归档),人们可以去查看详细信息。http://cve.mitre.org/的真正目的是提供一个组织良好的空间,每个漏洞都可以有一个名称以及获取更多信息的途径。一个条目的例子可以看http://cve.mitre.org/cgi-bin/cvename.cgi?name=2002-0092。请注意,引用可以非常的简洁,其中的来源表现为神秘的缩写。这些缩写的关键点可以看http://cve.mitre.org/data/refs/refkey.html

如果你的漏洞达到了CVE的标准,你或许会希望得到一个CAN号码。这个过程是故意封闭的:一般来说,你需要认识某人,或认识某人认识某人。这并不是表面上的那么疯狂。为了避免被伪造的或编写糟糕的提交压垮,CVE编辑委员会只从已知和信任的来源获取提交。然而,为了获取你的漏洞列表,你需要从你的项目找一个CVE编辑委员会认识的人。在你的开发者中询问一下是否认识某人之前曾经完成过CAN过程,或知道某人会认识。这样做的好处是该链路上的某处,某人会知道足够的信息告诉你 a) 根据MITRE的标准,它不会作为漏洞或曝光,所以没有提交的意义,或者 b) 这个漏洞已经有了CAN或CVE号码。后者可能是因为该bug已经在另一个安全忠告列表上发布了,例如位于http://www.cert.org/或者位于http://www.securityfocus.com/的BugTraq邮件列表。 (如果是在你的项目对此一无所知的情况下发生了这种情况,你一定会担心还有什么不知道的。)

如果你已经得到了CAN/CVE号码,你一定希望尽早将其纳入bug研究中来,这样以后的所有交流都可以引用这个号码。在公布之前,CAN条目会被禁止访问;这个条目会作为占位符保持(这样就不会丢失名称),但不会揭示任何漏洞信息,直到你宣布此bug并修正了它。

关于CAN/CVE流程的更多信息可以查看http://cve.mitre.org/about/candidates.html,一个开源项目中使用CAN/CVE号码的例子可以看http://www.debian.org/security/cve-compatibility

预通知

一旦你的安全响应团队(那些在安全邮件列表上的开发者,或者那些你认为应该加入到解决特定报告的人)准备好了修正,你就要决定如何描述它。

如果仅仅是提交你们的修正到版本库,或者是向全世界宣布,所有使用该软件的人就必须立刻升级,否则就要经受被攻击的风险。有时,更应该对某些特别重要的用户进行预提醒。对于客户端/服务器软件这一点尤其重要,因为也许某些用户的服务器是攻击的诱人目标。那些服务器的管理员也许会对提前一两天进行升级而感到感激,这样他们就可以在破解出现在公众之前做好保护。

预提醒的意思是在公布之前向那些管理员发送邮件,告诉他们这些漏洞以及如何修正。一定要确保只向你相信会保守秘密的人发送预提醒。也就是,接收预提醒的资格包括两重意思:接收者一定是在运营一个大的,重要的服务器,影响重大,而且这些接收者也一定不会在公开之前到处乱说这个安全问题。

向每个接收者单独(每次一个)发送预提醒邮件。不要一次向整个列表的接收者发送,因为他们会看到其他人的名字—那样意味着告诉了每个接收者他们的服务器有安全漏洞。完全通过暗送(BCC)也不是好方法,因为某些管理员使用垃圾过滤会屏蔽或减少BCC邮件的等级,因为现在有太多使用BCC发送的垃圾邮件。

以下是一个预提醒邮件:

From: 你的名字
To: admin@large-famous-server.com
Reply-to: 你的名字(不要用安全列表地址)
Subject: 重要Scanley漏洞提醒。


这个邮件是Scanley服务器安全警告的重要预提醒。

不要向任何人转发本邮件。公共声明将会在3月19日发布,我们很希望在此
之前能够保密此信息。

您收到此邮件是因为(我们认为)您运行了Scanley服务器,并希望在19号公
布此安全漏洞之前做好补丁。
参考:
===========

   CAN-2004-1771: Scanley查询堆栈溢出漏洞:
==============

   如果服务器的locale设置配置错误,而且客户端发送了不合法的查询,会导
   致可以运行任何命令。

严重程度:
=========

   非常严重,可以导致服务器上任意代码的执行。

周边工作:
============

   在scanley.conf中将'natural-language-processing'选项设置为'off',可以关闭
   这个漏洞。

补丁:
======

   以下补丁适应于Scanley 3.0、3.1和3.2。

   一个新的公共版本(Scanley 3.2.1)将会在3月19日发布,同时该漏洞也会
   公开。你可以现在打补丁,或者等待公开版本。3.2与3.2.1的唯一区别将是此
   补丁。

[...补丁在这里...]

如果你有CAN号码,即使该信息依然是保密的,它的MITRE页面没有任何内容,也请在预提醒中提供(上面例子中显示的)。包含CAN号码允许接收者可以知晓自己被预提醒的bug正是他们将来可能通过公共渠道获知的bug,这样他们就不必为是否要采取进一步的行动而感到担心,关键点就是CAN/CVE号码。

公开分发修正

处理安全bug的最后一步是公开分发修订。在一个单独的完整的声明中,你需要描述该问题,如果有CAN/CVE号码,也要提供,描述工作的背景,以及如何永久修正。通常情况下,“修正”意味着将软件升级到新版本,有时也可能是应用一个补丁,特别是如果你的软件以源代码形式运行时。如果你要发布新版本,一定要确保是与现有的某个版本的区别就是安全补丁。使用此方法,保守的管理员就可以作出升级,无需担心会影响其他的功能;他们也不必担心将来的升级,因为安全补丁将会理所当然的出现在未来版本中。(关于发布的详细信息可以看第 7 章 打包、发布和日常开发“安全发布”一节。)

无论公开修正是否包含了新的版本,不要像发布新版本那样粗糙:在项目声明列表中发送一封邮件,发布一个新的新闻稿,更新Freshmeat条目等等。你不应该因为项目的名誉,而试图减弱安全bug的存在性,你应当确立与安全声明问题的严重程度相匹配的基调和突出程度。如果安全漏洞仅仅是轻微的信息暴露,而不会导致用户攻克整个计算机,无需大惊小怪。你甚至会觉得无需为此分散声明列表的注意力。毕竟,如果项目每次都喊狼来了,用户会误以为软件很不安全,而且会在真的有大问题要宣布时不相信你。关于判断严重性的更好的介绍可以看http://cve.mitre.org/about/terminology.html

一般情况下,如果你对如何处理安全问题并不确定,可以找某个更有经验的人讨论一下。评估和处理漏洞更像是一种学习得到的技巧,一开始很容易误入歧途。



[22] 关于这个主题有许多有趣的学术研究;例如Gutwin、Penner和Schneider所著的Group Awareness in Distributed Software Development。这篇论文曾经在网上出现过一段时间,之后消失,后来又在http://www.st.cs.uni-sb.de/edu/empirical-se/2006/PDFs/gutwin04.pdf再次出现。所以,如果这个地址无法访问,请通过搜索引擎搜索新地址。

第 7 章 打包、发布和日常开发

本章关于自由软件项目如何打包和发布软件,以及如何让整个开发模式的组织围绕这个目标。

开源项目和私有项目的主要区别是缺乏对开发团队的中央管理。当准备新版本时,这个区别尤其明显:一个公司可以让整个开发团队集中精力在即将发生的版本上,而将新特性开发和不重要的bug修正放在一边。志愿团队不会如此整齐划一。人们因为各种各样的原因为项目工作,总有些人会对发布版本不感兴趣,会希望在发布时继续常规的开发工作。因为开发不会结束,开源的发布流程很容易变长,但不会如商业发布流程那样分裂。这就像修理高速路。有两种修理方法:你可以将其完全关闭,这样船员们可以全力投入,直到问题被解决,或者你可以在多个小道上同时工作,而让其他人可以自由通行。第一种方法对修理船员非常有效率,但对于其他人来说—完成任务前道路被完全关闭。第二种方法,修理船员(现在他们需要与较少)会需要更长的时间,但至少道路保持可用,尽管不能完全畅通。

开源项目通常会使用第二种方法。实际上,对于同时拥有多条版本线的成熟软件,项目一直处于修理小路的状态。总会有些小道会被关闭;一直存在的但是较低级别的不便能够被整个开发团队容忍,所以才能够有规律的计划发布版本。

这个模型不仅仅能用于版本发布。其原理是并行任务并不是互相依赖的—这并不是只存在于开源项目的原理,但开源项目使用了自己的方法实现了它。他们不能承受对修路工队员或常规交通的过度打扰,同样也不能承受让人们只是站在黄线以外,等待交通疏导。因而,他们会向平缓的、稳定管理负担的过程发展,而不会是充满更多的山谷和高峰。志愿者通常会希望工作中只有一些虽然持续但不太严重的不便;提供些许他们可预测性会让他们可以自由的安排自己的日程,无需担心在项目中发生冲突。但是,如果项目主日程中有些活动会排除其他活动,就会导致很多开发者停止很长时间—不仅非常没有效率,也非常无聊,因而会很危险,因为无聊的开发者会很快变成前开发者。

版本发布工作实际上是并行开发中最容易被注意到的非开发任务,所以下面章节中描述的方法主要针对如何允许发布。然而,也有其他的并行任务,例如翻译和国际化、在整个代码的基础上逐渐扩大API变更等。

版本号

在我们讨论如何发布之前,首先看一下如何命名版本,用户需要从版本中知道什么。一个版本发布意味着:

  • 老的bug被修正了。恐怕所有的用户都认为每个版本都理所当然应该做到这一点。

  • 会带来新bug。一般情况下这是必然的,除非是安全版本或其他特殊情况(见本章后面“安全发布”一节)。

  • 也加入了新的特性。

  • 新配置选项也会被添加,或者一些以前的选项有了微妙的变化。和上个版本相比,安装步骤可能有轻微的调整,即使人们不希望这样。

  • 也可能带来不兼容的变化,例如以前版本的软件所用的数据格式必须做出某种(可能是手工的)单向的转化,才能继续使用。

就像你看到的,发生的不都是好事。这就是为什么经验丰富的用户总是对新版本保持恐惧,特别是当软件已经足够成熟,已经能够满足他们的需要时(或者认为他们满足了)。即使新特性是好坏参半的事情,也意味着软件现在可能以不可预期的方式运行。

因此发布版本编号的目的是双重的:很明显这个编号可以在交流中明确发布的顺序(例如,通过比较两个版本号,你可以看出哪个版本更老),另一方面,也应该尽可能紧凑的表明该发布所带来变更的程度和性质。

仅仅是号码吗?或多或少是。版本编号策略是最古老的自行车库讨论(见第 6 章 交流“主题越软,辩论越长”一节),这个世界也似乎从来没有能达成一个单独的完整的标准。然而,还是出现了一些好的策略,依据了一些广泛认同的原理:一致性。采取一种编号方式,记录下来,并坚持使用。你的用户会感激不尽。

版本号组成部分

本小节详细描述了一些发布版本号的正式惯例,认为是已知的预先知识。目的仅仅是作为一个参考。如果你已经了解了这些惯例,你可以跳过本小节。

发布号码是一组点分割的数字:

Scanley 2.3
Singer 5.11.4

...等等。这些点不是小数点,而仅仅是分隔符;“5.3.9”之后将会是“5.3.10”。某些项目偶尔也会用其他的提示,例如非常有名的Linux内核,在Linux 1.0之前使用的是“0.95”、“0.96”... “0.99”,但是这种点号成为了固有的习惯,已经被认为是一种标准。数字部分(不包含点的数字部分)的数量没有限制,但是大多数项目不应该超过3或4。在后面我们会对原因有更清楚的认识。

除了数字部分之外,一些项目也会附加一个描述标签,例如“Alpha”或“Beta”(见Alpha和Beta),例如:

Scanley 2.3.0 (Alpha)
Singer 5.11.4 (Beta)

Alpha或Beta修饰意味着这个版本是一个将要发布版本(同样的版本号,但没有修饰)的先例。因此,“2.3.0 (Alpha)”将会带来“2.3.0”。为了能排列好多个这样的候选版本,修饰符也可以有一个之后的修饰。例如,下面是一系列即将发布的版本,根据发布时间排序:

Scanley 2.3.0 (Alpha 1)
Scanley 2.3.0 (Alpha 2)
Scanley 2.3.0 (Beta 1)
Scanley 2.3.0 (Beta 2)
Scanley 2.3.0 (Beta 3)
Scanley 2.3.0

请注意当使用“Alpha”修饰符时,Scanley的"2.3"写作"2.3.0"。这两个号码是等同的—出于简短的目的,结尾所有的0都可以丢掉—但是当有修饰词时,简短成为无需考虑的问题,所以人们会选择完整的方式。

另外一些半正规的修饰词包括“Stable”、“Unstable”、“Development”和“RC”(“发布候选”)。最常用的还是“Alpha”和“Beta”,而“RC”用于第三方,但是请注意“RC”总会包含一个数字修饰。也就是不要使用“Scanley 2.3.0 (RC)”,而使用“Scanley 2.3.0 (RC 1)”,然后是RC2,以此类推。

“Alpha”、“Beta”和“RC”都是已经广为人知的标签了,所以我不建议你使用其他标签,即使是那些乍看起来更常见而非方言的词汇,似乎是更好的选择。但是那些从发布包安装软件的人对于这三个词汇已经非常熟悉,没有理由选择特立独行。

尽管发布版本号码中的点数并不是小数点,但也是起到了位置标示的作用。所有的“0.X.Y”早于“1.0”(等同于“1.0.0”)。“3.14.158”是“3.14.159”直接前继版本,而“3.14.160”和“3.15.任意数”则是“3.14.158”的后继版本,担不是直接后继。

一致的发布版本号码策略可以让用户仅仅从某个软件的版本号就可以判断出版本的重要程度。在一个三部分的系统中,第一部分是主 版本号,第二部分是次 版本号码,而第三部分是小 版本号码。例如版本“2.10.17”是主版本2系列的次要版本10开发线的小版本17。词汇“开发线”和“系列”在这里并不正式,但他们代表了人们期望的含义。一个主系列仅仅是共享同一个主号码的版本,而次要系列(或次要开发线)则由相同次要主号码的版本。也就是说,“2.4.0”和“3.4.1”并不是位于同一个次要系列,即使他们都有次要版本号码4。另一个情况下,“2.4.0”和“2.4.2”则位于同一个次要开发线,尽管他们并不是相邻的版本,因为“2.4.1”版本位于他们之间。

这些号码的含义可以是你自己所期望的:主号码的变更表示发生了主要的变化;次要号码的变化表示发生了次要的变更。有一些项目会有第4部分,通常叫做补丁 号码,特别是一些对区别进行细致控制的项目(有一点让人混淆的是,一些项目将三部分系统中的“微(micro)”版本作为“补丁”。)。也有一些项目使用最后一部分作为构建 号码,随着项目的每一次构建递增,代表了每次变更的变化。这样帮助了项目将每个bug报告与特定构建联系起来,特别是当二进制发布包是发布默认方法时特别有用。

尽管对于使用多少个部分,每个部分的含义有许多不同的习惯,区别通常很小—你会受到一些压力,但是不会太大。下面两小节讨论了最常用的几个习惯。

简单策略

如果仅仅会改变微小版本号码,大多数项目对于将何种变更纳入到发布中会有一些规则,改变主要版本号码则也会有相应的规则。没有这些规则的标准集合,但下面描述是已经在许多项目广泛使用的的政策。你或许会在自己的项目中采用这些方法,但即使不使用,这仍是发布号码所应传达信息的好案例。这个政策是APR项目使用的编号系统,请看http://apr.apache.org/versioning.html

  1. 对于微小号码的变更(也就是在同一个次要开发线上发生的变化)只能是向前和向后兼容的。也就是说,变更只能是bug修正,或仅仅是对现有特性较小的改进。新特性一定不能在微小版本发布中引入。

  2. 次要版本号码(也就是位于同一个主开发线)的变更必须是向前兼容,但不必向后兼容。在次要版本中引入新特性非常常见,但是通常不要一次包含过多特性。

  3. 主版本号码的变更标识了兼容性的边界。新的主版本发布不必向前和向后兼容。新的主版本发布应该包含新的特性,甚至完全的新特性集合。

向后兼容向前兼容的含义取决于你的软件,但通常无需明确的解释。例如,如果你的项目是客户端/服务器应用,那么“向后兼容”意味着将服务器升级到2.6.0不会导致2.5.4的客户端失效,或者工作方式发生变化(当然要排除修正的bug)。另一方面,将客户端升级到2.6.0,可以让客户端享受2.5.4无法使用功能。如果不能做到这一点,则升级不是“向前兼容”:显然,你现在不能将客户端降级到2.5.4,并保持2.6.0的功能,因为一些功能是2.6.0新增的。

这也是微小版本主要用于bug修正的原因。一定要保持双向的兼容性:如果你从2.5.3升级到2.5.4,然后改变主意降级到2.5.3也不会有任何功能损失。当然,2.5.4中修正的bug会再次出现,但不会损失任何新特性,只是bug可能会妨碍现有特性的使用。

客户端/服务器协议仅仅是许多可能的兼容性领域的一种情况。另一种是数据格式:软件会将数据写入永久存储吗?如果是,则数据的写入和读取必须依照发布号码政策所承诺的兼容性方针。版本2.6.0需要能够读取2.5.4写的文件,但是可能会暗自将格式升级到2.5.4无法阅读的新格式,因为跨次要版本边界的无需有降级的能力。如果其他程序使用你的项目发布的代码库,则API也是需要考虑的兼容性领域:你必须确保明确说明源代码和二进制兼容性规则,用户无需担心直接升级是否安全。她应当可以通过版本号码立刻知道结果。

在这个系统中,只有增加主版本号码时你才能从头开始。这确实有些不便:也许你会希望增加某些特性,希望重新设计协议,但是为了维护兼容性而无法实现。这个问题没有魔法解决方案,除非你能在一开始就以可扩展的方式进行设计(值得用单独一本书讨论的主题,当然超出了本书的范围)。但是通过公布发布兼容性政策,并遵守它,是发布软件不能回避的一部分。某个低劣的惊奇只会疏远许多用户。刚刚描述的政策能起到的作用有限,因为它已经广泛传播,但是因为它易于解释和记忆,所以不熟悉的人也可以很快接受。

也需要知道上述规则并不适用于pre-1.0的版本(尽管您的发布政策应当明确陈述,只是要说清楚)。一个还处于初始发布状态的开发可以发布0.1、0.2、0.3以及依次的后续版本,直到1.0,这些发布之间的区别可以任意大。pre-1.0版本的微小版本号可以省略。取决于项目的特性和版本的区别,你或许会发现0.1.0、0.1.1也很有效。pre-1.0的版本号码规则通常比较松散,主要是因为人们明白在项目初期,较强的兼容性限制会严重阻碍开发,而且较早的使用者也较能够容忍这种变化。

请牢记所有这些指令仅适用于三部分系统。你的项目可以轻易的得到不同的三部分系统,甚至可以决定不使用这么细致的粒度,而仅仅使用两部分系统。重要的是要尽早决定,仅按照每个部分的含义发布,并坚持下去。

奇偶数策略

一些项目使用次要版本号码部分表示项目的稳定程度:偶数表示稳定,奇数表示不稳定。仅适用于次要版本号码,不能用于主版本号码和微小版本号码。微小版本号码依然表示bug修正(没有新特性),主版本号码的递增依然表示重大变更,新特性集合。

奇偶系统优势在于它已经被Linux内核项目使用,它提供了一种方法,可以发布新功能用于测试,而无需让产品用户受到潜在不稳定代码的影响。人们在看到“2.4.21”时可以认为能够用于他们使用的web服务器,但当看到“2.5.1”时,则可以用于家用工作站的实验中。开发团队掌握了来自不稳定(奇数次要版本号码)系列的bug报告,当在该系列的一些微小版本中完成了许多工作后,他们便增加次要版本号码(变成偶数),将微小版本号码恢复到“0”,并发布推定的稳定包。

这个系统保留了前面给定的兼容性政策,或至少没有发生冲突。仅仅是在次要版本号码上重载了一些额外的信息。仅仅是让需要的人每次需要增加两个次要版本号码,并没有重大的损害。奇偶系统通常最适合用于拥有较长发布周期的项目,以及因为本性上就需要较高比例的保留用户能为新特性评估稳定性的项目。当然这不是让新功能得以测试的唯一方法,本章后面的章节“稳定发布版本”一节描述了另一个方法,也是更常见的公布不稳定代码的方法,直接通过发布名称的标识让人们知晓风险/收益的代价。

发布分支

从开发者的角度讲,一个自由软件项目处于连续发布的状态。开发者通常一直在任何时候都运行最新的可用代码,因为他们需要定位bug,而且因为他们近距离的接触项目,可以避开当前特性的不稳定区域。他们通常会每天更新他们软件的备份,有时一天几次,当他们检入变更时,他们有道理认为其他开发者会在24小时内得到。

然而,何时项目应该做出正式的发布?是否仅仅取得某个时刻的快照,打包并交给世界,然后说“3.5.0”?常识告诉我们不是。首先,几乎没有一个时刻整个开发树是干净和准备好发布的。新开始的特性可能处于不同的状态。一些人可能检入了修正bug的主要变更,但是这个变更可能充满争议,在发生快照时依然处于辩论阶段。在这种情况下,仅仅是延后快照,等待辩论的结束是没有用的,因为此刻另一个不相关的辩论可能同时发生,那时你就需要等待那个辩论的结束。无法保证这个过程的终止。

在任何情况下,使用整个树的快照作为发布都会干扰正在进行的开发工作,即使整个树已经进入了可发布状态。假定快照将会成为“3.5.0”;而下个快照将会是“3.5.1”,会包含在3.5.0版本发现的大多数bug修正。但是如果快照来自同一个树,开发者在两个版本之间应该怎么做?他们不可以添加新特性;兼容性政策不允许这种行为。但是,不是每个人都会有激情修改3.5.0的代码bug。因为人们可能有需要完成的新特性,如果必须在静候和不想做的事情之间做出选择,他们会非常愤怒,而原因是项目发布过程要求开发树保持不自然的静默。

这个问题的解决方案一直是使用发布分支。一个发布分支仅仅是版本控制系统(见分支(branch))的一个分支,其中预定要发布的代码已经与开发主线分离。发布分支的概念不仅仅来自自由软件;许多商业开发组织也会使用它。然后,在商业环境中,发布分支通常被认为是昂贵的—一类正式的“最佳实践”可以在主开发线针对最终期限的同时,可以让团队的每个人分散精力去完成稳定主开发树的工作。

但是,发布分支在开源项目中是不可或缺的。我经历过的一些没有发布分支的项目,但是这样总会导致一些开发者必须停止下来等待别人—通常是微小的—发布出门的工作。在许多情况下通常结果是不好的。首先,整体开发动力被降低。其次,发布版本可能无法达到必须的质量,因为只有少数人在上面工作,而且他们会急于完成工作,这样别人才能回来工作。第三,通过设定了一个情形,不同类型的工作不必要的互相干扰了别人的工作,在心理上分割了开发团队。处于停滞的开发者可能会很乐意为发布分支贡献一些精力,只要他们可以根据自己的日程和兴趣做出选择。但是,没有这个分支,他们的选择就变成“今天我可以参与项目吗?”而不是“我可以为发布工作,还是为主开发线上的新特性的工作?”

发布分支的技巧

创建发布分支的确切技巧取决于你的版本控制系统,当然基本概念基本上是相同的。一个分支通常从另一个分支或主干分出。传统上,主干(trunk)是主要开发进行的地方,不受发布的限制。第一个发布分支,也就是将会变成“1.0”版本的分支是从主干分出的。在CVS中,分支命令类似下面的形式

$ cd trunk-working-copy
$ cvs tag -b RELEASE_1_0_X

或者在Subversion中,类似:

$ svn copy http://.../repos/trunk http://.../repos/branches/1.0.x

(这些例子都假设使用三部分的发布号码系统。因为我无法展示每个版本控制系统中的精确命令,我将会给出CVS和Subversion的例子,希望其他系统中对应的命令可以从中推导出来。)

请注意,我们创建了分支“1.0.x”(包含文字“x”),而不是“1.0.0”。这是因为同一条次要开发线—也就是同一个分支—将会被所有微小版本共用。用于发布的分支稳定化将会在本章后面的“稳定发布版本”一节描述。这里,我们仅仅关注与版本控制系统的交互和发布过程。当发布分支已经稳定并做好准备,则应该从分支完成标记快照了:

$ cd RELEASE_1_0_X-working-copy
$ cvs tag RELEASE_1_0_0

$ svn copy http://.../repos/branches/1.0.x http://.../repos/tags/1.0.0

现在标签代表了项目源代码树在1.0.0版本的精确状态(在较老版本的打包发布和二进制程序被去掉后,如果某人希望获取时非常有用)。同一开发线的下个微小版本也很可能需要在1.0.x分支上准备,完成后,则增加1.0.1的标签。再次,重复完成1.0.2等等。当需要完成1.1.x版本时,则从主干再创建一个分支。

$ cd trunk-working-copy
$ cvs tag -b RELEASE_1_1_X

$ svn copy http://.../repos/trunk http://.../repos/branches/1.1.x

维护可以在1.0.x和1.1.x上并行继续,而版本发布也可以在两条线上独立进行。实际上,在两个不同的开发线上近乎同步的发布版本并不罕见。较旧的系列是保守的站点管理员应该使用的,他们可能不希望在没有小心准备的情况下做出重大的跳跃到(假设到)1.1。而同时,更多勇于冒险的人会将版本保持在最高的开发线上,以确保他们能获取最新的特性,即使要冒更大的稳定性风险。

这并不是唯一的发布分支策略,当然。在一些情况下,可能也不是最好的,只是在我参与过的项目中它的表现相当好。尽可以使用有效的策略,但请牢记要点:发布分支的目的是隔离发布工作与日常开发,并给项目一个物理实体用于组织整个发布过程。这个过程将会在下一小节详细描述。

稳定发布版本

稳定化是让一个发布分支进入发布状态的过程;也就是决定哪些变更将会进入发布版本,并以此为根据修整分支的内容。

“决定”一词有许多潜在的不幸。在协作软件项目中最后一分钟特性冲击是非常常见的现象:当开发者看到软件发布将要发生,他们便混乱的结束当前的变更,不希望错过这班船。当然,这是在发布时你最不想看到的场面。如果人们能在比较以舒适的节奏,无需担心变更是进入这个版本还是下一个版本时完成这个特性,效果会更好。设法在最后一分钟进入发布的变更越多,代码就越不稳定,而且(通常是)也会造成更多的新bug。

大多数软件工程师认可在稳定阶段,变更进入发布版本线时使用严苛标准的理论。很明显,对于严重bug,尤其是没有临时解决办法的bug的修正应该进入。文档更新以及错误信息修改(除非是被认为是界面的一部分,并必须保持稳定的信息)也没问题。许多项目也允许特定类型的低风险或非核心变更在稳定期进入,并提供评估风险的正式指导。但是没有正式的文档可以回避对于人们判断的需要。在很多情况下项目需要为是否将哪个变更纳入发布作出决定。危险的是因为每个人都希望看到自己喜欢的变更进入发布版本,并会激发足够的人赞成这个变更,而不会激发足够的反对者。

因此,稳定一个发布版本也就是要创建一种说“不”的机制。对于开源项目来说,技巧在于如何能在说“不”的同时,尽可能避免造成过多的情绪伤害或失望的开发者,并且还要防止在发布版本中漏掉真正需要的变更。当然有许多不同的方法。可以很容易的设计一个满足这个标准的系统,只要项目能够将其视作重要的标准。在广阔的范围中,这里我仅仅介绍两种最流行的系统,希望这不会让你失去在项目中发挥创造性的激情。有足够多的其他方式也是可能的;但这两个是我在实践中使用过的。

发布所有者独裁

团队认可让某人成为发布所有者。这个人可以最终确定进入发布版本的变更。当然,有研讨和辩论也是正常和可以设想的,但是最后团队必须赋予所有者足够的权威作出最终的决定。对于此类系统,必须选出一个合适的人,具备理解所有变更的技术能力,具备在避免伤害过多感情的情况下将讨论引入发布的社会威望和社交技巧。

发布所有者场景会说“我不认为这个变更有什么错误,只是我们没有足够的时间测试,所以不能进入这个发布版本。”如果发布所有者对于项目具备广泛的技术知识将会非常有益,这样可以解释为什么这个变更会潜在的导致不稳定性(例如,当与软件的其他部分交互时,或移植性考虑等)。人们有时会为这类决定辩护,或者质问什么样的变更没有这种风险。这种对话不需要是对抗性的,只要发布所有者认为所有的论点都是客观的,而不是条件反射式的坚定自己的立场。

需要注意的是发布所有者与项目领导不必是同一个人(如果有项目领导的话,见第 4 章 社会和政治的基础架构“慈善独裁者”一节)。实际上,有时要确保他们不是同一个人。成为一个优秀项目领导的技巧与成为优秀发布所有者的技巧并不一定相同。在有些时候,与发布过程同等重要的是能有一个人可以成为项目领导判断力的平衡力量。

发布所有者角色与较弱独裁者角色的比较本章后面的“发布经理”一节

变更表决

发布所有者独裁方式的另一个极端就是为进入发布的变更进行表决。然而,因为发布稳定化最重要功能是排除变更,所以势必要设计一种表决系统,只有在大多数开发者表示正面意见时才将变更纳入发布。只有比简单多数更多的赞成才可以引入一个变更(见第 4 章 社会和政治的基础架构“谁进行表决?”一节)。否则,一个人提出,没有人反对,一个变更就足以进入发布,一个不幸的变化就是每个开发者都会提出自己的变更,而且处于防止他人报复的原因,他们也不会再反对其他人提出的变更。为了避免这个情况,必须安排一些开发者组成子团队,起到将变更纳入发布的协作作用。这并不是意味着让更多的人评审每个变更,而是为了减少每个单独的开发者在反对某个变更时的犹豫,因为她知道赞成该变更的所有人不会将她的反对意见当作人身攻击。子团队参与的人数越多,讨论就会更加集中与变更本身,而不会是关于某个人。

我们在Subversion项目中使用的系统达到了非常好的平衡,所以我在这里将会推荐它。为了让一个变更进入发布分支,必须至少有3位开发者要投票赞成它,而且没有反对者。一个单独的“反对”票足以阻止变更的进入;在发布场景中一个“反对”票等同于否决票(见“否决权”一节)。很自然,这类表决必须伴随着辩护意见,而且如果有足够多的人认为辩护毫无道理,也可以发起一次针对该变更的特别表决。在实践中,这种情况还没有发生过,我也不认为将会发生。人们面对发布时总是趋向于保守,当人们感到可以否决某个变更时,通常是因为有了足够好的理由。

因为,发布规程故意倾向于保守,所以否决时的辩护有时是出于程序上的原因,而非技术上的。例如,一个人认为某个变更写的很好,不太可能导致新bug,但是否决它进入微小版本的意见仅仅是它太大了—或许它引入了新特性,又或者它以微妙的方式违反了兼容性政策。我也偶尔会看到一些开发者仅仅因为有不好的感觉而否决一些东西,他们认为这些变更需要更多的测试,即使无法检查出任何bug。人们总会发些牢骚,但是否决已经成立,而且变更不会进入发布(即使我不记得之后的测试是否发现了bug)。

管理协作发布稳定化

如果你的项目选择了一种变更表决系统,一定要确保设置投票和发布表决的物理机制尽可能的便利。尽管有大量开源电子投票软件,在实践中最简单的方式还是在发布分支上设置一个叫做STATUSVOTES或诸如此类的文本文件。这个文件列出所有的变更提议—任何开发者可以提出包含某个变更的提议—之后就是同意和反对它的表决,以及注释或评论。 (提出一个变更并不意味着一定要为此投票,尽管两者经常一起出现。)这个文件中任意一个条目的内容类似这个:

* r2401 (issue #49)
  Prevent client/server handshake from happening twice.
  Justification:
    Avoids extra network turnaround; small change and easy to review.
  Notes:
    This was discussed in http://.../mailing-lists/message-7777.html
    and other messages in that thread.
  Votes:
    +1: jsmith, kimf
    -1: tmartin (breaks compatibility with some pre-1.0 servers;
                 admittedly, those servers are buggy, but why be
                 incompatible if we don't have to?)

在这个情况下,该变更得到了两个赞成票,但是被tmartin否决,他在附加说明中给出了原因。该条目的详细格式并不重要;你的项目如何设置都可以—或许tmartin的解释应该出现在“Notes:”部分,也许变更描述也应该有一个”Description: “头来匹配其他小节。重要的是需要评估这个变更的所有信息都是触手可及的,进行投票的机制也是尽可能的保持轻量级。提议的变更直接用版本库中的修订号码引用(如果是单个修订可能是r2401,当然提议的变更也可能由多个修订组成)。修订可以是引用在主干上的变更;而如果变更就发生在发布分支,可能没必要再表决了。如果你的版本控制系统没有引用某个变更的明确语法,则项目需要建立一个。为了表决的可操作性,每个需要考虑的变更必须是明确可标识的。

这些提议和表决可以保证变更可以干净的进入发布分支,也就是不会发生冲突(见冲突(conflict))。如果有冲突,则该条目应当包含指向一个可以使变更变干净的补丁,或者是包含已修正变更的临时分支,例如:

* r13222, r13223, r13232
  Rewrite libsvn_fs_fs's auto-merge algorithm
  Justification:
    unacceptable performance (>50 minutes for a small commit) in
    a repository with 300,000 revisions
  Branch:
    1.1.x-r13222@13517
  Votes:
    +1: epg, ghudson

这个例子取自真实的生活;来自Subversion 1.1.4发布过程的STATUS文件。请注意,它是如何使用原始的修订版本作为变更的标准描述方式,即使有一个分支已经有了修正冲突后的变更版本(为了更简单的将一定会被通过的变更合并到发布版本,分支也将三个trunk的修订版本合并为一个r13517)。这里还是提供了原始的修订版本,作为最早的可以检查的实体,因为他们都提供了原始的日志信息。临时分支不会有那些日志信息,为了避免信息的复制(第 3 章 技术基础设施“信息单一性”一节),分支上r13517的日志信息仅仅是“调整r13222、r13223和r13232回到分支1.1.x。”关于变更的所有其他信息都可以跟踪原始的修订版本得到。

发布经理

将已确认变更合并到发布分支的实际过程(见合并(又名搬运)(merge, a.k.a. port))可以由任何开发者执行。不必有一个人专门负责合并变更;如果变更很多,最好能有人分担工作。

然而,尽管表决和合并都以非集中的样式出现,在实践中通常会有一到两个人掌控着发布过程。这个角色有时被正式的称作发布经理,但是与拥有最终决定权的发布所有者(见本章前面的“发布所有者独裁”一节)有很大的区别。发布经理跟踪当前有多少正在考虑的变更,有多少已经确认,有多少可能会被确认等等。如果他们感到重要的变更未能获得足够的关注,或者可能因为缺少投票而无法进入发布,他们会有礼貌的提醒其他开发者检查并投票。当一组变更经过确认,这些人会自己去将它们合并到发布分支;如果有其他人愿意自己完成这个任务也没有问题,只要所有人都理解如果他们没有明确的声明要自己做,这便不是强制要做的工作。当要将发布公布于众时(本章后面的“测试和发布”一节),发布经理将会完成最终发布包的创建,收集数字签名,上传发布包并作出公告。

打包

分发自由软件的标准形式是源代码。无论软件是否以源代码的形式(例如解释性语言Perl、Python和PHP等等)运行,还是必须首先编译(例如C、C++和Java等),这一点是毋庸置疑的。通过编译好的软件,大多数用户可能无需自己编译源代码,而只需安装预先编译的二进制包(见本章后面的“二进制包”一节)。然而,这些二进制包依然来自主源代码分发包。原因是源代码包明确定义了发布版本。当项目分发“Scanley 2.5.0”时,真正的含义是“源代码文件的目录树,当编译(如果需要)和安装后将产生Scanley 2.5.0”。

对于源代码发布的式样有一个相对严格的标准。可能会有与标准的偏差出现,但是那只是例外,不是规则。除非有强有力的理由,否则你的项目也应该遵守这个标准。

格式

源代码必须以标准格式传输目录树。对于Unix和类Unix的操作系统,习惯上是TAR格式,压缩为compressgzipbzipbzip2。对于微软Windows,分发目录树的标准方法是zip格式,也是压缩格式,所以不必再进一步压缩归档文件。

命名和布局

打包的名称必须包含软件名称和发布版本号,然后是特定归档类型的格式后缀名。例如Scanley 2.5.0在Unix上使用GNU Zip(gzip)压缩的包类似:

scanley-2.5.0.tar.gz

或者是在Windows上使用zip压缩:

scanley-2.5.0.zip

所有的这些归档解压后,都应该能在当前目录创建一个名为scanley-2.5.0的单独目录。这个新目录中,所有的源代码应该是处于准备好进行编译(如果需要编译)的布局。在新目录树的最上层,应该有一个README文件,解释了软件是什么,发布版本是哪个,并给出了其他资源的指针,例如项目站点以及其他有用的文件等。README旁边也应该有一个INSTALL,说明在所有支持的操作系统上构建和安装软件的方法。就像第 2 章 起步“如何为你的软件应用许可证”一节所说明的,应该有COPYINGLICENSE,说明软件分发的条款。

也应当有一个CHANGES文件(有时称为NEWS),解释了发布版本的新功能。CHANGES文件按照逆向的历史顺序,汇集了所有发布版本的变更列表,所以最新的发布位于文件最顶部。完成这个列表通常是稳定发布分支的最后一项工作;一些项目会随着开发列出所有的片段,而另外一些项目更倾向于在最后阶段,让某人根据版本控制日志组合信息一次完成。这个列表类似下面:

Version 2.5.0
(20 December 2004, from /branches/2.5.x)
http://svn.scanley.org/repos/svn/tags/2.5.0/

 New features, enhancements:
    * Added regular expression queries (issue #53)
    * Added support for UTF-8 and UTF-16 documents
    * Documentation translated into Polish, Russian, Malagasy
    * ...

 Bugfixes:
    * fixed reindexing bug (issue #945)
    * fixed some query bugs (issues #815, #1007, #1008)
    * ...

根据具体情况,这个列表可能会很长,但是不需要包含所有的小bug修正和特性提升。它的目的仅仅是给用户一个印象,通过升级到最新版本将会获得哪些好处。实际上,习惯上会将变更列表包含在声明邮件(见本章后面的“测试和发布”一节)中,所以在编写时要考虑你的读者。

目录树中源代码的布局与项目版本控制系统检出的源代码的布局应当相同,或者尽可能的近似。通常情况下,会有些区别,例如因为发布包会包含一些用于配置和编译(见本章后面的“编译和安装”一节)的生成文件,或者因为它包含了非本项目维护的,而用户一般不会拥有的第三方软件,。但是,即使发布的目录树与版本控制系统中的开发目录树完全一致,发布包本身也不应当是一个工作拷贝(见工作拷贝(working copy))。发布版本代表了一个静态参考点—源文件特定的,不可改变的配置。如果它是工作拷贝,就会存在用户不小心作出更新的风险,而用户还会以为使用的是发布版本,尽管实际上已经有所不同。

请牢记无论打包方式如何,这个发布包应该是一样的。这个发布版本—精确的引用了某人所说的“Scanley 2.5.0”—是zip文件或tarball解压缩所创建的目录树。所以项目可以提供所有这些下载:

scanley-2.5.0.tar.bz2
scanley-2.5.0.tar.gz
scanley-2.5.0.zip

...但是通过解压他们创建的源代码树必须相同。源代码树是分发物;具体的形式只是为了方便使用。源代码包也可以有些许的差异:例如,在Windows包中,文本文件必须以CRLF作为行结束符(回车和换行),而Unix包应该使用LF。不同操作系统下如果因为编译的原因需要有不同的布局,源包的布局也可以有所不同。然而,这些都是些无关紧要的变形。同一发布版本不同包的基本源代码文件必须相同。

大写还是不大写

当通过名称引用一个项目时,人们通常会以正常的名词进行大写,如果是缩略词则也要大写:”MySQL5.0“,”Scanley2.5.0“等等。是否在包名上大写也取决于项目。例如,Scanley-2.5.0.tar.gzscanley-2.5.0.tar.gz都可以(我个人倾向于后者,因为我不喜欢让人去按shift键,不过很多项目使用有大写的包)。重要的是解压tarball得到的目录使用相同的大小写。不应该有什么意外:用户总是预计解压得到的目录会和压缩包使用相同的名称。

预发布

当发送预发布或候选发布时,合格者成为发布号码的一部分,所以在包的名称中要包含这个名字。例如,在之前“版本号组成部分”一节提到的alpha和beta系列的发布包名称为:

scanley-2.3.0-alpha1.tar.gz
scanley-2.3.0-alpha2.tar.gz
scanley-2.3.0-beta1.tar.gz
scanley-2.3.0-beta2.tar.gz
scanley-2.3.0-beta3.tar.gz
scanley-2.3.0.tar.gz

第一个解压后进入目录scanley-2.3.0-alpha1,第二个是scanley-2.3.0-alpha2,以此类推。

编译和安装

对于需要从源代码编译的安装的软件,有许多经验丰富的用户希望能够遵循的标准步骤。例如,以C、C++或特定其他编译语言编写的程序,在类Unix系统下的标准是输入:

   $ ./configure
   $ make
   # make install

第一个命令自动检测构建过程中需要的环境,第二个命令在原地构建软件(但不安装),最后一个命令是在系统上安装。前两个命令作为普通用户执行,而第三个以root用户。设置系统的详细信息可以看Vaughan、Elliston、Tromey和Taylor编写的优秀图书GNU Autoconf, Automake, and Libtool。它作为New Riders的treeware发布,内容也可以在网上http://sources.redhat.com/autobook/免费得到。

这不是唯一的标准,只是传播最广泛的一个。Ant(http://ant.apache.org/)构建系统也渐渐流行,特别是Java编写的项目,它拥有自己的构建和安装的标准步骤。另外,特定的编程语言,例如Perl和Python都有大多数使用这些语言所推荐的相同方法(例如Perl模块使用命令perl Makefile.pl)。如果不是清楚适应于项目的标准,可以询问资深的开发者;你可以安全的假定某些标准更加合适,即使一开始并不清楚是什么。

无论你的项目适合哪个标准,则如非必要一定不能与之偏离。标准安装过程对于许多系统管理员已经成为条件反射。如果在你的项目INSTALL文件中看到了熟悉的实施步骤,他们就会认识到你的项目遵守了一般的习惯,也就会轻松的完成其他的事情。另外,就像在第 2 章 起步“下载”一节中讨论的,拥有标准的构建程序可以让潜在的开发者满意。

在Windows中,构建和安装的标准比较薄弱。对于需要编译的项目,通常要提供一个适用于标准微软开发环境(Developer Studio、Visual Studio、VS.NET和MSVC++等等)工作空间/项目模型的目录树。取决于项目的本性,可以通过Cygwin(http://www.cygwin.com/)环境提供类Unix的构建选项。当然,如果你使用的语言或编程框架使用自己的构建和安装习惯—例如Perl或Python—你应当使用该框架标准的方法,无论是Windows、Unix、Mac OS X或任何其他操作系统。

要乐于花费额外的精力让项目遵守相关的构建或安装标准。构建和安装是切入点:如果一定需要,在这之后可以更加困难,但是如果用户或开发者一开始就需要使用意想不到的步骤与软件进行交互则是一种耻辱。

二进制包

尽管正式发布是源代码包,大多数用户会从二进制包安装,可以通过他们操作系统的软件分发机制得到,也可以从项目站点或第三方手工获取。这里“二进制”并不一定是“已编译”;它仅仅意味着一种预配置形式的包,允许用户在自己的电脑上无需执行一般的基于源代码的构建和安装程序,便可以进行安装。在RedHat GNU/Linux上,这是RPM系统;在Debian GNU/Linux上,则是(.deb)系统;在MS Windows,通常是.MSI文件或自安装的.exe文件。

无论这些二进制包是由项目相关的人组装,还是由关系较远的第三方组装,用户都会认为其等同于项目的官方发布版本,会根据二进制包的行为在项目bug跟踪系统上发起问题。因此,项目能否为打包者提供明确的指导方针就非常有意义,应该与他们更紧密的合作,认识到他们是否能够清楚和准确的产生软件。

打包者需要知道的主要问题是是否应当一直根据官方源代码版本发布他们的二进制包。有时,打包者会喜欢获取版本库较晚版本的代码,或者选择在发布后包含某个变更,从而为用户提供特定的bug修正或其他改进。打包者认为通过最新的代码,他是在为用户谋利益,但实际上这样会导致许多混乱。项目已经准备好了接受某个发布版本以及trunk和分支上(那些故意运行最前沿代码的人发现的)的bug报告。当一个bug来自这些源,回应者通常可以能确认bug在该快照出现,而且已经被修正,用户可以升级或等待下个发布。如果是一个还未知的bug,拥有精确的发布版本时,重现就会比较简单,在跟踪系统中也比较容易分类。

项目没有准备好根据未指明媒介或混血的版本接受bug报告。此类bug很难重现;另外,因为无法预期与来自发布之后开发的孤立变更进行交互的结果,所以产生的不正常也不应该成为对开发者进行谴责理由。我曾经非常沮丧的浪费了许多时间,因为某个bug似乎消失了,而实际上应该出现:某人运行的是轻微补丁的版本,基于(但不相同)官方发布版本,当预期的bug没有出现时,每个人都会尝试寻找原因。

在有一些情况下,打包者也确实需要在原发布基础上做出一些修改。要鼓励打包者向项目开发者提出这个问题,并描述他们的方案。他们可能得到许可,即使失败,也至少会让项目知道他们的目的,项目也可以关注一些不寻常的bug报告。开发者可以在项目站点上设置一个免责声明,并告知所有的打包者在合适的地方放置同样的东西,这样该二进制包的用户就可以知道他们获取的东西与项目官方发布并不完全相同。这种情形并没有任何敌意,但不幸的是经常会有这种结果。打包者与项目开发者有些不太一样的目标。打包者主要希望为用户提供最佳的开箱即用体验。开发者也希望如此,但他们也需要确保自己知道别人所用软件的版本,这样可以获取到一致的bug报告,并作出兼容性的保证。有时这些目标会有冲突。当发生这种情况时,需要牢记项目无法控制打包者,两种方式都承担了各自的义务。诚然项目通过产生软件为打包者提供了服务。但是打包者也是在为项目服务,通过提供这种单调的工作让软件更广泛的传播。当然可以不认可打包者,但是不要迁怒于他们;只需要尽自己的可能将工作做好。

测试和发布

一旦源代码tarball已经从稳定的发布分支产生,发布过程公共部分便已经开始。但是在tarball进入公开之前,必须经过少量开发者的确认,通常需要三位或者更多。确认不仅仅是检测发布的明显缺陷;理想情况下,开发者应该下载tarball,在干净的系统上构建并安装,运行回归测试包第 8 章 管理志愿者(见“自动测试”一节),然后执行一些手工测试。假如通过了这些检查以及项目的其他的发布检查列表条件,开发者可能需要使用GnuPG(http://www.gnupg.org/)、PGP(http://www.pgpi.org/)或其他可以产生PGP兼容签名的程序为tarball作出数字签名。

大多数项目中,开发者仅仅使用个人的数字签名,而不是许多开发者(有一小部分,担不是大多数)希望使用的项目共享密钥。签名的开发者越多,经过的测试也就越多,一个关心安全的用户也就越可能找到一个到达该tarball的数字信任路径。

一经确认,发布版本(所有的tarballs、zip文件以及其他需要分发的格式)就应当放置到项目的下载区,并伴有数字签名,以及MD5/SHA1校验(seehttp://en.wikipedia.org/wiki/Cryptographic_hash_function)。有许多做这些工作的标准。一种方法是为每个发布包提供一个对应的数字签名,以及一个校验文件。例如,如果发布包是scanley-2.5.0.tar.gz,在同一目录的scanley-2.5.0.tar.gz.asc包含了这个tarball的数字签名,另一个文件scanley-2.5.0.tar.gz.md5则包含了MD5校验,也可以有另外一个scanley-2.5.0.tar.gz.sha1文件,包含SHA1校验。另一种方法是收集所有发布包的签名到一个单独的文件scanley-2.5.0.sigs;校验文件与之类似。

具体怎样做并不重要。只要保持简单的模式,描述清楚,并在每次发布保持一致即可。所有签名和校验的目的是为了用户校验自己的拷贝未经恶意修改。用户会在自己的电脑上运行这些代码—所以如果代码被篡改,攻击者可以立刻拥有到达所有数据的后门。本章后面的“安全发布”一节有更详细的介绍。

候选发布

对于包含许多变更的发布版本,许多项目会首先推出发布候选,例如scanley-2.5.0之前的scanley-2.5.0-beta1。候选的目的让代码在发布之前接受更广泛的测试。如果发现了问题,可以在发布分支修正,并推出新的发布候选(scanley-2.5.0-beta2)。这个周期会持续到不能发现不可接受的bug为止,最后的发布候选成为正式发布版本—也就是说最后的候选发布和正式发布的唯一区别只是版本号码的修饰词。

在大多数其他方面,候选发布一定要与正式发布保持相同的待遇。alphabetarc修饰足以警告保守的用户等待真正的发布,而候选发布的声明邮件也必须指出他们的目的是征求反馈。除此以外,应该对候选发布提供与正式发布相同的关注。毕竟,你希望人们使用候选版本,因为暴露是发现bug的最佳方法,而且也因为你永远无法获知哪个候选会最终成为正式版本。

宣告发布

宣告发布很像宣布其他事件,一定要采用在第 6 章 交流“公开性”一节中描述的程序。当然,对于发布要额外注意一些事情。

每当你提供下载发布tarball的URL时,一定要确保给出MD5/SHA校验和数字签名文件的链接。因为宣告会出现在许多论坛里(邮件列表,新闻页等),这意味着人们会从许多地方获取到校验信息,这可以给关心安全的用户额外的保证,证明了校验本身没有被篡改。反复提供数字签名的链接并不会使其更安全,但是会让人们(尤其是与项目比较疏远的人)感受到项目对于安全的重视。

在宣告邮件和新闻页中,不应该仅仅报告关于发布的宣传信息,而应该包含CHANGES文件中相关的部分,这样人们就能够看到自己是否有兴趣去升级。这对于发布候选和最终发布同样重要;bug修正的出现和新特性的引入会吸引人们尝试候选版本。

最后,不要忘记感谢项目团队、测试人员以及所有花时间发起bug报告的人。不要单独提出某人的名字,除非某人承担了大量的工作,其价值被项目的每个人所认可。小心坐上信用贬值的索道(见第 8 章 管理志愿者“荣誉”一节)。

维护多发布线

大多数成熟的项目都平行的维护多个发布线。例如,1.0.0发布后,该发布线会继续微小发布1.0.1,1.0.2等等,直到项目明确的决定终止这条线。请注意,仅仅因为发布了1.1.0不足以终止1.0.x线。例如,一些用户会制定某类政策,永远不升级到较新的次要或主要版本的第一个发布—他们希望其他人能将bug试验出来,例如1.1.0,那么就等待1.1.1。这不一定是自私(请牢记,他们也放弃了bug修正和新特性);仅仅是出于某些原因,他们必须在升级上非常小心。因此,假设项目在发布1.1.0之前发现1.0.3中有一个重大bug,如果只是将bug修正纳入到1.1.0,而告知所有的1.0.x用户必须升级到1.1.0,其结果将会非常恶劣。为什么不同时发布1.1.0和1.0.4,这样大家都能高兴吧?

待1.1.x线圆满后,你可以宣布1.0.x进入了生命结束(end of life,EOL)。这一步必须正式宣告。宣告可以是独立的,也可以作为1.1.x发布宣告的一部分;可是这样做时,用户必须能够知道老的开发线正在被关闭,这样他们可以根据情况决定是否升级。

一些项目设置了保证对于前一发布线作出支持的窗口时间。在开源环境中,“支持”意味着接受针对该线的bug报告,并在发现重大bug后发布维护版本。另外一些项目并没有给出预定义的时间,而是根据报告的bug数量判断还在使用较旧发布线的用户。当低于某个百分比时,就可以宣布发布线的结束并停止对它的支持。

对于每个发布,请确保在bug跟踪系统中有目标版本目标里程碑,这样人们可以根据正确的发布填写bug。当然也不要忘记为最新的开发源代码提供叫做“开发”或“最新”的目标,因为总有些人—不仅仅是活跃的开发者—通常会在官方发布的最前沿。

安全发布

对于安全bug的处理请参考第 6 章 交流“声明安全漏洞”一节,但是对于安全发布有许多特殊的细节需要讨论。

一个安全发布是一个专门关闭安全漏洞的发布。修正bug的代码在发布之前不能公布于众,也就是说在发布日之前代码不能提交到版本库,也意味着在公开之前代码不能经过公共测试。很明显,开发者可以自己检查这个修正,并在私下里测试发布,但是无法进行广泛的真实世界测试。

因为缺乏测试,所以安全发布必须是在现有发布基础之上,只附加了安全bug的修正,没有其他变更的发布。这是因为未经测试的变更越多,越有可能导致新的bug,甚至是新的安全bug!这种保守也是对管理员的一种友好,他们将要部署安全修正,但是他们的部署策略倾向于不在同一时间部署任何其他变更。

作出安全发布有时有些小的诡计。例如,项目可能工作于发布1.1.3,对于1.1.2的一些bug修正已经公开声明,此时出现了安全报告。很自然,开发者在完成修正前不能讨论安全问题,他们必须继续讨论,好像1.1.3还会按照计划推出一样。但是当1.1.3实际上到来时,与1.1.2的区别只有安全补丁,而所有其他的修正都会进入1.1.4(当然,现在也会包含安全修正,以后所有的版本也会一直包含)。

你也可以为现有的版本号码添加一个额外的部分,以说明它只包含安全变更。例如,人们能够知道1.1.2.1是针对1.1.2的一个安全发布,所有更高的发布(1.1.3,1.2.0等)会包含相同的安全修正。对于了解内情的人,这个系统可以传递许多信息。在另一方面,那些不能紧跟项目的人,当大多数时间看到的是3部分的发布号码,偶尔看到4部分的号码会感到混乱。我见过的大多数项目会选择一致性,使用常规的下个号码作为安全发布,即使它意味着计划中的发布前进一个版本。

发布和日常开发

维护同时的平行发布包含了如何完成日常开发的暗示。特别是应该遵守每次提交只包含一个单独逻辑变更的铁律,绝不要在一次提交中混杂不相关的变更。如果一次提交的变更太大,或具有破坏性,可以分为N此提交,每次提交都是一个整体变更的分区子集,而且不包含与整体变更无关的内容。

这里是一个未经慎重考虑进行提交的例子:

------------------------------------------------------------------------
r6228 | jrandom | 2004-06-30 22:13:07 -0500 (Wed, 30 Jun 2004) | 8 lines

Fix Issue #1729: Make indexing gracefully warn the user when a file
is changing as it is being indexed.

* ui/repl.py
  (ChangingFile): New exception class.
  (DoIndex): Handle new exception.

* indexer/index.py
  (FollowStream): Raise new exception if file changes during indexing.
  (BuildDir): Unrelatedly, remove some obsolete comments, reformat
  some code, and fix the error check when creating a directory.

Other unrelated cleanups:

* www/index.html: Fix some typos, set next release date.
------------------------------------------------------------------------

当某人需要将BuildDir错误检查修正搬运到维护即将到来维护发布分支时,这种问题立刻变得非常明显。搬运者不希望任何其他的变更—例如,#1729问题的修正未能通过维护分支的确认,而且index.html的修改变得毫无关系。但是她不能仅仅通过版本控制工具的合并功能只获取BuildDir的变更,因为版本控制系统被告知该变更在逻辑上由所有其他不相关的事务组成。实际上,在合并之前这个问题也十分明显。仅仅为表决列出变更会有许多问题:不仅仅要提供修订版本号码,提议者也必须提供特别的补丁或变更分支,才能将提议的部分分离出来。对于其他人来说还要承受许多任务,仅仅因为最初的提交者未能按照逻辑把事情分组。

实际上,这个提交应该分为次独立的提交:一个用于修正#1729,另一个删除BuildDir中废弃的注释,并重新格式化代码,还有一个修正BuildDir中的错误检查,最后要修改index.html。其中第三个提交应该是为维护发布分支所做的提议。

当然,发布稳定不仅仅是要求每次提交仅包含一个逻辑变更的唯一原因从心理学上讲,语义上统一的提交更利于检查,更利于在必要时回退(在某些版本控制系统,回退只是一种特殊的合并)。这种每个人预先遵守的纪律可以避免项目之后的头痛。

计划发布

与私有项目相比,开源项目在发布计划上有历史上的区别。私有项目通常有严格的最后期限。有时是因为已经向客户许诺在规定时间完成升级,可能因为新发布需要配合其他市场目标的投入,也可能是因为风险投资希望在进一步投入前看到些结果。而对于自由软件项目,现阶段主要是由业余开发者以最字面意义的方式激励着:因为喜爱,所以编码。在所有的特性完毕之前,没有人觉得需要装运。并不是所有人的工作都在开发线上。

现今,许多开源项目由公司资助,越来越受到公司文化中的最后期限影响。无论如何这也是一件好事,但是会导致有工资的私有开发者与志愿贡献时间的冲突。这些冲突通常会围绕何时以及如何计划发布等问题发生。处于压力之下的有工资开发者很自然会希望选择一个发布发生的日期,并让每个人的活动投入到这个发布线。但是志愿者有自己的日程—或许是他们希望完成的特性,或一些希望进行的测试—他们希望发布能等待这些工作完成。

当然对于此类问题,除了讨论和妥协没有普通的解决方案。但是通过将发布中某个提议的出现与其完成的日期解耦,你可以最小化所导致阻力的频率和程度。也就是将讨论主题导向到项目在近期,以及中期将要作出的发布,以及其中包含的哪些特性,而不必一开始就确定所有关于日期的事情,除了粗略的一些猜测。[23]。通过尽早明确特性集合,你减少了针对任何单个发布讨论的复杂度,因而改进了可预测性。这也创建了一种惯性偏见,针对通过添加特性或其他复杂度的提议以扩展发布定义的人。如果发布的内容定义良好,则提议者需要承担证明该扩展的负担,即使发布的日期还没有设定。

在Thomas Jefferson的多卷传记Jefferson and His Time中,Dumas Malone讲了一个故事,Jefferson如何处理决定弗吉尼亚大学未来组织结构的第一次会议。大学首先来自Jefferson的一个构想,但是(不仅仅是在开源项目,其他领域也屡见不鲜)有许多其他参与者,都有自己的兴趣和日程。当他们召集在一起举行第一次会议时,Jefferson确保展示了精心准备的架构图,以及希望从欧洲引入的特定教职员工的姓名。房间中所有其他人都没有任何准备;这个团队从本质上就需要服从Jefferson的远见,而这个大学最终几乎按照他的计划建立。事实上整个建设远超预算,他的许多想法出于很多原因,最终未能得到解决,但那都是Jefferson一开始就了解,并预计到会发生的事情。他的目的是策略性的:通过在会议上展示非常确实的东西,让其他所有人仅仅需要履行修改提议的角色,所以项目整体的形状,以及随之而来的日程也可以和他的预期大体一致。

对于开源软件项目,没有一个单独的“会议”,而是一系列由问题跟踪系统代表的小建议。但是如果你在项目开始时有一些信誉,而且根据宣称的整体计划将许多特性、改进和bugs赋予到问题跟踪系统中的目标发布版本,人们会和你走到一起。一旦你根据自己的需要确立了一些事情,关于实际发布日期的对话将会变得非常平滑。

另一个很重要的,不要把任何决定当作是天经地义的。对于未来特定发布的某个问题所关联的注释中,邀请讨论、异议并尽可能真诚的希望被说服。不要为了练习控制而练习控制:其他人越是深入的参与到发布计划过程(见第 8 章 管理志愿者“像分担技术任务一样分担管理任务”一节),越是容易说服其他人分享你在这个问题上本属于你的特权。

另一个降低项目发布计划紧张程度的方法是提高发布的频率。当发布之间的时间很长时,每次发布在每个人心目中的地位也被放大;如果他们的代码未能进入,他们会感觉到更多的压力,因为他们知道下一次机会要等待很久。根据发布过程的重要程度,以及项目的本性,发布的间隔可以在3个月到6个月之间,尽管如果有需求时,维护线可以让微小发布更快一点。



[23] 作为另外一个选择,你或许希望阅读Martin Michlmayr博士的论文Quality Improvement in Volunteer Free and Open Source Software Projects: Exploring the Impact of Release Managementhttp://www.cyrius.com/publications/michlmayr-phd.html)。它使用的是基于时间的发布过程,而不是基于特性的大型自由软件项目。Michlmayr也在Google提供了一个该主题的演讲,可以通过Google Video的http://video.google.com/videoplay?docid=-5503858974016723264观看。

第 8 章 管理志愿者

让人们认可项目所需要的,并一同努力实现,不仅仅需要友好的氛围和避免明显的功能异常。需要某个人或一些人有意识的管理所有参与的人。管理志愿者可能不像计算机编程具有同样的技术技巧,但它是一种可以通过学习和实践改进的技艺。

本章是管理志愿者技术的摸彩袋。可能描绘的分量远重于之前的章节,会以Subversion项目作为案例研究,一方面因为我在这个项目工作,所有主要的资源就在手边,也因为砸自家的玻璃总比砸别人更能让人能接受吧。但是我也看到许多其他的项目因为应用这些建议而获益,以及未能应用的后果;当在政治上适合给出这些项目的案例时,我就会这样做。

说到政治,这是在近距离观察以抛弃那些恶毒语言的好时机。许多工程师认为政治只是其他人参与的东西。 “我只是提出对于这个项目最好的过程,但是出于政治原因提出反对。”我相信政治(以及那些认为是政治的事情)的灾难在工程师中特别强大,因为工程师带来的思想中总有些解决方案是客观的优于其他方案。因此,当有人被思考之外的方式激发—例如维护自己的影响,削弱其他人的影响,草率的讨价还价或避免伤害某人的情绪—项目中的其他参与者就会感到恼怒。当然,当关系到他们自己的关键利益时他们也很难避免这样做。

如果你认为”政治“是一句肮脏的词汇,希望你的项目远离它,请放弃吧。当人们需要合作的管理共享资源时,政治是不可避免的。每个人在作出决策时,都会很自然的考虑到决策的结果对自己在项目中影响力的影响。毕竟,如果你像其他程序员一样相信自己的判断和技能,那么未来影响力的降低也可以看作是技术的结果。同样的远离可以应用于其他的行为,从表面上看就是”纯粹的“政治。事实上,没有纯粹的政治:这是因为如果人们把政治作为首要考虑的因素,则行动在实际上会有多重的后果。最终,政治只是决策所要考虑的所有后果的一种承认。如果某个决策的结果可以让绝大多数参与者在技术上感到满意,但是会导致力量对比发生变化,使关键人物感觉自己被孤立,那么后者与前者同样重要。忽略它并不是高尚,只是短视。

就像你后面将要读到的建议,以及你自己工作的项目,请牢记没有人是高于政治的。对于高于政治的企图仅仅是一种特别的政治策略,有时非常有用,但并不现实。当某人有分歧时政治已经出现,成功的项目能够将政治机制建设性的用于管理分歧。

从志愿者中获取最多

志愿者为什么要为自由软件项目工作?[24]

当被询问时,许多人声称自己只是因为希望制作好软件,或希望自己修复所需要的bug。但是这些原因并不是完整的故事。毕竟,你能想象如果没有人欣赏他的工作或倾听他的讨论,这个志愿者还会呆在这个项目吗?当然不会。很明显,人们在自由软件上花费时间的原因不仅仅是单纯的对生产良好代码的渴望。理解志愿者的真实动机将会帮助你能够合理的安排,以确保吸引和保持他们。对生产优秀软件的渴望、在复杂问题上获取的挑战和学习价值也许都是动机。但是人们有与其他人一起工作的内在期望,并在合作活动中提供和获取尊重。从事合作活动的团队必须进化出行为的标准,能够通过帮助团队的活动获取并保持那种地位。

这些标准并不总能自己出现。例如,在一些项目中—资深的开源开发者可以从顶级人员中去除几个人—人们明确的感觉到是通过频繁并详细的发布取得的这种地位。他们并不是偶然得到这个结论;这是因为他们曾经因进行长时间的,复杂的辩论中而得到尊重的回报,即使对项目没有实际的帮助。下面是一些创建氛围的技术,可以让获取地位的活动与建设性活动一致起来。

委派

委派并不仅仅是将工作分散的方法;它也是政治和社会工具。考虑你要求某人做什么事情的所有效应。最明显的效应是如果他接受,就是他完成任务不是你。但是另一个效应则是他意识到你信任他能够处理这个任务。此外,如果你是在公共论坛发起这样的请求,那么他也知道团队中的其他人也表明了对他的信任。他也能感受到需要接受一些压力,这意味着你询问时要使用一种允许他拒绝的方式,如果他确实不想做这个工作的话。如果这个任务需要在项目中协调,你这样做可以有效的提议他更深入的参与进来,形成其他方式无法形成的契约,而且也有可能成为项目某个子领域权威的起源。增加的参与或许令人畏惧,也或者会导致他以其他方式参与进来,例如对于整体承诺的更多感觉。

因为所有这些效应,所以即使你认为你可以完成的更好更快,让其他人来完成也很有意义。当然,也有一个严谨的经济学效率作为论据:或许你自己完成的机会成本太高—在同一时间里你可以完成许多更重要的事情。但即使机会成本的论据并不适应,你还是会希望其他人完成这个任务,因为从长期来看你希望人们更深入的参与到项目当中,即使一开始需要花费更多的时间关注他们。相反的技术也适应:如果你偶然志愿完成其他人不喜欢或没时间完成的工作,你会得到他的友好关系和尊敬。委派和代理并不仅仅是要完成单个任务;他们也是将人们引入到项目核心的方法。

明确区分调查和指派

有时可以很明确的期待某人会接受特定的任务。例如,如果某人编写的代码带来了bug,或者提交的代码明显未能符合项目的指导方针,那么直接指出问题,那么之后你可以认为他会小心避免此类问题。但是在一些情况下,没有明确的方法可以确保你获得期望的行动。这个人可以听你的,也可以不听。因为没有人喜欢被熟视无睹,你需要敏感的察觉到这两种情形的区别,并以此为依据调整你的请求。

你让某人做某事,如果你采用的方式让人感觉这是他理所当然的责任,而实际上他并不是这么想的时,几乎一定会立刻让他们感到非常的厌恶。例如,分配的问题可能会带来很多讨厌的事。项目的参与者通常知道谁是某个领域的专家,所以当出现了bug报告,通常会有大家都知道的一两个人可以立刻快速的修正它。然而,如果你没有得到先前的许可就将问题分配给她,她会感觉自己处于一个不舒服的地位。她会感受到这种被期望的压力,而且感觉她是由于其专业技能而被惩罚了。毕竟,获取技能的方法就是通过修正bug,所以某人会接受这个问题!(请注意,在问题跟踪系统中根据bug报告的信息自动分配的问题通常并不太冒犯,因为每个人知道分配是自动的过程,并不代表人们的预期。)

虽然应该尽可能将负担均匀的分配,但有时你需要鼓励能够以最快速度修正bug的 人。考虑到你可能无法承受为每个这种分配进行这种交流的负担(“你愿意看一下这个bug吗?” “可以。” “好的,一会儿吧这个问题分配给你。” “好的。”),你应当以询问的形式进行分配,不要传递出任何压力。事实上所有的问题跟踪系统都允许为任务分配的问题作出评论。在那个评论中,你可以这样说:

把这个分配给你,jrandom,因为你可能是最熟悉这些代码的。如果没时间,尽管踢回来。(如果你想在以后接受这中请求,请让我们知道。)

请求完成工作与某人接受工作有明显的区别。在这里观众不仅仅是被分配工作的,而是所有人:整个团队可以看到被安排工作的人的专业技能得到了公开的确认,但是这些信息也明确的表明他可以自由的接受或者拒绝这种责任。

指派后要继续跟踪

当你要求某人做一些事情时,请牢记所做的,并无论如何要继续跟踪他。大多数请求是在公共论坛中做出的,形式大体上类似“你能处理一下X吗?我们只是要获知;如果你不行,那么没问题,我们只需要知道。 ”不一定会得到回应。如果你得到的回应是负面的,则环路可以关闭—你需要尝试其他的策略来处理X。如果有正面的回应,那就需要继续关注这个问题的进展,并为可见和不可见的进展作出评论(当知道其他人会欣赏他的作品时,每个人都会做的更好)。如果几天内没有回应,可以再次询问,或者发表文章说明你没有得到回应,希望找其他人做这件事。或者直接自己完成,但也要说明最初的询问未能获得回应。

公开提示缺乏回应的目的并不是要羞辱任何人,你的评论一定不要造成这种效果。目的仅仅是说明你还在跟踪自己征求的问题,而且你已经注意到了一些反应。这样做可以增大人们在下一次说同意的机会,因为他们会知道(即使只是无意的)你会注意到他们所做的任何工作,包括许多不太起眼的,人们会忽略的事件。

通知感兴趣的人

另一件可以让人们高兴的事情就是通知他们所感兴趣的事情—通常情况下,你注意到并记住某人的个性方面越多,他会越觉得舒适,他也就越会希望参与你的团队一起工作。

例如,在Subversion项目有一个非常有明显区别的划分,期望达到决定性的1.0发布的人,和那些主要希望添加新特性,并完成感兴趣的问题,但对1.0并不太关心的人。两者的地位相当;他们只是不同类型的开发者,都在项目中完成了大量工作。但是很快认识到我们绝不能假设所有的人都是由1.0发布的喜悦所驱动的。电子媒介可能很有迷惑性:在你感觉到共同目标的氛围中,实际上只是你与谈过话的人有共同的目标,而其他人则有完全不同的优先级。

你对人们对于项目的期望了解越多,你就越能有效发出请求。即使仅仅是描述一下他们所期望目标的理解,甚至不必发出任何相关的请求,也非常有用,这样可以确保所有人不仅仅是无差别群众中的粒子。

赞扬和批评

赞扬和批评并不矛盾;在大多数情况下,是类似的。都是关注的形式,越是明确就越有效。二者必须在牢记实在目标的情况下实施。两者都有可能因为夸大而削弱:赞扬过多或太频繁会使赞扬贬值;对批评也是同样,尽管在实践中,批评通常会有反作用,因而更加不容易贬值。

一个重要的技术文化特性是将详细的,不带偏见的批评当作一种赞扬(正如在第 6 章 交流“识别无礼”一节中所讨论的),因为这隐含了接收者的工作值得花时间去分析。然而,两种条件—详细的不带偏见的—必须同时满足。例如,如果某人对代码做了些马虎的修改,如果只是说“很马虎”是毫无用处(而且通常是有害的)的。马虎最终是的一种特性,而不是作品的,应该将反应集中到作品上。更有效的方法是描述变更中所有错误的地方,巧妙而无恶意。如果这是某人连续第3,或者第4次作出疏忽的修改,则可以再说一次这些事—不必发怒—批评的最后,要清楚的说明同样的模式早已经被注意到了。

如果某人对于批评不做任何改进,解决办法不应该是更多或更强的批评。对于团队来说,解决方法是将这个人从不能胜任的位置删除,并尽可能使用一种不会造成情绪伤害的方法;见“转化”一节本章后面的例子。但实际上,这种情况通常很少发生。大多数人可以很好的回应批评,当然批评必须要特定,详细并有明确的(即使没有说出来)改进预期。

赞扬不会伤害任何人的感情,但并不意味着使用时可以不像批评那样小心。赞扬是一种工具:在使用之前,要问自己为什么你希望使用它。作为一条戒律,不应该因为人们经常做的事情,或正常的和参与到团队中应当要做的行动赞扬他。如果你这样做,估计就停不下来了:你因为普通的事情而赞扬每个人?毕竟,如果你漏掉了某人,他们会问为什么。如果能珍惜你的赞扬和感激会更好,要针对不寻常或意料之外的努力,以鼓励此类努力为目的。当某个参与者永久的进入了更高生产力的状态,要根据此人调整赞扬的阀值。对普通的行为进行反复的赞扬会变得毫无意义。相反,这个人也应该感觉到自己较高的生产力水平已经是正常和自然的,只有超出这个范围的才会被特别关注。

当然,这并不是说不应该感谢某人的贡献。但是请牢记,如果项目设置正确,这个人做的任何事情都会看到,所以这个团队会知道(这个人也会知道团队中的其他人所知道的)所有她所做的。除了直接的赞扬,我们也有其他的方法感谢某人的工作。你也可以采用曲折战术,在讨论相关主题时,她已经给定领域做了许多工作,成为了领域专家;你可以公开的向她咨询代码的问题;或者更有效的,你可以大张旗鼓的进一步利用她的工作,这样她就会为别人依赖于她的工作结果而感到舒服。通常不必在这些问题上精打细算。那些有规律的为项目作出贡献的人知道自己会自然的得到有影响的地位。通常没有必要为此采取明确的步骤,除非你感觉到无论出于什么原因,贡献者都无法得到正确的评价时。

防止割据

请留意那些试图在项目中独占某一领域,或希望完成某一领域所有工作的参与者。此类行为已开始看起来很健康。毕竟,在表面上似乎是某人在肩负更多的责任,并展示在特定领域增长的活动。但从长期来看,则并没有建设性。当人们感觉到“禁止入内”的标志时,他们就会离开。这种结果会减少这个领域的检查,会使之更加脆弱,因为孤单的开发者成为失败的单独一点。更严重的,它会削弱项目的合作,平等精神。理论上应该欢迎任何开发者在任何时间帮助完成任何任务。当然,在实践中会有些不同:人们在不同领域的影响总有差别,非专家通常与项目特定领域的专家不同。但关键是这都是自愿的:非正式的权威是根据竞争性和证明的判断能力赋予的,而不可以主动的获取到。即使某人期望的权威是能够胜任的,仍然需要她非正式的保持权威,通过团队的共识和那种永远不会将其他人排除在该领域之外的权威。

当然,因为技术原因反对或编辑某人的工作则是完全另外一回事。决策因素是工作的内容,而不应该是谁恰好是守门人。也许也是同一个人完成恰好完成了最多的工作,但只要他没有阻止其他人完成这个工作,就没有问题。

为了对抗地方主义的萌芽,许多项目采用禁止在源代码文件中包含作者名或维护者签名的方法。我完全认可这种实践:我们在Subversion项目中也遵循这个方法,这也算是Apache基金会的一种正式政策。ASF成员Sander Striker是这样做的:

在Apache软件基金会中我们不鼓励在源代码中使用作者标签。除了法律分歧以外,还有多方面的原因。协作开发是以一个团队一起工作,将整个项目看作一个团队。给予信誉非常好,必须有人这么做,但是必须使用不会允许错误归因的方式,即使是通过暗示的方式。何时添加或删除作者标签没有明确的标准。在你修改注释后添加你的名字?或者是添加了一行的修正?在你重构了代码,改变了95%时就可以删除其他作者的标签?当人们去接触每一个文件,修改足够多的内容以达到名字标签的限额,这样他们的名字就会出现在每个地方时,你会怎么做?

提供信誉可以有更好的办法,我们推荐这些。从技术观点上讲,作者标签并不是必需的;如果你希望知道哪个人写了某段代码,版本控制工具可以提供。作者标签也经常失去时效性。你希望被私下咨询5年前编写,而且已经希望遗忘的代码?

软件项目的源代码文件时身份的核心。必须要反映整个开发社区为此负责,而不仅仅是简单的各自的封地。

人们有时会为源代码中作者或维护者标签的风格而争论,他们认为这些东西是所做工作的可见信誉。这种论点有两个问题。首先,不可避免的要面对多少工作量才可以进入这个列表的尴尬问题。其次,这样会将信誉的问题与权威合并了:过去曾经完成了工作并不意味着对于曾经工作区域的所有权,但是如果单个人的名字出现在源文件的顶部,想避免这种暗示就变得几乎不可能。在任何情况下,信誉信息都可以从版本控制日志和其他诸如邮件列表归档等外带机制中获取,所以在源代码文件中禁止其出现不会损失任何信息。[25]

如果你的项目禁止在源代码文件中包含姓名,请务必不要过分执着。例如,许多项目会有一个保存小工具和辅助脚本的contrib/区域,通常由与本项目不相关的人编写。这些文件可以包含作者姓名,因为他们完全不是由项目维护的。另一方面,如果贡献的工具被项目的其他人修改了,最终你希望将其从孤立的位置移出,如果原始作者许可,就可以删除作者名称,这样代码就像其他社区维护的资源一样了。如果作者对此有些敏感,折衷的方案也是可以接受的,例如:

# indexclean.py: 从Scanley索引删除旧数据。
#
# 原始作者: K. Maru <kobayashi@yetanotheremailservice.com>
# 现在维护者: Scanley项目组<http://www.scanley.org/>
#                    和K. Maru。
# 
# ...

但是最好避免此类折衷,如果可能,大多数作者会被说服,因为他们都会乐于自己的贡献更紧密的成为项目的一部分。

重要的是请牢记项目的核心和外围是一个连续体。项目的主要源代码文件显然是核心部分,会被认为应当是由社区维护的。在另一方面,伙伴工具或一些文档则可能是单独某个人的作品,始终独自维护,即使这些作品是与项目关联,甚至是与项目一起分发的。没有必要应用一个适用于所有文件的规则,只要坚持社区维护的资源不允许成为个人领土的原理就可以了。

自动化率

努力不让人做机器可以做的事情。作为一种经验法则,将一项工作自动化花费的工作量即使十倍于手工执行也是值得的。对于非常频繁或复杂的任务,这个比率可以轻松的达到20倍或更高。

将自己想象为“项目管理员”,而不仅仅是开发者,可能是一个有效的态度。有时,单个开发者会过于沉溺于较底层次的工作,而无法看到全局图并意识到每个人都在手工执行自动化任务上浪费了大量精力。即使那些意识到的人也可能不会花时间解决问题:因为每个个体都不会感觉此类任务是一个巨大的负担,没有人已经厌烦到要为此做些什么。使自动化如此引人注目的是每个很小的负担需要乘上每个开发者执行的次数,然后还要乘上开发者的数量

这里,我广泛的使用的术语“自动化”,并不仅仅是重复每次只需要修改1到2个变量的动作,而且包括任何辅助人们的技术基础架构。最低标准的自动化需要按照第 3 章 技术基础设施中描述的方式运行一个现在的项目,但是每个项目也都有自己的特殊问题。例如,一组编写文档的人会希望有一个网站能够在任何时间都显示最新版本的文档。因为文档通常由如XML的标记语言编写,会有一个编译步骤,通常非常复杂,包括创建可显示或可下载的文档。组织这种会在每次提交时进行此类编译的网站可能会有点复杂和花费时间—但是这样很值得,即使这要花费你一天或更多的时间。拥有最新网页的整体收益是巨大的,即使没有的代价仅仅是每个开发者需要每次多一些很小的烦恼。

进行这种步骤不仅仅可以消除时间的浪费,也可以确保消除在执行手工操作时步骤出错(不可避免的会发生)时的痛苦和沮丧。多步的,确定的操作恰好是发明计算机的目的;将人们拯救出来可以做更有意义的事情。

自动测试

自动测试对任何软件项目都有用,特别是开源软件项目,因为自动测试(特别是回归测试)可以让开发者舒服的修改自己不熟悉的代码,因而鼓励了探索性的开发。因为手工检测损坏是这样困难—需要从本质上猜测可能损坏的事情,而且必须尝试多种实验证明其没有损坏—通过自动化方法检测这种损坏为项目节省了大量时间。它也可以让人们可以更放松的大幅度重构代码,从而对软件的长期可维护性贡献良多。

回归测试并不是万能药。首先,它非常适于批量样式界面的程序。对于主要使用图形用户界面操作的软件很难程序化驱动。回归测试的另一个问题是测试套框架本身可能非常复杂,自己有一定的学习曲线和维护负担。减少这种复杂性是你可以做的一件非常有用的事,即使这需要花费相当多的时间。将新测试添加到测试套越简单,就会有越多的开发者这样做,发布中漏网的bug也就会越少。在使测试更简单上的努力将会在项目的生命周期中得到成倍的回报。

许多项目有一个“不要破坏构建!”的规则,意思是:不要提交会使软件不能编译或运行的变更。成为破坏构建的人通常会导致温和的窘迫和取笑。拥有回归测试套的项目通常有一个推论的规则:不要提交会导致测试失败的任何变更。如果整个测试套会自动每夜运行,随着结果发送到开发列表或专门的测试套列表,这类失败可以轻松定位;这是自动化价值所在的另一个实例。

大多数志愿开发者会愿意用额外的时间编写回归测试,只要测试系统是可理解的并易于使用。变更搭配测试可以理解为一种责任,也是协作的一种简单的机会:通常要由两个开发者分担bug修正的工作,其中一个编写修正本身,另外一个编写测试。后一个开发者通常要以更多的工作结束任务,因为编写测试并没有实际的修正那样让人愉悦,测试套不应当使测试体验超出本来应有的痛苦。

一些项目走的更远,每个bug修正或新特性都要伴随新的测试。这是否是个好主意取决于许多因素:软件的特性,开发团队的组成和编写新测试的难度。CVS(http://www.cvshome.org/)团队一直有这样一个规则。在理论上这是一个好政策,因为CVS是版本控制软件,所以非常希望规避处理或误处理用户数据可能性的风险。问题是在实践中CVS的回归测试套是一个单独的巨大shell脚本(好笑的是叫做sanity.sh),难于阅读,也难于修改或扩展。增加新测试的难度,以及对于新增补丁必须包含测试的要求,决定了CVS有效的阻碍了补丁。当我在CVS上工作时,我见过有人着手,甚至完成了一个CVS自己代码的补丁,但是当被告知需要在sanity.sh增加新测试时则放弃了。

编写新的回归测试比修正原来的bug花费更多的时间非常正常。但是CVS将这种现象发挥到了极致:一个人需要花费数小时才能正确的设计自己的测试,但仍然得到错误的结果,因为修改这样一个35000行的Bourne shell脚本有太多不可预测的复杂情况。即使是长期的CVS开发者也会为增加新测试而感到郁闷。

这种情况源于我们对于自动化比率考虑的失败。转换到一个真正的测试框架—无论是自定义的还是成品的—都会成为一种主要的动力。[26]随着时间的推移,这种忽视给项目带来更多的代价。有多少bug修正和新特性未能进入现在的CVS,仅仅因为这尴尬的测试套的阻碍?我们不知道精确的数量,但是一定远大于开发者为了开发新测试系统(或集成一个成品的系统)而会放弃的bug修正或新特性数量。这个任务只会耗费有限的时间,但如果无动于衷,则使用现有测试套的惩罚将会永远持续下去。

重点不在于强制编写测试是错误的,也不是说编写Bourne shell脚本的测试系统必然是不好的。它可能工作的很好,这取决于你的设计和测试的需要。重点仅仅是说当测试系统成为开发的明显障碍时,必须要有行动。同样的道理适用于所有成为障碍或瓶颈的常规过程。

将每个用户当作潜在的志愿者

与用户的每次交流都是发展新志愿者的好机会。当一个用户花时间在项目邮件列表上发表文章或报告bug时,他已经认为自己比大多数用户(那些项目永远听不到回音的人)有更大参与的可能。紧跟这种潜力:如果他描述了一个bug,感谢他的报告,并询问他是否有兴趣自己修正它。如果他说FAQ中漏掉了一项重要问题,或者程序的文档有些不足,请坦率的承认问题(假定确实存在),并询问他是否有兴趣自己编写遗失的材料。很自然,大多数时候这个用户不会同意。但是多问一句也不累,而且只要你每次都这么问,也会提醒论坛中的其他听众参与到项目当中是每个人都可以做的。

不要将你的目标限制在新开发者和文档编写者上。例如从长期来看,即使训练人们编写优秀的bug报告也是值得的,如果你没有在每个人身上花费多时间,而且如果在将来继续提交更多的bug—如果第一次报告时能获得建设性的互动,以后更有可能这么做。建设性的互动不必是对于bug的修正,尽管那样是理想的;它可以仅仅是一种要求更多信息的恳请,或仅仅是那种行为bug的确认。人们希望被倾听。其次,他们希望自己的bug被修正。你可能无法一直及时的给予后者,但你(或者说整个团队)可以给他们前者。

一个推论就是开发者不能向出于好意提出含糊bug报告的人们表现出愤怒。这是我个人很气恼的事情。我在许多不同的开源邮件列表中看到许多开发者一直这样做,危害是显而易见的。一些倒霉的新手会发布无用的报告:

嗨,我没法运行Scanley。每当我启动它,就会报错。有人遇到过这个问题吗?

一些开发者—可能已经遇到此类报告几千次了,但丝毫不考虑这个新手从未遇到过—会这样回复:

这么点信息我们能怎么做?天呐。请给点细节,例如Scanley的版本、你的操作系统和错误信息。

开发者无法从用户的角度看待事物,也未能考虑到这种反应对于观看这种交互的其他人的效果。很自然,对于没有编程经验的用户,之前没有报告bug的经验,当然不知道如何编写bug报告。对于这种人该怎样正确处理呢?教育他们!要使用会促使他们回来获取更多信息的方式:

很遗憾你遇到了困难。我们需要更多信息才能找出发生的问题。请告诉我们Scanley的版本,您的操作系统和错误的精确文本。最好能提供一份你所运行命令的脚本,以及对应的输出。更多信息请看http://www.scanley.org/how_to_report_a_bug.html。

这种从用户那里榨取信息的响应方法远谈不上有效率,因为它是从用户的角度编写的。首先,它展示了同情:你遇到了问题;我们也感到痛。(即使在bug报告回应中也不是必须的;这取决于问题的严重程度以及感觉到的用户的伤心程度。)其次,没有对她不知如何报告bug表示轻视,而是告诉她如何,以及怎样的详细程度才会实际有效—例如,许多用户并不理解“请给些细节”的意思是“展示错误的精确文本”,不要遗漏或删节。当你第一次与这样一个用户工作时,你需要说明这些。最后,应该提供到更加详细和完整的报告bug指导的链接。如果你成功的让用户感觉在为她考虑,她通常会花时间阅读该文档并按照你所说的去做。当然,这通常意味着你需要预先就准备好文档。必须说清楚哪种类型的信息是开发团队在每个bug报告中希望看到的。理想情况下,可能需要通过回应多个这样的用户,逐渐的查漏补缺,使之更好地为项目服务。

Subversion项目的bug报告指导可以说是这类形式的标准案例(见附录 D, 报告bug的样例指导)。请注意他们是如何以请求提供一个bug的补丁或修正结束的。这不是因为这种请求将会导致更高的补丁。报告率—大多数能够修正bug的用户都知道如果能提供补丁会受到欢迎,无需告知他们。请求的真实目的是为了向所有读者,特别是刚来到项目,或者刚来到自由软件的人强调,这个项目是通过志愿者的贡献运营的。这是许多新用户通常不熟悉的一个关键点。一旦他们意识到这一点,他们就更有可能在发生时帮助完成修正,即使不能提供代码,也会提供更完整的重现步骤,甚至是为其他人发布的内容测试修正。目标是让每个用户认识到他们和为项目工作的人没有天生的区别—问题只是他们能投入多少时间和力量,而不在于是谁。

对于愤怒回应的告诫不能适用于粗暴的用户。偶尔会有一些人会发送毫无信息量的bug报告或投诉,表现对项目某些失误的蔑视。通常此类人会在轻蔑与谄媚之间转换,例如Subversion邮件列表的这个人:

为什么几乎6天了还没有Windows平台的二进制程序?!?每次都是同样的故事,确实让人灰心。为什么这类工作就不能自动化,可以立刻出现。??当你发布“RC”构建时,我想你们的意思的是让用户测试构建,但是你们没为此事做任何事。如果你们没提供测试方法,又何必搞一个浸润期??

对于这种激动文章的最初回应是令人吃惊的克制:人们指出该项目有自己的发布政策,不会提供官方的二进制文件,并告诉他如果要改变恼人的程度,他应该志愿自己编译代码,如果真的对他很重要的话。相信与否,这段话属于他的下一次发布:

首先,我要说我认为Subversion很彪悍,很感谢每个参与者的努力。 [...]

...然后他再次继续为项目没有提供二进制,现在仍然没有志愿者做这件事而斥责项目。之后,大约50人跳了出来,我必须说我确实注意到这一点了。在第 2 章 起步“防无礼于未然”一节提出的,针对粗鲁行为的“零容忍”政策,已经潜移默化的应用到每个人的交互中。但是,当人们认清他一开始就要当一个喷子时,没人能给他好脸色。

很幸运,这些情形非常罕见,很少需要被项目特别关注,并投入力量去保持用户建设性的和有礼貌的交互。

像分担技术任务一样分担管理任务

运行项目时要像分担技术负担那样分担管理负担。随着项目的成长,就会有更多关于管理人员和信息流程的工作。没有道理不分担这些负担,这并不一定需要一种自顶向下的阶级组织—实践中更多是同级的网络拓扑结构,而不是军队式的命令结构。

有时管理角色是正式的,有时则是自然发生的。在Subversion项目中,我们有一个补丁管理员,一个翻译管理员,文档管理员和问题管理员(尽管是非正式的)以及一个发布管理员。有时这些角色是经过认真考虑才开始的,而有些则完全是自发的;随着项目的成长,我相信会增加更多的角色。下面我们会详细审视这些角色,以及一些其他的角色(除了在本章前面“发布经理”一节“发布所有者独裁”一节中介绍的发布管理员)。

就像你看到的角色描述,请注意没有人独占控制其所在领域。问题管理员并没有防止其他人在问题数据库中做出修改,FAQ管理员也不必是编辑FAQ的唯一人选。他们的角色都是非垄断的责任。每个领域管理员所作工作的重要组成部分是提醒在该领域工作的人,训练他们按照管理员的方式工作,这样多种力量就可以互相加强,而不是发生冲突。领域管理员必须记录他们工作的过程,这样当他们离开时,别人就可以立刻接班。

有时会发生一种冲突:两个或更多的人希望同一个角色。现在没有人处理这件事。你可以建议每个志愿者写一个计划(一个“申请”),让所有的提交者选出最佳。不过这样有些笨拙,而且可能有些尴尬。我发现最好的方法只是告诉多个候选者自己处理。他们通常能够,也会更满意自己得出的结果,而不是别人施加的结果。

补丁管理员

在一个接收许多补丁的自由软件项目,跟踪到达的补丁以及所做的决定会成为一场噩梦,特别当通过非集中方式完成时。大多数补丁是以邮件的形式出现在项目开发列表(尽管可能有些最早出现在问题跟踪系统,或外部站点)的,在补丁到达时有许多不同的处理补丁的例程可以选择。

有时,某人评审了补丁,发现了问题,然后踢回给原作者整理。这通常会导致一个交互过程—都在邮件列表中可见—原始的作者一直发布修正的补丁版本,直到评审者无法找到更多的问题。有时很难说清楚这个过程已经结束:如果评审者提交了补丁,则可以说整个周期已经结束。但是如果她没有,或许仅仅因为她没有时间,或者没有提交权限,而且无法拉其他开发者做这件事。

另一个对补丁的常见回应是轻快的讨论,不必是针对补丁本身,而是关于补丁之后的概念。例如,补丁可能修正了一个bug,但项目希望用另一种方式修正这个bug,作为解决一个更普通类型问题的一部分。通常一开始这都是未知的,只是补丁激发了探索。

偶然情况下,发布的补丁可能会遇到完全的沉默。通常是因为没有开发者有时间在那个时刻去评审这个补丁,都希望其他人能去做这件事。因为每个人等待其他人捡起这个球的时间并不一定,而其他优先的事情不断出现,很容易会造成补丁被漏掉的情况,但这是任何人都不会希望发生的事情。项目可能以这种方式错误可用的的补丁,也有其他有害的副作用:会打击作者,他为补丁做了许多工作,让他觉得整个项目难以靠近,特别是对于其他考虑编写补丁的人。

补丁管理员的工作就是确保补丁不会漏掉。这是通过跟踪每个补丁的稳定状态实现的。补丁管理员观察邮件列表中每个由提出补丁引发的线索。如果最终以补丁的提交完成,他不需要做任何事。如果进入了评审/修正迭代,以补丁的最终版本结束,但是没有提交,他发起一个指向最终版本以及相关邮件列表的问题,这样之后跟进的所有开发者都有了一个永久的记录。如果补丁定位了一个现有的问题,他会将相关信息注释到该问题,而不会开一个新事物。

如果某个补丁没有回应,补丁管理员应该等待几天,然后询问是否有人会去评审它。通常会有响应:某个开发者会解释她认为该补丁不必应用,然后给出原因,或者她会去评审它,。如果还是没有回应,补丁管理员可以发起,也可以不发起一个补丁的问题,要根据他自己的判断,但至少最初的提交者得到了一些回应。

拥有一个补丁管理员为Subversion开发团队节省了大量时间和心力。如果没有指定的人负责,每个开发者需要一直担心“如果我没有时间现在回应补丁,我能指望别人做吗?我是否要一直盯着? 但如果有别人盯着,同样的原因,这样是否是没必要的重复。” 每个开发者在第一次看到这个补丁的时候都要做这样的决定。如果她希望跟进评审,她就可以这样做—补丁管理员会根据情况调整他的行为方式。如果她希望完全忽略这个补丁,也没问题;补丁管理员会确保它没有被遗忘。

因为这个系统只有在补丁管理员不发生失误的情况下才能运作正常,所以这个角色必须正式任命。在Subversion,我们在开发和用户邮件列表中广而告之,得到了许多志愿者,并选了第一个回复的。当那个人请辞后(本章后面的“转化”一节),我们重复了这个步骤。我们一直没有试图让多个人分担这个角色,因为他们之间会需要交流的负担;但是如果补丁提交的规模更大,则一个多头的补丁管理员就会有意义。

翻译管理员

在软件项目中,“翻译”可能指的是两件完全不同的事。它可能指的是将软件文档翻译为其他语言,或者指的是翻译软件本身—也就是让程序使用用户选中的语言显示错误和帮助信息。两者都是复杂的任务,不过一旦建立了正确的基础架构,则可以很大程度上与其他开发分离。因为这些任务非常类似,所以设置一个单独的翻译管理员处理两部分任务就非常有意义(取决于你的项目),亦或者更好的方式是设置两个不同的管理员。

在Subversion项目,我们有一个处理两部分的翻译管理员。他自己并不编写翻译,当然—他可以帮助一两个,但是在写这些话时,如果他希望与他们所有人一起工作,他需要讲10种语言(12种方言)。因而,他管理志愿翻译者:他帮助他们互相协调,以及他们团队与项目其余部分的协调。

设置翻译管理员的一个原因是翻译者是与开发者不同的人。他们有时只有有限的甚至没有任何在版本控制版本库中工作的经验,也没有与分布式志愿团队一起工作的经验。但在另一方面,他们通常是最好的一类志愿者:拥有特定领域知识,可以看到需求,选择参与进来。他们也通常愿意学习,对工作充满热情。所需要只是有人告诉他们如何做。翻译管理员确保翻译不会没必要的干扰日常的开发。每当开发者必须被告知需要为支持翻译工作提供技术变更时,他也要作为翻译者作为一个统一整体的代表。

因此,这个位置最重要的技能是外交能力,而不是技术能力。例如,在Subversion我们有一个政策,每种语言的翻译都必须至少有两个人正在参与,否则,就没有人可以检查文本。譬如说,有新的志愿者请求提供Subversion马达加斯加语翻译时,翻译管理员必须提示他去与六个月前某个表达过马达加斯加语翻译意向的人建立联系,或者有礼貌的询问志愿者去寻找另一个马达加斯加翻译者与其搭档工作。当有了足够的人手,管理员就可以为他们设置正确的提交访问权限,告知他们项目的惯例(例如如何编写日志文件),然后紧盯他们是否遵循了这些惯例。

翻译管理员和开发者之间,以及翻译管理和翻译团队之间的对话通常使用项目原先的语言—也就是所以翻译的源语言。对于大多数自由软件项目,就是英语,但是是什么语言并不重要,只要项目认可即可。(对于希望吸引广泛国际开发社区的项目,英语可能是最好的语言。)

在特定翻译小组中的对话通常使用它们共享的语言,然而翻译管理员的另一个任务就是为了每个团队设定一个专门的邮件列表。通过这种方式,翻译者可以自由的讨论他们的工作,而不会打扰项目邮件列表中的人,他们可能根本不理解他们的翻译语言。

文档管理员

保持软件文档的实效性是一项无法结束的任务。每个进入代码的新特性或改进都可能会导致文档的变更。另外,一旦项目文档达到了一定级别的完整性,就会发现许多人发来的补丁是针对文档的,而不是代码。这是因为许多人是在文章中修正了bug,而不是在代码中:所有的用户都是读者,但仅有少数是程序员。

文档补丁通常比代码补丁更易于检查和应用。仅需要少许或无需测试,而且可以快速的通过检查评价变更的质量。因为数量很多,但是检查的负担相对较低,文档补丁中有效工作的管理负担比率远比代码补丁高。此外,大多数补丁需要一些调整,才能保持文档中作者语气的一致性。在大多数情况下,补丁通常会覆盖或影响其他补丁,在提交之前需要根据之间的关系进行调整。

出于处理文档补丁的紧迫性,以及需要持续监控代码基以便保持文档的实效性,有必要让某个人或一个小组专门从事这项任务。他们需要精确的保存文档在何处滞后于软件的记录,而且他们可以用一种整体方式的实践步骤来处理大量的补丁。

当然,这样不会阻碍项目中的其他人在工作中应用文档补丁,特别是时间允许时一些小的补丁。同一个补丁管理员(见本章前面提到的“补丁管理员”一节)可以同时跟踪代码和文档补丁,当开发和文档团队希望时完成它们。(如果补丁的总数已经超出了单个人可以跟踪的容量,最好的一个步骤可能就是将补丁管理员分为代码和文档。)文档团队的关键是使人们把保持文档组织性、实效性和一致性当作自己的责任。在实践中,这意味着对于文档的熟悉,关注其他人提交给文档的变更,关注到来的文档补丁,并使用所有这些信息源完成保持文档健康的所有必要工作。

问题管理员

项目bug跟踪系统中问题的数量是随着使用产品的人数同比例增加的。因而,即使你在一个快速成长的健壮程序中修正bug并装运,您还是会看到大量开放的问题漫无边际的产生。重复问题,以及不完整或描述糟糕的问题也会频繁发生。

问题管理员通过关注进入数据库的信息,定期的清除特定问题有助于缓和这种问题。他们的大多数常见行为可以修正进入的问题,一方面因为报告者未能正确的处理部分字段,另一方面也因为问题与数据库中的一个问题已经重复。很明显,问题管理员对项目bug数据库越熟悉,他就越能有效率的检测到重复问题—这也是设置一小部分人专门关注bug数据库,而不是让每个人都特别参与其中的原因。当团队试图按照非集中式的方式完成这项任务时,就不会有任何一个人具备对于数据库内容的深入专业知识。

问题管理员可以帮助我们映射问题和个别开发者。当有大量bug报告进入时,不是每个开发者会以平等的态度读取问题通知邮件列表。然而,如果某人知道开发团队紧盯着所有进入的问题,她可以将注意力放到特定合适的bug上。当然,这需要对项目所有开发的事情,接受者期望和性情都很敏感。因而,问题管理员最好也是开发者的一分子。

取决于你的项目如何使用问题跟踪系统,问题管理员也可以调整该数据库以反映项目的优先级。例如,在Subversion我们将问题排入未来的特定发布,这样每当有人询问“某个bug X何时可以修复时?”我们可以说“之后的两个发布,”即使我们不能说出确切的日期。这个发布在问题跟踪系统中以目标里程碑的形式展示,也就是IssueZilla中的一个字段。[27]作为一个规则,每个Subversion发布都有一个新的特性和一组特定的bug修正。我们为该发布的所有问题赋予一个合适的目标里程碑(包括新特性—它也会得到一个问题),这样人们就可以通过发布计划查看bug数据库。这些目标很少情况下会保持静止。随着新bug的到来,等级会发生切换,而且有些bug必须移到另一个里程碑,以保证每个发布的可管理性。再次,最好由对项目数据库的内容以及问题之间的关系有着整体意识的人完成。

问题管理员的另一项值得关注的任务是管理废弃的问题。有时,某个bug会因为软件一个不相关变更而意外的修正,或者有时项目对于特定行为是否为bug的意见发生改变。寻找废弃的问题并不简单:唯一的系统方法是清理数据库中的所有问题。随着问题数量的增长,完全的清理会变得越来越不可行。在达到某个点时,保持数据库健康的唯一方法就是分而治之:根据进入数据库的情况将问题分类,并直接分配给合适的开发者或团队。然后接受者负责问题余下的工作,根据需要决定是解决还是废弃。如果数据库足够大,问题管理员的工作就更倾向于协调,将会花费较少的时间用于自己查找问题,而是花更多的时间使之到达正确的人手中。

FAQ管理员

FAQ维护是一项出人意料的困难工作。项目中其他文档的内容都是由作者预先计划得到的,而FAQ则完全是被动的文档(见维护FAQ)。无论它变得如何巨大,你永远不知道何时会再一次添加。而且因为它总是零零散散的添加,它很容易变得不够一致并缺乏组织,甚至会包含重复的或半重复的条目。即使它没有任何此类的明显问题,项目之间也通常会有不引人注目的互相依赖—必须有链接,但是没有—因为与关联的项目添加的时间相差一年。

FAQ管理员的角色是双重的。首先,通过至少对所有问题的标题保持熟悉,她维护了FAQ的整体质量,这样每当有人添加的新条目与原来的条目重复或者相关,可以作出合适的调整。其次,她关注着项目的邮件列表和其他论坛中重复发生的问题或疑问,并根据这些输入编写新的FAQ条目。后一项工作可能非常复杂:必须能紧跟线索,识别出其中的核心问题,发表一个提议FAQ条目,组合来自其他人的评论(因为FAQ管理员不可能是FAQ包含的所有主题的专家),并感知何时结束这个过程并将其添加到FAQ。

FAQ管理员通常也会成为FAQ格式的默认专家。有许多保持FAQ结构的小细节(见第 6 章 交流“将所有的资源视为归档”一节);当某人编辑了FAQ,他们可能会忘记这些细节。但只要FAQ管理员能够在之后查漏补缺,这样便没有任何问题。

许多自由软件可以用于辅助维护FAQ的过程。只要能够保证FAQ的质量,就可以选一个来使用,但是要避免过度自动化。一些项目试图完全自动化FAQ维护的过程,使用类似wiki的模式允许每个人贡献和编辑FAQ条目(见第 3 章 技术基础设施“Wikis”一节)。我曾经遇到过在Faq-O-Matic上发生的这种情况(http://faqomatic.sourceforge.net/),尽管我看到原因仅仅是对Faq-O-Matic超出本来目的的滥用。在任何情况下,虽然完全的分布式FAQ维护可以减少项目的负担,但也会导致较差的FAQ。没有人具备整个FAQ的广泛视野,没有人注意到了哪个条目需要更新或变得完全不可用,每个人看到的都是孤立的条目。结果是FAQ经常会无法为用户提供他们所需要查找的东西,甚至会误导他们。您可以使用任何必须的工具维护项目FAQ,但是不要因为工具便利性的诱惑而损害FAQ的质量。

见Sean Michael Kerner在http://osdir.com/Article1722.phtml的文章The FAQs on FAQs,描述和评估了开源FAQ维护工具。

转化

一次又一次,某个位置上承担责任的志愿者(例如补丁管理员,翻译管理员等)无法执行该位置的责任。这可能是因为出现了超出他预期的工作,或者完全因为是许多外部因素:结婚、孩子出世、新的老板等等之类的。

当一个志愿者陷入这种境地,他通常不会立刻注意到。可能以很小的程度发生着变化,而且没有一个时刻可以自觉的认识到他已经无法完成这个角色的任务。相反,项目中的其他部分只是发现有一段时间未能听到他的消息了。然后他们会会立刻匆忙行动,而他则觉得长时间对项目的怠慢是有愧的,并立刻连夜赶工。然后就有更长的一段时间你无法听到他的消息,然后可能是或可能不是另一场慌乱。但是,很少有主动提出的正式辞职。志愿者用自己的业余时间工作,辞职意味着公开承认他的业余时间被永久的减少了。人们通常不愿意这样做。

因而,需要你和项目中的其他人发现发生的事情—或者说发现没有发生—,并能够询问哪个志愿者可以继续。这种询问必须是友好和100%无内疚的。你的目的只是找出真相,而不是让人难过。通常情况下,这个询问应当对项目的其他人可见,但是如果你知道一些必须私下进行的原因,也没有问题。公开进行的主要原因是如果志愿者回复说无法完成工作时,就可以为你的下一次公开发布提供一个上下文环境:请求一个新的志愿者完成该角色。

有时,一个志愿者无法完成其接受的工作,但是没有意识到或不希望承认这个事实。当然,任何人在一开始都会遇到困难,特别是当责任很复杂时。然而,如果某人不努力完成他接受的任务,即使所有人都给出全部的帮助和建议,最后唯一的解决方法只能是他放弃并让其他人来尝试。而且如果这个人没能看到这一点,需要有人告诉他。基本上来讲,我认为只有一种处理方法,但是需要一个多步骤的过程,每个步骤都很重要。

首先,确保你自己没有发疯。在私下与项目的其他人讨论,看看他们是不是和你一样认为问题很严重。即使你们已经肯定,这样也实现了让其他人知晓你们正考虑让这个人退出的目的。通常不会有人反对—他们会很高兴你肩负这个尴尬的任务,这样他们就不必动手了!

下一步,私下联系有问题的志愿者并友好和直接的告知他,你所发现的问题。为了效果,要尽可能提供多的实例。确保能够指出人们是如何不愿继续帮助的,而问题一直存在得不到改善。请确保花较长的时间编写该邮件,对于此类邮件,如果你无法支持你所说的,最好就什么都不要说。要说明你会找一个新的志愿者充当这个角色,但也要指出有许多方法可以支持这个项目。在这个阶段,不要说你已经为此与其他人进行了谈话;没有人希望被告知有人在准备接替他。

之后,可以有许多其他不同的方法。最可能的反应是他们可能会认可你,或者在某种程度上会争论,并愿意退出。如果是这个情况,建议他自己作出声明,然后你可以跟从他的文章寻找一个替代者。

或者,他可能认可自己的问题,但是请求多一点的时间(或者再多一次机会,例如离散任务角色的发布管理员)。如何响应这个情况需要您的判断,但是无论您如何做,不要仅仅因为感到无法拒绝这种请求而表示同意。这样会延续痛苦,但不会有所减轻。这通常是拒绝这种请求的好原因,换句话说就是已经给了足够多的机会,而现在就是得到的结果。这是我告知某人无法肩负发布管理员角色的邮件:

>如果您希望别人替代我,我会有好的将这个角色交给下个人。我有个
>不情之请。我希望再尝试一次发布来证明我。
>
我完全能够体会您的想法,但是在这种情况下 ,我们无法“再试一次”。

这不是第一次或第二次发布,而是第6或第7次... 我知道你也对结果
不够满意(因为我们之前已经讨论过)。所以我们已经有效的完成了
再次尝试的程序。最终,总有一次是最后一次... 我认为[上一次发布]就是
了。

在最坏的情况下,志愿者可能完全不同意。然后你需要接受事情变得尴尬并预先准备。现在是与其他人讨论此事了(但在得到他们的允许前,还是不能说是谁,因为这些对话是机密的)的时候了,也是你认为项目不应该这样继续下去的时候了。坚持,但不要威胁。请注意,大多数角色的转换可能始于某个新人已经开始了它的工作,而不是老人结束了他的工作。例如,如果争论事关角色,譬如说问题管理员,在任何时刻你和其他有影响的人可以请求一个新的问题管理员。可以不必是之前做这些事的人停止了工作,只要他没有妨害(故意或其他原因)新志愿者的努力。

有一个充满诱惑力的想法:为何不去尝试不必告知人们辞职,而仅仅是为他寻找一些帮助?为什么不可以有两个问题管理员、补丁管理员或任何角色?

尽管理论上听起来很不错,但通常不是一个好方法。是什么让管理员角色可以工作—是什么使之发挥作用,实际上—应该是非集中化。能够以非集中式完成的工作通常已经这样做了。有两个人肩负管理员角色会带来两个人的交流负担,也可能会带来不可靠的互相依赖(“我以为你带了急救箱!” “我?我以为带了急救箱”)。当然,也有例外。有时两个人可以配合的极好,或者任务本身就可以轻松的分散给多个人。但当你见到某人挣扎于某个他不适合的角色时,通常并不会起太大作用。如果他一开始就能够重视这些问题,之前就会寻求此类帮助。在任何情况下,让一个人持续做一件不会让人关注的事情都是失礼的。

让某个人隐退的重要因素是隐私:给他空间作出决定,而不要让他感觉大家都在关注和等待。我曾经犯过这种错误—非常明显的错误,回想起来—也就是同时向所有的三方当事人发送邮件,征求Subversion发布管理员,接替另外两个志愿者。我已经与两个人私下有所交流,也知道他们希望肩负这个责任。所以我认为,有些天真有些迟钝,通过向他们同时发送邮件开始了转换过程,省去了时间和争辩。我设想现在的发布管理员已经完全意识到了问题,也会立刻理解我的用意。

我错了。当前的发布管理员被冒犯了,完完全全的冒犯了。被人要求交出工作是一回事,而在大庭广众之下被要求交出工作则是另外一回事。当我意识到我的行为有些冒犯,我做出了道歉。他最终有礼貌的退出,并继续参与这个项目。但是他的感情受到了伤害,无需再说,对新志愿者来说也不是一个吉利的开始。

提交者

作为所有开源项目中唯一正式的明确阶层,需要对提交者格外关注。提交者是系统中不可避免的对鉴别的让步,而其他角色则是尽可能的非鉴别。但是“鉴别”这里绝无轻视的含义。提交者发挥的功能是绝不可少的,我不相信一个项目会在没有这个角色的情况下取得成功。我们需要质量控制,是的,控制。总会有许多人觉得自己具备对某个程序修改的能力,但实际上只有少数人确实具备。项目不能依赖人们自己的判断,必须设置标准并为达到标准的人赋予提交权限[28]。 另一方面,要让可以直接提交变更的人与不能设置明显权利变化的人一起工作。这种变化必须是受管理的,这样才不会损害项目。

第 4 章 社会和政治的基础架构“谁进行表决?”一节,我们已经讨论考虑过新提交者的机制。这里我们会讨论潜在的新志愿者必须被判断的标准,以及在一个大的社区中如何展示这个过程。

选择提交者

在Subversion项目,我们主要根据希波克拉底原理选择提交者:首先,不要伤害。我们的主要标准不是技术技巧或对代码的认识,仅仅是提交者展示出好的判断。判断仅意味着知道不要做什么。一个人可以只发布小的补丁,修正代码中的小问题;但只要这个补丁能够干净的应用,不会带来新的bug,能够最大程度的符合项目的日志信息和代码习惯,而且有足够多的补丁可以展示明显的模式,则现有的提交者通常会提议为该人赋予提交权限。如果至少三个人赞成,且没有人反对,则提议通过。诚然,也许我们没有证据证明这个人有能力解决代码基所有部分的复杂问题,但这并不重要:他所做的已经证明他至少能对自己的能力有正确的判断。技术技巧可以习得(和讲授),但无法获得最重要的判断。然而,在赋予一个人提交权限之前,这是你需要确保某人所具备的能力。

当一个新的提交者提议引起了讨论,通常不会是关于技术能力,而是关于该人在邮件列表或IRC中的行为方式。有时,某人展示了技术能力和按照项目正式方针工作的能力,以及在公共论坛中一致的好战或不合作性。这需要认真的关注;如果即使经过了回复的提示,这个人也一直未能改变,我们不会将其添加为提交者,无论其技巧怎样高。在一个志愿者团队中,社会技巧,或者说在“沙盒中玩耍的”能力,与原始的技术能力同样重要。因为任何东西都会进入版本控制,添加一个不该添加的提交者不会在代码层面带来太多的问题(评审可以迅速定位这些问题),但那样会导致最终强制项目收回该人的提交权限—这绝不是一项让人愉快的行为,有时会让人失望。

许多项目坚持潜在的提交者展示了特定级别的技术专业技能和持久性,通过提交一定数量的非琐碎补丁—也就是项目不仅仅希望知道他不会伤害项目,而且希望知道他会使项目在代码基上获益。这样很好,但是要小心,不要将提交权变为一个排他俱乐部的身份。每个人的脑子中都应该有一个问题:“怎样做才会为代码带来最好的结果?”而不是“认可这个人是否会降低提交权关联的社会状态的价值?”如果您有100个提交者,10个进行常规的较大的变更,而其他90个则仅仅是每年修正几个拼写和小的bug,依然比只有10个提交者更好。

收回提交权限

关于收回提交权限首先要做到:尝试不要一开始就进入这种情况。取决于谁的权限将会被收回,以及收回的原因,相关的讨论将会显著不同。即使没有不同,这也将会是有效率工作的一项费时的分心的工作。

然而,如果您必须如此,一定要确保讨论必须处于将会为该人赋予权限进行投票的人之间,无论他们拥有怎样的投票风味。一定不要包含本人。这似乎否定了针对保密性的禁令,但在这种情况下这是必要的。首先,没有人能够以别的方式自由言论。其次,如果行动失败,你不会希望让此人知道这被考虑过,因为这会带来一些问题(“谁站在我这边? 谁反对我?”),会导致最坏类型的党派主义。在一些罕见的情形下,团队会希望某人知道收回提交权限的过程正在进行中,作为警告提示,但一定要确保这种公开是团队决策的结果。任何人不应当擅自行动,将别人认为是秘密的讨论信息和表决透漏出去。

一旦收回了某人的权限,结果必然要公开(见本章后面的“避免神秘”一节),你需要尝试尽可能谨慎的公布于众。

部分提交权限

有些项目提供细粒度的提交权限。例如,有些贡献者的提交权限限于文档,而不能是代码。常见的部分提交权限包括文档、翻译、其他语言的绑定代码,打包的特定文件(例如RedHat RPM规范文件等等),以及其他即使发生错误也不会导致核心项目问题的地方。

因为提交权限不仅仅关于提交,而且事关选举资格(见第 4 章 社会和政治的基础架构“谁进行表决?”一节),自然回带来另一个问题:部分提交者能够为何投票?没有一个正确的答案;这取决于你的项目有何种部分提交领域。在Subversion中,我们尽可能让事情简单:一个部分提交者只可以参加提交者领域的部分投票,其他地方则不行。更重要的,我们有一个可以覆盖建议投票的机制(其实质在于,表决时提交者可以写"+0"或"+1 (非绑定)",而不仅仅是"+1")。......................

完全提交者可以为任何事情投票,就像他们可以任意提交一样,只有完全提交者可以为添加所有类型的提交者投票。在实践中,通常这种添加新部分提交者的能力通常会被代理:任意完全提交者可以“发起”一个新的部分提交者,而且某个领域的部分提交者通常会为同一领域选择新的提交者(这在保证翻译工作正常运行时特别有益)。

你的项目可能有些许不同的安排,这取决于你所作工作的特性,但相同的原理适用于所有的项目。每个提交者必须能为她提交权限相关的事物进行投票,不相关的则不能,而且程序上的问题默认由完全提交者表决,除非有原因(要由完全提交者决定)来扩大投票范围。

关于部分提交权限的强制性:最好不要让版本控制系统约束提交领域,即使技术上可行。原因请见第 3 章 技术基础设施“授权”一节

休眠提交者

一些项目会在提交者在一定时间(例如一年)内未能提交任何东西时,自动删除其提交权限。我认为这样没有太大帮助,甚至有不良的后果,有以下两个原因。

首先,这会诱使人们提交可接受但不必要的变更,仅仅为了保住将要过期的提交权限。其次,这样没有意义。如果赋予提交权限的主要标准是判断力,为何仅仅因为他离开了项目就认为其判断力的下降?即使他完全的消失了几年,没有看任何代码或跟踪开发讨论,但当他重新出现时,他会知道他已经多久未从联系,并以此行动。你原来相信他的判断,为何不永远相信他?如果高校的文凭不会过期,那么提交权限也不应该。

有时,一个提交者会要求将其删除,或在提交者列表中明确的标记为休眠状态(关于该列表的更多信息见后面的“避免神秘”一节)。在这种情况下,项目当然必须答应个人的意愿。

避免神秘

尽管围绕添加特定新提交者的讨论必须保持机密,其规则和步骤本身不应该保密。实际上,最好公开,这样人们可以意识到提交者并不是什么神秘的秘密法庭,也不是凡人免进,而是任何人可以参与,仅需要发布一些好的补丁,并指导如何在社区中交流。在Subversion项目中,我们将信息放在开发指南文档中,因为那些希望为项目贡献代码的人们对如何赋予提交权限最有兴趣。

除了发布步骤,也要发布提交者列表。该文件的传统位置是项目代码树顶级目录中叫做MAINTAINERSCOMMITTERS的文件。它首先必须列出所有的提交者,紧跟是多个部分提交域以及其中的提交者。要列出每个人的名字,如果该人愿意,也包括邮件地址,地址可以为防止垃圾邮件进行编码(见第 3 章 技术基础设施“归档中的地址隐藏”一节)。

因为完全提交者和部分提交者访问权限有着明显的区别,也做出了明确的定义,所以这个列表也应该列出这种区别。除此以外,该列表不应当试图表明项目中不可避免会出现的非正式的区别,例如谁更具影响力。它是公共记录,不是致谢文件。请使用字母顺序或其出现顺序列出提交者。

荣誉

荣誉是自由软件世界的主要货币。无论人们怎样说他参与项目的动机,我不知道有哪个开发者会乐于匿名,或以其他人的名义的做这些事。有一些有形的原因:一个人在一个项目的名声大体上决定了他的影响力,参与一个开源项目也会间接的带来金钱,因为某些雇主希望寻找简历。也有一些无形的原因,或许更加强大:人们只希望被赏识,本能的寻找被别人识别的标志。荣誉的希望是项目一个最重要的动机。当小的贡献被认可,人们会返回作出更多。

协作开发软件的一项重要特性是(见第 3 章 技术基础设施)保持何人何时做了何事的精确记录。如果存在,请尽可能使用现有的机制确保荣誉精确的分配,要根据贡献的本性特别处理。不要仅仅写下"感谢J. Random <jrandom@example.com>",作为替代可以在日志信息中写为"感谢J. Random jrandom@example.com>的bug报告以及对于重现bug的描述"。

在Subversion中,对于bug报告者的荣誉,我们有一个非正式的但是一致的政策,如果有发起的问题,则在问题中记录,如果没有发起问题,则在修正该bug的提交日志信息中记录。对于提交编号14525之前的Subversion日志进行了一个快速调查,发现10%的提交包含了某人名字和邮件地址的荣誉信息,通常是报告或分析该提交的bug修正的人。请注意,这些人与实际作出提交的开发者不同,这些开发者的名字已经自动记录到了版本控制系统。在目前Subversion的80位完全和部分提交者中,有55位在他们成为提交者之前,曾经在提交日志(通常多次)中被记录过荣誉。当然这并不是说,被记录荣誉是继续参与的一个因素,但至少给了人们知道自己的贡献如何被认可的氛围。

很重要的一点是区分常规的感谢和特别感谢。当讨论特定代码片段或其它某人的贡献时,最好能够感谢他们的工作。例如,假设“Daniel最近对于增量代码的变更意味着我们现在可以实现特性X”,需要同时帮助人们识别你所谈论的变更并感谢Daniel的工作。另一方面,仅仅单独感谢Daniel对于增量代码的变更无法达到即刻的实践目的。它不会增加任何信息,因为版本控制系统和其他机制已经记录了他所做的变更。感谢所有人的所有工作则会分散最终的信息,因为感谢的内容是他与所有默认的、背景的评论级别相比的突出程度。当然这并不意味着你不需要感谢大家。只需要确保不会陷入荣誉通货膨胀。遵循下面的指导会有所帮助:

  • 这个论坛越是短暂,越应该对在这里自由表达感谢感到自由。例如, 在IRC对话中感谢某人传来的bug修正很好,在邮件中旁敲侧隐也很不错。但是最好不要单独发一个感谢某人的邮件,除非是真的不同寻常的壮举。很有可能,不要因为表达感激弄乱项目的网页。一旦你开始这样做,便会永远无法清理,也无法停止。而且绝不要将感谢置于代码的注释之中;这将会分散注释主要目的的注意力,注释本来的作用是帮助读者理解代码。

  • 一个人参与项目越少,就更应该对她的所作所为提出感谢。这似乎与直觉并不一致,但是表示感谢的态度适用与某人作出的贡献,超出了你对他的预期。因此,一直感谢常规贡献者的日常工作表现了对他们所做工作的较低的预期。如果说有效果,可能是反效果!

    这个规则有一些偶尔的例外。如果感谢某人完成了预期角色,而这个角色反复包含了许多临时的、紧张的努力,则这是可以接受的。一个标准的例子是发布管理员,他在每次发布时都会投入紧张的工作,但其他时间则陷入休眠(作为发布管理员休眠,在有些情况下—它还可以是活跃的开发者,但那是另外一回事了)。

  • 就像批评和荣誉,感谢必须是特定的。不要因为伟大而感谢,即使确实如此。要为他们所做的超出寻常的事情表示感谢,如果能恰当的说出他们的伟大之处也能额外加分。

通常情况下,在确保某个人的贡献已经被识别出来,和确保整个项目是一个团队,而不是一些荣耀的个体时,总会有些紧张。只要意识到这种紧张,并且强调表现团队,以及未能掌握的事物。

分叉

第 4 章 社会和政治的基础架构“分叉能力(forkability)”一节,我们说了潜在的分叉能力对于项目管理的重要影响。但是当分叉确实发生时,我们应该怎么做?你应该如何处理,会发生怎样的情况?与之对应,何时你应当开始一个分叉。

答案取决于你选择的分叉类型。有一些分叉源于对于项目方向的友善但不可调和的异议;也有一些由于技术分歧和个人冲突。当然,很难说清楚二者之间的区别,因为技术争论也会包含个人元素。所有分叉的共同之处是有一队开发者(有时仅仅是一个开发者)认为与某些人或所有其他人一起工作的成本已经大于收益。

一旦项目分叉,对于分叉与“原”项目谁是谁非,没有明确的答案。人们会通俗的说分叉F来自于项目P,好像P继续沿着自然路径保持不变,而F则进入新的领域,但这实际上是一个观察者的声明。但这纯属个人感觉:当足够高百分比的观察者认可,这个断言便成为真。并不是说一开始就有一个客观事实,而只是一开始的一个不太完美的感觉。此外,感觉客观事实,因为最终一个项目—或一个分叉—仅仅是存在于人们思想中的一个实体。

如果开始分叉的人们感觉自己是在建立主项目的一个分支,则感知问题可以立刻轻易的解决。每个人,开发者和用户会将分叉视为新的项目,有新的名称(或许基于旧有的名称,但容易与之区分),一个单独的网页以及单独的哲学或目标。当双方都认为自己是原项目遗产的守卫者,理所当然继续使用原来的名称时,事情会变的复杂。如果某个组织拥有这个名称的商标权,或对于域名或网页有法律控制,通常可以平滑的解决这个问题:这个组织可以决定谁是这个项目,谁是分叉,因为它拥有公共关系战争中的所有卡片。很自然,一般不会如此过分:因为每个人都知道权利动力学,他们会避免一场结局已定的战斗,会直接跳到结局。

幸运的是,大多数情况下可以轻松的区分哪个是项目,哪个是分叉,因为分叉从本质上是一个自信的投票。如果过半的开发者倾向于采纳分叉的过程,通常意味着没有必要分叉—这个项目可以自己走这条路,除非它有一个顽固的独裁者,按照独裁方式运行。另一方面,如果支持者少于一半,则分叉则明显是少数派的反叛,根据礼貌和常识,它应当认为自己是分叉,而不是主线。

处理分叉

如果某人在项目中威胁进行分叉,请保持冷静并牢记你的长期目标。分叉的存在不是对项目的伤害,而是开发者和用户的损失。你真正的目标,不是为了镇压分叉,而是最小化其损害。也许你会生气,你或许感到分叉是不公正和不请自来的,但如果这样公开表示则是对未决定用户的疏远。相反,不要强制人们做出唯一的选择,要与分叉实行可行的合作。首先,不要因为某人决定在分叉上工作,而删除其在你的项目中的提交权限。在分叉上工作并不意味着他立刻失去了在原项目工作的资格;之前的提交者之后还是提交者。此外,你应当展示与分叉保持兼容的愿望,并表达你希望开发者能够在二者之间搬运合适的变更。如果你对项目服务器有管理权限,一开始就公开提供分叉的基础架构帮助。例如,如果他们无法通过其他方法获得,可以为他们提供一个完整的,版本控制库的深度历史副本,这样他们就不必以无历史数据作为开始(必要性取决于版本控制系统)。询问他们是否有其他的需要,并尽你所能提供。这种支持表明了你不会阻挠他们,而且希望该分叉以自己价值成功或者失败,仅此而已。

这样做—以及公开这样做的—原因实际上并不会帮助分叉,但是通过尽可能的展示非报复心态,会使开发者相信你这边是安全带。战争中有时强制人们选择一边非常有意义(战略意义,而不是人的感觉),但是自由软件几乎从不这样做。实际上,分叉后一些开发者会公开的在两个项目同时工作,并尽可能保持二者兼容。这些开发者保持了分叉之后的交流。他们允许您的项目从分叉中有趣的新特征中获益(是的,分支也有你想要的),另外也会增长在未来合并的可能。

有时,某个分支变得异常成功,即使他最初的煽动者也认为他们开始于一次分叉,但成为人人都喜欢的版本,最终由于其流行性取代了最初的版本。一个著名的实例是GCC/EGCS分叉,GNU Compiler CollectionGCC,以前称为GNU C Compiler)是最著名的开源本代码编译器,也是世界上最便于移植的编译器。源于对GCC官方维护者和Cygnus软件的分歧。[29]GCC的一个最活跃的开发团队,Cygnus创建了一个GCC的分叉,称为EGCS。该分叉谨慎保持非敌对位置:从任何角度看,EGCS开发者从没有试图把他们版本的GCC描绘成新的官方版本。相反,他们集中精力使EGCS尽可能的好,比官方的GCC维护者以更快的频率整合补丁。EGCS受到了欢迎,最终一些主流的操作系统发布商决定将EGCS而不是GCC作为打包产品的默认编译器。此刻,对于GCC的维护者很清楚,坚持“GCC”的名称,而让所有人切换到EGCS分叉上需要每个人承受毫无必要的名称修改负担,对防止切换毫无意义。所以GCC采用了EGCS的代码基,再一次只有一个GCC,但因为分叉获得了极大的改进。

这个例子向我们展示了为什么不能单纯的将分叉视为一件坏事。分叉时可能充满痛苦和不受欢迎,但你不能必然知道它是否会成功。因而,你和项目的余下部分要一直留意它,不仅仅要准备好吸收可能的特性和代码,在极端情况下,如果分叉获得了项目的精神占有率,甚至需要加入分叉。当然,通过观察谁加入了分叉你也能预测到其成功的可能性。如果分叉由项目最大的抱怨者开启,并有少数不满的看起来起不到建设作用的开发者加入,他们将无法通过分叉解决问题,你也无须担心分叉会将原项目的动力带走。但是如果你看到有影响和令人尊敬的开发者支持这个分叉,你必须问自己这是为什么。或许整个项目被限制了,最好的方案是在主线项目采纳一些分叉打算的行动—从本质上,通过变成它而避免分叉。

初始一个分叉

这里的所有建议假设你将分叉作为最后的依靠。初始分叉前耗尽了所有的可能性。分叉总是意味着丢失开发者,只留下一个不确定的在以后获得新产品的承诺。它也意味着开始了对用户注意力的竞赛:每个下载这个软件的人都会问自己:“哦,这个还是那个? ” 无论你是哪个,情况也是肮脏的,因为出现了原本不存在的问题。一些维护分叉的人们会维护软件的整体生态系统的健康,通过标准的自然选择论点:适者生存,意味着最终每个人得到更好的软件。从生态学的角度这或许是正确的,但对于单个项目来说则并不正确。大多数分叉并不成功,大多数项目不喜欢被分叉。

一个推论就是不要使用分叉的威胁作为极端的辩论技巧—“按照我的方式,否则我要将项目分叉! ”—因为每个人都会意识到如果是无法吸引开发者离开原项目的分叉,不太可能长久存活。所有的观察者—不仅是开发者,还有用户和操作系统打包者—会对选择哪一方做出自己的判断。你不必表现出极端不情愿分叉,这样如果你最终这样做了,你可以光荣的宣布这是最后一条路。

在评估你的分叉成功可能性时,不要忽视所有的因素。例如,如果项目的许多开发者都有同一个雇主,那么即使他们不满且私下里倾向于分叉,也不太会大声说出他们的雇主是赞成还是反对。许多自由软件程序员以为如果代码有自由许可证,那么没有哪个公司可以控制开发。许可证确实如此,是一种终极意识,自由的保障—如果其他人强烈的希望分叉项目,并有足够的资源,它可以这样做。但是在实践中,一些项目开发团队大多由一个实体资助,没有证据说明这些实体的支持无关紧要。如果他们反对分叉,他们的开发者不会离开,即使私下里希望如此。

如果你还是确认必须分叉,最好首先私下联络好支持,然后使用不含敌意的语调宣布分叉。即使你对当前的维护者感到愤怒,或者失望,不要在这些信息中写出来。只需要不露声色的陈述导致你决定分叉的动机,以及你对所分叉原项目并无敌意。假定你考虑一次分叉(相对于对原项目的紧急保存),强调你分叉的是代码而不是名称,并选择一个与原项目不会冲突的名称。你可以使用一个包含或引用原名称的名称,只要不会造成识别上的混淆。当然,在分叉的主页上也可以突出解释其来自的原始程序,甚至对于替代它的期望。但是不要迫使用户解开识别争议,给他们带来额外的麻烦。

最终,通过为原项目的所有提交者,包括那些公开反对分叉的提交者赋予提交权限,就可以自动让事情开始运转。即使他们不会访问,但你的信息是明确的:这里存在争议,但是没有敌人,你欢迎来自所有竞争源的代码贡献。



[24] 这个问题已经被详细研究,Karim Lakhani和Robert G. Wolf的一篇论文有非常有趣的结果,题目为Why Hackers Do What They Do: Understanding Motivation and Effort in Free/Open Source Software Projects。见http://freesoftware.mit.edu/papers/lakhaniwolf.pdf

[25] 但是邮件列表中链接为http://groups.google.com/group/sage-devel/browse_thread/thread/e207ce2206f0beee“having authors names in .py files”的这篇文章是一个很好的抗辩,作者是William Stein。我认为关键在于许多作者来自一种将信誉直接取自源代码视为标准并高度评价的文化。在那种环境中,可能有必要将作者的名字置于源代码中,并精确的描述每个作者的贡献,因而大多数潜在的贡献者会希望有这种样式的承认。

[26] 请注意,没有必要将所有已存在的测试转化到新框架;二者可以和平共处,只需要转化需要改变的测试。

[27] IssueZilla就是我们使用的问题跟踪系统;它是BugZilla的后继。

[28] 请注意,在非集中式的版本控制系统中,提交权限的含义有些区别,在非集中式系统中,任何人可以建立与项目关联的版本库,并为自己设置到该库的访问权限。然而,提交权限的概念依然适用:“提交权限”是“改变软件下一次发布中输送代码的权利”的缩写。在集中式版本控制系统中,这意味着直接的提交权限;在非集中式系统中,这表示了将某人的变更默认拖入主发布。其实是相同的含义;其实现的机制并不重要。

[29] 现在是RedHat(http://www.redhat.com/)的一部分。

第 9 章 许可证,版权和专利

只要是开源许可证,你选择的许可证可能不会是影响采用项目的主要因素。用户通常根据质量和特性选择软件,而不是许可证的细节。虽然如此,你还是需要对自由软件许可问题有基本的了解,一方面确保项目的许可证与其目标一致,另一方面可以与其他人讨论许可证决策。请注意,我不是律师,本章的内容不应当作为正式的法律建议。对于法律事务,你需要雇佣一个律师或自己是律师。

术语

在开源许可证的任何讨论中,最明显的是首先要看到有许多不同的单词指的是同一件事:自由软件开源FOSSF/OSSFLOSS。首先从列出这些开始,然后引出一些其他的术语。

自由软件

可以自由分享和修改的软件,包含源代码格式。该术语首先由Richard Stallman创造,他在GNUGeneral Public License (GPL)中编写了这个词,并创建了自由软件基金会(http://www.fsf.org/)来发扬这个概念。

尽管“自由软件”几乎覆盖了几乎“开源”软件的同一个范围,FSF还是倾向于前一个术语,因为它强调了自由的理念,自由分发软件的概念主要是一种社会的而不是技术的运动。FSF承认这个术语的不明确性—它可以是“0费用”的“free”,而不是“自由”的“free”—但还是认为这是最好的术语,其他可能性在英语中还是有自己的混淆。(在本书中,“free”取“自由”之意,而非“0费用”之意。)

开源软件

自由软件的另一个名字。但是不同的名字反映了重要的哲学差异:开源促进会(Open Source Initiative http://www.opensource.org/)创造了“开源软件”一词,作为“自由软件”的可替换词,他们试图通过以开发方法学而不是政治运动的方式进行展示,努力使此类软件成为公司更可口的选择。他们也期望消除另一个污点:任何“免费的”一定是低质量的。

所有的许可证是自由的则也是开源的,反之亦然(除了少许的例外),人们倾向于选择一个并保持不变。概括说来,喜欢“自由软件”的更有可能喜欢在这个问题上保持一个哲学或道德姿态,而喜欢“开源”的则或许是不认为自由十分重要,亦或者不希望极力宣扬他们所做的。关于这次分裂的历史请看第 1 章 介绍““自由”还是“开源””一节

对于这两个术语,自由软件基金会有一个非凡的—完全不可反对的,但是微妙而公平的—解释,位于http://www.fsf.org/licensing/essays/free-software-for-freedom.html。开源软件研究院通过这两个页面传播:http://www.opensource.org/advocacy/case_for_hackers.php#marketinghttp://www.opensource.org/advocacy/free-notfree.php

FOSS, F/OSS, FLOSS

开始是两件事,不久后就变成三件,这确实是自由软件中术语所发生的事情。学术世界或许更希望精确和内涵,而不是优雅,所以设置FOSS或有时F/OSS来代表“Free / Open Source Software”。另一个变种是FLOSS,代表了“Free / Libre Open Source Software”(libre在许多语言中也是被人所熟悉的,并且没有“free”的模糊含义;更多信息请见http://en.wikipedia.org/wiki/FLOSS)。

所有这些术语实质上是同一件事:任何人可以修改并分发的软件,有时—并不一直是—要求衍生的作品必须按照同样的条款自由的分发。

DFSG-符合

符合Debian自由软件方针(http://www.debian.org/social_contract#guidelines)。这是一个许可证是否为真的开源软件(free、libre等等)的广泛使用的测试。Debian项目的目标是维护整个自由软件操作系统,这样人们安装之后就无需担心自己是否有权限修改和分发系统的任意部分。Debian自由软件方针是软件包许可证进入Debian所必需达到的要求。因为Debian项目花费了大量时间考虑如何构建这样一个测试,所以得出的方针被证明是非常健壮(http://en.wikipedia.org/wiki/DFSG)的,并且至少以我看来,无论是自由软件基金会还是开源研究院都没有提出严重的反对。如果你知道一个许可证是DFSG-符合的,你就知道它保证了支持开源项目动态性的重要自由行(例如甚至违背最初作者意愿的可分叉性)。本章讨论的许可证都是DFSG-符合的。

OSI-确认

经由开源研究院确认。这是另外一个广泛采用的确定许可证是否执行所有必要自由的测试。OSI对开源软件的定义基于Debian自由软件方针,只要符合其中一个定义就几乎可以符合另一个定义。这几年有了一些例外,但是只包括niche licenses,与这里毫无关系。不像Debian项目,OSI维护了一个所有已经经过确认的许可证列表,位于http://www.opensource.org/licenses/,所以被“OSI-确认”是一个毫不含糊的状态:许可证是否在这个列表中。

自由软件基金会在http://www.fsf.org/licensing/licenses/license-list.html维护了一个许可证的列表。FSF不仅仅根据是否自由来分类许可证,而是根据其是否与GNU的GPL兼容分类。GPL兼容是一个重要的主题,将会在本章后面的“GPL和许可证兼容性”一节介绍。

私有, 闭源

“自由”或“开源”的对立面。这意味着软件按照传统的、基于授权的许可条款分发,用户需要为每一份拷贝支付,亦或者按照其他足够限制开源动态性操作的条款分发。即使软件可以不支付的情况下分发也可以是私有软件,只要它的许可证禁止自由分发和修改。

通常来说“私有”和“闭源”是同义词。然而“闭源”有甚至看不到源代码的附加含义。因为大多数私有软件看不到源代码,所以这经常是一个没有差别的区别。然而,偶然情况下,有一些人会使用允许其他人查看代码的许可证发布私有软件。令人混淆的是,他们有时称之为“开源”或“近似开源”等等,但确实是误导。源代码的可见性确实不是问题所在;重要的问题是你能对此做什么。因而,私有和闭源的区别几乎毫不相关,二者可以被当作同义词。

有时会使用商业作为“私有”的同义词,但是严格说来,二者并不是一回事。自由软件也可以是商业软件。毕竟,自由软件可以出售,只要购买者没有被限制为禁止放出他们自己的拷贝。在其他方面也可以是商业的,例如出售支持、服务和认证。现在有许多数百万美元的公司是建立在自由软件之上的,所有没有什么固有的反商业和反公司。另一方面,反私有则是本性,这是其区别与传统每拷贝许可证模型的关键方式。

公共域

没有版权所有者,也就是说没有人拥有可以限制复制这些作品的权利。进入公共域中与没有作者并不相同。任何事物都有一个作者,即使某个作品的作者选择将作品放到公共域,这改变不了他们编写的事实。

当一个作品进入公共域,由其组成的材料可以变成有版权的作品,之后该材料的拷贝与整个作品处于同一个版权下。但是这不会影响原始作品的存在性,它还是会保存在公共域。因而,在公共域发布一些东西从技术讲就是根据大多数自由软件认证组织的方针,使之“自由”。然而,通常有许多原因促使我们使用一些许可证,而不仅仅是简单的发布到公共域:即使对于自由软件,特定的限制也是非常有用的,这不仅仅是对于版权的所有者,也是对其他接受者,下个小节会澄清这个问题。

copyleft

使用版权法取得反对传统版权的结果的许可证。取决于你所问的人,这个许可证可能是允许这里讨论的自由,也可能是更窄一些,并非允许这些自由,而是通过契约保证必须在作品中履行自由,强制它们的许可证。自由软件基金会排他的使用第二种定义;其他情况下则只是匆忙上马:许多人像FSF一样使用这个术语,但是其他人—包括那些为主流媒体写作的人—倾向于第一种定义。不太清楚使用这个术语的人是否意识到了需要做一些区分。

一个本地的例子更加狭窄,一个更严格的定义是GNU GPL,强制所有衍生的作品也必须使用GPL许可证;更多信息请见本章后面的“GPL和许可证兼容性”一节

许可证的方面

尽管有许多不同的自由软件许可证,但在许多重要的方面所说的是同一件事:任何人可以修改代码,也就是任何人可以再次分发其原始和修改的形式,而版权所有者和作者不做任何保障(考虑到人们会在不知情的情况下运行修改的版本,免责非常重要)。不同许可证的区别经常出现在这些问题上:

私有许可证的兼容性

有一些自由许可证允许覆盖的代码用于私有软件。这不会影响私有程序的许可证条款:它还是私有软件,它仅仅是包含了一些非私有的源。Apache许可证、X Consortium许可证、BSD样式的许可证以及MIT样式的许可证都是私有兼容的许可证。

与其他自由许可证的兼容性

大多数自由许可证与其他兼容,意味着某个许可证下的代码可以与其他的代码合并,使用任意一种许可证分发也不会违反另外一种许可证的条款。主要的例外是GNU GPL,它要求使用GPL化的代码则必须按照GPL分发,并不得增加任何GPL所要求的更多限制。GPL只与某些自由许可证兼容。本章后面的“GPL和许可证兼容性”一节将会详细讨论这些细节。

荣誉的强制性

一些自由许可证强制对于所覆盖代码的任意使用,必须伴随一个已指明了放置和显示方式的提示,给予代码的作者或版权拥有者荣誉。这些许可证仍然是私有兼容的:他们并不要求衍生的作品是自由的,仅仅要求给予自由代码一份荣誉。

商标保护

强制荣誉的一个变种。商标保护许可证指明在未经预先书面许可前,原始软件的名称(或者其版权所有者,或他们的机构等等)不能被用于衍生的作品中。尽管荣誉强制坚持使用特定的名字,而商标保护保证其不被使用,但他们只是相同目的不同表达方式:原始代码的名声必须保存和传递,但不要因为关联而玷污。

"艺术完整性"保护

有一些许可证(例如著名的Perl编程语言实现所使用的艺术许可证,以及Donald Knuth的TeX许可证)要求分发时必须明确区分代码的原始版本和所有的修改。他们与其他自由许可证在实质上允许同样的自由,但是提出了特定要求,可以轻松的确认原始代码的完整。除了制作这些许可证的特定程序,并没有太多这类许可证的使用,所以将不会在本章讨论;它们的出现仅出于完全性的考虑。

大多数这类强制不是互斥的,某些许可证会包含多个。他们之间相同的线索是在接受者那里设置要求,交换接受者使用和/或发布代码的权利。例如,一些项目希望他们的名称和名声能够随着代码传播,并且也值得放置额外的荣誉或商标条款;取决于其难度,这种负担会导致某些用户选择较少要求的包。

GPL和许可证兼容性

私有不兼容与私有兼容许可证的最尖锐区别,也就是GNU GPL与其他许可证的区别。因为GPL作者的主要目标是提升自由软件,他们故意使它们的许可证不可能让GPL代码混入私有程序。具体说来,在GPL的要求中(见http://www.fsf.org/licensing/licenses/gpl.html的全文)有这样两点:

  1. 所有衍生作品—也就是任何包含非琐碎量GPL代码的作品—也必须在GPL下分发。

  2. 对于原始作品或衍生作品的分发没有其他附加的限制。(另一种表达是:“你不可以为接受者设置一些超过这里列出的进一步限制。 ”)

通过这些条件,GPL成功的让自由传播。一旦某个程序在GPL下设置版权,它的再次发布条款会像病毒—传播到与之组合的代码中,有效的使GPL化的代码无法用于闭源程序中。然而,同样的条款也使GPL与其他自由许可证无法兼容。一个常见的方式是其他许可证设置了一个需求—例如,需要以某种方式提及原始作者的荣誉条款—与GPL中“不得设置进一步的限制不兼容...”。从自由软件基金会的角度,这种二阶的后果是理想的,至少没有值得后悔的。GPL不仅仅保持你的软件的自由,也有效的推动其他软件强制自由。

这是否是提升自由软件地位的好方法这个问题是互联网上一场持久的圣战(见第 6 章 交流“避免圣战”一节),我们不做深入分析。重要的是GPL兼容性是我们选择许可证时的一个重要问题。GPL是最流行的开源许可证;在http://freshmeat.net/stats/#license大约是68%的份额,而第二高的许可证则只有6%。如果你希望你的代码可以自由的与GPL的代码混合—这里有大量GPL的代码—然后你必须选择一种GPL兼容的许可证。大多数GPL兼容的开源许可证也是私有兼容:也就是说,在该许可证下的代码可以用于GPL程序,也可以用于私有程序。当然,混合的结果不会互相兼容,因为一种是GPL,另一种则是闭源作品。但是真正相关的是衍生的作品,而不是你一开始分发的代码。

幸运的是,自由软件基金会维护了一个与GPL兼容或不兼容的许可证列表,位于http://www.gnu.org/licenses/license-list.html。本章讨论的许可证都会展现在这个列表中,兼容的和不兼容的。

选择一个许可证

当选择为项目应用一个许可证时,如果可能,请尽量选择一个而不是建一个新的。选择已有的许可证有两个原因:

  • 熟悉度。如果你使用最流行的三,四个许可证之一,人们会感到在使用代码前不需要阅读这些法律条款,因为他们之前已经阅读过了。

  • 质量。除非你有一个可以支配的律师团队,否则你很难得到一个法律坚实的许可证。这里说的许可证时大量思想和经验的产品;除非你的项目确实有不同寻常的需要,你不太可能做的更好。

关于应用这些许可证的某个到你的项目,见第 2 章 起步“如何为你的软件应用许可证”一节

MIT / X Window System License

如果你的目标是希望代码能被最大可能数量的开发者和衍生作品使用,而且你对这些代码用于私有程序不太在意,选择MIT / X Window System许可证(这样命名是因为它是麻省理工学院发布的X Window System代码的许可证)。该许可证的基本信息是“你可以任意的自由使用这些代码。”它与GNU GPL兼容,而且简短、简单和易于理解:

Copyright(c) <年份> <版权所有者>

现授予的权限,免费向任何人索取该软件和相关的文档文件
(“软件”),以处理软件,没有任何限制,包括但不限
于使用权,复制,修改,合并,出版,发行,授权,和/或销
售软件的副本,并允许的人提供的软件是这样做,但须符合
下列条件:

上述版权声明和本许可声明中应包括所有副本或实质性部分
的软件。

该软件是“按原样”提供,不做任何保证,明示或暗示,包
括但不限于适销性,针对特定用途的适用性和非侵权的。在
任何情况下,作者或版权持有人对任何索赔,损害赔偿或其
他责任,无论是在一项行动的合同,侵权或其他因出于或有
关的软件或利用等交易必须软件。 

(取自http://www.opensource.org/licenses/mit-license.php。)

GNU General Public License

如果你不希望你的项目代码用于私有程序,或者如果你对代码是否用于私有程序毫无在意,请选择GNU GPL(http://www.fsf.org/licensing/licenses/gpl.html)。GPL可能当今世界上是最广泛使用的自由软件许可证;这种快速的识别性本身就是GPL的主要优点。

当编写代码库时,也就是说代码主要被用于其他程序,请考虑清楚GPL设置的这个限制是否与你的项目目标一致。在某些情况下—例如,当你试图取代另一个完成同样功能的竞争私有库时—如果以可以将其混入私有程序的许可证方式分发代码会有一些战略意义,即使你并不想这样做。自由软件基金会甚至为这种情况设计了一种替代GPL:GNU Library GPL,不久之后更名为GNU Lesser GPL(大多数人一直使用首字母缩写LGPL)。LGPL比GPL有更宽松的限制,可以与其他非自由代码轻松的混合。然而,它也有一些复杂,需要花一些时间理解,所以如果你不会继续使用GPL,我建议你使用MIT/X样式的许可证。

GPL是自由还是不自由?

选择GPL的一个后果就是会有—小的,但不是无限小—的可能卷入GPL是否为真正“自由”的争论中,考虑到它为你如何处置代码设置了一些限制—也就是代码不能以其他任何许可证分发。对于某些人,这些限制的含义是GPL比诸如MIT/X的宽松许可证有“较少的自由”。这种争论会一直在继续,当然,因为“更多的自由”比“较少的自由”更好(毕竟,谁不喜欢自由?),下面是这些比GPL更好的许可证。

这种争论是另一场圣战(见第 6 章 交流“避免圣战”一节)。避免参与,至少不要在项目论坛。不要试图证明GPL更自由或是更不自由,或者比其他许可证更自由。相反,强调你的项目选择GPL的原因。如果许可证的可识别性是一个原因,说出来。如果是为了强制衍生作品的自由许可证,也说出来,但是拒绝陷入这是否会使代码更自由的讨论。自由是一个复杂的主题,如果术语继续用于作为事实的掩饰,这种讨论毫无意义。

因为这是一本书,而不是邮件列表讨论,然而,我必须承认我从没有理解“GPL是不自由的”论据。GPL设置的唯一限制是防止人们设置进一步限制。说这样不自由对我来说就像是在说失去法律保护的奴隶制减少了自由,因为它防止了某些人拥有奴隶。

(噢,如果你陷入了这样一场争论,不要使用激烈的类比来提升自己的证据。)

那BSD许可证呢?

有大量开源软件使用BSD许可证(或者有时BSD样式的许可证)分发。原始的BSD许可证用于Berkeley软件分发版本,是加利福尼亚大学分发的Unix实现的重要部分。该许可证(完整的文本在http://www.xfree86.org/3.3.6/COPYRIGHT2.html#6的2.2.2)与MIT/X许可证有相似的精神,除了这个条款:

所有提及该软件特性或使用的宣传材料必须包含如下致谢:该产品包含加州大学Lawrence Berkeley实验室的软件。

这个条款的出现不仅使得最初的BSD许可证不兼容,也设置了一个危险的先例:其他组织也在他们的自由软件中设置了类似的广告条款—用他们自己组织的名称代替“加州大学,Lawrence Berkeley实验室”—软件分发商面对了一个日益增长需要显示什么的负担。幸运的是,许多使用这种许可证的项目注意到了这个问题,并删除了这个广告条款。在1999年,甚至加州大学也放弃了这个条款。

结果是修订的BSD许可证,仅仅是删除广告条款的原始BSD许可证。然而,这个历史使得“BSD许可证”有一些暧昧:它指的是原始的还是修订的版本?这就是我倾向于MIT/X许可证的原因,本质上是相同的,但不会面对这种不明确。然而,也有一个选择修订的BSD许可证而不是MIT/X许可证的原因,也就是BSD有这个条款:

在经过特定的预先书面许可之前,<组织>的名称和贡献者的名称都不可以用于支持或提升此软件衍生的产品。

不清楚如果没有这个条款,软件的接受者是否拥有使用许可者的名称的权利,但这个条款清除了这个可能的疑问。对于担心商标控制的组织,修订的BSD许可证可能比MIT/X更好。大体来说,一个自由主义的版权许可证并没有暗含了接受者可以使用或削弱您的商标的权利—版权法和商标法是两个不同的东西。

如果你希望使用修订的BSD许可证,这里有一个模板http://www.opensource.org/licenses/bsd-license.php

版权分配和所有权

有三种处理自由代码和文档版权所有权的方法,许多人为此做出了贡献。第一种是完全无视版权的问题(我不建议如此)。第二种方法是从项目中工作的每个人那里收集一个贡献者许可证协议CLA),明确项目对使用个人贡献的权利。这通常对大多数项目已经足够了,更好的是在一些司法权中,CLA是可以通过email发送的。第三种方法是从贡献者那里获得真正的版权协议,这样项目(例如一些法律实体,通常是非盈利)就是所有东西的版权所有者。这通常是无懈可击的方法,但也是贡献者的负担;只有少数项目坚持如此。

请注意,即使在集中式的版权所有权时,代码[30]还是自由的,因为开源许可证并没有给版权持有者可以将所有代码的拷贝收回所有的权利。所以即使作为法律实体的项目突然转向开始将所有的代码使用限制许可证发布,也不会给公共社区带来什么问题。其他开发者可以简单的根据最新的代码拷贝开始一个分叉,并当作没发生任何事情一样继续。因为他们知道他们可以这样做,大多数被问及签署CLA或版权协议时会非常合作。

无为而治

大多数项目从来没有从他们的贡献者那里收集过CLA或版权协议。相反,只要代码是合理清除,而且贡献者愿意将其组合进项目,他们就会接受代码。

在通常情况下,这是正常的。但是偶尔会有人决定因版权侵害而诉讼,声称他们是问题代码的所有者,而且他们从没有同意这些代码由项目使用开源许可证分发。例如,SCO团队向Linux团队这样做的,细节见http://en.wikipedia.org/wiki/SCO-Linux_controversies。当这些发生时,项目没有文档说明贡献者正式的赋予使用这些代码的权利,可能会导致一些法律辩护。

贡献者许可证协议

CLA可能是在安全性和便利性之间提供了最好的折衷。一个CLA通常是一个发送给开发者填写并发回项目的电子表格。在大多数司法中,邮件提交已经足够。或许需要安全电子签名;可以咨询律师找出对你的项目最合适的方法。

大多数项目使用两个些许不同的CLA,一个针对个人,一个针对公司贡献者。但是在两种类型中,核心的语言是相同的:贡献者赋予项目"...永久的、全世界的、非独占的、免费的、特许自有、不能取消的版权许可证,可以用于重新制作、准备衍生作品、公开显示、公开操作、发放从属证书和分发这些贡献和此类衍生作品。"再次强调,你应当有一个律师确认CLA,但是如果你能了解所有这些程序,那样会很好。

当你从贡献者那里请求CLA时,请确认强调你不是要求真正的版权授予。实际上,许多CLA使用这些语句来提醒读者:

这仅仅是一个许可证协议;它不会转移版权所有权,也不会改变因任何目的使用自己贡献的权利。

下面是一些例子:

版权转移

版权转移的含义是贡献者将自己的贡献赋予给项目版权所有权。理想情况下,需要书面完成并传真或邮寄给项目。

一些项目坚持完全的协议,因为如果开源许可证的条款需要强制时,一个单独的法律实体拥有整个代码基的版权会非常有用。如果没有单个实体有这样的权利,所有贡献者需要合作,但问题发生时可能某人没有时间或无法找到。

不同的组织对于收集授权的严苛程度不同。有一些仅仅是某个贡献者在公共邮件列表中的简单非正式陈述—类似“我这里将我的在该项目的代码授权,使用其余代码相同的许可证条款。 ”至少有一个我交流过的律师认为这样已经足够,大体推测,可能是因为它发生在一个版权授权已经非常普通和预期的方式,而且因为它代表了项目一方对于确保开发者真正意图的诚意努力。另一方面,自由软件基金会则进入对立的极端:他们要求贡献者物理上签署并邮寄一份文件,包含版权授权的正式描述,有时仅针对一份贡献,有时针对当前和未来的贡献。如果开发者被雇佣,FSF也会要求雇员签署这个东西。

FSF的偏执狂可理解的。如果某人违反了GPL关于将他们的软件组合到私有程序的条款,FSF会需要与之在法庭上斗争,他们希望他们的版权在这种情况发生时可以无懈可击。因为FSF是许多流行软件的持有者,他们认为这是真实可能的。无论你的组织是否有只有你所决定的需要类似的小心谨慎,请咨询律师。通常情况下,除非一些特别的原因需要你的项目拥有完全的版权授权,你可以直接采用CLA;他们对每个人都很简单。

双许可证模式

一些项目希望通过双许可证模式资助自己,也就是私有衍生作品向所有者支付使用代码的版权,但代码对于开源软件依然免费。很自然,代码库比独立应用更适合这种方式。精确的条款各不相同。通常其属于自由的许可证为GNU GPL,因为它已经禁止了他人在未经版权持有者允许前,将覆盖的代码组合到他们的私有产品中,但是有时一些自定义许可证起到相同的效果。前者的一个例子是MySQL许可证,这里有描述http://www.mysql.com/company/legal/licensing/;后者的例子是Sleepycat软件许可证策略,描述在http://www.oracle.com/technology/software/products/berkeley-db/htdocs/licensing.html

你或许有些疑惑:为什么明明GNU的GPL规定代码必须在较少约束的条款下发布,而版权持有者还可以提供私有许可证。答案是GPL的条款是版权持有者为所有其他人设置的;而所有者可以自由的决定是否对其本身应用这些条款。对此,一个好的理解方法是想象版权所有者在桶里有无数份软件的拷贝。每次它从桶中取出一个发送到世界上时,它可以决定是采用GPL,私有或其他许可证。这并不是仅仅与GPL或其他任何开源许可证相关,它仅仅是版权法所赋予的权利。

双许可证的吸引力在于,为自由软件项目提供了一种可靠的收入来源。不幸的是,它也可能干扰开源项目本身的一般动力性。问题是任何为代码作出贡献的志愿者现在开始为两个不同的实体贡献:代码的自由版本和私有版本。当然,贡献者会乐于贡献自有版本,因为这是开源项目的标准,如果是为他人的半私有收入贡献,她会感到可笑。由于双许可证的这一事实加剧了这种尴尬,版权所有者确实需要从所有贡献者收集正式的,签署的版权授权,从而才能保护自身之后不会受到不满的贡献者对于从私有收入中获取自己份额的指控。收集这种授权文件的过程意味着贡献者要严酷的面对这一事实,他们在为别人赚钱而工作。

不是所有的志愿者会因此而困扰;毕竟他们的贡献也进入了开源版本,这是他们的兴趣所在。虽然如此,双许可证是版权持有者赋予自己,而项目中的其他人所没有的特权的一个例子,而且一定程度上会引起一些紧张,至少对某一些志愿者。

在实践中,我们看到许多基于双许可证软件的公司确实没有真正平等的开发社区。他们只能从外部获得很小规模的bug修正和清理补丁,而通过内部源做大量艰苦的工作。例如,Zack Urloker,MySQL的副主管告诉我,公司通常最终会雇佣最活跃的志愿者。因而,尽管产品本身是开源的,使用GPL许可证,它的开发还是或多或少受到公司的控制,虽然也可能有人确实不满意这个公司把持着这个软件而分叉这个项目。一定程度上,这种威胁迫使公司政策的内容,但在也有一定几率,MySQL没有发现在开源世界或之外存在着接受的问题。

专利

软件专利现在是自由软件运动中的一个避雷针问题,因为他们设置了自由软件无法防御的真正威胁。版权和商标问题一直可以绕开。如果你的部分代码看起来侵害了某人的版权,你只需要重写该部分。如果某人拥有你的项目名称的商标,最坏也就是将项目改名。尽管改名是一种暂时的不便,但长期来讲问题不大,因为代码依然发挥着应有的作用。

但是专利则是针对实现特定思想的完全禁令。无论谁编写的代码,无论使用了什么编程语言。一旦某人指控某个自由软件项目侵害了专利,这个项目必须停止实现某个特定特性,或者面对昂贵和费时的法律诉讼。因为这种法律诉讼的教唆者通常都是有大把钞票的公司—拥有抢先获得专利的资源和倾向—大多数自由软件项目不能负担后一种可能,只能立刻认输,即使他们认为在法庭上该专利很有可能无法强制执行。为了预先避免这种情形,自由软件项目必须防御性的开发编码,预先避免有专利的算法,即使知道那是针对某个编程问题的最佳,甚至是唯一可用的方法。[31]

民意调查和其他证据显示,不仅仅是开源程序员的绝大多数,也包括大多数程序员认为应当完全废止软件专利。[32]开源程序员容易对此有更强的感受,也许会拒绝在与软件专利的集合或强制过于接近的项目中工作。如果你的组织收集软件专利,请以公开和不可更改的方式明确,这些专利不会强加到开源项目上,他们仅用于防御某些其他组织针对你的组织的侵害事件。这不仅仅是做正确的事情,也事关开源公共关系。[33]

不幸的是,因防御目的收集专利是一项有理性的行动。当前的专利系统,至少在美国,本质上是一场军备竞赛:如果你的竞争者获得了大量专利,那么你最好的防御是也获取大量专利,这样如果你遇到了专利侵害诉讼,你可以使用类似的威胁—然后双方通常会坐下来并取得跨许可证交易,这样双方都无需支付费用,当然,不包括他们的知识产权律师。

然而,软件专利对于自由软件的危害不仅仅是对代码开发的威胁。软件专利鼓励了固件设计师中的私密气氛,他们理所当然的担心如果公布他们接口的细节,就是为其的竞争对手提供了技术帮助,使他们可以使用专利侵害诉讼进行打击。这不仅仅是理论上的危险,例如,很明显在显卡工业这存在了很长时间。许多显卡制造商很不情愿发布详细的可以为他们的显卡产出高性能开源驱动的编码规范,因而使自由操作系统无法发挥这些显卡的全部潜力。为什么生产商这样做?这与他们反对软件支持无关;毕竟,兼容的操作系统越多,就会有越多的显卡出售。但是那样做的结果,设计室的门后,这些厂商全部违反了他人的专利,有时是已知,有些则纯属巧合。专利是在如此的不可预测和漫无边际,没有哪个显卡厂商可以确信安全,即使经过了专利搜索。因而,制造商不敢发布他们的所有接口规范,因为这样可以使他们的竞争者可以轻易的指出是否有专利受到了侵害。(当然,这种情形的本性决定了不会从主要来源获得书面承认;我是通过个人交流获得这些信息。 )

一些自由软件许可证有一些与软件专利斗争,或至少不鼓励软件专利的条款。例如GNU GPL包含这些语言:

  7. 若法院判决、专利侵权主张或者其他任何理由(不限于专
利争议)的结果,使得加诸于您的条件(无论是由法院命令
、协议书或其他方式造成)与本授权规定有所冲突,他们并
不免除您对于本授权规定的遵守。若您无法同时符合依本授
权所生义务及其他相关义务而进行发布,那么其结果便是您
不得发布该程序。例如,若专利授权不允许其他人直接或间
接取得复制物,通过您以免付权利金的方式再发布该程序,
您唯一能同时滿足该义务及本授权的方式就是徹底避免进行
该程序的发布。

[...]

本条的目的并不在诱使您侵害专利或其他財产权的权利主张
,或就此类主张的有效性加以争执;本条的唯一目的,是在
保障藉由公共授权惯例所执行自由软件发布系统的完整性。
许多人信赖该系统一贯使用的应用程序,而对经由此系统发
布的大量软件有相当多的贡献;作者/贡献者有权决定他或
她是否希望经由其他的系统发布软件,而被授权人则无该种
选择权。

Apache许可证,版本2.0(http://www.apache.org/licenses/LICENSE-2.0)也包含了反专利的要求。首先,它规定在该许可证分发代码的任何人,隐含包括了一个可能他们持有并可以应用于这些代码的专利的免专利费许可证。其次,更贤明的,通过在主张做出时自动终止他们的隐含专利许可证,它惩罚了任何对代码主张专利侵害的人。

3.专利许可证的授予。

根据本许可证的条款,每个贡献者授予用户永久性的、全球
性的、非专有性的、免费的、无版权费的、不可撤销的(除在
本部分进行说明)专利许可证对作品进行制作、让人制作、使
用、提供销售、销售、进口和其它转让,且这样的许可证仅
适用于在所递交作品的贡献中因可由单一的或多个这样的贡
献者授予而必须侵犯的申请专利。如果用户对任何实体针对
作品或作品中所涉及贡献提出因直接性或贡献性专利侵权而
提起专利法律诉讼(包括交互诉讼请求或反索赔),那么根据
本许可证,授予用户针对作品的任何专利许可证将在提起上
述诉讼之日起终止。


尽管这很有用,不管是法律还是政治,以这种方式将专利防御构建到了自由软件许可证当中,但最终这些步骤不足以形成对于自由软件的专利诉讼威胁的寒翅效用。只有国际版权法的主旨或解释可以解决这个问题。关于此问题的更多信息,以及相关的斗争,请看http://www.nosoftwarepatents.com/。维基百科文章http://en.wikipedia.org/wiki/Software_patent也有许多软件专利的有用信息。我也写过一篇总结软件专利争论的blog,位于http://www.rants.org/2007/05/01/how-to-tell-that-software-patents-are-a-bad-idea/

深入资源

本章仅仅是对自由软件许可证问题的一个介绍。尽管我希望包含能够让你开始自己的开源项目的足够信息,但对于许可证问题的任何深入研究都会迅速耗尽本书所能提供的。下面的列表是一些关于开源许可证的深入材料:

  • Understanding Open Source and Free             Software Licensing作者Andrew M. St. Laurent. O'Reilly媒体出版,第一版2004年8月, ISBN: 0-596-00581-4.

    这是一整本关于开源许可证的书,包含许多本章省略的主题。更多细节见http://www.oreilly.com/catalog/osfreesoft/

  • Make Your Open Source Software GPL-Compatible. Or Else.作者David A. Wheeler,网站 http://www.dwheeler.com/essays/gpl-compatible.html.

    这是一篇非常详细和优秀的文件,论述了为什么要使用GPL兼容的许可证,即使你不使用GPL本身。该文章也涉及了其他许可证问题,有高密度的优秀链接。

  • http://creativecommons.org/

    创作共用是一个旨在提升比传统版权实践所提倡的更灵活和自由的版权的组织。他们不仅仅提供软件的许可证,也包括文字、艺术和音乐、以及所有用户友好的许可证可以访问的;有一些许可证是copyleft,也有一些是非copyleft但是仍然免费,另外则是一些传统的版权,但限制略有放松。创作共用站点对此有着非常清楚的解释。如果我必须描述自由软件运动更广的哲学含义,这就是一个例子。



[30] 之后我使用的“代码”指的是代码和文档。

[31] Sun Microsystems和IBM针对此问题也做出了完全相反的姿态,他们解放了大量软件专利—分别为1600和500—用于自由软件社区。我不是一个律师,因而无法评估这些授予的真实功用,但是即使全部是重要的专利,而且授予的条款确实能够真正的自由用于开源项目的,这也仅仅是沧海一粟。

[32] 这里有一个相关的民意调查http://lpf.ai.mit.edu/Whatsnew/survey.html

[33] 例如,RedHat保证它的专利对开源项目是安全的,见http://www.redhat.com/legal/patent_policy.html

附录 A. 自由版本控制系统

这些是在2007年中段我所知的所有开源版本控制系统。我日常唯一使用的是Subversion。除了Subversion和CVS,我对大多数系统仅有很少,甚至没有任何经验;这里的信息取自他们的网站。也请看http://en.wikipedia.org/wiki/List_of_revision_control_software

CVS已经有很长的历史了,许多程序员已经非常熟悉。它曾经是革命性的:它是第一个开源版本控制系统,在网络上被开发者广泛使用(在我所知的范围内),也是第一个提供匿名只读检出的系统,可以让心开发者轻松的开始参与项目。CVS只能版本化文件,但不包括目录;它能提供分支、标签和优良的客户端性能,但不能很好的处理大文件和二进制文件。它也不支持原子提交。[免责声明:在开始替代CVS的Subversion项目前,我也在CVS开发上活跃了大约5年。]

Subversion是最早也是最重要的CVS替代者—也就是以与CVS近似的方法实现版本控制,但没有经常困扰CVS用户的一些问题和特性缺失。Subversion的一个目标就是使已经习惯CVS的用户能够平滑的过渡到Subversion。这里没有空间详细描述Subversion的特性;相关信息请看它的网站[免责声明:我参与了Subversion开发,也是在日常中唯一使用的系统。]

尽管SVK建立在Subversion之上,但它更类似于下面说的一些非集中式的系统,而不是Subversion。SVK支持分布式开发、本地提交、精密的变更合并和从非SVK版本控制系统镜像目录树的能力。详细信息可以看它的网站。

Mercurial是一个分布式版本控制系统,提供“完整的文件和变更集的跨索引;有效率的带宽和CPU下的HTTP和SSH同步协议;开发者分支间的任意合并;集成独立的web界面;UNIX、MacOS X和Windows跨平台能力”以及更多(前面的特性列表来自Mercurial网站)。

GIT — http://git.or.cz/

GIT是Linus Torvalds开启的一个用于管理Linux kernel源代码的项目。一开始GIT仅仅限于满足kernel开发的需要,但不久就超出了这个范围,被用于Linux kernel之外的项目中。它的主页上说“...设计用于快速有效的处理非常大的项目;主要用于各种开源项目,最引人注目的是Linux kernel。 Git属于分布式源代码管理工具,类似于GNU Arch或Monotone(或私有世界的BitKeeper)。每个Git工作目录是一个完整的版本库,包含了完整的修订跟踪能力,不依赖于网络访问或中央服务器。”

Bazaar还处于开发中。它是GNU Arch协议的一个实现,并依然随着演进的GNU Arch协议保持兼容,而且与GNU Arch社区中对于需要用户友好的任何协议变更的进程进行配合,。

Bazaar-NG — http://bazaar-ng.org/

Bazaar-NG(或bzr)目前由Canonical(http://canonical.com/)开发。它提供了一种在单个项目中结合集中式和非集中式工作的选择。例如,当在办公室中,你可以在一个共享的中央分支上工作;对于实验性变更或离线工作,你可以在笔记本上建立一个分支,并在之后合并回去。

“David的高级修订控制系统(Advanced Revision Control System)是另一个CVS的替代者。它由Haskell编写,已经用于Linux、MacOS X、FreeBSD、OpenBSD和Microsoft Windows。Darcs包含一个可以查看版本库内容的cgi脚本。”

GNU Arch同时支持分布式和集中式的开发。开发者将变更提交到一个可以是位于本地的”归档(archive)“,而管理员可以根据情况将变更推和拉到其他归档。这个方法学暗示了Arch提供比CVS更精密的合并。Arch也允许一个人轻松的为没有提交权限的人建立归档的分支。这里只是简短的描述;更多细节请看Arch网页。

”monotone是自由分布式版本控制工具。它提供了一个简单,单个文件事务的版本存储,包含完全无连接的操作,以及有效率的端到端同步协议。它理解历史敏感的合并,轻量级的分支、集成代码评审和第三方测试。它使用加密的命名和客户端的RSA凭证。它也有不错的国际化支持,没有外部依赖,可以按照GNU GPL运行在linux、solaris、OSX和windows上。“

Codeville — http://codeville.org/

”为什么需要另一种版本控制系统?所有其他版本控制系统需要你小心跟踪分支间的关系,这样你才能不会重复合并同一个冲突。Codeville更加自由。它允许你随时更新或提交到任意版本库,而无需担心重复合并。“

”Codeville为每个完成的变更创建一个标识符,并记住每个文件已经已经应用的变更列表。如果有冲突,它会检查某一方是否已经应用到另一方,如果是这样,则使另一方自动获胜。如果确实有非自动的可合并的版本冲突,codeville则与CVS的工作方式相同。“

”Vesta是一个可移植的SCM[软件配置管理]系统,旨在支持任意规模的,从相对较小(小于10000行源代码)到非常巨大(10000000行)的软件系统的开发。“

”Vesta是一个成熟的系统。它是Compaq/Digital系统研究中心10年研究和开发的成果,它是Compaq的Alpha微处理器团队两年半的时间里生产使用的系统。Alpha团队有超过150个活跃开发者位于距离几千英里的两地,分别在美国的西海岸和东海岸。该团队使用Vesta管理编译超过130MB的源数据,会产生1.5GB的衍生数据。东部的构建每天会产生10到15GB的衍生数据,全部由Vesta管理。尽管Vesta主要关注的是软件开发,但Vesta Alpha团队设法使系统可以用于硬件开发,将它们的硬件描述语言检入到Vesta的源代码控制用具中,并使用Vesta构建器构建模拟器和其他衍生的对象。前Alpha团队的成员,现在是Intel的一部分,在新的微处理器项目中还是继续使用Vesta。“

”Aegis是一个基于事务的软件配置管理系统。它提供了一个框架,在其中一个团队的开发者可以独立的为程序的多个变更工作,而Aegis协调将这些变更集成到程序的主源中,并尽可能减少中断。“

CVSNT — http://cvsnt.org/

”CVSNT一个高级跨平台的版本控制系统。与行业的标准CVS协议相比,添加了许多附加特性。 ... CVSNT是开源,使用GNU GPL许可证的自由软件。“它的特性列表包括通过CVS协议的认证,以及Windows特定的SSPI和活动目录。支持安全传输,通过sserver或加密的SSPI;跨平台性(可以运行于Windows或Unix环境);NT版本与Win32系统完全集成;MergePoint处理的含义是没有更多的标签和合并;处于活跃开发中。

”Meta-CVS是一个建立在CVS周边的版本控制系统。尽管它保留了CVS的大多数特征,包括所有的网络支持,它比CVS能干,更易于使用。“META-CVS的站点包括的特性列表:目录结构版本化,改进的文件类型处理,类似和更用户友好的分支和合并,支持符号链接,附加属性列表的版本化数据,改进的第三方数据导入,以及易于从CVS升级。

OpenCM — http://www.opencm.org/

”OpenCM设计为一个安全的,CVS的高完整性替代产品。关键特性列表可以在特性页面找到。虽然不像CVS那样‘特性丰富’,但它提供了一些CVS缺乏的特性。简要来说,OpenCM提供了第一流的重命名、配置、加密认证和访问控制和第一流的分支。“

”Stellation是一个高级,可扩展的软件配置管理系统,最初由IBM研究院开发。虽然Stellation提供了任何SCM系统提供的所有标准功能,但它也提供了许多高级特性,例如面向任务的变更管理,一致的项目版权化和轻量级的分支,目的是简化由松散结合的开发者组成的大规模团队开发软件系统的难度。“

”PRCS,项目修订控制系统是一系列工具(如CVS)的前端,提供了一种以一个整体管理一组文件和目录的方法,保存了整个集合的一致版本。 ... 它的目的类似于SCCS、RCS和CVS,但是(至少根据其作者称)与这些工具相比更加简单。“

ArX是一个分布式修订控制系统,提供了分支和合并特征,加密数据完整性验证和将归档轻松发布到任意HTTP服务器的能力。

SourceJammer — http://sourcejammer.org/

”SourceJammer是一个使用Java编写的源代码控制和版本化系统。它由服务器端维护文件和版本历史,处理检入、检出等功能的组件,以及客户端向服务器发起请求并管理客户端文件系统的组件组成。 “

”一个使用文件修订变更集,并且分布式而非集中控制的‘现代’系统。只要你有一个邮件帐号,你就可以使用FastCST。对于较大的分发,只需要一个FTP服务器和一个HTTP服务器,或使用内置的‘serve’命令来直接提供服务。所有的变更集都是全局唯一,并且有大量元数据,这样你可以拒绝任何未经测试的东西。合并是通过比较合并的变更集和当前的目录内容完成的,而不是试图将其与另一个变更集合并。“

Superversion — http://www.superversion.org/

”Superversion是一个基于变更集的多用户分布式版本控制系统。它的目标是成为一个行业力量,商业解决方案的开源选择,提供相同(或更简单)的易用性和类似的强大。实际上,从一开始,直觉和可用的效率就处于Superversion开发的最高优先级之一。 “

附录 B. 自由Bug跟踪系统

无论项目使用哪个bug跟踪系统,某些开发者总会有些抱怨。在这一点上bug跟踪系统比其他标准开发工具更具代表性。我想这是因为bug跟踪系统是这样可视化和可交互,可以轻松的想象出一个人可以做的改进(如果某人有时间),并说出这些改进的描述。把这些不可避免的抱怨当作可信也可疑的吧—下面说的跟踪系统都已经足够好了。

在这个列表中,”问题(issue)“用于代表跟踪系统跟踪的条目。但是请牢记每个系统都会有自己的属于,对应的术语包括”制品(artifact)“或”bug“或其它。

Bugzilla — http://www.bugzilla.org/

Bugzilla非常流行,活跃的维护中,看起来让它的用户都很快乐。我曾经有四年在工作中使用了一个修改的变种,很喜欢它。它并不能高度的自定义,而是以一种可以看作其特性的古怪方式:Bugzilla看起来和它创建时差不多,意味着许多开发者已经习惯了它的界面,而且感觉它位于熟悉的版图。

GNU GNATS是最古老的开源bug跟踪系统之一,被广泛使用。它最大的长处是界面的多样性(可以仅仅通过浏览器,也可以通过邮件或命令行工具),以及纯文本问题存储。所有问题数据以文本文件存放在磁盘上这一事实,使我们可以轻松的编写自定义工具获取并解析数据(例如,生成统计报告)。GNATS也可以用多种方法自动吸收邮件,并根据邮件头的模式将其加入到合适的问题中,使得对于用户/开发者的对话的记录非常简单。

RequestTracker (RT) — http://www.bestpractical.com/rt/

RT的网站说”RT是一个企业级问题系统,可以让一组人智能和有效的管理任务、问题和一个团队的用户提交的请求,以及所有的汇总。“RT有一个相对优美的web界面,也有相当广泛的安装基础。界面在视觉上有些复杂,但当你熟悉后就不会觉得那么乱了。RT的许可证是GNU GPL(出于某些原因,他们的web站点说的并不是那么清楚)。

Trac不仅仅是一个bug跟踪系统了,它也是一个集成wiki的bug跟踪系统。它使用wiki链接来关联问题、文件和版本控制变更集和wiki页面。它也很易于设置,并与Subversion集成(见附录 A, 自由版本控制系统)。

Roundup相对来说很易于安装(只需要Python 2.1或更高版本),而且很简单。它包括web,email和命令行接口。问题数据模板、web接口和部分状态转换逻辑是可以自定义的。

Mantis是一个基于web的bug跟踪系统,由PHP编写,并使用MySQL数据库作为存储。它拥有你所期望的特性。个人来见,我觉得web界面非常干净、本能,看起来很简单。

Flyspray — http://www.flyspray.org/

Flyspray是一个使用PHP编写的基于web的bug跟踪系统。它的网页将其描述为“非复杂的”,特性列表包括:支持多种数据库(目前支持MySQL和PGSQL);多项目;‘关注’任务,包括发生变更时提醒(通过email或Jabber);复杂的任务历史;CSS主题;文件附件;高级搜索特性(简单易用);RSS/Atom供稿;wiki和纯文本输入;表决;依赖图表。

Scarab是一个高度可自定义的,完全特性的bug跟踪系统,提供了其他bug跟踪系统所支持的特性的组合:数据条目、查询、报告、相关方通知、评论的交互式累加和依赖跟踪。

它是通过管理web网页实现的。在单个Scarab安装中你可以有多个“模块”(项目)。在给定模块中,你可以创建新的问题类型(缺陷、改进、任务和支持请求等)。并可以增加任意属性,以满足你的项目特定需求。

2004末,Scarab已经接近于1.0发布版本。

Debian Bug跟踪系统(DBTS) — http://www.chiark.greenend.org.uk/~ian/debbugs/

Debian Bug跟踪系统的不寻常之处在于所有问题的输入和处理都是通过邮件完成:每个问题都有自己的专用邮件地址。DBTS的扩展性很好:例如http://bugs.debian.org/有277,741个问题。

因为交互是通过普通的邮件客户端,这个大多数人都熟悉并可以轻松访问的工具完成的,DBTS非常适合处理需要快速分类和响应的大规模数据。当然也有缺点。开发者需要花费时间学习邮件命令系统,用户必须在没有引导他们选择编写信息的web表单的情况下编写bug报告。也有工具可以帮助用户发送更好的bug报告,例如命令行。reportbug程序或Emacs的包debbugs-el。但大多数用户不会使用这个工具;他们只会手工编写邮件,他们可能有,也可能没有遵循你的项目所发布的bug报告指南。

DBTS有一个只读的web界面,用于查看和查询问题。

Trouble-Ticket Trackers

这更像是一个面向服务台的问题跟踪系统,而不是软件bug跟踪。你或许可以在普通的bug跟踪中正常工作,但是因为完整性这里要列出,因为可以理解某个非同一般的项目可能更需要一个trouble-ticket系统,而不是传统的bug跟踪。

Bluetail Ticket Tracker (BTT) — http://btt.sourceforge.net/

BTT算是处于标准trouble-ticket tracker和bug跟踪之间。它提供了隐私特性,这在开源bug跟踪中并不常见:系统的用户被分为Staff、Friend、Customer或Anonymous,取决于不同的类别,会有或多或少的数据。它提供了一些邮件集成,一个命令行界面和将邮件转化为问题的机制。它也提供了一种维护与特定问题不相关信息的特性,例如内部文档或FAQ。

附录 C. 为什么我要关注车棚的颜色?

你不应当;这并没有什么意义,你有更多值得花时间的事情。

Poul-Henning Kamp著名的“车棚”论述(这个第 6 章 交流的节选)是一份关于项目讨论容易陷入误区的雄辩论文。经过允许在这里重新打印,原始的地址是http://www.freebsd.org/cgi/getmsg.cgi?fetch=506636+517178+/usr/local/www/db/text/1999/freebsd-hackers/19991003.freebsd-hackers

Subject: 更绿的草坪上的车棚(任何颜色都可以)...
发自: Poul-Henning Kamp <phk@freebsd.org>
日期: 1999年10月2日 星期六 16:14:10 +0200
Message-ID: <18238.938873650@critter.freebsd.dk>
发送人: phk@critter.freebsd.dk
抄送: Blind Distribution List: ;
MIME-Version: 1.0


[暗送到committers, hackers]

我的上一份小册子已经接收的差不多了,我不太需要再发送一份,今天我
有时间愿意这样做。

我对此类事务的正确决定有一些困难,这一次是密送committers和hackers,
这是我能做的最好的事情了,我不太会订阅hackers,但是之后我订阅的更
多了。

这次触发我的事情是“sleep(1)应当有小数部分”的讨论,这已经困扰我们很长
时间了,已经过了好几周了,我甚至懒得去检查。

如果你错过了这个讨论:那就太恭喜了。

有人认为如果给sleep(1)一个非整形的参数会让这个函数很脏,这点燃了
丛林山火。除此以外我不会再多说,因为与他的讨论长度相比,这确实
是一件太小的事情,于此同时我们还有许多真正的问题。

sleep(1)的传奇是我们在FreddBSD中自行车棚讨论的最吵闹案例。这些
建议已经经过充分思考,我们能够获得与OpenBSD和NetBSD,以及所有已经
编写代码的兼容性。

然而出现和启动了这样多的反对、建议和变更,我们只好以为这些变更
会把瑞士奶酪的空都插满,或者是改变可口可乐的口味等等等等。

“关于自行车棚是什么?”你们中的某些人问过我。

这是一个很长很长的故事,或者说一个很老的故事,但实际上也很短,叫做
“帕金森定律”,包含了管理动态性的深入见地。

你可以在亚马逊找到,也可能在爸爸的书架上找到,它物超所值,也值得花
时间去读,如果你喜欢呆伯特,那一定会喜欢帕金森。

有些人最近告诉我阅读之后发现只有50%可以应用到现如今,我只能说真的
够好了,大多数现代管理书籍的命中率远低于此,要知道这本书已经超过35
年了。

与自行车棚相关的特定例子中,另一个至关重要的部分是核电站,我猜这透
漏了书的年龄。

帕金森展示了如何进入主管委员会并获得建造价值几百万甚至几十亿美元的
核电站,但是当你希望建造自行车棚时,却会陷入无尽的讨论中。

帕金森解释了这是因为核电站是这样巨大,这样昂贵,这样复杂,没有人能
够掌握,甚至只是尝试,他们只是假设某个其他人已经检查了所有细节。
Richard P. Feynmann在他的书中给了许多关于洛斯阿拉莫斯(美国原子弹生
产中心)的有趣而且到位的案例。

另一方面是自行车棚。任何人可以在周末建一个,还能剩下时间看电视比赛。
所以无论如何准备,无论你的建议如何的合理,总会有人展示自己的存在,
他就在这里。

在丹麦,我们称之为“留下指纹”。它是关于个人骄傲和声望,关于能够指向
某个方向,然后说“在这里,我做的。”这是政治家的一个强烈特色,但是如
果有机会,大多数人会试试。想想我们在湿水泥上留下的足迹吧。

我只能低头向最初的建议者表示敬意,因为他将枪口从地毯处转向了剧场的
最高后座,而且这个改变就在我们现在的讨论树中。我会折返回去,来到该
线索中不太顺手的消息中。


而这些告诉我,就像我之前许诺的,我为什么不订阅hackers:


几年之前我就取消订阅了hackers,因为我无法承受紧跟邮件的压力。同样的原
因,我也取消了其他一些列表。


但我还是收到很多邮件。许多直接由过滤器转向到/dev/null:人们喜欢[遗漏的]
永远不会来到我的屏幕,例如用我不理解的语言提交到文档,以及提交到ports。
所有的事情都在没有我的时候发生,甚至我都不知道。


虽然我的邮箱有这些尖利的牙齿,我还是得到太多邮件。

这是更绿的草丛进入视野的地方:

我希望能够减少我们列表中噪音的量,我希望可以让每人经常建造一个车棚,
我真的对他们喷什么颜色并不关心。


第一个愿望是关于公民的,敏感和智能的使用我们的邮件。

如果我可以简明精确的定义一组标准,规定何时某人可以回复,何时不可以
回复邮件,这样任何人都可以认可和遵守它,我会成为一个快乐的人,但我
是太明智了,甚至不会去尝试。

但是先让我建议一些我希望邮件程序可以在人们发送或回复邮件列表时能够
提供的弹出窗口:

      +------------------------------------------------------------+
      | 您的邮件会发送给成百上千的人,他们需要花费10秒钟来阅读才能 |
      | 决定是否有兴趣,阅读您的邮件至少会花费两个人周会。许多接收 |
      | 者会需要为下载邮件而产生花费。                                 |
      |                                                            |
      | 您是否绝对确定该邮件的重要程度值得打扰所有其他人?         |
      |                                                            |
      |                                                            |
      |                  [是]  [修订]  [取消]                      |
      +------------------------------------------------------------+

     
      +------------------------------------------------------------+
      | 警告:您还没有阅读讨论中的所有邮件,其他人已经说了您在回复 |
      | 中所说的内容。在回复任何邮件时,请阅读整个讨论。           |
      |                                                            |
      |                                                            |
      |                      [取消]                              |
      +------------------------------------------------------------+
      
    
      +------------------------------------------------------------+
      | 警告:您的邮件程序未能为您展示所有的信息。逻辑上讲您不可能 |
      | 阅读了整个邮件,并且理解了其内容。                         |
      |                                                            |
      | 在没有全部阅读和认真思考前就发送邮件是不礼貌的。           |
      |                                                            |
      | 一个降温定时器会在一个小时内防止您回复该线索               |
      |                                                            |
      |                       [取消]                               |
      +------------------------------------------------------------+

      
      +------------------------------------------------------------+
      | 您编写这个邮件超过了N.NN字符/秒,不太可能以超过A.AA字符/秒 |
      | 的速度思考和输入,因而您的回复可能不够连贯,思考不充分且过 |
      | 于感情化。                                                 |
      |                                                            |
      | 一个降温定时器会在一个小时内防止您发送任何邮件。           |
      |                                                            |
      |                       [取消]                               |
      +------------------------------------------------------------+
      

我的愿望的第二部分更加感情化。很明显,在sleep(1)线索中我们可以操纵的
不友好火焰,尽管已经在项目中存在多年,从来没有对其有足够的关心,所以
为什么有这么多人被许多年轻人激怒?

我希望我知道。

我知道推理对停止这种“保守主义”无能为力。可能是因为这些人对于之后提供
有形贡献的缺乏,亦或是这些人认为“我们年老还古怪,我们知道年轻人的所作
所为”。


任何一种方式对于项目都是低生产率的,但我对如何停止它没有任何办法。
我只能建议忍住不要给潜伏在邮件列表的怪兽添油加醋:直接忽略他们,不要
回答,忘记他们的存在。

我希望我们可以在FreeBSD得到一个强大且广泛的志愿者基础,而且希望我们
能够团结起来通过吞噬、分化和驱散古怪的老家伙和[漏掉的],防范他们有
任何立足之地。

对于已经潜藏下来,由于参与这些怪人而驱散的人:我只能说不好意思,并
鼓励您无论如何继续尝试,我不希望环境成为这样。

Poul-Henning

附录 D. 报告bug的样例指导

这是Subversion项目针对新用户如何报告bug的在线指导的少许修改版本。为什么项目有一个这样的指导的重要性请见第 8 章 管理志愿者“将每个用户当作潜在的志愿者”一节。原始的文档位于http://svn.collab.net/repos/svn/trunk/www/bugs.html

                       Subversion中如何报告Bug

该文档说明了如何以及在何处报告Bug。(这里不是所有现存Bug的列表 - 您可以
在这里得到。)

何处报告Bug
---------------------

    * 如果是Subversion本身的Bug,可以发送邮件到users@subversion.tigris.org。
      如果确认是bug,或许您可以将其输入问题跟踪系统。(或者如果您对Bug
      非常确定,可以直接在我们的开发列表dev@subversion.tigris.org发布。
      但是,如果您不能确定,最好首先在users@提交;某人会告诉您您所遇到的
      情况是否与预期一致。)

    * 如果是APR库的Bug,请同时在以下列表中报告:
      dev@apr.apache.org,dev@subversion.tigris.org

    * 如果是Neon HTTP库的Bug,请同时在以下列表中报告:
      neon@webdav.org,dev@subversion.tigris.org

    * 如果是Apache HTTPD 2.0的Bug,请同时在以下列表中报告:
      dev@httpd.apache.org,dev@subversion.tigris.org。Apache httpd
      开发者邮件列表流量较大,您的报告可能会被错过。您也可以在
      http://httpd.apache.org/bug_report.html发起一个bug。

    * 如果您的毯子有bug,请给他一个拥抱让它保持温暖。
    

如何报告一个Bug
-------------------

首先,请确保它是一个bug。如果Subversion无法按照您的预期工作,请检查
文档和邮件列表,确保它确实应该按照您的预期工作。当然,如果是常识,
例如Subversion破坏了您的数据并导致您的显示器冒烟,您可以相信自己的
判断。但是如果并不确定,请继续在用户邮件列表users@subversion.tigris.org
中询问,或者在IRC的irc.freenode.net中的频道#svn中询问。

一旦您确定是一个bug,最重要的事情得到一个简单的描述和重现步骤。例如,
如果您发现的bug,只会发生在5个文件的10次提交中,请设法使之在单个文件
的单个提交中发生。重现步骤越简单,开发者越有可能重现bug并修正它。

当您写下重现步骤时,不要仅仅写下使bug发生的散文描述,而应当给出一个
您所运行命令的一系列文本脚本,及其输出。请使用复制粘贴,如果与文件
有关,请包含文件名,如果您觉得与内容有关,也请提供文件内容。最好是能
提供打包的重现步骤脚本,那会使我们获益良多。

快速健全性检查:您正在运行Subversion最近的版本,对吧?:-)或许bug已经
修正;请对最新的Subversion开发树运行重现步骤进行测试。

除了重现步骤,我们也需要重现Bug的完整环境描述。包括:

    * 您的操作系统
    * Subversion的发布版本和修订版本
    * 构建Subversion的编译器和配置选项
    * 您对Subversion的私下修改
    * 运行Subversion的Berkeley DB版本,如果使用的话
    * 所有其他可能相关的事情,宁肯信息多一点也不要少一点。

一旦完成了这些,您就准备好了编写报告了。从对Bug的简短描述开始,也就是
您对Subversion的预期行为方式,与之对应的实际行为方式。虽然Bug对
你是显而易见的,但对其他人可能并不是这么明显,所以最好可以避免猜谜游
戏。然后是环境描述,以及重现步骤。如果您希望也可以包含对于原因的猜测,
甚至是修正bug的补丁,那样就太棒了 - 关于发送补丁的指导请看
http://svn.collab.net/repos/svn/trunk/www/hacking.html#patches。

将所有信息发送到dev@subversion.tigris.org,或者如果您已经在此询问并被
要求发起一个问题,可以根据这里的指导进入问题跟踪系统。

谢谢。我们知道要发起一个有效的bug报告还有很多事情要做,但是一个好的报告
可以为开发者节省大量时间,会让bug更有可能被修正。

附录 E. 版权

本作品按照创作共用署名-相同方式共享 3.0 Unported许可证发布,完整的许可证
可以访问http://creativecommons.org/licenses/by-sa/3.0/deed.zh,或者发送
信件到Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305,
USA。许可证的摘要如下,之后是完整的法律文本,如果您希望使用其他许可证发布
本作品部分或全部内容,请联系作者Karl Fogel<kfogel@red-bean.com>。

-*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*-

您可以自由: 

    * 分享 – 复制、发行、展览、表演、放映、广播或通过信息网络传播本作品
    * 重新修改 – 创作演绎作品

惟须遵守下列条件:

    * 署名 – 您必须按照作者或者许可人指定的方式对作品进行署名。

    * 相同方式共享 — 如果您改变、转换本作品或者以本作品为基础进行创作,
      您只能采用与本协议相同的许可协议发布基于本作品的演绎作品。 

    * 对于本作品的任何复用或分发,必须清晰说明本作品的许可证条款,最佳
      的方法是提供本文的链接。

    * 如果得到版权所有者的许可,以上所有条件可以免除。

    * 本许可证未有任何内容损害或限制作者的道德权利。

-*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*- -*-

   Creative Commons Legal Code: Attribution-ShareAlike 3.0 Unported

CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR
DAMAGES RESULTING FROM ITS USE.

License:

THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS
CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS
PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE
WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
PROHIBITED.

BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND
AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS
LICENSE MAY BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU
THE RIGHTS CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH
TERMS AND CONDITIONS.

1. Definitions

   a. "Adaptation" means a work based upon the Work, or upon the Work
      and other pre-existing works, such as a translation, adaptation,
      derivative work, arrangement of music or other alterations of a
      literary or artistic work, or phonogram or performance and
      includes cinematographic adaptations or any other form in which
      the Work may be recast, transformed, or adapted including in any
      form recognizably derived from the original, except that a work
      that constitutes a Collection will not be considered an
      Adaptation for the purpose of this License. For the avoidance of
      doubt, where the Work is a musical work, performance or
      phonogram, the synchronization of the Work in timed-relation
      with a moving image ("synching") will be considered an
      Adaptation for the purpose of this License.

   b. "Collection" means a collection of literary or artistic works,
      such as encyclopedias and anthologies, or performances,
      phonograms or broadcasts, or other works or subject matter other
      than works listed in Section 1(f) below, which, by reason of the
      selection and arrangement of their contents, constitute
      intellectual creations, in which the Work is included in its
      entirety in unmodified form along with one or more other
      contributions, each constituting separate and independent works
      in themselves, which together are assembled into a collective
      whole. A work that constitutes a Collection will not be
      considered an Adaptation (as defined below) for the purposes of
      this License.

   c. "Creative Commons Compatible License" means a license that is
      listed at http://creativecommons.org/compatiblelicenses that has
      been approved by Creative Commons as being essentially
      equivalent to this License, including, at a minimum, because
      that license: (i) contains terms that have the same purpose,
      meaning and effect as the License Elements of this License; and,
      (ii) explicitly permits the relicensing of adaptations of works
      made available under that license under this License or a
      Creative Commons jurisdiction license with the same License
      Elements as this License.

   d. "Distribute" means to make available to the public the original
      and copies of the Work or Adaptation, as appropriate, through
      sale or other transfer of ownership.

   e. "License Elements" means the following high-level license
      attributes as selected by Licensor and indicated in the title of
      this License: Attribution, ShareAlike.

   f. "Licensor" means the individual, individuals, entity or entities
      that offer(s) the Work under the terms of this License.

   g. "Original Author" means, in the case of a literary or artistic
      work, the individual, individuals, entity or entities who
      created the Work or if no individual or entity can be
      identified, the publisher; and in addition (i) in the case of a
      performance the actors, singers, musicians, dancers, and other
      persons who act, sing, deliver, declaim, play in, interpret or
      otherwise perform literary or artistic works or expressions of
      folklore; (ii) in the case of a phonogram the producer being the
      person or legal entity who first fixes the sounds of a
      performance or other sounds; and, (iii) in the case of
      broadcasts, the organization that transmits the broadcast.

   h. "Work" means the literary and/or artistic work offered under the
      terms of this License including without limitation any
      production in the literary, scientific and artistic domain,
      whatever may be the mode or form of its expression including
      digital form, such as a book, pamphlet and other writing; a
      lecture, address, sermon or other work of the same nature; a
      dramatic or dramatico-musical work; a choreographic work or
      entertainment in dumb show; a musical composition with or
      without words; a cinematographic work to which are assimilated
      works expressed by a process analogous to cinematography; a work
      of drawing, painting, architecture, sculpture, engraving or
      lithography; a photographic work to which are assimilated works
      expressed by a process analogous to photography; a work of
      applied art; an illustration, map, plan, sketch or
      three-dimensional work relative to geography, topography,
      architecture or science; a performance; a broadcast; a
      phonogram; a compilation of data to the extent it is protected
      as a copyrightable work; or a work performed by a variety or
      circus performer to the extent it is not otherwise considered a
      literary or artistic work.

   i. "You" means an individual or entity exercising rights under this
      License who has not previously violated the terms of this
      License with respect to the Work, or who has received express
      permission from the Licensor to exercise rights under this
      License despite a previous violation.

   j. "Publicly Perform" means to perform public recitations of the
      Work and to communicate to the public those public recitations,
      by any means or process, including by wire or wireless means or
      public digital performances; to make available to the public
      Works in such a way that members of the public may access these
      Works from a place and at a place individually chosen by them;
      to perform the Work to the public by any means or process and
      the communication to the public of the performances of the Work,
      including by public digital performance; to broadcast and
      rebroadcast the Work by any means including signs, sounds or
      images.

   k. "Reproduce" means to make copies of the Work by any means
      including without limitation by sound or visual recordings and
      the right of fixation and reproducing fixations of the Work,
      including storage of a protected performance or phonogram in
      digital form or other electronic medium.

2. Fair Dealing Rights.

   Nothing in this License is intended to reduce, limit, or restrict
   any uses free from copyright or rights arising from limitations or
   exceptions that are provided for in connection with the copyright
   protection under copyright law or other applicable laws.

3. License Grant.

   Subject to the terms and conditions of this License, Licensor
   hereby grants You a worldwide, royalty-free, non-exclusive,
   perpetual (for the duration of the applicable copyright) license to
   exercise the rights in the Work as stated below:

   a. to Reproduce the Work, to incorporate the Work into one or more
      Collections, and to Reproduce the Work as incorporated in the
      Collections;

   b. to create and Reproduce Adaptations provided that any such
      Adaptation, including any translation in any medium, takes
      reasonable steps to clearly label, demarcate or otherwise
      identify that changes were made to the original Work. For
      example, a translation could be marked "The original work was
      translated from English to Spanish," or a modification could
      indicate "The original work has been modified.";

   c. to Distribute and Publicly Perform the Work including as
      incorporated in Collections; and,

   d. to Distribute and Publicly Perform Adaptations.

   e. For the avoidance of doubt:

         i. Non-waivable Compulsory License Schemes. In those
            jurisdictions in which the right to collect royalties
            through any statutory or compulsory licensing scheme
            cannot be waived, the Licensor reserves the exclusive
            right to collect such royalties for any exercise by You of
            the rights granted under this License;

        ii. Waivable Compulsory License Schemes. In those
            jurisdictions in which the right to collect royalties
            through any statutory or compulsory licensing scheme can
            be waived, the Licensor waives the exclusive right to
            collect such royalties for any exercise by You of the
            rights granted under this License; and,

       iii. Voluntary License Schemes. The Licensor waives the right
            to collect royalties, whether individually or, in the
            event that the Licensor is a member of a collecting
            society that administers voluntary licensing schemes, via
            that society, from any exercise by You of the rights
            granted under this License.

   The above rights may be exercised in all media and formats whether
   now known or hereafter devised. The above rights include the right
   to make such modifications as are technically necessary to exercise
   the rights in other media and formats. Subject to Section 8(f), all
   rights not expressly granted by Licensor are hereby reserved.

4. Restrictions. 

   The license granted in Section 3 above is expressly made subject to
   and limited by the following restrictions:

   a. You may Distribute or Publicly Perform the Work only under the
      terms of this License. You must include a copy of, or the
      Uniform Resource Identifier (URI) for, this License with every
      copy of the Work You Distribute or Publicly Perform. You may not
      offer or impose any terms on the Work that restrict the terms of
      this License or the ability of the recipient of the Work to
      exercise the rights granted to that recipient under the terms of
      the License. You may not sublicense the Work. You must keep
      intact all notices that refer to this License and to the
      disclaimer of warranties with every copy of the Work You
      Distribute or Publicly Perform. When You Distribute or Publicly
      Perform the Work, You may not impose any effective technological
      measures on the Work that restrict the ability of a recipient of
      the Work from You to exercise the rights granted to that
      recipient under the terms of the License. This Section 4(a)
      applies to the Work as incorporated in a Collection, but this
      does not require the Collection apart from the Work itself to be
      made subject to the terms of this License. If You create a
      Collection, upon notice from any Licensor You must, to the
      extent practicable, remove from the Collection any credit as
      required by Section 4(c), as requested. If You create an
      Adaptation, upon notice from any Licensor You must, to the
      extent practicable, remove from the Adaptation any credit as
      required by Section 4(c), as requested.

   b. You may Distribute or Publicly Perform an Adaptation only under
      the terms of: (i) this License; (ii) a later version of this
      License with the same License Elements as this License; (iii) a
      Creative Commons jurisdiction license (either this or a later
      license version) that contains the same License Elements as this
      License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative
      Commons Compatible License. If you license the Adaptation under
      one of the licenses mentioned in (iv), you must comply with the
      terms of that license. If you license the Adaptation under the
      terms of any of the licenses mentioned in (i), (ii) or (iii)
      (the "Applicable License"), you must comply with the terms of
      the Applicable License generally and the following provisions:
      (I) You must include a copy of, or the URI for, the Applicable
      License with every copy of each Adaptation You Distribute or
      Publicly Perform; (II) You may not offer or impose any terms on
      the Adaptation that restrict the terms of the Applicable License
      or the ability of the recipient of the Adaptation to exercise
      the rights granted to that recipient under the terms of the
      Applicable License; (III) You must keep intact all notices that
      refer to the Applicable License and to the disclaimer of
      warranties with every copy of the Work as included in the
      Adaptation You Distribute or Publicly Perform; (IV) when You
      Distribute or Publicly Perform the Adaptation, You may not
      impose any effective technological measures on the Adaptation
      that restrict the ability of a recipient of the Adaptation from
      You to exercise the rights granted to that recipient under the
      terms of the Applicable License. This Section 4(b) applies to
      the Adaptation as incorporated in a Collection, but this does
      not require the Collection apart from the Adaptation itself to
      be made subject to the terms of the Applicable License.

   c. If You Distribute, or Publicly Perform the Work or any
      Adaptations or Collections, You must, unless a request has been
      made pursuant to Section 4(a), keep intact all copyright notices
      for the Work and provide, reasonable to the medium or means You
      are utilizing: (i) the name of the Original Author (or
      pseudonym, if applicable) if supplied, and/or if the Original
      Author and/or Licensor designate another party or parties (e.g.,
      a sponsor institute, publishing entity, journal) for attribution
      ("Attribution Parties") in Licensor's copyright notice, terms of
      service or by other reasonable means, the name of such party or
      parties; (ii) the title of the Work if supplied; (iii) to the
      extent reasonably practicable, the URI, if any, that Licensor
      specifies to be associated with the Work, unless such URI does
      not refer to the copyright notice or licensing information for
      the Work; and (iv) , consistent with Ssection 3(b), in the case
      of an Adaptation, a credit identifying the use of the Work in
      the Adaptation (e.g., "French translation of the Work by
      Original Author," or "Screenplay based on original Work by
      Original Author"). The credit required by this Section 4(c) may
      be implemented in any reasonable manner; provided, however, that
      in the case of a Adaptation or Collection, at a minimum such
      credit will appear, if a credit for all contributing authors of
      the Adaptation or Collection appears, then as part of these
      credits and in a manner at least as prominent as the credits for
      the other contributing authors. For the avoidance of doubt, You
      may only use the credit required by this Section for the purpose
      of attribution in the manner set out above and, by exercising
      Your rights under this License, You may not implicitly or
      explicitly assert or imply any connection with, sponsorship or
      endorsement by the Original Author, Licensor and/or Attribution
      Parties, as appropriate, of You or Your use of the Work, without
      the separate, express prior written permission of the Original
      Author, Licensor and/or Attribution Parties.

   d. Except as otherwise agreed in writing by the Licensor or as may
      be otherwise permitted by applicable law, if You Reproduce,
      Distribute or Publicly Perform the Work either by itself or as
      part of any Adaptations or Collections, You must not distort,
      mutilate, modify or take other derogatory action in relation to
      the Work which would be prejudicial to the Original Author's
      honor or reputation. Licensor agrees that in those jurisdictions
      (e.g. Japan), in which any exercise of the right granted in
      Section 3(b) of this License (the right to make Adaptations)
      would be deemed to be a distortion, mutilation, modification or
      other derogatory action prejudicial to the Original Author's
      honor and reputation, the Licensor will waive or not assert, as
      appropriate, this Section, to the fullest extent permitted by
      the applicable national law, to enable You to reasonably
      exercise Your right under Section 3(b) of this License (right to
      make Adaptations) but not otherwise.

5. Representations, Warranties and Disclaimer

UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING,
LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR
WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED,
STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF
TITLE, MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY,
OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR NOT
DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED
WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.

6. Limitation on Liability.

EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT
OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

7. Termination

   a. This License and the rights granted hereunder will terminate
      automatically upon any breach by You of the terms of this
      License. Individuals or entities who have received Adaptations
      or Collections from You under this License, however, will not
      have their licenses terminated provided such individuals or
      entities remain in full compliance with those licenses. Sections
      1, 2, 5, 6, 7, and 8 will survive any termination of this
      License.

   b. Subject to the above terms and conditions, the license granted
      here is perpetual (for the duration of the applicable copyright
      in the Work). Notwithstanding the above, Licensor reserves the
      right to release the Work under different license terms or to
      stop distributing the Work at any time; provided, however that
      any such election will not serve to withdraw this License (or
      any other license that has been, or is required to be, granted
      under the terms of this License), and this License will continue
      in full force and effect unless terminated as stated above.

8. Miscellaneous

   a. Each time You Distribute or Publicly Perform the Work or a
      Collection, the Licensor offers to the recipient a license to
      the Work on the same terms and conditions as the license granted
      to You under this License.

   b. Each time You Distribute or Publicly Perform an Adaptation,
      Licensor offers to the recipient a license to the original Work
      on the same terms and conditions as the license granted to You
      under this License.

   c. If any provision of this License is invalid or unenforceable
      under applicable law, it shall not affect the validity or
      enforceability of the remainder of the terms of this License,
      and without further action by the parties to this agreement,
      such provision shall be reformed to the minimum extent necessary
      to make such provision valid and enforceable.

   d. No term or provision of this License shall be deemed waived and
      no breach consented to unless such waiver or consent shall be in
      writing and signed by the party to be charged with such waiver
      or consent.

   e. This License constitutes the entire agreement between the
      parties with respect to the Work licensed here. There are no
      understandings, agreements or representations with respect to
      the Work not specified here. Licensor shall not be bound by any
      additional provisions that may appear in any communication from
      You. This License may not be modified without the mutual written
      agreement of the Licensor and You.

   f. The rights granted under, and the subject matter referenced, in
      this License were drafted utilizing the terminology of the Berne
      Convention for the Protection of Literary and Artistic Works (as
      amended on September 28, 1979), the Rome Convention of 1961, the
      WIPO Copyright Treaty of 1996, the WIPO Performances and
      Phonograms Treaty of 1996 and the Universal Copyright Convention
      (as revised on July 24, 1971). These rights and subject matter
      take effect in the relevant jurisdiction in which the License
      terms are sought to be enforced according to the corresponding
      provisions of the implementation of those treaty provisions in
      the applicable national law. If the standard suite of rights
      granted under applicable copyright law includes additional
      rights not granted under this License, such additional rights
      are deemed to be included in the License; this License is not
      intended to restrict the license of any rights under applicable
      law.

Creative Commons Notice

Creative Commons is not a party to this License, and makes no warranty
whatsoever in connection with the Work. Creative Commons will not be
liable to You or any party on any legal theory for any damages
whatsoever, including without limitation any general, special,
incidental or consequential damages arising in connection to this
license. Notwithstanding the foregoing two (2) sentences, if Creative
Commons has expressly identified itself as the Licensor hereunder, it
shall have all rights and obligations of Licensor.

Except for the limited purpose of indicating to the public that the
Work is licensed under the CCPL, Creative Commons does not authorize
the use by either party of the trademark "Creative Commons" or any
related trademark or logo of Creative Commons without the prior
written consent of Creative Commons. Any permitted use will be in
compliance with Creative Commons' then-current trademark usage
guidelines, as may be published on its website or otherwise made
available upon request from time to time. For the avoidance of doubt,
this trademark restriction does not form part of the License.

Creative Commons may be contacted at http://creativecommons.org/.