不该用的代码生成器

Categories:

在十几年前我还在上大学学编程的时候,就已经诞生了各种各样的代码生成器。

现在2023年了,各种代码生成器依然大行其道。

读取数据库表结构并生成相应的Entity、Mapper、Service、Controller。

为什么我标题说不该用呢?

主要的点在于,我认为生成Service和Controller是不该的、错误的。

三大弊端

重复冗余代码

生成Entity和Mapper的过程显然是重复、枯燥的,所以造出个代码生成器显然是没有问题。

Entity的代码本身也不可能是重复的,但是Controller、Service显然是同样的模板生成出来的,

按照我们平时优化代码的习惯,相似的代码不就该将变化的部分提取成变量/方法抽象封装一层吗?

既然都能模板化,为什么不能在运行时用占位符动态计算呢?

举例,一堆的雷同Controller

@RestController
@RequestMapping("/users")
public class UserController {

    private UserService userService;
    
    @GetMapping("/")
    public List<User> list(){
        return userService.list();
    }
    
    @GetMapping("/{id}")
    public User get(@PathVariable("id") String id){
        return userService.findById(id);
    }
}

@RestController
@RequestMapping("/roles")
public class RoleController {

    private RoleService roleService;

    @GetMapping("/")
    public List<Role> list(){
        return roleService.list();
    }

    @GetMapping("/{id}")
    public Role get(@PathVariable("id") String id){
        return roleService.findById(id);
    }
}

上面这种重复雷同的代码,为什么不能直接用BaseController的形式,通过通配符+泛型来代替?

@RestController
public class BaseController {
    
    @GetMapping("/{entity}")
    public List list(@PathVariable("entity") String entity){
        BaseService baseService = findService(entity);
        return baseService.list();
    }

    @GetMapping("/{entity}/{id}")
    public Object get(@PathVariable("entity") String entity, @PathVariable("id") String id){
        BaseService baseService = findService(entity);
        return baseService.findById(id);
    }
}

其实Spring就已经有了 Spring Data Rest,根本就不需要用代码生成器造一堆重复的代码出来。

程序是用来解决重复劳动的,不是用来制造重复代码的。

而代码生成器生成的Controller、Service就是这样一堆重复代码。

业务抽象与技术抽象的混淆

Controller是业务的抽象,Entity是技术的抽象,而Service是两者的转换区。

举个例子,用户将雪碧、可乐两件商品加入购物车,点击下单,那么Controller应该有个下单接口。

在数据库设计上,可能你会设计一个订单表Order和订单商品表OrderItem,这是技术的设计。

至于Service,干的就是按订单规则生成订单号、将数据存到Order和OrderItem表,可能还有优惠计算、积分累计、后续的付款单号生成等逻辑。

这是从业务需求到技术设计的一般流程。

而如果你用代码生成器,因为有Order表和OrderItem表所以不管三七二十一就生成了OrderController、OrderItemController、 OrderService、OrderItemService,这难道不是一件很奇怪的事吗?

再比如,你用的就不是MySQL这种关系型数据库,而是MongoDB这种非关系型文档数据库, 你可能就不会建Order和OrderItem两个表,而是直接在Order里加个items字段存数据。

在这种情况下,你绝对只会建一个OrderController、一个OrderService吧?

不会有OrderItemController、OrderItemService了。

这时问题来了,相同的业务需求,你有多少个Controller、多少个Service取决于你建了多少表?

显然你这不是面向业务编程,而是面向数据库编程了。

Service与Dao的界限

很多人分不清Service与Dao的边界,原因也就在于此。太多无用的Controller和Service了。

很多人都写出 aService调用bService再由bService调用bDao 这样的代码。

这里也请移步查看我的另一篇文章aService直接调用bDao合适吗?

如果你觉得本文对你有帮助或不错,可略表心意,请我喝一杯冰可乐。

Comments