Có trường hợp đặc biệt mà chúng tôi có thể chấp nhận mã trùng lặp?


57

Tôi đang làm việc trên một dự án phần mềm nơi chúng tôi phải xây dựng ba API. Một cho kênh ngân hàng gia đình , một cho kênh đại lý và một cho kênh di động .

API cơ quan là một API đầy đủ nhất vì nó có tất cả các chức năng .. sau đó là API Home nhỏ hơn một chút và API di động.

Các kiến ​​trúc sư ở đây đã tạo một lớp chung (các dịch vụ EJB kênh chéo được chia sẻ bởi tất cả các API). Nhưng sau đó các API thì khác.

Hiện tại không có sự khác biệt lớn giữa các API. Đội ngũ lớn bắt đầu với kênh đại lý và chúng tôi hiện đang điều chỉnh nó cho kênh chủ. Chúng tôi chỉ làm phong phú các đối tượng cụ thể cho ứng dụng nhà của chúng tôi. Mặt khác, mã giống nhau 95% giữa các API. Các API được xây dựng dựa trên Spring MVC và nó có (bộ điều khiển, mô hình và một số tiện ích).

Về cơ bản, các bộ điều khiển đang thực hiện ánh xạ BO sang ChannelObject (có vẻ như tôi không phải là nơi thích hợp để làm điều đó) và một số tiện ích bổ sung và tuần tự hóa. Tất cả là bản sao cho bây giờ. Họ đang nói rằng lý do trùng lặp là họ muốn các API độc lập. "Nếu ngày mai chúng tôi muốn có một hành vi khác cho gia đình hơn là đại lý hoặc điện thoại di động, chúng tôi sẽ không đấu tranh !!"

Có trường hợp nào chúng ta nên chấp nhận mã trùng lặp?


22
Và nếu ba ngày mai họ quyết định họ muốn truy cập và đại diện dữ liệu nhất quán giữa tất cả các API ... thì ... "Đấu tranh!"
Becuzz

26
Mã trùng lặp không nhất thiết là một điều xấu. Câu nói "DRY là kẻ thù của việc tách rời" không thể được nhấn mạnh đủ. Ông nói rằng, thiết kế cho tương lai, thay vì bây giờ, thực sự thực sự là một điều rất tồi tệ. Tương lai đó gần như không bao giờ đi qua. Thay vào đó, hãy thiết kế một giải pháp tách rời cao, được bao phủ bởi các thử nghiệm tự động tốt cho những gì cần thiết bây giờ. Sau đó, trong tương lai, nếu cần một cái gì đó khác biệt, nó sẽ dễ dàng thay đổi hơn.
David Arno

2
Tôi nghĩ rằng hai trường hợp mà tôi chưa bao giờ hối tiếc về việc sao chép mã là (a) trong đó mã trùng lặp là một phần rất nhỏ và không quan trọng trong tổng số, và (b) khi tôi sao chép mã từ một hệ thống đã chết vào một hệ thống mới được thiết kế để kéo dài tuổi thọ. Có nhiều trường hợp khác tôi đã khóc những giọt nước mắt cay đắng sau khi rút mã.
Michael Kay

14
Nơi tôi đã làm việc, người ta thường lưu ý rằng một người nên (thường) lặp lại một lần và trừu tượng hóa lần thứ ba. Điều này loại bỏ zeitgeist sớm, có thể không phù hợp, trừu tượng làm tăng khớp nối thay vì gắn kết. Khi các yêu cầu trong tương lai thực sự được hiểu rõ, tất nhiên các ngoại lệ có thể được thực hiện.
Pieter Geerkens

3
Một trường hợp tầm thường mà mã trùng lặp có thể được chấp nhận là nếu nó được tạo tự động
samgak

Câu trả lời:


70

Sao chép có thể là điều đúng đắn, nhưng không phải vì lý do này.

Nói rằng "chúng tôi có thể muốn ba vị trí này trong cơ sở mã hoạt động khác nhau mặc dù ngay bây giờ, chúng giống hệt nhau" không phải là lý do chính đáng để sao chép quy mô lớn. Khái niệm này có thể áp dụng cho mọi hệ thống, và nó có thể được sử dụng để biện minh cho bất kỳ sự trùng lặp nào , điều này rõ ràng là không hợp lý.

