找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2629

积分

0

好友

369

主题
发表于 8 小时前 | 查看: 0| 回复: 0

从模糊需求到清晰代码的完整路径

“这个需求你来负责——用户下单后30分钟未支付要自动关闭订单,释放库存。”

当我还是初级程序员时,面对这样的需求总是直接开写代码。结果要么是不断返工,要么是代码臃肿难以维护。直到经历过几个大项目后,我才明白:比写代码更重要的,是如何思考代码

第一步:需求澄清——5W1H分析法

1.1 不要急着写代码,先问对问题

面对“订单超时关闭”需求,我会先问:

What(做什么)

  • 具体要关闭什么?只关闭订单状态,还是需要连带操作?
  • “关闭”是逻辑删除还是物理删除?

Why(为什么做)

  • 为什么是30分钟?业务依据是什么?
  • 为什么需要自动关闭?解决什么问题?

When(何时触发)

  • 精确的时间点要求?30分钟是创建时间还是更新时间?
  • 是否有例外情况?(如客服手动干预)

Who(涉及角色)

  • 系统自动执行,还是人工触发?
  • 关闭后需要通知哪些人?

Where(影响范围)

  • 只影响订单模块,还是涉及库存、优惠券等?
  • 数据一致性要求级别?

How(如何实现)

  • 实时性要求?秒级还是分钟级可接受?
  • 预计订单量?性能要求?

1.2 需求澄清的输出

经过沟通,明确需求细节:

  • 触发条件:订单创建30分钟后,状态仍为“待支付”
  • 关闭操作:订单状态变更为“已关闭”,释放库存,优惠券回退
  • 执行方式:系统自动执行,支持手动干预
  • 性能要求:5分钟内完成关闭即可
  • 数据量:日均10万订单,峰值1000单/分钟

第二步:领域建模——从业务语言到技术概念

2.1 识别核心业务实体

// 不是一上来就写getter/setter,而是先理解业务含义
public class Order{
    // 订单的唯一标识 - 业务标识符
    private String orderNo;

    // 订单的状态流转 - 业务生命周期
    private OrderStatus status;

    // 时间点 - 业务时效性
    private LocalDateTime createTime;
    private LocalDateTime payTime;
    private LocalDateTime closeTime;

    // 业务规则:是否应该关闭
    public boolean shouldAutoClose(){
        return status == OrderStatus.WAITING_PAYMENT &&
               isCreatedOver30MinutesAgo();
    }

    // 业务操作:关闭订单
    public void close(String closeReason){
        this.status = OrderStatus.CLOSED;
        this.closeTime = LocalDateTime.now();
        this.closeReason = closeReason;
    }
}

2.2 定义业务枚举和值对象

// 订单状态 - 业务状态机
public enum OrderStatus {
    WAITING_PAYMENT("待支付"),
    PAID("已支付"),
    CLOSED("已关闭"),
    DELIVERED("已发货");

    private final String desc;

    OrderStatus(String desc) {
        this.desc = desc;
    }

    // 状态流转规则
    public boolean canChangeTo(OrderStatus newStatus){
        switch (this) {
            case WAITING_PAYMENT:
                return newStatus == PAID || newStatus == CLOSED;
            case PAID:
                return newStatus == DELIVERED;
            default:
                return false;
        }
    }
}

// 订单金额 - 值对象(业务含义)
public class OrderAmount{
    private final BigDecimal originalAmount; // 原始金额
    private final BigDecimal discountAmount; // 优惠金额
    private final BigDecimal finalAmount;    // 实付金额

    public OrderAmount(BigDecimal originalAmount, BigDecimal discountAmount){
        validateAmount(originalAmount, discountAmount);
        this.originalAmount = originalAmount;
        this.discountAmount = discountAmount;
        this.finalAmount = originalAmount.subtract(discountAmount);
    }

    private void validateAmount(BigDecimal original, BigDecimal discount){
        if (original.compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("金额不能为负");
        }
        if (discount.compareTo(original) > 0) {
            throw new IllegalArgumentException("优惠金额不能超过订单金额");
        }
    }
}

第三步:技术方案设计——多种思路的权衡

面对一个业务需求,思考多种Java实现方案并进行权衡,是优秀工程师的基本功。

3.1 方案一:数据库轮询(简单直接)

适用场景:数据量小,实时性要求不高

