前言

只有光头才能变强。

文本已收录至我的GitHub精选文章,欢迎Star:https://github.com/ZhongFuCheng3y/3y

最近在整合各种的系统,在这个过程中遇到了各种的问题,三歪今天来分享一下关于「项目结构」或者说「二方包」的事。

我们先不聊「二方包」,因为初学或者还没工作的同学可能没听过这个词。

初学的时候或者刚做项目的时候,我们的项目架构是怎么样的呢?我翻出了我在大学的时候写的小Demo:

可以看到的是,我们的项目只有一个Module,里边我们分各种的包:dao/service/controller/utils...等等。

这看起来好像没啥问题吧?

我们去到公司里边,可能看到的项目都分了多个Module,比如下图:

有什么区别呢?我们用一个Module在里边分各种的子包,看起来也还行。为什么我们要分多个Module呢?

我个人认为原因是这样的:Maven本身就支持多模块(Module)的管理,将不同的层分出来,项目看起来更加清晰,在改动的时候针对某个模块去变更就好了

  • 比如,我把dao层分成一个模块,当我变更dao这个模块的时候,我只需要关心这个模块就好了,不需要关心service模块或者web模块
  • 举个例子:每层几乎都会有自己的配置信息(配置文件),数据访问层会有数据库的配置文件、业务层也会有对应的配置文件。我们抽出多个Module(不同的Module放属于自己的配置文件),从代码结构层面上会显得更加清晰。

我们写完的代码是需要维护的,可维护性很重要

很多编程方式客观上没有对错之分,一致性很重要,可读性很重要,团队沟通效率很重要。程序员天生需要团队协作,而协作的正能量要放在问题的有效沟通上。个性化应尽量表现在系统架构和算法效率的提升上,而不是在合作规范上进行纠缠不休的讨论、争论,最后没有结论。

二方包

当年我看《阿里巴巴开发手册》的时候也写过一篇总结,当时的文章也提到了那时候不咋懂二方包,现在我回来填坑了。

首先来科普一下什么是二方库?(二方库也叫·)

  • 一方库指的是本项目中的依赖
  • 二方库指的是公司内部其他项目提供的依赖
  • 三方库指的是其他组织、公司等来自第三方的依赖

如果看过我之前文章的同学都知道,三歪在公司目前维护的是消息管理平台,全公司发送的消息都会经过我的系统。

我会打个「二方包」到公司的Maven仓库,然后他们引入我的pom依赖,调用我的接口去下发消息。

假如我没有分Module,所有的代码都写在同一个Module下,那我发到公司的Maven仓库会发生什么?打包(deploy)这个过程是没毛病的。

如果他们依赖了我这个没有处理过的二方包,相当于把我整个工程给依赖进去了,这是非常可怕的。

如果有从零搭过系统或者整合过系统的同学会知道,这个过程有会有多「版本」的坑。只要版本不一致,就会出现一大堆奇奇怪怪的问题,并且这些问题都不太好解决。

所以,一般我们的二方包都应该是很清爽的。比如我提供的二方包,它就只有接口和接口所需要的实体,没有杂余的繁琐依赖。

业务方是不关心接口的实现的,我们只需要暴露接口就好了。

三歪一次经历

最近三歪在整合系统嘛,分享一次经历。

我负责的消息管理平台系统的架构是这样的:

可以看到,我所负责的系统是分得很细的(很符合分布式的理念)。从功能上看,这些系统变成一个大工程也不是什么问题,只是这个系统会非常非常大。

消息管理平台除了上面的系统,还有其他的子系统,比如说「ID映射」。这里当初设计的时候也把它当做一个系统给抽出去了。

「ID映射」应该不难理解:业务方传入的是站内的userId,但要发的是短信。我这边要把userId转换成手机号,可以简单理解这个系统就做的这么一个ID转换的功能。

现在要规划把这个「ID映射」给整合起来,原有的机器要下线了,要把这个服务的功能给整到消息管理平台的系统中。(为啥要整到我这个架构上?因为本身这个系统就只有我这边在频繁使用)