Sao chép nên được dung thứ chỉ khi loại bỏ nó sẽ là tổng thể tốn kém hơn hiện nay đối với một số lý do nào khác (không thể nghĩ ra một trong những tốt ngay bây giờ, nhưng được bảo đảm có thể là một - hầu như tất cả mọi thứ trong chương trình là một sự đánh đổi chứ không phải là một pháp luật).

Đối với những gì bạn đang làm, giải pháp phù hợp có thể là ví dụ trích xuất hành vi được sao chép ngay bây giờ vào Chiến lược hoặc một số mẫu khác mô hình hóa hành vi như các lớp và sau đó sử dụng ba trường hợp của cùng một lớp. Bằng cách đó, khi bạn làm muốn thay đổi hành vi trong một trong ba nơi, bạn chỉ cần tạo ra một chiến lược mới và nhanh chóng mà ở một nơi. Bằng cách đó, bạn chỉ phải thêm một số lớp và để phần còn lại của cơ sở mã gần như hoàn toàn không bị ảnh hưởng.


1
Nếu hai điều xảy ra để hành xử giống nhau, đó là sự trùng lặp. Mặc dù trừ khi họ hành xử giống nhau vì một lý do, họ không nên được hợp nhất. Có thể trích xuất một số phần phổ biến của việc thực hiện? Đôi khi có những khối xây dựng chưa được trừu tượng hóa, ai biết được.
Ded repeatator

32
Ví dụ, chúng tôi có một đoạn mã được sử dụng bởi ba phần trong ứng dụng của chúng tôi và nó được viết khá khủng khiếp với rất nhiều nhánh có điều kiện nhỏ ở khắp mọi nơi để bao gồm các ngoại lệ cho cả ba phần đó. Nhưng , và đây là bit quan trọng, nó đã được sử dụng rất nhiều trong hai năm mà không có bất kỳ báo cáo lỗi đáng kể nào. Vì vậy, khi một phần thứ tư của ứng dụng cần phải làm một cái gì đó với nó, nhưng hơi khác một chút, quyết định được đưa ra là không chạm vào mã hoàn hảo chạy hoàn hảo, và chỉ sao chép nó và tạo ra một cơ sở linh hoạt, được viết tốt hơn cho tương lai.
KRyan

2
Sao chép là điều nên làm khi chi phí dễ đọc tăng quá nhiều so với chi phí bảo trì cuối cùng được gắn với nhau. Tôi không nghĩ rằng điều này áp dụng hoàn toàn trong kịch bản này và thường được thấy ở quy mô nhỏ hơn trong một dự án, không phải như thế này. Thậm chí sau đó, rất hiếm khi bạn gặp phải tình huống như vậy, nó sẽ xảy ra nếu bạn có một số trùng lặp lồng nhau, điều này sẽ buộc bạn phải sử dụng mẫu Phương thức mẫu hoặc tương tự nhưng ở những nơi nhỏ. Điều này thường sẽ kết thúc mã obfuscating.
opa

Một ví dụ trong đó việc sao chép là hữu ích (và "loại bỏ nó bạn sẽ tốn kém hơn bây giờ ") là định giá đầu vào trong các ứng dụng web: Chúng tôi sử dụng xác nhận đầu tiên (có thể đơn giản hóa) tại máy khách để người dùng nhận được phản hồi ngay lập tức về các vấn đề; và sau đó chúng tôi thực hiện xác nhận tương tự (hoặc kỹ lưỡng hơn) tại máy chủ vì khách hàng không thể tin cậy được.
Hagen von Eitzen

3
@HagenvonEitzen Nhưng điều đó thậm chí không cần phải sao chép, tùy thuộc vào ngăn xếp công nghệ. Ví dụ: bạn có thể có đầu vào kiểm tra JavaScript trong trình duyệt và sau đó kiểm tra Java trên máy chủ, do đó bạn có chức năng trùng lặp. Nhưng nếu bạn đã chạy Node.js trên máy chủ, bạn có thể sử dụng cùng một xác thực JavaScript trong trình duyệt và trên máy chủ, loại bỏ sự trùng lặp. Bạn vẫn muốn mã chạy ở nhiều nơi (môi trường đáng tin cậy và không tin cậy), nhưng không nhất thiết phải được sao chép.
Joshua Taylor

