중복 코드를 수락 할 수있는 예외적 인 경우가 있습니까?


57

우리는 세 가지 API를 빌드해야하는 소프트웨어 프로젝트를 진행하고 있습니다. 하나는 뱅킹 채널, 하나는 대행사 채널 , 다른 하나 는 모바일 채널입니다.

대행사 API는 모든 기능을 갖추고있어 가장 완벽한 API입니다. 그 다음에는 약간 작은 Home API와 모바일 API가 있습니다.

여기서 설계자는 공통 계층 (모든 API가 공유하는 교차 채널 EJB 서비스)을 만들었습니다. 그러나 API는 다릅니다.

API 간에는 큰 차이가 없습니다. 대기업 팀은 대행사 채널을 시작으로 홈 채널에 맞게 조정하고 있습니다. 우리는 홈 앱에 특별히 객체를 보강하고 있습니다. 그렇지 않으면 코드는 API간에 95 % 유사합니다. API는 Spring MVC를 기반으로 구축되었으며 컨트롤러, 모델 및 일부 유틸리티가 있습니다.

기본적으로 컨트롤러는 BO를 ChannelObject에 매핑하고 (적절한 장소가 아닌 것 같습니다) 일부 추가 유틸리티와 직렬 변환기를 수행합니다. 지금은 모두 중복되었습니다. 그들은 중복의 이유는 API를 독립적으로 원하기 때문이라고 말합니다. "내일 우리가 대행사 나 모바일과 다른 행동을 원한다면 우리는 어려움을 겪지 않을 것입니다."

중복 코드를 수락해야하는 경우가 있습니까?


22
그리고 내일 3 명이 내일이면 모든 API간에 일관된 데이터 액세스 및 표현을 원한다고 결정합니다. ... 음 ... "투쟁!"
Becuzz

26
중복 코드가 반드시 나쁜 것은 아닙니다. "DRY는 디커플링의 적"이라는 말은 충분히 강조 할 수 없습니다. 현재보다는 미래를위한 디자인은 실제로 매우 나쁜 것입니다. 그 미래는 거의 지나치지 않습니다. 대신, 현재 필요한 것에 대한 우수한 자동화 테스트를 통해 고도로 분리 된 솔루션을 설계하십시오. 그런 다음 나중에 다른 무언가가 필요한 경우 변경하기가 더 쉬울 것입니다.
David Arno

2
중복 된 코드를 후회하지 않은 두 가지 경우는 (a) 복제 된 코드가 총계에서 매우 작고 중요하지 않은 부분이며 (b) 이미 죽어 가고있는 시스템에서 코드를 복사하는 경우입니다. 수명을 위해 설계된 새로운 시스템으로 코드를 포크 한 후 쓴 눈물을 흘린 다른 많은 경우가 있습니다.
Michael Kay

14
내가 일한 곳에서 종종 (한 번) 한 번 복제하고 세 번째 공통점을 추상화해야한다는 사실이 종종 나타났습니다. 이것은 응집력 대신 결합을 증가시키는 부적절한 초기 추상화를 위해 zeitgeist 를 제거합니다 . 미래의 요구 사항이 실제로 잘 이해되면 예외가 발생할 수 있습니다.
Pieter Geerkens

3
중복 코드를 수용 할 수있는 한 가지 사소한 사례는 자동 생성되는 경우입니다.
samgak

답변:


70

복제 올바른 일이 될 수 있지만 이러한 이유로는 수 없습니다.

"현재 코드베이스에서이 세 곳이 다르게 동작하기를 원할 수도 있습니다"라고 말하는 것은 대규모 복제의 좋은 이유가 아닙니다. 이 개념은 모든 시스템에 적용될 수 있으며 중복 을 정당화 하는 데 사용될 수 있습니다 .

복제는 전체 비용이 많이 드는 것 제거하는 경우에만 허용되어야한다 지금 (지금 좋은 생각 할 수는 없지만 하나가 될 수 있습니다 확신 할 다른 이유로 - 프로그래밍의 거의 모든 (A)보다 트레이드 오프 오히려입니다 법).

당신이하고있는 일에 대한 올바른 해결책은 예를 들어 지금 전략에 복제 된 행동이나 클래스로 행동을 모델링 한 다음 같은 클래스의 세 인스턴스 를 사용하는 다른 패턴으로 추출하는 것일 수 있습니다 . 당신이 때 그런 식으로, 세 가지 장소 중 하나의 동작을 변경하려면, 당신은 단지 새로운 전략을 만들고 한 곳에서 그 인스턴스를해야합니다. 이렇게하면 클래스를 추가하고 나머지 코드베이스를 거의 그대로 유지하면됩니다.


