从抽象地狱逃出来:一段 Python 代码看清“过度设计”的代价

摘要

你可能见过这样的项目:刚起步就整上微服务框架、Kafka 消息中间件一把梭,再加上好几层抽象工厂 + 策略模式。等上线后才发现,系统只有两三个接口,压根没人用。

这些“自我感动式”的开发,其实是一种隐形浪费。它不是技术能力的展现,而是一种“过度假设未来”的风险决策。本文就来聊聊,怎么在架构设计中避免掉进“过度工程”的坑,选对“当下最合适”的解法。

引言

在很多开发讨论中,经常会出现这样的对话:

  • “咱们加个事件总线吧,不然以后不好扩展。”
  • “这个模块最好先拆微服务,以后独立部署才方便。”
  • “要不我们写个接口层 + 抽象层吧,万一换实现也简单。”

这些听起来都很“有道理”,但问题是:

你确定那个“以后”真的会来吗?

架构设计,不能为了“展示设计能力”而去设计。而应该是——为当前的实际问题找最直接、最简单的解决方案,同时保留未来演进的可能。

架构设计里那些常见的“坑”

典型“过度工程”场景盘点

下面这些操作你可能都见过:

  • 项目刚立项,产品都没写完,就先上 DDD + CQRS 架构;
  • 接口调用还没超过 10QPS,就搭建 Kafka + Redis + RabbitMQ 三件套;
  • 把一个简单的“用户积分增加”逻辑,写成工厂模式 + 策略模式 + 抽象接口 + 依赖注入;
  • 三个人的团队,把项目拆成六个微服务部署,还搞 CI/CD 全自动流程;

这些设计在“大公司大业务”里可能确实需要,但对很多项目来说,是 沉没成本+运维负担+认知负债 三杀。

为什么会这样做?

  • 怕未来被打脸:“我们现在不考虑,将来肯定会痛苦。”
  • 试图显得专业:“我会架构设计,抽象能力强。”
  • 兴趣驱动:“我最近刚学完微服务,想找机会试试。”
  • 写着写着就上头了:“加个接口好像也不麻烦,再加个中间层吧?”

“设计是否真的必要”的判断准则

提出三个关键问题

在开始设计之前,问自己:

  1. 这个设计是为了解决当前的问题吗?
  2. 有没有证据表明这个问题“马上就要来”?
  3. 有没有一个更简单的方法,能先解决问题并保留演进空间?

设计越多,维护成本越高;模块越多,沟通成本越高。

识别 YAGNI 现象

YAGNI(You Aren’t Gonna Need It)原则的核心是:

“别为未来做设计,除非它真的已经来了。”

比如:

  • “我们加个缓存接口吧,以后可以换 Redis/Memcached。”但现在连用户量都没破千;
  • “做个抽象层吧,说不定后面接入第三方支付。”但其实你短期根本不打算加;

这些全都是典型的 YAGNI。

用实际例子说话:一个“用户积分”服务的两种写法

背景需求

业务需求非常简单:

  • 给用户加积分;
  • 输入一个 user_id 和积分值;
  • 返回这个用户当前的积分总值。

这类接口在很多 App、运营系统、活动平台里都很常见。

写法一:过度工程版本(反例)

# service.py
class PointsService:
    def add_points(self, user_id: int, points: int) -> int:
        raise NotImplementedError

class PointsServiceImpl(PointsService):
    def __init__(self):
        self.points_db = {}

    def add_points(self, user_id: int, points: int) -> int:
        self.points_db[user_id] = self.points_db.get(user_id, 0) + points
        return self.points_db[user_id]

# factory.py
def get_points_service() -> PointsService:
    return PointsServiceImpl()

# main.py
service = get_points_service()
print(service.add_points(123, 10))

这个结构你肯定不陌生:接口 -> 实现 -> 工厂模式。

问题是:

  • 现在根本没多个实现;
  • 工厂也没什么逻辑,只是返回一个类;
  • 所有模块拆得很散,不利于快速开发或测试。

写法二:适度设计版本(推荐)

# 简洁明了版本
points_db = {}

def add_points(user_id: int, points: int) -> int:
    points_db[user_id] = points_db.get(user_id, 0) + points
    return points_db[user_id]

# 测试用例
if __name__ == "__main__":
    print(add_points(123, 10))  # 输出: 10
    print(add_points(123, 5))   # 输出: 15

优势:

  • 函数式结构清晰、轻量;
  • 易于快速测试、上手;
  • 不失灵活性,未来可以轻松迁移成 class 结构;
  • 更适合 MVP 阶段快速验证。

QA 环节:你可能会问的几个问题

Q1:那以后业务复杂了怎么办?

答:架构是可以演进的。你今天用一个函数实现,明天拆 class,一周后提取模块,一月后可以拆服务。

Q2:怎么判断是不是过度设计?

答:看使用频率、实现复杂度和维护成本之间的关系。如果你写了 100 行,只为支撑一个调用一次的接口,那就该反思一下。

Q3:是不是完全不能做抽象?

当然不是。适度抽象依然重要,但要把握节奏。抽象是为了解耦,不是为了堆技术词。

总结

架构设计的终极目标,不是“用最炫的技术”,而是“用最低的成本,跑通正确的业务”。

一个好的工程师,不是技术最潮的那一个,而是能判断什么时间该用什么设计的那一个。

切记:写代码是为了解决问题,不是为了写代码本身。

未来展望

未来系统肯定会越来越复杂,需求也会不断增长。但你现在最重要的任务,是:

  • 活下来(先跑通 MVP)
  • 跑得稳(上线不出事)
  • 改得动(迭代不崩盘)

架构设计,不是一次性拍板的定案,而是伴随业务和团队成长的“长期策略”。

真正的技术力,是看你如何处理“复杂问题”,而不是你堆了多少“复杂技术”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网罗开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值