Cách tiếp cận DDD với các hoạt động CRUD cơ bản trong một ứng dụng tập trung vào miền phức tạp


9

Công ty của tôi đang viết lại ứng dụng web của chúng tôi từ đầu. Đây là một ứng dụng cấp doanh nghiệp lớn với một lĩnh vực phức tạp trong ngành tài chính.

Chúng tôi đang sử dụng ORM (khung thực thể) để duy trì.

Về bản chất, một nửa ứng dụng của chúng tôi tập trung vào việc thu thập dữ liệu thô từ người dùng, lưu trữ và sau đó, nửa còn lại của ứng dụng chứa hầu hết logic miền thực tế của chúng tôi lấy dữ liệu thô đó để tạo ra hình ảnh miền khác với những gì ban đầu đầu vào thô và chuyển nó vào một động cơ calc, chạy calcs và phun ra kết quả, sau đó được hiển thị cho người dùng.

Trong cách tiếp cận DDD bằng cách sử dụng các lớp, có vẻ như các hoạt động CRUD đi qua lớp miền. nhưng ít nhất trong trường hợp của chúng tôi, điều này dường như không có ý nghĩa.

Khi người dùng vào màn hình chỉnh sửa để thay đổi tài khoản đầu tư, các trường trên màn hình là các trường chính xác được lưu trữ trong cơ sở dữ liệu, không phải là đại diện miền được sử dụng sau này để tính toán. Vậy tại sao tôi lại tải đại diện miền của tài khoản đầu tư khi màn hình chỉnh sửa cần đại diện cơ sở dữ liệu (đầu vào thô)?

Sau khi người dùng nhấp vào "Xong" trên màn hình tài khoản đầu tư và POST được thực hiện cho bộ điều khiển, bộ điều khiển hiện có khá nhiều đại diện cơ sở dữ liệu chính xác của tài khoản đầu tư mà nó cần lưu. Nhưng vì một số lý do, tôi phải tải đại diện miền để sửa đổi thay vì chỉ ánh xạ trực tiếp mô hình của bộ điều khiển vào mô hình cơ sở dữ liệu (mô hình khung thực thể)?

Vì vậy, về bản chất, tôi đang ánh xạ một mô hình dữ liệu vào mô hình miền, để sau đó nó có thể được ánh xạ trở lại mô hình dữ liệu. điều đó có nghĩa gì?

Câu trả lời:


9

Ok hãy tưởng tượng bạn triển khai trang tạo tài khoản của mình ánh xạ bài đăng mẫu trực tiếp đến một đối tượng EF sau đó được lưu vào db.

Cho phép thêm rằng cơ sở dữ liệu có nhiều hạn chế khác nhau để ngăn chặn dữ liệu sai hoàn toàn được nhập vào. Tài khoản luôn có Khách hàng, v.v.

Mọi thứ dường như hoạt động tốt. Nhưng sau đó doanh nghiệp làm cho một quy tắc mới.

  • Tài khoản được tạo vào thứ Năm nhận được lãi suất thưởng 2%. (giả sử lãi suất là một trong các trường tài khoản)

Bây giờ bạn phải đặt logic này ở đâu đó và bạn không có đối tượng miền để đặt nó vào.

DDD giả định rằng bạn sẽ luôn có những loại quy tắc này, và bạn có thể làm được. Tạo một tài khoản phải có nhiều kiểm tra khác nhau, nhật ký kiểm toán, v.v. nó sẽ không chỉ là 'viết một hàng vào db'

Lập kế hoạch tên miền của bạn với giả định rằng không có bộ điều khiển MVC hoặc bộ điều khiển MVC nào có logic bổ sung. Hãy đảm bảo bạn nắm bắt được tất cả các yêu cầu và tất cả chúng đều nằm trong mô hình miền.


3
Đó là một cách tốt để đặt nó. Tôi ghét việc tìm kiếm các quy tắc kinh doanh trộn lẫn với các chi tiết DB. +1
candied_orange