1
두 가지가 동일하게 작동하면 중복입니다. 같은 이유로 동작하지 않으면 병합되지 않아야합니다. 구현의 공통 부분을 추출 할 수 있습니까? 때로는 아직 추상화되지 않은 빌딩 블록이 있습니다.
중복 제거기

32
예를 들어, 우리는 응용 프로그램의 세 부분에서 사용하는 코드 덩어리를 가지고 있었고, 세 가지 각각에 대한 예외를 다루기 위해 거의 모든 조건부 분기로 엄청나게 작성되었습니다. 그러나 이것은 중요한 부분이었습니다. 어떤 종류의 중대한 버그보고도없이 2 년 동안 많이 사용되었습니다. 따라서 응용 프로그램의 네 번째 부분에서 무언가를 수행해야하지만 약간 다른 경우 에는 결함이없는 코드를 건드리지 않고 코드를 복사하여 더 잘 작성되고 유연한 기반을 만들기로 결정했습니다. 미래.
KRyan

2
중복은 함께 묶인 유지 관리 비용과 비교할 때 가독성 비용이 너무 많이 올라갈 때 올바른 일입니다. 나는이 시나리오에서 이것이 전혀 적용되지 않는다고 생각하며 종종 프로젝트와 같이 작은 규모로 보이지 않습니다. 그렇다하더라도 이러한 상황이 발생하는 경우는 매우 드물지만 템플릿 방법 패턴 등을 작은 장소에서 사용해야하는 틈새 중첩 복제가있는 경우 발생합니다. 이것은 일반적으로 난독 화 코드로 끝납니다.
opa

복제가 유용한 (및 " 현재 전체를 더 비용이 많이 드는 것을 제거하는 것 ") 예는 웹 응용 프로그램의 입력 유효성 검사입니다. 우리는 클라이언트에서 첫 번째 (아마도 단순화 된) 유효성 검사를 사용하여 사용자가 문제에 대한 즉각적인 피드백을받을 수 있도록합니다. 그런 다음 클라이언트를 신뢰할 수 없으므로 서버에서 동일한 (또는보다 철저한) 유효성 검사를 수행합니다.
Hagen von Eitzen

3
@HagenvonEitzen 그러나 기술 스택에 따라 중복 될 필요는 없습니다. 예를 들어, 브라우저에 JavaScript 검사 입력이 있고 서버에 Java 검사가있을 수 있으므로 기능이 중복됩니다. 그러나 서버에서 Node.js를 실행하는 경우 브라우저와 서버에서 동일한 JavaScript 유효성 검사를 사용하여 중복을 제거 할 수 있습니다. 코드가 여러 곳 (신뢰할 수 있고 신뢰할 수없는 환경)에서 계속 실행 되기를 원 하지만 반드시 코드 를 복제 할 필요는 없습니다.
Joshua Taylor

87

Ruby 생태계의 유명한 소프트웨어 엔지니어이자 저자 인 Sandi Metz는 훌륭한 블로그 게시물 과 복제와 추상화의 관계에 대해 이야기 합니다. 그녀는 다음 결론에 온다

중복은 잘못된 추상화보다 훨씬 저렴합니다.

그리고 나는 그녀에게 완전히 동의합니다. 이 인용문에 더 많은 문맥을 알려 드리겠습니다. 때로는 올바른 추상화를 찾는 것이 매우 어렵습니다. 그러한 경우 중복을 줄이기 위해 추상화가 필요 합니다 . 그러나 나중에 추상화가 모든 경우에 해당되는 것은 아닙니다. 그러나 모든 것을 다시 바꾸고 다른 길을가는 것은 비용이 많이 듭니다 (더 나은 설명을 위해서는 그녀의 이야기를보십시오!).

예, 저에게있어, 복제를 받아들이는 것이 올바른 결정 인 예외적 인 경우가 있습니다. 특히 앞으로 올 일이 확실하지 않고 요구 사항이 변경 될 수 있습니다. 귀하의 게시물에서 나는 지금 많은 중복이 있다고 생각하지만, 동료들은 이것이 변경되어 두 응용 프로그램이 서로 연결되지 않을 것을 제안합니다. 제 생각에는 이것은 유효한 주장이며 일반적으로 무시할 수 없습니다.


23
예, 일반화 된 규칙을 추론 할 수 없다면 추상적 인 규칙을 시도하면 실패 할 수 있습니다. 그리고 일치하는 것이 우연 일 경우 수명이 짧을 수 있습니다.
중복 제거기

