Vi phạm nguyên tắc DRY


10

Tôi chắc chắn có một tên cho mô hình chống này ở đâu đó; tuy nhiên tôi không đủ quen thuộc với các tài liệu chống mẫu để biết nó.

Hãy xem xét kịch bản sau đây:

or0là một hàm thành viên trong một lớp. Dù tốt hay xấu, nó phụ thuộc rất nhiều vào các biến thành viên của lớp. Lập trình viên A xuất hiện và cần chức năng như or0nhưng thay vì gọi or0, Lập trình viên A sao chép và đổi tên toàn bộ lớp. Tôi đoán rằng cô ấy không gọi or0bởi vì, như tôi nói, nó phụ thuộc rất nhiều vào các biến thành viên cho chức năng của nó. Hoặc có thể cô ấy là một lập trình viên cơ sở và không biết cách gọi nó từ mã khác. Vì vậy, bây giờ chúng tôi đã có or0c0(c cho bản sao). Tôi không thể hoàn toàn có lỗi với Lập trình viên A cho cách tiếp cận này - tất cả chúng ta đều có thời hạn chặt chẽ và chúng tôi hack mã để hoàn thành công việc.

Một số lập trình viên duy trì or0để bây giờ là phiên bản orN. c0bây giờ là phiên bản cN. Thật không may, hầu hết các lập trình viên duy trì lớp chứa or0dường như hoàn toàn không biết c0- đây là một trong những lập luận mạnh mẽ nhất mà tôi có thể nghĩ về sự khôn ngoan của nguyên tắc DRY. Và cũng có thể có sự duy trì độc lập của mã trong c. Dù bằng cách nào nó cũng xuất hiện or0c0được duy trì độc lập với nhau. Và, niềm vui và hạnh phúc, một lỗi xảy ra trong cNđó không xảy ra orN.

Vì vậy, tôi có một vài câu hỏi:

1.) Có một tên cho mô hình chống này? Tôi đã thấy điều này xảy ra thường xuyên. Tôi cảm thấy khó tin rằng đây không phải là một kiểu chống tên.

2.) Tôi có thể thấy một vài lựa chọn thay thế:

a.) Khắc phục orNđể lấy tham số chỉ định giá trị của tất cả các biến thành viên cần. Sau đó sửa đổi cNđể gọi orNvới tất cả các tham số cần thiết được truyền vào.

b.) Cố gắng sửa lỗi cổng thủ công từ orNđến cN. (Hãy nhớ rằng tôi không muốn làm điều này nhưng đó là một khả năng thực tế.)

c.) Recopy orNto cN--again, yuck nhưng tôi liệt kê nó để hoàn thiện.

d.) Cố gắng tìm ra nơi cNbị hỏng và sau đó sửa chữa nó một cách độc lập orN.

Thay thế một có vẻ như việc sửa chữa tốt nhất trong thời gian dài nhưng tôi nghi ngờ khách hàng sẽ cho tôi thực hiện nó. Không bao giờ thời gian hay tiền bạc để sửa chữa mọi thứ đúng nhưng luôn luôn có thời gian và tiền bạc để sửa chữa cùng một vấn đề 40 hoặc 50 lần, phải không?

Bất cứ ai có thể đề nghị các phương pháp khác tôi có thể không xem xét?


"Có một tên cho mô hình chống này?" Mẫu chống vi phạm 'khô-vi'? :) IMHO bạn khá nhiều trả lời nó cho mình.
Steven Jeuris

Có thể gọi nó là "Kẻ vi phạm khô"?
Thất vọngWithFormsDesigner

2
Tôi gọi nó là: DRY va chạm.
AJC

5
Sao chép và dán mã hóa?
tylermac

Nó được gọi là mô hình "quá nhiều đầu bếp làm hỏng nước dùng".
Doc Brown

Câu trả lời:


18
  1. nó chỉ được gọi là mã trùng lặp - tôi không biết bất kỳ tên nào lạ mắt hơn cho cái này. Hậu quả lâu dài là như bạn mô tả, và tồi tệ hơn.

  2. Tất nhiên, loại bỏ sự trùng lặp là lựa chọn lý tưởng nếu chỉ có thể. Nó có thể mất rất nhiều thời gian (trong một trường hợp gần đây trong dự án cũ của chúng tôi, tôi đã có một số phương thức được nhân đôi qua hơn 20 lớp con trong một hệ thống phân cấp lớp, nhiều trong số đó đã phát triển dần dần sự khác biệt / mở rộng của chúng trong nhiều năm. Tôi khoảng 1,5 năm thông qua việc viết và tái cấu trúc bài kiểm tra đơn vị liên tiếp để thoát khỏi mọi sự trùng lặp. Sự kiên trì là xứng đáng).

    Trong trường hợp như vậy, bạn vẫn có thể cần một hoặc nhiều tùy chọn khác dưới dạng sửa chữa tạm thời, ngay cả khi bạn quyết định bắt đầu tiến tới loại bỏ sự trùng lặp. Tuy nhiên, cái nào tốt hơn phụ thuộc vào rất nhiều yếu tố, và không có nhiều bối cảnh chúng ta chỉ đoán.

    Rất nhiều cải tiến nhỏ có thể tạo ra sự khác biệt lớn trong dài hạn. Bạn không nhất thiết cần sự chấp thuận rõ ràng của khách hàng cho những điều này - một chút tái cấu trúc mỗi khi bạn chạm vào lớp đã nói để sửa lỗi hoặc triển khai một tính năng có thể đi một chặng đường dài theo thời gian. Chỉ cần thêm một số thời gian để tái cấu trúc trong các ước tính nhiệm vụ của bạn. Nó giống như bảo trì tiêu chuẩn để giữ cho phần mềm khỏe mạnh trong thời gian dài.


