# [因为这个我要点名批评  Hacker News ][14]


> “实现高速缓存会花费 30 个小时，你有额外的 30 个小时吗？
不，你没有。我实际上并不知道它会花多少时间，可能它会花五分钟，你有五分钟吗？不，你还是没有。为什么？因为我在撒谎。它会消耗远超五分钟的时间。这一切把问题简单化的假设都只不过是程序员单方面的乐观主义。”
>
> — 出自 [Owen Astrachan][1] 教授于 2004 年 2 月 23 日在 [CPS 108][2] 上的讲座

[指责开源软件总是离奇难用已经不是一个新论点了][5]；这样的论点之前就被很多比我更为雄辩的人提及过，甚至是出自一些人非常推崇开源软件的人士口中。那么为什么我要在这里老调重弹呢？

在周一的 Hacker News 期刊上，一段文章把我逗乐了。文章谈到，一些人认为 [编写代码实现和一个跟 StackOverflow 一样的系统可以简单到爆][6]，并自信的 [声称他们可以在 7 月 4 号的周末就写出一版和 StackOverflow 原版一模一样的程序][7]，以此来证明这一切是多么容易。另一些人则插话说，[现有的][8][那些仿制产品][9] 就已经是一个很好的例证了。

秉承着自由讨论的精神，我们来假设一个场景。你在思考了一阵之后认为你可以用 ASP.NET MVC 来编写一套你自己的 StackOverflow 。我呢，在被一块儿摇晃着的怀表催眠之后，脑袋又挨了别人一顿棒槌，然后像个二哈一样一页一页的把 StackOverflow 的源码递给你，让你照原样重新拿键盘逐字逐句的在你的环境下把那些代码再敲一遍，做成你的 StackOverflow。假设你可以像我一样打字飞快，一分钟能敲 100 个词 ([也就是大约每秒敲八个字母][10])，但是却可以牛叉到我无法企及的打字零错误率。从 StackOverflow 的大小共计 2.3MB 的源码来估计（包括 .CS、 .SQL、 .CSS、 .JS 和 .aspx 文件），就单单是照着源代码这么飞速敲一遍而且一气呵成中间一个字母都不错，你也要差不多用掉至少 80 个小时的时间。

或者你打算从零开始编码实现你自己的 StackOverflow，虽然我知道你肯定是不会那样做的。我们假设你从设计程序，到敲代码，再到最终完成调试只需要区区十倍于抄袭 StackOverflow 源代码的时间。即使在这样的假设条件下，你也要耗费几周的时间昼夜不停得狂写代码。不知道你是否愿意，但是至少我可以欣然承认，如果只给我照抄 StackOverflow 源代码用时的十倍时间来让我自己写 StackOverflow，我可是打死也做不到。

_好的_，我知道你在听到这些假设的时候已经开始觉得泄气了。*你在想，如果不是全部实现，而只是实现 StackOverflow __大部分__ 的功能呢？这总归会容易很多了吧。*

好的，问题是什么是 “大部分” 功能？如果只去实现提问和回答问题的功能？这个部分应该很简单吧。其实不然，因为实现问和答的功能还要求你必须做出一个对问题及其答案的投票系统，来显示大家对某个答案是赞同还是反对。因为只有这样你才能保证提问者可以得到这个问题的唯一的可信答案。当然，你还不能让人们赞同或者反对他们自己给出的答案，所以你还要去实现这种禁止自投自票的机制。除此之外，你需要去确保用户在一定的时间内不能赞同或反对其他用户太多次，以此来防止有人用机器人程序作弊乱投票。你很可能还需要去实现一个垃圾评论过滤器，即使这个过滤器很基础很简陋，你也要考虑如何去设计它。而且你恐怕还需要去支持用户图标（头像）的功能。并且你将不得不寻找一个自己真正信任的并且与 Markdown 结合很好的干净的 HTML 库（当然，假设你确实想要复用 StackOverflow 的 [那个超棒的编辑器][11] ）。你还需要为所有控件购买或者设计一些小图标、小部件，此外你至少需要实现一个基本的管理界面，以便那些喜欢捣鼓的用户可以调整和改动他们的个性化设置。并且你需要实现类似于 Karma 的声望累积系统，以便用户可以随着不断地使用来稳步提升他们的话语权和解锁更多的功能以及可操作性。

但是如果你实现了以上_所有_功能，可以说你_就已经_把要做的都做完了。

除非……除非你还要做全文检索功能。尤其是在“边问边搜”（动态检索）的特性中，支持全文检索是必不可少的。此外，录入和显示用户的基本信息，实现对问题答案的评论功能，以及实现一个显示热点提问的页面，以及热点问题和帖子随着时间推移沉下去的这些功能，都将是不可或缺的。另外你肯定还需要去实现回答奖励系统，并支持每个用户用多个不同的 OpenID 账户去登录，然后将这些相关的登录事件通过邮件发送出去来通知用户，并添加一个标签或徽章系统，接着允许管理员通过一个不错的图形界面来配置这些标签和<ruby>徽章<rt>Badge</rt></ruby>。你需要去显示用户的 Karma 历史，以及他们的历史点赞和差评。而且整个页面还需要很流畅的展开和拉伸，因为这个系统的页面随时都可能被 Slashdot、Reddit 或是 StackOverflow 这些动作影响到。 

