首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Java 架构师:从写代码到定边界的能力跃迁

Java 架构师:从写代码到定边界的能力跃迁

原创
作者头像
用户12339161
发布于 2026-10-14 16:46:09
发布于 2026-10-14 16:46:09
290
举报

核心结论: Java 架构师的核心能力不是"会更多框架",而是能在业务不确定的前提下,用最小的约束成本划出系统边界。写代码解决的是"怎么实现",定架构解决的是"什么不该做、什么必须隔离、什么允许以后改"。前者是技术,后者是判断。

一、架构师和高级开发的分界线

高级开发的评价标准是"能搞定复杂需求",架构师的评价标准是"让复杂需求不会同时压垮系统"。两者的差异体现在三个决策上:

决策维度

高级开发

架构师

关注点

本次功能怎么实现

这个能力三年后还能不能改

边界

模块内代码质量

模块间依赖方向

变更成本

改代码要多久

改架构要动几个团队

技术选型

哪个框架好用

哪个约束代价最低

一个典型的架构失手案例:业务早期为了"快速上线",让订单模块直接调用库存模块的 Mapper。半年后库存要拆成独立服务,发现订单里嵌了几十处库存表查询。省下的是当初两天的接口设计,付出的是后来两个月的重构。

二、边界设计:依赖倒置的工程价值

架构师最常用的工具是依赖倒置。以下是一个订单创建场景的骨架,核心是把"订单依赖库存"改成"订单依赖库存的能力接口":

代码语言:javascript
复制
// 订单模块定义自己需要的能力,不关心谁实现
public interface StockService {
    boolean tryLock(String skuId, int qty);
    void release(String skuId, int qty);
}

// 订单服务只依赖接口
@Service
public class OrderService {
    private final StockService stockService;

    public OrderService(StockService stockService) {
        this.stockService = stockService;
    }

    @Transactional
    public Order create(CreateOrderCmd cmd) {
        boolean locked = stockService.tryLock(cmd.getSkuId(), cmd.getQty());
        if (!locked) {
            throw new BizException("库存不足");
        }
        try {
            Order order = doCreate(cmd);
            return order;
        } catch (Exception e) {
            stockService.release(cmd.getSkuId(), cmd.getQty());
            throw e;
        }
    }
}

库存的实现放在基础设施层,通过 Spring 注入:

代码语言:javascript
复制
@Repository
public class DbStockService implements StockService {
    private final StockMapper mapper;

    @Override
    public boolean tryLock(String skuId, int qty) {
        return mapper.decrease(skuId, qty) > 0;  // 乐观锁扣减
    }

    @Override
    public void release(String skuId, int qty) {
        mapper.increase(skuId, qty);
    }
}

这个设计的价值不在"看起来解耦",而在变更可控:库存从数据库换成 Redis、从单体拆成远程服务、从同步改成异步预占,订单模块一行都不用改。架构师定的是这个约束,不是具体实现。

三、事务边界:别让架构承诺做不到的事

架构师最容易犯的错误是承诺"分布式事务保证一致性"。在真实系统里,跨服务的强一致性代价极高,工程上通常用最终一致性 + 补偿替代。以下是本地消息表的核心逻辑:

代码语言:javascript
复制
@Service
public class OrderTxService {
    private final OrderMapper orderMapper;
    private final MessageMapper messageMapper;

    @Transactional
    public void createWithEvent(CreateOrderCmd cmd) {
        Order order = buildOrder(cmd);
        orderMapper.insert(order);
        // 事件与业务在同一事务内落库,保证不丢
        messageMapper.insert(new Message(
            "ORDER_CREATED", order.getId(), "PENDING"));
    }
}

// 独立调度器扫描 PENDING 消息投递
@Scheduled(fixedDelay = 3000)
public void dispatch() {
    for (Message m : messageMapper.findPending(100)) {
        try {
            mqProducer.send(m);
            messageMapper.markSent(m.getId());
        } catch (Exception e) {
            messageMapper.markFailed(m.getId());
        }
    }
}

架构师在这个场景要做三个判断:是否允许短暂不一致(允许)、失败后能否人工介入(能)、补偿逻辑是否幂等(必须)。这三个判断比选哪个 MQ 重要得多。

四、演进边界:为变化留接口,不为猜测加抽象

架构师常被批评"过度设计"。判断一个抽象该不该加,看它是否有明确的变更预期。以下是一个配置读取的演进示例:

代码语言:javascript
复制
// 第一版:直接读配置,够用
@Service
public class RateLimitService {
    @Value("${rate.limit.qps:100}")
    private int qps;
}

// 需要支持按租户动态调整时,才引入策略接口
public interface RateLimitPolicy {
    int qpsOf(String tenantId);
}

@Service
public class ConfigurableRateLimitService {
    private final RateLimitPolicy policy;

    public boolean allow(String tenantId) {
        return counter.tryAcquire(tenantId, policy.qpsOf(tenantId));
    }
}

第一版直接读配置是对的——那个阶段没有多租户需求。第二版引入接口也是对的——需求出现了,抽象有了明确边界。没有变更预期的抽象是负债,有变更预期的抽象是资产。

五、工程化要点

第一,依赖方向比依赖数量重要。 业务层可以依赖基础设施层的接口,基础设施层不能反向依赖业务。方向错了,模块再小也会烂。

第二,事务边界要诚实。 能本地事务就别分布式,能最终一致就别强一致。架构师的价值是给出可落地的方案,不是给出最完美的方案。

第三,抽象跟着变更走。 没有明确的变更预期,不加接口层。加了就要维护,维护成本也是成本。

第四,留文档不如留约束。 把依赖规则写进 CI(比如 ArchUnit 测试),比写在文档里更可靠:

代码语言:javascript
复制
@ArchTest
static final ArchRule layerRule = layeredArchitecture()
    .layer("Controller").definedBy("..controller..")
    .layer("Service").definedBy("..service..")
    .layer("Infra").definedBy("..infra..")
    .whereLayer("Controller").mayNotBeAccessedByAnyLayer()
    .whereLayer("Service").mayOnlyBeAccessedByLayers("Controller");

Java 架构师的能力分水岭,不在于会用多少框架,而在于能否在业务压力下守住边界。写代码的人决定系统今天能不能跑,定架构的人决定系统明年还能不能改。

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

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

目录
  • 一、架构师和高级开发的分界线
  • 二、边界设计:依赖倒置的工程价值
  • 三、事务边界:别让架构承诺做不到的事
  • 四、演进边界:为变化留接口,不为猜测加抽象
  • 五、工程化要点
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档