前言
作为一个Java程序员,忽略间发现自己已经在这个行业摸爬滚打了六年了。自认为算得上一个业务比较资历的人士了,不敢说在某领域拥有超过常人的积累和认识,但是自认为拥有整套完整思维模式和优秀认知事务的能力。可以深入地研究一些东西或者技术,自己写一些出来,而不是这也用过,那也知道,但是多半都是局限于仅仅见过,会用,却从来没有认真思考过其代码背后蕴含的思想,更少有人研究过源码,去体会一下大神会解决问题的思想。程序员是最有活力和最有思想的一个群体,需要不断的学习和提升,勤于思考,而不是让自己浮于表面。
个人感觉,国内大部分程序员很少有人研究过源码,这也算是国内大部分程序员最让人悲哀的地方了,当然这也与外界浮躁氛围的蔓延不无关系。
我在思考,为什么以前会把如此多的时间全部用在编程上。大量的编程。那是我渴望深入研究一个类库,一个框架或一门技术,各种新技术,因为新奇让人兴奋。
我负责什么
在过去的一年中,我担任公司技术开发部一名高级工程师,主要从事JAVA项目的开发与维护工作,今年主要侧重点之一是业务重构开发。2020年度大概贡献代码20余万行,虽然辛苦,但是你能感受到你每天都在成长。为了今后更好的工作,总结经验、完善不足,本人就今年度的工作总结如下。
我做了什么
- 负责团队整体核心项目的完全重构
- 核心功能迭代
- 架构设计优化,疑难点处理
我的2020重构小结
什么样的代码是好代码?
- 好代码的检验标准就是人们是否能轻而易举地修改并理解他。
如何才能写出高质量的代码
- 设计思想
- 设计原则
- 设计模式
- 编码规范
- 重构技巧
什么是重构?
- 对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。
- 在不改变代码外在行为的前提下,对代码做出修改,以改进程序的内部结构。
- 大规模高层次的重构
- 内容:对代码分层、模块化、解耦、梳理类之间的交互关系、抽象复用组件
- 理论基础:设计思想、原则、模式
- 小规模低层次的重构
- 内容: 规范命名、注释、修正函数参数过多、消除超大类、提取重复代码等编程细节问题,主要是针对类、函数级别的重构
- 理论基础: 编码规范
重构目的?
- 不改变可观察行为
- 提高代码的可理解性,降低修改成本
哪些可以重构?
-
神秘命名Mysterious Name
- 深思熟虑如何给函数、模块、变量和类命名,使它们能清晰地表明自己的功能和用法
-
重复代码 Duplicated Code
- 一旦有重复代码的存在,阅读这些重复的代码时就必须加倍仔细,留意其间细微的差异。如果要修改重复代码,必须找出所有的副本来修改。
-
过长函数 Long Function
-
过长参数列表 Long Parameter List
-
全局数据 Global Data
- 全局数据的问题在于,从代码库的任何一个角落都可以修改它,而且没有任何机制可以探测出到底哪段代码做出了修改。
- 把全局数据用一个函数包装起来,至少可以看到修改它的地方,并开始控制对它的访问。之后可以把它放在一个类或者模块中,只允许模块内的代码使用它,尽量控制作用域。
-
可变数据Mutable Data
- 对数据的修改经常导致出乎意料的结果和难以发现的bug。需要采用一些手段来约束对数据的更新,降低风险。
-
发散式变化 Divergent Change
- 一旦需要修改,只需要跳到系统的某一点,只在该处做修改。这是必须要做到的抽象,若因为修改一处代码同时牵连要修改多个函数,就会带来很严重的坏味道。
-
霰弹式修改 Shotgun Surgery
- 散弹式修改类似于发散式变化,如果遇到某种变化,都必须在许多不同的类内做出许多小修改,那么面临的坏味道就是散弹式修改。
- 面对这样的问题,一个常用的策略就是使用与内联(inline)相关的重构把本不该分散的逻辑拽回一处。完成内联之后,可能会闻到过长函数或者过大的类的味道,不过总可以用于提炼相关的重构手法将其拆解成更合理的小块。
- 解决:改变只在一处发生,不要多处修改。将总是一起变化的东西放到一块儿。
-
数据泥团 Data Clumps
- a\b\c三个变量,经常同时出现在多个函数的参数列表中。
- 解决:那么考虑把a\b\c封为一个类内,以此类当参数。
-
基本类型偏执 Primitive Obsession
- 用合适的类型匹配合适的对象描述。
- 表现为:用简单的基本类型描述不同的含义的对象描述。
- 不合适的情况举例,如:0表示数学,1表示英语,2表示语文。那么可以考虑将数学/英语/语文的012用枚举定义,更易理解。
-
重复的switch Repeated Switches
- 表现为:在多处不同的地方,重复使用完全相同的switch语句或ifelse语句。重复的switch的问题在于:每当想增加一个选择分支时,必须找到所有的switch,并逐一更新。
- 这样的问题在于,如果产生变化,需要多处修改。任何switch语句都应该用以多态取代条件表达式消除掉。甚至所有条件逻辑都应该用多态取代。
-
循环语句。Loops
- 使用管道操作,如filter/map等,代替循环语句。
- 好处在于使得我们更快地看清被处理的元素以及处理它们的动作。
-
冗赘的元素 Lazy Element
- 指的是,多层不必要的包装。
- 如:方法a中包的是b,b包的是c,c包的是d。但是bc只是基于某种考虑的纯粹包装,而从未有其他变化,这时可以让a直接包d,bc就去掉吧。
-
夸夸其谈通用性 Speculative Generality
- 存在一些方法或参数是用于在未来某一天会实现的,但暂时还未实现就写了进去,这会加深对系统的理解和维护。应该搬移掉。
- 指的是,过度设计,假象的灵活机制。从未被用到的。
-
临时字段
- 有些类:其内部某个字段仅为某种特定情况而设,违背了通常认为对象在所有时候都需要它的所有字段的思维。
- 使用提炼类和搬移函数把所有和这些字段相关的代码都放到单独的类中统一管理。
-
过长的消息链
- 用户向一个对象请求另一个对象,然后再向后者请求另一个对象,然后接着请求另一个对象…这就是消息链。容易造成的问题很明显,客户端代码将与查找过程中的导航结构紧密耦合。如果对象间的关系发生变化,客户端就必须做出修改。
- 使用隐藏委托关系(189)。先观察消息链最终得到的对象是用来干什么的,看能否提炼函数(106)把使用该对象的代码提炼到一个独立的函数中,在运用搬移函数(198)把这个函数推入消息链。
-
中间人。Middle Man
- 对象的基本特征之一就是封装-对外部世界隐藏其内部细节。封装往往伴随着委托。
- 过度委托,举例:a使用b的b1 b2 b3三个函数,但是b1 b2 b3这三个函数都是c的c1 c2 c3。那么就把b这个中间人去掉,直接a使用c1 c2 c3
-
内幕交易
- 模块之间的数据交换会增加模块间的耦合。在实际情况里,一定的数据交换是不可避免的,但必须尽量减少这种情况,把交换放到明面上。
- 如果两个模块有共同的兴趣,可以尝试再新建一个模块,把这些公用的数据放在一个管理良好的地方;或者用隐藏委托关系,把另一个模块变成两者的中介。
-
过大的类 Large Class
- 让类业务功能单一,避免一个类干很多事情。
-
被拒绝的遗赠 Refused Bequest
- 指的是,子类只想继承超类的部分字段和函数,其他的拒绝使用。这意味着继承体系设计错误。超类中的字段函数应该是子类的必备数据。
- 继承体系设计时,应该是真是一个体系。而不应因为多个并行的类有某些行为相像的函数,而抽取超类。比如猪和牛都有四条腿和一个尾巴,但不应该抽取一个只有四条腿和一个尾巴的超类,猪牛不是一个体系的。
-
注释 Comments
- 一段又长又臭的代码,无法自解释,只能靠注释解释其含义。这不是注释原本的意义。
- 注释可以用来记述将来的打算之处,标记并无十足把握的区域,或是写下“为什么做某某某事”,这类信息可以帮助将来的修改者。
参考:https://www.processon.com/view/5efaaa337d9c0844203d96fd#map
2021年我能做什么
-
技术方向
- 基础理论
- 编程语言 Java、python、go
- 数据结构 mysql 、redis
- 网络通信
- 分布式理论
- 源码解析
- Redis
- SpringBoot
- 技术布道
- 工程方法论
- 设计模式
- 开发模式
- 架构设计
- 平台架构方向
- 运行时支撑服务
- 负载均衡
- 配置中心
- 服务网关
- 服务容错
- Alibaba(Sentinel)
- 服务监控
- 日志监控
- 调用链监控
- Metrics监控
- 健康检查
- 分布式服务
- 消息系统
- ...
- 发布机制
- 灰度
- 服务部署
- 发布系统
- 发布机制
- 云原生
- 运行时支撑服务
- 平台架构方向
- 基础理论
-
管理方向
- 争取进入管理层级
- 团队
- 思考方式
- 思考层面
- 做事心态
- 架构管理