首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >代码的三大核心素养:如何同时兼顾可维护性、可扩展性、可测试性

代码的三大核心素养:如何同时兼顾可维护性、可扩展性、可测试性

原创
作者头像
tcilay
发布2025-12-16 10:34:46
发布2025-12-16 10:34:46
1660
举报

一、为什么这三者是 “工业级代码” 的基石?

很多后端开发者都有过这样的经历:

  • 接手老项目时,面对 “面条式代码”,改一行怕崩一片(缺乏可维护性);
  • 业务新增需求(如新增支付方式、扩展字段),需要大面积修改原有逻辑(缺乏可扩展性);
  • 想写测试验证功能,却因代码耦合严重,连 Mock 依赖都难(缺乏可测试性)。

这三者看似独立,实则相辅相成:

  • 可维护性是基础:代码能被快速理解、修改,减少协作成本;
  • 可扩展性是延伸:基于良好的维护性,应对变化时无需重构核心逻辑;
  • 可测试性是保障:通过测试验证修改的正确性,避免 “改一处崩多处”,反过来又倒逼代码结构优化。

核心目标:写出 “能抗住业务迭代” 的代码 —— 既让当前开发者省心,也让未来的自己 / 同事少踩坑。

二、可维护性:让代码 “好懂、好改”

可维护性的核心是 “降低认知负担”:任何人拿到代码,能快速理清逻辑、定位问题、安全修改。

1. 核心原则:一致性、简洁性、自解释性
  • 一致性:命名规范、代码结构、异常处理、日志格式统一(如团队约定 “布尔值用 is/has 开头”“日志必须包含业务标识”);
  • 简洁性:拒绝冗余逻辑、过度设计,用最少的代码实现核心功能;
  • 自解释性:代码本身能说明 “做什么”,注释补充 “为什么”。
2. 落地方法(附反例 / 正例)
(1)命名与注释:拒绝 “猜谜游戏”
  • 反例:
代码语言:javascript
复制
// 反例1:命名模糊public void processData(List // list是什么?用户列表?订单列表?    for (String s : list) {        if (s.length() > 6) {            // 做某些操作        }    }}// 反例2:注释冗余/无效public int add(int a, int b) {    // a加b,返回结果(代码本身已说明,注释多余)    return a + b;}
  • 正例:
代码语言:javascript
复制
// 正例1:命名精准public void filterInvalidUserIds(List<String> userIds) { // 明确是“过滤无效用户ID”    for (String userId : userIds) {        if (userId.length() > 6) { // 为什么是6?注释补充背景            // 兼容老系统:老用户ID为6位以上,新用户为6位,仅保留新用户ID            validUserIds.add(userId);        }    }}
(2)模块化拆分:拒绝 “大泥球代码”
  • 反例:一个UserService包含用户注册、登录、信息修改、权限校验、订单查询等所有逻辑,上千行代码;
  • 正例:按功能拆分模块,每个模块职责单一:
代码语言:javascript
复制
com.example.user├── service/│   ├── register/  # 注册相关│   │   ├── UserRegisterService.java  # 注册核心逻辑│   │   └── UserRegisterValidator.java  # 注册参数校验│   ├── login/     # 登录相关│   └── profile/   # 个人信息相关└── model/    ├── dto/       # 入参/出参DTO    └── po/        # 数据库实体
(3)控制逻辑复杂度:拒绝 “嵌套地狱”
  • 反例:多层 if-else 嵌套,逻辑绕圈:
代码语言:javascript
复制
public String getDiscount(User user, Order order) {    if (user != null) {        if (user.isVIP()) {            if (order.getAmount().compareTo(new BigDecimal(1000)) > 0) {                return "8折";            } else {                return "9折";            }        } else {            if (order.getAmount().compareTo(new BigDecimal(1000)) > 0) {                return "9.5折";            } else {                return "无折扣";            }        }    } else {        return "无折扣";    }}
  • 正例:扁平化逻辑,用 “卫语句” 提前返回,或用策略模式:
