Là khớp nối lỏng lẻo không sử dụng trường hợp chống mẫu?


22

Ghép nối lỏng lẻo, đối với một số nhà phát triển, là chén thánh của phần mềm được thiết kế tốt. Đó chắc chắn là một điều tốt khi nó làm cho mã linh hoạt hơn khi đối mặt với những thay đổi có thể xảy ra trong tương lai gần hoặc tránh được sự sao chép mã.

Mặt khác, những nỗ lực để ghép đôi các thành phần một cách lỏng lẻo làm tăng lượng cảm ứng trong một chương trình, do đó làm tăng sự phức tạp của nó, thường làm cho nó trở nên khó hiểu hơn và thường làm cho nó kém hiệu quả hơn.

Bạn có xem trọng tâm của khớp nối lỏng lẻo mà không có bất kỳ trường hợp sử dụng nào cho khớp nối lỏng lẻo (chẳng hạn như tránh sao chép mã hoặc lập kế hoạch cho các thay đổi có thể xảy ra trong tương lai gần) là một mô hình chống? Khớp nối lỏng có thể rơi dưới chiếc ô của YAGNI?


1
Hầu hết các lợi ích đi kèm với một chi phí. Sử dụng nếu lợi ích vượt xa chi phí.
LennyProgrammer

4
bạn đã quên mặt trái của đồng xu khớp nối lỏng lẻo, và cái này high cohesionkhông có cái kia là một sự lãng phí công sức và minh họa thiếu hiểu biết cơ bản của một trong hai.

Câu trả lời:


13

Một chút nào đó.

Đôi khi khớp nối lỏng lẻo mà không cần quá nhiều nỗ lực là tốt, ngay cả khi bạn không có yêu cầu cụ thể yêu cầu một số mô-đun được tách rời. Trái cây treo thấp, như nó đã được.

Mặt khác, việc áp đảo cho số lượng thay đổi lố bịch sẽ có rất nhiều phức tạp và nỗ lực không cần thiết. YAGNI, như bạn nói, đánh vào đầu nó.


22

Thực hành lập trình X tốt hay xấu? Rõ ràng, câu trả lời luôn luôn là"nó phụ thuộc."

Nếu bạn đang xem mã của mình, tự hỏi "mẫu" nào bạn có thể tiêm, thì bạn đã làm sai.

Nếu bạn đang xây dựng phần mềm của mình để các đối tượng không liên quan không đùa nghịch với nhau, thì bạn đã làm đúng.

Nếu bạn đang "thiết kế" giải pháp của mình để nó có thể được mở rộng và thay đổi vô hạn, thì thực tế bạn đang làm cho nó trở nên phức tạp hơn.

Tôi nghĩ vào cuối ngày, bạn còn lại với một sự thật duy nhất: có ít nhiều phức tạp để có các đối tượng tách rời? Nếu nó ít phức tạp hơn để ghép chúng, thì đó là giải pháp chính xác. Nếu nó ít phức tạp hơn để tách chúng ra, thì đó là giải pháp phù hợp.

(Hiện tại tôi đang làm việc trong một cơ sở mã khá nhỏ, thực hiện một công việc đơn giản theo một cách rất phức tạp và một phần của điều khiến nó trở nên phức tạp là sự thiếu hiểu biết về các thuật ngữ "khớp nối" và "gắn kết" trên một phần của bản gốc nhà phát triển.)


4
Tôi đã làm điều này chỉ vào một ngày khác: Tôi nghĩ rằng tôi sẽ cần một chút gián tiếp giữa hai lớp "chỉ trong trường hợp". Sau đó, tôi đau đầu cố gắng gỡ lỗi một cái gì đó, xé toạc sự gián tiếp, và hạnh phúc hơn nhiều.
Frank Shearar

3

Tôi nghĩ những gì bạn nhận được ở đây là khái niệm về sự gắn kết . Liệu mã này có một mục đích tốt? Tôi có thể tiếp thu mục đích đó và hiểu "bức tranh lớn" về những gì đang diễn ra không?

