커플 링을 늘리지 않고 DRY를 적용 할 수 있습니까?


14

함수 F를 구현하는 소프트웨어 모듈 A가 있다고 가정합니다. 다른 모듈 B는 F '와 동일한 기능을 구현합니다.

중복 코드를 제거하는 방법에는 여러 가지가 있습니다.

  1. A가 B의 F '를 사용하게하십시오.
  2. B가 A의 F를 사용하게하십시오.
  3. F를 자체 모듈 C에 넣고 A와 B가 모두 사용하도록하십시오.

이러한 모든 옵션은 모듈간에 추가 종속성을 생성합니다. 커플 링을 증가시키는 비용으로 DRY 원리를 적용합니다.

내가 볼 수있는 한, DRY를 적용 할 때 커플 링은 항상 증가하거나 임대 상태에서 더 높은 수준으로 이동합니다. 소프트웨어 설계의 가장 기본적인 두 가지 원칙간에 충돌이있는 것 같습니다.

(실제로 나는 그런 충돌이 있다는 것이 놀랍지 않습니다. 이것은 아마도 훌륭한 소프트웨어 디자인을 어렵게 만드는 것입니다. 이러한 충돌이 일반적으로 서론에서 다루어지지 않는 것은 놀라운 일입니다.)

편집 (설명을 위해) : 나는 F와 F '의 평등이 단지 우연의 일치가 아니라고 가정합니다. F를 수정해야하는 경우 F '도 같은 방식으로 수정해야합니다.


2
... DRY는 매우 유용한 전략 일 수 있지만이 질문은 DRY의 비 효율성을 보여줍니다. 일부 (예를 들어, OOP 애호가)는 A와 B의 개념적 자율성을 유지하기 위해 F를 B에 복사 / 붙여 넣기해야한다고 주장 할 수도 있지만 필자는 그렇게 할 시나리오에 빠지지 않았습니다. 복사 / 붙여 넣기 코드는 최악의 옵션에 불과하다고 생각합니다. "단기 메모리 손실"이라는 느낌이 들기 때문에 이미 무언가를 수행하는 메서드 / 함수를 작성했다고 확신 할 수는 없습니다. 한 기능에서 버그를 수정하고 다른 기능을 업데이트하지 않는 것이 또 다른 주요 문제 일 수 있습니다.
jrh

3
서로 모순되는이 OO 원칙이 많이 있습니다. 대부분의 경우 합리적인 균형을 찾아야합니다. 그러나 IMHO DRY 원칙이 가장 중요합니다. @ jrh가 쓴 것처럼 : 여러 장소에서 동일한 행동을 구현하는 것은 어떤 희생을 치르더라도 피해야하는 유지 보수의 악몽입니다. 프로덕션 환경에서 중복 사본 중 하나를 업데이트하지 않은 것을 발견하면 비즈니스가 중단 될 수 있습니다.
Timothy Truckle

2
@TimothyTruckle : 우리는 다른 프로그래밍 패러다임에도 적용되기 때문에 OO 원칙이라고 부를 수 없습니다. 그리고 그렇습니다. DRY는 가치가 있지만지나 치면 위험합니다. 의존성과 복잡성을 유발하는 경향이 있기 때문입니다. 또한 서로 다른 이유가있는 우연의 일치로 인한 복제본에도 적용됩니다.
Frank Puffer

1
... 또한 때때로이 시나리오를 시작했을 때 나는 F를 A가 필요로하는 것과 B가 필요로하는 것에 사용할 수있는 부분으로 나눌 수있었습니다.
jrh

1
커플 링은 본질적으로 나쁜 것이 아니며 종종 오류를 줄이고 생산성을 높이기 위해 필요합니다. 함수 내에서 언어의 표준 라이브러리에서 parseInt 함수를 사용했으면 함수를 표준 라이브러리에 연결하게됩니다. 몇 년 동안 이것을하지 않는 프로그램을 보지 못했습니다. 핵심은 불필요한 커플 링을 생성하지 않는 것입니다. 대부분의 경우 인터페이스는 이러한 커플 링을 피하거나 제거하는 데 사용됩니다. 예를 들어, 내 함수는 parseInt 구현을 인수로 사용할 수 있습니다. 그러나 이것이 항상 필요한 것은 아니며 항상 현명하지도 않습니다.
Joshua Jones

