转至元数据结尾
转至元数据起始

不要被ctrlC、ctrlV、ctrlF所奴役。每个人可以做得更好!

不要被 `ctrl+C`、`ctrl+V`、`ctrl+F` 所奴役。每个人也许可以做得更好!

不要被 `⌘+C`、`⌘+V`、`⌘+F` 所奴役。每个人也许可以做得更好!

【代码注释】

注释,记得曾在哪本里看到解释为是代码无法解释其本身的一种无能的表现。这句话挺有道理,也并非完全正确(类的作者和编写时间),至少透露给我们一个观点:我们应该尽可能定义明确易读的代码。


在如下情况下,有必要添加注释:

方法代码与另一段代码(类/方法/属性)相关,使用@see、@link、@inheritDoc
代码编写的背景
希望使用者如何用
与之相关的文档、文本等信息


我们中台的企业API服务中有两个方法: EnterpriseVO getById(Long enterpriseId); 和 EnterpriseVO selectById(Long enterpriseId); 这两个方法 getById 是获取企业表的数据, getById 是企业信息的聚合接口,不仅包含企业表的数据,还包括了企业的发票配置、费率配置等数据。 随着企业数据量增多,消费者端调用合适的接口就变得尤为重要,例如,如果只需要获取企业表的数据,那么,调用selectById就足够了,如果调用的是 getById,那么可能就会影响业务处理时效了。
我们总不能要求调用者先去看一下实现再做选择吧。这时,重命名方法会解决一部分这个痛点,javadoc注释也是不错的实践。

/**
* 仅仅返回仅仅返回bosskg.emax_enterprise表的数据
* @param enterpriseId
* @return
*/
EnterpriseVO selectById(Long enterpriseId);
/**
* TODO: 此接口很大很大,需拆分。 求求你,不要再不加思考地调用这个接口了。
* ----->企业信息较多(如基本信息、业务配置、任务配置信息、发票邮寄信息、发票抬头信息、分账配置、风控配置、
* 登陆账号),这种all-in-one的方式已经不适合,需要按职责粒度细化为不同的接口。例如:{@link #selectEnterpriseTaskConfig(Long)}
* @param id
* @return
*/
EnterpriseVO getById(String id);



用户注册白名单的风控校验逻辑中,许多if都是return校验失败,其中有一个数据查询不到return校验通过。这种情况,需要javadoc来标明,提高可理解性。

sohoCheckResponseVO.setCode(RiskConstants.RES_SUCCESS);
if (!validate.isSuccess()) {
	sohoCheckResponseVO.setCode(RiskConstants.RES_FALSE_6000);
	sohoCheckResponseVO.setMeg(validate.getMessage());
	return sohoCheckResponseVO;
}
if (dto.getIdCard().trim().length() != 18) {
	sohoCheckResponseVO.setCode(RiskConstants.RES_FALSE_6000);
	sohoCheckResponseVO.setMeg("身份证格式有误");
	return sohoCheckResponseVO;
}
LevyBrandRiskControl levyBrandRiskControl = levyBrandRiskControlManager.getByLevyCodeAndBrandCode(dto.getLevyCode(), dto.getBrandCode());
log.info("查询落地服务商年龄限制:{}",levyBrandRiskControl);
if(ObjectUtil.isNull(levyBrandRiskControl)){
	// 风控数据查不到,则认为校验通过。
	return sohoCheckResponseVO;
}



客户申请开票,页面上展示的服务商没有过滤状态,而在提交申请时,后端程序里有过滤状态,导致客户无法申请开票。曹老师加了个新的方法。这个方法与原来的方法如何区分?如何防止日后的误用---注释的重要性


PaymentTransQueryByPAYH 调用平安银行查单接口,在付款成功的代码里,未记录付款完成时间。经与当事人开发者了解,是平安银行不返回。下面note,好代码会说话。

