第二章 邮件必达

简介: 自1993年起,我就在宾州西切斯特的一家提供免费网络服务的小公司CCIL(Chester County InterLink)负责技术工作。我协同创建了公司并编写了一个专用的多用户论坛程序——你可以通过telnet连接locke.ccil.org一探究竟。

1993年起,我就在宾州西切斯特的一家提供免费网络服务的小公司CCILChester County InterLink)负责技术工作。我协同创建了公司并编写了一个专用的多用户论坛程序——你可以通过telnet连接locke.ccil.org一探究竟。如今它在三十条线路上支持着近三千名用户。这使我可以每天二十四小时的通过CCIL56K专线上网——其实,这是工作需要。

我已经惯于使用网络邮件了,但不时地登录locke检查邮件实在很烦人。我所希望的是有办法能将邮件转送到我家的机器(snark)上,并在到达的时候通知我,而且可以用本地工具进行处理。

互联网默认的邮件传输协议SMTP显然不能满足我的要求,STMP是为全时在线的机器设计的,而我家的机器不可能全天在线——况且它也没有一个固定的IP。我需要一个程序,让我能在拨号之后链接到服务器上把邮件下载到本地。我知道有这种工具存在,它们大都使用一种称为POP的简单协议,现在常用的邮件客户端软件都支持这个协议,但那时,我的邮件阅读软件并不支持它。

我在网上找到了三四个这样的POP3客户端软件。其中一个我用了一段时间,可是他明显缺少一个功能:抽取正确的邮件地址。

事情是这样的,如果locke上一个叫乔的人发给我一封邮件,我将其下载到snark上。可是在回复的时候我的邮件程序会高高兴兴的把信投寄给一个在snark上并不存在的乔。手工修正地址是件痛苦的事。

显然这是一件应该由电脑来完成的事情,可是没有一个现存的POP软件知道如何解决。这给我们上了第一课:

 

1.好软件都源自解决开发者的切身之痛。

Every good work of software starts by scratching a developer's personal itch.

 

或许这是众所周知的(不是有句名谚叫做“需要是发明之母”吗?),可是有那么多软件开发者为了薪水把时间都消耗在他们及不喜欢又不需要的程序上了。然而这却不会发生在Linux世界,或许这就是Linux社区产品平均质量很高的原因吧?

那么我是否应该疯狂的投入战斗,编写一套新的POP软件来和它们一较高下呢?打死都不干!相反,我仔细地检视我手中的东西,看看哪个最接近需求。因为:

 

2.优秀的程序员知道要写什么,而伟大的程序员知道要改写(和重用)什么。

Good programmers know what to write. Great ones know what to rewrite (and reuse).

 

我不敢自诩伟大,但是我努力效法那些伟大的程序员。他们都有一个重要的特点——建设性的懒惰,因为我们要的是结果而不是过程。从一个优质的部分接手总比你白手起家要容易的多。

以李纳斯为例,他并没有从零开始编写Linux。相反他借重了Minix的代码和理念。(Minix是一个用于个人电脑的小型类Unix操作系统)虽然Minix的全部代码最终被全部摘除或重写了,但是它毕竟为Linux充当了学步车。

出于同样的考虑,我开始寻找一个现存的有最有条理的POP程序来作为开发基础。

Unix世界共享源代码的传统让我们很容易的对它们并重新加以利用。(这也是为什么尽管GNUUnix成见很深,却依然采用Unix为基础开发操作系统的原因)而Linux世界更是把这种传统发挥到了技术的极限。在浩如烟海的Linux开放代码中花点时间来寻找一个不错的程序,总比去别处要强的多。

加上我之前用到的,第二次的搜索让我有了九个候选对象:fetchpopPopTartget-mailgwpoppimppop-perlpopcpopmailupop。首先选用的是肖恩[1]fetchpop,我对其做了一些改动并将改写邮件地址的功能加了进去。后来他把这些改动加入到了自己的1.9版本中。

