Skip to content

代码功底 ​

代码功底是架构师的基础能力,直接影响系统的质量和稳定性。优秀的代码功底体现在代码质量、异常处理、可读性和抽象能力等多个方面。

📋 目录结构 ​

💻 一、代码质量 ​

代码质量是架构师代码功底的核心体现,直接影响系统的稳定性和可维护性。

1.1 编码规范 ​

编码规范是保证代码质量的基础,统一的编码规范能够让团队协作更高效。

1.1.1 命名规范 ​

变量命名原则:

  • 使用有意义的变量名,避免使用 a、b、x 等无意义的名字
  • 遵循驼峰命名或下划线命名,保持风格统一
  • 布尔变量使用 is、has、can 等前缀
  • 常量使用全大写下划线分隔

好的命名示例:

java
// ✅ 好的命名
String userName = "admin";
boolean isActive = true;
boolean hasPermission = false;
int maxRetryCount = 3;
static final int MAX_CONNECTION_POOL_SIZE = 100;

// ❌ 不好的命名
String n = "admin";  // 无意义
boolean flag = true; // 不清楚含义
int num = 3;        // 不明确

函数命名原则:

  • 使用动词开头,清晰表达函数功能
  • 查询函数使用 get、find、query 等前缀
  • 修改函数使用 set、update、delete 等前缀
  • 布尔返回使用 is、has、can 等前缀

好的函数命名示例:

java
// ✅ 好的命名
public User findUserById(Long id) { }
public void updateUser(User user) { }
public boolean isUserActive(Long userId) { }
public List<User> queryUsersByRole(String role) { }

// ❌ 不好的命名
public User user(Long id) { }  // 不清楚是查询还是创建
public void process(User user) { }  // 不明确处理什么

1.1.2 代码格式 ​

缩进和空格:

  • 使用统一的缩进(2 空格或 4 空格)
  • 运算符前后留空格
  • 方法参数之间留空格
  • 大括号位置统一

代码格式示例:

java
// ✅ 好的格式
public class UserService {
    public User findUserById(Long id) {
        if (id == null || id <= 0) {
            throw new IllegalArgumentException("Invalid user id");
        }
        return userRepository.findById(id);
    }
}

// ❌ 不好的格式
public class UserService{
public User findUserById(Long id){
if(id==null||id<=0){
throw new IllegalArgumentException("Invalid user id");}
return userRepository.findById(id);}}

行长度控制:

  • 每行代码不超过 120 个字符
  • 长表达式拆分为多行
  • 方法参数过多时,每个参数占一行

1.1.3 代码组织 ​

类组织原则:

  • 类应该只有一个职责
  • 类的成员变量应该在顶部
  • 构造函数应该在成员变量之后
  • 方法应该按功能分组,公共方法在前

包组织原则:

  • 按功能模块组织包结构
  • 使用清晰的包命名
  • 避免循环依赖

包结构示例:

com.example.project
├── controller      # 控制器层
├── service         # 服务层
│   ├── impl       # 服务实现
│   └── dto        # 数据传输对象
├── repository      # 数据访问层
├── model          # 数据模型
└── util           # 工具类

1.2 测试覆盖 ​

完善的测试覆盖是保证代码质量的重要手段。

1.2.1 单元测试 ​

单元测试原则:

  • 测试覆盖率应该达到 80% 以上
  • 每个公共方法都应该有对应的测试
  • 测试应该独立,不依赖其他测试
  • 测试应该快速执行

单元测试示例:

java
// 被测试的类
public class Calculator {
    public int add(int a, int b) {
        if (a < 0 || b < 0) {
            throw new IllegalArgumentException("Numbers must be positive");
        }
        return a + b;
    }
    
    public int divide(int a, int b) {
        if (b == 0) {
            throw new ArithmeticException("Cannot divide by zero");
        }
        return a / b;
    }
}

// 单元测试
@RunWith(JUnit4.class)
public class CalculatorTest {
    private Calculator calculator;
    