if (StringUtils.equals(stt, "20")) {
	//付款成功,解析map
	queryVO.setBankOrderId(resMap.get("FrontLogNo"));
	queryVO.setOrderStatus(OrderStateEnum.SUCCESS);
	queryVO.setQueryCode(stt);
	queryVO.setQueryMsg(resMap.get("Yhcljg"));
	queryVO.setHostFlowNo(resMap.get("hostFlowNo"));
	queryVO.setOrderEndTime(new Date()/**@note:平安银行不返回交易完成时间*/);


bosskg交易表拆表的重构升级里,新增的表是emax_order_detail_ext。为了降低程序复杂度,我们将 OrderDetailExtManager 的可见性限制在它所在的package里。下面class声明代码里的 /*public*/ 比没有要好,因为它传达了必要的信息————这个class不能标记public(这个class的可见性仅限当前package)。

@Service
@Slf4j
/*public*/ class OrderDetailExtManager extends ServiceImpl<OrderDetailExtMapper, OrderDetailExt> {


=========================================================================================

【日志】


别跟风, 尤其是对外暴露的统一API接口,或者是 程序里的facade方法, 你上来就把参数打印出来,你有没有考虑过元芳的感受??

先思考一下为什么记日志?
🍀为了方便排查问题
🍀埋点--例如,在某个接口里打印一行日志,可以用来分析执行次数、时段。当我们不确定某个接口方法是否在使用时,可以加个log,这样,我们就可以通过一段时间的日志情况来辅助我们决策。
🍀监控告警---例如,借助ELK等工具,基于日志中的特定异常或关键字触发告警
不需要记的东西---秘钥,一长串。再有,图片base64串、加密报文。
重复的不记。如请求一个外部api, service和api里各记一份,多余,没用,反而不利于排查问题。
如果服务稳定了,请求响应可以不记,只在异常的时候打印。

如果你写了一堆没用的或重复的log,会遭人反感的。尤其在你的代码出问题时,别人通过log排查问题的时候。

最可气是的,关键有用的逻辑你没记log,反而是记了一堆无用的重复的log。
=========================================================================================

【要有文档】


要有文档
文档不必高大上,文档是给人看的,易读。
如何编写易读的文档
1.清晰表达
-- 小师的分享
-- 混合云实施计划
2.一图胜千言
视觉内容能在短时间内产生更大的影响力,研究表明,大脑处理视觉内容的速度比文字内容快60000倍。图片比文字来说,更容易被大脑接受,大脑储存时不需要进行过多的转译,文字进入大脑后还需要用“想象力”处理成画面进行记忆。
在清晰的图片比文字更具优势。设计图


vs

vs





=========================================================================================

【硬编码(hard code)】

IDEA都不喜欢硬编码


hard-coded strings are a bad practice.


【碎碎念】


方法较多、代码行较多的类,按职责划分,将相同职责的方法放在一块儿。LevyChannelRouteServiceImpl.java
《阿里巴巴Java开发手册》14. 【推荐】当一个类有多个构造方法,或者多个同名方法,这些方法应该按顺序放置在一起,便于阅读。

.net语言中,有 #region / #endregion 指令,也是鼓励开发者尽可能将有关联的代码组织在一起。 java语言没有这个指令,也不是没办法。look bellow↓



下面代码违背正交性原则。当在properties文件里把fileSize由1024改为其他值时,请问,你那个“1M”的提示还恰当吗?谁又能保证一定会在配置文件(properties)或配置中心(如apollo)修改后,再来改这段代码中的提示​话术?- - nobody can!

@Value("${product.settle.file.size:1024}")
private Integer fileSize;

@PostMapping(value = "/bosskg/uploadSettleFile")
public Result<Void> uploadSettleFile(ImportOrderApplyDTO applyDTO, MultipartFile file) {
	...

	if (file.getSize() > fileSize * 1024) {
		return Result.err("批量付款文件不能大于1M");
	}

	....
}


【杂七杂八】


https://zhuanlan.zhihu.com/p/141394935 简评《注重实效的程序员》(《程序员修炼之道》)
方法签名 ---https://www.cnblogs.com/buguge/p/15465662.html 吓尿了,程序启动一堆异常
程序实现---异步:什么该异步,该同步的不能异步(下发,持久化更新订单状态都搞成异步了)。 能异步的才异步,异步线程里处理异步的业务(服务商下发重发)
因噎废食——使用缓存出现问题,就不用缓存了?https://www.cnblogs.com/buguge/p/17673309.html

非A即B?---对象互转,有了MapStruct,那个经年陪伴我们的基于orika的BeanMapper就要彻底废弃?
枚举的规范和沉淀,感谢我们的研发团队。

庞大的企业应用,稳定、可维护、可扩展、易于开发,相比于优雅、性能、算法往往更重要。----不靠谱程序员断章取义:性能不重要。


编写评论...