今天跟同学交流关于源码阅读,以及设计模式的一些内容,简单润色总结一下。
误区
新手阅读框架源码最大的误区在于,起点要求大而全,要阅其血肉,还要望其筋骨,结果往往苦其心志却不得其意,反而因为难有进展而放弃。依个人经验而言,非也,学习时要俯瞰全局,架构了然于胸,再寻找突破点,其次以点带面,循序渐进,最终做到知其然且知其所以然。
如何实践
新手如何阅读源码呢?依个人经验可以参考如下:
- Github,源代码,架构,设计要点,业务场景等等均能找到,以此用于窥其概貌。
- 搜索引擎,大牛分析文章,借鉴其思路
- Demo,自身实践才能有真知,可以通过Debug寻找单项突破点,比如某某小功能的设计思路
- 核心流程,很多框架是CS架构,往往Debug难度极大,可以选择性带目的的看完整的核心流程。
- 搜索引擎,Github,寻找其他使用大厂在其框架的分析,扩展等等
- 反复阅读,反复思考*
举个栗子
如何阅读RocketMQ的源码?
- 在Github寻找第一手材料,阅读后应有所获,比如架构设计要点,注册中心,生产者,消费者,Broker,顺序消息,事务消息,同步刷盘,异步刷盘,集群模式,广播模式,主从架构,集群选举等等
- 搜集大牛文章,书籍,比如丁威大佬的RocketMQ技术内幕等等
- 动手实践,阅读客户端设计,比如看看如何做负载均衡,如何做重试,重试次数等等
- 在有了之前的经验后,可以深入Broker的源码,剖析其架构,了解CommitLog,ConsumerQueue, MessageIndex。了解如何实现同步刷盘,了解如何实现事务消息,为何顺序写取代随机写等等
- 看看滴滴,美团等对其扩展与优化,比如延迟消息的设计,还可以与QMQ对比学习
- 反复了解反复学习反复思考,以点带面。
新手对于设计模式似乎情有独钟,但学习后最常见的感慨就是,用不到。我看过不少三五年开发者经验的同事,写出的代码略有粗糙,有句话说得好,用着面向对象语言写着面向过程的程序。(PS:我的水平也很差,只是就这么讨论)
误区
- 被‘不要因为设计而设计’这样的胡话耽误了
- 没有深入理解业务,也没有真正想要写好代码的思维,受困于业务
- 重于形而轻其神
- ....
如何学会才能把设计模式根植到习惯中?依个人经验而言:
- 实践,实践,实践,去‘为了设计而设计’
- 用心理解业务,提高坏味道的嗅觉,努力想要写好代码
- 实践过程,反复思考原则性的指导,比如面向接口编程,组合优于继承,单一职责,开闭原则等等
- 忘记设计模式,专注于通过这些原则性的指导来编程
设计模式本身是一种工程实践,属于术的层面,而原则性的指导则属于道的层面。这里我想提一个关于底层思维的指导,称之为‘第一性原理’,新技术层出不穷,底层技术并没有多少变化,设计模式亦如是。
举个栗子
之前遇到一个需求,RocketMQ有时候不够稳定,比如出现过事故,导致MQ大概有10分钟的不可用问题,由于没有做好可靠性优化,很多消息发送失败后记录在日志中,此事要去日志中捞如此多的消息体,简直可怕。
解决的方案:将消息在投递前先落库,落库后在事务成功后投递消息。投递成功后,将库中的消息异步删除,投递失败,通过另外的消息补偿机制来重新投递。(暂不讨论该方案对性能的影响,因为这将会回到业务上来探讨)
论如何写出面向过程的代码?
DAO.save()
success = MQ.send(message)
if(success) {
DAO.delete(message)
}
如此,这以后要写多少重复的代码?坏味道闻到的人,会想办法去解决。
如果在这个应用把这些重复的东西都抽取出来,是不是就更好了?那别的应用呢?所以放到组件是不是更好呢?
这个需求要怎么设计,我想不同的开发者依据不同的经验会有不同的设计思路,可能也会被时间,人力等等的因素所左右,这个需求是我一年前刚到公司时做的设计,因为当时刚好遇到,我简单说一下我的思路:
- 把整个过程抽象出IClean, ISend, IConsistent三个接口,寓意清理消息,发送消息,保存消息。
- 通过模板方法将这些接口能力聚合起来达到流程上的完整(是不是组合会更好?仁者见仁智者见智,要依据场景去分析)
最终该功能集成在之前实现的好MQStarter上,类图大概如下(水平很差,欢迎斧正):

设计模式往往被讨论得很多,很多经验足的人其实相当慎重,因为深知过度设计的后果,但是对于新人还是要勇于实践,勤于思考。如果没有足够的实践经验,又怎么去谈是否过度设计呢?
网友评论