    @Before
    public void setUp() {
        calculator = new Calculator();
    }
    
    @Test
    public void testAdd_PositiveNumbers_ReturnsSum() {
        // Given
        int a = 5;
        int b = 3;
        
        // When
        int result = calculator.add(a, b);
        
        // Then
        assertEquals(8, result);
    }
    
    @Test(expected = IllegalArgumentException.class)
    public void testAdd_NegativeNumber_ThrowsException() {
        // Given
        int a = -5;
        int b = 3;
        
        // When
        calculator.add(a, b);
        
        // Then - 应该抛出异常
    }
    
    @Test
    public void testDivide_ValidNumbers_ReturnsQuotient() {
        // Given
        int a = 10;
        int b = 2;
        
        // When
        int result = calculator.divide(a, b);
        
        // Then
        assertEquals(5, result);
    }
    
    @Test(expected = ArithmeticException.class)
    public void testDivide_ByZero_ThrowsException() {
        // Given
        int a = 10;
        int b = 0;
        
        // When
        calculator.divide(a, b);
        
        // Then - 应该抛出异常
    }
}

1.2.2 集成测试 ​

集成测试原则:

  • 测试系统各模块之间的集成
  • 测试与外部系统的交互
  • 使用测试数据库,避免影响生产数据
  • 测试后清理测试数据

集成测试示例:

java
@RunWith(SpringRunner.class)
@SpringBootTest
@Transactional
public class UserServiceIntegrationTest {
    @Autowired
    private UserService userService;
    
    @Autowired
    private UserRepository userRepository;
    
    @Test
    public void testCreateUser_Success() {
        // Given
        UserDTO userDTO = new UserDTO();
        userDTO.setName("John");
        userDTO.setEmail("john@example.com");
        
        // When
        User createdUser = userService.createUser(userDTO);
        
        // Then
        assertNotNull(createdUser.getId());
        assertEquals("John", createdUser.getName());
        assertEquals("john@example.com", createdUser.getEmail());
        
        // 验证数据库中的数据
        User dbUser = userRepository.findById(createdUser.getId()).orElse(null);
        assertNotNull(dbUser);
        assertEquals("John", dbUser.getName());
    }
}

1.2.3 测试覆盖率 ​

覆盖率指标:

  • 行覆盖率(Line Coverage):执行的代码行数 / 总代码行数
  • 分支覆盖率(Branch Coverage):执行的分支数 / 总分支数
  • 方法覆盖率(Method Coverage):执行的方法数 / 总方法数

覆盖率目标:

  • 核心业务代码:覆盖率应该达到 90% 以上
  • 工具类和辅助代码:覆盖率应该达到 80% 以上
  • 整体代码:覆盖率应该达到 80% 以上

1.3 代码审查 ​

代码审查是保证代码质量的重要环节。

1.3.1 审查要点 ​

功能正确性:

  • 代码是否实现了需求
  • 边界条件是否处理正确
  • 异常情况是否处理

代码质量:

  • 代码是否符合编码规范
  • 是否有重复代码
  • 是否有明显的性能问题

可维护性:

  • 代码是否易于理解
  • 是否有充分的注释
  • 是否有适当的文档

1.3.2 审查流程 ​


🛡️ 二、异常处理 ​

完善的异常处理机制是保证系统稳定性的关键。

2.1 异常场景 ​

系统运行过程中会遇到各种异常场景,需要妥善处理。

2.1.1 常见异常类型 ​

运行时异常:

  • NullPointerException:空指针异常
  • IllegalArgumentException:非法参数异常
  • IndexOutOfBoundsException:数组越界异常
  • ArithmeticException:算术异常

检查异常:

  • IOException:IO 异常
  • SQLException:SQL 异常
  • ClassNotFoundException:类未找到异常

自定义异常:

  • 业务异常:如 UserNotFoundException、InsufficientBalanceException
  • 系统异常:如 SystemException、ServiceException

