学习一个复杂系统时,需要注意,既不要过分忽视顶层设计,也不能无视实现的细节设计。
最好是先整体地了解这个系统的诸多组件,知道哪些组件做了什么。这使得我们遇到一部分尚未了解的代码时,不至于完全不了解它的功效与副作用,以至于陷入跨模块的源码阅读上。
一个大型项目,其具体的实现细节大部分时候是比较琐碎的,牵扯到许多与核心设计思想无关的部分:代码组织、特定的 bug 修复、平台适配,等等。
而且,必须要承认的是,无论是多么优秀的项目,只要他足够大型,那必然存在多种时期不同风格的代码。它们可能有好有坏,也有可能已经陈旧。
但是,也应该避免过分地陷入到细节当中。在学习具体实现时,更要注意避免变成源码复读机。仅仅是复读一遍源码,学到的东西是有限的。我一直认为,读源代码自然不是真的想看看它的代码到底是怎么写的(当然我不否认有的项目源码确实具备很高的参考价值),更多时候更应该关心的是:
- 它通过什么机制实现的?
- 某个组件解决了什么问题?通过什么方式解决的?别的解决方式不好在哪?
- 具体实现是怎么发展到现在的样子的?发展的过程中是遇到了什么问题?
- 它走了哪些弯路?有什么历史包袱?怎么避免、改进的?
- 它的设计有哪些缺陷?为什么难以修复?
- 它的哪些设计在后续的演进中被替换?
等等。
这些问题大多数时候不是光看源代码就能看出来的,更多的时候需要我们观察一个项目演进的历史,从而从中学到“历史经验”。
具体的编程实现或许并不那么重要——世界上没有两个相同的项目,或许某些代码片段、代码组织的方式是值得借鉴的,但每个项目都总会遇到各种各样的特有问题,导致具体代码实现的复用存在一定的困难。
不过,设计思想永不过时——基于前人的经验超越它,这正是历史经验的价值。