为啥要整合?现在的潮流可能是把单个系统拆出多个系统做”微服务“,但真正系统多起来未必是一件好事。

一些小的功能其实没必要单独分出来一个系统,这是需要成本的,至少我们机器成本是有的(一个系统我们至少会有四台机器)->两台线上,一台预发,一台线下

OK,说完背景了以后,我们再来看看「ID映射」这个系统的代码架构:

说白了,就是这个工程下有这三个Module,如果你要问我为什么没看到dao层的Module,而是直接放到core 层,问就是当初设计不合理。依我的理解,应该至少是要把数据访问层抽出一个Module。

可以看到的是,这个「ID映射」系统其实也是一个完整的系统,从后台管理页面到数据库都是完整的。

现在要把这个系统给整到消息管理平台的架构下,如果是你,你会怎么弄呢

其实就两种方式:

  1. 把这个「ID映射」系统整个搬到某一个系统中
  2. 把这个「ID映射」系统通过模块拆出来,分到各个系统中。

最简单的做法肯定是把这个系统的代码搬到另一个系统,然后就可以run起来了。但前人已经把系统分得那么干净了,如果我这样干了,后面接手的人会不会锤我呢?

三歪认为服务相关的代码,应该就整合到专门提供服务的系统。后台相关的代码,就应该整合到后台相关的系统。即便我后台系统发布了,丝毫不影响对外提供的服务。

所以,我决定把「ID映射」的各个Module抽出来,分到不同的系统中。把api层和部分core层的代码的Module分到service系统中,把web层的Module分到admin系统中。

看似是挺完美的,我当初也是这样执行的,于是我顺利把apicore的代码整合到service系统之后,正打算把web的代码整合到admin系统中,遇到了一个问题。

web的代码是controller层,它显然会依赖service层的代码,service层的代码也显然会依赖dao的代码。

现在我已经把api/core层的代码大多数已经迁到了service系统,而admin系统是没有这些代码和依赖的,我需要整个系统是能跑通的,我能怎么办?

此时能想到的有两种方案:

  1. service系统的代码再到admin系统中实现。

  2. 现在service系统已经实现好了,打个二方包,然后让admin系统依赖。这里也有两个方案:

    1. 二方包不做任何处理,admin系统直接依赖其所有的实现。
    2. admin系统所依赖的接口再出一个api层,admin系统只需要依赖api层,实现远程调用

如果是你,你会选择哪种?我们来分析一下:

  • 第一种方案:service系统的代码再到admin系统实现,这肯定会有代码冗余的情况。毕竟service系统肯定会依赖dao层的,而admin系统最终也是需要依赖dao层。dao层没有完全抽出,在前期就肯定会有代码冗余的情况
  • 第二种方案分支①:将service系统已实现的代码直接打成二方包,admin系统直接引入就没有任何代码冗余的问题。但这会引发其他问题:
    • 直接打成二方包意味着要把所有的实现依赖都打进去,admin系统在引入的时候需要针对这个二方包做一系列的排包操作。(这个非常蛋疼)
    • 其实最致命的是我们干不了。我们的系统在发布的时候是分环境的(线上、预发、线下),我们会在发布的时候根据不同的环境使用不同的配置。如果我们此时直接打个二方包,我们是需要指定环境的,这说明我们只能用一个环境的配置,这是行不通的。
  • 第二种方案分支②:把admin系统所依赖的接口再出一个api层,实现远程调用。从字面上,这是最优雅的方案,但如果admin系统依赖的接口众多的时候,实际践行的时候会发现这工作量巨大
    • admin系统所依赖的接口有40+个,这些接口所依赖的实体有80+个。我搞了大半天,发现完全搞不动,工作量巨大!!这是单纯的体力活

第二个方案的分支①三歪再来聊聊为什么说干不了,首先我们的实现是有配置的

我们在deploy的时候就必须指定一个环境,比如我们默认选择线上环境的配置好了。打完包以后,这个包默认的环境就是给线上使用的。但是admin系统他还需要在线下环境启动,怎么办?没办法吧?

