为什么你的代码迟早会崩成"意大利面"?一个概念,毁掉了无数系统
Site Owner
发布于 2026-05-24
内聚性决定了代码能活多久。功能聚合、顺序聚合、通信聚合、时间聚合、逻辑聚合、偶然聚合——这七种内聚级别,划定了你的代码是能改还是只能重写。AI时代,内聚问题比以往更严峻。

为什么你的代码迟早会崩成"意大利面"?一个概念,毁掉了无数系统
一个在Hacker News上被点了上千赞的评论这样说:
"大语言模型很擅长写代码,但在软件工程上表现很差……我正在修复一个靠氛围编程写出来的应用,单个功能看着还行,但整体就是一团意大利面条式的烂摊子。"
说这话的是一个50岁的老程序员。而让他如此痛心的,不是别人的代码,是他自己的——他用了四十年积累的经验,居然在AI时代眼睁睁看着代码质量崩塌。
问题出在哪?
不是AI不行。是你压根没搞懂一个叫"内聚"的东西。
代码为什么会长成"意大利面条"
你有没有过这种经历:
接手一个老项目,打开一看,所有函数都堆在一个文件里。你想改一个打印功能,结果把数据计算也给搞崩了。改完之后测试,发现另一个完全不相干的功能出问题了。
这不是你技术不行。这是代码的"内聚性"太差。
所谓内聚,衡量的是一个模块内部各个元素结合得有多紧密。理想状态是:一个模块只做一件事,这件事做得漂亮极了。但现实往往是——一个模块里塞了一堆八竿子打不着的东西,堆上去的唯一原因是"当时懒得再建一个文件"。
举个具体的。
// 典型的低内聚代码
function initSystem() {
// 时间聚合:这些操作唯一的共同点就是需要在启动时执行
connectDatabase(); // 连接数据库
loadConfig(); // 加载配置
sendWelcomeEmail(); // 发欢迎邮件
startScheduler(); // 启动定时器
initializeLogger(); // 初始化日志
}
这个函数里干的事没有一件跟另一件有关系。它们唯一的共同点是"系统启动时需要跑一遍"。这种内聚叫时间聚合,属于内聚级别里比较差的那种。
再比如:
// 逻辑聚合:把一堆不相干的东西因为"逻辑上差不多"塞一起
function handleData(data, type) {
if (type === 'user') {
validateUser(data);
saveToUsersTable(data);
sendNotification(data);
} else if (type === 'order') {
validateOrder(data);
processPayment(data);
generateInvoice(data);
}
// 一旦要加新类型,这里就开始膨胀
}
打印用户数据和处理订单,看起来都是"处理数据",但它们不是同一件事。强行捏在一起,就是逻辑聚合,内聚级别更差。
时间长了,这种代码就像往冰箱里塞东西——今天塞,明天塞,塞到冰箱门都关不上了,你都不知道里面有什么。
内聚的七重境界
计算机科学家花了几十年研究内聚,给它画了一个从高到低的阶梯:
功能聚合 > 顺序聚合 > 通信聚合 > 过程聚合 > 时间聚合 > 逻辑聚合 > 偶然聚合
最理想:功能聚合
一个模块只干一件事,而且这件事干得无比彻底。
# 功能聚合:只计算平方根,别的什么都不管
def calculate_square_root(number):
if number < 0:
raise ValueError("Cannot calculate square root of negative number")
return number ** 0.5
这个函数简单到不需要注释。任何人看到这个函数名,就知道它会做什么,不会做什么。这就是功能聚合,内聚的最高境界。
中间档:顺序聚合
前一步的输出,是后一步的输入。
# 顺序聚合:读取 → 处理 → 保存,数据流清晰
def process_user_data(user_id):
raw_data = fetch_user_from_db(user_id) # 第一步的输出
cleaned_data = clean_and_normalize(raw_data) # 第二步的输入
save_to_datawarehouse(cleaned_data) # 第二步的输出
这种内聚不算最优,但数据流清晰,可测试性强,在真实项目里已经很实用了。
最差劲:偶然聚合
模块里的各个元素之间压根没有任何关系。
# 偶然聚合:这是从哪抄来的代码?
def utility_mess():
process_order()
send_email()
calculate_distance()
update_cache()
format_phone_number()
# 它们唯一的共同点是被我随手扔到了这个文件里
偶然聚合就是代码混乱的终极形态。当一个团队长期缺乏架构意识,他们写出来的代码最终都会退化到这个状态。
AI时代,内聚问题变得更严重了
文章开头那个老程序员的担忧正在成为现实。
越来越多的开发者开始用AI辅助编程。AI确实能提升单个函数、单段代码的质量。但问题来了:AI不知道你整个系统要做什么,它只会根据你给的上下文生成看起来合理的东西。
结果是:
- 单个函数写得挺好
- 但函数之间关系混乱
- 数据流穿过整个代码库,毫无章法
- 改一处,另一处莫名其妙地崩了
这不是AI的bug。这是架构意识的缺失。
人类工程师花了二十年才搞明白"模块化设计"的重要性。AI只是把这个过程加速了,但同时把那些该踩的坑也一并跳过了。
更讽刺的是,那些靠"氛围编程"快速搭出来的应用,上线三个月之后,维护成本往往是预期的好几倍。因为代码烂到连AI自己都不想接手。
所以,内聚到底有什么用
你可能觉得,这不就是教科书上的概念吗?考完试就可以忘了。
错了。
内聚决定了你的代码能活多久。
高内聚的代码:
- 修改一个功能,不会影响另一个功能
- 新人接手,能快速理解模块边界
- 测试可以精准定位问题
- 重构时不用担心牵一发动全身
低内聚的代码:
- 改一个bug,制造三个新bug
- 每次上线都像在拆炸弹
- 团队人员一换,代码就成了"祖传秘方"
- 最后要么大规模重写,要么直接推翻重来
你见过那种"屎山"项目吗?十几年没人敢动,文档早就没了,会的人早走了,每次需求过来都得先做一周考古。这就是内聚失败的代价。
怎么判断你的代码内聚性
一个简单的心法:当你描述一个函数时,用了"和"字,就说明它在干两件事。
"这个函数负责验证用户身份和发送欢迎邮件和记录日志。"
用了三个"和",说明三个职责被塞进了同一个函数。这个函数迟早会变成一个谁都不敢动的怪物。
正确的做法是:每个函数只描述一件事,如果你发现你在用"和"来描述,就拆。
# 拆分前:验证用户身份和发送欢迎邮件和记录日志
def register_user(user_data):
if not validate_email(user_data['email']):
raise InvalidEmailError()
save_to_database(user_data)
send_welcome_email(user_data['email'])
log_registration(user_data['id'])
# 拆分后:职责单一,每个函数都可以独立测试和复用
def validate_email(email):
...
def save_user_to_database(user_data):
...
def send_welcome_email(email):
...
def log_registration(user_id):
...
def register_user(user_data):
validate_email(user_data['email'])
user = save_user_to_database(user_data)
send_welcome_email(user_data['email'])
log_registration(user['id'])
拆完之后,每个小函数都变得极好理解,极好测试,极好复用。这就是功能聚合的魔力。
给这个AI满天飞的时代
现在的程序员是幸运的,也是悲哀的。
幸运的是,AI让写代码变得前所未有的快。悲哀的是,快不代表好。
那些靠AI堆出来的"意大利面条"代码,正在成为新一代的技术债务。三年后接手的人会恨死写出这些代码的人——而那个写出这些代码的人,可能就是现在的你。
高内聚不是一种追求,是一种责任。
你的代码六个月后会不会崩成新的"意大利面条",取决于你今天愿不愿意多花十分钟,把那个越滚越大的函数拆开。
代码能跑不算完,能改才算。