杂项
一些不知道归类到哪里的笔记和代码片段。
避免过度优化
一直学不好算法,除了自己的愚笨和没有用心之外,我找到了两个不错的托辞:
很多时候都在面向Accepted编程,并没有真正去领会算法的妙处,尤其是忽视了对复杂度的讨论;
话说回来,面向Accepted又有几分TDD的意味。
很多算法题的解答不是很让人信服,有点忽视工程实际为了优化而优化的意思。我一贯是个“能用就行”主义者,因此常常会想,要谨防过度优化。很多优化做到极致的时候是“反模式”的,为了取得一点性能上的收益经常使用一些比较“hack”的手段。短期来看确实取得了收益,但如果综合长期理解教学迭代维护所耗费的生产力来看其实却未必是优化,只是当时的人太过短视不可见而已。因此我不喜欢各种偏门左道式的优化。
upstream first
开源领域有个词叫做“upstream first”,大致意思是我们在下游所做的更改要设法推送到上游再传播下来,避免后期因为上游的变动频繁做适配。这个概念有很多变种,这是我一下子想到的一些:
Windows的Linux子系统,听说第一版就是因为无法接受持续跟进上游变更所花费的代价才有的WSL2;
Vue中的双向绑定,我们在改变子组件中来自上游组件的状态的时候,要么通过事件机制通知上游,由上游进行修改再传播到子组件,要么使用上游传递下来的句柄、dispatcher进行修改。无论哪一种其核心都是要通知上游,避免我们的修改上游不知情从而上游按照它的假设自行变更状态之后产生BUG,而且往往这种BUG难以定位;
SOLID中的D,原本直接依赖的三方接口转为一个注入的实现。我们在使用三方的API或工具的时候,最好要建立一个“防腐层”。举一个真实的例子,前端目前主流的工程化工具是webpack、rollup和基于rollup的vite,我以前在团队中开发维护的工程化cli套件就是基于webpack@4的,一个vue-cli式的工具,在设法迁移到webpack@5和vite的时候遇到了很多麻烦。现在如果让我重新设计的话,我会首先对我们所需要工程化工具提供的功能做出定义,然后设计一套类似接口的东西,我们团队内部的开发套件都是基于这个接口来制作,根据这个接口再进行webpack或者vite的两套具体实现。这样即使webpack和vite的接口发生破坏性变更,也无非是具体实现上的变更,对接口另一边的开发工具并不会造成影响,这个接口就起到了隔离防腐的作用。其实这个道理并不复杂,但我们在实践中往往第一反应不会考虑这么深远。
Docker,然后到K8s,OCI/CRI的出现改变了上下游结构。
其他一些值得留意的模式/方法论
- 基于历史的分析预测:分支预测、多级反馈队列(MLFQ)、LRU、KMP
- 迭代到不动点(Fixpoint):优化问题
- 模式匹配(Pattern Matching):递归下降、元编程、函数重载、类型推断、逻辑编程
- 虚拟化、标准化与介入(Interposition):内存分页、容器与集装箱
- 混合折衷(Hybrid):组相联、段页、两阶段锁(spin-sleep)、Hybrid Web App