TOC
Open TOC
The Pragmatic Programmer 读书笔记
这次笔记的形式比较特殊,因为原书的内容涉猎就十分广泛,所以我就联系一下实际的编码过程,写一写自己的感受
软件的熵
- 破窗:糟糕的设计、错误的决定、低劣的代码
- 破窗效应:软件恶化、腐烂
这一点在稍大一些项目中就会体现出来,比如 PA 或 AP 的项目,主要问题还是设计上欠考虑,导致后期调试和变更极其困难
我想起了 PA3 中把 RTL 临时寄存器当作 CSR 寄存器,不过更多的是命名上的不一致
温水煮青蛙
- 走出编码的舒适区,牢记全景
我需要手动解析 XML,还是尝试调用第三方库帮助我解析,哪一个选择可以帮助我更好的实现文档预览的功能?
手动解析确实简单,而且知道运作的原理,但是不易变更,设计需要更多的思考
调用第三方库则处于知识盲区
需求分析
- 够好即可
这一点在 AP Projects 第二阶段体现的十分明显,比如我需要解析出 Word 或 LaTeX 中的哪些元素?我的界面需要十分精致吗?
知识组合
- 定期投资
- 多样化
- 风险管理
- 评估调整
- ……
想了一下,大一的时候似乎很喜欢看技术书籍,喜欢那种全面讲解某种编程语言的书籍,也为此整理了许多笔记,但在实际编码过程中需要用到相应的知识时,还是需要 STFW 或者 RTFM,所以现在知识的获取更多以按需为主
各种编程范式的语言都学习了一点,Racket / Haskell / JS,主要还是体会不同的编程思想
非技术书籍,现在应该就是第一本吧
不同的编码环境,目前正在逐步向 Linux 调整,从 IDE 变为 Vim + Make
不过 IDEA 和 Pycharm 还是很香的……
不过交流似乎少了一点……
英语就是另一门编程语言
- RTFM / STFW
主要是最新的内容都是以英文形式呈现,想想 RISC-V 的文档,中文翻译的版本已经落后了两年,不过似乎没有被坑到……
强调母语,还是强调交流的重要性
突然想起了一些中文编程项目
文档
- 把文档嵌入,而不是拴在表面
想起了 Python 的 doctest 和 PA 中可以在网页显示的 Makefile
我写过的文档大概只停留在注释和 README 的层次……
ETC
- Easier To Change
这大概是编码的核心思想了,优秀的设计比糟糕的设计更容易变更
更多的是一种价值观,那些设计模式不过只是 ETC 的推论
想起了 PA 里指令译码的过程,添加一条新的指令非常容易,这背后设计了多重辅助函数还有惊为天人的 macro
DRY
- 不要重复自己
ETC 的直接推论
Ctrl + C / V 固然很爽,但是一旦要变更就难受了
重复不只是代码,还可能是文档
函数的抽象作用,类的抽象作用,都是 DRY 的一些实践
正交性
- 消除不相关事物之间的影响
正交性体现在许多方面,比如程序设计语言(语法之间),编译器的前端和后端(使用中间代码解耦合)
实际一点的例子,比如 PA 的四个抽象层,或者 MFC 里的文档 - 视框架
一些保持正交性的方法,如代码解耦(模块的封装),避免全局数据等
基于正交性设计和实现的系统更容易测试
正交性也适用于文档,比如 Markdown 文档,内容就是那些语法的组合,但是呈现却可以大不相同,解析出文档结构后对每个部分的 CSS 都可以调整
可逆性
- 不设最终决定
还是强调解耦
从基于浏览器到基于移动 APP,服务器端不应对客户端做任何假设
曳光弹和原型
- 曳光弹:简单但是完整,最终系统框架的组成部分
- 原型:一次性代码,跳过细节,专注于系统的特定方面,最终需要丢弃
似乎没怎么切身感受过,但实际编码过程中可能已经实践过了……
不要冲出前灯范围,小步前进
DSL
- 领域特定语言
- 内部语言:拓展语法
- 外部语言:编写解析器
目的是为了靠近问题域编程
一些动态的配置可以使用 DSL 编写,如 JSON / Open XML
估算
- 项目完成时间
- 代码的复杂度
- 时间
- 空间
基础工具
这一部分已经有单独的笔记了
其核心是纯文本,人类可读,人类可理解
于是我们有了 Shell,威力在于所见非全部,管道将数据变换,类似流式编程
编辑器让我们 edit text at the speed of thought
版本控制 VCS 则是项目的中枢
不仅是代码和文档,配置信息也可以进行版本控制,如 .vimrc / .bashrc
甚至是安装的软件
而密钥不应通过版本控制管理,应通过配置文件和环境变量管理
调试理论 jyy 已经介绍过了,基本心态是 don’t panic,要尝试阅读出错信息,二分法,使用 trace,尽早奔溃(死掉的程序不会说谎),或者找个橡皮鸭解释一遍代码,都可以帮助调试
另外,不要假设,要证明,不要进行巧合式编程
使用一些脚本来处理文本,比如本地图床 → Github 图床,一些简单的胶水语言可以简化编码
契约和断言
- 契约式设计 DBC
- 前置条件
- 后置条件
- 类的不变式
- A Tour of C++ 中有所提及
- 断言
- 预防不可能的事情
保持资源的平衡
- 分配
- 释放
如 C++ 的 RAII,栈变量离开作用域
但异常的出现会打破这种平衡,使用 finally 子句
面向事件编程
所有的模块或类都是通过事件来交互,如消息队列
没有尝试过,下面是几个策略:
- 有限状态机
- 观察者模式
- 发布 / 订阅
- 响应式编程
继承税
SECI 已经将继承和组合进行了对比
这里有一些替代方案:
- 接口和协议
- Java interface
- 委托
- 也就是组合
- mixin 和特征
- Python mixin
- 不是 is-a,而是 -able
并发
- 打破时域耦合
- 不要共享状态
一些替代方案:
- 角色
- 黑板
现在不太懂……
重构
重构不是添加功能
尽早重构,经常重构
测试
- 测试与找 Bug 无关
- 测试是代码的第一个用户
- 测试驱动编码
不同侧重点下的测试:
- 单元测试 → 正交性
- 针对契约测试 → DBC
- 基于特性测试 → 如排序后检查数组长度和是否有序,随机数据