1. 接手老项目后,模板代码是那根最扎手的刺
今年年初我接手了一个已经运行三年的CRM客户管理系统,系统不算大,但代码量将近二十万行。刚开始一周我还在按部就班地看业务逻辑,越往后越觉得不对劲:这个项目的模板代码怎么这么多,而且每一处都透着一股“能跑就行”的味道。
举几个我实在忍不了的例子。前端列表页里有一大段模板字符串,用+拼接出一整块HTML,变量名是x、d、tmp,中间还夹着几个三元运算符。后端邮件模块更夸张,一个模板文件里堆了四十多个${xxx}占位符,很多占位符在哪一层数据里根本看不出来,偶尔还会出现同一个字段被拼错的情况。更别提代码生成器生成的那些样板文件,光读一遍就要消耗不少耐心。
那段时间我每天花大量时间在“找代码”上:要改一个按钮的样式,得先在模板字符串里数第几个三元表达式是控制按钮颜色;要调整邮件内容,得先对着后端返回的JSON一层一层扒数据对应的字段。终于在第N次被模板代码坑了之后,我决定停下来做一次系统性的可读性改造。这篇文章就是这次改造的复盘记录,内容覆盖我踩过的坑、提炼出的方法论,以及几个不同场景下的具体改法。不管你是写前端模板、后端模板引擎、类模板还是代码生成器模板,我相信都有参考价值。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 顺着不可读的模板代码,挖出四个根因
动手改造之前,我先做了一件事:把这几十处“不舒服”的模板代码全部列出来,逐段问自己“为什么读起来这么费力”。我发现它们的问题可以归为四类,而且这四类问题在很多项目里都是同时出现的,并不是某一种代码风格导致。
2.1 模板里塞满了逻辑,模板语言本身却撑不起复杂度
模板代码最典型的失控方式,就是把本该在服务端或组件逻辑里完成的判断、循环、字段格式化统统塞进模板里。
我见过最夸张的一段前端模板字符串,里面包含了两层map、三个条件判断、外加一串}`拼接出来的列表项。能跑吗?能跑。但任何人想快速看出来“什么条件下列表显示什么样式”,都要花上小半天把表达式拆开再心算一遍。模板语言(不管是JS模板字符串、Thymeleaf还是FreeMarker)本质上是为“展示结构”设计的,它的表达能力和调试手段远不如完整编程语言。一旦把复杂业务逻辑压进去,可读性崩塌是必然的。
2.2 命名碎片化,模板成了“语义黑洞”
模板里出现的临时变量和占位符,往往是整个项目里命名质量最差的一批。因为写模板的人心里想的是“反正就是输出一段文本”,于是data、item、obj、tmp满天飞。更隐蔽的是,来自后端接口的字段名经常是缩写和拼音混合,比如custNm、xfDate,模板里直接引用,不查接口文档根本不知道含义。
命名问题的本质不是“不够文艺”,而是丢失了上下文。模板是数据和界面之间的桥梁,桥上没有路标,过桥的人自然迷路。
2.3 作用域不透明,变量出处全凭猜
一个模板文件越是复杂,你越难回答“这个变量到底从哪来”。以Thymeleaf页面为例,如果页面上用了${user.name},你可能需要翻三层Controller、Service才知道user是从Session里取还是从Model里塞的。模板引擎的上下文传递本身没有显式的类型声明,IDE也无法像普通Java代码一样帮你追寻引用。
有次我为了找邮件模板里一个${createDate}的赋值链路,从模板搜到工具类,再搜到定时任务,最后发现是另一个模板中的同名变量被缓存上下文带入的。这种隐式依赖让人相当崩溃。
2.4 缺少统一的“文体规范”,每个人写的模板风格都不一样
同一个项目里,A同事写的模板是缩进两格的HTML风格,B同事喜欢把字符串拆成五行然后串联,C同事坚持用模板引擎自带的宏。这些风格上的差异平时无伤大雅,可一旦合并到同一个文件、同一次迭代中,读起来就像在看一本每换一页就换一种口吻的翻译小说。
我把这四个根因写在便利贴上贴在显示器旁边。后续所有改造动作,最终都落在“减少逻辑”“修复命名”“显式作用域”“统一风格”这四句话上。
3. 可读性改造的三个层级:命名、结构、工具约束
理清根因后,我意识到“提升可读性