代码语言:javascript
复制
public String getDiscount(User user, Order order) {    // 卫语句:提前处理异常场景    if (user == null || !user.isVIP()) {        return order.getAmount().compareTo(new BigDecimal(1000)) > 0 ? "9.5折" : "无折扣";    }    // 核心逻辑简化    return order.getAmount().compareTo(new BigDecimal(1000)) > 0 ? "8折" : "9折";}

三、可扩展性:让代码 “能加、能改”

可扩展性的核心是 “拥抱变化”:当业务新增需求、修改规则时,无需重构核心逻辑,仅通过 “新增代码” 或 “配置调整” 实现。

1. 核心原则:开闭原则、依赖抽象、最小修改
  • 开闭原则:对扩展开放,对修改关闭;
  • 依赖抽象:依赖接口 / 抽象类,而非具体实现;
  • 最小修改:新增功能时,修改的代码行数越少越好。
2. 落地方法(附反例 / 正例)
(1)面向接口编程:解耦实现与调用
  • 反例:硬编码依赖具体实现,新增功能需修改原有逻辑:
代码语言:javascript
复制
public class OrderPaymentService {    // 硬编码依赖支付宝实现,新增微信支付需修改此类    private AlipayService alipayService = new AlipayService();        public boolean pay(Order order) {        return alipayService.pay(order.getOrderNo(), order.getAmount());    }}
  • 正例:依赖接口,新增实现无需修改核心逻辑:
代码语言:javascript
复制
// 1. 定义支付接口public interface PaymentProvider {    boolean pay(String orderNo, BigDecimal amount);}// 2. 支付宝实现public class AlipayProvider implements PaymentProvider {    @Override    public boolean pay(String orderNo, BigDecimal amount) { /* 支付宝逻辑 */ }}// 3. 微信支付实现(新增,无需修改原有代码)public class WechatPayProvider implements PaymentProvider {    @Override    public boolean pay(String orderNo, BigDecimal amount) { /* 微信逻辑 */ }}// 4. 核心服务依赖接口public class OrderPaymentService {    private final PaymentProvider paymentProvider;        // 构造函数注入,灵活切换实现    public OrderPaymentService(PaymentProvider paymentProvider) {        this.paymentProvider = paymentProvider;    }        public boolean pay(Order order) {        return paymentProvider.pay(order.getOrderNo(), order.getAmount());    }}
(2)配置化与插件化:避免硬编码规则
  • 反例:将业务规则写死在代码中,修改规则需重新部署:
代码语言:javascript
复制
public class DiscountService {    // 硬编码:VIP折扣8折,普通用户9.5折,修改需改代码    public BigDecimal calculateDiscount(User user) {        return user.isVIP() ? new BigDecimal("0.8") : new BigDecimal("0.95");    }}
  • 正例:规则配置化,修改配置无需改代码:
代码语言:javascript
复制
// 1. 配置文件(application.yml)discount:  vip: 0.8  normal: 0.95// 2. 代码读取配置@ConfigurationProperties(prefix = "discount")public class DiscountProperties {    private BigDecimal vip;    private BigDecimal normal;    // getter/setter}// 3. 核心服务public class DiscountService {    private final DiscountProperties discountProperties;        public BigDecimal calculateDiscount(User user) {        return user.isVIP() ? discountProperties.getVip() : discountProperties.getNormal();    }}
(3)预留扩展点:提前规划变化场景

核心业务中,预判可能的变化,预留扩展接口,避免后续重构。

  • 示例:电商订单状态流转,预留 “状态变更钩子”:
代码语言:javascript
复制
public class OrderStatusMachine {    // 状态变更处理器,支持扩展不同状态的自定义逻辑    private Map<OrderStatus, OrderStatusHandler> handlers = new HashMap();        // 注册处理器(扩展点)    public void registerHandler(OrderStatus status, OrderStatusHandler handler) {        handlers.put(status, handler);    }        public void changeStatus(Order order, OrderStatus newStatus) {        // 执行默认逻辑        order.setStatus(newStatus);        // 执行扩展逻辑(如订单完成后发送通知、更新库存)        OrderStatusHandler handler = handlers.get(newStatus);        if (handler != null) {            handler.handle(order);        }    }}// 扩展:订单完成后的处理逻辑public class OrderCompletedHandler implements OrderStatusHandler {    @Override    public void handle(Order order) {        // 发送通知、更新库存等    }}

四、可测试性:让代码 “能测、易测”

可测试性的核心是 “能独立验证逻辑正确性”:无需依赖复杂环境,就能通过测试用例覆盖核心场景。

1. 核心原则:依赖隔离、输入输出明确、无副作用
  • 依赖隔离:核心逻辑与外部依赖(数据库、缓存、外部接口)解耦;
  • 输入输出明确:函数 / 方法的输入(参数)和输出(返回值)清晰,无模糊状态;
  • 无副作用:避免修改全局变量、静态变量,相同输入始终得到相同输出(纯函数优先)。
2. 落地方法(附反例 / 正例)
(1)依赖注入:替换外部依赖为 Mock
  • 反例:硬编码依赖外部服务,无法 Mock,测试困难:
代码语言:javascript
复制
public class OrderService {    // 硬编码依赖库存服务,测试时需启动库存服务    private StockService stockService = new StockServiceImpl();        public boolean createOrder(Order order) {        // 扣减库存(依赖真实库存服务)        boolean deductSuccess = stockService.deduct(order.getProductId(), order.getQuantity());        if (deductSuccess) {            // 创建订单            return true;        }        return false;    }}
  • 正例:构造函数注入依赖,测试时用 Mock 替换:
代码语言:javascript
复制
public class OrderService {    private final StockService stockService;    private final OrderMapper orderMapper;        // 构造函数注入,测试时可传入Mock对象    public OrderService(StockService stockService, OrderMapper orderMapper) {        this.stockService = stockService;        this.orderMapper = orderMapper;    }        public boolean createOrder(Order order) {        boolean deductSuccess = stockService.deduct(order.getProductId(), order.getQuantity());        if (deductSuccess) {            orderMapper.insert(order);            return true;        }        return false;    }}// 测试用例(Mockito)@Testpublic void testCreateOrder_success() {    // 1. Mock依赖    StockService mockStockService = Mockito.mock(StockService.class);    OrderMapper mockOrderMapper = Mockito.mock(OrderMapper.class);    Mockito.when(mockStockService.deduct("product_1001", 2)).thenReturn(true);        // 2. 初始化服务(注入Mock)    OrderService orderService = new OrderService(mockStockService, mockOrderMapper);        // 3. 执行测试    Order order = new Order("order_2001", "product_1001", 2);    boolean result = orderService.createOrder(order);        // 4. 验证结果    Assert.assertTrue(result);    Mockito.verify(mockStockService, Mockito.times(1)).deduct("product_1001", 2);    Mockito.verify(mockOrderMapper, Mockito.times(1)).insert(order);}
(2)拆分 “纯逻辑” 与 “副作用代码”
  • 反例:函数中混合业务逻辑与数据库操作,难以测试核心逻辑:
代码语言:javascript
复制
public BigDecimal calculateOrderAmount(List> items) {    BigDecimal amount = BigDecimal.ZERO;    for (OrderItem item : items) {        // 业务逻辑:计算金额(含折扣、税费)        BigDecimal itemAmount = item.getPrice().multiply(new BigDecimal(item.getQuantity()));        amount = amount.add(itemAmount.multiply(new BigDecimal("0.98"))); // 98折    }    // 副作用:写入数据库日志(混合逻辑,测试需依赖数据库)    orderLogMapper.insert(new OrderLog(amount));    return amount;}
  • 正例:拆分纯逻辑函数(无副作用)和副作用函数,分别测试:
代码语言:javascript
复制
// 纯逻辑函数:仅计算金额,无依赖、无副作用,易测试public BigDecimal calculateOrderAmount(List<OrderItem> items) {    BigDecimal amount = BigDecimal.ZERO;    for (OrderItem item : items) {        BigDecimal itemAmount = item.getPrice().multiply(new BigDecimal(item.getQuantity()));        amount = amount.add(itemAmount.multiply(new BigDecimal("0.98")));    }    return amount;}// 副作用函数:处理数据库操作,依赖纯逻辑函数@Transactionalpublic void saveOrderLog(List<OrderItem> items) {    BigDecimal amount = calculateOrderAmount(items);    orderLogMapper.insert(new OrderLog(amount));}// 测试纯逻辑(无需任何外部依赖)@Testpublic void testCalculateOrderAmount() {    // 准备测试数据    List> items = Arrays.asList(        new OrderItem("product_1", new BigDecimal("100"), 2),        new OrderItem("product_2", new BigDecimal("200"), 1)    );    // 执行测试    BigDecimal result = calculateOrderAmount(items);    // 验证结果(100*2 + 200*1 = 400,98折后为392)    Assert.assertEquals(new BigDecimal("392.00"), result.setScale(2));}// 测试副作用函数(Mock数据库依赖)@Testpublic void testSaveOrderLog() {    // Mock依赖    OrderLogMapper mockMapper = Mockito.mock(OrderLogMapper.class);    OrderService orderService = new OrderService(mockStockService, mockOrderMapper, mockMapper);        // 准备数据    List> items = Arrays.asList(new OrderItem("product_1", new BigDecimal("100"), 1));        // 执行测试    orderService.saveOrderLog(items);        // 验证:数据库日志被正确插入    Mockito.verify(mockMapper, Mockito.times(1)).insert(        Mockito.argThat(log -> log.getAmount().equals(new BigDecimal("98.00")))    );}
(3)避免静态方法依赖:静态方法难以 Mock
  • 反例:依赖静态工具类,测试时无法替换逻辑(如测试 “过期时间” 场景):
代码语言:javascript
复制
public class OrderValidator {    public boolean validate(Order order) {        // 依赖静态方法,无法Mock“时间”相关逻辑        return DateUtils.isAfterNow(order.getPayTime()) // 静态方法:判断付款时间是否在当前之后                && StringUtils.isNotBlank(order.getOrderNo());    }}
  • 正例:将静态工具类封装为实例依赖,测试时可 Mock:
代码语言:javascript
复制
// 1. 封装静态工具为实例类(解耦静态依赖)public class TimeValidator {    public boolean isAfterNow(Date date) {        return date.after(new Date()); // 底层仍可调用DateUtils,但对外提供实例方法    }}public class StringValidator {    public boolean isNotBlank(String str) {        return StringUtils.isNotBlank(str);    }}// 2. 依赖注入实例,而非静态方法public class OrderValidator {    private final TimeValidator timeValidator;    private final StringValidator stringValidator;        // 构造函数注入    public OrderValidator(TimeValidator timeValidator, StringValidator stringValidator) {        this.timeValidator = timeValidator;        this.stringValidator = stringValidator;    }        public boolean validate(Order order) {        return timeValidator.isAfterNow(order.getPayTime())                 && stringValidator.isNotBlank(order.getOrderNo());    }}// 3. 测试用例:Mock时间逻辑,覆盖“过期”场景@Testpublic void testValidate_fail_whenPayTimeExpired() {    // Mock工具类实例    TimeValidator mockTimeValidator = Mockito.mock(TimeValidator.class);    StringValidator mockStringValidator = Mockito.mock(StringValidator.class);        // 准备测试数据(付款时间已过期)    Order order = new Order("order_2001", new Date(System.currentTimeMillis() - 3600000));        // 设定Mock行为:模拟“付款时间已过期”    Mockito.when(mockTimeValidator.isAfterNow(order.getPayTime())).thenReturn(false);    Mockito.when(mockStringValidator.isNotBlank(order.getOrderNo())).thenReturn(true);        // 执行测试    OrderValidator validator = new OrderValidator(mockTimeValidator, mockStringValidator);    boolean result = validator.validate(order);        // 验证结果:验证失败    Assert.assertFalse(result);}
(4)控制函数粒度:避免 “大函数”,单个函数仅做一件事
  • 反例:一个函数包含参数校验、业务计算、外部调用,测试场景极多:
代码语言:javascript
复制
public boolean processOrder(OrderDTO orderDTO) {    // 1. 参数校验    if (orderDTO == null || StringUtils.isBlank(orderDTO.getProductId()) || orderDTO.getQuantity()         return false;    }    // 2. 业务计算:转换DTO为PO    Order order = new Order();    order.setOrderNo(UUID.randomUUID().toString());    order.setProductId(orderDTO.getProductId());    order.setQuantity(orderDTO.getQuantity());    order.setAmount(orderDTO.getPrice().multiply(new BigDecimal(orderDTO.getQuantity())));    // 3. 外部调用:扣减库存    boolean deductSuccess = stockService.deduct(orderDTO.getProductId(), orderDTO.getQuantity());    if (!deductSuccess) {        return false;    }    // 4. 持久化:保存订单    orderMapper.insert(order);    return true;}
  • 正例:拆分为多个小函数,每个函数职责单一,单独测试:
代码语言:javascript
复制
// 1. 参数校验函数public boolean validateOrderDTO(OrderDTO orderDTO) {    return orderDTO != null             && StringUtils.isNotBlank(orderDTO.getProductId())             && orderDTO.getQuantity() > 0;}// 2. DTO转PO函数(纯逻辑)public Order convertToOrder(OrderDTO orderDTO) {    Order order = new Order();    order.setOrderNo(UUID.randomUUID().toString());    order.setProductId(orderDTO.getProductId());    order.setQuantity(orderDTO.getQuantity());    order.setAmount(orderDTO.getPrice().multiply(new BigDecimal(orderDTO.getQuantity())));    return order;}// 3. 核心流程函数(组合小函数)public boolean processOrder(OrderDTO orderDTO) {    // 校验    if (!validateOrderDTO(orderDTO)) {        return false;    }    // 转换    Order order = convertToOrder(orderDTO);    // 扣减库存    boolean deductSuccess = stockService.deduct(orderDTO.getProductId(), orderDTO.getQuantity());    if (!deductSuccess) {        return false;    }    // 保存订单    orderMapper.insert(order);    return true;}// 测试:单独测试参数校验(无需依赖其他服务)@Testpublic void testValidateOrderDTO_fail_whenQuantityZero() {    OrderDTO orderDTO = new OrderDTO("product_1001", new BigDecimal("100"), 0);    boolean result = validateOrderDTO(orderDTO);    Assert.assertFalse(result);}// 测试:单独测试DTO转PO(纯逻辑,无依赖)@Testpublic void testConvertToOrder() {    OrderDTO orderDTO = new OrderDTO("product_1001", new BigDecimal("100"), 2);    Order order = convertToOrder(orderDTO);    Assert.assertEquals("product_1001", order.getProductId());    Assert.assertEquals(new BigDecimal("200.00"), order.getAmount().setScale(2));}
(5)避免全局状态:全局变量会导致测试相互干扰
  • 反例:使用静态变量(全局状态)存储业务数据,测试用例执行顺序会影响结果,导致测试不稳定:
代码语言:javascript
复制
public class OrderService {    // 全局静态变量:存储已处理的订单数(所有实例共享)    private static int processedCount = 0;        public boolean processOrder(Order order) {        // 业务逻辑:保存订单        orderMapper.insert(order);        processedCount++; // 修改全局状态,所有实例共享该值        return true;    }        public int getProcessedCount() {        return processedCount;    }}// 测试用例1:执行后会修改全局状态@Testpublic void testProcessOrder_case1() {    OrderService service = new OrderService();    service.processOrder(new Order("order_001"));    Assert.assertEquals(1, service.getProcessedCount()); // 预期1,执行通过}// 测试用例2:依赖测试用例1的执行结果,顺序变了就失败@Testpublic void testProcessOrder_case2() {    OrderService service = new OrderService();    service.processOrder(new Order("order_002"));    // 若先执行case2,预期2但实际是1;若先执行case1,预期2但实际是2——测试结果不稳定    Assert.assertEquals(2, service.getProcessedCount()); }

问题本质:全局状态是 “共享资源”,多个测试用例修改同一状态会导致 “测试污染”,测试结果依赖执行顺序,无法保证可靠性。

  • 正例:去掉全局静态变量,改用 “实例变量” 或 “状态上下文”,每个实例独立持有状态:
代码语言:javascript
复制
public class OrderService {    // 实例变量:每个服务实例单独持有状态,不共享    private int processedCount = 0;    private final OrderMapper orderMapper;        // 构造函数注入依赖    public OrderService(OrderMapper orderMapper) {        this.orderMapper = orderMapper;    }        public boolean processOrder(Order order) {        orderMapper.insert(order);        processedCount++; // 仅修改当前实例的状态,不影响其他实例        return true;    }        public int getProcessedCount() {        return processedCount;    }}// 测试用例1:独立实例,状态隔离@Testpublic void testProcessOrder_case1() {    OrderMapper mockMapper = Mockito.mock(OrderMapper.class);    OrderService service1 = new OrderService(mockMapper); // 实例1    service1.processOrder(new Order("order_001"));    Assert.assertEquals(1, service1.getProcessedCount()); // 稳定通过}// 测试用例2:独立实例,与case1状态互不干扰@Testpublic void testProcessOrder_case2() {    OrderMapper mockMapper = Mockito.mock(OrderMapper.class);    OrderService service2 = new OrderService(mockMapper); // 实例2    service2.processOrder(new Order("order_002"));    Assert.assertEquals(1, service2.getProcessedCount()); // 稳定通过,与执行顺序无关}
  • 进阶场景:若确实需要 “共享状态”(如统计全系统订单数),应通过 “外部存储”(如数据库、Redis)而非内存全局变量:
代码语言:javascript
复制
public class OrderStatisticService {    private final RedisTemplate> redisTemplate;    private static final String KEY = "order:processed:count";        public OrderStatisticService(RedisTemplateTemplate) {        this.redisTemplate = redisTemplate;    }        public void incrementCount() {        // 用Redis原子操作记录状态,测试时可Mock Redis        redisTemplate.opsForValue().increment(KEY, 1);    }        public Integer getCount() {        return redisTemplate.opsForValue().get(KEY);    }}// 测试用例:Mock Redis,隔离外部依赖@Testpublic void testIncrementCount() {    RedisTemplateRedis = Mockito.mock(RedisTemplate.class);    ValueOperations> mockOps = Mockito.mock(ValueOperations.class);    Mockito.when(mockRedis.opsForValue()).thenReturn(mockOps);    Mockito.when(mockOps.increment(KEY, 1)).thenReturn(1);        OrderStatisticService service = new OrderStatisticService(mockRedis);    service.incrementCount();        Mockito.verify(mockOps, Mockito.times(1)).increment(KEY, 1);    Assert.assertEquals(1, service.getCount().intValue());}
3. 可测试性常见误区

误区

后果

修正方案

依赖全局静态变量 / 单例(无注入)

测试用例相互污染,结果不稳定

改用实例变量,单例通过依赖注入暴露

函数返回 void,无输出

无法验证函数执行效果

让函数返回执行结果(如布尔值、状态对象),或通过 Mock 验证副作用

业务逻辑与 HTTP 请求 / 响应强耦合

测试需启动 Web 容器,效率低

拆分 Controller 与 Service,Service 层纯业务逻辑无 Web 依赖

测试用例依赖真实数据库 / 缓存

测试环境要求高,执行慢

用 H2 内存数据库、Mock 工具(Mockito、TestContainers)隔离外部依赖

五、三者协同:如何平衡 “可维护性、可扩展性、可测试性”

很多开发者会陷入 “过度设计” 的误区:为了追求某一个特性,导致代码复杂度飙升(比如为了可扩展性,设计十几层抽象)。核心原则是 “适度设计,按需优化”:

1. 协同关系:一个良性循环
  • 可维护性是基础:模块化、命名清晰的代码,自然更容易拆分扩展点、隔离依赖(提升可扩展性和可测试性);
  • 可测试性是保障:写测试的过程会倒逼你拆分耦合、明确输入输出(反过来优化可维护性和可扩展性);
  • 可扩展性是目标:基于前两者,代码才能 “低成本应对变化”,避免频繁重构。
2. 平衡技巧
  • 核心业务:重点优化三者,采用接口抽象、依赖注入、模块化拆分(如支付、订单核心流程);
  • 非核心业务:优先保证可维护性,无需过度设计可扩展性(如内部工具、临时报表功能);
  • 迭代优化:初期无需追求 “完美设计”,先实现核心功能,后续通过重构逐步优化(如先写简单实现,有扩展需求时再抽象接口)。

六、总结:写出 “三优代码” 的核心心法

可维护性、可扩展性、可测试性,本质都是 “降低代码的认知成本和修改成本”。落地的关键不是死记设计模式,而是记住三个核心:

  1. 拆分:按职责拆分模块、函数,拒绝 “大泥球代码”;
  2. 解耦:依赖抽象而非具体实现,隔离外部依赖和核心逻辑;
  3. 简洁:避免过度设计,用最少的代码实现核心功能,让代码 “一眼能看懂”。

优秀的后端代码,经得起业务迭代的考验,也经得起时间的考验 —— 这不仅是技术能力的体现,更是对团队和未来自己的负责。从今天开始,试着在写代码时多问自己三个问题:

  • 别人能快速看懂我的代码吗?(可维护性)
  • 新增需求时我需要改多少代码?(可扩展性)
  • 我能轻松写出测试用例覆盖核心场景吗?(可测试性)

坚持下去,你的编码能力会在潜移默化中实现质的飞跃。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、为什么这三者是 “工业级代码” 的基石?
  • 二、可维护性:让代码 “好懂、好改”
    • 1. 核心原则:一致性、简洁性、自解释性
    • 2. 落地方法(附反例 / 正例)
      • (1)命名与注释:拒绝 “猜谜游戏”
      • (2)模块化拆分:拒绝 “大泥球代码”
      • (3)控制逻辑复杂度:拒绝 “嵌套地狱”
  • 三、可扩展性:让代码 “能加、能改”
    • 1. 核心原则:开闭原则、依赖抽象、最小修改
    • 2. 落地方法(附反例 / 正例)
      • (1)面向接口编程:解耦实现与调用
      • (2)配置化与插件化:避免硬编码规则
      • (3)预留扩展点:提前规划变化场景
  • 四、可测试性:让代码 “能测、易测”
    • 1. 核心原则:依赖隔离、输入输出明确、无副作用
    • 2. 落地方法(附反例 / 正例)
      • (1)依赖注入:替换外部依赖为 Mock
      • (2)拆分 “纯逻辑” 与 “副作用代码”
      • (3)避免静态方法依赖:静态方法难以 Mock
      • (4)控制函数粒度:避免 “大函数”,单个函数仅做一件事
      • (5)避免全局状态:全局变量会导致测试相互干扰
    • 3. 可测试性常见误区
  • 五、三者协同:如何平衡 “可维护性、可扩展性、可测试性”
    • 1. 协同关系:一个良性循环
    • 2. 平衡技巧
  • 六、总结:写出 “三优代码” 的核心心法
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档