专栏名称: 逸言
文学与软件,诗意地想念。
目录
相关文章推荐
程序员小灰  ·  这款AI编程工具,将会取代Cursor! ·  昨天  
码农翻身  ·  为何 Linus ... ·  昨天  
OSC开源社区  ·  DeepSeek-V3满血版在国产沐曦GPU ... ·  3 天前  
程序员的那些事  ·  热搜第一!DeepSeek百万年薪招AI人才 ... ·  2 天前  
程序员的那些事  ·  趣图:初五迎财神,初六送穷鬼 ·  4 天前  
51好读  ›  专栏  ›  逸言

用AI大模型与DDD实现业务服务驱动编程

逸言  · 公众号  · 程序员  · 2024-08-19 08:30

正文

我在GitChat公众号上读到一篇转译的文章《 代码生成交给机器,我们的工作将变成软件概念的设计师 》,作者是MIT计算机与AI实验室(CSAIL)副主任和计算机科学教授Daniel Jackson,他提出了基于“概念”的软件设计方法。

这篇文章来自Daniel Jackson教授在2024全球软件研发技术大会中的演讲。以我之愚见,Daniel Jackson提出“概念(Concept)”的概念,其定义本身比较抽象,即便他通过iPod、Zoom等应用为例,深入细致地说明如何在应用开发中运用“概念”,但其本意仍有混淆不清之感。当然,也可能是我理解能力不足。
在我反复咀嚼该篇文章之后,我“自大”地发现Daniel Jackson提出的所谓“概念”,与我在自己的著作《解构领域驱动设计》中提出的“业务服务”颇类似。
文中如此定义:“概念是单个软件、一类软件以及各类软件的特征。”这个定义很模糊,但可以读懂它传递的一个重点,即概念是该软件有别于其他软件的某个或某些功能/特性。
接着,Daniel Jackson教授用Zoom举例说:
你可以将 Zoom 理解为由这些概念构建而成,包括会议链接、视频频道(VideoChannel)等。其中一些概念是创新性的,如会议链接;有些是我们非常熟悉的,如在线聊天;还有一些是通用性的概念,几乎在每个应用程序中都能见到,例如用户身份验证,这是最典型的通用性概念之一。这些概念通过 “交互+同步” 的方式融合在一起。
既然概念为软件之特征,则它体现了该软件的主要功能,这些功能又由一些领域概念(此概念非Daniel Jackson教授所倡导之概念,但二者有相似之处)和行为构成:
  • 领域概念:会议链接、视频频道
  • 领域行为:用户身份验证

文中提及的“创新性概念”,可认为是DDD中的核心领域(核心领域是一家企业具备竞争力的高价值领域,创新特性是战略规划的一部分,在经过充分验证之后,理应归入核心领域);而所谓“通用性概念”,应为DDD的通用子领域。
Daniel Jackson教授又提出:“我们可以将应用程序视为概念的集合,并将其简化为最核心的部分。”他认为需要从场景提炼出概念,这一说法更接近于“业务能力”。他举例说:
对于 Zoom 来说,基本的概念可能是会议链接和视频会议。对于像 Calendly 这样的日程安排软件,核心概念可能是自助预约和通知。而对于 iPod 来说,则是歌曲管理、音乐商店以及文件同步的概念。
他提及的这些概念,不就是Zoom、Calendly与IPod最为核心的业务能力吗?正是因为具有了这些业务能力,这些产品才能在市场上傲视群雄,甚至引领一时之风气。
文中还提到:“ 概念本质上是一个可以通过 API 来定义的服务 。比方说,列出一系列动作。这些动作实际上是出现在场景中的行为,可以被视为 API 的组成部分。”这就将具有业务含义的内容和技术实现绑定起来了。
之后,进一步阐释:
概念不像程序那样,可以用较大的包含较小的。相反,每个概念对用户来说都是平等的,软件或系统就是一组串联运行的概念组合。
根据Daniel Jackson教授给出的这些解释和例子,我觉得他提出的“概念”一词仍有含混之处,如果结合领域驱动设计,则可初步得出一些结论:
  • “概念”是软件的业务功能特征,可以是我们常说的具有名词特征的领域概念,也可以是具有动词特征的领域行为
  • 可以将“概念”依据价值之高低划分到核心子领域、通用子领域以及支撑子领域
  • 每个概念都是独立的,概念与概念之间是正交的,在技术端,就是通过API定义的服务
  • 不按照粒度大小来划分概念,而是按照概念的完整性与业务价值进行划分,故而每个概念都是平等的,彼此不应互相包含,但可以互相调用

