概要
业务系统需要尽量风格统一,让代码的可读性和易维护性得到保障,代码不可能没有bug ,得看我们在哪个阶段去解决他,自测,qa一起review
,leader review,还是需要等到线上。如果代码风格统一,在代码review 阶段可以降低bug 上线的率,统一监控、统一模板 、通过Tmoniter、 ApiTeamplate 、APIRequest 、APIResponse 这些基础类能统一返回值风格和统一监控。接下来看一下这些基础类的编写。
统一代码风格(模板编程)
阿里发布一个编码手册,哪些是作为基础的编码风格统一,我们首先看一下提供的公共模板。模板使用抽象类并且使用抽象方法process(),在使用模板时必须传入监控的Key。
/**
* Api逻辑模板, 所有的对外暴露的服务的方法实现均需要使用这个模板来编写 模板已经处理了 未知异常,监控
*
* @version $Id$
*/
public abstract class ApiTemplate {
protected Logger logger = LoggerFactory.getLogger(getClass());
protected String monitorKey;
protected ApiTemplate(String monitorKey) {
this.monitorKey = monitorKey;
}
protected void checkParams() throws BizException {
}
protected abstract APIResponse process() throws BizException;
protected void afterProcess() {
}
protected void onSuccess() {
}
protected String getCustomMessage() {
return StringUtils.EMPTY;
}
private APIResponse buildFailAPIResponse(Throwable t) {
logger.error("ApiTemplate execute fail,error msg:{}", t.getMessage(), t);
if (t instanceof BizException) {
return APIResponse.returnFail(biz.getBizErrorCode(),biz.getMessage());
} else if (t instanceof NullPointerException || t instanceof IllegalArgumentException) {
return APIResponse.returnFail(109998, t.getMessage());
} else {
String errorMes = t.getMessage();
if (StringUtils.isNotBlank(getCustomMessage())) {
errorMes = getCustomMessage();
}
return APIResponse.returnFail(109997, errorMes);
}
}
public APIResponse execute() {
long start = System.currentTimeMillis();
try {
//1.check
checkParams();
//2.handler
APIResponse result = process();
//3.after doing
onSuccess();
return result;
} catch (Throwable e) {
return buildFailAPIResponse(e);
} finally {
try {
afterProcess();
} catch (Exception e) {
logger.error("execute afterProcess fail", e);
}
}
}
}
调用示例:
@Override
public APIResponse queryBrandInfoByLandlordId(long landlordId) {
return new ApiTemplate("queryBrandInfoByLandlordId") {
@Override
protected APIResponse process() throws BizException {
return APIResponse.returnSuccess(brandService.queryBrandInfoByLandlordId(landlordId));
}
}.execute();
}
APIResponse类
public class APIResponse implements Serializable {
private static final long serialVersionUID = 5241526151768786394L;
private final String ver = "1.0";
private boolean ret;
private String errmsg;
private int errcode;
private T data;
public APIResponse() {
}
private APIResponse(T t) {
this.ret = true;
this.data = t;
this.errcode = 0;
}
private APIResponse(String errmsg, T t) {
this.ret = false;
this.errmsg = errmsg;
this.data = t;
this.errcode = -1;
}
private APIResponse(int errcode, String errmsg, T t) {
this.ret = false;
this.errmsg = errmsg;
this.errcode = errcode;
this.data = t;
}
public static APIResponse returnSuccess() {
return new APIResponse(null);
}
public static APIResponse returnSuccess(T t) {
return new APIResponse(t);
}
public static APIResponse returnFail(String errmsg) {
return new APIResponse(errmsg, null);
}
public static APIResponse returnFail(String errmsg, T t) {
return new APIResponse(errmsg, t);
}
public static APIResponse returnFail(int errcode, String errmsg) {
return new APIResponse(errcode, errmsg, null);
}
public static APIResponse returnFail(int errcode, String errmsg, T t) {
return new APIResponse(errcode, errmsg, t);
}
public String getVer() {
return ver;
}
public boolean isRet() {
return ret;
}
public void setRet(boolean ret) {
this.ret = ret;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((data == null) ? 0 : data.hashCode());
result = prime * result + ((errmsg == null) ? 0 : errmsg.hashCode());
result = prime * result + (ret ? 1231 : 1237);
result = prime * result + errcode;
result = prime * result + ((ver == null) ? 0 : ver.hashCode());
return result;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
APIResponse that = (APIResponse) o;
if (errcode != that.errcode)
return false;
if (ret != that.ret)
return false;
if (data != null ? !data.equals(that.data) : that.data != null)
return false;
if (errmsg != null ? !errmsg.equals(that.errmsg) : that.errmsg != null)
return false;
if (ver != null ? !ver.equals(that.ver) : that.ver != null)
return false;
return true;
}
@Override
public String toString() {
return "APIResponse [" +
"ver='" + ver + '\'' +
", ret=" + ret +
", errmsg='" + errmsg + '\'' +
", errcode=" + errcode +
", data=" + data +
']';
}
}
代码diff
开发提测是需要对自己的代码进行diff基本的check点。 如下:
接口
代码:所有文件名以controller结尾的代码位置
配置文件:文件名称里带有“dubbo“关键字的xml文件改动
数据存储(mysql/sqlserver/MongoDB、redis、es)
代码:确定表名、或redis的key值、或es的type值,代码改动里全局搜索相关代码位置
配置文件:文件名称里带有“datasource”、"redis"、”cache“等关键字的xml文件改动
消息
代码:确定队列名称,代码改动里全局搜索相关代码位置
配置文件:文件内容里有”队列名称“的xml文件改动
定时任务
任务平台的定时任务配置
确定定时任务名称,代码改动里全局搜索相关代码位置
apollo配置
apollo平台的修改内容
确定apollo的key值,代码改动里全局搜索相关代码位置
总结
统一的编码风格和详细的业务监控都能保持线上业务代码的高效迭代。