假设环境配置的问题能解决,等着我们还有各种依赖的问题。admin系统和二方包的依赖冲突了怎么办?

比如说:相同的配置项,不同的配置信息。在service系统上能兼容(毕竟代码都在同一个工程下),但直接打成二方包就没法跟admin系统兼容了。

只能删除冲突的部分,然后再发包了吧?但冲突是admin系统冲突的,跟我service系统的有啥关系呢?这我要做成一个完美兼容adminservice系统的Module吗?老实说,不太现实

扯了一大堆,三歪最终选择的是第一个方案

在初期现在dao层的代码肯定是在adminservice系统上冗余的。service层不好抽取,但dao层还是相对好抽取的啊。

为什么daoservice层的代码不一样?明明我在上面已经讲了怎么多直接抽取二方包的不可行性了。

dao层的代码相较于service层的代码要简单多了,一个合格dao层应该是只管访问数据库,不应该有dao层的代码去调service层的代码的。

代码的简单意味着依赖会很少,比如我们的dao层就应该只有Mybatis和Spring相关的依赖,其余的就不应该有。而前面提到的环境配置的问题,我们可以交给业务方去实现,不在dao层上做任何配置信息,开个hook给业务方去做。

像三歪这种”微服务“系统,本应该要把dao层给抽出来。再回看我的系统架构图,可以发现会有几个系统都需要依赖dao,如果没有抽出来,这必会冗余,冗余的代码意味着不好维护。

规范

之前看不懂的阿里巴巴开发手册,现在能看懂了。我建议有空的时候还是可以看看的,都说得挺有道理的。

阿里大佬们踩了一堆坑,然后总结出来的规范。

【强制】二方库的新增或升级,保持除功能点之外的其它 jar 包仲裁结果不变。如果有改变,

必须明确评估和验证,建议进行 dependency:resolve 前后信息比对,如果仲裁结果完全不一

致,那么通过 dependency:tree 命令,找出差异点,进行<excludes>排除 jar 包。

【参考】为避免应用二方库的依赖冲突问题,二方库发布者应当遵循以下原则:

1)精简可控原则。移除一切不必要的 API 和依赖,只包含 Service API、必要的领域模型对

象、Utils 类、常量、枚举等。如果依赖其它二方库,尽量是 provided 引入,让二方库使用

者去依赖具体版本号;无 log 具体实现,只依赖日志框架。

2)稳定可追溯原则。每个版本的变化应该被记录,二方库由谁维护,源码在哪里,都需要能

方便查到。除非用户主动升级版本,否则公共二方库的行为不应该发生变化。

三歪瞎扯

为什么我们会用多模块(Module)?其实就是让我们的项目代码变得更加清晰,像对外服务的api层就必须要抽出一个精简Module给别人使用。

不知道你们如果能看完这篇文章能不能有所启发,反正我已经写完了。如果你们感兴趣的话,等我整合完这些系统我再来写一篇关于这段时间的感受。

我是三歪,一个要成为光头强的男人,下期见。给三歪点个赞,对三歪真的非常重要!**