답변:


14

이러한 모든 옵션은 모듈간에 추가 종속성을 생성합니다. 커플 링을 증가시키는 비용으로 DRY 원리를 적용합니다.

왜 그래요? 그러나 그들은 선 사이의 결합을 줄입니다. 당신이 얻는 것은 커플 링을 바꾸는 힘입니다. 커플 링은 여러 형태로 제공됩니다. 코드를 추출하면 간접 및 추상화가 증가합니다. 그것이 좋거나 나쁠 수 있습니다. 당신이 얻는 것을 결정하는 가장 중요한 것은 당신이 사용하는 이름입니다. 내면을 볼 때 그 이름을보고 놀라게된다면 당신은 어떤 호의도하지 않은 것입니다.

또한 진공 상태에서 DRY를 따르지 마십시오. 중복을 제거하면 해당 코드의 두 가지 용도가 함께 변경 될 것으로 예측해야합니다. 독립적으로 변경 될 가능성이있는 경우 혼동과 추가 작업이 거의 발생하지 않습니다. 그러나 정말로 좋은 이름은 그것을 더 맛있게 만들 수 있습니다. 당신이 생각할 수있는 모든 것이 나쁜 이름이라면, 제발 그만하십시오.

시스템이 너무 격리되어 있지 않으면 커플 링은 항상 존재하여 아무도 작동하는지 알 수 없습니다. 리팩토링 커플 링은 독을 선택하는 게임입니다. DRY를 따르는 것은 변경이 매우 어려울 때까지 여러 곳에서 동일한 설계 결정을 반복해서 표현함으로써 생성 된 커플 링을 최소화함으로써 보상 할 수 있습니다. 그러나 DRY를 사용하면 코드를 이해하지 못할 수 있습니다. 그 상황을 구하는 가장 좋은 방법은 정말 좋은 이름을 찾는 것입니다. 좋은 이름을 생각할 수 없다면 의미없는 이름피하는 데 능숙 하시길 바랍니다.


추출한 코드에 좋은 이름을 지정하면 추출 된 코드는 더 이상 소프트웨어를 이해하는 데 더 이상 관련이 없습니다. 커플 링은 여전히 ​​기술적 인 수준에 있지만인지적인 수준에는 없습니다. 따라서 상대적으로 무해합니다.
Frank Puffer

1
걱정하지 마라, 내 나쁜 : meta.stackexchange.com/a/263672/143358
Basilevs

@FrankPuffer 더 나은가?
candied_orange

3

명시 적 의존성을 깨는 방법이 있습니다. 가장 인기있는 것은 런타임에 의존성을 주입하는 것입니다. 이 방법으로 DRY를 얻고 정적 안전 비용으로 커플 링을 제거하십시오. 요즘 사람들이 이해하지 못하는 것은 너무나 인기가 있으며, 그것은 절충입니다. 예를 들어, 애플리케이션 컨테이너는 복잡성을 숨겨서 소프트웨어를 복잡하게 만드는 종속성 관리를 일상적으로 제공합니다. 일반 오래된 생성자 삽입조차도 유형 시스템이 없기 때문에 일부 계약을 보장하지 못합니다.

제목에 대답하려면 가능하지만 런타임 디스패치의 결과에 대비하십시오.

  • F 기능을 제공하는 A 에서 인터페이스 F A 정의
  • B 에서 인터페이스 F B 정의
  • F를 C에 넣다
  • 모든 종속성을 관리하기 위해 모듈 D를 만듭니다 (A, B 및 C에 따라 다름)
  • F를 F A 와 F B에 적응D에서 에
  • 래퍼를 A와 B에 주입 (통과)

이런 식으로, 당신이 가질 수있는 유일한 의존성 유형은 서로 다른 모듈에 따라 D입니다.

