题外:从老家从早到晚总算折腾回了杭州,进站太早,火车晚点,提包带断,什么倒霉事也遇上了,先发个已经整理好的部分,后续仍待整理。
多道程序设计:分离进程为独立的功能
无论在协作进程还是在同一进程的协作子过程层面上,Unix设计风格都运用“做单件事并做好的方法“,强调用定义良好的进程间通信或共享文件来连通小型进程,提倡将程序分解为更简单的子进程,并专注考虑这些子进程间的接口,这至少需要通过以下三种方法来实现:
1、降低进程生成的开销(思考下Erlang的process)
2、提供方法(shellout、IO重定向、管道、消息传递和socket)简化进程间通信
3、提倡使用能由管道和socket传递的简单、透明的文本数据格式
Unix IPC方法的分类:
1、将任务转给专门程序,如system(3),popen调用等,称为shellout
2、Pipe、重定向和过滤器,如bc和dc
3、包装器,隐藏shell管线的复杂细节。
4、安全包装器和Bernstein链
5、主/从进程
6、对等进程间通信:
(1)临时文件
(2)信号
(3)系统守护程序和常规信号
(4)socket
(5)共享内存,mmap
远程过程调用(RPC)的缺憾:
1、RPC接口很难做到可显,如果不编写和被监控程序同样复杂的专用工具,也难以监控程序的行为。RPC接口和库一样具有版本不兼容的问题,由于是分布式的,因此更难被追查。
2、类型标记越丰富的接口往往越复杂,因而越脆弱。随着时间的推移,由于在接口之间传递的类型总量逐渐变大,单个类型越来越复杂,这些接口往往产生类型本体蠕变问题。这是因为接口比字符串更容易失配;如果两端程序的本体不能正确匹配,要让它们通信肯定很难,纠错更是难上加难。
3、支持RPC的常见理由是它比文本流方法允许“更丰富”的接口,但是接口的功能之一就是充当阻隔点,防止模块的实现细节彼此泄漏,因此,支持RPC的主要理由同时恰恰证明了RPC增加而不是降低了程序的全局复杂度。
Unix传统强烈赞成透明、可显的接口,这是unix文化不断坚持文本协议IPC的动力。
ESR在这里还谈到XML-RPC和SOAP等协议,认为是RPC和unix对文本流支持的一种融合,遗憾的是SOAP本身也成为一种重量级、不那么透明的协议了,尽管它也是文本协议。
线程是有害的:
线程是那些进程生成昂贵、IPC功能薄弱的操作系统所特有的概念。
尽管线程通常具有独立的局部变量栈,它们却共享同一个全局内存,在这个共享地址空间管理竞争和临界区的任务相当困难,而且成为增加整体复杂度和滋生bug的温床。除了普通的竞争问题之外,还产生了一类新问题:时序依赖。
当工具的作用不是控制而是增加复杂度的时候,最好扔掉从零开始。
微型语言:寻找歌唱的乐符
(注,这里谈的微型语言,就是现在比较热门的词汇DSL)
对软件错误模式进行的大量研究得出的一个最一致的结论是,程序员每百行程序出错率和所使用的编程语言在很大程度上是无关的。更高级的语言可以用更少的行数完成更多的任务,也意味着更少的bug。
防御设计不良微型语言的唯一方法是知道如何设计一个好的微型语言。
语言分类法:
对微型语言的功能测试:不读手册可以编写吗?
现代微型语言,要么就完全通用而不紧凑,要么就非常不通用而紧凑;不通用也不紧凑的语言则完全没有竞争力。
一些引申想法:我认为这个评判标准也可以用在任何编程语言上,以此来判断一些语言,C语言既通用又紧凑,Java是通用而不紧凑,ruby、Python之类的脚本语言也是如此,正则表达式(如果也算语言的话)是不通用而紧凑,Erlang也是通用而紧凑,awk却是既不通用也不紧凑,XSLT也可以归入不通用不紧凑的行列;Javascript是个另类,按理说它也是不通用不紧凑,说它不通用是因为它的主要应用范围还是局限在web开发的UI上,实际上Javascript也是门通用语言,但是很少会有人会用javascript去写批处理脚本,Javascript显然是不紧凑的,太多的边边角角甚至奇奇怪怪的东西需要你去注意,然而就是这样一门不通用不紧凑的语言现在却非常有前途,只能说时势所然。
设计微型语言:
1、选择正确的复杂度,要的是数据文件格式,还是微型语言?
2、扩展和嵌入语言
3、编写自定义语法,yacc和lex
4、慎用宏,宏的主要问题是滥用带来的奇怪、不透明的代码,以及对错误诊断的扰乱。
5、语言还是应用协议。