@Component
public class OrderTimeoutChecker{
    @Scheduled(fixedRate = 60000) // 每分钟执行
    public void checkTimeoutOrders(){
        // 查询30分钟前的待支付订单
        List<Order> timeoutOrders = orderRepository
 .findByStatusAndCreateTimeBefore(
                OrderStatus.WAITING_PAYMENT,
                LocalDateTime.now().minusMinutes(30));

        for (Order order : timeoutOrders) {
            closeOrder(order);
        }
    }
}

优点:实现简单,逻辑清晰
缺点:精度低,数据库压力大,空轮询浪费资源

3.2 方案二:延迟消息(推荐方案)

适用场景:实时性要求高,系统解耦

@Service
@Transactional
public class OrderService{

    public void createOrder(CreateOrderCommand command){
        // 创建订单
        Order order = new Order(command);
        orderRepository.save(order);

        // 发送延迟消息
        sendTimeoutCheckMessage(order.getId(), 30);
    }

    private void sendTimeoutCheckMessage(Long orderId, int delayMinutes){
        Message message = MessageBuilder.withPayload(orderId)
            .setHeader("delay", delayMinutes * 60 * 1000)
            .build();
        delayQueue.send(message);
    }

    @EventListener
    public void handleOrderTimeout(OrderTimeoutEvent event){
        Order order = orderRepository.findById(event.getOrderId());
        if (order.shouldAutoClose()) {
            closeOrder(order);
        }
    }
}

优点:实时性好,解耦,节省资源
缺点:依赖消息队列,消息可能丢失

3.3 方案三:时间轮算法(高性能方案)

适用场景:海量数据,高性能要求

@Component
public class TimingWheel{
    private final WheelBucket[] wheel;
    private int currentTick;

    public void addTimeoutTask(Long orderId, int delaySeconds){
        int ticks = delaySeconds;
        int index = (currentTick + ticks) % wheel.length;
        wheel[index].addTask(orderId);
    }

    @Scheduled(fixedRate = 1000)
    public void tick(){
        processCurrentBucket();
        currentTick = (currentTick + 1) % wheel.length;
    }
}

优点:性能极高,内存占用小
缺点:实现复杂,调试困难

第四步:架构设计——平衡复杂性和扩展性

4.1 分层架构的职责划分

Controller层:HTTP协议适配,参数校验,格式转换
    ↓
Service层:业务逻辑编排,事务控制,异常处理
    ↓
Manager层:通用业务能力,组件编排
    ↓
Repository层:数据持久化,缓存处理
    ↓
基础设施:数据库,消息队列,缓存等

4.2 订单关闭的完整实现

// Controller层:关注HTTP交互
@RestController
@RequestMapping("/orders")
@Validated
public class OrderController{

    @PostMapping
    public ApiResult<String> createOrder(@Valid @RequestBody CreateOrderRequest request){
        String orderNo = orderApplicationService.createOrder(request);
        return ApiResult.success(orderNo);
    }
}

// ApplicationService层:业务用例编排
@Service
@Transactional
public class OrderApplicationService{

    public String createOrder(CreateOrderCommand command){
        // 1. 参数校验
        validationService.validate(command);

        // 2. 执行业务逻辑
        Order order = orderDomainService.createOrder(command);

        // 3. 保存数据
        orderRepository.save(order);

        // 4. 发送领域事件
        eventPublisher.publish(new OrderCreatedEvent(order));

        return order.getOrderNo();
    }
}

// DomainService层:核心业务逻辑
@Service
public class OrderDomainService{

    public Order createOrder(CreateOrderCommand command){
        // 库存检查
        inventoryService.checkStock(command.getItems());

        // 价格计算
        OrderAmount amount = priceCalculator.calculate(command);

        // 构建订单
        Order order = OrderFactory.create(command, amount);

        return order;
    }

    public void closeOrder(Order order, String closeReason){
        if (!order.canClose()) {
            throw new BusinessException("订单当前状态不可关闭");
        }

        order.close(closeReason);

        // 释放库存
        inventoryService.restoreStock(order);

        // 退回优惠券
        couponService.returnCoupon(order);
    }
}

第五步:异常处理——业务边界情况考虑

5.1 定义业务异常体系

// 基础业务异常
public abstract class BusinessException extends RuntimeException{
    private final String code;
    private final String message;

    public BusinessException(String code, String message){
        super(message);
        this.code = code;
        this.message = message;
    }
}