Nó có thể dẫn đến mã khó theo dõi, không chỉ vì có nhiều tệp nguồn hơn (giả sử đây là các lớp riêng biệt), nhưng vì dường như không có lớp nào có mục đích.

Từ góc độ nhanh, tôi có thể đề xuất rằng khớp nối lỏng lẻo như vậy sẽ là một mô hình chống. Nếu không có sự gắn kết, hoặc thậm chí sử dụng các trường hợp cho nó, bạn không thể viết các bài kiểm tra đơn vị hợp lý và không thể xác minh mục đích của mã. Bây giờ, mã nhanh có thể dẫn đến khớp nối lỏng lẻo, ví dụ như khi phát triển dựa trên thử nghiệm được sử dụng. Nhưng nếu các thử nghiệm đúng được tạo ra, theo đúng thứ tự, thì có khả năng có cả sự gắn kết tốt và khớp nối lỏng lẻo. Và bạn chỉ nói về những trường hợp khi rõ ràng không có sự gắn kết nào ở đó.

Một lần nữa từ quan điểm nhanh nhẹn, bạn không muốn mức độ gián tiếp giả tạo này bởi vì nó lãng phí nỗ lực vào một cái gì đó có lẽ sẽ không cần thiết dù sao. Tái cấu trúc dễ dàng hơn nhiều khi nhu cầu là có thật.

Nhìn chung, bạn muốn khớp nối cao trong các mô-đun của mình và khớp nối lỏng lẻo giữa chúng. Nếu không có khớp nối cao, có lẽ bạn không có sự gắn kết.


1

Đối với phần lớn các câu hỏi như thế này, câu trả lời là "nó phụ thuộc". Nhìn chung, nếu tôi có thể làm cho một thiết kế được kết hợp một cách hợp lý theo những cách có ý nghĩa, mà không cần một chi phí lớn để làm như vậy, tôi sẽ làm. Theo tôi, tránh việc ghép mã không cần thiết là một mục tiêu thiết kế hoàn toàn xứng đáng.

Một khi xảy ra tình huống có vẻ như các thành phần cần được kết hợp chặt chẽ, tôi sẽ tìm kiếm một cuộc tranh luận hấp dẫn trước khi tôi bắt đầu phá vỡ chúng.

Tôi đoán nguyên tắc tôi làm việc với hầu hết các loại thực hành này là một quán tính. Tôi có một ý tưởng về cách tôi muốn mã của tôi hoạt động và nếu tôi có thể làm theo cách đó mà không làm cho cuộc sống khó khăn hơn thì tôi sẽ làm. Nếu làm điều đó sẽ làm cho việc phát triển trở nên khó khăn hơn nhưng việc bảo trì và công việc trong tương lai dễ dàng hơn, tôi sẽ thử và đoán xem liệu nó sẽ làm việc nhiều hơn trong suốt vòng đời của mã và sử dụng nó làm hướng dẫn của tôi. Nếu không, nó sẽ cần phải là một điểm thiết kế có chủ ý để có giá trị đi cùng.


1

Câu trả lời đơn giản là khớp nối lỏng là tốt khi được thực hiện chính xác.

Nếu nguyên tắc của một chức năng, một mục đích được tuân theo thì nó sẽ đủ dễ dàng để làm theo những gì đang diễn ra. Ngoài ra, mã cặp đôi lỏng lẻo là một vấn đề tất nhiên mà không cần bất kỳ nỗ lực.

Quy tắc thiết kế đơn giản: 1. không xây dựng kiến ​​thức về nhiều mặt hàng thành một điểm duy nhất (như được chỉ ra ở mọi nơi, tùy thuộc) trừ khi bạn đang xây dựng giao diện mặt tiền. 2. một chức năng - một mục đích (mục đích đó có thể là nhiều mặt như trong một mặt tiền) 3. một mô-đun - một tập hợp rõ ràng các chức năng liên quan đến nhau - một mục đích rõ ràng 4. nếu bạn không thể đơn giản kiểm tra đơn vị thì nó không có một mục đích đơn giản

