编程的本质:LCD-逻辑、控制与数据的解耦艺术
本文基于《左耳听风:传奇程序员练级攻略》的读书笔记整理而成
编程的本质可以归纳为三个核心要素:逻辑(Logic)、控制(Control)和数据(Data)。我们所使用的各种编程范式和设计方法,本质上都是围绕这三个方面展开工作。
- 逻辑:反映问题的本质,定义如何解决问题的具体方法
- 控制:解决问题的策略,如循环执行、异步执行等流程控制
- 数据:问题的表现形式和载体
在实际开发中,业务逻辑本身往往就很复杂,这是程序复杂度的主要来源之一。当这些复杂的逻辑与控制流程交织在一起时,就构成了程序的完整复杂度。
因此,有效分离逻辑、控制和数据,成为编写高质量程序的关键。这涉及到软件工程中的一个核心概念——解耦:通过降低模块间的依赖程度,消除不必要的耦合关系。
从聚合支付案例看LCD的演变
让我们通过一个聚合支付系统的例子,来理解逻辑、控制和数据的分离过程。
初始版本:纯粹的业务逻辑
聚合支付系统收到支付请求,保存支付数据,然后请求外部银行接口。
我们简化为下面的Logic-逻辑:
pay(PayRequest request) {
PayData data = from(request);
savePayData(data);
invokeBankAPI(data);
return "支付受理成功";
}
这个版本只关注核心业务逻辑:转换数据、保存记录、调用银行接口。
引入控制:异步执行(为便于阅读和讲解,这里使用Thread)
pay(PayRequest request) {
PayData data = from(request);
savePayData(data);
// 控制:异步执行
new Thread(() -> {
invokeBankAPI(data);
}).start();
return "支付受理成功";
}
这里引入了控制元素——异步执行。我们只需启动一个线程,Java运行时环境会处理具体的异步执行细节。
增加事务控制,以及创建时间、创建人等审计字段赋值
@Transactional
pay(PayRequest request) {
PayData data = from(request);
data.setCreateBy(***); // 数据加工
data.setCreateTime(***); // 数据加工
savePayData(data);
new Thread(() -> {
invokeBankAPI(data);
}).start();
return "支付受理成功";
}
增加了事务控制和数据加工逻辑,代码开始变得复杂。
添加幂等控制
@Transactional
pay(PayRequest request) {
key = createKey(request);
if(!redis.setnx(key)){
return "请勿重复发起";
}
PayData data = from(request);
data.setCreateBy(***);
data.setCreateTime(***);
savePayData(data);
new Thread(() -> {
invokeBankAPI(data);
}).start();
return "支付受理成功";
}
幂等控制的加入进一步增加了代码复杂度。
异常处理,并要区分异常类型做不同处理
@Transactional
pay(PayRequest request) {
try {
key = createKey(request);
if(!redis.setnx(key)){
return "请勿重复发起";
}
PayData data = from(request);
data.setCreateBy(***);
data.setCreateTime(***);
savePayData(data);
new Thread(() -> {
invokeBankAPI(data);
}).start();
return "支付受理成功";
} catch(Exception e) {
log.error("程序异常", e);
if (e instanceof ChannelException) {
// 特殊处理
}
}
}
至此,这段代码已经比较复杂了,包含了多种关注点:业务逻辑、异步控制、事务管理、幂等校验和异常处理。
解耦与重构:回归LCD本质
当代码变得如此复杂时,我们需要重新思考设计,将逻辑、控制和数据进行有效分离:
- 封装幂等组件:将幂等校验逻辑抽象为独立组件
- 实现全局异常处理:通过统一的异常处理机制避免业务代码中的try-catch块
- 参数校验器:独立处理参数验证逻辑
- 数据转换组件:专门负责数据转换和加工
- 全局审计字段处理:通过AOP或框架机制自动设置创建人、创建时间等字段
- 控制逻辑迁移:将异步调用银行接口的代码迁移到专门的银行通道实现类中
通过这种解耦方式,我们可以让核心业务逻辑保持简洁和清晰,而将各种控制 concerns 和数据处理逻辑放到适当的位置和层次中。
结语
编程的本质在于合理组织逻辑、控制和数据三者之间的关系。优秀的程序设计不是避免复杂性,而是通过有效的分离和解耦来管理复杂性。当我们能够清晰区分"做什么"(逻辑)、"怎么做"(控制)和"用什么做"(数据)时,代码的可读性、可维护性和可扩展性都将得到显著提升。
这种LCD分离思想不仅适用于单个方法或类,也同样适用于系统架构的设计。在任何层级上,保持逻辑、控制和数据的清晰边界,都是高质量软件的关键特征。
当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/18427803