面对软件错误构建可靠的分布式系统-12附录

附录A 致谢

Erlang系统、OTP库集、还有Erlang内置的所有应用都是许多人进行了大量的工作后的集体成果。

致谢部分总是很难写的,因为我不想弄丢任何对系统有贡献的人,也不想出任何差错——我将力图做到准确,但是如果还有任何疏忽或差错,我先在这里表示歉意。

首先,我要感谢当初的管理者们,他们使得一切成为可能。我在Ericsson时候的领导Bjarne Däcker大力支持我们的工作,为了维护我们而积极地斗争——谢谢你,BjarneTorbjörn JonssonBjarne的领导)也为了维护Bjarne而积极地斗争,谢谢你,Torbjörn,我从你身上学到了许多东西。Jane Walerud(即Open Source Erlang的幕后策划者),Bluetail的常务懂事,是她教会我如何经营一家小公司。

现在轮到Erlang的开发者的一个大名单了。Erlang团队的最初成员有我、Robert VirdingMike Williams。当初我编写了Erlang的编译器,Robert编写了库,Mike编写了JAM仿真器。Robert和我写过多个版本的Erlang仿真器,大部分是用Prolog写的,后来MikeC重写了一遍。两年后,Claes Wikström(我们叫他Klacke)加入了进来,为Erlang增加了分布式的能力,Bogumil Hausman这时候发明了改进版的Erlang虚拟机,即BEAM1

还有CSLab的许多成员先后加入到我们的项目中,用Erlang编写了许多程序,后来又去做其它的事情去了。Carl Wilhelm Wellin写了yeccKlackeHans Nilsson写了mnesiamnemosyneTony RogvallKlackeErlang语言增加了二进制语法,使得Erlang可以如此漂亮地支持网络编程。Per Hedeland的耐心相当好,回答了我所有Unix方面的愚蠢的问题,确保了我们的系统能够一直工作的很好,并且他主动解决了Erlang仿真器中的一些顽疾。Magnus Fröberg编写了调试器。Torbjörn Törnkvist编写了接口生成器,使得Erlang可以与C交互。

ErlangCSLab搬出来, OTP诞生的时候,我们的团队扩大了,并且进

1 Bogdans Erlang Abstract Machine,即Bogdans Erlang虚拟机。


181

行了改组。Magnus FröbergMartin Björklund和我设计了OTP的库结构和behaviour的结构,OTPbehaviour库是在我们实验室多年的思想积累之上编写的。Klacke之前就编写过一个类似于gen_server通用服务器Peter Högfelt之前也写过另一个通用服务器,是监督树模型的早期的版本。关于进程监督的许多思想来源于Peter在移动服务器项目中的工作。

我离开Ericsson之后,系统的日常维护和开发交给了新一带的程序员们。Björn Gustavsson维护着仿真器模块,Lars ThorsénKenneth LundinKent BoortzRaimo NiskanenPatrik NyblomHans BolinderRichard GreenHåkan MattssonDan Gudmundsson维护着OTP库集。

而现在呈现在我们的用户面前的Erlang/OTP系统,则是从与我们的忠实的用户们的互动中,已经得到了非常显著的提高。

我们的第一个用户群,即用Eralng构建第一个正式产品的团队是:Mats PerssonKerstin ÖdlingPeter HögfeldÅke RosbergHåkan KarlssonHåkan Larsson

AXD301项目中,Ulf WigerStaffan Blau在首次用Erlang实现运营商级的应用做了许多意义非凡的开创性工作。

无论是Ericsson内部的用户,还是Ericsson之外的用户,都做得非常棒。英国的one-2-one公司(现在是T-mobile公司)的Sean Hinde简直是一个人的Erlang工厂

最后要说,Erlangmailing list也是我们的灵感和勇气的源泉。今天无论是任何人想要了解Erlang的任何事,他们只需要问一下Erlangmailing list,就可以很快得到一个准确而全面的回答。感谢mailing list中的所有人,特别是那些素未谋面,确有过很长很长的有意思的email来往的人。

