编程的恶习

不知道从什么时候开始, 我写程序染上了一个恶习——倾向于用自己不熟悉的东西挑战自我.

这个恶习表现在很多方面, 比如倾向于用新潮的编程语言, 倾向于用新的框架和库, 倾向于换个方式实现一些本来可以轻易实现的功能, 倾向于任性地将原本不能自然搭配的事物组合在一起让它工作.

好比最近, 我用CouchDB替代MongoDB, 你问我为什么这么做, 我真的说不出个所以然来, 大概就是有病吧. CouchDB的REST API确实很酷, 让人眼前一亮, 可除此之外, 它似乎没有一处是对开发者友好的. CouchDB几乎完全依赖MapReduce的查询功能并不适用于常规的Web项目, 连字符串的模糊匹配也需要靠Lucene这样的全文搜索引擎来实现, 一点也不如全心全意服务开发者的MongoDB好用.

CouchDB的每一处特性都不够灵活, 像是它的Validation Functions被设计出来限制文档的CRUD操作, 开发者可以用这个功能实现一个复杂的Document Schema, 但如果你想按照一定的规则修改内容, 就只能换用另一个叫做Update Functions的功能实现, Validation和Update作用的阶段如此接近, 二者却不能组合起来用, 必须分成单独的函数, 更可怕的是, Update Functions乃至Design Functions下的很多函数, 都需要客户端的主动调用, 不能触发执行. 这在无后端开发时是一个很大的问题, 本来无后端开发就面临着安全上的挑战, 对于带有恶意的用户行为只能通过ACL解决, 市面上的BaaS大多也是这么做的, CouchDB的Validation虽然可以做到ACL, 但由于Update Functions是需要主动调用的, 如果不通过Update Functions, 你让数据库自己给新增的文档加个时间戳都做不到, 可是作恶者哪里会理会你的Update Functions呢? 最终结果就是你的数据库会变得不可信任, 更不要提展示给用户了.

当然如果你有一个后端程序, 那么CouchDB可以的安全性就可以得到很大程度上的提升, 但纯MapReduce查询的缺陷仍然是难以解决的, 同样的场景下, 完全不如使用MongoDB或是RethinkDB之流的数据库来得舒服.

不过说实话, CouchDB的REST API启发了我, 它让我意识到直接用REST API操作数据库是一件很爽的事情, 而CouchDB低效率的开发体验则让REST API的优势荡然无存. 于是我开始寻找可以在MongoDB和RethinkDB上实现REST API的程序: RethinkDB官方明确表示自己没有实现REST API的计划, 它的第三方库也没有类似的功能, MongoDB则有一个通过Python编写的叫做eve的REST API程序. 发现了eve的我如获至宝, 这个项目的Github有3k star, 真酷啊, 肯定各种场景都考虑到了, 于是我马上着手将之前在CouchDB上的功能转换到eve上, 但事实证明我还是too young. eve非常严格的遵守了REST的设计规范, 有一套参数非常之多的配置和验证规则, 而且所有配置都是围绕着MongoDB中事实存在的Collections和Documents进行的, 以至于不能轻易的实现一些不RESTful的接口, 比如说登录这种明显有副作用的行为, 由于其自带的验证功能无法满足我的需求, 所以只能通过一种极其迂回的方式来实现同样的行为.

之后我花了很长时间才在eve上实现了类似CouchDB REST API的session存取, 还因此违反了REST语义, 让GET成为了一个不安全不幂等的操作. 回头看代码, 东一处西一处的Hook handler, 非常不优雅, 让人感叹自己都他妈写了些什么. 在从CouchDB的REST API迁移到eve时, 产生了太多的沉没成本, 让我非常不甘心就此放弃. 但我真的太累了, 我不得不停下来反省自己的行为, 最终仅存的一丝理智让我放下了一切.

停下来, 我才猛然发现, 几乎一样的功能我用Python, PHP, Golang, Node.js配合MySQL, MongoDB, SQLite, Redis都实现过, 把以前写过的代码拿出来照抄一遍都能做完, 代码也很是清晰. 所以为什么这次我偏偏要去用CouchDB? 还非要无后端? 而且最后还实现不了, 完全不能理解我之前的行为, 妈的我简直就是个傻逼啊.

"简约至上", "少即是多", "KISS原则", 这些设计理念基本中的基本, 我忘记他们太久了, 我太沉迷于挑战自我这件事情, 以至于这次的失败让我非常难以接受. 我忘记了编程本应该是一个有趣的事情, 忘记了对优雅清晰的代码的追求. 忘记了初心的我回过神来, 才发现给自己平日里堆砌的所谓"挑战性"一直在增加我编码时的挫败感. 我自认是一个挺抗压的人, 心理学和NPL的知识让我能够很快的调节自己的心态, 但这些并不能够阻止我自己反复不断地犯决策上的错误, 反而让我能在错误的路上走得更远, 最后便无法回头了, 这次的情况算是彻底击溃了我往日在"应对挑战"上积累出来的盲目的自信, 我完全错了.

好累, 真的好累.