在这之后！你会以为你基本已经大功告成了！

……为了产品的完整性，在上面所述的工作都完成之后，你又奋不顾身的去实现了升级功能，界面语言的国际化，Karma 值上限，以及让网站更专业的 CSS 设计、AJAX，还有那些看起来理所当然做起来却让人吐血的功能和特性。如果你不是真的动手来尝试做一个和 StackOverflow 一模一样的系统，你肯定不会意识到在整个程序设计实施的过程中，你会踩到无数的鬼才会知道的大坑。

那么请你告诉我：如果你要做一个让人满意的类似产品出来，上述的哪一个功能是你可以省略掉的呢？哪些是“大部分”网站都具备的功能，哪些又不是呢？

正因为这些很容易被忽视的问题，开发者才会以为做一个 StackOverflow 的仿制版产品会很简单。也同样是因为这些被忽视了的因素，开源软件才一直让人用起来很痛苦。很多软件开发人员在看到 StackOverflow 的时候，他们并不能察觉到 StackOverflow 产品的全貌。他们会简单的把 Stackoverflow 的实现抽象成下面一段逻辑和代码:

```
create table QUESTION (ID identity primary key,
											 TITLE varchar(255), --- 为什么我知道你认为是 255
											 BODY text,
											 UPVOTES integer not null default 0,
											 DOWNVOTES integer not null default 0,
											 USER integer references USER(ID));
create table RESPONSE (ID identity primary key,
											 BODY text,
											 UPVOTES integer not null default 0,
											 DOWNVOTES integer not null default 0,
											 QUESTION integer references QUESTION(ID))
```

如果你让这些开发者去实现 StackOverflow，进入他脑海中的就是上面的两个 SQL 表和一个用以呈现表格数据的 HTML 文件。他们甚至会忽略数据的格式问题，进而单纯的以为他们可以在一个周末的时间里就把 StackOverflow 做出来。一些稍微老练的开发者可能会意识到他们还要去实现登录和注销功能、评论功能、投票系统，但是仍然会自信的认为这不过也就是利用一个周末就能完成了；因为这些功能也不过意味着在后端多了几张 SQL 表和 HTML 文件。如果借助于 Django 之类的构架和工具，他们甚至可以直接拿来主义地不花一分钱就实现用户登录和评论的功能。

但这种简单的实现却_远远不能_体现出 StackOverflow 的精髓。无论你对 StackOverflow 的感觉如何，大多数使用者似乎都同意 StackOverflow 的用户体验从头到尾都很流畅。使用 StackOverflow 的过程就是在跟一个精心打磨过的产品在愉快地交互。即使我没有深入了解过 StackOverflow ，我也能猜测出这个产品的成功和它的数据库的 Schema 没有多大关系 —— 实际上在有幸研读过 StackOverflow 的源码之后，我得以印证了自己的想法，StackOverflow 的成功确实和它的数据库设计关系甚小。真正让它成为一个极其易用的网站的原因，是它背后_大量的_精雕细琢的设计和实施。多数的开发人员在谈及仿制和克隆一款产品的难度时，真的_很少会去考虑到产品背后的打磨和雕琢工作_，因为他们认为_这些打磨和雕琢都是偶然的，甚至是无足轻重的。_

这就是为什么用开源工具去克隆和山寨 StackOverflow 其实是很容易失败的。即使这些开源开发者只是想去实现 StackOverflow 的主要的“规范和标准特性”，而非全面的高级特性，他们也会在实现的过程中遭遇种种关键和核心的问题，让他们阴沟翻船，半途而废。拿徽章功能来说，如果你要针对普通终端用户来设计徽章， 则要么需要实现一个用户可用来个性化设置徽章的 GUI，要么则取巧的设计出一个比较通用的徽章，供所有的安装版本来使用。而开源设计的实际情况是，开发者会有很多的抱怨和牢骚，认为给徽章这种东西设计一个功能全面的 GUI 是根本不可能的。而且他们会固执地把任何标准徽章的提案踢回去，踢出第一宇宙速度，击穿地壳甩到地球的另一端。最终这些开发者还是会搞出一个类似于 Roundup 的 bug tracker 程序都在使用的流程和方案：即实现一个通用的机制，提供以 Python 或 PHP 为基础的一些系统 API， 以便那些可以自如使用 Python 或 PHP 的人可以轻松的通过这些编程接口来定制化他们自己的徽章。而且老实说，PHP 和 Python 可是比任何可能的 GUI 接口都要好用和强大得多，为什么还要考虑 GUI 的方案呢？（出自开源开发者的想法）

