
接手一个陌生代码仓库的第一周大部分人都干过同一件蠢事打开仓库根目录看到十几个子目录、上万行代码然后决定从 README.md 开始读读完了才发现 README 是五年前写的架构早就不一样了。我经历过三次类似的事情最后得出的结论是——与其直接埋头啃代码不如先拥有一张代码地图。这里说的代码地图就是标题里的 Archify 这类工具干的事把整个代码仓库丢进去几十秒自动生成一张架构图。它不是 UML 类图也不是在 Visio 里手动拖拽出来的那种系统蓝图而是直接从仓库真实代码里反推出系统有哪些模块、谁依赖谁、整体分几层的高层视图。Archify 本身支持本地仓库扫描也能直接接 GitLab、Gitee 这类远程代码仓库属于代码仓库秒生架构图这个赛道里比较有代表性的工具。这篇内容适合谁读如果你跟我一样经常接手老项目、要给微服务梳理依赖、带团队做架构评审或者只是希望自己手上的仓库不再是黑盒那 Archify 这套从扫描到出图、再到团队落地的完整玩法你应该用得上。下面我会从它解决的问题、底层原理、实际操作、常见翻车点一直讲到怎么把它放进团队协作流程全程都是我自己实际跑过的流程和踩过的坑。1. 为什么需要代码地图先搞清楚它解决的是哪个问题1.1 一个真实的新人上手场景我团队里有个刚入职两个月的开发有次被分配去改一个老订单服务的 bug。他从 clone 仓库到开始动手改代码花了整整一天半其中大部分时间在干嘛在考古打开一个包名点进去看几个类回到入口再跳到另一个服务最后在群里问我订单状态这个字段到底是在这边改还是那边改。这其实是常态。代码仓库的本质是大量不可见关系的集合光靠文件和目录你只能看到有哪些零件看不到零件之间怎么咬合。如果当时有一张自动生成的代码架构图他要做的事就简单得多先在图上定位订单服务看到它依赖了哪些基础模块、被谁调用再顺着边找到真正需要改的包。整个过程从读源码猜结构变成按图索骥看实现。1.2 手工画架构图的三座大山有人会说架构图这东西我们团队有啊用 Visio 画的还有专门的架构图软件。这就说到点子上了。我见过很多团队维护架构图的方式每年画一次放在 wiki 里吃灰。手工作图这件事至少有三个绕不过去的坑。第一是时间成本。你不把代码读明白是画不出正确架构图的而读明白恰恰是整个流程里最贵的事。拿 Visio 根据 Excel 生成组织架构图来类比前提是你已经把人员结构整理成了数据而代码架构图的前提是把几万行代码的真实依赖关系整理成数据这份名单本身就是巨量工作。大部分团队根本收集不起这份数据所以图只能靠架构师的记忆硬画。第二是失真速度。代码每周都在变架构图不一定。上个月还是标准三层架构这个月因为一个紧急需求插了个旁路模块图还是老样子。三个月后新人照着旧图定位问题跟对着五年前的 README 一样不靠谱。很多人问总体架构图怎么画我的答案通常很扫兴先放弃手画让代码自己诚实交代。第三是主观性。同一个仓库让两个人分别画架构图画出来的模块边界大概率不一样因为每个人对高内聚的判断标准不同。谁画的图后续就只能靠谁解释这个人一离职图基本就废了。架构图这门 skill真正的难点从来不是画而是准确理解代码并转成结构化关系这一步恰恰最适合自动化。1.3 代码地图是什么不是什么要理解 Archify 这类工具先得把它和常见的类图、组件图区分开。Archify 生成的不是 UML 类图——它不会把每个类的属性和方法都画出来那样在大型仓库里只会变成一团乱麻。它生成的是模块级架构图一个服务、一个包、一个聚合根级别的模块作为节点节点之间用有向边表示依赖关系再按逻辑或运行时的层次做布局。打个比方类图是城市里每栋楼的户型图代码地图是整座城市的路网图。你要找一个具体房间确实需要户型图但你要想搞清楚从哪儿走到哪儿、先经过哪个片区路网图才是能用的东西。Archify 做的就是自动测绘路网并且这份路网永远和真实街道一致因为它的数据来源就是代码本身。2. Archify 的工作原理从源码到架构图的完整链路2.1 第一步识别语言和项目骨架Archify 拿到一个仓库之后第一件事不是读代码而是认门。它会根据根目录的特征文件判断这是什么类型的项目有package.json是 Node 项目有pom.xml或build.gradle是 Java 项目有go.mod是 Go 项目有requirements.txt或pyproject.toml是 Python 项目。同时它会扫描整体目录结构识别出约定俗成的代码组织方式比如 Maven 的src/main/java、Go 的cmd和internal分层、前端项目的src/pages这类约定。这一步还会顺带做一件关键的事把第三方依赖和自家代码分开。node_modules、Python 虚拟环境里的 site-packages、本地 Maven 仓库这些都不算地图上的节点否则整张图会被几万个第三方包淹没。它只关注你自己的代码之间的依赖关系外部依赖会被折叠成边界上的一个小标签告诉你这个模块引入了哪些外部能力。2.2 第二步静态分析提取依赖关系核心环节是静态分析。Archify 会为每种支持的语言拉起对应的解析器把源码解析成抽象语法树AST然后从 AST 里提取谁引用了谁Java 的 import 语句、包路径、类型引用关系以及 Spring 这类框架的注解Service、Controller、RepositoryJavaScript/TypeScript 的 import/require 语句外加路径别名如/utils的解析Go 的 import 与包路径引用Python 的 import 语句包括相对导入。除了直接的 importArchify 还会做一层函数级调用分析把入口方法一路追踪下去看它实际调用了哪些业务模块里的方法从而补出那些没有直接 import、但通过框架路由串起来的调用关系。比如 Spring 里 Controller 调 Service、Service 调 Mapper这种关系是理解业务架构的关键静态分析会结合注解和配置一起处理。需要说明的是纯静态分析天然有盲区动态 import、反射调用、SPI 加载、字符串拼接出来的类名这些是它看不见的。后面我会专门讲这些盲区怎么补这里先记住一个结论代码地图的价值是八九不离十 自动更新而不是字节级精确。2.3 第三步模块聚合从类到包再到子系统解析出来的原始关系是类到类级别的数量动辄上千个节点直接画出来没法看。所以 Archify 会做聚合这一步最见功力。它的聚合规则大致有三类。一是目录边界聚合。按包名和目录把类归成模块同一个目录或顶层包里的类默认是一个模块除非内部有明显再分层。二是框架约定聚合。Java 后端里controller、service、mapper/repository是天然的逻辑层聚合之后再分层编排出图时从上到下就是 Controller - Service - DAO 的经典三层。三是行为相关性聚合。两个类虽然不在同一个包但其中一个被另一个高频引用、存在强调用关系算法会把它们拽到一起避免出现两个模块之间几十条交叉引用的混乱局面。聚合之后工具会重新计算模块之间关系权重并顺手完成循环依赖识别A 依赖 B、B 又依赖 A。这类结构在图上会用醒目颜色标出因为它往往是后续重构的重点区域。2.4 第四步布局算法与渲染关系数据算出来了最后一步是把图画出来。这里用的是图布局算法常见的是分层布局layered layout和力导向布局force-directed layout的组合先按逻辑层把模块归到不同泳道再在泳道内部根据依赖权重做力导向排布让关系密的节点挨得近、关系疏的隔得远。真正的 Archify 出图不是一张静态大图而是支持缩放的交互式画布。不同的放大层级看到的粒度不同最上层是服务/子系统视图往下钻一层是模块视图再往下是包视图。你也可以选中一个模块只看它依赖了什么和被谁依赖这就是地图上的高亮街区。渲染完成后可以导出 SVG、PNG 或者 JSON 关系数据方便放进文档或做二次分析。3. 实操把一个真实仓库变成架构图的完整流程3.1 环境准备与仓库接入Archify 的典型使用方式有两种连接远程仓库和扫描本地目录。远程仓库方面目前主流的 GitLab、Gitee、GitHub 都支持接入方式是在设置里添加个人访问令牌Personal Access Token把仓库授权给 Archify。如果你习惯把代码推到 Gitee 管理思路完全一样Gitee 上开一个 token在 Archify 里通过 token 导入仓库之后每次 push 新代码它可以自动触发重新扫描保证图上反映的是最新状态。本地扫描更直接适合不想把代码传给第三方服务的团队。我自己通常先用本地模式做验证# 安装命令行工具不同版本命令略有差异以官方文档为准 npm install -g archify/cli # 进入仓库根目录并初始化 cd ~/projects/order-service archify init # 执行扫描并生成架构图 archify scan . --out ./archify-output如果你是先本地开发再推到 Gitee 的节奏流程也很顺git push推送到远程仓库之后在 Archify 控制台选择该仓库点一次扫描即可。对一个中型仓库来说首次全量扫描通常在几十秒到几分钟之间起手速度确实对得起秒生架构图这个说法。3.2 第一次扫描前的关键配置很多第一次用的人上来就archify scan .然后发现生成的图乱七八糟、什么都看不清。问题多半出在没做配置。Archify 会在初始化时生成一个archify.yml我建议你至少改这几个字段project: name: order-service languages: [java] scan: ignore: - **/test/** - **/target/** - **/generated/** entryPoints: - src/main/java/**/controller/** aggregate: maxNodes: 60 groupBy: [packagePrefix]这里面我最看重ignore。测试代码、构建产物、自动生成的代码对架构分析来说都是噪声不忽略掉它们图里会多出一堆不属于业务架构的节点。maxNodes控制聚合颗粒度节点太多就提高聚合层级节点太少就降低。这个参数值得多试几个值直到图上恰好能一眼看全又不损失关键信息。提示代码地图追求的不是 100% 还原而是主要依赖不遗漏、架构趋势不错位、信息始终新鲜。想通这一点很多边角细节就不会纠结太久。3.3 怎么读懂生成的架构图图生成了怎么读是关键。我习惯按三步走先看分层再看依赖走向最后找异常点。第一步看布局。Java 后端服务呈三层排列很常见最上层 Controller 接 HTTP 请求中间 Service 处理业务下层 Mapper/Repository 访问数据库最下面往往挂着 Redis、MQ、外部 API 这类基础设施节点。如果你发现某个模块明明叫util却被画在顶层说明它被 Controller 直接引用了这里往往藏着分层违规。第二步看依赖走向。从任意模块点进去看出边它依赖谁和入边谁依赖它。入边很多说明它是被大量复用的基础模块出边很多说明它是聚合入口或上帝模块。一个健康的模块依赖数量应当可控出边别超过十个超过就怀疑职责过重。第三步找异常点。循环依赖标红的优先处理孤立节点没有任何依赖关系的模块多半是死代码所有边都指向它一个的模块就是架构上的单点瓶颈。这三类问题手工读代码往往要好几天才能发现一次扫描就全标出来了。3.4 导出与维护出图之后我强烈建议把它当成一等公民来维护。Archify 支持导出 SVG、PNG 和 JSON。SVG 可以保持清晰度嵌进团队 Wiki 或 READMEJSON 关系数据则可以喂给其他分析脚本做二次处理。维护节奏有两种。手动模式每次发布前在 CI 里跑一次archify scan把生成结果和上一次做 diff重点看有没有新增的循环依赖或不合理依赖。自动模式接入远程仓库每次 push 后自动重新扫描架构图永远和主分支同步。实测下来自动模式省心得多。人工维护的架构图活不过三个月自动生成的图才可能真的被团队用起来。4. 翻车现场我用 Archify 踩过的坑和解决办法4.1 扫描慢得像蜗牛先查这三处我试过一个接近上百万行代码的 Java 老仓库第一次扫描跑了快四十分钟一度怀疑工具坏了。排查下来是三个原因叠加一是没有配置 ignore把几个generated-source目录和测试代码全扫进去了这部分占了至少一半时间二是分析器默认开启函数级调用追踪对巨型仓库是很大负担三是没开增量扫描每次都是从零开始全量解析。解决办法对应三条把构建产物、生成代码、测试代码全部加进 ignore函数级追踪只对入口模块开启其余走 import 级别快速分析接入远程仓库后开启仅扫描变更文件模式。调整完之后同样这个仓库的增量扫描压缩到一分钟以内。4.2 依赖爆炸图变成一盘意面另一个常见问题是依赖关系太多图上全是密密麻麻的线节点之间互相交叉完全失去可读性。这通常是聚合参数没调好模块边界切得太细把同一个业务域拆成十几个小模块彼此大量互相引用或者循环依赖太多算法为了把这些循环关系画出来不得不拉出无数条边。解决思路是先合并、再过滤。把maxNodes调小强制模块聚合成更大粒度比如把user-service下的多个包合并成一个user模块线上数量立刻降下来。再开启边权重过滤只显示权重超过阈值的依赖边那些个别的一次性调用不画图上立刻清爽很多。依赖爆炸本身也在说明架构有问题别只顾着调图——它提示你该做模块间解耦了。4.3 多语言仓库和微服务仓库怎么处理现在很多仓库是前后端同仓或多语言混合Java 后端 TypeScript 前端 Python 脚本。Archify 对多语言仓库是逐个语言分别分析再通过共享节点拼到一起。比如同一个 API 路径后端是被调用方、前端是调用方工具会根据接口定义或者手动规则把两边连起来。微服务场景更复杂一点。我的做法是把各服务仓库分别扫描然后导出关系数据在 Archify 里用多仓库聚合视图合并成一张服务级架构图。这张图上的节点是各个服务边是服务间调用。如果服务间用的是 gRPCproto 文件里的 service 定义就是现成的调用关系如果用的是 REST可能需要在配置里维护一份服务间调用清单。聚合视图的价值在于你可以第一次同时看到十几个服务的完整拓扑哪个服务被依赖得最多、哪些服务之间互相调用形成环一目了然。这其实是很多人想要的微服务架构图而且是自动生成、随代码更新的不是发布会前熬夜手绘的静态 PPT。4.4 动态代码造成的误报和漏报前面提到静态分析的盲区实际使用时会真实碰到。最常见的场景一个类不是通过 import 直接引用的而是在配置文件里写死了类名启动时通过反射加载Spring 的Bean动态注册、Java SPI 机制都属于这类。Archify 对这类节点可能会漏导致图上出现失踪的依赖。另一种是相反方向的误报两个类只是名字像或者通过字符串拼接生成类名静态分析把八竿子打不着的两个模块连在了一起图上出现幽灵依赖边。我一般是这么处理的把图当作参考而不是唯一事实遇到反射和动态加载场景在 Archify 里手工补一条白名单依赖或者画一条已知边同时定期用运行时调用链数据比如 APM 里的链路追踪和静态图对照两边一拼盲区就小多了。四种高频问题我整理成了一张速查表排查时可以照着来翻车现象常见原因我优先检查的点扫描极慢未设置 ignore、函数级追踪全开、未开增量ignore 列表、追踪开关、增量扫描依赖爆炸聚合粒度过细、循环依赖过多maxNodes、边权重过滤、模块合并多语言关系断裂各语言独立分析、缺少桥接共享节点配置、手动补边反射/动态加载盲区静态分析看不到运行时行为手工依赖补充、运行时链路对照5. 把代码地图放进团队协作我总结的一套落地方法5.1 新人 onboarding先看图再读代码我后来在团队里定了一条规矩新同学入职、接受仓库讲解之前先花十分钟自己看一遍 Archify 生成的架构图然后回答三个问题系统分成几层核心服务依赖了哪些基础模块它调用了哪些外部依赖答不上来再去看代码。这套流程跑下来效果很直接新人第一次上手改代码的时间从原来的一天半缩短到大约小半天。他们不是不用读代码了而是带着地图去读读到每个类都知道我现在在整条路上的哪个位置而不是打开一个目录就开始猜。5.2 架构评审与重构辅助让问题可视化代码地图最被低估的场景是架构评审。以前评审靠 PPT 和架构师的记忆现在直接打开项目的最新架构图过一遍哪个模块依赖数量超阈值、哪里出现循环依赖、哪些模块没人引用全部在图上现场标注。评审从听人讲变成了看数据说话。重构场景用得更多。我之前负责过一个支付服务老模块的重构重构前先导出一份现状架构图的 JSON 数据重构完成后再导出一份新的两张图做 diff哪些依赖被清掉了、哪些边界变清晰了一目了然。这种重构前后对比图拿给领导和组员看比任何文字汇报都有说服力。5.3 让统计说话代码量和注释率的补充视角代码仓库代码量和注释率统计这类需求其实和代码地图是很好的搭配。光看架构图你能知道模块之间的依赖结构但不知道每个模块的规模和维护状况。我会把两类数据放在一起看某个模块被大量依赖、同时代码行数上万、注释率又很低那它就是整个系统的高危区——所有人都在依赖一个没人读得懂的黑盒。Archify 在导出架构图时通常能顺带带出各模块的代码行数、文件数、注释率这类基础统计。我习惯在架构评审表格里把这三个指标一起列上作为这个模块是否值得优先重构的量化依据。架构问题一旦跟规模数据挂钩优先级排序就容易得多。5.4 与文档、CI 的联动让图活在流程里最后一步是把它焊进日常流程。我的做法很简单在项目 README 顶部放一张最新架构图的链接或 SVG 预览图旁边注明本图由 Archify 自动生成随 CI 自动更新在 CI 脚本里加一步archify scan把生成的图作为构建产物上传到内部文档系统代码评审模板里加一条 checkbox本次改动涉及模块的依赖关系是否合理是否存在新增循环依赖。这套闭环跑起来之后架构图过期这件事基本消失了。因为图的更新是自动的旧图没有机会存在。团队对系统整体长什么样的认知第一次真正意义上跟上了代码演进的节奏。这也是我理解中代码地图类工具最大的价值它把架构这个原本靠人脑维护的东西变成了和 CI 一样可靠的自动化资产。最后再分享一个小技巧新项目从第一天就用 Archify体验比老项目半路接入好太多。老项目扫描出来的第一版地图往往千疮百孔容易打击信心新项目或刚做完大重构的项目代码结构还规整首图就很漂亮大家看了有成就感也更容易把看图说话的习惯坚持下去。如果你也是团队里那个经常被人问这个东西在哪改的人建议先拿自己手里最大的那个仓库跑一次扫描看看 Archify 画出来的第一张图跟你脑子里对系统的印象差了多少——这个差距就是团队里每个人每天都在付出的沟通成本。