Điểm tốt, nhưng nếu các quy tắc xác thực này chỉ áp dụng trong quá trình tạo và cập nhật đầu vào của người dùng thì sao? Sau đó, khi chúng ta có đầu vào của người dùng, mô hình được tạo khi chạy tính toán là một mô hình hoàn toàn khác. Chúng ta có nên có hai mô hình miền cho một tài khoản đầu tư? Một cho các hoạt động CRUD của đầu vào thô cho người dùng và một cho các đầu vào đó được sử dụng để tạo mô hình miền được sử dụng trong tính toán?
Wired_in

làm tôi bối rối bạn sẽ phải đưa ra một ví dụ đầy đủ. Nếu bạn có logic miền thì nó phải đi trong một đối tượng miền. Điều đó không có nghĩa là bạn không thể tạo một đối tượng miền khác sau đó từ đối tượng đầu tiên
Ewan

Hãy tưởng tượng một công cụ tính toán phức tạp. Một trong những đầu vào cần thiết để chạy tính toán là tài khoản đầu tư, nhưng tất cả tài khoản đầu tư vào công cụ calc là một dòng thu nhập trong một khoảng thời gian. Mô hình miền của tài khoản đầu tư này hoàn toàn khác với đầu vào thô mà người dùng đã nhập cho tài khoản đầu tư này. Tuy nhiên, khi người dùng đang nhập các đầu vào cơ bản như Tên, Giá trị hiện tại, v.v. vẫn cần phải có logic xác thực, nhưng nó không liên quan gì đến mô hình mà công cụ calc sử dụng. Vì vậy, có hai mô hình miền cho một tài khoản đầu tư ở đây?
Wired_in

..... hoặc có thể có một mô hình tài khoản đầu tư trong miền là quá mức cần thiết cho các hoạt động CRUD và chỉ nên có một số thuộc tính trình xác nhận được sử dụng hoặc một cái gì đó
Wired_in

7

điều đó có nghĩa gì?

Câu trả lời ngắn gọn: không .

Câu trả lời dài hơn: các mẫu nặng để phát triển mô hình miền không áp dụng cho các phần của giải pháp đó chỉ là cơ sở dữ liệu.

Udi Dahan đã có một quan sát thú vị có thể giúp làm rõ điều này

Dahan cho rằng một dịch vụ phải có cả chức năng và dữ liệu. Nếu nó không có dữ liệu, thì đó chỉ là một chức năng. Nếu tất cả những gì nó làm là thực hiện các thao tác CRUD trên dữ liệu, thì đó là cơ sở dữ liệu.

Quan điểm của mô hình miền, xét cho cùng, là đảm bảo rằng tất cả các cập nhật cho dữ liệu duy trì bất biến kinh doanh hiện tại. Hoặc, nói cách khác, mô hình miền chịu trách nhiệm đảm bảo rằng cơ sở dữ liệu hoạt động như hệ thống bản ghi là chính xác.

Khi bạn đang xử lý một hệ thống CRUD, bạn thường không phải là hệ thống ghi dữ liệu. Thế giới thực là cuốn sách kỷ lục và cơ sở dữ liệu của bạn chỉ là một đại diện được lưu trữ cục bộ của thế giới thực.

Chẳng hạn, hầu hết thông tin xuất hiện trong hồ sơ người dùng, như địa chỉ email hoặc số nhận dạng do chính phủ cấp, có nguồn sự thật nằm ngoài doanh nghiệp của bạn - đó là quản trị viên thư của người khác gán và thu hồi địa chỉ email, không phải ứng dụng của bạn. Chính phủ chỉ định SSN, không phải ứng dụng của bạn.

