从一年开发经验的视角看如何优雅编程

编程绝非易事,需要大家在日常工作中仔细钻研,下面我们从实际业务开发的角度来分析一下如何优雅地进行编程,简单可以总结几点:
1.整体理解业务
2.从开发角度分解业务
3.结合各业务点整体分析系统结构
4.针对每一个业务点进行边界分析
5.对每个功能点进行测试分析
6.快速编码


一、整体理解业务
都说业务是一切系统架构的基础,那么其也是我们在项目开发中首先要理解的内容,因为接下来的所有工作都将围绕这些业务点进行开展,如果对业务理解不透彻,那么后续很有可能出现错误、遗漏等问题,最终导致项目延期。总结这一年多的工作经验,个人认为可以通过如下几步来理解业务:

  • 提前阅读PRD,如果有时间可以将BRD也看一下;
  • 将文档中的需求点(新增、改动)摘出,带着疑问去参加PRD评审;
  • 试着将摘出的内容和PRD评审会中听到的内容在脑海中绘制成一个完整的场景(也可以进行画图梳理),绘制过程中可能会出现连接不通的点,而这些点往往就是项目中的细节或者重点,需要我们仔细思考或者向需求提出的同事进行核实;
  • 如果是在老业务基础上开展的,还需要进行关联思考,主要思考哪些部分是完全增量的,哪些是存在交集的,哪些是需要删除的等等,这些点的确认将直接影响到系统结构的设计。

经过上述四个步骤,我们就可以对业务有一个较为深入的认识了,不过在实际工作中,我们大部分人往往不可能一开始就对业务点完全吃透,反正我就做不到,哈哈。那么,如果大家真的像我一样做不到怎么办呢,我个人认为不用太担心,这些没有吃透的点会在实际编程中完全暴露出来,这个时候再完善即可,虽然一步到位显得更香,但咱不是没办法嘛。总之,这一步非常重要,我们此时此刻对业务的认知将是接下来系统设计的基础与依据。

二、从开发角度分解业务
在对业务整体情况认识之后,我们就要以一个研发者的思路去剖析它了,这个过程我们也可以称为功能点拆分。

  • 首先,我们要将整个业务按照大功能点(操作流)进行拆分,如一个加购物车的功能点、一个付款的功能点、一个订单生成的功能点、一个修改退款流程的功能点、一个投保功能点、一个退保功能点等;
  • 其次,对大的功能点按照数据流转的思路进行细拆,拿一个面向C端的投保功能进行举例:第一点,要考虑提交的保单数据如何获取,显然是需要用户进行填写的,所以我们的拆分结果为,保险产品拉取-》保险详情展示-》保险投保单表单展示-》数据填写与提交;第二点,数据提交后要如何流转,如要生成投保单,拆单,算费,聚合保单,推结算,生成投保凭证,通知用户投保结果等;第三点,流转过程中往往需要组合其他数据,那么这些数据从何处获取也是一个非常重要的点;
  • 最后,对细拆的业务点进行再分类,如哪些点要作为对外接口,哪些点要作为业务处理服务,哪些点作为补偿服务等。

经过上述的业务细化拆分,就可以将一个整体的业务量化为开发者的工作量,而这些量化后的业务才是系统设计真正的参考依据。

三、系统整体设计
根据业务的细分点,我们可以对系统结构进行设计:

  • 首先,作为对外接口(RESTful、RPC风格)的点需要一个controller层来承载;
  • 其次,作为业务处理服务,可以直接将全部点作为一个service层,亦或者将每一个单独的业务模块(如拆单、结算等)都作为一个service层,两者的区别在于是否某个模块可以直接作为一个微服务的形式从主体服务剥离出来,即具备非常好的封装性和松耦合性;
  • 然后,作为补偿服务,我们系统要考虑是否需要异常单备案,定时重试机制,而这些机制是否要融入本系统,还是直接作为独立的监控、补偿系统进行开发,如果是这样就要考虑如何抽象来适配更多的可能性,如何与服务系统进行交互等。
  • 最后,考虑各个层次之间该如何关联,是需要进行同步调用还是进行异步调用(建议使用MQ),调用过程中的幂等性、数据一致性、安全性怎么做(起码要保证数据不丢失),单点问题如何解决,流程处理性能如何保证,异常控制怎样更合理等,在整个过程中可以使用许多开发技巧,可操作性非常强,具体设计成什么样子和项目负责人的构架能力直接相关。

