引言:
春暖花开,草长莺飞,然而和煦的阳光并没有给互联网的严冬带来多少温暖,互联网大厂的裁员消息层出不穷……作为技术人员,如何过冬?就是要使自己更优秀!通过提升自身的经验与能力,加强自己在团队的影响力,扩充发展空间!本文主要是作者回顾苏宁采购平台搭建到现在,从系统的框架演进,项目迭代开发中遇到的问题进行的总结与思考,以及一些共性的问题跟大家聊聊,抛砖引玉同时也避免大家在踩坑的路上“前仆后继”。
要成为一名优秀的开发,首先要成为一名合格的开发!作为一名合格的开发,需要有相关意识!
代码更多是给人看的!
代码虽然最终是编译成二进制的文件给jvm执行的,代码写的是否优雅机器不会挑剔的,但是一个合格的开发者应该意识到:代码更多是给人看的!
(一)命名合理:
简洁易懂,合理的命名会给你的代码极佳的印象分。也有效帮助review代码的人快速了解代码的逻辑。有不少开发者有这样的想法,与其费尽心思想个类名方法名不如多写几行代码。其实大错特错的,这是别人了解你代码的窗口,犹如人的眼睛,无论你长得多么英俊,漂亮,缺少一双明亮有神的眼睛也会让人对你的印象大打折扣。
(二)格式清晰:
这里的格式包括类文件,配置文件,各种脚本,静态文件以及方法都需要分门别类的放置,循环/判断不乱用,提升整体可读性和可用性。这里有几点经常被忽视。
1.永远不要用一个常量类来放置所有的常量,一个公共类存放所有公共方法。这就犹如你把自己所有衣服放到一个箱子。想象一下,在周一早晨你起晚了,还要在杂乱无章的箱子里翻找一双袜子的情形,是多么的令人抓狂!相信如果条件允许,你更愿意买双新的,周而复始,最后你会发现有了一堆很像的袜子,更不知道哪两只是一双……
2.深度过大的循环和判断,会使代码可读性成指数级降低!人的记忆暂存时间是有限的,超过三层的循环或判断,特别是一些较复杂的条件,一般人很难记住整体逻辑。导致的后果是,review代码的时候循环往复的看一段代码,不仅耽误时间,而且极度影响review者的心情,一些隐藏的bug可能就阴差阳错的漏过了!
(三)注释规范:
注释的主要作用是准确反应设计思想和代码逻辑的,同时需要和代码逻辑变更保持同步更新。注释不规范甚至和代码实际逻辑相悖,往往给交接功能和后续处理问题的同事挖下一个深坑。
好的注释永远只有一个标准:能让别人快速准确的了解这块代码的逻辑!现在大部分公司都采用敏捷开发,要求快速迭代和迅速响应问题处理。作为开发,代码就是第一手的资料。当分配给你一个功能优化点,只给你一天时间,你找到这个类的时候发现近千行代码,结构命名混乱,全篇无一个注释的时候,相信你的心情是有多么的崩溃!所以合理注释从自身做起。借助《流浪地球》的一句名言,请记住”代码千万行,注释第一行,注释不规范,同事两行泪!”
(四)日志合理:
日志是排查生产问题的重要途径,有排查过生产问题经历的人应该都有同感,那么什么样的日志是好的日志?答案只有一个,能帮助快速定位生产问题的日志就是好的标准。日常review代码过程中,日志是最容易被开发忽视的,当有生产问题需要排查时,你会觉得合理记录日志的同学是最可爱的人!
1.日志有明确的等级划分,乱用日志级别只会带来反作用。滥用error级别的日志,相关的报警次数多了,就如同狼来了喊多了一样。
2.几个关键记录日志的地方:方法,接口调用前的入参,返回的结果。核心判断逻辑入口,对处理逻辑有影响的中间变量,异常处理场景
细节是开发质量最有力的表现形式!
一个有经验的开发不是代码写的多么天花乱坠,更多的是细节考虑是否周全。祸患常积于忽微,隐患往往都埋在细节里面,这里的隐患是个很宽泛的概念,包含了安全/性能/逻辑上的一些隐藏问题,即使忽视了,通常情况下不会对业务有什么大的影响,但是在极端情况下,忽视的某些小问题可能就是致命的根源!下面从日常开发涉及的代码编写,线程管理,缓存使用中,列出容易忽略的细节供借鉴。
1.创建新方法能私有就私有,oop开发中首先要保护好自己,其次是提供更优质的服务。使用你提供公用功能的开发者,不是你想象的那么单纯,即使你修改自己的public方法也可能影响了一个你做梦也想不到的一个功能!
2.不要忽视基本数据类型的默认值的影响。当你把考试成绩定义成int,你如何应对产品提出的统计下没考试的和考0分的需求?0和没值永远是两种业务含义。
3.警惕巨型的类和方法,以及方法的无脑拷贝,这些顺序思维编程的产物除了给团队挖坑,另外一个作用是暴露你新手的特质,即使你有了几年的开发经验。
4.POJO对象不要混用,数据对象后缀DO,数据传输对象后缀DTO,展示对象后缀VO,业务对象后缀BO。可能有同事基于好心,优化某个功能时纠正你一个命名不规范的地方,即使他很小心的通过IDE查了所有影响范围,可是不知道你VO和BO混用了,结果可想而知。
5.永远不要用float和double这种浮点数参与计算和直接比较,偶发的精度问题的排查足以令你抓狂,因此而产生的问题数据的处理更是会让你追悔莫及!
6.不要忽视数据库更新和插入操作的返回值,即使你通过各种手段和预查询确认数据库操作一定会成功,现实是很骨干的,未知的情况往往会给你一个非你期望的结果的。导致整个后续逻辑的执行偏离你预期。这个后果可能需要你的团队花费几天甚至更长时间去处理问题数据
7.线程是把双刃剑,能不用线程的不要用线程,能用线程池的决不单起线程,能用容器管理的线程池,不要自建线程池。乱用线程,线程池生产环境的OOM足以令你抓狂。
8.鸡蛋不要放到一个篮子里,即使使用容器托管线程池,但也不要把所有业务的线程都用一个线程池。除非你想体会一下核心功能服务积压了一堆需要立马处理的数据,但是线程池线程被一些非紧急的下载任务疯狂占用的无能为力感。
9.线程池配置的拒绝策略需要慎重,数据无缘无故的毫无痕迹的丢失问题,一般人的小心脏经不起几次折腾。
10.Redis是很便捷,大的value值存入redis,带给你的便捷建立在伤害其他功能的基础上的,记住redis是单线程的!大value值的存取使redis的多路并发基本成为摆设。
11.Redis的雪崩和穿透能瞬间压垮数据库,这都是大并发和恶意操作赋予的威力。
12.要求数据强一致性的业务不要使用缓存,即使你用种种手段去保证数据同步,但是总有你想不到的情况。
数据库,系统的绝对瓶颈!
毫不夸张的说系统性能问题或多或少的都能看到数据库的影子。一个糟糕的表设计不仅制约相关功能实现,也为日后的扩展设下层层障碍。下面主要从建表,索引,sql语句3个方面总结以往开发过程中数据库相关的常见问题(项目主要使用mysql,一些特性问题单指mysql)。
(一)建表规范:
1.建表同样离不开命名。表名,字段名除了固定格式要求,更多的和上面提到的变量命名规则是一致的,好的表名能让人通过表名就知道该表属于哪块业务的,存放什么业务数据的,好的字段名能准确表达字段的业务含义
2.不同表同业务含义的字段类型一致也至关重要,实际项目开发过程中这块也是最容易被忽视的地方!类型不一致表关联时,隐式的类型转换会使表关联查询索引失效!
3.字段的类型定义需要严谨,业务上定长的字段定义varchar,这是你不了解char和varchar对索引效率的影响!
4.字段长度定义随心所欲更是常见,特别是varchar的滥用,当你扩几次过亿数据的表的字段长度,那个执行过程会保证令你记忆深刻!
5.规范的字段命名是需要的,详尽的字段备注描述也是一个负责任的开发应该做的,当你纠结01,02,03…。。不知道其代表的业务含义的时候,你会打心底感谢那个备注了字段含义的同学。
6.强烈推荐每个表建一个自增的id并且设置成主键,至于原因呢B+树和聚簇索引了解下……
7.在表中冗余一些字段尽可能减少表的关联个数,是提升查询性能的很好的手段,即使违反第二范式,空间换时间还是很值得的。
(二)索引合理:
1.建新表的时候,一起加上合理的索引是个好习惯。等数据量上来了,功能响应变慢了,再被动的去加索引,那会已经影响了用户的体验。
2.索引不是越多越好,也讲求个”中庸之道”,但必要的索引还是要加的,因为索引引起的插入更新而导致的性能影响其实对大多数的业务系统来说是很小的,如果实在担心做个插入压测就知道了。
3.加个业务字段的唯一索引其实是很有必要的,不是去依赖数据库做唯一性校验,而忽略代码里面业务逻辑的校验,记住总有你想不到的异常场景会导致数据重复存库,这是最后一道防线。
4.mysql的数据表其实称之为一个”大索引”更贴切,数据都是挂在主键索引上的,其他索引依赖主键索引取数据,索引数据就能满足需要而带来的微小性能提升有时候能给你带来一些惊喜。
5.建了单键索引的字段又出现在同表的组合索引的头部也比较常见,养成良好习惯清除重复索引,一定程度上提升数据库优化器的性能,也节省了宝贵的数据库空间,何乐而不为呢。
(三)语句健壮:
1.写出复杂的sql,不是你牛的表现,恰恰相反,反应出你很low。sql牵扯过多逻辑不利于后面运维,也给数据库的运行带来巨大压力,说雪上加霜也不为过。
2.过多的表关联查询sql,在数据量少的时候是没问题。后面业务推广,数据量上来了怎么办?请记住欠账总是要还的。
3.平时写sql的时候都要想有几种影响索引生效的情况也不太现实,只要记住一点索引都是左匹配的原则,基本上能避开大部分的索引的坑。
4.即使使用分页查询也需要注意大数据结果集的影响,数据库返回分页的数据不是跳到特定行的取值,而是取出所有行后虑出分页返回的那些数据,深度查询对数据库的影响足以令你怀疑人生。
5.防止数据覆盖,除了共享锁以外,表中多加一个版本号,通过版本号去控制也是一个不错的方法。
6.安全意识要提高,当前的持久层框架有效避免了sql注入的风险,安全的意识还是不可或缺,这里的安全偏向数据安全。记住不怀好意的人时刻垂涎你认为的”不重要”的数据。除了数据泄露风险,日常更新删除数据也需要有安全意识,你能想象更新或删除语句的where条件失控带来的后果吧。
当你有了上面的意识,并在实际开发中高标准严要求自己,你已经是一名合格的开发了,如何进一步做到优秀,其实只差了思维上的升华。
开发要有产品的思维!
什么是产品思维,简单点就是站在用户的角度,想用户之所想。产品思维应该贯穿在整个产品的生命周期中,从项目开启前的用户调研、每次项目更新的用户需求评估到产品设计,开发以及测试过程中等等,一个好的产品应该做到苹果乔老爷子宣称的比用户更了解用户的需求。开发作为产品功能的绝对意义上的第一个使用者,同样要有产品思维。
1.需求评审,优秀的开发是从用户体验出发,协助产品同事完善需求,大家以如何提供一个用户体验好的又能保证系统性能稳定的为共同目标。作为开发要用于挑战技术框架束缚,这也是提高自身能力的契机。
2.产品实现,产品细节的完善。再优秀的产品设计也无法考虑全部的细节,而开发过程是对产品细节完善的一个绝佳阶段。优秀的开发会在开发过程中对一些细节提出自己的见解和完善方案。做一个有思想的开发,会助你打破职业瓶颈。
结尾:
再寒冷的冬天也会过去,只要你足够优秀,不会惧怕任何寒风!蓦然回首你会发现这不过是你成长路上的一道风景。