Vì vậy, thông thường bạn sẽ không thực hiện bất kỳ xác thực tên miền nào trên dữ liệu đến với bạn từ thế giới bên ngoài; bạn có thể kiểm tra tại chỗ để đảm bảo dữ liệu được hình thành tốt và được vệ sinh đúng cách ; nhưng đó không phải là dữ liệu của bạn - mô hình miền của bạn không có quyền phủ quyết.

Trong cách tiếp cận DDD bằng cách sử dụng các lớp, có vẻ như các hoạt động CRUD đi qua lớp miền. nhưng ít nhất trong trường hợp của chúng tôi, điều này dường như không có ý nghĩa.

Điều đó đúng cho trường hợp cơ sở dữ liệu là sổ ghi chép .

Ouarzy đặt nó theo cách này .

Mặc dù làm việc với rất nhiều mã kế thừa, tôi quan sát các lỗi phổ biến để xác định những gì bên trong miền và những gì bên ngoài.

Một ứng dụng có thể được coi là CRUD chỉ khi không có logic nghiệp vụ xung quanh mô hình dữ liệu. Ngay cả trong trường hợp (hiếm) này, mô hình dữ liệu của bạn không phải là mô hình miền của bạn. Điều đó chỉ có nghĩa là, vì không có logic kinh doanh nào được tham gia, chúng tôi không cần bất kỳ sự trừu tượng hóa nào để quản lý nó và do đó chúng tôi không có mô hình miền.

Chúng tôi sử dụng mô hình miền để quản lý dữ liệu thuộc về miền; dữ liệu từ bên ngoài miền đã được quản lý ở một nơi khác - chúng tôi chỉ lưu trữ một bản sao.

Greg Young sử dụng các hệ thống kho như một minh họa chính cho các giải pháp trong đó sổ ghi chép ở một nơi khác (ví dụ: sàn kho). Việc triển khai mà anh mô tả rất giống với cơ sở dữ liệu của bạn - một cơ sở dữ liệu logic để thu thập các thông điệp nhận được từ kho, và sau đó là một cơ sở dữ liệu logic riêng biệt lưu trữ các kết luận rút ra từ phân tích các thông báo đó.

Vì vậy, có lẽ chúng ta có hai bối cảnh giới hạn ở đây? Mỗi người có một mô hình khác nhau cho mộtinvestment account

Có lẽ. Tôi miễn cưỡng gắn thẻ nó như một bối cảnh bị ràng buộc, bởi vì không rõ hành lý khác đi kèm với nó là gì. Có thể là bạn có hai bối cảnh, đó có thể là một bối cảnh với sự khác biệt tinh tế trong ngôn ngữ phổ biến mà bạn chưa chọn.

Kiểm tra giấy quỳ có thể có: bạn cần bao nhiêu chuyên gia tên miền để bao quát phổ này hoặc chỉ một người nói về các thành phần theo những cách khác nhau. Về cơ bản, bạn có thể đoán được bạn có bao nhiêu bối cảnh bị ràng buộc bằng cách làm ngược luật của Conway.

Nếu bạn coi bối cảnh giới hạn được liên kết với các dịch vụ, có thể dễ dàng hơn: bạn có thể triển khai hai phần chức năng này một cách độc lập không? Có gợi ý hai bối cảnh giới hạn; nhưng nếu chúng cần được giữ đồng bộ, thì có lẽ nó chỉ là một.


Vâng, có xác thực và logic mặc định, nhưng nó chỉ áp dụng khi tạo / cập nhật các đầu vào thô cho tài khoản đầu tư. Sau đó, chúng tôi sử dụng một mô hình phong phú hơn nhiều cho tài khoản đầu tư khi chúng tôi sử dụng nó làm đầu vào cho một công cụ calc. Vì vậy, có lẽ chúng ta có hai bối cảnh giới hạn ở đây? Mỗi người có một mô hình khác nhau cho một tài khoản đầu tư '
Wired_in

