面向过程还是面向对象?对象是骨架,流程是血肉

流程是易变的、脆弱的,对象是稳定的、高内聚的。面向对象的流程是分治,将易变的流程拆分成多个稳定的对象,对象之间面向接口协作,复杂性拆分成局部复杂性。 现象 我们 iaas 很多代码都是面向过程,而架构上也有很多是面向过程,而没有面向对象。 比如创建主机,存储资源没有抽象,全都是在过程中各种条件判断来处理的。其实需要的是一个存储系统、存储对象。 创建备份也是一样,创建备份和存储备份耦合在一起,没有区分。 存储备份完全是面向过程,写了两个流程: rsync 上传到 snapshot; snapshot 之间复制副本。 其实创建备份和存储备份完全是独立的两个事务,而且是差别很大的两个事务。 很明显,存储应该是一个独立系统,是一个存储对象。 我们需要的是面向对象,过程应该是在对象内的。 核心:对象是骨架,流程是血肉 流程是易变的、脆弱的,编排流程; 对象是稳定的、高内聚的。 最终: 面向过程的流程,是一个大的、长的、前后依赖的、复杂性指数增加的判断组合; 面向对象的流程,是分治,将易变的、脆弱的,拆分成多个稳定的对象,对象之间面向接口协作,复杂性拆分成局部复杂性,在大流程里是一个线性复杂性,在对象内是常数复杂性。 相比面向过程的流程的指数复杂性,这是数学上可证明的面向对象的优势。 软件工程设计的目标就是 kiss,一切围绕控制复杂性设计。 宏观面向对象,微观面向流程 上层的业务流程确实是面向过程的,但它又不负责具体的业务规则,而是编排。 宏观架构上,要"面向对象":划分好边界,把复杂的业务拆解成一个个职责明确、内聚的对象,以此来抗住需求的变更和系统的规模; 微观执行上,要"面向流程":在 Service 层,清晰、直观地把这些对象串联成一条条业务流,满足用户的实际需求。 对象是骨架,流程是血肉。 面向过程 vs 面向对象 面向过程 优点:逻辑简单直接,符合人类"按步骤做事"的直觉;代码体积小、执行效率高;调试和上手成本低,适合小型程序; 缺点:可维护性差,需求变更时需修改大量相关函数,牵一发动全身;复用性低;扩展性差,难以应对复杂系统的需求迭代。 面向对象 优点:可维护性强,封装使对象内部变化不影响外部,模块化降低耦合;复用性高,继承和多态大幅减少重复代码;扩展性好,新增功能只需定义新类/方法,无需修改原有代码(开闭原则);更贴合复杂问题的本质; 缺点:复杂度高,需设计类的结构、关系,上手门槛高;性能稍低;过度设计风险,简单问题可能被复杂化。 业务的悖论:用"空间对象"承载"时间流程" “业务的本质是流程(时间推进),但为什么现代软件工程推崇对象(空间治理)?” 这是软件设计中最迷人的核心矛盾。 我们通过 DDD(领域驱动设计)思想完成了这两者的空间与时间平衡: 宏观架构上(空间划分)——面向对象:划分出干净、内聚的领域模型(如用户、商品、订单)。这些对象是系统的"零件",负责锁住状态与核心业务规则; 微观执行上(时间推进)——面向流程:在应用服务层,用直观的面向过程逻辑,将这些对象串联成一条条满足用户最终需求的"业务流"。 架构大智慧:对象是骨架(空间),流程是血肉(时间)。 好的代码,是用面向对象的画笔,画出面向过程的蓝图。 为什么业务是流,我们却要用对象? 为了应对"变化"和"规模"。 如果一个业务流程永远不改,面向过程绝对是最高效的。但现实是,业务流程会无限膨胀和变化。 面向过程的灾难:假设一个"下单流程",起初只有 3 步。随着业务发展,变成了 30 步,里面充斥着各种 if-else。最后这个流程长达几千行,没人敢改,因为改了第 5 步,可能会调断第 28 步的数据; 面向对象的解法:面向对象不是消灭流程,而是把流程中的"参与者(实体)“抽离出来,让它们自己负责自己的事情。下单流程不再是一条黑盒管道,而是变成了用户对象、商品对象、营销引擎对象、库存对象之间的交互。 用一个比喻来理解: 面向过程是"流水线工厂”:传送带上一条道走到黑,一旦产品要加个新功能,整条流水线可能都要停工重组; 面向对象是"现代企业组织":划分为财务部、销售部、研发部。公司的业务依然是一个个流程,但流程是由各个部门通过协作完成的。如果财务流程变了,只需要财务部内部调整,销售部根本不需要知道。 小结 流程是易变的、脆弱的,对象是稳定的、高内聚的; 面向对象的流程是分治,复杂性拆分成局部复杂性; 面向过程的流程是指数复杂性,面向对象是线性复杂性; 宏观架构上要面向对象,微观执行上要面向流程; 对象是骨架,流程是血肉; 用面向对象的画笔,画出面向过程的蓝图。

April 25, 2026 · 1 min · 74 words · 文叨叨

即便是补丁,也要面向对象,而不是针对流程打补丁