87

Sandi Metz, một kỹ sư phần mềm nổi tiếng và là tác giả của hệ sinh thái Ruby, có một bài đăng blog tuyệt vời và một bài nói chuyện , nơi cô cũng nói về mối quan hệ giữa trùng lặp và trừu tượng. Cô đi đến kết luận sau

trùng lặp rẻ hơn nhiều so với trừu tượng sai

Và tôi hoàn toàn đồng ý với cô ấy. Hãy để tôi cung cấp cho bạn nhiều bối cảnh hơn để trích dẫn này. Đôi khi tìm được sự trừu tượng đúng là rất khó. Trong những trường hợp như vậy, thật hấp dẫn khi chỉ cần thực hiện bất kỳ sự trừu tượng hóa nào để giảm sự trùng lặp. Nhưng sau này bạn có thể phát hiện ra rằng sự trừu tượng của bạn không giữ cho tất cả các trường hợp. Tuy nhiên, thật tốn kém khi thay đổi mọi thứ một lần nữa và đi một con đường khác (để giải thích rõ hơn nhiều hãy xem cô ấy nói chuyện!).

Vì vậy, có, đối với tôi, có những trường hợp đặc biệt, trong đó chấp nhận trùng lặp là quyết định đúng đắn, đặc biệt là khi bạn không chắc chắn điều gì sẽ đến và yêu cầu có thể thay đổi. Từ bài đăng của bạn, tôi cho rằng hiện tại có nhiều sự trùng lặp, nhưng các đồng nghiệp của bạn cho rằng điều này có thể thay đổi và không kết hợp cả hai ứng dụng với nhau. Theo tôi đây là một lập luận hợp lệ và nói chung không thể coi thường.


23
À đúng, nếu bạn không thể suy ra các quy tắc chung chung, cố gắng trừu tượng hóa chúng chỉ có thể thất bại. Và nếu sự tương ứng là ngẫu nhiên, nó có thể là ngắn ngủi.
Ded repeatator

5
Có thể sẽ rất tốn kém khi thay đổi một sự trừu tượng một khi nó diễn ra, nhưng việc loại bỏ sự trùng lặp một khi nó diễn ra có thể còn rắc rối hơn nữa. Tất nhiên điều này phụ thuộc rất nhiều vào ngôn ngữ, v.v. - các hệ thống loại tĩnh mạnh hiện đại có thể làm tốt công việc giúp bạn có được những thay đổi quy mô lớn đối với một số trừu tượng ngay. Tuy nhiên, việc giữ các tính năng trùng lặp không phải là thứ mà hệ thống loại có thể giúp bạn nhiều (vì các bản sao này, đối với hệ thống loại , chỉ khác nhau). Nhưng tôi cho rằng trong các ngôn ngữ gõ vịt năng động, nó đúng hơn là cách khác; vì vậy nó có thể có ý nghĩa đối với Ruby.
leftaroundabout

34

Nếu mọi người bắt đầu suy luận về thiết kế với từ "nếu ngày mai" , thì đây thường là một dấu hiệu cảnh báo lớn đối với tôi, đặc biệt là khi tranh luận được sử dụng để biện minh cho một quyết định bao gồm công việc và nỗ lực thêm, mà không ai thực sự biết liệu điều này sẽ bao giờ trả hết, và khó thay đổi hoặc hoàn nguyên hơn quyết định ngược lại.

Sao chép mã làm giảm nỗ lực chỉ trong một thời gian ngắn, nhưng nó sẽ tăng các nỗ lực bảo trì gần như ngay lập tức, tỷ lệ thuận với số lượng dòng mã trùng lặp. Cũng lưu ý rằng một khi mã được sao chép, sẽ rất khó để loại bỏ trùng lặp khi hóa ra đây là quyết định sai, trong khi nếu bây giờ không sao chép mã, thì vẫn dễ dàng đưa ra sao chép sau nếu nó bị dính vào DRY là quyết định sai lầm.