几周之后,我偶然接触到了卡尔·哈里斯popclient代码时,问题出现了。尽管fetchpop有那么多优秀的原创功能(比如他的后台程序),但是却只能支持POP3协议,而且代码不够老练(肖恩很聪明,但是缺少经验)。卡尔的代码则更好,专业而稳固。但是却缺少很多重要的功能——那些fetchpop中的妙作(包括我加入的部分)。

是继续使用fetchpop还是改用popclinent?如果转换的话,就意味着我不得不放弃已经完成的代码来换取一个更好的开发基础。

一个实际的转换动机是去支持更多协议。POP3使用最广,却不是唯一。Fetchpop和那个竞争对手同样不支持POP2RPOPAPOP。出于好玩,我那时已经有了在其中加入IMAP(最新设计的,最强大的POP协议)的模糊想法。

其实我还有一个更正式的理由支持我更换软件,这是我在玩Linux之前就学到的:

 

3.为舍弃而计划,无论如何,你都要这样做。”(弗雷德里克·布鲁克斯,《人月神话》第十一章,)[2]

Plan to throw one away; you will, anyhow. (Fred Brooks, The Mythical Man-Month, Chapter 11)

 

换言之,当你开始尝试解决一个问题的之后,你通常并不知道症结所在。再次着手,或许能够游刃有余。所以想把事情做好,你得准备“至少重来一次”。【注】

好吧,(我对自己说)对fetchpop的修改就算是我的第一次吧。于是,放弃了它。

1996625,我给卡尔寄去了第一批程序补丁。才发现他对这个程序基本失去了兴趣。代码已经乏人照料很久了,小错误流连不去,有很多改动要做。我们一拍即合,由我接手。

不经意间,工作的规模扩大了。我不再只是真对一个POP客户端进行修补,而是要负责维护整个程序。一些可能会引发变革的想法在我脑海中浮现。

在鼓励代码共享的软件文化里,这样的演进方式是自然而然的。我只是将这些原理付诸实践:

 

4.只要你态度正确,有趣的问题就会找上门来。

If you have the right attitude, interesting problems will find you.

 

卡尔的态度更加重要,他懂得:

 

5.对一个项目失去兴趣的时候,你的最后责任就是找一个称职的接班人。

When you lose interest in a program, your last duty to it is to hand it off to a competent successor.

 

为了创造一个最佳的解决方案,我和卡尔不谋而合。唯一的问题是,我是否能证明我的能力。一旦我做到了,卡尔便优雅而迅速的交托给我。希望有一天轮到我这么做的时候,我能同样的出色。

 

 

注:
著名的计算机学家乔·本特利Jon Bentley)在其著作《编程珠玑》(Programing Pearls)对其做了如下评注:“如果你舍弃了一个,你还会舍弃第二个”。他的话完全正确,布鲁克斯本特利指出:不要期望一蹴而就,以一个好主意重头来过通常要比梳理一团乱麻要好的多。

 

译者按:

1.肖恩Sean Ohfetchpop的作者,书中出现的名称是Seung-Hong OhSean是其英文名。有译者将其音译作“欧松宏”,我认为这个译音有失精当。因为Oh Seung Hong这三个拼写在韩英互译时是很常见的。与其对应的韩文大致是“오승홍”,译成汉语则大致是“吴承弘”。在没有办法联系到作者本人的情况下,为了行文不出差错,我选用了其英文名。

2.The Mythical Man-MonthFrederick P. Brooks。《人月神话》,作者弗雷德里克·布鲁克斯。计算机学家,被称作“IBM 360之父”,曾获得图灵奖和美国国家技术奖——两个计算机界举足轻重的奖项。《人月神话》是其随笔集,其在书中对繁复的工程管理做了洞见的观察。在第十一章《未雨绸缪》(Plan to Throw One Away)中其提出了舍弃型原型的概念。本文引言是强调“为舍弃而计划”,“one”用来指代一个计划或者原型,我认为不能直接译为“一个”所以用了代词“它”放宽其概念。