用实战项目经验告诉你什么是二方包!相关推荐

  1. 赠书|大牛BTA大厂实战项目经验分享,真会玩!

    如今,全球早已步入数据时代,随着行业的高速发展,相关岗位缺口已超150万,且薪资超同行业50%.未来十年,数据细分岗位将扩张5倍,各行业数据人才缺口明显. 很多人想抓住机遇进入数据分析行业,却经常遇到 ...

  2. 什么是互联网大厂_仅限今天!大厂最热数据分析经典实战项目大公开!

    原标题:仅限今天!大厂最热数据分析经典实战项目大公开! 如今,全球早已步入数据时代,随着行业的高速发展,相关岗位缺口已超150万,且薪资超同行业50%.未来十年,数据细分岗位将扩张5倍,各行业数据人才 ...

  3. 真相!没项目经验高薪就无望?

    福利!廖雪峰最新研磨的实战宝典<如何将大数据开发做到优秀>首次开放了,内容出自开课吧 vip 课程"大数据高级开发实战班",为帮助大家特殊时期职场走得更加顺畅,现决定将 ...

  4. B站 ‘顶流‘ 实战项目,yyds

    哈喽,大家好,我是朋哥,一个资深的软件开发工程师,致力于:Java核心技术(SpringBoot,SpringCloud,算法,数据库,热衷高性能,高并发,分布式技术的研究),专注前沿技术开发,非常硬 ...

  5. Vue3+node.js网易云音乐实战项目(五)

    推荐歌单详细页面顶部 1.推荐歌单详细页面 1.1.导航条和背景 1.2.头像和简介 1.3.头部完整代码 1.4.链接 实现效果 1.推荐歌单详细页面 1.1.导航条和背景 推荐歌单页面做好后,我们 ...

  6. vue+websocket+express+mongodb实战项目(实时聊天)(一)

    ##vue+websocket+express+mongodb实战项目(实时聊天)(一) 在原来基础上增加了多个聊天室以及发送图片[vue+websocket+express+mongodb实战项目( ...

  7. Vue3+node.js网易云音乐实战项目(三)

    页面 一.头部导航栏布局 二.轮播图的实现 三.请求网易的banner图 四 链接 一.头部导航栏布局 首先我们看最上面这里的布局,大致可分为三个模块,顶部左边,顶部中间,顶部右边 那么我们在comp ...

  8. Java 高并发_JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过!...

    JAVA并发编程与高并发解决方案 JAVA高并发项目实战课程 没有项目经验的朋友不要错过! 1.JPG (37.82 KB, 下载次数: 0) 2018-12-3 09:40 上传 2.JPG (28 ...

  9. dt测试软件的学习心得,无线网络优化dt测试心得_适合新手入门,高手进阶_5年项目经验实战经验.docx...

    无线网络优化DT测试心得_适合新手入门,高手进阶_5年项目经验实战经验 无线网络优化DT测试心得_适合新手入门,高手进阶_5年项目经验实战经验 路测中不常见的问题和个人心得 1.深井子镇投诉测试报告 ...

最新文章

  1. 名校 Stanford
  2. MySQL-索引优化篇(4)_索引的维护
  3. oracle分区表相关
  4. 孟岩谈Erlang:并行计算和云计算
  5. andriod studio 查看项目依赖_Intellij IDEA 中如何查看maven项目中所有jar包的依赖关系图...
  6. 经理人如何与这“六种人”打交道?
  7. 19-6/28作业:100以内偶数求和
  8. vue控制台报错Duplicate keys detected: 'xxxx'. This may cause an update error.解决方案
  9. [渝粤教育] 广东-国家-开放大学 21秋期末考试互联网金融10139k2
  10. 在linux中配置编译u-boot方法,U-Boot编译过程解析
  11. 烟雾传感器的matlab程序,单片机烟雾传感器proteus仿真+程序+PCB原理图
  12. 数据库设计—图书管理数据库系统设计
  13. java怎么用unicode写程序_简单的讲解Java是使用Unicode字符集
  14. Mac book 合并分区,报错文件系统验证失败的解决办法
  15. 2008年IT行业10大热门职业调查结果出炉
  16. 解决在串口调试助手中每次复位后只能发送一次数据的问题
  17. 组建一个最简单的局域网
  18. Mask R-CNN 原理解析
  19. 使用scrapy再次爬取猫眼前100榜单电影!
  20. 宗镜录略讲——南怀瑾老师——系列9

热门文章

  1. 【Python爬虫_8】爬取必应图片
  2. GLES2.0中文API-glCompressedTexSubImage2D
  3. provider: SQL Network Interfaces , error: 26 - Error Locating Server / Instance
  4. 【已解决】阿里自动滑块 x5sec 解密 钉钉数据采集
  5. 京东抢购失败?试试用Python准时自动抢购!七夕秒抢种礼物!
  6. 沪市和深市股票托管方式的区别
  7. android友盟埋点,友盟数据埋点前,你要知道这些
  8. 组网胖模式_胖瘦AP组网优劣对比
  9. 请保持内心中最后一点良知
  10. 2020下半年中小学教资考试教育知识与能力试题(中学)——主观题