短短两个月的实习就要结束了,给这段时间做一个简短的总结。
做了什么
这次的实习因为时间较短,导师只好模拟了一个小的业务场景给我们练手。实现的是一个后端的中间件系统,用于在两个系统之间传递通讯信息并且记录下通讯的所有过程。
初始设计
数据库设计
一开始需要完成的任务是数据库设计,这一步的工作步骤大概是:
- 研读数据库设计规范文档。
- 研读业务文档,理清业务逻辑。
- 设计 ER 图,生成数据库表。
在读完了数据库设计规范文档以后可以明显感觉到 MySQL 在实现上的不足,因为 MySQL 的大部分高级功能都被禁用了。因为之前对于数据库的学习都只是达到了能用就行的程度,所以在设计数据库字段类型的时候总是会自以为是,比如认为 INT(11) 的意思是存储最多 11 位的 INT 值。虽然很多时候可以从表面去猜测一个类型的含义,但是对于不清楚的事物还是需要经过详实地查证,单纯的凭空猜想百害而无一益。
数据库设计和业务逻辑的关联性较大,所以最好是在透彻理解业务逻辑的情况下再设计数据库,否则就可能出现数据库设计一半的时候出现无法跑通业务逻辑的情况。(不过很多时候对业务逻辑的理解也是在数据库设计的过程中逐步加深的)
其次 弄清所开发的系统边界和核心功能也很重要,否则在数据库设计的过程中也会绕很多弯,比如会额外考虑到很多不必要的情况或抓不到重点而设计出无法实现系统功能的数据库表。
数据库的设计是一门很深的学问,为了设计出符合功能且性能优良的数据库不但需要知道数据库的原理和性能表现,更需要结合具体业务情况具体分析。单纯符合教科书上范式的数据库往往不是最合适的数据库。
接口设计
由于牵扯到的业务场景较小,所以需要设计的接口比较少也比较简单,需要注意的是在约定接口的时候应 尽可能限制接口的功能(单一性)和适用性,避免调用接口的程序员滥用接口对后端服务造成难以预计的 bug,同时严格的接口设计也能免去许多校验工作。(强约束双方接口)
这次尝试了一下用 dubbo 来实现接口间的调用,发现果然无论是什么框架,基础的使用都是很简单的,所以这次主要学习到的还是相关的技术理念。
接口调用通常包含两个部分,序列化和通信协议。常见的序列化协议包括json、xml、hession、protobuf、thrift、text、bytes等;通信比较流行的是http、soap、websockect,RPC通常基于TCP实现,常用框架例如dubbo,netty、mina、thrift。
具体实现遇到的问题
XSD 生成 POJO 类
需要实现的中间件系统要对 XML 报文进行处理,所以通过 XSD 生成 POJO 类就很重要。
在做这个转换的时候采用了各种 maven 插件来处理,但是由于官方对于 maven 插件的支持没跟上,所以实际上使用起来的时候存在许多摸不着头脑的 bug,甚至按照官方手册编写的配置也会存在问题(技术落后,缺少维护)。最后是在导师的帮助下稍微改了一下配置文件就成功了。
因此在遇到 bug 的时候应注意:
- 最先关注官网 github 中的 issue,避免无意义的搜索。
- 老旧代码不可迷信官网。
全局唯一序列号
中间件需要生成全局唯一的序列号来确保报文的唯一性,考虑到分布式和高并发的问题,那么在生成序列号的时候就一定要用锁来控制并发。在网络上搜集到一些方法:
- 简单的数据库主键自增 ID(如果数据库是分布式的就挂了)
- UUID(过长)
- Redis 实现(额外配置环境很麻烦)
- Twitter 的 SnowFlake 算法(原生算法生成的序列号过长)
最后采用的是 SnowFlake 算法,该算法有高性能低延迟的特点,不过需要在应用上独立地进行部署和开发,且强依赖时间戳,在代码中需要处理好时间回滚造成的错误。
虽然该算法原生生成的序列号超过业务需求,但是我们可以根据实际需求对算法进行修改。
在搜集解决方案的时候需注意:
- 首先搜一下业内的大公司是如何解决问题的,这种搜索思路可以提供有保障的解决方案。
业务逻辑的重要性
这次模拟的业务场景虽然很小,但是因为前期对业务的理解一直不到位,因此经常在编码的时候发现设计有问题,导致数据库设计和接口设计一直在做修改。在这之前我还是比较轻视业务逻辑的,感觉一切都是技术为王,但经过这次模拟业务的开发,我才明白对业务逻辑的深刻理解能为应用的开发省去许多麻烦,同时也能少绕很多弯路。(起码能省去对设计进行反复修改的过程)
果然软件工程中强调的理论有着很强的实际应用价值啊(比如清晰的需求分析,对系统边界的划分)。
不足的知识点 & 错误的理解
这次实习我也发现了许多以往理解错误或者没有认真钻研过的知识点:
- Java 泛型的概念和使用
- TDD 方法的实际使用
- 有关数据库的知识点(如事务,操作的原子性等等)
同步异步概念的错误理解
同步和异步的概念其实相当易懂,但是之前在了解过概念后并没有进行过实践,所以一直处于一知半解的状态。简单来说同步会造成执行过程的阻塞,而异步就不会。
以前认为和编码相关的知识点并没有很大的难度,只要肯堆砌时间,总能达到一定的高度,这样的理解导致我的学习积极性始终无法高涨。但是后来发现计算机编码的知识体系实在是过于庞大,如果不愿意付出努力和时间去学习掌握各方面的“简单”知识点,那么在需要寻找解决方案的时候往往会舍近求远,有时甚至连个思路都没有。(比如在这次的实习中,因为不知道数据库 update 是原子性操作,在处理最后报文并发接收的时候绕了好大一个弯)
再仔细想想周边拿到优秀 offer 的大佬们,或许大家的学习能力都差不多,但是他们确确实实在编码上花费了比我更多的时间和精力,这么看来也是相当的公平。因此我也没什么好抱怨的,毕竟现在的处境都是由于自己的眼高手低和好高骛远而造成的。
她那时候还太年轻,不知道所有命运赠送的礼物,早已在暗中标好了价格。 —-茨威格 《断头皇后》