3
+1, nếu không chỉ để đề cập đến mã trùng lặp, mà còn cho nỗ lực tuyệt đối liên quan đến câu chuyện tái cấu trúc mã của bạn. : D
Andreas Johansson

9

Có một tham chiếu đến mẫu WET (Chúng tôi thích gõ) nhưng tôi không biết đó có phải là tên tiêu chuẩn không.

... Cấp phép phần mềm là một ngoại lệ đáng chú ý đối với thực tiễn DRY (Đừng lặp lại chính mình) - mã cấp phép phần mềm phải là WET (Chúng tôi thích Nhập - ngược lại với DRY) càng tốt.

Nếu bạn tách biệt logic cấp phép của mình ở một nơi, tách biệt với các mối quan tâm khác, bạn sẽ dễ dàng sửa đổi phần mềm của mình để vô hiệu hóa việc cấp phép hoàn toàn. Sẽ tốt hơn nhiều khi lặp lại logic cấp phép nhiều lần trong toàn bộ ứng dụng, tốt nhất là nó được thực thi nhiều lần trong suốt một lần thực thi phần mềm.

Ví dụ: chúng tôi khuyên bạn nên thực hiện kiểm tra cấp phép trong khi cài đặt, trong khi khởi động ứng dụng và bất cứ khi nào các tính năng quan trọng được truy cập. Đừng kiểm tra giấy phép một lần trong khi khởi động & vượt qua giá trị đó; thay vào đó, thực sự sao chép kiểm tra cấp phép trong từng khu vực. Điều đó thật bất tiện, nhưng tốt hơn nhiều so với việc phát hành một sản phẩm dễ bị bẻ khóa ...


3
WET có thể có nghĩa là: Viết mọi thứ hai lần
StuperUser

1
@StuperUser Tôi phát hiện ra rằng trên Dailywtf ngày hôm qua ...
jeremy-george

3

Nếu tôi hiểu bạn đúng, có quá nhiều thứ đang diễn ra trong lớp. Điều đó tạo ra các phương pháp không tuân theo nguyên tắc trách nhiệm duy nhất . Dẫn đến mã cần được di chuyển xung quanh, các mảnh được lấy trong khi những người khác rời đi. Điều này cũng có thể tạo ra rất nhiều thành viên.

Bạn cũng nên xem lại các sửa đổi khả năng truy cập. Đảm bảo những điều đó là công khai, trên thực tế nên được công khai. Người tiêu dùng không cần biết về mọi thành viên nhỏ ... sử dụng đóng gói.

Điều này gọi cho một refactor. Nó cũng xuất hiện rằng mã đang được viết mà không có thiết kế trả trước. Nhìn vào sự phát triển của Driven. Viết mã như thế nào nên được gọi thay vì gọi mã tuy nhiên nó được thực thi. Nhìn vào TDD để biết một số gợi ý về cách hoàn thành nhiệm vụ.


3

Nếu bạn đang sao chép mã, bạn sẽ đưa ra một khoản nợ kỹ thuật về bảo trì kép hoặc cụ thể hơn là: sao chép mã .

Thông thường điều này được cố định thông qua tái cấu trúc. Cụ thể hơn, bạn chuyển hướng tất cả các cuộc gọi đến một chức năng mới (hoặc một phương thức mới trong một lớp mới) có mã chung. Cách dễ nhất để bắt đầu là xóa tất cả các mã đã sao chép và xem những gì bị hỏng, trong đó bạn khắc phục bằng cách chuyển hướng các cuộc gọi đến mã chung.

Để khách hàng của bạn đồng ý mã tái cấu trúc có thể khó khăn vì khó thuyết phục một người không có kỹ thuật để sửa một khoản nợ kỹ thuật. Vì vậy, lần tới khi bạn đưa ra ước tính thời gian, chỉ cần bao gồm thời gian cần thiết để cấu trúc lại ước tính của bạn . Hầu hết thời gian khách hàng cho rằng bạn đang dọn sạch mã trong suốt thời gian bạn thực hiện sửa lỗi.


1

Âm thanh như mã spaghetti với tôi. Cách khắc phục tốt nhất là refactor / viết lại.