또는 빌트인 의존성 주입으로 애플리케이션 컨테이너에 C를 등록하고 천천히 증가하는 런타임 클래스 로딩 루프 및 교착 상태를 자동 배선하는 것을 즐기십시오.


1
+1이지만 명백한 경고를 받으면 이는 일반적으로 나쁜 트레이드 오프입니다. 정적 안전은 여러분의 보호를위한 것입니다. 멀리 떨어진 곳에서 으스스한 행동으로 그것을 피하는 것은 단지 프로젝트 복잡성이 조금 커질 때 추적하기 어려운 버그를 요구합니다 ...
Mason Wheeler

1
DI가 정말로 의존성을 깰 수 있습니까? 공식적으로도이를 구현하려면 F의 서명이있는 인터페이스가 필요합니다. 그러나 여전히 모듈 A가 C에서 F를 사용하는 경우에는 C가 런타임에 주입되거나 직접 연결되어 있는지 여부에 관계없이 C에서 F를 사용합니다. DI는 종속성을 중단하지 않으며 종속성이 제공되지 않으면
버그만

@ max630 그것은 구현 의존성을 계약상의 것으로 대체합니다.
Basilevs

@ max630 맞습니다. DI는 의존성을 깨뜨릴 수 없다. 실제로, DI는 의존성 을 도입 하는 방법이며 , 실제로 커플 링과 관련된 질문에 직교합니다. F (또는 그것을 캡슐화하는 인터페이스)의 변화는 여전히 A와 B의 변화를 요구할 것이다.
킹 사이드 슬라이드

1

추가 컨텍스트가없는 대답이 의미가 있는지 확실하지 않습니다.

않습니다 A이미에 따라 B반대 또는 그? —이 경우 우리는 분명한 집을 선택할 수 있습니다F .

수행 AB이미위한 좋은 집이 될 수있는 공통의 종속성을 공유F ?

얼마나 큰 / 복잡한가 F? 다른 것F 의존합니까?

모듈이 AB 같은 프로젝트에 사용?

의지 AB 몇 가지 일반적인 종속 어쨌든 공유 끝?

사용중인 언어 / 모듈 시스템 : 프로그래머의 고통, 성능 오버 헤드에서 새 모듈이 얼마나 고통 스럽습니까? 예를 들어, COM이 모듈 시스템 인 C / C ++로 작성하는 경우 소스 코드에 통증을 유발하고 대체 툴링이 필요하며 디버깅에 영향을 미치고 성능에 영향을 미칩니다 (모듈 간 호출의 경우). 잠시 멈추십시오.

반면에 단일 실행 환경에서 원활하게 결합되는 Java 또는 C # DLL에 대해 이야기하는 것은 또 다른 문제입니다.


함수는 추상화이며 DRY를 지원합니다.

그러나 좋은 추상화는 완전해야합니다. 불완전한 추상화는 기본 구현에 대한 지식을 사용하여 소비 클라이언트 (프로그래머)가 부족을 보완 할 수 있습니다. 이는 추상화가보다 완전한 것으로 제공되는 경우보다 더 긴밀한 결합을 초래합니다.

그래서, 더 나은 추상화를 만드는 모습으로 주장 A하고 B단순히 새로운 모듈에 하나 개의 기능을 이동보다 의존하는 C

새로운 추상화로 놀릴 함수 세트를 찾고 있습니다. 즉, 코드 기반이 더 나올 때까지 기다릴 수 있으므로 하나의 기반이 아닌 더 완전하고 완전한 추상화 리팩토링을 식별 할 수 있습니다 단일 함수 코드에서 tell.


2
추상화와 의존성 그래프를 결합하는 것이 위험하지 않습니까?
Basilevs

Does A already depend on B or vice versa? — in which case we might have an obvious choice of home for F.이것은 A가 항상 B에 의존한다고 가정하고 (또는 그 반대), 이는 매우 위험한 가정입니다. OP가 F를 본질적으로 A (또는 B)의 일부가 아닌 것으로 간주한다는 사실은 F가 라이브러리에 고유하지 않고 존재한다는 것을 암시합니다. F가 하나의 라이브러리 (예 : DbContext 확장 메소드 (F) 및 Entity Framework 래퍼 라이브러리 (A 또는 B))에 속하는 경우 OP의 질문은 문제가됩니다.
Flater

