噢,你的代码像一坨翔 然后呢?(你的代码写的真棒表情包)
mhr18 2024-10-09 12:23 59 浏览 0 评论
Big Ball of Mud,中文名称“一坨翔”。自打我入行以来,就一直在和这一坨翔做搏斗。此处略去一千字,反正相信我,哥肯定是吃过翔的。
虽然不少翔是自己拉的。有太多文章谈论这个问题了,每次满怀热情的打开,然后看到结尾要么就是告诉你要拆微服务,要么就是告诉你我这有个什么样的中间件产品,你要不要用一用。你妹啊,如果知道怎么拆,需要来看你的文章么…… 咱不多废话了,严肃起来。
Big Ball of Mud 的系统有三种死法:
因为性能不满足要求而死,这个时候需要懂内核懂数据结构的架构师来好好做一下拆分。让系统更符合计算机体系结构,最大化利用硬件资源。各种新式的中间件就是在这个领域不断革命。
因为业务逻辑复杂得hold不住而死,开发效率慢到爆
因为软件架构不符合组织架构,导致团队间吵架吵到死的,这个时候老板重新思考什么样的组织架构才是合适的(大boss通过组织架构划分,他绝对是最终极的架构师)。
计算机体系架构因为其是确定性的,这个结构调整相对好做。我们见过很多实际的例子,通过调整代码的结构,使得 cache miss, branch prediction rate,data locality 大幅优化,而性能数倍提高。
我的梦想就是,找到一种拆分系统的原则,使得其能够和业务架构非常贴合。从而减少让焦油坑一般的厚重的业务逻辑代码也可以变得充满美感。对计算机有兴趣的青年,不应该最后都到基础架构的领域里去造轮子。Eric Evans 对于 Core Domain 的说法深得我心。
然后就开始了找赤脚大夫,抓药方的不归路。
药方一:领域模型
在那个还有 CRC 卡的年代。面向对象设计,领域模型这些是被寄予厚望的。在曾经的 javaeye 论坛上,如红小兵一般的当年的我,也是很激情澎拜地参与着模型是应该贫血还是充血的争论。
大部分尝试使用领域模型的项目,好一点的只是在代码里多了一个model目录,倒没有付出什么成本。差一点的是把整个数据表重新定义了一个xxxBO的对象,然后每次都要多一次对象的字段拷贝。逻辑写来写去只看见增删改查,哪里有什么领域模型可言?
领域模型说穿了就是一个AggregateRoot,就说要维护一个model的概念完整性(conceptual integrity)。比如一个账单上的账要是平的,某个条目上多了,另外一个条目就要少了。这些业务上的恒定规则(invariant)需要被封装到对象内部被保护起来,以免数据出现逻辑上的错乱(和并发无关)。有多少系统有复杂的业务规则需要这么封装的?其实很少。
面向对象流派发展到后来又出现了 qi4j (Qi4j Community)以及 DCI (Lean Software Architecture)。概念其实都是一样的,一个对象来承担不同上下文的职责是会膨胀的,完全没有必要把参与不同业务流程的不同职责,强行塞到同一个对象里。我们应该要把对象按照不同context,把逻辑拆出来。但是等 James Coplien 这些大牛们想明白的时候,微服务已经主宰世界了。在微服务的世界里,服务的拆分代替了类的设计,变成了主要的建模工具。至于一个服务自身是贫血还是充血的,已经没有人在乎了。
药方二:所谓服务化改造
最常见的药方长这个样子
这个药方在不同时期,被不同的大夫,以不同的名字开过。还记得当年的 .NET Web Service,SOA 吗?把各种 RPC 技术往DB前面一挡,咱就服务化了。
我一直就纳闷了,你一个远程调用的 DAO 有什么贡献?业务代码里写 http://mysql.xxx 和写 http://rpc.xxx 有本质区别?当然数据服务可以处理分库分表,缓存同步等问题。但是那些本质上都是非功能性需求,是一个业务无关的轮子。对于业务代码的贡献就是把非业务的逻辑给剥离出去了而已。
药方三:企业服务总线
比卖RPC方案(WS-xxx 标准当年也养活了不少人那)更可恶的厂商,是那些兜售 ESB 的厂商。也许这些所谓的流程引擎,可以在 OA,运维部署工具 等特定领域减少开发工作量。打着提高开发效率的做一个平台,来托管业务逻辑的行为是可耻的。Udi Dahan 的一个评价特别静精辟,这些做得好,最多就是一个VB6,做得不好就是场灾难。
曾经自己拉一坨这样的翔,然后含着泪喂给伙伴们吃完之后,从此看见 BPM/ESB 这样的字眼就特别紧张。构造一个平台,和发明一门 PHP 这样的语言差不多复杂。上面需要有调试,编辑,版本管理,版本diff等一系列的支持。大部分的公司内部系统,没有足够的资源去把这些东西给做完善来。如果不是面向特定的场景(数据处理,OA,运维),而是一个非常通用的系统,其效果只能比 PHP 裸写逻辑还要糟糕。
安利一下,世界上最好的流程调度和编排工具:PHP,没有之一。
药方四:异步化
另外一个流派的口头禅是耦合。你看,RPC是邪恶的。服务之间调用耦合太严重了。我们需要引入队列来解耦。Fred George 同学甚至把这种通过消息异步解耦的系统架构推上了神坛的高度。
看架构图,我们都是兴奋的。这种太好了,我业务都不用感知到这些下游服务的存在了。你们自己去订阅我的消息队列就好了。但是一旦用到实践中,就发现你根本没法直接用起来。常见的借口是这样的:
消息处理的可靠性:kafka 后面最常见的业务是什么?其实是一些看趋势,做智能分析的业务。如果你不用在乎少几条数据没处理,大可以用这种异步架构。如果你要出财务报表?那还是老老实实用DB吧。
消息处理的及时性:你别把 kafka 用到主流程里。这个消息要是被延迟了,会死人的。RPC 还是“可靠”一点。
业务本来就是同步的:我是一个手机 app,我的端的交互接口就是需要在操作了之后,同步得到服务甲乙丙N个服务的处理结果。没有这些数据,操作完了的界面上就看不到剩余配额,看不到账单,看不到xxx。你 mq 能给我返回值么?我擦……
当然做为一个理想追求的你来说,觉得这些都不是问题:
消息处理的可靠性:消费的时候如果失败了不提交offset就行了嘛。挂了会从上次失败的地方重试的。最多重,不可能丢的。再说了,还可以实时对账,隔天对账嘛。
消息处理的及时性:就好像 RPC 服务不会挂一样。异步无非就是多了 mq 这一跳而已嘛。我拍胸脯,保证不挂,行不行?我给你做压测,保证p99的延迟低于xyz毫秒。
业务本来就是同步的:doXXX 这样的接口就不应该返回具体的界面数据。应该是doXXX给个成功和失败,然后 getX,getY,getZ。如果消息还在异步处理中,大不了显示的counter还没有+1,或者我就干脆写一个“还在处理中”就好了嘛。
世界上的人都是你这样有理想的人该有多好哇。不过相信我,大部分同学会认同,异步化没有帮他们解决什么问题,反而搞出一堆麻烦事情来。你说让他们去找产品,把需求改成异步的?扯淡吧……
药方五:Event Sourcing
以 Greg Young 同学为代表的大夫,最喜欢的就是跟你说“我这有一个蓝色的小药丸,你吃不吃?”。他的药丸长这个样子
你们都做错了,业务逻辑要以 command/event 为中心,而不是以 state 为中心。难怪你们都写出来的是一坨翔。你看哥的这种 event handler 的模式,多么牛x。我们知道丝袜可以治疗静脉曲张。但是不代表人人都应该穿丝袜。到底 Event Sourcing 怎么就解决了复杂业务逻辑的问题?我就是不用 event sourcing,我也可以在业务代码里产生事件并写 mq 啊?
Greg Young 的说法是如果你的业务不是以 event 为中心的,那么这个 event 你怎么知道是对的呢?来来来,我们看看 accountant 都是怎么工作的
会计是从来不用橡皮擦的。只有我们的系统是以 append only 的 event 为基础的,我们才是可信的。我擦,好有道理的样子哦。
但是我相信你从激动里回过神来,尝试了三五天之后,肯定会放弃在你的生产环境里吞下这个小药丸。简单来说,就是不值得。大部分的人都不是在做高并发写入,同时又具有复杂业务逻辑的事情。大部分人的工作就是增删改查,把数据按照业务逻辑算对了而已。没有对冲基金,证券交易所这种的业务上下文,Event Sourcing 就是 over design。
事实上所有的 DB 都是 Event Sourcing 的。我们只是把这部分有挑战的工作,托管给了 Oracle 那帮聪明的家伙了而已。只有当悲观锁(事务),乐观锁(单行事务,update xxx=zzz where version=1)都玩不转了的时候。我们才值得把状态从 DB 迁移到业务代码里,自己来管理状态的并发写入。
刨去了 OLTP 部分用Event Handler的模式,Event Sourcing的另外一部分故事,不过是前面异步化方案的新瓶装旧酒而已。仍然有同样的问题,不是所有人“都愿意”被异步化的。这是一个技术问题,更一个团队合作方式的问题。
且听下回分解:
噢,你的代码像一坨翔。甩锅呗!
作者:陶文
链接:https://zhuanlan.zhihu.com/p/25169261
来源:知乎
相关推荐
- Java培训机构,你选对了吗?(java培训机构官网)
-
如今IT行业发展迅速,不仅是大学生,甚至有些在职的员工都想学习java开发,需求量的扩大,薪资必定增长,这也是更多人选择java开发的主要原因。不过对于没有基础的学员来说,java技术不是一两天就能...
- 产品经理MacBook软件清单-20个实用软件
-
三年前开始使用MacBookPro,从此再也不想用Windows电脑了,作为生产工具,MacBook可以说是非常胜任。作为产品经理,值得拥有一台MacBook。MacBook是工作平台,要发挥更大作...
- RAD Studio(Delphi) 本月隆重推出新的版本12.3
-
#在头条记录我的2025#自2024年9月,推出Delphi12.2版本后,本月隆重推出新的版本12.3,RADStudio12.3,包含了Delphi12.3和C++builder12.3最...
- 图解Java垃圾回收机制,写得非常好
-
什么是自动垃圾回收?自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制。所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象;而未使用中的对象(未引用...
- Centos7 初始化硬盘分区、挂载(针对2T以上)添加磁盘到卷
-
1、通过命令fdisk-l查看硬盘信息:#fdisk-l,发现硬盘为/dev/sdb大小4T。2、如果此硬盘以前有过分区,则先对磁盘格式化。命令:mkfs.文件系统格式-f/dev/sdb...
- 半虚拟化如何提高服务器性能(虚拟化 半虚拟化)
-
半虚拟化是一种重新编译客户机操作系统(OS)将其安装在虚拟机(VM)上的一种虚拟化类型,并在主机操作系统(OS)运行的管理程序上运行。与传统的完全虚拟化相比,半虚拟化可以减少开销,并提高系统性能。虚...
- HashMap底层实现原理以及线程安全实现
-
HashMap底层实现原理数据结构:HashMap的底层实现原理主要依赖于数组+链表+红黑树的结构。1、数组:HashMap最底层是一个数组,称为table,它存放着键值对。2、链...
- long和double类型操作的非原子性探究
-
前言“深入java虚拟机”中提到,int等不大于32位的基本类型的操作都是原子操作,但是某些jvm对long和double类型的操作并不是原子操作,这样就会造成错误数据的出现。其实这里的某些jvm是指...
- 数据库DELETE 语句,还保存原有的磁盘空间
-
MySQL和Oracle的DELETE语句与数据存储MySQL的DELETE操作当你在MySQL中执行DELETE语句时:逻辑删除:数据从表中标记为删除,不再可见于查询结果物理...
- 线程池—ThreadPoolExecutor详解(线程池实战)
-
一、ThreadPoolExecutor简介在juc-executors框架概述的章节中,我们已经简要介绍过ThreadPoolExecutor了,通过Executors工厂,用户可以创建自己需要的执...
- navicat如何使用orcale(详细步骤)
-
前言:看过我昨天文章的同鞋都知道最近接手另一个国企项目,数据库用的是orcale。实话实说,也有快三年没用过orcale数据库了。这期间问题不断,因为orcale日渐消沉,网上资料也是真真假假,难辨虚...
- 你的程序是不是慢吞吞?GraalVM来帮你飞起来性能提升秘籍大公开
-
各位IT圈内外的朋友们,大家好!我是你们的老朋友,头条上的IT技术博主。不知道你们有没有这样的经历:打开一个软件,半天没反应;点开一个网站,图片刷不出来;或者玩个游戏,卡顿得想砸电脑?是不是特别上火?...
- 大数据正当时,理解这几个术语很重要
-
目前,大数据的流行程度远超于我们的想象,无论是在云计算、物联网还是在人工智能领域都离不开大数据的支撑。那么大数据领域里有哪些基本概念或技术术语呢?今天我们就来聊聊那些避不开的大数据技术术语,梳理并...
- 秒懂列式数据库和行式数据库(列式数据库的特点)
-
行式数据库(Row-Based)数据按行存储,常见的行式数据库有Mysql,DB2,Oracle,Sql-server等;列数据库(Column-Based)数据存储方式按列存储,常见的列数据库有Hb...
- AMD发布ROCm 6.4更新:带来了多项底层改进,但仍不支持RDNA 4
-
AMD宣布,对ROCm软件栈进行了更新,推出了新的迭代版本ROCm6.4。这一新版本里,AMD带来了多项底层改进,包括更新改进了ROCm的用户空间库和AMDKFD内核驱动程序之间的兼容性,使其更容易...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle 空为0 (51)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (78)
- php redis (88)
- redis 存储 (66)
- redis 锁 (69)
- 启动 redis (66)
- redis 时间 (56)
- redis 删除 (67)
- redis内存 (57)
- redis并发 (52)
- redis 主从 (69)
- redis 订阅 (51)
- redis 登录 (54)
- redis 面试 (58)
- 阿里 redis (59)
- redis 搭建 (53)
- redis的缓存 (55)
- lua redis (58)
- redis 连接池 (61)
- redis 限流 (51)