Tất cả những nhận xét về việc tái cấu trúc dễ dàng hơn sau này là một tải các cod. Một khi kiến ​​thức được tích hợp vào nhiều nơi, đặc biệt là trong các hệ thống phân tán, chi phí tái cấu trúc, đồng bộ hóa và mọi chi phí khác sẽ khiến nó bị loại bỏ vì cho rằng trong hầu hết các trường hợp, hệ thống cuối cùng bị vứt bỏ vì nó.

Điều đáng buồn về phát triển phần mềm ngày nay là 90% mọi người phát triển các hệ thống mới và không có khả năng hiểu các hệ thống cũ, và không bao giờ có mặt khi hệ thống gặp phải tình trạng sức khỏe kém như vậy do liên tục tái cấu trúc các bit và miếng.


0

Không quan trọng việc kết hợp chặt chẽ giữa một thứ với nhau như thế nào nếu điều đó không bao giờ thay đổi. Nhìn chung, tôi đã thấy nó hiệu quả hơn trong nhiều năm qua để tập trung vào việc tìm kiếm ít lý do hơn để thay đổi, tìm kiếm sự ổn định, hơn là làm cho chúng dễ dàng thay đổi hơn bằng cách cố gắng đạt được hình thức khớp nối lỏng lẻo nhất có thể. Việc tách riêng tôi thấy rất hữu ích, đến mức đôi khi tôi thích sao chép mã khiêm tốn cho các gói tách rời. Để làm ví dụ cơ bản, tôi có lựa chọn sử dụng thư viện toán học của mình để triển khai thư viện hình ảnh. Tôi đã không và chỉ sao chép một số hàm toán học cơ bản không đáng để sao chép.

Bây giờ thư viện hình ảnh của tôi hoàn toàn độc lập với thư viện toán học theo cách mà bất kể loại thay đổi nào tôi thực hiện đối với lib toán học của tôi, nó sẽ không ảnh hưởng đến thư viện hình ảnh. Đó là đặt sự ổn định lên trên hết. Hiện tại thư viện hình ảnh ổn định hơn, vì có rất ít lý do để thay đổi, vì nó được tách ra khỏi bất kỳ thư viện nào khác có thể thay đổi (ngoài thư viện tiêu chuẩn C hy vọng sẽ không bao giờ thay đổi). Như một phần thưởng, nó cũng dễ dàng triển khai khi nó chỉ là một thư viện độc lập không yêu cầu kéo theo một loạt các lib khác để xây dựng và sử dụng nó.

Sự ổn định là rất hữu ích với tôi. Tôi thích xây dựng một bộ sưu tập mã được kiểm tra tốt, có ngày càng ít lý do để thay đổi trong tương lai. Đó không phải là một giấc mơ xa vời; Tôi có mã C tôi đã sử dụng và sử dụng lại từ cuối những năm 80 mà không thay đổi gì kể từ đó. Nó được thừa nhận là những thứ cấp thấp như mã định hướng pixel và liên quan đến hình học trong khi rất nhiều thứ cấp cao hơn của tôi trở nên lỗi thời, nhưng nó vẫn là thứ giúp ích rất nhiều cho xung quanh. Điều đó hầu như luôn có nghĩa là một thư viện dựa vào ngày càng ít thứ hơn, nếu không có gì bên ngoài cả. Độ tin cậy tăng lên và tăng lên nếu phần mềm của bạn ngày càng phụ thuộc vào nền tảng ổn định mà tìm thấy ít hoặc không có lý do để thay đổi. Ít bộ phận chuyển động thực sự tốt đẹp, ngay cả trong thực tế, các bộ phận chuyển động có số lượng lớn hơn nhiều so với các bộ phận ổn định.