Tôi mới trở lại vấn đề này sau vài năm và nhận xét của bạn đang gây được tiếng vang hơn trước vì một số lý do. Có rất nhiều thứ hay ho ở đây, nhưng bạn có thể làm rõ một điều cho tôi không? Bạn nói "Quan điểm của mô hình miền, xét cho cùng, là đảm bảo rằng tất cả các cập nhật cho dữ liệu duy trì bất biến kinh doanh hiện tại." Điều này sẽ áp dụng cho phần ứng dụng của chúng tôi lưu / cập nhật thông tin. Phần khác chỉ là một công cụ tính toán. Nó lấy một đại diện của dữ liệu làm đầu vào và phun ra kết quả. Có phải đó không phải là một phần của mô hình miền không? Vì nó không ảnh hưởng đến dữ liệu được lưu trữ?
Wired_in

2

Trong miền của bạn, bạn không cần phải biết rằng cơ sở dữ liệu thậm chí còn tồn tại.

Tên miền của bạn là về các quy tắc kinh doanh. Những thứ cần tồn tại khi công ty làm cho cơ sở dữ liệu của bạn bị phá sản. Đó là, nếu bạn muốn công ty của bạn tồn tại. Thật tuyệt khi những quy tắc đó không quan tâm rằng bạn đã thay đổi cách bạn duy trì dữ liệu.

Chi tiết cơ sở dữ liệu tồn tại và cần phải được xử lý. Họ nên sống ở một nơi khác. Đặt chúng qua một ranh giới. Kiểm soát cẩn thận cách bạn giao tiếp qua ranh giới đó hoặc đó không phải là ranh giới.

Chú Bob có điều này để nói về những gì cần đưa dữ liệu của bạn vào:

Thông thường dữ liệu vượt qua các ranh giới là các cấu trúc dữ liệu đơn giản. Bạn có thể sử dụng các cấu trúc cơ bản hoặc các đối tượng Truyền dữ liệu đơn giản nếu muốn. Hoặc dữ liệu có thể chỉ đơn giản là đối số trong các cuộc gọi chức năng. Hoặc bạn có thể đóng gói nó thành một hashmap hoặc xây dựng nó thành một đối tượng.

Điều quan trọng là các cấu trúc dữ liệu đơn giản, đơn độc được truyền qua các ranh giới. Chúng tôi không muốn gian lận và vượt qua các hàng Thực thể hoặc Cơ sở dữ liệu. Chúng tôi không muốn các cấu trúc dữ liệu có bất kỳ loại phụ thuộc nào vi phạm Quy tắc phụ thuộc.

[V]] khi chúng tôi chuyển dữ liệu qua một ranh giới, nó luôn ở dạng thuận tiện nhất cho vòng tròn bên trong.

Kiến trúc sạch

Ông cũng giải thích làm thế nào các lớp bên ngoài của bạn phải là bổ sung cho các lớp bên trong của bạn để các lớp bên trong thậm chí không biết các lớp bên ngoài tồn tại.

Kiến trúc sạch cheat sheet

Làm theo cách tương tự và bạn sẽ có một vị trí đẹp để bỏ qua cơ sở dữ liệu nơi bạn có thể lo lắng về quy tắc xác thực đầu vào, quy tắc đầu vào phải được duy trì bằng cách nào đó, quy tắc để chạy tính toán, quy tắc để gửi kết quả đó đến bất kỳ đầu ra nào. Thật ra việc đọc loại mã này thực sự dễ dàng hơn.

Đó là hoặc bạn quyết định rằng tên miền của bạn thực sự chỉ để thao túng cơ sở dữ liệu. Trong trường hợp đó, ngôn ngữ miền của bạn là SQL. Nếu tốt như vậy nhưng đừng hy vọng việc bạn thực hiện các quy tắc kinh doanh sẽ tồn tại một sự thay đổi trong sự kiên trì. Cuối cùng bạn sẽ cần phải viết lại hoàn toàn chúng.


