若是一个项目经历了快速发展,势必在业务发展背后留下了一个很无序,结构混乱的代码,无序而混乱的代码势必形成很大的bug修复及扩展成本。数据库
说到搭建系统都在谈论高并发,大数据,而易于维护和可扩展性则被大部分人抛之脑后,增长最基础的面向对象思想和设计模式帮助咱们组织好易于维护和阅读的代码。设计模式
不要好高骛远看一下高并发,高可用的东西,作好如下这些最基础的东西,你的系统在可读性和可维护可扩展方面将会提高一倍的能力,将你们的人效从每次bug产生梳理代码的过程当中解放出来,创建标准创建原则才是架构师首先要作的。缓存
命名须要见名知义,注释则能够帮助咱们去了解当时的业务逻辑,否则后期只能经过一行行的日志去定位问题了。数据结构
考虑到IDE会帮助咱们建立变量名称,若是名称类似则存在误用可能形成很难定位的BUG,入参能够以Req结尾或者Command结尾,返回值以Resp结尾或者Result结尾。架构
Web系统的入口层是Controller,基于RPC的服务入口层每每是XxxServiceImpl,入口层应该像一本书的目录和前言部分,说明了这个方法的主要目的,同时梳理了核心的业务流程,流程不要太细或者太粗,刚恰好知足产品的需求骨骼为主,能够简单的理解为是产品PRD的信息抽象。并发
大型系统或者业务系统具备必定的复杂程度,势必在某些问题场景包含一些必要的大逻辑处理,因而创建一个胶水层代码,胶水类能够用入口层的一个方法名称做为名称定义。
胶水层代码向外暴露的public接口则为入口层的核心骨骼逻辑,将内部复杂逻辑进行封装,达到部分方法随时能够删掉,注释掉,替换掉而不影响核心骨骼逻辑的效果,能够理解为TDD,关注入参和返回值就好。
若是经过RPC或者ResultAPI和其余系统具备必定的依赖,则放到这里。
其实这层有些上DDD里面的Domain,可是DDD用很差的话在分布式微服务场景下会出现很难把控的问题。异步
在入口和业务逻辑之下基本就是Service层代码和Dao层代码了,Dao主要是和存储系统打交道,主要目的是能够随时切换到其余的存储逻辑中去,而不影响上层业务和代码。
Service则是进行必定的数据结构组织,数据结构可能来自于底层Dao,可能来自于消息队列的订阅,可能来自于Redis缓存或者Hbase等,放在这一层能够有效分离依赖系统数据和本系统数据。分布式
public class WmPoiReq { private long userId; private long wmPoiId; private int channel; }
public class WmPoiResp { }
public class Activity { int activityId; Long wmPoiId; int channel; long valida; }
public class CServiceImpl { /** * 发送积分 * @param req * @return */ public WmPoiResp wmPSendC(WmPoiReq req){ // 入参不合法,及时失败 if(null == req || req.getUserId() < 1l || req.getPId() < 1l || req.getCh() < 0){ throw new IllegalStateException("参数无效"); } PSendCHandler handler = new PSendCHandler(); // 1. 获取可用列表 List<Activity> activities = handler.getActivityList(req.getPId(), req.getUserId(), req.getCh()); // 2. 知足,进行发操做 boolean sendStatus = handler.sendC(req.getPId(), activities); // 3. 调用接口服务化发 // RPC调用服务发送 WmPoiResp resp = new WmPoiResp(); return resp; } }
public class PSendCHandler { /** * 获取可用活动列表 * @param iId * @param userId 用户id * @param channel * @return */ public List<Activity> getActivityList(long PiId, long userId, int channel){ // 1. 根据PiId, channle获取活动列表 List<Activity> activities = ... // 伪装从底层数据获取 if(activities.size() == 0) return new ArrayList<>(); // 2. 判断获取是否已过时 boolean expire = activities.size() > 0 ? activities.get(0).getValida() > new Date().getTime() : true; if(expire) return new ArrayList<>(); // 3. 判断是不是新用户 boolean freshMan = ... // 伪装从底层数据获取 if(freshMan){ // 新用户,验证是否有适用于新用户活动 Iterator<Activity> iterator = activities.iterator(); while (iterator.hasNext()){ // 检查每一个activity是否适用于新用户 } // 全部活动不适用于新用户 return new ArrayList<>(); } // 返回可用活动列表 return activities; } /** * 发券 * @param PiId 门店id * @param activities 活动集合 * @return */ public boolean sendC(long PiId, List<Activity> activities){ // 经过线程池异步发 // 同时记录缓存 return true; } }
其实总结起来很简单,增长必要的封装和抽离,经过入参和返回值把控。
用看书的思惟组织代码系统的,增长一个业务的可阅读可理解能力,在一个系统发展必定阶段以后,最让RD同窗苦恼的不是技术问题,每每是一些业务逻辑或者布丁代码,因此研发同窗要有意识的对业务和技术进行抽离,而不是简单的将技术和业务纠缠在一块儿,作好某块业务逻辑代码随时能够删掉而不影响系统的能力。
创建适当的代码命名规则,避免IDE带来的没必要要的误用。
丰富wiki及文档,涉及到测试用例,数据库字段文档,产品PRD等。微服务