当前位置: 首页 > 科技观察

程序员应该如何驱动自己,快速成长?

时间:2023-03-20 13:17:40 科技观察

刚进公司的时候,从CRUD到一年前的运维支持,我还是一个只会CRUD的普通程序员。我加入了一个初创的互联网项目组。很快融入工作环境后,开始手写CRUD代码。虽然不知道底层原理,但是对SSM模板代码已经很熟悉了。另外,对于避免之前工作中的坑,我也有了一些基础和经验,比如空值校验,防止重复提交等等,让自己能够快速的完成业务代码。领导看到了,把我安排到运维支持部,开始让我做一些运维工作(这是公司初期用人的特点)。那时,我们开始一项一项地推出服务。这是我从无到有了解公司技术状况的开始,也是加班到死的开始。其实我很理解加班的原因。这与公司的技术现状密不可分。让我慢慢来吧。系统部署难:了解技术全貌一个晚上,领导拿了一份文件,列了一系列要上线的服务和要部署的服务器,然后我们就慢慢开始干活了。新服务器非常纯净,连一些基本命令都没有,只好慢慢学习安装。yuminstallxxxx,运行xxx,psaux|grep,telnet....,一天过去了,什么jdk,tomcat,都安装好了。(ps.这段运维最好的收获就是linux命令很熟练了)服务部署好后,启动的时候遇到一个问题:之前的服务是打war包的,放在tomcat里面,但是现在该服务需要java-jar才能启动。我试了nohupjava-jar这个可以后台启动的,直接翻车了。只好问起之前的发展。他们说应该使用screen命令在后台启动程序。我是一个好奇的人,后来发现开发为了不让进程退出,错误的使用了监听控制台事件的方式,导致nohup启动异常。当时从事核心业务开发的人一直忙于开发和调试,与我们的交流很少;而负责部署的我们,不懂业务,当时的开发也懒得对一些问题进行详细的解释,所以只能靠猜测来部署程序。混乱程度可见一斑,但这不是少数程序员能控制的。我当时学到的第一件事是:当信息不足,交流受限时,你要尝试学习必要的自我推理,根据现有信息的上下文补全缺失的信息。上网很重要,所以让我们暂时启动屏幕上的程序。但节目开始后,更尴尬的事情发生了。当时服务之间的调用方式都是通过HttpClient直接调用目标服务。如果我先启动服务A,服务A依赖服务B,服务B没有启动,服务A在初始化的时候会报错。于是,谁先启动,谁后启动,就成了一个棘手的问题。查看了每个服务的项目配置示例,发现每个服务的config.properties都有一个选项配置为root,标识了服务的发布路径。比如用户服务,他的config.properties会配置root=/userservice/,我就知道,调用服务肯定是这样的http路径:http://ip:port/userservice/xxxx。在config.properties中,还会有一些具有以下特点的配置reference_user=http://ip:port/userservice/xxxx。我自然明白了,这一定是该服务所依赖的其他服务的调用地址。因此,我想到可以根据各个服务的配置文件理顺服务之间的调用关系。为了确保我的猜测是正确的,我用网上的工具反编译了一个项目,发现原来的服务都是通过HttpClient调用的。然后画了一个项目依赖关系图,仔细梳理了程序的具体依赖关系。***,终于对服务部署的顺序和方法有了一个概念,而一些程序员,私底下,已经有人开始说工作不下去了,想走人。终于明白怎么部署了,但是接下来比较尴尬的问题是程序已经启动和调整了,但是leader需要负载均衡和集群。一个服务直接调用另一个服务使用HttpClient直连方式,怎么搞负载均衡?该怎么办?怎么集群?当时离DeadLine不远,上线很重要,所以忍痛买了阿里云的SLB来实现各个服务的负载均衡。当时最痛苦的事情就是理顺这种蛛网般的服务调用关系。画好项目依赖关系图,这个就好办了。我每天加班到凌晨两点。经过一个半月的时间,我终于成功部署了所有的服务。难以想象,我这个完全不懂业务的人,靠日志信息和配置关系搭建了一个成功的服务。其实有80%的功能是可以正常使用的,这让我作为一个加班加点的程序员很有成就感,虽然这20%不能处理的功能是后来负责这个的开发人员开发出来的区(领导出面,不能敷衍)。虽然,后面还有一些小插曲,虽然一开始申请可能是坑坑洼洼的,但好在终于如期上线了。在过去的一个半月时间里,我已经掌握了公司的技术架构。当一些程序员因为不了解而拒绝部署kafka、nginx、zookeeper、activemq等基础设施时,我就主动部署了。怎么用,等到部署完成,时间够了,我也了解了这些技术是干什么用的,不亏。最后整理了一下当时公司的整体技术图。有些网络转发和机房架构由于保密原因就不描述了(虽然我已经掌握了)。代码层面我简单说一下:1.服务之间,通过RESTful风格的HTTP调用使用HttpClient,需要像蜘蛛网一样维护服务调用关系。第二,配置文件在本地,有的在数据库中。每次在代码中获取配置,都要在本地加载,选择数据库。(冲击性能)。三、无用的配置文件和无用的代码散落各处,对运维造成干扰,代码有历史遗留的味道。第四,技术栈不规范。有人外置tomcat,有人内置tomcat,有人用Netty。五是命名不规范统一,用词不表达意思。公司使用elastic-job作为分布式任务调度平台。elastic-job要求每个job在启动时都需要指定job-name。但是运维在控制台上经常无法根据job-name来定位是哪个job,比如工程job是payServiceAllJob,但是在console上却注册为AllJob,让人一头雾水。痛点一:服务缺失自动发现服务上线后,由于项目本身长出的规章制度缺失,上线后仍会疯狂加班,补一个又一个坑。.那时候还没接触业务,还要加班加开发,人工监控值班。加、删、改、查,一个月过去了,终于有机会开始做点什么了。当时我让领导说服技术部使用Dubbo,因为它可以自动发现服务和扩展服务,无需配置。它是一个非常流行的RPC框架。但是由于当时我们没有技术权威,这件事情很难推进,一切以稳定为主。我用过Dubbo,一直不明白的是为什么Dubbo在使用ZooKeeper的时候可以自动扩容?服务可以自动发现吗?这一定和ZooKeeper有关系。由于我是一个好奇的开发者,所以开始在周末晚上和上下班路上自学ZooKeeper,什么序列节点,***节点,临时节点,什么树存储,动态监控和通知。最后不看Dubbo的源码突然明白:Dubbo的服务提供者和服务消费者都配置了一个服务名。如果我把服务路径集合存放在ZooKeeper的一个名称节点下,那么每次添加新服务或者下线服务都会通知任何监听这个名称的客户端?(后来才知道这个叫命名空间命名服务),Dubbo肯定是用了Zookeeper的命名服务来实现服务的动态发现!大多数程序员在使用HttpClient时都会使用一个名为HttpHelper的工具类。我的改造是从工具类HttpHelper开始,让程序员传递自己服务的ip、端口、serviceName、destinationName、zookeeperUrl,然后我在工具类中封装了调用路径列表,封装了两个负载均衡算法:ip_hash,随机数。(其实我只会写这两个)。在公司的四次迭代中,他们在快速发展业务的同时,逐渐将自己编写的HttpHelper工具类替换为我编写的工具类。最后,他们能够去掉slb,实现简单的HTTP服务动态发现。当时反对的声音其实挺大的,但是对运维的要求更高,配置url太麻烦了!当时公司架构重组,受到领导赏识。我被调到技术部,成为基础平台研发部的TeamLeader,管理几个程序员。痛点二:缺少配置中心解决了第一个痛点之后,想在写增删改查的同时解决第二个痛点:配置问题。以前每次上线部署一个程序,每次都得一个个服务器改配置。我想,我在这种逐个服务器的配置更改上浪费了我的时间。我真的不甘心。而且这样改配置也容易出错。虽然公司没有主动问写什么。(公司的主要重心还是在功能和业务的实现上。)那时候加班没那么辛苦。程序员做完增删改查就回家了。我还在想如何实现配置中心。当时微服务的概念很火,学习了Spring-cloud-config。我知道有个东西叫配置中心。是的,我们还需要一个配置中心来集中配置和管理。既然掌握了ZooKeeper,自然知道做配置中心的想法。半个月写完,时间主要浪费在写页数上。(汗,作为一个后台程序员,我承认自己的页面能力是比较差的)当然这期间也做了一些修改。没想到ZooKeeper有Curator这样好用的客户端。之前一直在用的原生org.apache.zookeeper客户端运行,监控消费后又要监控。写完配置中心,也是一个周末发到群里,推广了。这一次,由于公司人员的团结性提高了很多,而我已经是群里的TeamLeader了,我就先在群里普及一下。而且,我在集团外的游说和宣传也没有那么困难。最终每个服务都登陆了配置中心,实现了一个变更,处处生效,传说中的配置热更新也实现了。这些没有任何先进的技术,它们只是依赖于一个ZooKeeper。做完这一切,我已经感受到了做技术的快乐。同时,我的领导也觉得让我写增删改查是一种浪费。他让我把手头的任务都分配给组员,我去解决别人的问题。问题...我获得了更多时间来推动自己并改善公司的基础设施。痛点三:缺乏缓存框架接下来,我以为我就没事了,但是感谢左耳听风的一个专栏,他说描述一个业务(DSL)比写一个业务更容易维护,很多人在公司都在用Redis缓存,但是用的库不一样,经常出现各种奇怪的问题,调试起来极其麻烦。当然最后还是看不下去,决定自己写一个缓存框架,因为看到自己组员写的代码跟业务严重耦合,一会儿操作Redis,一会儿操作数据库尽管。我发现了这个痛点,在研究了Spring的AOP和他的@Transtional注解是如何实现的之后,我最终决定自己动手写一个微型的缓存框架。基本思路是在完全不侵入业务代码的情况下,通过可插拔的@CacheEnable(key=xxxx,timeout=xxx...)实现Redis缓存。如果没有,只需删除方法上的注释即可。手写这个Redis缓存框架花了半个月时间。毕竟我的技术能力还是有限的。如何实现AOP和Spring的融合,如何抽象等等,每天写之前都会让我思考很久,有时候一天一行代码都写不出来。期间看了一本书,名叫《面向对象编程》,里面说面向接口编程靠的是抽象,而不是具体的实现……我突然好像打通了任督二脉。我依赖CacheHandler中的CacheStorage接口,注入了RedisCacheStorage作为实现类。因此,我的框架可以同时支持redis、memcache、local。写完这个框架,我总结了三个抽象点:1.序列化方式(jdk,protobuf,thirtyft,json)2.Scriptparser方式(也就是解析key的方式:比如可以用spel或者ognl:"userId"+#user.id)3.缓存实现(redis、memcache)。后来从刘大的码农公众号写的一篇文章中日志系统的设计中了解到“正交”这个词,大概就是“正交”的意思。最尴尬的是Spring已经实现了,叫做SpringCache。汗。(码友注意:那篇文章叫《一个著名的日志系统是怎么设计的》)后面的事情我就不细说了,大概是从私有框架到公共成熟库的转变,最后用上了Dubbo框架。至于我自己,只是明白了一些以前无法理解的东西:为什么Dubbo可以改变一个组件的配置,那个组件改成不同的实现。(面向接口编程)看Mybatis的源码也没有那么难。两年前是完全不可能做到的。当然,我也变得更加热爱科技。那我想跟大家分享一下我这两年的经历。1.作为程序员,要懂得挖掘自己,不能只实现业务功能,不能只等着领导布置任务。功能耦合,代码编写速度慢,运维麻烦。这些都是潜在的需求。我们现在加班是为了避免以后加班,是为了提高自己的效率,也是为了停止原地踏步。2、一定要真正学好一门技术。在我的实际工作中,我发现有些用了一年Git的同学,连GitHub项目拉到本地都不知道,反而会把GitLib项目拉到本地。程序启动异常。有同学从网上找了一个jar包导入到项目中,但是问他为什么把jar包导入到项目中后代码启动正常,他也不知道。有的同学用了一年Maven,却不知道mvncompile是什么意思,只知道mvnpackage就是打包。这些都不是真正学的一门技术,只是在工作中生搬硬套,只是复制粘贴,然后复制粘贴用于下一个项目,模仿别人的代码写逻辑,这是你学不会的东西。我想你肯定会有时间去学习这些东西的,网上有很多资料和教程。一定要知其然,知其所以然,千万不能把配置方法改成一模一样你就看不懂了。3、掌握公司的技术栈,需要深挖。公司用的什么rpc框架?如何使用?原理是什么?公司用的nginx,如何配置nginx。公司使用配置中心,什么是配置中心?公司的负载均衡框架是做什么用的,存在哪些问题?我写了一个缓存框架,你是不是有研究它是如何实现的冲动?保持技术上的好奇心很重要。我认识的一个同学,来我们公司后,简历上说会SSM。后来经历了我的配置中心的演变,学会了使用。后来他离职了,简历上还说会SSM,别的什么都没有。本来,他要是说到配置中心,就是一大亮点。工作一年,最怕的就是挥一挥衣袖,带不走一朵云。4、善于挖掘。总有一些亮点和金子,只是你找不到。我在我们公司学到的一个安全设计就是token机制,它改变了我的观念。以前一直以为单点登录只能session共享。现在我知道你也可以使用时间换空间的方法,使用令牌。签名代替了sessionId,让登录过程变成了无状态的计算……这就是我发现的,很多程序员根本无法实现这些技术亮点,融进自己的脑子里,变成自己的东西。5、利用碎片化时间学习,不要总抱怨时间不够用。学习是枯燥的,但是当你收到学习带来的巨大红利时,你就会越来越想学。我个人的体会是,当我写的配置中心和缓存框架投入生产并得到了我想要的效果后,我现在更喜欢学习,对技术也更痴迷了。我的技术能力不强。很多事情因为我的兴趣逐渐被激发,因为我的热爱而发生了质的变化。6、多思考,正确执行业务。你有没有观察过,同样的业务,有的人写的实现很全很稳定,而有的人写的接口直接调用就可能会报错。很多程序员在写代码的时候只关心正常分支的逻辑,从来不考虑异常逻辑的处理。在写业务代码的时候,多分析用户场景,会避免很多问题。比如接口参数的校验,可以根据使用场景写额外的适配和容错。比如界面中有一个字段A,这个字段是否区分大小写?如果用户在此字段中输入额外的空格怎么办?如果你从业务分析中能发现字段大小写不敏感,我会把所有字段都转成小写进行对比。空格不是正常参数的一部分。我将删除空格以允许简单的容错。那么,你可能会避免哪天某个业务人员来找你,你为什么告诉我这个参数不存在,因为我写对了。不要小看业务代码,你不需要掌握多高深的技术原理,只要你能稳健的实现业务逻辑,就已经很考验你的能力了,说明你是一个喜欢做事的人思考并注意细节。结语现在越来越喜欢研究源码和底层了。随之而来的是,我之前的一些疑惑也就解开了。这当然是因为我收到了积极的反馈,我的努力会得到回报。现在被公司里的一些程序员误认为是大神。当然,我还差得远呢。现在公司的技术和代码在逐步完善,工程规范也在逐步规范和统一。这是令人欣慰的。我最近一直在研究API网关。公司的业务并发量越来越大。我觉得需要一个入口来统一管理API,负责鉴权、鉴权、限流、熔断等一系列功能。(这些话都是在微服务课上学的)。我已经开发了其中的一部分。使用Netty接收请求,使用HttpClientPool转发请求,中间使用责任链模式做Handler中转拦截处理。我不知道什么时候完成。