사실 우리가 자주 이야기하는 "좋은"과 "나쁜"은 코드 품질에 대한 설명입니다. "좋음"은 일반적으로 고품질 코드를 의미하고, "나쁨"은 일반적으로 품질이 낮은 코드를 의미합니다. 코드 품질에 대한 설명에 관해서는 "좋다", "나쁘다"와 같은 비교적 간단하고 조잡한 설명 외에도 많은 다른 설명을 자주 듣습니다. 이러한 설명 방법은 의미가 더 풍부하고, 더 전문적이며, 더 자세합니다. 일반적으로 가독성, 유지 관리성, 확장성, 재사용성, 유연성, 테스트 가능성 등 여러 가지 기준이 있습니다.
가독성
소프트웨어 디자인 전문가인 마틴 파울러(Martin Fowler)는 이렇게 말했습니다. 어떤 바보라도 컴퓨터가 이해할 수 있는 코드를 작성할 수 있습니다. 좋은 프로그래머는 인간이 이해할 수 있는 코드를 작성합니다." 중국어로 번역하면 "어떤 바보라도 컴퓨터가 이해할 수 있는 코드를 작성할 수 있습니다." "좋은 프로그래머는 사람이 이해할 수 있는 코드를 작성할 수 있습니다." Google에는 가독성이라는 인증도 있습니다. 이 인증을 획득한 엔지니어만이 코드 검토 중에 다른 사람이 코드를 제출하도록 승인할 수 있습니다. 결국 코드를 작성하고 실행하는 횟수보다 코드를 읽는 횟수가 훨씬 더 중요하다는 것을 알 수 있습니다.
저는 개인적으로 코드 가독성이 코드 품질을 평가하는 가장 중요한 지표 중 하나여야 한다고 믿습니다. 코드를 작성할 때 코드가 읽고 이해하기 쉬운지 항상 고려해야 합니다. 또한 코드의 가독성은 코드의 유지 관리성에 큰 영향을 미칩니다. 결국, 버그를 수정하든, 기능 코드를 수정하고 추가하든, 가장 먼저 해야 할 일은 코드를 이해하는 것입니다. 코드를 잘 이해하지 못하면 고려가 부족하여 새로운 버그가 발생할 가능성이 매우 높습니다.
가독성이 매우 중요하므로 코드의 가독성을 어떻게 평가해야 할까요? 코드가 코딩 표준을 준수하는지, 네이밍이 의미가 있는지, 코멘트가 상세하게 작성되었는지, 함수 길이가 적절한지, 모듈 구분이 명확한지, 높은 응집력과 낮은 결합도를 충족하는지 등을 확인해야 합니다. 긍정적인 측면에서 모든 평가 지표를 포괄하는 목록을 제공하는 것이 어렵다는 점도 느낄 수 있을 것입니다. 이것이 바로 가독성을 수량화할 수 없는 이유이기도 합니다.
사실 코드 리뷰는 코드의 가독성을 테스트하는 좋은 방법입니다. 당신이 작성한 코드를 동료가 쉽게 읽을 수 있다면 코드의 가독성이 매우 좋다는 뜻이고, 동료가 코드를 읽을 때 질문이 많다면 코드의 가독성을 높여야 한다는 뜻입니다
Maintainabilitymaintainability
일반적으로 원래 코드 디자인을 파괴하지 않고 새로운 버그를 가져오지 않고 신속하게 버그를 수정하거나 코드를 추가하는 능력을 말하며 코드의 유지보수성이 좋음을 나타냅니다. 코딩 개발에 있어 소위 "유지 관리"란 버그 수정, 기존 코드 수정, 새 코드 추가에 지나지 않습니다. 소위 "코드 유지 관리가 쉽다"는 것은 원래 코드 디자인을 파괴하거나 새로운 버그를 도입하지 않고도 코드를 빠르게 수정하거나 추가할 수 있음을 의미합니다. 소위 "코드 유지 관리가 쉽지 않다"는 것은 코드를 수정하거나 추가하려면 새로운 버그가 발생할 위험이 크고 완료하는 데 오랜 시간이 걸린다는 의미입니다.
Extensibility
향후 새로운 요구 사항에 직면하여 변경되는 코드의 능력 일반적으로 새로운 요구 사항을 개발할 때 원본 코드를 수정하지 않고도 원본 코드를 개발할 수 있습니다. 수정이 거의 없으므로 일반적으로 일부 기능 확장 지점이 예약됩니다.
재사용성
1. 단위 테스트 작성이 쉬운가요?
이러한 치수는 코드 치수를 판단하는 데 있어 더 중요한 지표 중 일부입니다.
2 지도 이론
높은 응집력과 낮은 결합도는 거의 모든 프로그래머가 이야기하는 것이지만 이 용어는 너무 광범위하고 정확하기 때문에 똑똑한 프로그래머들은 품질을 측정하기 위해 몇 가지 객체 지향 설계 원칙을 제시했습니다. 코드:
개방-폐쇄 원칙 OCP(개방-폐쇄 원칙)
단일 책임 원칙 SRP(단일 책임 원칙)
종속성 역전 원칙 DIP(종속 역전 원칙)
최소 지식 원칙 ( 최소 지식 원리)) / Demeter 법칙
Liskov 대체 원리 LSP(Liskov 대체 원리)
인터페이스 분리 원리 ISP(인터페이스 분리 원리)
조합/집계 재사용 원리 CARP(Composite/Aggregate Reuse) 원칙)
모두가 이 이론을 잘 알고 있어야 합니다. 이는 우리가 코드를 작성할 때 지침이 됩니다. 이러한 원칙에 따라 개발된 코드는 즉, 이러한 원칙을 사용할 수 있습니다. 코드의 품질을 측정하는 원칙.
모든 엔지니어는 고품질의 코드를 작성하고 싶어하며, 성장하지 않고 남의 비난을 받는 나쁜 코드를 계속 작성하고 싶지 않다고 믿습니다. 그렇다면 어떻게 고품질 코드를 작성할 수 있을까요? 지금까지 고품질 코드가 무엇인지에 관해 가장 일반적으로 사용되고 중요한 평가 지표 7가지에 대해 이야기했습니다. 따라서 고품질 코드를 작성하는 방법을 묻는 것은 유지 관리하기 쉽고, 읽기 쉽고, 확장하기 쉽고, 유연하고, 간결하고, 재사용 가능하고, 테스트 가능한 코드를 작성하는 방법을 묻는 것과 같습니다. 그러나 좋은 코드를 작성하려면 반드시 필요한 것은 아닙니다. 이는 많은 연습과 축적이 필요합니다. 다음은 간단한 예입니다.
추상적 사고는 우리 엔지니어에게 가장 중요한 사고 능력입니다. 왜냐하면 소프트웨어 기술은 본질적으로 추상 예술이기 때문입니다. 우리 엔지니어들은 매일 추상적 사고를 사용하여 문제 영역에 대해 분석, 요약, 종합, 판단 및 추론함으로써 다양한 개념을 추상화하고 개념 간의 관계를 탐구한 다음 프로그래밍 언어를 통해 비즈니스 기능을 구현해야 합니다. 코드를 작성하는 것이 아니라 요구 사항을 정리하고 개념을 명확히 하며 요구 사항에 대한 전반적인 이해를 얻는 시간입니다. 추상화 능력은 저와 제 팀이 코딩과 디자인에 있어 질적인 변화를 느끼게 해줍니다.
사례 1: 비동기식 Excel 내보내기
사실 Excel 내보내기 기능은 우리 프로젝트의 모든 곳에서 볼 수 있습니다. 특히 우리 작업에서는 우리 작업에 너무 많은 부담을 주지 않기 위해 한 번에 최대한 많은 데이터를 내보내기를 원합니다. 시스템, 빅 데이터의 경우 수량 내보내기는 일반적으로 비동기식으로 수행됩니다. 이러한 간단한 기능의 경우 어떻게 추상화해야 합니까?
일반 작성:
public String exportXXX(参数) throws Exception { //业务实现 } public String exportXXX2(参数) throws Exception { //业务实现 }
추상 작성:
실제로 각 비동기 내보내기를 비동기 작업으로 간주할 수 있으며, 각 작업별로 내보낼 수 있는 내용이 다르기 때문에 내보내기를 추상화할 수 있는 방법, 각 특정 구현 클래스는 다음과 같이 다양한 콘텐츠를 구현하고 내보냅니다.
// 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; } }
사례 2: 시스템 알림
현재 마이크로서비스가 널리 사용되는 시대에는 시스템 처리량을 향상시키기 위해 시스템 책임이 점점 더 세부화되고 각 시스템 모듈이 상호 작용해야 합니다. 따라서 이전 주문과 같은 복잡한 데이터 상호 작용 시나리오의 경우 이전 주문은 취소 과정에서 많은 시스템과 상호 작용해야 하며 매장, 창고 및 재고 모듈과 많은 상호 작용을 해야 합니다. ? 추상화하는 방법은 무엇입니까? 다음은 다양한 시스템과의 상호 작용을 할당하는 코드 예제입니다
//接口定义 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 { //业务代码实现 } }
실제로 다른 시스템과 상호 작용할 때 상호 작용할 때마다 각 상호 작용 작업을 알림 이벤트로 추상화할 수 있습니다. 알림 이벤트로 충분합니다.
조합/집합 재사용 원칙에 대해서는 실제로 프로젝트 과정에서 자주 접하게 되는데, 예를 들어 프로젝트를 진행하다 보면 각종 문서를 관리하는 경우가 많습니다. 구매 주문서, 양도 주문서 등으로, 문서마다 다양한 검증이 있을 것입니다. 먼저 건설 및 양도 주문에 대한 코드를 살펴보겠습니다. 구체적으로 다운로드하는 방법:
//接口定义 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); } }
위 내용은 Java 프로젝트 엔지니어링 예제 코드 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!