// 具体业务异常
public class OrderNotFoundException extends BusinessException{
    public OrderNotFoundException(String orderNo){
        super("ORDER_NOT_FOUND", "订单不存在: " + orderNo);
    }
}

public class OrderStatusException extends BusinessException{
    public OrderStatusException(String currentStatus, String expectStatus){
        super("ORDER_STATUS_ERROR",
"订单状态错误,当前状态: " + currentStatus + ",期望状态: " + expectStatus);
    }
}

public class InventoryShortageException extends BusinessException{
    public InventoryShortageException(String skuCode){
        super("INVENTORY_SHORTAGE", "库存不足: " + skuCode);
    }
}

5.2 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler{

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<ErrorResponse> handleBusinessException(BusinessException e) {
        ErrorResponse response = new ErrorResponse(e.getCode(), e.getMessage());
        return ResponseEntity.badRequest().body(response);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleException(Exception e) {
        log.error("系统异常", e);
        ErrorResponse response = new ErrorResponse("SYSTEM_ERROR", "系统繁忙");
        return ResponseEntity.internalServerError().body(response);
    }
}

@Data
class ErrorResponse{
    private final String code;
    private final String message;
    private final long timestamp = System.currentTimeMillis();
}

第六步:测试策略——保障代码质量

6.1 单元测试:核心业务逻辑

class OrderDomainServiceTest{

    @Test
    void should_close_order_when_timeout(){
        // given
        Order order = OrderFixture.timeoutOrder();

        // when
        orderDomainService.closeOrder(order, "超时关闭");

        // then
        assertThat(order.getStatus()).isEqualTo(OrderStatus.CLOSED);
        assertThat(order.getCloseReason()).isEqualTo("超时关闭");
    }

    @Test
    void should_throw_exception_when_close_paid_order(){
        // given
        Order order = OrderFixture.paidOrder();

        // when & then
        assertThatThrownBy(() -> orderDomainService.closeOrder(order, "测试"))
            .isInstanceOf(OrderStatusException.class);
    }
}

// 测试数据构造
class OrderFixture{
    public static Order timeoutOrder(){
        Order order = new Order();
        order.setStatus(OrderStatus.WAITING_PAYMENT);
        order.setCreateTime(LocalDateTime.now().minusMinutes(31));
        return order;
    }
}

6.2 集成测试:完整业务流程

@SpringBootTest
class OrderIntegrationTest{

    @Test
    void should_complete_order_flow(){
        // 创建订单
        CreateOrderRequest request = buildRequest();
        String orderNo = orderController.createOrder(request).getData();

        // 验证订单创建
        Order order = orderRepository.findByOrderNo(orderNo);
        assertThat(order).isNotNull();

        // 模拟超时
        testTimeProvider.plusMinutes(31);
        timeoutChecker.checkTimeoutOrders();

        // 验证订单关闭
        Order closedOrder = orderRepository.findByOrderNo(orderNo);
        assertThat(closedOrder.getStatus()).isEqualTo(OrderStatus.CLOSED);
    }
}

总结:从需求到代码的思考框架

7.1 我的六个思考步骤

  1. 需求澄清(30%时间):确保理解业务本质
  2. 领域建模(20%时间):将业务概念转化为技术模型
  3. 方案设计(15%时间):权衡不同技术方案的利弊
  4. 架构设计(15%时间):设计清晰的分层和职责
  5. 异常处理(10%时间):考虑各种边界情况
  6. 测试策略(10%时间):保障代码质量

7.2 避坑经验分享

新手常犯的错误:

  • 直接写代码,不思考业务本质
  • 过度设计,引入不必要的复杂性
  • 忽略异常情况,系统健壮性差
  • 不考虑性能,后期优化困难

我的建议:

  • 先理解业务,再思考技术
  • 简单方案能解决就不要复杂化
  • 代码是写给人看的,可读性很重要
  • 测试不是可有可无,而是必备环节

记住:优秀的程序员不是写出最复杂代码的人,而是用最简单方案解决复杂问题的人。

希望这个从需求到代码的完整思考框架能对你的开发工作有所启发。如果你想了解更多关于Java开发、架构设计的实战经验,欢迎来云栈社区交流探讨。




上一篇:OpenCode AI绘制电气原理图实践:电机起保停控制电路生成指南
下一篇:Rust内核开发:为何用Relaxed原子操作替代READ_ONCE/WRITE_ONCE
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-25 18:05 , Processed in 0.381710 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表