最后,感谢我在SICS的朋友和同事们,感谢Seif Haridi教授,是他审阅了这篇论文。感谢Per Brand,是他鼓励我写这篇论文的。感谢分布式系统实验室的所有成员们,与他们的讨论给我留下了深刻的印象。

谢谢大家!


182 183

附录B 编程规范和约定

Erlang进行程序开发的

编程规范和约定1

K Eriksson, M Williams, J Armstrong

1996 3 13

摘要

本文描述了用Erlang编写系统的一些编程规范和建议。

注释

本文档只是一个初步文档,并不完整。

EBCBase System的使用在这里并没有做要求,如果要使用Base System,那么就应该在设计的很早的阶段就遵守它。这些要求已经写入了1/10268-AND 10406 UenMAPStart and Error Recovery一文。

1 这里发表的是对Ericsson内部文档(EPK/NP 95:035)重新整理后的版本——原文已经作为Open Source Erlang的配套资料的一部分公开发布。


184

目录

1 目的.................................................................................................................................187

2 结构和Erlang术语............................................................................................................187

3 软件工程原则...................................................................................................................188

3.1 从一个模块导出的函数越少越好........................................................................188

3.2 尽量降低模块间的依赖........................................................................................188

3.3 将公用的代码放入库中........................................................................................189

3.4 复杂的脏的代码隔离到单独的模块中........................................189

3.5 不要对调用者如何使用函数调用的结果作出任何假设....................................190

3.6 抽象出代码的共用样式或行为............................................................................191

3.7 自顶向下................................................................................................................191

3.8 不要优化代码........................................................................................................191

3.9 牢记最小惊诧原则..........................................................................................191

3.10 尽力消灭副作用..................................................................................................192

3.11 不要让私有数据结构从模块中泄漏出来..................................................192

3.12 使代码达到最大确定性(deterministic.........................................................195

3.13 不要防御式编程..........................................................................................196

3.14 用设备驱动隔离硬件接口..................................................................................196

3.15 doundo都在一个函数里做...............................................................................196

4 错误处理...........................................................................................................................198

4.1 将错误处理代码和正常情况代码分离................................................................198

4.2 标明错误内核........................................................................................................198

5 进程、服务器和消息.......................................................................................................198

5.1 将一个进程的实现放在一个模块中....................................................................198

5.2 利用进程来组织系统............................................................................................199

5.3 注册进程................................................................................................................199

5.4 给系统中的每个真正的并发活动注册唯一一个并行进程................................199

5.5 每个进程应该只有一个角色........................................................................199

5.6 在服务器和协议处理器中尽可能地使用通用函数............................................200

5.7 给消息打上标签....................................................................................................200

5.8 清掉未知消息........................................................................................................201

5.9 编写尾递归的进程处理函数................................................................................202

5.10 接口函数..............................................................................................................203

5.11 超时......................................................................................................................204

5.12 捕获退出信号(trapping exits........................................................................204

6 一些Erlang的特别约定....................................................................................................204

6.1 使用record作为标准数据结构..............................................................................204

6.2 使用选择器(selector)和构造器(constructor..............................................204

6.3 给返回值打标签....................................................................................................205

6.4 使用catchthrow时要极其小心..........................................................................205

6.5 使用进程字典(process dictionary)时要极其小心...........................................206

6.6 不要使用import.....................................................................................................207

6.7 导出(export)函数..............................................................................................207


185

7 特别的词汇和风格约定...................................................................................................208

7.1 不要编写深度嵌套的代码....................................................................................208

7.2 不要编写很大的模块............................................................................................208

7.3 不要编写很长的函数............................................................................................208

7.4 不要编写很长的代码行........................................................................................208

7.5 变量名....................................................................................................................208

7.6 函数名....................................................................................................................209

7.7 模块名....................................................................................................................209

7.8 程序格式保持一致风格........................................................................................210

8 代码文档化.......................................................................................................................210

8.1 注明代码归属........................................................................................................210

8.2 提供代码中对规格说明的引用............................................................................211

8.3 将所有错误文档化................................................................................................211

8.4 将消息中的所有的标准数据结构文档化............................................................211

8.5 注释........................................................................................................................211

8.6 注释每个函数........................................................................................................212

8.7 数据结构................................................................................................................213

8.8 文件头,版权........................................................................................................213

8.9 文件头,修订历史................................................................................................213

8.10 文件头,描述......................................................................................................213

8.11 不要注释过时代码——删除它..........................................................................214

8.12 使用一个源代码控制系统..................................................................................214

9 最普遍的错误...................................................................................................................214

10 必备文档.........................................................................................................................215

10.1 模块描述..............................................................................................................215

10.2 模块描述..............................................................................................................215

10.3 进程......................................................................................................................216

10.4 错误消息..............................................................................................................216


186

1 目的

本文罗列了在使用Erlang说明和编写软件系统时应该考虑的一些方面。本文并不尝试对与Erlang的使用没有太大关系的一般的需求和设计活动给出一个完整的描述。

2 结构和Erlang术语

Erlang系统被划分成模块(module)。模块由函数(function)和属性(attribute)组成。函数要么只能在模块内部可访问,要么被导出(exported),即能够被其它模块中的函数调用。属性由-开头,被放在模块的开头处。

Erlang编写的系统,所有的工作(work)都是由进程(process)来完成的。一个进程是一个可以使用其他模块中函数的作业(job)。进程之间通过发送消息(sending message)来进行通信,一个进程可以决定准备接收什么消息,而其它的消息就排队等待,直到进程准备好接收它们。

一个进程可以通过与其它进程建立连接(link)来监控其它进程的存在。当一个进程终结时,会自动向与之相连的进程发送一个退出信号(exit signal),收到一个退出信号以后,一个进程的默认行为就是终结掉自己,并向与之相连的所有进程传播该退出信号。一个进程可以通过捕获退出信号(trap exits)来改变这种默认行为,这样可以把发送给一个进程的所有退出信号转换成正常消息。

纯函数(pure function)是一个不管处于什么样的上下文中,只要使用的参数相同,就会返回相同结果的函数。这也是我们平常期望的一个数学函数的行为。一个非纯函数的函数我们说它具有副作用(side effects)。

如果一个函数做了下面的这些事情,一般就会产生副作用:a)发送一个消息;b)接收一个消息;c)调用exitd)调用任何会改变一个进程的环境或操作模式的BIF(例如get/1put/2erase/1process_flag/1等等)。