Khớp nối lỏng lẻo nằm trong cùng một tĩnh mạch, nhưng tôi thấy rằng khớp nối lỏng lẻo kém ổn định hơn nhiều so với không khớp nối. Trừ khi bạn làm việc trong một nhóm với các nhà thiết kế giao diện và khách hàng vượt trội hơn nhiều so với những gì tôi từng làm việc, thậm chí các giao diện thuần túy thường tìm lý do để thay đổi theo cách vẫn gây ra sự phá vỡ tầng trong mã. Ý tưởng này có thể đạt được sự ổn định bằng cách hướng sự phụ thuộc vào trừu tượng hơn là cụ thể chỉ hữu ích nếu thiết kế giao diện dễ dàng có được ngay lần đầu tiên so với việc thực hiện. Tôi thường thấy nó đảo ngược nơi mà một nhà phát triển có thể đã tạo ra một triển khai rất tốt, nếu không tuyệt vời, đưa ra các yêu cầu thiết kế mà họ nghĩ họ nên đáp ứng, chỉ để thấy trong tương lai các yêu cầu thiết kế thay đổi hoàn toàn.

Vì vậy, tôi thích ưu tiên sự ổn định và tách rời hoàn toàn để ít nhất tôi có thể tự tin nói: "Thư viện biệt lập nhỏ bé này đã được sử dụng trong nhiều năm và được bảo đảm bằng thử nghiệm kỹ lưỡng gần như không có khả năng yêu cầu thay đổi cho dù có xảy ra trong thế giới hỗn loạn bên ngoài . " Nó mang lại cho tôi một chút tỉnh táo bất kể loại thay đổi thiết kế nào được gọi cho bên ngoài.

Khớp nối và ổn định, ví dụ ECS

Tôi cũng thích các hệ thống thành phần thực thể và chúng giới thiệu rất nhiều khớp nối chặt chẽ bởi vì hệ thống phụ thuộc vào thành phần tất cả truy cập và thao tác trực tiếp dữ liệu thô, như vậy:

nhập mô tả hình ảnh ở đây

Tất cả các phụ thuộc ở đây là khá chặt chẽ vì các thành phần chỉ lộ dữ liệu thô. Các phần phụ thuộc không chảy theo trừu tượng, chúng chuyển sang dữ liệu thô , điều đó có nghĩa là mỗi hệ thống có lượng kiến ​​thức tối đa có thể về từng loại thành phần mà chúng yêu cầu truy cập. Các thành phần không có chức năng với tất cả các hệ thống truy cập và giả mạo dữ liệu thô. Tuy nhiên, thật dễ dàng để suy luận về một hệ thống như thế này vì nó quá phẳng. Nếu một kết cấu xuất hiện khó khăn, thì bạn sẽ biết ngay với hệ thống này rằng chỉ có các thành phần kết cấu và vẽ hệ thống truy cập, và bạn có thể nhanh chóng loại trừ hệ thống kết xuất vì nó chỉ đọc từ kết cấu.

Trong khi đó, một sự thay thế kết hợp lỏng lẻo có thể là thế này:

nhập mô tả hình ảnh ở đây

... Với tất cả các phụ thuộc chảy vào các hàm trừu tượng, không phải dữ liệu và mọi thứ trong sơ đồ đó phơi bày một giao diện công cộng và chức năng của chính nó. Ở đây tất cả các phụ thuộc có thể rất lỏng lẻo. Các đối tượng thậm chí có thể không phụ thuộc trực tiếp vào nhau và tương tác với nhau thông qua các giao diện thuần túy. Tuy nhiên, rất khó để suy luận về hệ thống này, đặc biệt là nếu có sự cố xảy ra, do các mớ tương tác phức tạp. Cũng sẽ có nhiều tương tác (nhiều khớp nối hơn, mặc dù lỏng hơn) so với ECS vì các thực thể phải biết về các thành phần mà chúng tổng hợp, ngay cả khi chúng chỉ biết về giao diện chung trừu tượng của nhau.