假如这些结论站得住脚,那么“ 概念 ”这个概念就和 业务服务 颇为类似,甚至我认为他说的“概念”,还不如用业务服务更加清楚。《解构领域驱动设计》一书对业务服务的定义为:
业务服务是业务的参与者主动向目标系统发起服务请求,完成一次连续而完整的功能交互,并体现服务价值的业务行为。
在识别业务服务时,同样不按照粒度大小划分,而是将参与者与目标系统的 一次完整交互 视为一个独立的业务服务。这种交互往往通过前端或其他客户端向目标系统对外公开的API发起请求,从技术角度看,一个业务服务确实就是一个通过API定义的服务。如果将多个业务服务组合起来,就体现了该系统或系统之下的限界上下文对外提供的各种业务能力。
业务服务承载了用户的业务需求,并成为需求分析阶段的基本业务单元。遵循 统一语言 的原则,可以按照特定规约编写业务服务,使之清晰地传递领域建模需要用到的领域概念、领域行为和领域规则。下图是我规定的业务服务规约及其案例:

好。倘若这一假设成立,则Daniel Jackson教授提出的 用概念驱动编程 ,即可称为 业务服务驱动编程 ,由于它的粒度和规格具有确定性,即可解决GitHub首席执行官Thomas Dohmke针对AIGC提出的问题:“开发者的关键技能在于,‘ 我需要细化到什么程度才能用 AI 自动生成代码?’
我的回答是:只需细化到如上图所示的业务服务规约就可以了。注意,这个业务规约完全可以由领域专家完成,接下来,只需将这份输出作为prompt的一部分,交给AI大模型就足够了。

让我们试验一下。我选择最基本的GPT-4 Omni Mini模型,编写的prompt内容为:

你是一名开发人员,在与需求人员充分沟通后,得到了如下格式的需求规格描述,它说明了一个代表用户功能的业务服务:

服务名:提交订单

服务描述:

作为买家,

我想要提交订单,

以便买到我心仪的商品。

触发事件:买家点击“提交订单”按钮

基本流程

1.验证订单有效性;

2.验证订单所购商品是否缺货;

3.插入订单;

4.从购物车中移除所购商品;

5.锁定库存;

6.通知买家订单已提交。

替代流程

1a.如果订单无效,给出提示信息;

2a.如果所购商品缺货,给出提示信息;

3a.若订单提交失败,给出失败原因。

验收标准

1.订单需要包含客户ID、配送地址、联系信息及已购商品的订单项;

2.订单项中商品的购买数量要小于或等于库存量;

3.订单提交成功后,订单状态更改为“已提交”;

4.购物车对应商品被移除;

5.  在完成支付或取消订单前,需要锁定对应数量的商品;

6.买家收到订单已提交的通知。

分析该需求规格描述,提炼出领域概念,然后按照DDD的要求编写该业务服务的领域层代码,用Java语言来表示。


以下是大模型的回答:
在分析该需求规格描述后,我们可以提炼出一些领域概念。这些概念通常来自业务需求并与领域模型相关联。根据给定的需求,以下是一些可以提取的领域概念:
领域概念
  1. Buyer(买家):代表购买商品的人。
  2. Order(订单):表示买家购买的商品及其相关信息。
  3. Cart(购物车):存放买家选择但尚未购买的商品。
  4. Product(商品):可以购买的物品,包含库存信息。
  5. OrderItem(订单项):订单中每个具体商品的详情,包含数量和状态。
  6. Inventory(库存):表示商品的可用数量。