Nói rằng, trong các tổ chức lớn hơn, đôi khi có lợi cho sự độc lập của các đội khác nhau theo nguyên tắc DRY. Nếu loại bỏ trùng lặp bằng cách trích xuất 95% các phần phổ biến của API, hai thành phần mới dẫn đến sự kết hợp của hai nhóm độc lập khác, đây có thể không phải là quyết định khôn ngoan nhất. Mặt khác, nếu bạn có nguồn lực hạn chế và sẽ chỉ có một nhóm duy trì cả hai API, tôi chắc chắn rằng họ sẽ không quan tâm đến việc tạo ra bất kỳ nỗ lực kép nào và tránh mọi sự trùng lặp mã không cần thiết.

Lưu ý thêm, điều này sẽ tạo ra sự khác biệt nếu API "Home" và "Agency" được sử dụng hoàn toàn bởi các ứng dụng hoàn toàn khác nhau hoặc nếu ai đó có thể cố gắng viết một bản dựng thành phần trên các API đó có thể được sử dụng trong ngữ cảnh "Home" như trong một bối cảnh "Cơ quan". Trong tình huống này, việc có các phần chung của API giống hệt nhau (mà bạn chỉ có thể đảm bảo nếu các phần chung không bị trùng lặp), sẽ giúp việc phát triển một thành phần như vậy có thể dễ dàng hơn nhiều.

Vì vậy, nếu hóa ra sẽ có các nhóm phụ thực sự khác nhau, mỗi nhóm chịu trách nhiệm cho từng API, mỗi nhóm có lịch biểu và tài nguyên khác nhau, thì đã đến lúc sao chép mã, nhưng không phải "chỉ trong trường hợp".


3
Thậm chí dấu hiệu cảnh báo lớn hơn "nếu ngày mai" đối với tôi là "Điều đó sẽ không bao giờ thay đổi".
abuzittin gillifirca

@abuzmitillifirca: và điều này có liên quan gì đến câu hỏi hoặc câu trả lời của tôi?
Doc Brown

1
Tôi đang thách thức đoạn đầu tiên của bạn.
abuzittin gillifirca

2
@abuzmitillifirca: tốt, hãy đọc lại câu hỏi: đó là về lý luận với lập luận "nếu ngày mai" để đưa ra quyết định sao chép khó thực hiện , do đó làm cho phần mềm thực sự khó thay đổi hơn đối với một số trường hợp nhất định. Nó có thể hơi phản trực giác, nhưng cách tốt nhất để giữ phần mềm thay đổi cho tương lai không phải là đưa ra bất kỳ giả định (có thể sai) nào về tương lai, mà là giữ cho phần mềm càng nhỏ và RẮN càng tốt.
Doc Brown

13

Nhân đôi để ngăn chặn khớp nối . Giả sử bạn có hai hệ thống lớn và bạn buộc chúng sử dụng cùng một thư viện. Bạn có thể ghép nối chu kỳ phát hành của cả hai hệ thống. Điều này có thể không quá tệ nhưng hãy nói rằng một hệ thống cần phải đưa ra một sự thay đổi. Các nhu cầu khác để phân tích sự thay đổi và có thể bị ảnh hưởng. Đôi khi nó có thể phá vỡ mọi thứ. Ngay cả khi cả hai bên có thể điều phối các thay đổi, đó có thể là rất nhiều cuộc họp, thông qua các nhà quản lý, thử nghiệm, phụ thuộc và kết thúc của nhóm tự trị nhỏ.

Vì vậy, bạn đang trả giá của mã trùng lặp để có được sự tự chủ và độc lập.


Vì vậy, đây là sao chép liên thành phần để tránh khớp nối. Nhưng bạn vẫn muốn tránh trùng lặp nội bộ, phải không?
TemplateRex

Vâng, vâng, bạn muốn giảm thiểu mã trùng lặp vì nó sẽ giúp mã của bạn dễ hiểu và sửa đổi hơn. Nhưng hãy nhớ rằng có những câu trả lời tốt với các ngoại lệ khả thi. Sự trừu tượng đúng để tránh trùng lặp có thể khó tìm.
Borjab
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.