心路历程

趁着学校的专业实践2(最终结果是要交一篇论文),其实本可以拿之前的课程论文交差了事的,但是想了一下,这也是一个不错的机会,可以让回顾并且总结一下过去所学的知识,并且去尝试将其组装成一个小小的成果出来。

大概自己一部分是菜再加上人还是略佛,另一部分也是个人在学习知识时总是倾向于深度优先,一个点卡住就会想疯狂搞懂,再加上还有考研的准备,,所以直到现在,补齐基础的进度也还是停留在CS 61B 21sp的过半这个位置吧。但仔细回顾起来,其实学到的已经不少了:线性表以及其基于数组和引用的实现,各类树形结构(并查集、二叉堆、平衡树)以及其基于引用和数组的实现etc。我认为自己能独立地把这些知识的内容从intuition到相互之间的联系再到代码的实现讲个八九不离十(个别特别变态的内容可能要准备下——说的就是你,红黑树!)。

写过文档码过代码,结合优秀的课程的知识导入结构与体系的建立与梳理,才能让自己去真正地理解并运用所学的内容。

最开始的时候,我想,要不专业实践2做一个数据结构可视化的项目吧。但是考察了一下,如果简单地取考虑这个项目的需求,那只是调用一下类似于graphviz这种的成熟库以及在此基础上封装api,就能做出个大概来;如果想要相对复杂一些的功能,例如把可视化的实现和具体的语言进行独立,自己做一套简单的,支持循环语句,函数定义和递归调用的语言,然后后台解析用户的指令并生成相应的图形,那就需要编译原理的知识了,但显然对于若干个星期的时间来说,不足以完成这一目标。

于是我的第一个想法就陷入了,简单的话太简单,难的话又太难的局面。于是我想着,有没有更好的方案,其所需要的知识是我学过的,但是实现起来又需要自身对所学知识的深入理解以及良好的设计和编码风格才能完成的项目——于是,一个简单的KV存储系统便成为了我的考虑目标。用红黑树来作为表结构,B+树作为索引,并且在前台有简单的调度系统,来管理数据的读写和处理以及内存和磁盘的交互,这样,既实现了知识内容是基于所学范围的,同时实现起来又有一定难度的目标。


结果

最后时间所限,实现了表和索引结构,以及在纯内存场景下的,数据读写和存储的调度。还差磁盘和内存的交互以及把调度模块进行独立地抽象和模块化。


心得

始终要保持对项目整体的把握感

我认为第一点,也是最重要的一点是,要时刻保持对项目整体的“把握感”。这种把握感在于:

  • 你对项目整体的构思和设计是怎样的,它有可能会在不远的未来发生变动么?
    • 如果会,变动的频繁程度怎么样?
    • 每次变动涉及到的变化量,你的预估是多少?
    • 以及对应地,你该如何进行复杂度的管理?
  • 当前的工作处于项目整体的什么位置
    • 你所开发的内容,是为了满足整体中的哪一部分的需求?
    • 会涉及到哪些组件/模块的依赖?
    • 以及随着你当前的工作,项目整体的架构是否会发生改变?

可以看到,这里有两个不同的抽象层需要兼顾——整体以及局部。其所处的位置不同,但又相互影响,处理不好的结果,那就是当项目的量级达到一定程度后,再要维护时发现复杂度爆炸。

除了项目有抽象上的复杂度需要维护,人脑也有自己的复杂度。工作在local和global时,人脑的context是不一样的,当项目整体的规模够大时,每次context switching带来的开销也够咱喝一壶的。

因此,个人认为,解决之道是在项目开发的时候,documenting的工作也需要实时跟进且不能过于马虎。要做到

  1. 叙述项目整体的构建以及主要模块的工作、之间的依赖、以及交互的方式;
  2. 分层记录开发流程与进度,维护一个进度树。这样工作在local时,记录和维护较低层的进度信息;local工作完成时,返回祖先层更新进度,同时查看接下来的任务以及回溯整体的开发情况;
  3. 在发生重构时(例如在开发子模块时发现可以或需要进行全局性的改动),也是顺着工作树进行调整;

这样,整个开发的流程和工作有一个较为系统的组织,也方便管理,可以弥补项目中后期复杂度增加以及人脑上下文切换带来的巨大开销所造成的复杂性的增加。