Ngoài ra, nếu có thay đổi thiết kế đối với bất cứ điều gì, bạn sẽ nhận được nhiều sự phá vỡ tầng hơn ECS, và thường sẽ có nhiều lý do và cám dỗ cho thay đổi thiết kế vì mỗi điều đều cố gắng cung cấp một giao diện hướng đối tượng và trừu tượng đẹp. Điều đó ngay lập tức đi kèm với ý tưởng rằng mỗi một điều nhỏ nhặt sẽ cố gắng áp đặt các hạn chế và hạn chế đối với thiết kế, và những hạn chế đó thường là những gì bảo đảm thay đổi thiết kế. Chức năng bị hạn chế hơn nhiều và phải đưa ra rất nhiều giả định thiết kế so với dữ liệu thô.

Trên thực tế, tôi đã tìm thấy loại hệ thống ECS ​​"phẳng" ở trên dễ hiểu hơn rất nhiều so với các hệ thống được ghép lỏng lẻo nhất với một mạng nhện phức tạp của sự phụ thuộc lỏng lẻo và quan trọng nhất với tôi, tôi thấy rất ít lý do đối với phiên bản ECS cần phải thay đổi bất kỳ thành phần hiện có nào vì các thành phần phụ thuộc không có trách nhiệm ngoại trừ việc cung cấp dữ liệu phù hợp cần thiết cho các hệ thống hoạt động. So sánh khó khăn trong việc thiết kế IMotiongiao diện thuần túy và đối tượng chuyển động cụ thể thực hiện giao diện đó cung cấp chức năng tinh vi trong khi cố gắng duy trì bất biến trên dữ liệu riêng tư so với thành phần chuyển động chỉ cần cung cấp dữ liệu thô có liên quan để giải quyết vấn đề và không bận tâm với chức năng.

Chức năng rất khó để có được quyền hơn dữ liệu, đó là lý do tại sao tôi nghĩ rằng thường là tốt hơn để hướng luồng phụ thuộc vào dữ liệu. Rốt cuộc, có bao nhiêu thư viện vector / ma trận ngoài kia? Có bao nhiêu trong số chúng sử dụng cùng một biểu diễn dữ liệu và chỉ khác nhau một cách tinh tế về chức năng? Vô số, nhưng chúng tôi vẫn có rất nhiều mặc dù biểu diễn dữ liệu giống hệt nhau bởi vì chúng tôi muốn sự khác biệt tinh tế trong chức năng. Có bao nhiêu thư viện hình ảnh ngoài kia? Có bao nhiêu trong số chúng đại diện cho pixel theo một cách khác biệt và độc đáo? Hầu như không, và một lần nữa cho thấy chức năng không ổn định hơn nhiều và thiên về thay đổi thiết kế so với dữ liệu trong nhiều tình huống. Tất nhiên, tại một số điểm chúng tôi cần chức năng, nhưng bạn có thể thiết kế các hệ thống trong đó phần lớn các phụ thuộc chảy vào dữ liệu, và không hướng tới sự trừu tượng hay chức năng nói chung. Như vậy sẽ được ưu tiên ổn định trên khớp nối.

Các hàm ổn định nhất tôi từng viết (loại tôi đã sử dụng và sử dụng lại từ cuối những năm 80 mà không phải thay đổi chúng) đều là những hàm dựa trên dữ liệu thô, giống như một hàm hình học chỉ chấp nhận một mảng số float và số nguyên, không phải số nguyên phụ thuộc vào một Meshđối tượng hoặc IMeshgiao diện phức tạp , hoặc phép nhân vectơ / ma trận chỉ phụ thuộc vào float[]hoặc double[], không phụ thuộc vào FancyMatrixObjectWhichWillRequireDesignChangesNextYearAndDeprecateWhatWeUse.

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.