标签:步骤 结果的处理 boolean dsl dde not prope turn stat
1 为什么我要研究领域驱动设计
1.1 设计方法各样且代码无法反映设计
我大概从2017年10月份开始研究DDD,当时在一家物流信息化的公司任职架构师,研究DDD的初衷在于为团队寻找一种软件设计的方法论。作为架构师,经常参与设计评审,包括:需求评审、设计评审、代码评审。在评审过程中,有一点感受非常深,就是评审过程非常痛苦且几乎没有效率和成果。让我痛苦的地方有:
1.2 代码质量很难有效提升
在承担架构师之前,我的另一个职责是技术管理,做的工作是与软件质量相关的。当时加入一个大概2000万规模的项目,有大约100开发人员参与,开发周期大概1年。加入该团队在开发的过程中,发现了两个问题:
基于第一个问题,我定义了统一的界面规范,这个界面规范通过和公司的PMO合作将其融入到工程过程中,作为开发人员必须遵循的规范。第二个问题,我则花费了很多的时间来尝试解决(大概有2年时间都与代码质量做斗争),最终与寻找统一的设计方法殊途同归。
如何让我们的代码变得更加干净,我在执行的过程中,按照以下步骤一步一步的执行。
基于以上的代码质量管理方法,我认为已经是做的相当不错,但是非常遗憾的是,当我抽样评审产品的代码时,我依然感到无比沮丧,软件的代码还是太复杂、太难看懂了,与《代码整洁之道》的要求相差太远了,我耗费了1年多的工作几乎毫无成果可言。因此,我在深深思考,在编码层面,定义了规范、做了优雅编码培训、定义了编写优秀代码的相关制度,就为了让开发人员把代码写好,使代码看起来更加清晰,软件更加容易维护,为什么还是无法实现?
2 软件复杂性的根源
贫血模型是软件复杂性的根源。贫血模型本质是面向数据的设计,面向过程的编码。基于贫血模型的分层架构,通常分为UI层、业务逻辑层、数据访问层、贫血模型层,贫血模型与数据模型一致,业务逻辑主要集中在业务逻辑层,业务逻辑层非常厚重。业务逻辑实现过程中,混杂了上层UI展现逻辑、数据库访问、缓存等各种逻辑,业务逻辑很凌乱的分散在各个层和关联对象,被非业务逻辑的代码隔离。通过业务逻辑层来还原真实的业务逻辑非常的困难,因此,很难从代码反映其设计,并且,复杂度会随着需求的变更变得更加复杂。
以下是一段示例基于贫血模型开发的代码。
public OrderDto signOrder(Order order) { Assert.notNull(order, "OrderDto can not be null."); OrderDto result = new OrderDto(); result.setIsOperationSuccess(true); if (null == order.getId()) { result.setIsOperationSuccess(false); result.setOperationMassage("id不能为空。"); return result; } OrderCondition orderCondition = new OrderCondition(); orderCondition.setId(order.getId()); order = orderMapper.selectOne(orderCondition); if (null == order) { result.setIsOperationSuccess(false); result.setOperationMassage("该订单不存在。"); return result; } if (order.getOrderStatus() != Integer.valueOf(StatusEnum.ORDER_STATUS.ORDER_WAIT_RECEIVE.getCode())) { result.setIsOperationSuccess(false); result.setOperationMassage("订单号:{" + order.getOrderNo() + "}不是待收货状态,不能进行签收。"); return result; } // 该订单下的所有商品的实收数(发货数量)必须都大于0 boolean validDeliveryCount = true; Double orderTotalAmount = 0d; List<OrderGoodsDto> orderGoodsList = orderGoodsBiz.selectOrderGoodsByOrderId(order.getId()); List<OrderGoods> orderGoodsListForUpdate = new ArrayList<>(); if (EmptyUtil.isNotEmpty(orderGoodsList)) { for (OrderGoodsDto orderGoods : orderGoodsList) { if (null == orderGoods.getDeliveredNum() || orderGoods.getDeliveredNum() <= 0) { validDeliveryCount = false; } else { // 根据商品发货数量重新计算订单总金额...... Double price = (null == orderGoods.getDiscountPrice() ? orderGoods.getOriginalPrice() : orderGoods.getDiscountPrice()); Integer goodsNum = (null == orderGoods.getDeliveredNum() ? 0 : orderGoods.getDeliveredNum()); orderTotalAmount += price * goodsNum; // 更新orderGoods的收货数量 orderGoods.setReceivedNum(goodsNum); OrderGoods orderGoodsForUpdate = new OrderGoods(); BeanUtils.copyProperties(orderGoods, orderGoodsForUpdate); orderGoodsListForUpdate.add(orderGoodsForUpdate); } } } if (!validDeliveryCount) { result.setIsOperationSuccess(false); result.setOperationMassage("订单号:" + order.getOrderNo() + ",订单下所有商品都已发货才可进行签收操作,请确认。"); return result; } order.setOrderStatus(Integer.valueOf(StatusEnum.ORDER_STATUS.ORDER_SIGN.getCode())); order.setOrderTotalAmount(orderTotalAmount); order.setPaymentAmount(orderTotalAmount); order.setUnpaidAmount(orderTotalAmount); update(order); orderGoodsBiz.batchUpdate(orderGoodsListForUpdate); List<Order> orders = new ArrayList<Order>(); orders.add(order); saveRouteMessage(orders); return result; }
类似这样的代码非常常见,通过阅读这段业务逻辑代码,可以发现它处理了以下的任务:
(1)返回结果的处理。
(2)数据库访问。
(3)关联对象的数据库访问。
(4)业务规则。
业务规则代码混杂在各种任务的代码中,通过代码还原业务规则会越来越复杂且随着时间推移,代码逻辑会越来越偏离设计。作为软件系统最核心的部分——业务规则,如果我们仅仅将其从其它任务中剥离,我们的代码将演化如下。
public void signOrder(Order order) { Assert.notNull(order, "OrderDto can not be null."); if (order.getOrderStatus() != Integer.valueOf(StatusEnum.ORDER_STATUS.ORDER_WAIT_RECEIVE.getCode())) { throw new BusinessException(“订单号:{" + order.getOrderNo() + "}不是待收货状态,不能进行签收。"); } // 该订单下的所有商品的实收数(发货数量)必须都大于0 boolean validDeliveryCount = true; Double orderTotalAmount = 0d; List<OrderGoods> orderGoodsList = order.getOrderGoods(); if (EmptyUtil.isNotEmpty(orderGoodsList)) { for (OrderGoods orderGoods : orderGoodsList) { if (null == orderGoods.getDeliveredNum() || orderGoods.getDeliveredNum() <= 0) { validDeliveryCount = false; } else { // 根据商品发货数量重新计算订单总金额...... Double price = (null == orderGoods.getDiscountPrice() ? orderGoods.getOriginalPrice() : orderGoods.getDiscountPrice()); Integer goodsNum = (null == orderGoods.getDeliveredNum() ? 0 : orderGoods.getDeliveredNum()); orderTotalAmount += price * goodsNum; // 更新orderGoods的收货数量 orderGoods.setReceivedNum(goodsNum); } } } if (!validDeliveryCount) { throw new BusinessException(“订单号:" + order.getOrderNo() + ",订单下所有商品都已发货才可进行签收操作,请确认。"); } order.setOrderStatus(Integer.valueOf(StatusEnum.ORDER_STATUS.ORDER_SIGN.getCode())); order.setOrderTotalAmount(orderTotalAmount); order.setPaymentAmount(orderTotalAmount); order.setUnpaidAmount(orderTotalAmount); }
你可以发现这段单纯实现业务规则的代码,会更加的简单、清晰,也会使软件更加的容易维护。在DDD的方法论里面,业务规则是在领域层来实现的,领域层的代码仅仅是业务规则,这时候,其分层架构的分层逻辑和基于贫血模型的分层逻辑也会不一样了。
通过以上代码的对比我们发现:
3 DDD如何解决软件复杂性
DDD解决软件复杂性的方法核心为两点:
软件实现与领域模型保持一致是本书的核心思想,DDD构建了一套完整的方法论来支持领域模型驱动程序设计。这套方法论简述如下。
我将在下一篇文章中详细解释DDD的核心思想,让你明白它是如何解决复杂性的。
解构领域驱动设计(一):为什么领域驱动设计能够解决软件复杂性
标签:步骤 结果的处理 boolean dsl dde not prope turn stat
原文地址:https://www.cnblogs.com/baihmpgy/p/10259264.html