2.1.2 异常处理策略 ​

异常处理层次:

异常处理示例:

java
// 业务异常定义
public class BusinessException extends RuntimeException {
    private String code;
    private String message;
    
    public BusinessException(String code, String message) {
        super(message);
        this.code = code;
        this.message = message;
    }
    
    public String getCode() {
        return code;
    }
}

// 业务层异常处理
@Service
public class UserService {
    public User findUserById(Long id) {
        if (id == null || id <= 0) {
            throw new BusinessException("INVALID_USER_ID", "Invalid user id");
        }
        
        User user = userRepository.findById(id);
        if (user == null) {
            throw new BusinessException("USER_NOT_FOUND", "User not found");
        }
        
        return user;
    }
}

// 全局异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public Result handleBusinessException(BusinessException e) {
        logger.warn("Business exception: {}", e.getMessage());
        return Result.failure(e.getCode(), e.getMessage());
    }
    
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public Result handleException(Exception e) {
        logger.error("System exception: ", e);
        return Result.failure("SYSTEM_ERROR", "System error, please try again later");
    }
}

2.2 资源管理 ​

系统使用的资源(内存、连接、文件等)需要妥善管理,避免资源泄漏。

2.2.1 内存管理 ​

内存泄漏防范:

  • 及时释放不再使用的对象
  • 避免循环引用
  • 使用对象池复用对象
  • 监控内存使用情况

内存管理示例:

java
// ❌ 不好的做法 - 可能导致内存泄漏
public class BadResourceManager {
    private List<Object> cache = new ArrayList<>();
    
    public void addToCache(Object obj) {
        cache.add(obj);  // 没有限制,可能无限增长
    }
}

// ✅ 好的做法 - 限制缓存大小
public class GoodResourceManager {
    private static final int MAX_CACHE_SIZE = 1000;
    private List<Object> cache = new ArrayList<>();
    
    public synchronized void addToCache(Object obj) {
        if (cache.size() >= MAX_CACHE_SIZE) {
            cache.remove(0);  // 移除最旧的元素
        }
        cache.add(obj);
    }
    
    public synchronized void clearCache() {
        cache.clear();
    }
}

2.2.2 连接管理 ​

数据库连接管理:

  • 使用连接池管理数据库连接
  • 及时关闭连接,避免连接泄漏
  • 设置连接超时时间

连接管理示例:

java
// ✅ 使用 try-with-resources 自动关闭连接
public class UserDao {
    @Autowired
    private DataSource dataSource;
    
    public User findById(Long id) {
        String sql = "SELECT * FROM users WHERE id = ?";
        
        try (Connection conn = dataSource.getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql)) {
            
            stmt.setLong(1, id);
            
            try (ResultSet rs = stmt.executeQuery()) {
                if (rs.next()) {
                    return mapRow(rs);
                }
            }
        } catch (SQLException e) {
            logger.error("Error finding user by id: {}", id, e);
            throw new DataAccessException("Error finding user", e);
        }
        
        return null;
    }
}

HTTP 连接管理:

java
// ✅ 使用连接池管理 HTTP 连接
@Configuration
public class HttpClientConfig {
    @Bean
    public CloseableHttpClient httpClient() {
        PoolingHttpClientConnectionManager connectionManager = 
            new PoolingHttpClientConnectionManager();
        
        // 设置最大连接数
        connectionManager.setMaxTotal(200);
        // 设置每个路由的最大连接数
        connectionManager.setDefaultMaxPerRoute(20);
        
        RequestConfig requestConfig = RequestConfig.custom()
            .setConnectTimeout(5000)      // 连接超时 5 秒
            .setSocketTimeout(10000)      // 读取超时 10 秒
            .setConnectionRequestTimeout(3000)  // 从连接池获取连接超时 3 秒
            .build();
        
        return HttpClients.custom()
            .setConnectionManager(connectionManager)
            .setDefaultRequestConfig(requestConfig)
            .build();
    }
}

