关于面向对象设计与SRP、DIP原则
不知道自己在哪个阶段,但如果用认知四阶段来比喻的话,大概处于有意识胜任的阶段吧。虽然还没有把握什么才是好的设计,但在这种过程中逐渐产生了一些似乎明白的东西,其中有些让我觉得挺有意思。
面向对象简评
面向对象设计的背景及其擅长的是众所周知的。为了打破传统过程式范式的局限,具体来说是为了保留抽象思维,以人更容易理解的方式自然地设计复杂的业务逻辑。然而,关于这种方法论为何获得如此大的反响,讨论相对较少。对此,我找到了两个视角:商业和哲学。
一。承担责任的商人、有野心的人不喜欢不确定性。北方接壤帝国不断侵略朝鲜半岛国家的原因之一,就是在完成大陆征服这一事业之前稳定后方。罗马在攻打迦太基之前先统一了意大利半岛,德国在入侵法国之前与苏联签订了互不侵犯条约。案例和动机大同小异。事业规模越大、负责人的执念越认真,阻断黑天鹅就越必要。
二。现代物理学家渴望大统一理论、语言学家假定全世界所有语言之间存在普遍语法、经济学家试图用供需这一张图解释数百万人的行为等,都出自控制混乱的意图。为什么这种努力在历史上一直相伴而行?背后可能有降低认知成本这种实用的原因,但我更喜欢阿尔贝·加缪的视角。比如”人无法忍受不确定性和模糊性,渴望清晰的认知框架”。
虽然只是想象,但从直觉上看,将面向对象理解为风险管理倾向之类的人性,似乎也不会有太大违和感。面向对象将传统过程式代码拆分整理到适当的位置,在结构和名称上留下更多路标。结果是复杂性和不确定性得到控制,给开发者带来稳定感。
SRP:单一职责原则
每个对象只应承担一个职责。
类似地,写作中有一文一事原则,即一个句子只讨论一个主题。因此单一职责原则的宗旨本身并不陌生,反而容易误解。“剔除关注点以实现语义上的清晰”,这是SRP的主要意图,但并非核心。SRP真正想要达到的,是剔除琐碎的语义分支,从而实现变更的可预测性。
SOLID原则是以活着的程序为前提制定的。情况会不断变化,程序也必须不断变化。这时需要的是孙子兵法的态度——通过彻底的计算来管理风险并实现效率。正如”役不再籍,粮不三载”所说,消除重复成本很重要。
同样的原因,在开发阶段清晰认识工作目标与最小化工作量、能无副作用地大胆执行与不能之间,存在巨大的成本差异。在这个语境下,语义关系清晰意味着行为的影响力可预测,这又意味着可以计算行为风险。这就是SRP被视为标准、基本功的原因。
DIP:依赖倒置原则
抽象不应依赖细节,细节应依赖抽象。
我在履行替代役(社会服务)期间观察了公司的自我净化能力能贯彻到何种程度,有趣的是,在这个过程中我不断想起DIP原则。想法是这样的:在一个有部门及其成员分工的典型公司结构中,根据DIP,公司应只依赖社会预先达成的概念——分工,而不应依赖执行该工作的员工的个人能力或技能。
这是常识。公司的日常看似固定,人们往往觉得昨天、今天、明天那个员工都会在那个岗位上做同样的工作。但实际上,定期调任、突发人事变动、辞职,极端情况下像巴士因子(Bus Factor)中可怕的假设那样,因员工死亡等理由,人员更替是不可避免的。如果组织不仅依赖分工,还依赖个人能力,那么无论何种原因,当那个人缺席时都会产生混乱。
从这个角度看,防止将超出约定范畴的工作委托给一个人的原因,不仅在于那是利用他人善心的不道德行为,更在于它威胁组织的可持续性。一次可能还行,但多次就不行了。如果组织所需的工作量增加,不应加重个人负担,而应通过调整分工来重构责任分配结构。这一逻辑转化为技术性表述,就是原文:“抽象不应依赖细节,细节应依赖抽象。“
形式化
务实提出的概念在成为规范后,意义消失、变质为形式的情况时有发生。事实上不止是”时有发生”,我们所熟知的大多数事物都是这样成为文化和传统的。OOP也是以实用为价值的方法论出发,但在今天的编程课程中明显有被视为一种通过仪式的倾向。
因此我产生了怀疑。性能方面已经有DOD这样出色的方法,状态管理的复杂性方面有函数式范式作为替代。当然,它完全可能继续长期存在下去。但最近从Vibe Coding到Harness Engineering,最新的趋势正朝着人不直接审视代码设计的方向发展,未来是否还必须以对象方式编写代码,这一点正被打上问号。希望无论哪种范式,都不会长久地成为僵化的传统。