相关文章
|
前端开发 JavaScript 定位技术
threejs绘制风羽
threejs绘制风羽
543 0
|
存储 机器学习/深度学习 消息中间件
数据处理能力相差 2.4 倍?Flink 使用 RocksDB 和 Gemini 的性能对比实验
在本篇文章中我们将对 RocksDB、Heap 和 Gemini 在相同场景下进行压测,并对其资源消耗进行对比。测试的 Flink 内核版本为 1.10.0。
数据处理能力相差 2.4 倍?Flink 使用 RocksDB 和 Gemini 的性能对比实验
|
Java 数据安全/隐私保护 索引
使用Java中的随机函数生成随机数
在Java编程中,我们经常需要生成随机数来模拟各种情况或者作为密码等敏感信息的一部分。Java提供了一个内置的随机函数库,可以轻松地生成各种类型的随机数。本篇博客将介绍如何使用Java中的随机函数来生成随机数。
419 1
|
11月前
|
数据采集 人工智能 监控
揭秘数据治理:七步工作法&十大准则全解析
数据治理的“七步工作法”与“十大准则”为企业构建科学、系统、高效的数据治理体系提供了重要的指导和借鉴。企业应结合自身实际情况,灵活运用这些方法和准则,充分挖掘数据潜能,赋能业务创新,实现数字化转型的稳健推进。
|
7月前
|
机器学习/深度学习 编解码 异构计算
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 ICCV 2023的EfficientViT 用于高分辨率密集预测的多尺度线性关注
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 ICCV 2023的EfficientViT 用于高分辨率密集预测的多尺度线性关注
135 0
RT-DETR改进策略【模型轻量化】| 替换骨干网络为 ICCV 2023的EfficientViT 用于高分辨率密集预测的多尺度线性关注
|
11月前
|
搜索推荐 数据安全/隐私保护
智能玻璃:自适应环境变化的建筑材料
【10月更文挑战第17天】智能玻璃是一种能够根据外界环境条件自动调节透明度、颜色或隔热性能的高科技建筑材料。本文介绍了智能玻璃的工作原理(如电致变色、热致变色、光致变色)、分类、应用领域(建筑、汽车、航空)以及其在节能环保、隐私保护、光线控制等方面的卓越表现。未来,智能玻璃将更加智能化,助力建筑行业向绿色化、可持续方向发展。
|
11月前
|
NoSQL 网络协议 Linux
卡速售电商系统2.0搭建教程(详细图文版)
本文详细介绍了在Linux服务器上(推荐CentOS 7.x / Ubuntu 20.04)使用宝塔面板安装和配置卡速售的安装及配置过程,包括安装PHP 8.0及其扩展(fileinfo、redis、swoole4)、调整内存限制、配置二进制日志等。同时提供了安装系统程序的具体步骤,如添加站点、上传并解压文件、设置运行目录及伪静态规则,并通过进程守护管理器启动程序。最后附有故障排查指导,确保安装顺利进行。
217 5
|
JavaScript
Vue3相关组件项目依赖依赖版本信息
这篇文章展示了一个Vue 3项目中使用的组件和库的依赖版本信息,包括`ant-design-vue`、`swiper`、`vue`、`vue-router`等,以及开发依赖如`vite`、`vue-tsc`、`eslint`等。
185 0
Vue3相关组件项目依赖依赖版本信息
|
JSON 网络安全 PHP
WordPress上传图片错误:不是合法的JSON响应
最近在迁移WordPress到新服务器时遇到一个问题,就是在编辑文章上传图片时,会报错:此响应不是合法的JSON响应,经过多方验证,最后得出结论,是由于php的一些模块没有开启的原因,下面就详细讲一下,php安装后应该开启哪些模块及开启方法。
259 0
|
SQL 开发框架 .NET
C#进阶-LINQ表达式之多表查询Ⅱ
本篇文章我们将演示LINQ扩展包基础语法里的多表查询 ,以Join连接查询为主要内容。目前LINQ支持两种语法,我会在每个案例前先用大家熟知的SQL语句表达,再在后面用C#的两种LINQ语法分别实现。LINQ语法第一次接触难免感到陌生,最好的学习方式就是在项目中多去使用,相信会有很多感悟。
265 0