哪里遇到问题了,就找个地方加个开关、加个检查、加个条件判断来处理掉。这导致不够系统化,引入了局部的分支点,会造成多流程的耦合交叉,扩展容易遗漏。 现象 我们的代码这种情况非常的多。 就是哪里遇到问题了,好,我们按照这个问题找个地方加一个开关,或加一个检查,或加一个条件判断来处理掉。 这导致的问题,就是不够系统化,引入了局部的分支点,但是对于整体的影响没有分析。 这个分叉会造成后续扩展的问题,扩展的时候压根不会注意到有这个分叉。而且类似的问题可能还会继续分叉。 不够系统化,这样会造成多流程的耦合交叉,扩展容易遗漏。 例子 比如我们关机对于资源的可见性的管理(主要是 image),没有统一的约束和要求。 克隆的时候发现路径不在,报错了,然后加一个 open 修复一下,其他流程也是一样。 哇,这完全是黑盒,完全没法分析和预判,就等错误暴露了修复。 比如 drbd 发现脑裂了,直接操作了 --discard-my-data,这样很有问题,这样上层还在正常的创建资源。 实际需要给 node 抽象状态,当然我们有个 failed 状态,但是这是完全不可用的状态,相当于是宕机状态。 那么你没有准备好的状态,需要独立抽象的。发现了脑裂,其实是需要修复的,标记为未准备好的状态,那么其他流程都根据这个状态决定自己的操作。这是一个解耦的操作。 反常识的组合 包括下面的检查,开启了灾难检查,又开了一个 flag 的情况下跳过检查,很奇怪。 为什么不直接统一为关闭灾难检查呢,或者就统一的 flag 文件。 两个组合在一起,还是相反意思的,非常反常识,非常不结构化、不系统化。 小结 打补丁要面向对象,而不是针对流程打补丁; 哪里遇到问题就加开关、加检查、加条件判断,会导致不够系统化; 不够系统化会造成多流程的耦合交叉,扩展容易遗漏; 给 node 抽象状态,其他流程根据状态决定自己的操作,是解耦的操作; 两个相反意思的 flag 组合在一起,非常反常识、不系统化。

March 21, 2026 · 1 min · 42 words · 文叨叨

面向接口,面向接口,面向接口

接口很多时候听起来很有道理,写的时候会质疑是不是为了接口而接口。一写二抄三重构,前面没有必要的时候不用接口,后面重复的时候可以引入接口。 现象 接口很多时候听起来很有道理,写的时候会质疑是不是为了接口而接口。 实际上,一写二抄三重构: 前面没有必要的时候,不用接口; 后面重复的时候,可以引入接口; 二次重复的时候,就必须要重构了,引入接口是其中一种。 接口作用很大 def disk_build: if PitrixFolder.is_tps_container(): image_name = ctx.tpsc_mgr.get_head_img(instance_id) else: image_name = PitrixFolder.get_head_img(instance_id) 就像存储,存储有多种,我们遍地的 if else,太难维护了,扩展性很差。 这个时候,如果我们用的是接口: 那么所有类似 disk_build 的地方,参数都是接口; disk_build 内没有条件判断,只有接口调用; 而调用 disk_build 的时候传入具体的存储类型; 大量的 disk_build,就避免了大量的条件判断。 条件判断不是问题,重复判断才是问题。 而接口,也可以方便的扩展存储,因为不用去调整大量的 disk_build 函数,只需要在调用 disk_build 的地方传入新的类型。 接口不是完全避免了新引入类型的工作量,入口处还需要处理,但是依然保证了内部核心流程的稳定性,因为入口处肯定不是核心流程嘛。 小结 面向接口,一写二抄三重构; 前面没有必要的时候不用接口,后面重复的时候可以引入接口; 二次重复的时候,就必须要重构了; 条件判断不是问题,重复判断才是问题; 接口保证内部核心流程的稳定性,入口处处理新类型即可。

March 8, 2026 · 1 min · 46 words · 文叨叨

抽象流程还是抽象对象?一写二抄三重构

要不要抽象,关键在于要不要复用。业务流程都是独立的,不需要复用;技术类流程需要复用。一写二抄三重构,第二次大量重复时就可以开始重构了。 现象 写代码的时候,总纠结要不要抽象流程、抽象对象、面向组合。 这样很难,因为没有明确的复用需求,不知道稳定点在哪。 核心:一写二抄三重构 一写,二抄,三重构。 要不要抽象,关键在于要不要复用。 业务流程都是独立的,不需要复用,所以谈不上抽象; 技术类的流程,是需要复用的。 但是没必要第一次就绞尽脑汁抽象流程、抽象对象、面向组合。 第二次是抄还是重构 不是说第二次就一定是抄。 如果是一个方法,抄没问题; 如果是一个流程,一堆方法,第二次抄就不合理了。 这样的后果是第三次重构非常困难,甚至会因为功能的兼容影响没法进行。 如果是大量的话,第二次就可以开始重构了。 抽象流程 vs 抽象对象 k8s 为什么牛逼,原因在于它定义了一套声明式的流程。 我们创建主机、创建备份等,看起来流程不一样,但是上升一个维度,都能用声明式的流程来处理。 但 2026 年更新后的认知是:k8s 是极致的面向对象。 虽然它的控制器是面向流程的,但是控制器仅仅是对象下的血肉。 顶层还是围绕对象设计的; 控制器是属于对象的; k8s 极致面向对象,消除流程,将流程隐藏在对象中。 流程是易变的,对象是相对稳定的,所以不会去抽象流程,而是抽象对象。 一个例子:采集 pv-lv 和 lv info 数据采集、数据同步,涉及到新增和删除。 所以这里的流程最后抽象为: 采集; 从 db 获取; diff 得到 insert 和 delete; 执行 insert 和 delete。 不同的数据对象,提供支持 diff、insert 和 delete 的方法即可。 这个流程也不是一开始就想出来的,也是边写、边思考做出来的。 小结 要不要抽象,关键在于要不要复用; 业务流程独立,不需要复用;技术类流程需要复用; 一写二抄三重构,第二次大量重复时就可以开始重构; 流程是易变的,对象是相对稳定的,所以抽象对象而非流程; 好的抽象是边写边思考做出来的,不是一开始就设计好的。

February 15, 2026 · 1 min · 64 words · 文叨叨