Có phải Inversion của Control Control thúc đẩy mô hình tên miền thiếu máu


32

Khi tôi sử dụng IoC Container trong dự án cuối cùng của mình, tôi đã kết thúc với các thực thể thiếu máu và hầu hết logic kinh doanh của tôi trong Dịch vụ phi trạng thái.

Tôi đã thấy các dự án được viết bởi các nhà phát triển khác sử dụng "Đảo ngược kiểm soát" và chúng luôn luôn là "Thiếu máu".

Vì "Mô hình miền thiếu máu" là mô hình chống, nên có thể sử dụng IoC và Rich Domain không? Có bất kỳ ví dụ tốt, dự án nguồn mở nào làm được điều đó không?


Tôi nghĩ rằng chúng ta cần xem một số ví dụ cụ thể về trường hợp cụ thể của bạn để giúp đỡ.
Martijn Verburg

1
Xin lỗi, ý tôi là đoạn mã :)
Martijn Verburg

Câu trả lời:


11

Dành cho người mới bắt đầu: DI và IoC không phải là từ đồng nghĩa. Tôi xin lỗi nhưng tôi phải chỉ ra điều đó (dường như với tôi rằng bạn nghĩ họ như vậy).

Đối với yêu cầu của bạn ... Chà, Dependency Injection chỉ là một công cụ. Làm thế nào bạn sẽ sử dụng công cụ này là điều hoàn toàn riêng biệt. Ngoài ra còn có các công cụ khác (mẫu thiết kế) có thể gây ra vấn đề. Ví dụ, tôi cảm thấy rằng việc áp dụng rộng rãi mẫu MVC là một trong những thành phần quan trọng để hình thành mô hình chống mô hình miền thiếu máu: Bộ điều khiển (trong các ứng dụng đơn giản hơn, trong các ứng dụng phức tạp hơn sẽ là Lớp dịch vụ bổ sung) chịu trách nhiệm xác thực các quy tắc kinh doanh , thực thi chúng cũng như chuyển đổi các thực thể DB thành một cái gì đó hữu ích, trong khi Lớp nghiệp vụ biến thành Lớp truy cập dữ liệu đơn giản là ORM đơn giản với ánh xạ một-một đến các thực thể cơ sở dữ liệu.

Chắc chắn đó là cách bạn thiết kế ứng dụng của mình - bạn có thể tạo Mô hình miền chính xác nếu bạn muốn và tất cả các IoC, DI, MVC này không ngăn bạn. Điều có thể ngăn bạn là đội của bạn. Bạn bằng cách nào đó cần phải thuyết phục họ sử dụng đúng đường dẫn và có thể khó vì nhiều Nhà phát triển phần mềm không có nền tảng kiến ​​trúc mạnh mẽ.


Tôi sẽ nói thêm rằng có lẽ bạn có thể xem qua cách tiếp cận DDD được tán thành bởi Eric Evans et al.
Martijn Verburg

1
Tôi đã đọc cuốn sách của Eric Evans. Nó là tốt cho phương pháp chung và ngôn ngữ phổ biến, nhưng hơi thiếu trong các ví dụ thực tế.
Mag20

Cảm ơn đã chỉ ra sự khác biệt giữa DI và IoC. Tôi nghĩ vấn đề có liên quan nhiều hơn với IoC sau đó DI. Thay đổi câu hỏi để phản ánh điều đó.
Mag20

Theo kinh nghiệm của tôi với DI khung / container (Spring DI, CDI, Unity), họ thực sự làm ngăn cản bạn từ việc tạo ra một "Domain Model đúng", mà với tôi có nghĩa là các nhà phát triển không nên bị hạn chế từ việc sử dụng đúng (ví dụ, stateful) đối tượng . Nhưng DI không thực sự hỗ trợ điều đó.
Rogério

8

Hầu hết (nếu không phải tất cả) các ứng dụng là sự pha trộn giữa các mối quan tâm về cơ sở hạ tầng và tên miền. Khi bạn đạt đến một mức độ phức tạp nhất định, bạn sẽ dễ dàng quản lý hơn nếu tên miền được tách ra khỏi cơ sở hạ tầng để dễ lý luận hơn và có thể phát triển độc lập.

Tất nhiên, mô hình miền vẫn cần liên lạc với phần còn lại của hệ thống và thông thường, điều này sẽ là với các dịch vụ không trạng thái (là một phần của miền) có mối quan tâm về cơ sở hạ tầng (như quyền truy cập cơ sở dữ liệu) được đưa vào chúng. Sử dụng bộ chứa IoC không loại bỏ sự phụ thuộc này, nó di chuyển cấu hình của nó sang một khu vực riêng - một lần nữa giúp dễ dàng lý luận và duy trì.

Các thực thể đang lưu trữ nhà nước và phải chịu trách nhiệm cho các quy tắc kinh doanh. Nếu các dịch vụ của bạn đang thực thi tất cả các bất biến và các quy tắc kinh doanh khác thì có khả năng logic đó đã sai.

Bây giờ nếu bạn đã có logic ở đúng nơi mà vẫn kết thúc với các dịch vụ không hơn bao bọc xung quanh các cơ sở hạ tầng và các thực thể chỉ là túi tài sản thì rất có thể miền không đủ phức tạp để biện minh chi phí hoạt động của mô hình riêng. Bất cứ điều gì bạn sẽ đọc về DDD sẽ có từ chối trách nhiệm rằng nó thực sự chỉ dành cho các tên miền phức tạp, nhưng điều này dường như quá thường xuyên bị lãng quên.


7

