In fact, what we usually say in our mouths are "good" and "Rotten" is a description of code quality. "Good" generally means high-quality code, and "bad" generally means low-quality code. Regarding the description of code quality, in addition to relatively simple and crude descriptions such as "good" and "bad", we often hear many other descriptions. These description methods are semantically richer, more professional, and more detailed. I collected and sorted it out and listed it below. Generally, there are several standards, namely readability, maintainability, scalability, reusability, flexibility, testability, etc.
Readabilityreadability
Software design guru Martin Fowler once said: “Any fool can write code that a computer can understand. Good programmers write code that humans can understand. Translated into Chinese: "Any fool can write code that computers can understand. Good programmers can write code that humans can understand." There is even a certification within Google called Readability. Only engineers who have obtained this certification are qualified to approve others to submit code during code review. It can be seen how important the readability of the code is. After all, the number of times the code is read far exceeds the number of times it is written and executed.
I personally believe that code readability should be one of the most important indicators for evaluating code quality. When we write code, we must always consider whether the code is easy to read and understand. In addition, the readability of the code affects the maintainability of the code to a great extent. After all, whether we are fixing bugs or modifying and adding functional code, the first thing we have to do is to understand the code. If you don't understand the code well, it's very likely that new bugs will be introduced due to insufficient consideration.
Since readability is so important, how should we evaluate the readability of a piece of code? We need to check whether the code complies with coding standards, whether the naming is meaningful, whether the comments are detailed, whether the function length is appropriate, whether the module division is clear, whether it meets high cohesion and low coupling, etc. You should also be able to feel that from the positive side, it is difficult for us to give a list that covers all evaluation indicators. This is also why we cannot quantify readability.
In fact, code review is a good way to test the readability of the code. If your colleagues can easily read the code you wrote, it means that the readability of your code is very good; if your colleagues have a lot of questions when reading your code, it means that the readability of your code needs to be improved.
Maintainabilitymaintainability
1. Is unit testing easy to write?
2. When writing unit tests, you cannot rely on the environment or the excuse to call other services remotely, and mock data as much as possible , keeping the services decoupled. Although it is difficult for everyone in the team to follow this specification, our team has a mandatory requirement that each functional function cannot exceed 50 lines of code, and the code is required to be as short as possible.
These dimensions are some of the more important indicators for judging code dimensions.
2 Guiding Theory
Open-Close Principle OCP (The Open-Close Principle)
Single Responsibility PrincipleSRP (Single Responsibility Principle)
Dependency Inversion Principle DIP (Dependence Inversion Principle)
Least Knowledge Principle LKP (Least Knowledge Principle)) / Law Of Demeter
Liskov Substitution Principle LSP (Liskov Substitution Principle)
Interface Segregation PrincipleISP (Interface Segregation Principle)
combination /Aggregate Reuse Principle CARP (Composite/Aggregate Reuse Principle)
public String exportXXX(参数) throws Exception { //业务实现 } public String exportXXX2(参数) throws Exception { //业务实现 }Abstract writing method: We can actually regard each asynchronous export as an asynchronous task, and the content that each task can export are different, so the export can be abstracted as a method, and each specific implementation class can implement the export of different contents, as follows:
// export excel public interface IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception; } //样例实现类 XXXXExportTask implements IExcelExportTask { String export(BizCommonExportTask exportTask) throws Exception{ public String export(BizCommonExportTask exportTask) throws Exception { //组织数据筛选条件 TestReq queryReq = GsonUtils.toObject(exportTask.getInputParams(),TestReq.class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(),System.currentTimeMillis(),".xlsx"); String downUrl = excelService.uploadExcel(fileName, null, new Fetcher<PreOccupyModel>(PreOccupyModel.class) { //循环获取数据 @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException{ TestQueryResp resp = testFethchLogic.fetchRecord(queryReq); return pageNo > resp.getPageNum() ? Collections.emptyList() :toExcelModel(resp); } }); return downUrl; } } public class XXXXExportTask1 implements IExcelExportTask { @Override public String export(BizCommonExportTask exportTask) throws OspException { TestQuery query = GsonUtils.toObject(exportTask.getInputParams(), TestQuery .class); String fileName = String.format("%s%s%s", exportTask.getUploadFileName(), System.currentTimeMillis(), ".xlsx"); return excelService.uploadExcel(fileName, null, new Fetcher<ExportItemModel>(TestModel.class) { @Override public List<TestModel> fetch(int pageNo, int pageSize) throws OspException { return XXXXLogic.queryExportItem(query, pageNo, pageSize); } }); } } //导出任务分发器 public class ExcelTaskDispacther extends ApplicationObjectSupport { public boolean dispacthTask(Long taskId) throws OspException { updateTaskStatus(exportTask,CommonExportStatus.CREATING,TransferExportStatus.CREATING,StringUtils.EMPTY); try { String beanName = getBeanName(); ExportTaskHandler exportTaskHandler = getApplicationContext().getBean(beanName , IExcelExportTask .class); if(exportTaskHandler == null) { log.warn(String.format("任务ID[%s]写入配置错误!", taskId)); return false; } updateTaskStatus(exportTask,CommonExportStatus.CREATE_SUCCESS,TransferExportStatus.CREATE_SUCCESS,StringUtils.EMPTY); log.info(String.format("任务ID[%s]RFID为[%s]处理成功", exportTask.getId(),rfid)); return true; } catch(BusiException ex) { log.info("任务ID[{}]失败,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } catch(Exception ex) { log.info("任务ID[{}]失败,原因:{}", exportTask.getId(),ex.getMessage(),ex); updateTaskResult(); } return false; } }Case 2: System notificationIn Today, when microservices are popular, in order to improve system throughput, system responsibilities are becoming more and more detailed. Each system module needs to frequently exchange data. So for complex data interaction scenarios, such as our allocation order, the allocation order needs to be reversed with Many systems interact with each other, including stores, warehouses, and inventory modules. How should we abstract it? The following are code examples for allocating interactions with each system
//接口定义 public interface BizNotificationHandler { /** * 抛异常会当失败处理 * 是否需要重试由BizNotificationStatus返回状态来决定 * @param bizNotification * @return * @throws OspException */ BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException; } //推送调拨差异数据给库存系统 public class SyncDiffToSimsAndBackQuotaHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务逻辑实现 return BizNotificationStatus.PROCESS_SUCCESS; } } //占用库存 public class TransferOccupyInventoryHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务实现 } } //在GPDC生成新条码 public class GpdcGenerateNewBarcodeHandler implements BizNotificationHandler { @Override public BizNotificationStatus handleNotification(BizNotification bizNotification) throws OspException { //业务代码实现 } }In fact, we are interacting with other systems At that time, we can abstract each interactive action into a notification event. Every time there is an interaction, just write an event notification event. 2 Principle of combination/aggregation reuse As for the principle of combination/aggregation reuse, in fact we often encounter it during the project process. For example, we often manage various documents in the project. , such as purchase orders, transfer orders, receipt orders, etc., and there are various verifications for each document. Let's first look at a code to create a transfer order. How to download it specifically:
//接口定义 public interface TransferValidator { boolean validator(CreateTransferCtx ctx) throws OspException; } //接口实现1 public class W2sCrossPoQtyValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //较验器代码实现 } //接口实现2 public class W2sStoreBarcodeSaleLimitValidator implements TransferValidator { @Override public boolean validator(CreateTransferCtx ctx) throws OspException { //较验器代码实现 } } //较验器组装 public class TransferValidators { public ValidatorChain newChain() { return new ValidatorChain(); } public class ValidatorChain { private final List<TransferValidator> validators = new ArrayList<>(); public ValidatorChain qtyValidator() { validators.add(qtyValidator); return this; } public ValidatorChain transferRouteCfgValidator() { validators.add(transferRouteCfgValidator); return this; } public ValidatorChain prodValidator() { validators.add(prodValidator); return this; } public ValidatorChain w2sWarehouseStoreValidator() { validators.add(w2sWarehouseStoreValidator); return this; } public ValidatorChain w2sStoreBarcodeSaleLimitValidator() { validators.add(w2sStoreBarcodeSaleLimitValidator); return this; } public ValidatorChain w2sAssignPoValidator() { validators.add(w2sAssignPoValidator); return this; } public ValidatorChain w2sCrossPoValidator() { validators.add(w2sCrossPoValidator); return this; } public ValidatorChain w2sCrossPoQtyValidator() { validators.add(w2sCrossPoQtyValidator); return this; } public ValidatorChain w2sCross4XupValidator() { validators.add(w2sCross4XupValidator); return this; } public ValidatorChain repeatLineValidator() { validators.add(repeatLineValidator); return this; } public ValidatorChain sstradeBarcodeValidator() { validators.add(sstradeBarcodeValidator); return this; } public ValidatorChain s2wWarehouseStoreValidator() { validators.add(s2wWarehouseStoreValidator); return this; } public boolean validator(CreateTransferCtx ctx) throws OspException { for (TransferValidator validator : validators) { if (!validator.validator(ctx)) { return false; } } return true; } } } //业务代码使用 public interface TransferCreator { boolean createOrder(CreateTransferCtx ctx) throws OspException; } public abstract class DefaultTransferCreator implements TransferCreator { @Override public boolean createOrder(CreateTransferCtx ctx) throws OspException { validator(ctx) //实现业务逻辑 } protected abstract boolean validator(CreateTransferCtx ctx) throws OspException; } //店仓调拨单 public class S2wRefundCreator extends DefaultTransferCreator { //较验器自由组装 @Override protected boolean validator(CreateTransferCtx ctx) throws OspException { return transferValidators.newChain() .qtyValidator() .transferRouteCfgValidator() .prodValidator() .validator(ctx); } }
The above is the detailed content of Java project engineering example code analysis. For more information, please follow other related articles on the PHP Chinese website!