警告:这篇文档中就包含有坏代码的例子。


187

3 软件工程原则

3.1 从一个模块导出的函数越少越好

模块是Erlang的基本代码结构实体。一个模块可以包含有大量的函数,但是只有包含在导出列表中的函数才能够在模块外部被调用。从一个模块的外部看,模块的复杂性决定与它所导出的函数的个数。一个只导出一、两个函数的模块肯定比导出几十个函数的模块更容易理解。

用户希望一个模块的导出函数/非导出函数的比率越低越好,这样他只需要理解导出函数的功能就足够了。

还有,只要模块的外部接口保持不变,模块代码的编写者和维护者可以任意改变模块的内部结构。

3.2 尽量降低模块间的依赖

一个调用了许多不同模块中的函数的模块要比只调用了很少的几个模块中的函数的模块要难以理解得多。

这是因为每次我们修改一个模块的接口时,我们必须要检查所有调用了该模块的地方。降低这种模块间的相互依赖将会简化这些模块的维护工作。

我们可以通过减少一个特定模块调用的不同模块的数量来简化我们的系统结构。

还要注意,模块间的调用依赖关系最好形成的是树型结构而不是环状结构。例如:


188

而不要是:

3.3 将公用的代码放入库中

公用的代码应该放入库中。这个库应该是相关的函数的集合,应该努力使得库中包含的是同类型的函数。因此,像一个叫lists的库只包含对列表操作的函数,这是一个好的决策;而一个叫lists_and_maths的库既包含对列表的操作的函数,也包含有数学运算的函数,就不是一个好的决策。

最好的库函数是没有副作用的。含有带副作用的函数的函数的库限制了其可复用性。

3.4 复杂的脏的代码隔离到单独的模块中

一个问题的解决通常需要综合用到净代码和脏代码,那么就把净代码和脏代码放入彼此隔离的模块中。

脏代码是指做了一些脏事情的代码。如:

      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值