美文网首页
我的程序员之路

我的程序员之路

作者: 若兮相言 | 来源:发表于2023-05-22 02:21 被阅读0次

    做程序员的时间里, 伴随自己的热爱走到今天,总结出一些经验,供大家参考,也希望和更多人找到共鸣,仅此而已,也欢迎大家在技术的范畴尽情讨论。独立思考,敢于质疑,搞懂为什么,怎么做。

    一、设计篇

    按功能聚合代码

    受传统MVC思想的影响,大多数java web软件的分包结构是按controllerdao, service等这样的结构,很多没什么关联性的controller、dao、service都放在了同一个包下,这样的分包结构,会使得程序员在关注某一个功能时,在IDE中来回的寻找他需要的service,dao等。特别是类的数量特别多时,频繁的找类,是一件浪费心力的事情。

    事实上mvc只是技术上的分层,软件的设计思想;按照功能来聚合代码和分包更加的科学,这使得程序员在关注处理一个功能模块的时候不用来回的寻找,且有助于设计时模块化这些代码。可以在一个功能包下,再去划分controller,service等这些技术包。

    用字典还是枚举硬编码?

    字典通常设计为单独的表, 可以在UI上灵活增减,枚举一般硬编码在代码中。

    1. 当系统并不关心这个数据是什么,而只是需要一个数据范围的约束时,使用字典,且由于字典表可以灵活增减,所以最好存储文本不存储字典表的ID(或者设置为系统字典,不可随意删除),前端一般可设计为自动完成组件
    2. 当每个数据类型涉及到不同的逻辑,在系统中需要判断处理,且每增加一种类型,都需要编码实现一部分功能时,使用枚举写死更好。通常这样的功能逻辑中也会使用到这些数据,使用枚举也可以保持类型安全(这里如果再使用字典实现,还需保持程序和数据的一致性,徒增复杂度)
    3. 当只有少部分数据需要系统处理不同的逻辑,其他数据都是一样的逻辑,且会有增减,这时可以将数据分为系统和非系统,系统数据硬编码程序中写死ID。如默认的管理员角色,和普通角色,这时如果有不同的环境,应当统一ID,并在系统启动阶段校验这些数据的合法性,系统初始化阶段自动或手动初始化这些数据。

    不为了抽象而抽象

    有一些系统中,为了实现“面向接口编程”,每个Service类都去抽象了接口出来,实际上这些接口的实现类只有一个,整个项目连一个多实现的Service类都没找到,以为这样就是面向接口编程,其实是自欺欺人。相反不写接口,直接写实现类,需要的接口的时候再去抽象接口,减少复杂度和无用编码。有一个理由是为了使用JDK动态代理来提高性能,事实上JDK和CGLIB在性能上的差异根本没到我们必须选择某一个的程度,而且,云原生时代无状应用扩容伸缩非常便利,完全可以补足这一点。

    优化代码,哪怕只是一点点

    有时候费了很大功夫,才发现只是少写了一行代码,或者只是简单了一点点,到底值得吗?
    我问过自己这个问题,是不是有点小题大做,我想不是的。每一个小的优化点都降低了系统的一点点复杂度,别小看这一点点复杂度,这大大降低了程序员阅读代码时的心智损耗,把一个屋子里的东西分类整理好,把他们放到各自的盒子里,寻找起来比乱糟糟的屋子好找多了对吧。当一个系统的每个模块都复杂一点点,那你维护这个系统的过程时,大脑考虑的东西就多了很多,出现BUG的可能性就多了一些,写一个hello world出BUG的几率比写一个cms小得多。想想这样的场景:老板问你这个改动需要几天?你思考了半天觉得改动的东西很多还怕出BUG。需求浮在水面,需求背后的实现却是一座冰山藏在水下!而这座冰山需要在工程的各个角落小心敲打让它变小

    模型转换代码不要写在Service中

    DO DTO VO PO BO,各种模型类之间需要进行转换时,往往应在模型类中提供of, valueOf等这样的方法,在这些方法中时间模型转换的逻辑,避免service中出现冗长的转换代码,影响阅读,service中主要体现业务的逻辑,如出现长篇幅的类型转换代码,在阅读起来会耗费更多心力。且of,valueOf这样的方法亦可被spring的类型转换系统识别(ObjectToObjectConverter),在一些地方可以使用spring的类型转换系统来转换模型对象

    像新人一样写注释

    在编写代码注释时,往往是最了解程序运行逻辑的时候,这时容易因为知识的遮蔽性导致只描述了当时编写人认为需要描述的内容,一个好的办法是以一个刚接手这个项目的新人的角度来思考,到底应该将注释写到什么程度来帮助之后维护这段代码的程序员。

    允许3方失败

    在功能设计中,如果和第三方系统对接,最好要考虑调用第三方接口失败的情况(墨菲定律,请相信他一定会失败),三方的失败是否需要影响本来的业务流程,还是降级处理,先把自己的业务处理成功,之后采用人工/定时任务补偿第三方接口。这通常需要在功能上多设计几个功能。
    例如微信支付回调没收到时,系统主动拉取待支付订单的支付状态或手动点击同步按钮。
    另外一个例子是新增数据要同步给其他系统时,考虑同步失败时要不要影响自身系统的新增数据流程?有没有后续的补偿流程?
    并不是所有的三方对接都是需要允许3方失败,根据业务具体情况考虑

    追求性能还是可读性?

    性能和可读性都是判断一个程序好坏的指标,但在实际中并不是所有的优化都可以做到帕累托优化,大多数时候性能和可读性是成反比,提高性能的同时需要进行一部分可读性的牺牲。在考虑一个优化是否值得时,

    1. 应用响应速度提高多少?
    2. 用户体验是否得到提高?
    3. 目前这一功能在性能上是否是或将要成为瓶颈?
    4. 该优化导致可读性或设计的降低程度?其他的副作用?
      考虑这些问题能让自己更客观的考虑问题而不坚持于自己追求某一方面的执念。
      例如:曾遇到一位高级安卓开发工程师,为了提高性能坚持在各种业务场景中都不使用包装数据类型Integer而使用int,int不能存储null值,在一些业务场景下并不能完整表达业务的意义,当我不理解为什么使用int可以提高性能时,他给我看一篇关于包装数据类型性能测试的博文,文中大概意思是在使用了大量的(可能有几百万)包装数据类型时,性能是下降的(可能有几十毫秒,记不清了),所以得出结论:尽可能的使用基本数据类型以提高性能。在这个场景中,接口返回的数据是分页的,最多100个int类型的数据都没有,实际能提高的性能聊胜于无,而且app中也没有大量计算的场景,坚持这一点来提高性能简直就是捡了芝麻丢了西瓜。
      如果完全的追求性能,大可以直接写C语言,没有面向对象的封装,会比JAVA快很多。

    如果多注意项目的可读性,诸如“这里改起来可能会有很多问题”,“我不知道修改这里会不会出问题”这样的声音会少很多,毕竟程序运行花的是CPU的时间,维护代码花的是程序员的时间。

    尽可能无状态

    这里的标题事实上是一个缩写,完整的标题应当是“尽可能保证应用的无状态”,状态是可以存储到各个地方的,认证使用jwt替换session,就是将状态放置在了客户端,将session外置到redis,就是移动到了redis,保证后端应用的无状态,可以在容器平台的加持下非常方便的伸缩扩容,通常有状态的应用是不容易扩容的。判断一个程序有无状态最简单的办法就是,当启动两个实例时,用户访问其中一个实例1做了任何操作,再访问另一个实例2时,实例2的表现和访问实例1是一致的。

    尽量的使用类型安全

    JAVA是编译型语言,尽可能的将错误暴露在编译器是非常好的避免BUG的做法,特别是配置类的地方,能使用类型安全的配置就不使用字符串配置,在重构代码时,IDE可以更好的同时更改这些地方。如spring在一些扫描配置注解中同时提供了basePackagesbasePackageClasses,basePackageClasses是类型安全的配置。

    安全的暴露接口

    最容易产生安全问题的,就是系统的输入,对于前端的传参应当做充分的校验,例如一个状态字段一般只能在某几个状态之间进行变化,阿里编码规约中也指出3个以上的状态就要画状态图帮助梳理业务逻辑了,因为很多时候看似线性的状态变化中隐藏了很多回溯,实际的状态变化是比较复杂的(跑题了),我要举的例子是,例如状态字段可能的值是(1,2,3),接口设计时不应该将这个状态字段的值直接传入,而应该提供操作接口去处理,待支付->已支付不是简单的0变成1,而是经过支付这个操作,已支付->已取消也不是1变成2,而是经过取消订单这个操作,接口的设计应当是支付接口或者是取消接口,而不是updateStatus(int status),没有复杂业务逻辑的状态字段页不建议这么做,参数范围太大,再加上如果没做入参校验,一旦被渗透后果可想而知

    二、安全篇

    分页大小限制

    容易被忽略的是,分页的页大小一定要进行限制,尤其C端,可以想象pageSize=999999,发送一万个请求是什么样子的。

    @生产服务器安全规范

    思考篇

    你可以让自己更懒一点

    我喜欢做程序员的一个原因就是,解决一个问题之后,以后可以一直享受这个问题的便利,这种劳动一次享受终生的感觉很让人着迷。于是,任何让我更多劳动的地方我都会想办法让机器来代替,提高效率,然后把自己解脱出来,然后去享受或者做更多这样的事。人不就是这样进步的吗?

    流程篇

    TODO

    相关文章

      网友评论

          本文标题:我的程序员之路

          本文链接:https://www.haomeiwen.com/subject/qpcutdtx.html