0

이 문제를 "최소화"할 수있는 모든 방법에 중점을 둔 답변은 장애를 일으키는 것입니다. 그리고 단순히 커플 링을 생성하는 다양한 방법을 제공하는“솔루션”이 진정한 솔루션은 아닙니다.

진실은 당신이 만든 바로 그 문제를 이해하지 못한다는 것입니다. 귀하의 예제와 관련된 문제는 DRY와 관련이 없으며 응용 프로그램 디자인과 관련이 있습니다.

모듈 A와 B가 동일한 기능 F에 의존하는 경우 왜 모듈 A와 B가 분리되어 있는지 자문 해보십시오. 물론 디자인이 잘못되면 종속성 관리 / 추상화 / 커플 링 / 사용자 이름에 문제가있을 수 있습니다.

동작에 따라 적절한 응용 프로그램 모델링이 수행됩니다. 따라서 F에 의존하는 A와 B의 조각은 자체의 독립적 인 모듈로 추출해야합니다. 이것이 가능하지 않으면 A와 B를 결합해야합니다. 두 경우 모두 A와 B는 더 이상 시스템에 유용하지 않으며 더 이상 존재하지 않아야합니다.

DRY는 잘못된 디자인을 노출시키는 데 사용될 수있는 원칙입니다. DRY를 달성 할 수없는 경우 (응용 프로그램의 구조로 인해 정말로 적용 -편집 내용을 기록 ) 구조가 책임이되었다는 명백한 징후입니다. 이것이 바로 "연속 리팩토링"이 따르는 주요 이유입니다.

ABC의 다른 설계 원칙 (SOLID, DRY 등)은 모두 응용 프로그램 변경 (리팩토링 포함)을보다 쉽게 수행 하는 데 사용됩니다 . 그것에 집중 하면 다른 모든 문제가 사라지기 시작합니다.


모든 응용 프로그램마다 정확히 하나의 모듈을 사용하도록 제안하십니까?
Basilevs

@Basilevs 절대로 아닙니다 (보증되지 않는 한). 가능한 한 완전히 분리 된 모듈을 많이 사용하는 것이 좋습니다. 결국, 그것은 모듈의 전체 목적입니다.
킹 사이드 슬라이드

문제는 모듈 A와 B가 관련없는 기능을 포함하고 이미 추출 된 이유와 방법을 중단해야한다는 것을 의미합니다. 명시된대로 문제에 대한 해결책은 무엇입니까?
Basilevs

@Basilevs이 질문은 A와 B가 제대로 모델링되지 않았 음을 암시합니다. 처음에는 문제를 일으키는 원인 이 바로이 내재 된 결함입니다 . 물론 그들은 단순한 사실 존재들이 있다는 증거하지 해야 존재는. 그것이 제가 위에서하는 요점입니다. 분명히 DRY가 깨지는 것을 피하기 위해 대체 설계가 필요합니다. 이러한“디자인 원칙”의 목적은 응용 프로그램을보다 쉽게 ​​변경할 수 있도록하는 것입니다.
킹 사이드 슬라이드

완전히 다른 의존성을 가진 수많은 다른 방법이 잘못 모델링 되었기 때문에 단지 하나의 우발적이지 않은 방법으로 다시 작성해야합니까? 아니면 모듈 A와 B에 각각 단일 방법이 있다고 가정합니까?
Basilevs

0

이러한 모든 옵션은 모듈간에 추가 종속성을 생성합니다. 커플 링을 증가시키는 비용으로 DRY 원리를 적용합니다.

적어도 세 번째 옵션에 대해서는 다른 의견이 있습니다.

설명에서 :

  • 요구 F
  • B는 F를 필요로한다
  • A와 B는 서로 필요하지 않습니다.

A와 B 모두 이미 C의 기능을 필요로하기 때문에 C 모듈에 F를 넣어도 커플 링이 증가하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.