Về nguồn. Bắt đầu với tác phẩm của Fowler trên Mô hình miền thiếu máu . Ông tham khảo Thiết kế hướng miền của Eric Evan như một ví dụ về thực hành tốt. Mã nguồn cho điều đó là ở đây . Tải về nó.

Quan sát rằng nó sử dụng Inversion of Control (tìm kiếm @Autowired) và có các lớp dịch vụ (TicketService) và các lớp "quy trình kinh doanh" (ví dụ: ItineraryUpdater).

Bài viết gốc của Fowler bắt đầu con đường dẫn đến ví dụ mà bạn đang tìm kiếm.


Trên thực tế, ứng dụng mẫu đó không phù hợp với DDD như được mô tả trong sách. Một mâu thuẫn cụ thể với cuốn sách là nó hoàn toàn vi phạm khái niệm "cơ sở hạ tầng", bằng cách cho phép nó chứa mã dành riêng cho tên miền; ví dụ, VoyageRepositoryHibernatelớp được đặt trong lớp cơ sở hạ tầng nhưng thực sự phụ thuộc vào lớp miền.
Rogério

Có, cuốn sách nói ở trang 73 rằng lớp cơ sở hạ tầng "bên dưới" lớp miền và "nó không nên có kiến ​​thức đặc biệt về tên miền mà nó đang phục vụ". Điều này chỉ không bao giờ có ý nghĩa với tôi. Hãy xem xét một dự án có hai triển khai VoyageRep repository: VoyageRep repositoryHibernate và một lớp VoyageRep repositoryJDBC. Việc triển khai của họ nhất thiết phải rất khác nhau, và công nghệ cụ thể. Do những thứ này thuộc về lớp miền? Hay tầng cơ sở hạ tầng? Trong mã của chúng tôi, theo cuốn sách, chúng tôi làm điều đó ngược lại: lớp cơ sở hạ tầng có thể tham chiếu lớp miền, nhưng không phải ngược lại.
jamie

Họ thuộc lớp tên miền, vâng. Việc triển khai dựa trên JDBC sẽ chứa mã SQL được liên kết với các bảng và cột trong cơ sở dữ liệu ứng dụng, dành riêng cho miền. Đặt bất kỳ mã tên miền hoặc ứng dụng cụ thể nào vào lớp cơ sở hạ tầng là sai, vì "mã cơ sở hạ tầng" chỉ nên được sử dụng để giải quyết các mối quan tâm kỹ thuật và (lý tưởng) có thể được sử dụng lại hoàn toàn giữa các ứng dụng và miền khác nhau. Giải pháp để có mã "cấp thấp" (ví dụ: SQL) trong lớp miền không phải là loại bỏ hoàn toàn, mà là triển khai nó trên cơ sở hạ tầng tốt hơn, chẳng hạn như ORM.
Rogério

Đối với tôi, việc thực hiện lưu (MyDomainObject foo) là một mối quan tâm thuần túy về mặt kỹ thuật. YMMV.
jamie

Chỉ khi nó không dẫn bạn vi phạm quy tắc cơ bản của kiến ​​trúc phân lớp: lớp thấp hơn không thể phụ thuộc vào lớp cao hơn. Vì vậy, nếu bạn triển khai save(foo)với mã có thể thay đổi khi mô hình miền thay đổi (ví dụ: nếu một thuộc tính mới được thêm vào MyDomainObject), thì nó phải (theo định nghĩa) thuộc về lớp miền; mặt khác, bạn không thể nói về việc có "lớp" nữa.
Rogério

7

có thể sử dụng IoC và Rich Domain không? Có bất kỳ ví dụ tốt, dự án nguồn mở nào làm được điều đó không?

Tôi giả sử bạn có nghĩa là DI thay vì IoC và dự án bạn đã làm việc sử dụng container DI như Spring. IoC có hai hương vị chính: mẫu DI và Locator. Tôi không thấy lý do tại sao mô hình Định vị phải là một vấn đề, vì vậy hãy tập trung vào DI.

Tôi không nghĩ rằng nó có thể, hoặc ít nhất sẽ rất không chính xác. Khía cạnh chính của các thùng chứa DI là chúng kiểm soát việc tạo ra các đối tượng khi chúng tiêm chúng vào các vật thể khác ("các đối tượng được quản lý"). Tập hợp các đối tượng được quản lý còn sống khi các dự án chạy độc lập với các mục miền tồn tại trong dự án của bạn nhưng phụ thuộc vào cách các đối tượng được nối dây và phạm vi nào (singleton, nguyên mẫu) được gán cho chúng.

Đây là lý do tại sao bạn không muốn để bộ chứa DI quản lý các đối tượng miền của mình. Nhưng nếu bạn tạo các đối tượng theo cách thủ công (với mới), bạn không thể đưa các đối tượng khác vào đối tượng miền của mình. . Do đó, bạn sẽ không muốn đặt chức năng vào các đối tượng miền hoặc bạn sẽ mất các tính năng của DI.

Tôi không thấy làm thế nào một container DI giả định có thể hoạt động mà không quản lý các đối tượng của bạn và không có triển khai nào hiện có cho phép điều đó. Vì vậy, thật công bằng khi tuyên bố rằng DI dựa vào việc quản lý các đối tượng. Do đó, nó sẽ luôn cám dỗ bạn chia các đối tượng Rich Domain tiềm năng thành một lớp thiếu máu và một hoặc một vài lớp tập lệnh giao dịch.


Câu trả lời này thực sự đánh vào đầu đinh khi nói đến sự căng thẳng giữa Mô hình miền phong phú và Tiêm phụ thuộc.
jrahhali
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.