業務程式碼程式設計陷阱案例 - jaxenter
當我們開始編寫軟體時,我們總是希望有一個好的設計。我們閱讀書籍,運用最佳實踐,最後,我們常常一團糟。根據我在一家定製軟體開發公司的經驗,我每天必須處理此類程式碼,尤其是在某些舊系統上工作時。
造成這種情況的原因多種多樣,我將嘗試在一系列文章中以一些實際的方式來探討其中的一些原因。在我的第一個示例中,我將說明為什麼簡單的軟體會演變成一場噩夢,並建議進行一些改進。我將只專注於處理業務邏輯的服務層。
讓我們從一個簡單的儲存應用程式開始。我們擁有帶有服務,儲存庫的產品資源,並且我們可以執行我們認為需要的CRUD操作。我們的產品服務如下所示:
public class ProductService { public String create(Product product) { return productRepository.create(product); } public String update(Product product) { return productRepository.update(product); } public Product get(String productId) { return productRepository.get(productId); } public void delete(Product product) { productRepository.delete(product); } } |
還會有其他一些東西,例如DTO到實體的對映,控制器等。但是正如我所說的,我們將考慮將它們編寫為簡化起見。我們的產品實體是簡單的Java Bean,我們的儲存庫儲存在正確的資料庫表中。然後,我們得到另一個要求,即我們還將建立一個線上商店,並且需要一種下訂單的方法。因此,我們新增了快速訂購服務來滿足我們仍然很簡單的要求:
public class OrderService { public String saveOrder(Order order) { return orderRepository.save(order); } } |
它簡單,易讀且有效!然後,下訂單時就需要更新庫存中的產品的新要求。我們這樣做:
public class OrderService { public String saveOrder(Order order) { Product product=productService.get(order.getProductId()); product.setAvailableQuantity(product.getAvailableQuantity()-order.getQuantity()); productService.update(product); return orderRepository.save(order); } } |
我們又碰到三個新需求:
- 我們需要致電運輸服務將該產品運送到一個地址
- 如果沒有足夠的庫存來履行訂單,則丟擲一個錯誤
- 如果產品的可用數量低於最低數量以進行重新庫存。
結果如下:
public class OrderService { public String saveOrder(Order order) { Product product=productService.get(order.getProductId()); //The order service works more like a product service in the following liness if(product.getAvailableQuantity()<order.getQuantity()){ throw new ProductNotAvailableException(); } product.setAvailableQuantity(product.getAvailableQuantity()-order.getQuantity()); productService.update(product); if(product.getAvailableQuantity()<Product.MINIMUM_STOCK_QUANTITY){ productService.restock(product); } //It also needs to know how shipments are created Shipment shipment=new Shipment(product, order.getQuantity(), order.getAddressTo()); shipmentService.save(shipment); return orderRepository.save(order); } } |
我知道這可能是一個極端的例子,但是我確信我們在專案中已經看到了類似的程式碼。這樣做有多個問題–責任z職責共擔,與其他領域的邏輯和基礎架構混淆在以前等等。如果這是一個真實的商店,那麼接單的人就像總經理–照顧一切,從實際訂購庫存維護和交付。
更好的版本
讓我們嘗試以不同的方式處理相同的情況。我將從訂購服務開始。為什麼我們呼叫方法saveOrder?因為我們將其視為開發人員,而不是從業務角度來看。我們開發人員的想法通常是資料庫驅動的(或REST驅動的),我們將我們的軟體視為一系列CRUD操作。通常,當我們閱讀有關領域驅動設計的書籍時,會提到通用語言-開發人員和使用者之間的通用語言。如果我們嘗試在我們的程式碼中為業務建模,那麼為什麼不使用正確的術語。我們可以將初始程式碼更改為:
public class OrderService { public String placeOrder(Order order) { return orderRepository.save(order); } } |
使用placeOrder替代了原理的saveOrder方法名。
進行很小的更改,但即使那樣也會使其更具可讀性。這是業務層,而不是資料庫層–我們去商店時下訂單place order,但不儲存訂單save order。然後,當其他需求出現時,而不是開始使用帶有CRUD操作的現有服務來編碼它們,我們可以嘗試重新建立業務模型。我們詢問業務人員,他們告訴我們,下訂單時,接單的人員會致電庫存部門,詢問他們產品是否可用,然後進行儲備並致電帶有預定編號和地址的交貨人員,以便他們裝運它。是什麼阻止我們在程式碼中執行相同的操作?
public class OrderService { public String placeOrder(Order order) { String productReservationId=productService.requestProductReservation(order.getProductId, order.getQuantity()); String shippingId=shipmentService.requestDelivery(productReservationId, order.getAddressTo()); order.addShippingId(shippingId); return orderRepository.save(order); } } |
在我看來,它看起來更加乾淨,代表了實際商店中發生的事件的順序。訂單服務不需要知道產品如何工作或運輸如何工作。它只是使用完成工作所需的方法。我們也需要修改其他服務:
public class ProductService { //Method used in Orders Service public String requestProductReservation(String productId, int quantity){ Product product=productRepository.get(productId); product.reserve(quantity); productRepository.update(product); return createProductReservation(product, quantity); } private String createProductReservation(Product product, int quantity){ ProductReservation reservation=new ProductReservation(product,quantity); reservation.setStatus(ReservationStatus.CREATED); return reservationRepository.save(reservation); } //Method used in Shipment Service public ProductReservation getProductsForDelivery(String reservationId){ ProductReservation reservation=reservationRepository.getProductReservation(reservationId); reservation.getProduct.releaseReserved(reservation.getQuantity()); if(reservation.getProduct().needRestock()){ this.restock(product); } reservation.setStatus(ReservationStatus.PROCESSED); reservationRepository.update(reservation); } } |
產品服務提供了其他服務要使用的兩種方法,但對它們的結構一無所知。它不關心訂單,發貨等。當產品需要補貨以及產品數量是否足夠時,邏輯就在實際產品內部。
public class Product() { //Fields, getters, setters etc... public void reserve(int quantity){ if(this.availableQuantity - this.reservedQuantity > quantity){ this.reservedQuantity+=quantity; } else throw new ProductReservationException(); } public releaseReserved(int requested){ if(this.reservedQuantity>=requested){ this.reservedQuantity-=requested; this.availableQuantity-=requested; } else throw new ProductReservationException(); } public boolean needsRestock(){ return this.availableQuantity<MINIMUM_STOCK_QUANTITY; } } |
裝貨服務:
public class ShipmentService { public String requestDelivery(String reservationId, Address address){ ProductReservation reservation=productService.getProductForDelivery(reservationId); Shipment shipment=new Shipment(reservation, address); return shipmentRepository.save(shipment); } } |
我並不是說這是最好的設計,但我認為它要乾淨得多。每個服務都照顧自己的領域,並且對其他服務瞭解得最少。實際的實體不僅是資料持有者,而且還攜帶與之相關的邏輯,因此服務不需要直接修改其內部狀態。在我看來,最有價值的是程式碼真正代表了業務運作方式。
相關文章
- Shell 指令碼程式設計陷阱指令碼程式設計
- 程式設計師的“能力陷阱”程式設計師
- 反應式程式設計是正確的方法嗎? - JAXenter程式設計
- 不要陷入極限程式設計的陷阱程式設計
- [程式碼結構設計]根據不同條件使用不同實現類的業務程式碼設計
- Linux Shell指令碼程式設計while語句案例Linux指令碼程式設計While
- 無程式碼程式設計程式設計
- 天天寫業務程式碼的程式設計師,怎麼成為技術大牛程式設計師
- python 程式設計基礎案例Python程式設計
- NIO非阻塞程式設計小案例程式設計
- 入門程式碼程式設計程式設計
- 哪些業務場景需要做程式碼審計?程式碼審計很重要嗎?
- 程式設計師必知的 Python 陷阱與缺陷列表程式設計師Python
- 程式設計師程式碼面試指南程式設計師面試
- 如何優雅的在業務中使用設計模式(程式碼如詩)設計模式
- 好程式設計師分享JavaScript中8個常見的陷阱程式設計師JavaScript
- 4個費勁心思卻走向程式設計地獄的陷阱程式設計
- 求助!!!求jdon的原始碼,“Struts應用系統案例設計程式設計講解”原始碼程式設計
- Python程式設計:探索有趣的程式碼設計模式Python程式設計設計模式
- 相親原始碼開發,使用了哪些設計模式來優化業務程式碼?原始碼設計模式優化
- STL案例程式碼
- 程式設計師如何寫出好程式碼?程式設計師
- 好程式設計師不寫程式碼程式設計師
- 程式設計師這樣寫程式碼程式設計師
- 低程式碼-業務流程引擎
- 程式碼設計問題
- 程式碼分層設計
- 程式設計師or碼農程式設計師
- scala指令碼程式設計指令碼程式設計
- SELL 指令碼程式設計指令碼程式設計
- Spring響應式Reactive程式設計的10個陷阱 -Jeroen RosenbergSpringReact程式設計ROS
- ios程式設計師職業中需要避免的八大「陷阱」iOS程式設計師
- 程式設計師生活智慧集——卓越程式設計師密碼程式設計師密碼
- WEB程式設計開發常用的程式碼Web程式設計
- 當程式設計師寫不出程式碼了……程式設計師
- 程式設計師垃圾程式碼分類指南程式設計師
- 程式設計師應該每天寫程式碼程式設計師
- 程式設計師,千萬不要重寫程式碼程式設計師