11 | 依赖混乱:你可能还没发现问题,代码就已经无法挽救了
郑晔
你好,我是郑晔。
我们前面已经讲了许多坏味道,无论是你很容易接受的,还是挑战你编程习惯的,它们都有相对直观的表现形式,属于你很容易一下子就看出来问题的。这一讲,我们要讲的坏味道就不属于一下子就能看出来的,需要你稍微仔细一点看代码才会发现问题,那就是依赖关系。
我前面在讲“大类”这个坏味道的时候曾经说过,为了避免同时面对所有细节,我们需要把程序进行拆分,分解成一个又一个的小模块。但随之而来的问题就是,我们需要把这些拆分出来的模块按照一定的规则重新组装在一起,这就是依赖的缘起。
一个模块要依赖另外一个模块完成完整的业务功能,而到底怎么去依赖,这里就很容易产生问题。
缺少防腐层
我们还是先来看一段代码:
这段代码是创建一部作品的入口,也就是说,它提供了一个 REST 服务,只要我们对 /books 这个地址发出一个 POST 请求,就可以创建一部作品出来。那么,这段代码有问题吗?
按照一般代码的分层逻辑,一个 Resource (有的团队称之为 Controller)调用一个 Service,这符合大多数人的编程习惯,所以看起来,这段代码简直是正常得不能再正常了,这能有什么问题?
从 Resource 调用 Service,这几乎是行业里的标准做法,是没有问题的,但问题出在传递的参数上。请问,这个 NewBookRequest 的参数类应该属于哪一层,是 resource 层,还是 service 层呢?
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了软件开发中常见的依赖混乱问题,并提出了解决方案。通过具体的代码示例,作者指出了依赖关系不清晰可能导致的问题,以及如何通过引入新的模型来解决这些问题。文章强调了在设计中构建防腐层的重要性,以隔离不同层次的责任,避免混乱和重复。作者还介绍了一些工具,如ArchUnit,可以帮助程序员在写代码时保证依赖关系的稳定性。总之,本文通过深入浅出的方式,帮助技术人员更好地理解和解决依赖混乱问题,为他们提供了有益的技术指导。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《代码之丑》,新⼈⾸单¥59
《代码之丑》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(17)
- 最新
- 精选
- qinsi对照DDD,是否可以理解为接口层接收DTO,转换为DO后传入业务层?那么缺少防腐层的问题也可能发生在业务层和持久化层之间,比如业务层直接操作持久化对象(PO)? 相比把DTO当成DO用,把PO当DO用似乎更常见。除了违反单一职责原则之外,实际使用中似乎问题不大,因为很多系统都是从先从数据表开始设计的。郑老师对此怎么看?
作者回复: 严格地说,持久化对象也应该与业务对象分开,但在实际的项目中,一般来说,持久化对象和业务对象是合在一起的,这么做的主要原因就是,一般持久化都是一个系统在内部完成的,对于一个系统而言,是一种可控的变化。
2021-01-23416 - pc想引申问一个问题,service层的参数也用struct/class来表达,就会构建很多类,感觉很别扭,这是没问题的吗?
作者回复: 你要习惯于用业务术语去表达,而不仅仅是技术术语。封装是为了概念,而不单纯是为了封装。
2021-07-105 - 明星老师,如果后期把飞书替换成别的消息发送,需要怎么做呢?假如换成email的话,新建一个继承那个FailureSender接口的EmailFailureSenderImp然后加上@Service,再把飞书的那个服务的@Service注释或删除掉吗?
作者回复: 这是依赖注入怎么做的事,依赖注入的 bean 其实都是有名字的,可以指定一个名字就好了,也就是 Qulifier。
2021-01-2825 - 邓志国看了bob大叔的干净架构后就改成这样了
作者回复: 你基本上已经理解了Clean Code。
2021-01-2544 - 慎独明强抽象不依赖于细节,细节依赖于抽象。我们业务中就出现了违反依赖倒置原则。 影响点:当抽象新增一种实现时,业务代码就很难兼容。 到店任务业务由调拨单具体实现来开展,当到店任务新增一种单据,代码写不动了... 增加一种模型,到店任务来进行解藕。具体实现依赖抽象,而抽象不依赖具体实现。这就是血淋淋的教训,也加深了对依赖倒置的理解
作者回复: 有教训不可怕,能汲取经验最重要。
2021-06-283 - bigbendubbo接口是resource层还是service层?
作者回复: 如果你这里的 dubbo 接口指的是 dubbo 框架本身的接口,那它不属于这里任何一层。它只是一种实现,不在业务中,需要适配到业务接口中。
2021-08-161 - Jxin1.所以说,按ddd的分层。应用层不能接收dto,应当新建一个参数类(这样工厂类的实现不依赖dto倒是很好保证了)?那么这个参数类归属什么?感觉不属于实体也不属于值对象。 2.dto转pojo感觉还是不好。虽然从职责分配的角度看,dto能满足pojo创建的诉求,所以归属到dto做pojo的工厂方法。但这样dto就依赖了pojo,而这个依赖是非强必要的,所以减少依赖可能更好,借助工具单独实现一个dto转pojo的转换器。
作者回复: 参数类属于业务层,不用纠结它属于什么,它就是一个参数。 具体的转换其实就是一个工厂方法,放到 Request 里面而不是单独放置,就不用多谢一个额外的类了。
2021-01-2621 - 岁月神偷提供稳定的接口,去除不稳定的实现
作者回复: 接口要稳定,实现可以变。
2021-01-251 - Geek_c1529b老师,您好,请教个事情,@Task这个注解是做什么用的?是线程池吗?能否给个包全路径
作者回复: 其实可以忽略它,这不是重点
2022-06-20 - 阳感谢老师的分享,解了自己很久的疑惑。有个问题请教,防腐层的目录该如何组织,既然不属于resource和service层,他该放在哪个目录,如何命名。有没有参考的完整工程目录组织供学习参考?2022-07-011
收起评论