带过几个 Python 项目之后我发现一个挺普遍的现象代码仓库里的 README 写得很详细接口文档也齐全但你要让一个新同学在半小时内说出系统分几个模块、数据怎么流基本做不到。问题就出在缺一张 Python 应用架构图。很多时候大家把架构图当成“项目答辩专用材料”平常根本想不起来维护等到要给别人讲系统、或者项目规模大到改不动的时候才后悔当初没把图留好。这篇文章我就围绕架构图怎么设计、怎么画、用什么画结合真实的单体应用、微服务、数据处理管道三个场景把一些常见做法和踩过的坑一次说清楚。不管你是准备给项目补文档还是正在画第一版架构图都值得往下看。1. 画架构图之前先想清楚你要表达什么很多同学拿到画图任务第一反应是打开工具开始拖框框结果画出来的图自己都看不下去。其实架构图画不好九成不是工具问题而是没想清楚这张图到底要说什么。1.1 架构图的三个层次别把概念混在一起我见过太多人把用户、数据库、服务器、业务流程全部塞进一张图最后变成一张谁都不愿意看的蜘蛛网。要避免这个局面首先得区分架构图的三个层次。业务架构图描述角色、业务流程、业务模块之间的关系。它不关心技术实现只关心“业务上谁和谁打交道”。系统架构图描述服务、组件、模块之间的调用关系。这是最常见的“技术架构图”强调依赖方向、接口边界、数据流。部署架构图描述物理节点、容器、网络、端口、实例数量。它回答的是“这个系统跑在哪里怎么被访问”。在实践中业务架构图给产品经理和老板看系统架构图给开发同事看部署架构图给运维和排障的人看。画之前先想清楚这张图给谁看内容取舍自然就清楚了。1.2 架构图必须回答的三个问题不管选哪种层次一张合格的架构图至少要让看图的人在三分钟内找到三个答案系统有哪些核心组件这些组件之间怎么交互数据从哪里来最终到哪里去第一个问题决定你要画哪些框第二个问题决定箭头怎么打第三个问题决定数据流是否闭环。我自己画图时有个习惯先把这三个问题的答案写在空白处再开始设计图形而不是直接动手画组件。这样画出来的图信息密度高且不跑偏。1.3 先画主干再补细节头几次画架构图我的毛病是恨不得把每个函数都画进图里。后来带我的老前辈说了一句话我一直记着架构图的读者没有耐心超过十五个框就开始烦躁。所以第一版图永远只画主干分支细节放到单独的局部图里或者用文字补充。一个合理的做法是主图上保留核心模块和关键依赖每个模块旁边标注“详见 xx 子图”把复杂度拆开各讲各的。2. 先设计再画图一个 Python 应用架构的完整推导画图本身不难难的是图背后那套架构设计思路。这个部分我拿一个模拟项目 X 来走一遍完整推导项目背景是一个内容发布系统读者可以对照自己手头的项目理解。2.1 从需求到模块划分的推导方法模拟项目 X 的需求很简单用户注册登录、发布文章、查看文章、发表评论。拿到这种需求先别急着写代码花十分钟把功能点列出来再按职责归类用户相关注册、登录、用户资料内容相关文章发布、文章编辑、文章列表互动相关评论、点赞、通知系统相关权限校验、日志、配置管理归类之后你会发现自然形成了四个模块边界认证模块、内容模块、评论模块、公共基础模块。模块边界清晰之后数据库表也就好设计了用户表、文章表、评论表以及它们之间的外键关系。这一步不涉及任何 Python 技术栈但它是架构图的灵魂。2.2 分层架构的典型结构模拟项目 X 采用最常见的分层架构自顶向下四层表现层负责接收 HTTP 请求通常由 FastAPI 或 Flask 的路由构成服务层承载业务逻辑比如发文章前先校验用户权限、再写数据库数据访问层封装所有数据库操作通常用 SQLAlchemy 这类 ORM数据存储层PostgreSQL、Redis 等具体存储为什么要分层我打个比方餐厅里点菜员不直接进厨房炒菜而是通过传菜窗口和厨师交互。表现层就像点菜员服务层是厨师长数据访问层是配菜师傅数据库是食材仓库。每一层只跟相邻层打交道哪一环要换比如把 PostgreSQL 换成 MySQL只需要动数据访问层其他层完全不知道。2.3 箭头方向比组件本身更重要分层架构图里最常见的错误是把箭头画反。记住一个原则箭头表示依赖关系依赖的方向应该朝向更稳定的一侧。表现层依赖服务层服务层依赖数据访问层数据访问层依赖数据库所以箭头的方向是从上往下指。反过来画就乱套了如果数据访问层反过来依赖表现层那说明你的架构已经存在循环依赖这是代码坏味道的预警。判断依赖方向的实战技巧很简单问自己一句话“如果我要把表现层整个换掉服务层以下需要动吗”如果答案是“不需要”说明依赖方向是对的。2.4 从现有代码反推架构的方法如果是给已经存在的项目补架构图逆向梳理的步骤很固定。第一步从入口文件开始通常就是 main.py 或 app.py看它注册了哪些路由第二步跟踪每个路由 handler 调用了哪些 service 方法第三步看 service 依赖哪些 repository 或 model第四步确认数据模型定义在哪个模块。把这一条条调用链写下来架构图就浮出水面了。这里我推荐一个小技巧不要全靠人肉读代码。利用 pydeps 这类工具扫描 Python 包的依赖关系会生成一个模块之间的依赖结构图作为初稿再人工修正比自己盯着代码看半个钟头高效得多。3. 绘制架构图的工具选型与实战工具没有绝对的好坏只有合不合适。我画过四五种工具这里直接给出一份横向对比帮大家节省试错时间。3.1 工具横向对比与选型建议工具适合场景上手难度协作方式我的评价PlantUML代码化绘图适合写进文档、走 Git 版本管理中等代码仓库团队协作首选可 reviewdraw.io手拖组件适合快速产出、做汇报图低文件共享交互灵活但难 diffGraphviz自动布局适合复杂依赖关系中高DOT 文件布局靠算法省手动排版excalidraw手绘风草图适合头脑风暴极低实时协作出不了正式文档感我的建议是正式项目文档用 PlantUML因为它背后是文本文件和代码一起进 Git每次改动都能看到 diff代码评审时顺手就把架构图评审了。临时画个思路草图用 excalidraw 或 draw.io五分钟出图不心疼。Graphviz 则适合组件多、连线关系复杂、手动排版排不过来的场景。3.2 PlantUML 实现一个分层架构图PlantUML 写架构图的思路其实和写代码一模一样定义组件、定义关系、交给编译器渲染。下面是我为模拟项目 X 画分层架构时实际用过的脚本去掉细节只保留主干startuml skinparam componentStyle rectangle skinparam monochrome true package 表现层 { [认证接口] as AuthAPI [文章接口] as PostAPI } package 服务层 { [用户服务] as UserSvc [文章服务] as PostSvc } package 数据访问层 { [用户仓储] as UserRepo [文章仓储] as PostRepo } database PostgreSQL as DB AuthAPI -- UserSvc PostAPI -- PostSvc UserSvc -- UserRepo PostSvc -- PostRepo UserRepo -- DB PostRepo -- DB enduml这段脚本生成的图里三个 package 把表现层、服务层、数据访问层清楚地围起来组件之间的箭头关系一目了然。重点说两个容易被忽略的细节一是skinparam componentStyle rectangle把组件画成矩形比默认的圆角图标更符合架构图习惯二是skinparam monochrome true输出黑白风格打印到纸上或者放投影仪上都不会看不清。3.3 用 draw.io 手工绘制时的布局原则如果你选择 draw.io我有几条实操经验。第一画面从上往下分层最上层放用户或外部系统最下层放数据库第二同层的组件水平排列保持视觉整齐第三箭头永远标注方向如果是数据流建议把数据内容写在箭头上比如“文章 JSON”而不是光画一条线第四用颜色区分层次但一张图不超过五种颜色否则变成彩虹图。坦白说draw.io 画出来的图确实好看但维护很痛苦。有一次项目迭代组件改了两个名字我手动改了五处还漏了一处从那以后我就把正式文档切换成了 PlantUML。手工工具的宿命就是改一处、漏三处代码化工具天然避免了这个问题。3.4 一个可以直接套用的通用模板如果你的项目没有什么特殊架构我建议直接套用下面这个五层模板改改名称就能用用户层浏览器、App、第三方调用方网关层Nginx、API 网关负责路由和鉴权应用层Python 服务实例按业务模块拆分成多个组件数据层关系型数据库、缓存、对象存储外部依赖层短信服务、邮件服务、支付回调等这五层覆盖了绝大多数中小型 Python Web 应用的架构形态。画的时候从下往上问自己数据存在哪谁读写数据谁调用应用谁在外面请求问完一圈框和线自然就填满了。4. 三个真实场景的架构图示例拆解这个部分是全文的干货核心。我选了三个最常见的 Python 应用场景分别演示架构图的画法和思考过程大家可以按场景对号入座。4.1 单体 Web 应用架构图示例第一个场景是某公司内部的管理后台技术栈是 Flask PostgreSQL Redis典型的单体应用。这类系统的架构图不需要画得很宏大但要把模块边界交代清楚。画图时我习惯用“组件 数据存储 外部依赖”三要素来组织外部浏览器用户、邮件服务网关Nginx负责静态文件代理和 HTTPS 终结应用Flask 主进程内含认证模块、业务管理模块、数据导出模块存储PostgreSQL主数据、Redis缓存和会话关键箭头有浏览器到 NginxNginx 到 Flask 应用Flask 内部三个模块之间的调用关系以及 Flask 到 PostgreSQL 和 Redis 的读写方向。外部邮件服务只被数据导出模块调用用虚线表示异步调用。这张图的核心表达是所有请求都遵循“入口统一、模块内聚、存储隔离”的原则。看的人只要抓住这三句话就能理解整张图。4.2 微服务架构图示例第二个场景是一个模拟电商平台包含订单服务、库存服务、用户服务、支付回调处理四类服务。微服务架构图最容易犯的病是“网状爆炸”所以我会刻意把图拆成两层来表达。第一层是流量入口客户端请求先经过 API 网关网关负责路由、限流、登录态校验再把请求转发给对应的业务服务。第二层是服务间调用订单服务在创建订单时需要查询用户服务、扣减库存服务而库存扣减通过消息队列异步完成。实际画图时我给每个服务框加了“服务名 职责 存储”三行信息比如“订单服务 / 创建与查询订单 / 订单库”。这样一张图看完每个服务的边界清清楚楚。微服务架构图的另一个要点是标注协议服务之间是同步 HTTP 调用还是异步消息要用实线和虚线区分开否则看图的人没法判断系统的耦合程度。4.3 数据处理管道架构图示例第三个场景是日志处理管道采集日志、写入消息队列、Python 任务消费清洗、结果落到数仓、最后出报表。这种管道类系统的架构图和 Web 应用不一样核心不是依赖关系而是数据流所以我更推荐用 Graphviz 来自动布局。DOT 脚本示例如下digraph pipeline { rankdirLR; source [label日志采集器]; queue [labelKafka 集群]; processor [labelPython 清洗任务]; warehouse [label数仓]; report [label报表服务]; source - queue; queue - processor; processor - warehouse; warehouse - report; }这段脚本渲染出来是一张从左到右的流程管道图每个阶段一个节点数据路径一目了然。我在实际项目里还会在每个节点下面加一列小参数比如采集器的采样频率、Kafka 的 topic 名称、清洗任务的并发数。这样架构图兼职了配置文档排障时一图在手不用翻三个系统。4.4 架构图中的连接线规范最后补一个规范化的小建议。我在团队里推过一套简单的连接线规范大家照着画图风格非常统一实线箭头同步调用比如 HTTP 请求、函数调用虚线箭头异步消息比如发消息队列、写事件日志粗箭头数据流强调一条数据从源头到目标的主链路普通细线无箭头的关系比如配置依赖、部署关系这套规范不需要学看一遍就懂但它能让不同人画出来的图保持一致的“语言”省去大量沟通成本。5. 绘图过程中最常见的坑与排查技巧再优秀的画图方案实操中也会遇到各种坑。我把这几年踩过的雷整理成一份速查清单每一条都是真实场景里出现过的。5.1 依赖方向画反架构图的头号错误分层架构里最常见的错误就是把表现层画在最下面然后箭头从数据访问层指向上面的服务层。出现这种情况通常不是画图的人手误而是代码本身就有循环依赖——服务层偷偷 import 了表现层的某个工具函数。所以我在 review 架构图时看到一个“向上的箭头”第一反应不是改图而是去查代码。画图反而不小心暴露了坏味道这是架构图的额外价值。5.2 组件信息过载一张图塞了 30 个框前面提过“超过十五个框就开始烦躁”这里我再补充一个精简技巧按层次删减。每画完一层问一句“这层的这三个组件能否合并成一句话描述”如果答案是“能”就把它们合并成一个框把细节写进注释。合并之后的架构图读起来就像一句话用户通过网关访问应用应用读写数据外部依赖通过异步消息解耦。5.3 中文乱码和字体问题PlantUML 默认渲染中文字体偶尔会出现乱码或方块这个问题我折腾过很久。第一步确保文件头部声明了 UTF-8 编码第二步给 PlantUML 指定支持中文的字体比如在脚本开头加一行skinparam defaultFontName Microsoft YaHei第三步如果还是乱码检查本机是否安装了对应字体。大多数情况下这三点改完就能正常显示中文。5.4 架构图与代码脱节架构图最大的敌人不是画得丑而是画完之后没人更新三个月后彻底失准。我个人的解法是架构图脚本和代码放在同一个仓库里并且约定了代码评审时如果涉及模块拆分、依赖方向变化必须同步更新架构图文件。这个约定执行半年后团队里再也没有出现过“图是旧的”的抱怨。还有一个技巧是给架构图文档加一个日期标注看到日期超过半年没变会自动触发一次核对。5.5 分享时看不清布局和导出的坑最后分享一个线上会议踩过的坑。有一次我投影架构图图上每个字大概只有 12 号大小参会同事纷纷皱眉。后来我总结了三个规律导出图片时最小宽度设置在两千像素以上文字字号宁可大一点也不要为了排版紧凑牺牲可读性用颜色区分层次比用细线区分更容易辨认。这三条看着是小事实际影响非常大。最后再分享一个个人习惯每次画完架构图我会把图打印出来或者放到手机里找个没写代码的空闲时间对着图把关键流程“讲”一遍。能从头到尾讲顺说明这张图是合格的讲到一半卡住那卡住的地方多半就是架构里的模糊地带值得回去好好想清楚。架构图的价值不在它本身有多精美而在于它能逼着我们把系统的边界、依赖和数据流梳理明白。希望这篇文章能帮你少走一些弯路画出真正能用的 Python 应用架构图。
阅读完成 · 觉得有帮助?