một thuật ngữ sai lầm cho mã nguồn có cấu trúc điều khiển phức tạp và rối, đặc biệt là một thuật ngữ sử dụng nhiều GOTO, ngoại lệ, luồng hoặc các cấu trúc phân nhánh "không cấu trúc" khác. Nó được đặt tên như vậy bởi vì dòng chương trình về mặt khái niệm giống như một bát mì spaghetti, tức là xoắn và rối ...

http://upload.wik hè.org/wikipedia/commons/thumb/9/93/Spaghetti.jpg/175px-Spaghetti.jpg


-1 Refactor và viết lại là hai tùy chọn rất khác nhau. Tổng số viết lại, ném phần mềm đi, không bao giờ là một ý tưởng tốt. joelonsoftware.com/articles/fog0000000069.html
P.Brian.Mackey

1
Mã Spaghetti là IMO một thuật ngữ tổng quát hơn - và lỏng lẻo hơn -. Mặc dù mã như vậy thường chứa các bản sao đôi, bạn có thể có mã spaghetti mà không bị trùng lặp, và cũng bị trùng lặp cao nhưng không phải mã spaghetti.
Péter Török

@ P.Brian.Mackey Tôi chưa bao giờ nói rằng Refactor và viết lại là cùng một thứ. OP nên quyết định sử dụng.
Tom Squires

2
Tôi chưa bao giờ là một fan hâm mộ của bài viết đó. Tôi đồng ý rằng viết lại là một ý tưởng tồi trong ví dụ được trích dẫn, nhưng chỉ vì đó là một ý tưởng tồi trong trường hợp đó không có nghĩa đó luôn là một ý tưởng tồi. Đối với người mới bắt đầu, việc thực hiện viết lại khối có tiến triển nào khác không? Nếu vậy, điều đó thật tệ; nếu không, thì điều đó gần như không tệ.
jhocking

@jhocking - Tôi tin rằng quan điểm của chính sách không viết lại không phải là ngăn chặn tiến trình trong các chương trình khác, thay vào đó là mất các bản sửa lỗi thực sự theo thời gian. Điều kỳ diệu "nếu (goldNugget> 22)" trong khi được đặt tên kém, vẫn giải quyết được một vấn đề cụ thể có thể không thể xác định được nếu không có nhiều giờ hoặc nhiều ngày nghiên cứu. Bây giờ, lấy cùng một dữ liệu và cải thiện nó là điều nên làm thay thế. Đó là một cấu trúc lại. Ném nó ra và nói rằng "chúng ta sẽ làm điều đó vào lần tới" là một sự lãng phí thời gian. Lý do tương tự giải quyết vấn đề đã được giải quyết là một sự lãng phí thời gian. Thêm mã tốt vào đầu nợ xấu tăng
P.Brian.Mackey

0

Bạn nói rằng bạn không thể đổ lỗi hoàn toàn cho A - nhưng sao chép một lớp theo cách này thực sự không thể tha thứ được. Đó là một thất bại lớn trong quá trình xem xét mã của bạn. Đó có thể là thất bại lớn nhất, không có đánh giá mã nào cả.

NẾU bạn từng nghĩ rằng bạn phải sản xuất mã khủng khiếp để đáp ứng thời hạn, thì yêu cầu ưu tiên cao nhất tuyệt đối cho việc phát hành sau đó sẽ là sửa mã khủng khiếp NGAY BÂY GIỜ. Vì vậy, vấn đề của bạn đã biến mất.

Nguyên tắc DRY dành cho các tình huống không hoàn hảo và có thể được cải thiện. Sao chép một lớp là một tầm cỡ hoàn toàn mới. Trước tiên tôi gọi nó là mã trùng lặp, và theo thời gian, nó sẽ thay đổi thành mã kém nhất mọi thời đại, mã trùng lặp khác biệt của Hồi: nhiều bản sao của cùng một mã gần như nhưng không hoàn toàn giống nhau và không ai biết nếu sự khác biệt là dự định, trùng hợp hoặc lỗi.


-3

Gần một thập kỷ muộn cho bữa tiệc này, nhưng tên của kiểu chống đối này là Thay đổi phân kỳ , trong đó nhiều lớp bao gồm các bản sao của cùng một hành vi nhưng khi thời gian và tiến trình bảo trì và một số lớp bị lãng quên, những hành vi đó bị phân kỳ.

Tùy thuộc vào hành vi được chia sẻ là gì và cách thức chia sẻ của nó, thay vào đó, nó có thể được gọi là Phẫu thuật Shotgun , sự khác biệt ở đây là một tính năng logic duy nhất được cung cấp bởi nhiều lớp thay vì một lớp.


1
Điều này không giống như điều tương tự. Thay đổi phân kỳ là khi nhiều thay đổi được thực hiện cho cùng một lớp. OP mô tả sao chép mã. Phẫu thuật Shotgun cũng không giống như vậy. Phẫu thuật Shotgun mô tả cùng một thay đổi được thực hiện cho một số lớp khác nhau.
Robert Harvey
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.