《Unix编程艺术》读书笔记(1)
这两天开始阅读该书,下面是自己的体会,以及原文的摘录,虽然有些东西还无法完全吃透。
写优雅的代码来提高软件系统的透明性:(P134)
Elegance is a combination of power and simplicity. Elegant code does much with little. Elegant code is not only correct but visibly, transparently correct. It does not merely communicate an algorithm to a computer, but also conveys insight and assurance to the mind of a human that reads it. By seeking elegance in our code, we build better code. Learning to write transparent code is a first, long step toward learning how to write elegant code — and taking care to make code discoverable helps us learn how to make it transparent. Elegant code is both transparent and discoverable.
调试工具是通往代码内部的窗口,能够发现大多数的bug:(P139)
The lesson is this: Don’t let your debugging tools be mere afterthoughts or treat them as throwaways. They are your windows into the code; don’t just knock crude holes in the walls, finish and glaze them. If you plan to keep the code maintained, you’re always going to need to let light into it.
GCC编译器是一个关于透明性的很好的实例,它能通过命令行清晰的揭示出预处理器,汇编器,连接器等各个组件的具体工作流,中间结果很有用:P(140)
the driver program has monitoring switches that merely (but sufficiently) expose the textual data flows among the components.
要追求代码的透明,就是不要在具体操作的代码之上叠放太多的抽象层,保持薄胶合层:P149
If you want transparent code, the most effective route is simply not to layer too much abstraction over what you are manipulating with the code.
批评了过度的面向对象,既要模块化编程,也要保持着地,而不是站的离基本组件太高(不同的语言应该有所侧重??):P150
Unix programmers are the original zealots about modularity, but tend to go about it in a quieter way. Keeping glue layers thin is part of it; more generally, our tradition teaches us to build lower, hugging the ground with algorithms and structures that are designed to be simple and transparent.
透明性和可显性,与模块性一样,是软件系统的设计特性,而不是代码的编码风格,难有特定的硬性规定,需要思考:P150
- What is the maximum static depth of your procedure-call hierarchy? That is, leaving out recursions, how many levels of call might a human have to model mentally to understand the operation of the code? Hint: If it’s more than four, beware.
- Does the code have invariant properties that are both strong and visible? Invariant properties help human beings reason about code and detect problem cases.
- Are the function calls in your APIs individually orthogonal, or do they have too many magic flags and mode bits that have a single call doing multiple tasks? Avoiding mode flags entirely can lead to a cluttered API with too many nigh-identical functions, but the obverse error (lots of easily-forgotten and confusable mode flags) is even more common.
- Are there a handful of prominent data structures or a single global scoreboard that captures the high-level state of the system? Is this state easy to visualize and inspect, or is it diffused among many individual global variables or objects that are hard to find?
- Is there a clean, one-to-one mapping between data structures or classes in your program and the entities in the world that they represent?
- Is it easy to find the portion of the code responsible for any given function? How much attention have you paid to the readability not just of individual functions and modules but of the whole codebase?
- Does the code proliferate special cases or avoid them? Every special case could interact with every other special case; all those potential collisions are bugs waiting to happen. But even more importantly, special cases make the code harder to understand.
- How many magic numbers (unexplained constants) does the code have in it? Is it easy to discover the implementation’s limits (such as critical buffer sizes) by inspection?
隐藏细节和无法访问细节有着重要区别,优秀的程序员应该给程序设定调试标志和探测开关,看开源代码,这一点很常见,debug选项,可以透视程序的运行状态。P151
Programs that cannot reveal what they are doing make troubleshooting far more difficult. Thus, experienced Unix users actually take the presence of debugging and instrumentation switches as a good sign, and their absence as possibly a bad one. Absence suggests an inexperienced or careless developer; presence suggests one with enough wisdom to follow the Rule of Transparency.
将软件系统划分为协作进程,虽全局复杂度降低,但是代价是需要合适的进程间通信协议,接口部分都是bug的聚集地,还需要为通信各方设计状态机,真正重要的不是协议语法而是协议逻辑(模型的正确性)。P159
The real challenge is not protocol syntax but protocol logic—designing a protocol that is both sufficiently expressive and deadlock-free. Almost as importantly, the protocol has to be seen to be expressive and deadlock-free; human beings attempting to model the behavior of the communicating programs in their heads and verify its correctness must be able to do so.
这里翻译的不好理解,应该理解为popen只能为shellout搭建输入或则输出管道,但是却不能构建双向管道,因为pipe是单向的。P168
Unix’s popen(3) call can set up either an input pipe or an output pipe for a shellout, but not both for a slave process — this seems intended to encourage simpler programming.
信号IPC的一种常用场景是pidfile,进程A把自身的PID写入到一个普通的文件中,在以后的某个时候进程B可以据此文件对A进行控制,如kill它。P171
A technique often used with signal IPC is the so-called pidfile. Programs that will need to be signaled will write a small file to a known location (often in /var/run or the invoking user’s home directory) containing their process ID or PID. Other programs can read that file to discover that PID. The pidfile may also function as an implicit lock file in cases where no more than one instance of the daemon should be running simultaneously.
SIGHUP信号通常作为守护进程重新载入配置文件的信号。P172
Many well-known system daemons accept SIGHUP (originally the signal sent to programs on a serial-line drop, such as was produced by hanging up a modem connection) as a signal to reinitialize (that is, reload their configuration files); examples include Apache and the Linux implementations of bootpd(8), gated(8), inetd(8), mountd(8), named(8), nfsd(8), and ypbind(8).
虽然文本流没有经典的RPC性能高,但是系统简单,易于理解,XML-RPC/json-rpc综合了二者的优点。P179
Even if text streams were less efficient than RPC, the performance loss would be marginal and linear, the kind better addressed by upgrading your hardware than by expending development time or adding architectural complexity. Anything you might lose in performance by using text streams, you gain back in the ability to design systems that are simpler — easier to monitor, to model, and to understand.
线程共享地址空间,暴漏了彼此太多的内部状态,所以产生了竞争问题。而进程有独立的地址空间,良好的封装,通过明确的IPC进行通信。而且,在多线程中的时序依赖也是一个很难的问题。P180
Threads are a fertile source of bugs because they can too easily know too much about each others’ internal states. There is no automatic encapsulation, as there would be between processes with separate address spaces that must do explicit IPC to communicate. Thus, threaded programs suffer from not just ordinary contention problems, but from entire new categories of timing-dependent bugs that are excruciatingly difficult to even reproduce, let alone fix.