Chúng tôi đang sử dụng ORM (Entity Framework), vì vậy cơ sở dữ liệu của chúng tôi đã được trừu tượng hóa, nhưng các mô hình dữ liệu (các lớp khung thực thể) tự nhiên có khá nhiều từ 1 đến 1 với các bảng cơ sở dữ liệu. Vấn đề là trong một số phần của ứng dụng của chúng tôi, người dùng về cơ bản chỉ là cập nhật mô hình dữ liệu (màn hình chỉ là một danh sách các hộp văn bản trong đó mỗi hộp văn bản là một trường trong cơ sở dữ liệu (mô hình dữ liệu).
Wired_in

Vì vậy, tôi không thấy một lý do để không chỉ sử dụng các biểu diễn của dữ liệu thô (mô hình dữ liệu) khi thực hiện các thao tác CRUD. Chúng tôi có một đại diện miền phức tạp được sử dụng để tính toán, đó là những gì tôi xem là mô hình miền của chúng tôi, nhưng tôi không hiểu tại sao tôi lại tải lên hình ảnh đó trong phần CRUD trong ứng dụng của chúng tôi.
Wired_in

Xác định ý của bạn bằng cách "sử dụng các biểu diễn của dữ liệu thô". Dữ liệu là đầu vào, dữ liệu được xác thực theo quy tắc tên miền, dữ liệu được duy trì bằng cách nào đó, dữ liệu được tính ngược lại, kết quả là đầu ra cho bất cứ điều gì. Tui bỏ lỡ điều gì vậy?
candied_orange

Tôi đang cố gắng nói rằng dữ liệu thô mà chúng tôi nhận được từ người dùng cho tài khoản đầu tư không phải là cách chúng tôi thể hiện tài khoản đầu tư đó trong các phần chính của ứng dụng, như khi nó được sử dụng cho calcs. Chẳng hạn, chúng ta có thể có một đầu vào boolean mà chúng ta lưu trong cơ sở dữ liệu có tên IsManagedAccount. Người dùng cung cấp cho chúng tôi điều này thông qua một nút radio trên màn hình chỉnh sửa. Vì vậy, đại diện từ cơ sở dữ liệu xuống màn hình là 1 đến 1. Khi chúng tôi xây dựng mô hình miền sau này trong ứng dụng, chúng tôi có thể có lớp ManagedAccount, do đó không có thuộc tính boolean. Hai cấu trúc rất khác nhau.
Wired_in

Vì vậy, khi người dùng chỉ chỉnh sửa các đầu vào thô trên màn hình chỉnh sửa, tại sao tôi lại tải hình ảnh tên miền và sau đó thêm rất nhiều phức tạp để ánh xạ bằng cách nào đó gõ mạnh lớp ManagedAccount trở lại một đại diện phẳng chỉ là một lớp duy nhất với IsManagedAccount bất động sản?
Wired_in

1

Áp dụng lý thuyết DDD:

Có hai bối cảnh bị ràng buộc trong miền đó:

  • Các tính toán của tài khoản đầu tư. Mô hình toán học tài khoản đầu tư là một yếu tố có thể là Tổng hợp.
  • Tài chính cốt lõi. Tài khoản đầu tư của khách hàng là một trong những Thực thể.

Mỗi Bối cảnh Bounded có thể có một thiết kế kiến ​​trúc khác nhau.

Thí dụ:

Tài khoản đầu tư của khách hàng là một Thực thể (có thể là Tổng hợp, tùy thuộc vào tên miền) và tính bền vững của dữ liệu được thực hiện thông qua Kho lưu trữ của thực thể (RDB hoặc loại DB khác như Cơ sở dữ liệu OO).

Không có cách tiếp cận DDD đối với các hoạt động CRUD. Để có một trường DB được gắn với dữ liệu của một đối tượng phá vỡ các nguyên tắc thiết kế.

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.