这一环节其实就是一个架构过程,当然,作为一名小菜鸟,我个人觉得无论整体架构成什么样子,具体编码中都要好好参考设计模式中的七个规则展开,即职责单一原则、里氏替换原则、开闭原则、依赖倒置原则、组合/聚合原则、接口隔离(单一)原则、迪米特法则。依据这些原则,结合业务点的特点做到最大程度的松耦合性和高复用性,只有这样,项目后期的迭代才能顺利进行,否则项目上线的那天就是今后痛苦的开端。

四、针对每一个业务点进行边界分析
不知道大家有没有同样的感受,在项目的整个过程中能够清晰把握每个业务点的边界真不是一件易事,这里的边界宽泛了些,具体细化可以分为功能模块的边界性模块中各个类的职责模块类中方法的职责

  • 功能模块的边界如果不够清晰将直接对模块的松耦合性、复用性和可维护性造成破坏,还拿投保模块来分析:首先投保模块只应该用来处理保单业务,这是底线,所以在封装上,模块内不要涉及其他业务内容,包括实体、枚举、常量、工具类和服务等,当然也不要将次模块的内容封装到其他模块中,一但违背了这一点,就会出现这样的场景:“假如投保模块放入了理赔模块的特有的枚举类,此时即使投保模块没有使用到这个枚举,两个模块也已经被耦合到了一起,一但后期理赔业务需要修改这个枚举,就会被迫改动投保,当然,如果投保模块使用了这个枚举类(增加了新枚举值或者使用了已有枚举值)就更加糟糕了,搞不好还得因此修改投保的相关代码”,很显然,我们应该提早对业务模块划清边界。
  • 模块中各个类的职责如果不清晰可能直接耦合本来不相关的类,并且存在编写出大类、乃至超大类的可能性,举例:一个处理投保请求的类应该包含投保数据正确性校验的内容、投保并发和幂等控制内容、投保数据存储内容、投保凭证生成内容、投保结算信息推送内容、投保响应内容组装等(当然这是按照整个投保流程的维度来划分职责的,如果发现内容太多,也可以将这个整体拆分成多个步骤式的职责来创建多个类),但是,如果将数据存储中涉及的数据库连接、SQL拼接、事务提交的内容或者结算数据分析、存库内容也放到此类中就出现了多职责,这时如果退保模块也要进行存库、推结算,势必也要用到数据库、结算方面的内容,那么无论是通过组合投保类来复用需要的内容还是直接复制一份都不是好的选择。
  • 类中方法的职责明确和类的职责类似,总之,最好不要写行数过多的方法,本着这一点来创建方法会很好的把握好各个方法的职责。

五、对每个功能点进行测试分析
关于编程,很多书中都提到了面向测试编程这个理念,即先编写单元测试,再为每个单元测试适配相应的功能。说实话,这个理念我一直不太能理解,也不知道该如何做到这一点,所以在实际工作中我也没有这样做,直到自己多次提测后被测试小姐姐啪啪打脸后才有些恍然大悟,说到这里真是惭愧!但是个人感悟还是有些不同的,首先,代码自测是一定要做的,不然真会被打脸;其次,最好在对各个功能点进行实现前要思考一下,如果功能开发完成,该如何测试它(也就是考虑一下测试用例)。这两点如果做到真的可以帮助我们对业务点的实现查漏补缺,非常有利于我们深入理解业务。

六、快速编码
隐隐记得软件工程中说过:编码在整个软件开发周期中所占的时间比例是最少的。现在看来也确实如此,因为真正费劲的内容在上面,哈哈。所以个人认为一定要在编码前做好上述五点,如果没有,写出的代码大概率是不能用的。编码虽快,但是我们也要养成一个好的编码习惯,要拒绝异味,要写机器能懂的代码,更要写出人能容易看懂的代码。


写到这里,我的一些小心得也就叙述完了,一年多下来发现了编程不易且博大精深,需要我们多多思考、好好沉淀。最后希望自己和所有身在编码职场的你越来越好,希望我的体会可以与你产生共鸣,也希望你可以分享自己的体会。

感恩今天,明天更好!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值