领域层代码
下面是用 Java 表达的模型,遵循 DDD(领域驱动设计)原则。
// Buyer (买家)public class Buyer {    private String id;    private String name;    private String contactInfo;    private String deliveryAddress;        // getters and setters}
// Product (商品)public class Product { private String id; private String name; private int stockQuantity;
public boolean isAvailable(int quantity) { return stockQuantity >= quantity; } // getters and setters}
// OrderItem (订单项)public class OrderItem { private Product product; private int quantity;
public OrderItem(Product product, int quantity) { if (!product.isAvailable(quantity)) { throw new IllegalArgumentException("商品库存不足"); } this.product = product; this.quantity = quantity; } // getters and setters}
// Order (订单)import java.util.List;
public class Order { private String id; private Buyer buyer; private List items; private String status;
public Order(Buyer buyer, List items) { this.buyer = buyer; this.items = items; this.status = "已提交"; // 默认状态 } // getters and setters}
// Cart (购物车)import java.util.ArrayList;import java.util.List;
public class Cart { private List items = new ArrayList<>();
public void addItem(OrderItem item) { items.add(item); }
public void removeItem(OrderItem item) { items.remove(item); } public List getItems() { return items; }}
// OrderService (业务服务)public class OrderService { public Order submitOrder(Buyer buyer, Cart cart) { // 验证订单有效性 if (cart.getItems().isEmpty()) { throw new IllegalArgumentException("购物车为空,无法提交订单"); }
// 验证订单商品是否缺货 List orderItems = new ArrayList<>(); for (OrderItem item : cart.getItems()) { if (!item.getProduct().isAvailable(item.getQuantity())) { throw new IllegalArgumentException("商品 " + item.getProduct().getName() + " 缺货"); } orderItems.add(item); }
// 创建订单 Order order = new Order(buyer, orderItems); // 插入订单 (此处可以调用持久化层方法保存订单)
// 从购物车中移除所购商品 for (OrderItem item : orderItems) { cart.removeItem(item); }
// 锁定库存 (此处可以调用库存服务锁定商品数量)
// 通知买家 (可以使用事件或消息机制发送通知)
return order; }}
说明
  • 以上代码展示了核心的领域模型,包括买家、商品、订单项、订单和购物车。
  • OrderService 类中的 submitOrder 方法实现了提交订单的基本流程,并进行了必要的校验。
  • 为了实现完整的系统,还需要实现持久化层的具体逻辑以及通知机制和库存管理逻辑。

如果你有其他需求或想进一步讨论的内容,请告诉我!

虽说这样的领域层代码还不够完善,但开发人员完全可以在此基础上做优化和调整,当然,也可以继续通过prompt与AI大模型互动。
如果按照业务服务的要求进行划分(划分业务服务由人来完成),一个业务服务就是一个API定义的服务,如此,还可以在此基础上要求AI大模型帮我们定义一个API。

我在以上回答的基础上继续提问:

如果将“提交订单”业务服务看做是一个后端服务的RESTful API,请生成一个后端服务的Java代码,满足API的定义。要求:在后端服务中,调用前面领域层代码定义的领域服务。
则AI大模型的回答为:
好的!下面是一个将“提交订单”业务服务实现为 RESTful API 的后端服务的 Java 代码示例。这段代码使用 Spring Boot 框架,并通过调用前面定义的领域层服务来执行订单提交功能。
Maven 依赖
首先,你需要在 pom.xml 中添加 Spring Boot 相关的依赖(只列出核心部分):
<dependencies>    <dependency>        <groupId>org.springframework.bootgroupId>        <artifactId>spring-boot-starter-webartifactId>    dependency>    <dependency>        <groupId>org.springframework.bootgroupId>        <artifactId>spring-boot-starter-data-jpaartifactId>    dependency>    <dependency>        <groupId>org.springframework.bootgroupId>        <artifactId>spring-boot-starterartifactId>    dependency>    dependencies>
RESTful API 代码
下面是实现 RESTful API 的控制器代码:
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController@RequestMapping("/api/orders")public class OrderController {
private final OrderService orderService;
@Autowired public OrderController(OrderService orderService) { this.orderService = orderService; }
@PostMapping("/submit")






请到「今天看啥」查看全文