前言
代码库规模
功能分岔了,强行弄一个始祖模板
说到屎山代码,肯定下意识认为是小白,写的修修补补,漏洞百出的代码。但是你见过专业人士写的屎山吗?没见过,来见识一下过度设计带来的屎山一角:ES的delete(update/search都一样)流程
在client阶段抽象模板设计无可厚非,当进行
action.excute时,你就会发现越来越觉得味来了:
┌───────────────────── 路径A ─────────────────────┐
│ TransportDeleteAction │
│ ↓ │
│ TransportAction.execute() │
│ ↓ │
│ TransportSingleItemBulkWriteAction.doExecute() │
│ ↓ │
│ 调用 bulkAction.execute() ←─ 这里是交接点,不是循环!
└─────────────────────────────────────────────────┘
↓
┌───────────────────── 路径B ─────────────────────┐
│ TransportBulkAction.execute() │
│ ↓ │
│ TransportAction.execute() │
│ ↓ │
│ TransportAbstractBulkAction.doExecute() │
│ ↓ │
│ 真正的批量处理逻辑 │
└─────────────────────────────────────────────────┘
栈的深度翻了一倍。为了模板而模板,但是在业务逻辑上根本没关系的,都抽象在一起,封装为bulk,再调delete流程。它们就不应该抽到TransportAction中,这都是技术债累积。当zab,raft大行其道的时候,ES仍旧zen,试图证明自己,扭扭捏捏修补zen,10年后实在适应不了分布式协调了硬着头皮改成raft,但是你能明显看出ES的raft仍然有zen的影子,很累。如果不壮士断腕,重构代码结构走不远的。补丁最终会让积木崩塌。功能设计再好,也抵不住运维没人。从1.x兼容到8.x的API,能不18000的代码量就奇怪了。后续维护很困难
BulkOperation
BulkOperation->ActionRunnable->AbstractRunnable{run{doRun()}}
BulkOperation写一个doRun,然后调用时BulkOperation.run调用AbstractRunnable的run方法绕一圈回来调用自己的doRun,它有一万种理由,但这么浪费栈的也是不多见,直接重写run,要什么donRun,感情就是为了这个方法名故意绕一圈。同理
ReroutePhase->ActionRunnable->AbstractRunnable{run{doRun()}}