2.3 超时控制 ​

合理的超时设置能够防止系统被长时间阻塞。

2.3.1 超时场景 ​

常见超时场景:

  • 数据库查询超时
  • HTTP 请求超时
  • RPC 调用超时
  • 文件读取超时

2.3.2 超时设置 ​

超时设置原则:

  • 根据业务特点设置合理的超时时间
  • 区分不同类型操作的超时时间
  • 提供超时后的降级方案

超时设置示例:

java
// 数据库查询超时
@Configuration
public class DatabaseConfig {
    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/test");
        config.setUsername("root");
        config.setPassword("password");
        
        // 连接超时时间 30 秒
        config.setConnectionTimeout(30000);
        // 连接最大生命周期 30 分钟
        config.setMaxLifetime(1800000);
        // 空闲连接最大存活时间 10 分钟
        config.setIdleTimeout(600000);
        // 查询超时时间 10 秒
        config.addDataSourceProperty("socketTimeout", "10000");
        
        return new HikariDataSource(config);
    }
}

// HTTP 请求超时
@Service
public class HttpService {
    @Autowired
    private RestTemplate restTemplate;
    
    public String callExternalApi(String url) {
        try {
            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> entity = new HttpEntity<>(headers);
            
            ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.GET,
                entity,
                String.class
            );
            
            return response.getBody();
        } catch (ResourceAccessException e) {
            // 超时异常处理
            logger.error("Request timeout: {}", url, e);
            return getDefaultValue();  // 返回默认值
        }
    }
}

📖 三、代码可读性 ​

可读性强的代码能够降低维护成本,提升开发效率。

3.1 命名规范 ​

良好的命名能够让代码自我解释。

3.1.1 变量命名 ​

命名原则:

  • 使用有意义的名称
  • 避免使用缩写
  • 保持命名一致性
  • 遵循团队命名规范

3.1.2 函数命名 ​

函数命名原则:

  • 使用动词开头
  • 清晰表达函数功能
  • 避免使用过长的名称

3.2 代码注释 ​

适当的注释能够帮助理解代码意图。

3.2.1 注释原则 ​

何时需要注释:

  • 复杂的业务逻辑
  • 算法实现
  • API 接口说明
  • 不明显的设计决策

注释示例:

java
/**
 * 计算用户积分
 * 
 * 积分规则:
 * 1. 基础积分:消费金额 * 0.01
 * 2. VIP 用户额外奖励:基础积分 * 0.2
 * 3. 活动期间双倍积分
 * 
 * @param amount 消费金额
 * @param isVip 是否为 VIP 用户
 * @param isActivityPeriod 是否在活动期间
 * @return 用户积分
 */
public int calculatePoints(BigDecimal amount, boolean isVip, boolean isActivityPeriod) {
    // 基础积分计算
    int basePoints = amount.multiply(new BigDecimal("0.01")).intValue();
    
    // VIP 用户额外奖励
    if (isVip) {
        basePoints = (int) (basePoints * 1.2);
    }
    
    // 活动期间双倍积分
    if (isActivityPeriod) {
        basePoints = basePoints * 2;
    }
    
    return basePoints;
}

3.3 文档同步 ​

代码文档应该与代码保持同步。

文档同步原则:

  • 代码变更时同步更新文档
  • 定期检查文档准确性
  • 使用自动化工具生成文档

🎯 四、抽象能力 ​

优秀的抽象能力是设计高质量架构的关键。

4.1 抽象设计 ​

良好的抽象能够隐藏实现细节,提供清晰的接口。

4.1.1 抽象层次 ​

抽象层次划分:

4.1.2 抽象示例 ​

抽象设计示例:

java
// 抽象接口定义
public interface PaymentService {
    /**
     * 支付接口
     * 
     * @param order 订单信息
     * @return 支付结果
     */
    PaymentResult pay(Order order);
    