5
추상화가 완료되면 변경하는 데 많은 비용이 소요될 수 있지만 일단 복제 를 제거 하면 더 많은 문제가 발생할 수 있습니다. 물론 이것은 언어 등에 따라 많은 영향을받습니다. – 현대의 강력한 정적 유형 시스템은 추상화에 대한 대규모 변경을 수행하는 데 도움이됩니다. 동기화 중복 기능을 유지하는 것은 그러나 형식 시스템이 많은 (중복이기 때문에, 당신을 도울 수있는 것이 아닙니다 유형 시스템에 , 단지 다른). 그러나 나는 동적 인 오리 형 언어에서 오히려 다른 방법이라고 생각합니다. 루비에게는 이치에 맞습니다.
leftaroundabout

34

사람들 이 "내일이라면" 이라는 단어로 디자인에 대해 추론하기 시작 하면 , 이것은 특히 나에게 큰 경고 신호입니다. 반대의 결정보다 변경 또는 되돌리기가 더 어려운 지불.

코드를 복제하면 단기간 동안의 노력이 줄어들지 만 코드의 중복 된 행 수에 비례하여 거의 즉시 유지 관리 노력이 증가합니다. 코드가 복제되면 잘못된 결정이라고 판명되면 중복을 제거하기가 어려워지며, 코드를 복제하지 않는 경우에도 DRY를 고수하면 나중에 중복을 도입하기가 쉽습니다. 잘못된 결정이었습니다.

더 큰 조직에서는 DRY 원칙보다 다른 팀의 독립성을 선호하는 것이 때때로 유리합니다. API의 95 % 공통 부분을 추출하여 중복을 제거하면 새로운 구성 요소 두 개가 독립적 인 두 팀을 연결하게되므로 이것이 현명한 결정이 아닐 수 있습니다. 반면에 리소스가 제한되어 있고 두 API를 유지 관리하는 팀이 하나 뿐인 경우 이중 노력을 기울이지 않고 불필요한 코드 중복을 피하는 것이 그들 자신의 이익이 될 것이라고 확신합니다.

"Home"및 "Agency"API가 완전히 다른 응용 프로그램에서만 독점적으로 사용되거나 "Home"컨텍스트에서도 사용할 수있는 API를 기반으로 구성 요소 빌드를 작성하려는 경우 차이가 있습니다. "Agency"컨텍스트에서와 같이 이 상황에서 API의 공통 부분이 정확히 동일하면 (공통 부분이 복제되지 않은 경우에만 보장 할 수 있음) 이러한 구성 요소의 개발이 훨씬 쉬워집니다.

따라서 서로 다른 하위 팀이 있고 각 팀마다 각기 다른 일정과 리소스를 가진 각 API를 담당하는 경우, 코드를 복제 할 때가되었지만 "사례"가 아닙니다.


3
나를 위해 "내일이면"보다 더 큰 경고 표시는 "그건 절대 변하지 않을 것"입니다.
abuzittin gillifirca

@abuzittingillifirca : 질문이나 내 대답과 관련이 있습니까?
Doc Brown

1
첫 단락에 도전하고 있습니다.
abuzittin gillifirca

2
@abuzittingillifirca : 글쎄요, 다시 질문을 읽으십시오 : 그것은 되돌릴 수없는 복제에 대한 결정을 정당화하기위한 "내일이면"이라는 주장으로 추론하는 것 입니다. 약간 반 직관적 일 수도 있지만, 미래를 위해 소프트웨어를 변경 가능하게 유지하는 가장 좋은 방법은 미래에 대해 (아마도 잘못된) 가정을하는 것이 아니라 소프트웨어를 가능한 작고 SOLID로 유지하는 것입니다.
Doc Brown

13

결합을 방지하기위한 복제 . 두 개의 큰 시스템이 있고 동일한 라이브러리를 사용하도록 강제한다고 가정 해 봅시다. 두 시스템의 릴리스주기를 연결했을 수 있습니다. 이것은 나쁘지는 않지만 한 시스템이 변경을 도입해야한다고 가정 해 봅시다. 다른 하나는 변경 사항을 분석해야하며 영향을받을 수 있습니다. 때로는 문제가 발생할 수 있습니다. 두 당사자가 변경 사항을 조정할 수 있더라도 관리자, 테스트, 종속성 및 소규모 자치 팀의 끝을 거치는 많은 회의가 될 수 있습니다.

자율성과 독립성을 얻기 위해 중복 코드의 가격을 지불하고 있습니다.


따라서 이것은 결합을 피하기 위해 구성 요소 간 복제입니다. 그러나 여전히 컴포넌트 내부 복제를 피하고 싶습니까?
TemplateRex

예, 코드를 이해하고 수정하기 쉽도록 중복 된 코드를 최소화하려고합니다. 그러나 가능한 예외를 가진 좋은 답변이 있다는 것을 기억하십시오. 복제를 피하기위한 올바른 추상화는 찾기 어려울 수 있습니다.
Borjab
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.