我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

SaaS平台CRUD代码生成:薄生成厚扩展与可审计实践

SaaS平台CRUD代码生成:薄生成厚扩展与可审计实践 1. 为什么SaaS平台离不开一个能持续跑的CRUD底座1.1 交付节奏被重复劳动拖慢的真实场景做过SaaS项目的人大概都有这样的体验一个中等规模的业务系统真正决定交付周期的往往不是那些花哨的核心算法而是一堆结构相似、字段不同、接口几乎一样的基础管理模块。用户管理、角色管理、字典管理、配置管理、公告管理、日志管理这些模块的代码骨架高度雷同写起来枯燥改起来更烦。我在某团队做交付支持时统计过一版数据一个标准后台系统里与CRUD直接相关的代码量占到总代码量的六成以上而其中真正包含差异化业务逻辑的部分不到三成。问题不在于CRUD本身简单而在于它必须批量地、规范地、可维护地存在。一个新人接手项目打开代码仓库看到二十个风格迥异的Controller命名一会儿是getUserList一会儿是queryAllUsers返回结构一会儿是裸数组一会儿是包了三层的Result对象这种项目后续的维护成本会成倍上升。更麻烦的是每次加一个新表就要重新复制一遍分页逻辑、参数校验、异常处理、审计字段填充复制过程中稍有疏忽就漏掉一处等到线上出问题再回头补付出的代价远高于一开始就统一。这也是为什么很多团队在做SaaS平台时会认真考虑引入代码生成工具。不是因为懒而是因为重复劳动的边际收益递减得太快而规范漂移的边际成本递增得太快。谷雨代码生成工具在这个背景下进入视野它的定位很明确把标准CRUD这类结构确定、规范统一、变更频繁的部分交给生成器把人的精力留给真正需要判断的业务逻辑。1.2 规范漂移的隐性成本规范这件事写在文档里是一回事落到代码里是另一回事。我见过不少团队开发规范文档写得非常完整命名约定、分层结构、异常码、返回体格式都有明确规定但实际代码里依然会出现各种变体。原因很简单规范靠人自觉执行而人在赶工期的时候最容易妥协。规范漂移带来的成本是隐性的短期看不出来长期会集中爆发。举几个具体的例子返回体格式不统一前端要针对每个接口写不同的解析逻辑联调时间被拉长分页参数命名不一致有的用page和size有的用pageNum和pageSize封装通用表格组件时就得做兼容层审计字段有的表有create_time有的叫created_at做数据归档和审计查询时就得写一堆特判。这些零碎的问题单看都不大叠加起来就是持续交付路上的减速带。代码生成工具的价值在这里体现得很直接规范不再依赖人的记性而是固化在模板里。生成出来的代码天然遵循同一套约定新人不需要背规范文档看两份生成物就能明白项目长什么样。这一点对SaaS平台尤其重要因为SaaS的特点是多租户、多模块、长期迭代代码风格的一致性直接决定了后续扩展的难易程度。1.3 代码生成工具在交付链路里的位置需要说清楚一个认知代码生成工具不是银弹它解决的是结构性重复问题不解决业务复杂度问题。把它放在交付链路里看它的位置大概在需求拆解和数据建模之后、业务逻辑开发之前。也就是说先用它把骨架搭起来让项目能跑通、能联调、能演示然后再在骨架上填业务的血肉。这个定位决定了工具的设计取向。如果生成器试图把业务逻辑也一起生成那它必然要理解业务语义复杂度会失控如果生成器只生成最基础的骨架把扩展点留清楚那它就能保持轻量和稳定。谷雨工具走的是后一条路后面几节会详细展开。我先给一个结论一个能长期用的代码生成工具衡量标准不是生成得多而是生成得稳、改得动、退得回。这三点分别对应模板稳定性、扩展机制和覆盖防护缺一个都会让工具从助力变成负担。2. 谷雨工具的设计取向薄生成、厚扩展2.1 模板驱动和元数据驱动的取舍代码生成工具有两条常见路线。一条是模板驱动开发者写好模板文件生成器把变量填进去渲染出代码另一条是元数据驱动开发者描述数据模型和约束生成器根据内置规则推导出完整产物。两条路线各有适用场景实际项目里往往是混合使用。模板驱动的优势是灵活想生成什么就写什么模板缺点是模板质量完全取决于写模板的人模板一多维护成本就上来了而且模板里的逻辑分支容易写得越来越复杂。元数据驱动的优势是统一字段类型、约束、索引这些信息描述一次生成器自动推导出实体类、Mapper、Service、Controller、DTO、查询参数对象缺点是灵活性受限遇到特殊需求要额外开扩展口。谷雨工具的做法是元数据为主、模板为辅。数据模型定义是唯一的事实来源字段名、类型、长度、是否可空、是否索引、注释这些信息集中描述模板只负责把推导结果渲染成目标语言的结构模板里不写业务判断。这么设计的理由很实际元数据是业务语义的自然表达改一个字段的可空性所有相关产物应该同步变化而模板里如果掺杂业务判断改一处逻辑就得改多个模板很快会失控。我用生活化的方式打个比方元数据像是菜谱上写的食材和用量模板像是固定的烹饪流程。食材换了流程不变出来的菜结构还是一样的。如果流程里写死了如果放牛肉就多炒两分钟那流程本身就成了业务逻辑后面加新食材就得改流程越改越乱。2.2 生成物与手写代码的边界这是代码生成工具最容易踩坑的地方。很多工具一开始很受欢迎用了半年就被团队弃用原因往往是生成物和手写代码混在一起再生成一次就把手写的东西覆盖了或者手写代码依赖了生成物的内部结构生成物一升级就全线报错。谷雨工具在边界划分上做了三件事。第一生成目录和手写目录物理隔离生成物统一落在generated包下手写代码放在business包下构建时两者一起编译但目录结构上泾渭分明。第二生成物里的扩展点用继承或组合的方式预留比如生成的Service是一个基础实现类业务侧继承它并覆写需要定制的方法而不是直接改生成文件。第三生成器带覆盖检测执行前会对比目标文件与上次生成记录的哈希发现被手工修改过就中止并提示避免误覆盖。这套边界设计带来的直接好处是生成器可以放心升级模板因为手写代码不依赖生成物的内部实现细节反过来手写代码里发现的问题也可以反哺模板把通用改进沉淀下来下次生成自动生效。这是一个正向循环也是可持续三个字的具体落地。2.3 为什么不做一键生成整个系统有些工具宣传的时候喜欢说一键生成整个后台听起来很吸引人实际用起来往往是灾难。原因在于一个完整系统里包含大量业务判断这些判断没法从数据模型里推导出来。强行生成的结果是一堆看起来能用、实际处处要改的代码改的成本比从零写还高因为你还得先读懂生成器的心智模型。谷雨工具明确不做这件事它的目标范围就是单表的标准化CRUD加上必要的查询能力。具体来说生成的内容包括实体类、数据访问层、服务层基础实现、控制器、请求参数对象、响应视图对象、基础校验注解、分页查询封装。这些内容的共同特征是结构确定、规范统一、变更多为字段级调整。至于复杂的业务编排、跨表事务、状态机流转一律不碰留给开发者。这个取舍看起来保守实际上是负责任的做法。工具的边界清晰使用者对它的预期就清晰不会出现以为它能干结果干不了的落差。我在实际项目里见过反面案例某团队引入了一个功能很全的生成器结果生成出来的代码有七成需要手工调整调整过程中又引入了新的不一致最后整个项目变成生成物和手写代码的混合体谁也不敢动。工具的克制恰恰是它可长期使用的前提。3. 3分钟生成一套规范CRUD的实操记录3.1 环境准备与目录约定先说我实际跑通的环境。JDK 17、Maven 3.9、Spring Boot 3.x、MyBatis-Plus 作为数据访问层数据库用MySQL 8。谷雨工具以Maven插件的形式引入好处是不依赖额外的运行时环境跟着构建走团队成员拉下代码就能用。目录约定这块建议提前定好不要等生成了一堆文件再回头整理。我的习惯是这样project-root ├── src/main/java │ ├── com.example.demo │ │ ├── generated # 生成物禁止手工修改 │ │ │ ├── entity │ │ │ ├── mapper │ │ │ ├── service │ │ │ ├── controller │ │ │ └── model │ │ ├── business # 手写业务代码 │ │ └── common # 公共组件 ├── src/main/resources │ ├── generator # 生成器配置与模板 │ └── mapper # XML映射文件插件配置大概长这样核心是数据源、包名、输出路径、作者信息几项plugin groupIdcom.example/groupId artifactIdguyu-generator-maven-plugin/artifactId version1.4.0/version configuration jdbcUrljdbc:mysql://localhost:3306/demo/jdbcUrl usernamedev/username passworddev_pass/password basePackagecom.example.demo/basePackage outputDirsrc/main/java/outputDir generatedPackagegenerated/generatedPackage authorteam/author enableSwaggertrue/enableSwagger enableValidationtrue/enableValidation /configuration /plugin注意数据库账号建议单独建一个只读账号给生成器用不要图省事用业务主账号。生成器只需要读表结构不需要写权限权限收窄是基本的安全习惯。3.2 数据模型定义的写法谷雨工具的元数据来源有两块一是数据库里已有的表结构二是配置文件里补充的业务语义。表结构能提供字段名、类型、长度、可空性、索引但提供不了这个字段在列表页展示、那个字段只在详情页展示这类信息所以需要补充配置。补充配置我一般写在generator/model.yaml里格式如下tables: - name: t_order comment: 订单表 fields: - name: order_no comment: 订单编号 queryType: eq # 精确查询 listVisible: true - name: customer_name comment: 客户名称 queryType: like # 模糊查询 listVisible: true - name: amount comment: 订单金额 queryType: range # 区间查询 listVisible: true - name: status comment: 订单状态 queryType: in listVisible: true dictCode: order_status # 关联字典 - name: remark comment: 备注 listVisible: false这里有几个我踩过坑的点。queryType这个字段很关键它决定了查询参数对象里生成什么样的字段和什么样的查询条件构造逻辑。如果不配生成器默认按精确匹配处理模糊搜索就得手工加加的时候又容易破坏统一的查询封装。listVisible控制列表页返回哪些字段不配的话默认全返回遇到大文本字段比如详情、富文本会把列表接口的响应体撑得很大实测下来一个列表接口返回两百条记录、每条带一个几KB的备注字段响应时间能翻好几倍。字典码dictCode是我很推荐的一个配置项。SaaS平台里状态类字段特别多订单状态、支付状态、审核状态如果每个模块自己维护一套枚举前端就得维护多套映射。配置了字典码之后生成器会自动在响应视图对象里加上状态描述字段前端直接展示不需要再写一遍映射逻辑。这个细节看起来小实际项目里能省掉大量重复沟通。3.3 执行生成与产物解读配置完成后执行一条命令mvn guyu:generate -Dtablet_order三分钟之内generated目录下会多出七个文件。我逐个说明它们的作用和设计意图。实体类OrderEntity对应表结构字段类型自动映射create_time和update_time这类审计字段会自动标注填充策略避免每次插入都要手工赋值。数据访问层OrderMapper继承通用的基础Mapper自带单表增删改查和条件构造能力只有复杂查询才需要写XML。服务层OrderService和实现类OrderServiceImpl提供基础CRUD方法方法签名统一为create、update、remove、getById、page。控制器OrderController暴露标准REST接口路径按/api/order约定方法上带参数校验注解和接口文档注解。请求参数对象OrderQuery是查询条件的载体包含了配置里定义的查询字段内部封装了区间查询、集合查询的逻辑调用方只需要赋值。响应视图对象OrderVO是列表和详情返回的结构包含了字典描述字段。还有一个OrderConvert负责实体和视图对象之间的转换把映射逻辑集中在一处。实操心得生成完先别急着写业务花十分钟把生成物从头到尾读一遍。一方面确认字段映射是否符合预期另一方面熟悉这套代码的风格后面手写业务代码时保持同样的写法整个项目的一致性会好很多。3.4 生成之后的扩展入口生成物是骨架业务逻辑要从扩展入口进去。谷雨工具预留的扩展方式是继承加覆写。比如订单创建时需要校验库存、计算优惠、生成流水号这些逻辑写在业务侧的服务类里Service public class OrderBizService extends OrderServiceImpl { Override public Long create(OrderCreateDTO dto) { checkStock(dto); String orderNo generateOrderNo(); dto.setOrderNo(orderNo); Long id super.create(dto); writeOrderLog(id, dto); return id; } }控制器侧同理如果某个接口需要额外的权限校验或者特殊的参数处理继承生成的控制器覆写对应方法即可。这种继承关系的好处是生成物升级时新增的方法会自动被业务类继承不需要手工同步而业务类覆写的方法保持稳定不受影响。这里要提醒一个设计上的细节生成的基础方法签名要尽量稳定不要频繁变动。我在早期版本里犯过一个错把create方法的返回值从void改成了主键ID结果所有覆写了这个方法的下游业务类全部编译报错。后来定了个规矩生成物的公开方法签名视为契约变更需要走版本号破坏性变更只在大版本里做小版本只加不改。这个规矩看起来是流程问题实际是工具能否被信任的关键。4. 让生成物像人写的规范落地的关键细节4.1 命名与分层规范生成物最容易被人诟病的一点是一眼看出是机器生成的代码能跑但读起来别扭。这个问题多半出在命名和分层上。谷雨工具在这块做了几层处理我觉得值得借鉴。命名方面表名到类名的转换有一套固定规则去掉表前缀比如t_、sys_下划线转驼峰单复数统一。t_order_item生成OrderItem而不是TOrderItem或者OrderItems。字段名到属性名的转换同理customer_name转customerName。这些规则写在配置里团队可以按自己的习惯调整但一旦定下来就全局统一。分层方面生成物严格遵循四层结构每层的职责边界清晰控制器只做参数接收和结果返回不写业务判断服务层承载业务编排数据访问层只管数据读写模型层负责数据结构定义。这个分层不新鲜但关键在于生成器强制执行不给图省事在控制器里直接调Mapper留口子。我在实际项目里见过太多控制器里写几十行业务逻辑的代码后期要加事务、加缓存、加权限全得重构。分层规范靠人守不住靠工具守才守得住。还有一个细节是注释。生成物的类注释、方法注释、字段注释全部从元数据里带出来表注释变成类注释字段注释变成属性注释。这一点对SaaS平台特别有价值因为SaaS的字段经常随客户需求调整注释跟着元数据走就不会出现代码改了注释没改的情况。数据库里的字段注释写清楚生成的代码注释就清楚前后端对接的时候少扯很多皮。4.2 查询接口的通用参数设计列表查询是CRUD里使用频率最高的接口也是最容易写乱的接口。不同开发者写出来的查询参数五花八门前端对接成本高。谷雨工具生成的查询参数对象采用统一的设计核心参数如下表所示参数名类型默认值说明pageNumInteger1页码从1开始pageSizeInteger20每页条数上限500orderByString空排序字段白名单校验orderDirectionStringasc排序方向只允许asc/desckeywordString空全局模糊搜索关键词这套参数的设计有几个考量。分页参数用pageNum和pageSize而不是page和size是因为前者语义更明确不容易和业务字段混淆。pageSize设上限500是防止有人传个一万进来把数据库拖垮这个上限在参数校验里强制执行。排序字段走白名单只允许配置里声明过的字段参与排序避免SQL注入风险这个点在安全审计时经常被问到。keyword这个全局搜索参数是我个人很推荐的设计。它对应多个字段的模糊匹配生成器会根据listVisible为true的文本字段自动拼出OR条件。比如订单列表的全局搜索会同时匹配订单编号和客户名称。这个参数的存在让前端只需要一个搜索框就能覆盖大部分场景交互简洁后端实现也统一。当然涉及大表的全局模糊搜索要注意索引问题我的做法是只对建立了索引的字段开放全局搜索其他字段走独立的条件查询。4.3 审计字段、权限与软删除的自动注入SaaS平台有几个通用能力每个模块都需要但每个模块单独实现又很啰嗦。谷雨工具把这些能力做成了生成时的自动注入。审计字段方面create_by、create_time、update_by、update_time四个字段由框架统一填充业务代码里不需要出现任何赋值语句。实现方式是在数据访问层加拦截器插入时填充创建信息更新时填充更新信息。这么做的好处是审计信息的准确性有保障不会因为某个开发者忘了赋值而出现空值。权限方面生成的控制器方法上会带上权限注解权限码按模块:操作的格式自动生成比如order:create、order:delete。权限码统一之后权限配置界面可以直接从注解里扫描出来不需要手工录入。这个设计在SaaS场景下价值很大因为SaaS的权限往往是按租户配置的权限码如果散落在各处配置和维护都会很混乱。软删除方面生成的删除方法默认是逻辑删除把deleted字段置为1查询时自动过滤。这里有个坑要提醒逻辑删除和唯一索引会冲突。比如订单编号设了唯一索引删掉一条记录后再用同样的编号新建会违反唯一约束。我的处理方式是把唯一索引改成(order_no, deleted)的联合唯一索引删除时deleted置为记录ID而不是1这样多次删除也不会冲突。这个细节在生成器里做了默认处理但团队最好知道背后的原因遇到问题时能自己判断。4.4 多租户隔离的处理多租户是SaaS平台绕不开的话题也是代码生成工具必须考虑的横切关注点。谷雨工具的处理方式是在元数据里标记租户字段默认tenant_id生成时自动在数据访问层加上租户过滤条件业务代码里完全不需要感知。具体实现是在查询构造和数据操作时统一追加tenant_id 当前租户的条件租户ID从上下文里取。插入时自动填充租户ID更新和删除时校验租户归属防止越权操作。这套机制对业务开发者是透明的写查询的时候不需要考虑租户框架兜底。注意多租户隔离一定要在数据访问层做不要在控制器或者服务层做。放在上层意味着每个方法都要记得加条件迟早会漏。放在数据访问层是最后一道防线漏不掉。另外涉及跨租户的统计查询要单独开白名单走专门的接口不要在主查询里开口子。还有一个容易被忽略的点租户隔离要和缓存、消息、文件存储一起考虑。生成器管的是数据库层其他层的隔离需要配套的组件支持。我的建议是在项目初期就把租户上下文做成一个统一的ThreadLocal所有需要租户信息的地方都从这里取生成器生成的代码也依赖这个上下文保持一致。5. AI时代的合规考量可审计的代码生产5.1 AI辅助编程带来的新变量这两年AI辅助编程工具普及得很快写代码的效率确实提升了但同时也带来了新的问题。AI生成的代码风格不统一同一个项目里能看到好几种写法AI有时会引入不存在的依赖或者过时的API代码能跑但存在隐患更麻烦的是AI生成的代码往往缺少上下文开发者自己也说不清这段逻辑为什么这么写后期维护时无从下手。对于SaaS平台来说这些问题会被放大。SaaS的特点是长期迭代、多人协作、多租户共用一套代码任何一处不一致都可能在后续扩展时变成障碍。我在某项目里就遇到过这样的情况团队成员用AI辅助生成了几个模块短期内功能都正常但半年后要做统一的权限改造时发现这几个模块的鉴权逻辑各写各的改造工作量比重新写还大。这不是说AI辅助编程不好而是说AI生成的代码需要有一个统一的收敛机制。代码生成工具在这里扮演的角色就是把结构性的部分从AI手里接管过来让AI专注于那些真正需要判断的逻辑。基础CRUD这种结构确定的部分用模板生成比用AI生成更可控因为模板是确定的、可审计的、可版本管理的。5.2 模板统一带来的可审计收益合规这个词听起来很宏大落到代码层面其实很具体能不能说清楚每一行代码是怎么来的能不能在出问题时快速定位能不能在审计时提供完整的证据链。模板生成的代码在这三点上有天然优势。先说来源清晰。生成物的每一行都来自模板加元数据模板是版本管理的元数据是配置管理的任何一个生成物的内容都可以通过模板版本加元数据快照完整复现。这意味着如果哪天发现某个模块有安全问题可以快速判断影响范围是模板的问题还是元数据的问题模板的哪个版本引入的哪些表受影响了。这个追溯能力在AI生成代码的场景下是很难做到的因为AI的输出具有不确定性同样的输入不一定得到同样的输出。再说定位效率。规范统一的代码在排查问题时效率高很多。分页逻辑只有一份实现出问题改一处权限校验只有一种写法漏校验的情况一眼能看出来审计字段的填充机制是统一的数据异常时排查路径是确定的。这些在规范漂移的项目里都是奢望每个模块都要单独看一遍。最后说审计证据。现在很多企业对软件交付有合规要求需要提供代码来源、变更记录、评审记录。模板生成的代码在变更记录上是清晰的元数据改了什么、模板改了什么、生成了哪些文件都有记录可查。这比某个开发者用AI生成了一段代码然后手工调整要容易审计得多。5.3 生成日志与变更追溯谷雨工具在执行生成时会产出一份生成日志记录本次生成的时间、操作人、涉及的表、生成的文件列表、每个文件的哈希值。这份日志我建议纳入版本管理和代码一起提交。它的作用在几个场景下会体现出来。场景一怀疑某个文件被手工改过。对比当前文件哈希和日志里的哈希不一致就说明被改过。这个检测在再生成之前自动执行发现不一致会中止并提示避免覆盖。场景二排查某个字段是什么时候加的。翻生成日志找到对应表的生成记录看元数据的变更历史一目了然。这比翻Git提交记录要直观因为Git记录的是文件变更生成日志记录的是模型变更。场景三新人接手项目。让他看一遍生成日志就能明白哪些模块是生成的、生成时用了什么配置、哪些是手写的。这个信息在项目交接时价值很高能省掉大量沟通。# 生成日志示例简化 [2024-06-12 10:23:41] tablet_order operatordev generated: OrderEntity.java (sha256: a1b2...) generated: OrderMapper.java (sha256: c3d4...) generated: OrderService.java (sha256: e5f6...) generated: OrderController.java (sha256: g7h8...) meta: model.yamlv3 fields[order_no,customer_name,amount,status,remark]实操心得生成日志不要只放在本地纳入版本管理。我见过团队因为日志丢失再生成时无法判断文件是否被改过只能全部覆盖结果把手工调整的逻辑冲掉了。这个坑踩一次就够记一辈子。6. 常见问题与排查实录6.1 表结构变更后的再生成表结构变更是常态加字段、改类型、加索引每次变更都要考虑再生成的影响。谷雨工具的处理逻辑是增量更新新增的字段会生成对应的属性和映射删除的字段会从生成物里移除修改的字段会更新类型和注释。听起来很顺但实际用起来有几个点要注意。第一字段删除要谨慎。生成物里删掉一个字段手写业务代码里如果还引用了这个字段会编译报错。我的做法是先改元数据把字段标记为废弃生成时保留属性但标注Deprecated观察一个迭代周期确认没有引用后再真正删除。这个流程看起来慢但比线上出问题快。第二字段类型变更要检查数据兼容性。比如amount从int改成decimal生成物里的类型会跟着变但数据库里的历史数据如果精度不够转换时可能丢精度。我的做法是类型变更前先跑一遍数据检查脚本确认现有数据能安全转换再执行变更。第三索引变更不影响生成物但影响查询性能。加索引之后要确认生成的查询条件能用上索引特别是复合索引的字段顺序要匹配查询条件的顺序。这个点生成器管不了得靠人看执行计划。6.2 手写代码被覆盖的防护这个问题在团队协作场景下最容易出现。某个开发者不知道生成物的规矩直接改了generated目录下的文件下次别人再生成时就被覆盖了改的东西没了排查半天才发现原因。防护措施有三层。第一层是目录约定加注释警告生成物的每个文件头部都有此文件由生成器生成请勿手工修改的注释醒目位置标明扩展方式。第二层是生成前哈希校验发现文件被改过就中止并列出被改的文件让人确认是回滚还是跳过。第三层是CI检查构建时校验生成物与元数据是否一致不一致就阻断合并。三层防护下来基本不会出现误覆盖。但也要留一个口子确实需要在生成物里加东西的时候走元数据或者模板的扩展机制而不是直接改文件。我在团队里定的规矩是改生成物必须同时改元数据或模板否则代码评审不通过。规矩执行一段时间后大家都形成了习惯。6.3 类型映射与分页失效的排查表实际使用中遇到的问题我整理了一张速查表覆盖最常见的几类现象可能原因排查方法解决方式生成的属性类型不对数据库类型与映射规则不匹配查生成器类型映射配置补充自定义映射规则分页查询返回全量数据分页插件未生效或参数未传递看SQL日志是否带limit检查插件配置和参数名模糊查询查不到数据字符集不一致或未加通配符直接执行SQL验证统一字符集检查拼接逻辑逻辑删除后数据仍可查到查询未经过拦截器检查是否走了自定义SQL自定义SQL手工加过滤条件租户隔离失效上下文未设置或异步线程丢失打日志看租户ID异步场景手工传递上下文字典描述为空字典码未配置或字典表无数据查字典表对应记录补字典数据或修正字典码这张表里的每一条都是我在实际项目里遇到过的。分页失效那条特别常见原因往往是参数名不一致前端传page后端接pageNum插件拿不到分页参数就走了全量查询。这种问题在联调阶段发现还好上线后发现就是性能事故。租户隔离失效那条更隐蔽同步调用正常异步线程里上下文丢了查出来的数据跨租户这种问题不打个日志根本发现不了。7. 我在实际项目里的几点体会这套工具用下来最大的感受是代码生成的价值不在于省了多少行代码而在于把确定性沉淀下来了。哪些东西是确定的就交给工具哪些东西需要判断就留给人。这个边界划清楚之后团队的协作效率提升是实实在在的新人上手快代码评审的焦点从格式对不对转移到逻辑对不对这才是评审该有的样子。还有一个体会是关于克制。工具的功能越加越多维护成本就越高使用者理解成本也越高。谷雨工具目前的能力范围控制得比较窄就是标准CRUD加必要的查询能力复杂的东西一概不碰。这个克制让它在项目里活了很久没有变成那种引入时很热闹、半年后没人用的工具。我见过太多大而全的框架最后被团队抛弃原因往往不是能力不够而是太重了重到大家不愿意学。最后分享一个实操中的小技巧每次生成之后花五分钟把生成物和上一次的生成物做个diff看看模板或者元数据的变更带来了什么影响。这个习惯帮我提前发现过好几次问题比如某次改模板不小心影响了一个不该影响的字段diff里一眼就看出来了。如果等到运行时才发现排查成本会高很多。工具是死的用工具的人是活的多看一眼总没错。
返回列表