    /**
     * 退款接口
     * 
     * @param orderId 订单ID
     * @return 退款结果
     */
    RefundResult refund(String orderId);
}

// 支付宝实现
@Service("alipayPaymentService")
public class AlipayPaymentService implements PaymentService {
    @Override
    public PaymentResult pay(Order order) {
        // 支付宝支付实现
        // ...
    }
    
    @Override
    public RefundResult refund(String orderId) {
        // 支付宝退款实现
        // ...
    }
}

// 微信支付实现
@Service("wechatPaymentService")
public class WechatPaymentService implements PaymentService {
    @Override
    public PaymentResult pay(Order order) {
        // 微信支付实现
        // ...
    }
    
    @Override
    public RefundResult refund(String orderId) {
        // 微信退款实现
        // ...
    }
}

// 使用抽象接口,不依赖具体实现
@Service
public class OrderService {
    @Autowired
    @Qualifier("alipayPaymentService")
    private PaymentService paymentService;
    
    public void processOrder(Order order) {
        // 使用抽象接口,可以轻松切换支付方式
        PaymentResult result = paymentService.pay(order);
        // ...
    }
}

4.2 接口设计 ​

良好的接口设计应该遵循 SOLID 原则。

4.2.1 接口隔离原则 ​

接口隔离示例:

java
// ❌ 不好的设计 - 接口太大
public interface UserService {
    void createUser(User user);
    void updateUser(User user);
    void deleteUser(Long id);
    User findUserById(Long id);
    List<User> findUsersByRole(String role);
    void sendEmail(User user, String content);
    void generateReport(User user);
}

// ✅ 好的设计 - 接口隔离
public interface UserRepository {
    void create(User user);
    void update(User user);
    void delete(Long id);
    User findById(Long id);
    List<User> findByRole(String role);
}

public interface UserNotificationService {
    void sendEmail(User user, String content);
}

public interface UserReportService {
    void generateReport(User user);
}

4.3 架构稳定 ​

稳定的架构应该能够应对需求变化。

4.3.1 扩展点设计 ​

扩展点设计示例:

java
// 策略接口 - 可扩展的扩展点
public interface DiscountStrategy {
    BigDecimal calculateDiscount(Order order);
}

// 普通折扣策略
@Component("normalDiscount")
public class NormalDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculateDiscount(Order order) {
        return order.getAmount().multiply(new BigDecimal("0.05"));
    }
}

// VIP 折扣策略
@Component("vipDiscount")
public class VipDiscountStrategy implements DiscountStrategy {
    @Override
    public BigDecimal calculateDiscount(Order order) {
        return order.getAmount().multiply(new BigDecimal("0.15"));
    }
}

// 使用策略模式,便于扩展新的折扣策略
@Service
public class DiscountService {
    private Map<String, DiscountStrategy> strategies;
    
    @Autowired
    public DiscountService(List<DiscountStrategy> strategyList) {
        strategies = strategyList.stream()
            .collect(Collectors.toMap(
                s -> s.getClass().getAnnotation(Component.class).value(),
                s -> s
            ));
    }
    
    public BigDecimal calculateDiscount(Order order, String strategyType) {
        DiscountStrategy strategy = strategies.get(strategyType);
        if (strategy == null) {
            throw new IllegalArgumentException("Unknown discount strategy: " + strategyType);
        }
        return strategy.calculateDiscount(order);
    }
}

📝 总结 ​

代码功底是架构师的基础能力,需要通过持续的学习和实践不断提升。

能力提升路径 ​

  1. 初级阶段:掌握编码规范和基本实践
  2. 中级阶段:提升代码质量和可维护性
  3. 高级阶段:设计优秀的抽象和架构

实践建议 ​

  • 编写代码时始终考虑代码质量
  • 充分测试,保证测试覆盖率
  • 参与代码审查,学习优秀代码
  • 持续重构,提升代码质量

上一章节:技术能力
下一章节:理论知识
返回目录:架构师能力图谱