同样的，开源开发者会认为那些系统设置和管理员界面也一样可以省略掉。在他们看来，假如你是一个管理员，有 SQL 服务器的权限，那么你就理所当然的具备那些系统管理员该有的知识和技能。那么你其实可以使用 Djang-admin 或者任何类似的工具来轻松的对 StackOverflow 做很多设置和改造工作。毕竟如果你是一个 mods （懂如何 mod 的人）那么你肯定知道网站是怎么工作的，懂得如何利用专业工具去设置和改造一个网站。对啊！这不就得了！ 毋庸置疑，在开源开发者重做他们自己的 StackOverflow 的时候，他们也不会把任何 StackOverflow 在接口上面的失败设计纠正过来。即使是原版 StackOverflow 里面最愚蠢最失败的那个设计（即要求用户必须拥有一个 OpenID 并知道如何使用它）在某个将来最终被 StackOverflow 删除和修正掉了， 我相信正在复制 StackOverflow 模式的那些开源克隆产品也还是会不假思索的把这个 OpenID 的功能仿制出来。这就好比是 GNOME 和 KDE 多年以来一直在做的事情，他们并没有把精力放在如何在设计之初就避免 Windows 的那些显而易见的毛病和问题，相反的却是在亦步亦趋的重复着 Windows 的设计，想办法用开源的方式做出一个比拟 Windows 功能的系统。

开发者可能不会关心一个应用的上述设计细节，但是终端用户一定会。尤其是当他们在尝试去选择要使用哪个应用的时候，这些终端用户更会重视这些接口设计是否易用。就好像一家好的软件公司希望通过确保其产品在出货之前就有一流的质量，以降低售后维护支持的成本一样，懂行的消费者也会在他们购买这些产品之前就确保产品好用，以防在使用的时候不知所措，然后无奈的打电话给售后来解决问题。开源产品就失败在这里，而且相当之失败。一般来讲，付费软件则在这方面做得好很多。

这不是说开源软件没有自己的立足之地，这个博客就运行在 Apache、[Django][12]、[PostgreSQL][13] 和 Linux 搭建的开源系统之上。但是让我来告诉你吧，配置这些堆栈可不是谁都可以做的。老版本的 PostgreSQL 需要手工配置 Vacuuming 来确保数据库的自动清理，而即使是最新版本的 Ubuntu 和 FreeBSD 也仍然要求用户去手工配置他们的第一个数据库集群。

相比之下，MS SQL (微软的 SQL 数据库) 则不需要你手工配置以上的任何一样东西。至于 Apache …… 我的天，Apache 简直复杂到让我根本来不及去尝试给一个新用户讲解我们如何可以通过一个一次性的安装过程就能把虚拟机、MovableType，几个 Diango apps 和 WordPress 配置在一起并流畅地使用。单单是给那些技术背景还不错但并非软件开发者的用户解释清楚 Apache 的那些针对多进程和多线程的设置参数就已经够我喝一壶的了。相比之下，微软的 IIS 7 或者是使用了 OS X 服务器的那个几乎闭源的 GUI 管理器的 Apache ，在配置的时候就要简单上不止一个数量级了。Django 确实是一个好的开源产品，但它也 _只是_ 一个基础构架，而并非是一个可以直接面向终端普通用户的商业产品。而开源真正的强项就 _恰恰在_ 这种基础构架的开发和创新上，这也正是驱使开发者为开源做贡献的最本真的动力。

所以我的结论是，如果下次你再看到一个你喜欢的应用程序，请好好细心地揣摩一下这款产品，揣摩一下所有的那些针对用户的体贴入微的设计细节。而不是武断的认为你可以轻轻松松的在一周之内就用开源工具做一个和这个应用一摸一样的产品出来。那些认为制作和实现一个应用程序如此简单的人，十之八九都是因为忽略了软件开发的最终产品是要交给用户去用的。

-------------------------------------------------------------------------------

via: https://bitquabit.com/post/one-which-i-call-out-hacker-news/

作者：[Benjamin Pollack][a]
译者：[hopefully2333](https://github.com/hopefully2333)，[yunfengHe](https://github.com/yunfengHe)
校对：[yunfengHe](https://github.com/yunfengHe)，[wxy](https://github.com/wxy)

本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

[a]:https://bitquabit.com/meta/about/
[1]:http://www.cs.duke.edu/~ola/
[2]:http://www.cs.duke.edu/courses/cps108/spring04/
[3]:https://bitquabit.com/categories/programming
[4]:https://bitquabit.com/categories/technology
[5]:http://blog.bitquabit.com/2009/06/30/one-which-i-say-open-source-software-sucks/
[6]:http://news.ycombinator.com/item?id=678501
[7]:http://news.ycombinator.com/item?id=678704
[8]:http://code.google.com/p/cnprog/
[9]:http://code.google.com/p/soclone/
[10]:http://en.wikipedia.org/wiki/Words_per_minute
[11]:http://github.com/derobins/wmd/tree/master
[12]:http://www.djangoproject.com/
[13]:http://www.postgresql.org/
[14]:https://bitquabit.com/post/one-which-i-call-out-hacker-news/
