YAGNI 또는 Good Design이 우선해야하는 것은 무엇입니까?


76

YAGNI 는 어느 시점 에서 좋은 코딩 관행에 우선 순위를 두어야 합니까? 나는 직장에서 프로젝트를 진행 중이며 동료들에게 좋은 코드 표준을 천천히 소개하고 싶습니다 (현재는 없으며 운율이나 이유없이 모든 것이 해킹됩니다). 그러나 일련의 클래스를 만든 후에 (우리는 TDD 또는 슬프게도 단위 테스트를 전혀하지 마십시오.) 나는 물러서서이 클래스를 확장 할 필요가 없다는 것을 확실히 알고 있기 때문에 YAGNI를 위반한다고 생각했습니다.

다음은 의미하는 구체적인 예입니다. 기본 CRUD 함수와 함께 기본 리포지토리 스타일 패턴을 사용하는 저장 프로 시저 집합을 래핑하는 데이터 액세스 계층이 있습니다. 모든 리포지토리 클래스에 필요한 소수의 메서드가 있기 때문에 리포지토리에 대한 일반 인터페이스 ()를 만들었습니다 IRepository. 그러나 각 리포지토리 유형 (예 :)에 대해 "마커"인터페이스 (예 : 새로운 기능을 추가하지 않는 인터페이스 ICustomerRepository)를 만들고 구체적인 클래스가이를 구현합니다. 저장 프로 시저에서 반환 한 DataReaders / DataSets에서 비즈니스 개체를 빌드하기 위해 Factory 구현과 동일한 작업을 수행했습니다. 내 저장소 클래스의 서명은 다음과 같습니다.

public class CustomerRepository : ICustomerRepository
{
    ICustomerFactory factory = null;

    public CustomerRepository() : this(new CustomerFactory() { }

    public CustomerRepository(ICustomerFactory factory) {
        this.factory = factory;
    }      

    public Customer Find(int customerID)
    {
        // data access stuff here
        return factory.Build(ds.Tables[0].Rows[0]);
    }
}

여기서 내가 염려하는 것은 YAGNI를 위반한다는 것입니다. 99 % 확실하게이 CustomerFactory저장소에 구체적인 것 이외의 다른 것을 줄 이유가 없다는 것을 알고 있기 때문 입니다. 우리는 단위 테스트가 없기 때문에 MockCustomerFactory비슷한 것을 필요로하지 않으며 인터페이스가 너무 많으면 동료를 혼란스럽게 할 수 있습니다. 한편, 공장의 구체적인 구현을 사용하는 것은 디자인 냄새처럼 보인다.

적절한 소프트웨어 설계와 솔루션을 오버 아키텍트하지 않는 것 사이에 타협 할 수있는 좋은 방법이 있습니까? 나는 모든 "단일 구현 인터페이스"가 필요한지 또는 약간의 좋은 디자인을 희생 할 수 있는지, 예를 들어 기본 인터페이스와 단일 콘크리트를 가질 수 있는지에 대한 질문을하고있다. 구현이 사용될 경우 인터페이스.


17
"우리는 단위 테스트가 없기 때문에 MockX가 필요하지 않기 때문에"자연스럽게 "IX가 필요없고 X 만 필요합니다"라고 말합니다. 나는 주위에, 당신은 단위 테스트가없는 사실 이런 일들은 당신이 도움이 될 것입니다 때문에, IX 및 MockX이 필요하다는 사실을 강조하는 플립 단위 테스트를. 테스트가 없다는 현실을 받아들이지 말고 일시적인 문제 (아마 좋은, 오랜 시간)로 해결 될 일시적인 문제로 취급하십시오.
Anthony Pegram

10
구글이 사소한 일이지만, 누군가 YAGNI가 "필요하지 않을 것"을 의미한다고 언급해야합니다.
thedaian

1
이런 새로운 클래스를 작성한다면 단위 테스트를 추가하고 싶을 것입니다. 동료가 그들을 운영하지 않더라도. 적어도 나중에 당신은 말할 수있다. "보라! 내 코드를 깨 뜨렸을 때 나의 단위 테스트가 그것을 잡았다! 얼마나 큰 단위 테스트가 있는지보십시오!" 이 경우, 조롱 가능하게 만드는 것이 가치가있을 수 있습니다. (내가 선호하는 것, 비록 객체는 인터페이스를 정의하지 않고 조롱 할 수 있다면)
윈스턴 Ewert에게

단위 테스트로 인해 모의 프레임 워크를 만들거나 사용하여 라이브 저장 프로 시저에 충돌하지 않습니까? 이것이 테스트를 추가하지 않는 주된 이유입니다. 우리는 각각 테스트하고 작성하는 프로덕션 데이터베이스의 로컬 사본을 가지고 있습니다.
Wayne Molina

3
@Anthony 그리고 조롱은 항상 수반되는 추가 복잡성 오버 헤드를 정당화합니까? 조롱은 훌륭한 도구이지만 그 유용성도 비용에 가중치를 두어야하며 때로는 과도한 간접 지정으로 스케일이 다른 방향으로 기울어 지기도합니다. 물론 추가 복잡성을 도와주는 도구가 있지만 복잡성을 없애지는 못할 것입니다. "모든 비용으로 테스트"를 주어진 것으로 취급하는 추세가 증가하고있는 것 같습니다. 나는 이것이 거짓이라고 믿는다.
Konrad Rudolph

답변:


75

적절한 소프트웨어 설계와 솔루션을 오버 아키텍트하지 않는 것 사이에 타협 할 수있는 좋은 방법이 있습니까?

야 그니.

나는 약간 좋은 디자인을 희생 할 수 있었다

틀린 가정.

기본 인터페이스와 단일 콘크리트,

그것은 "희생"이 아닙니다. 그것은 이다 좋은 디자인.


72
더 이상 추가 할 것이 아니라 빼앗을 것이 없을 때 완벽이 이루어집니다. Antoine De St-Exupery
Newtopian

5
@Newtopian : 사람들은 Apple의 최신 제품에 대해 여러 가지 감정을 가지고 있습니다. :)
Roy Tinker

14
이런 종류의 답변에 큰 문제가 있습니다. "Y가 말하고 X가 커뮤니티의 지원을 받고 있기 때문에 X는 사실"입니까? 실생활에서 누군가가 YAGNI를 상대로 도망 쳤다면이 대답을 논증으로 보여 주겠습니까?
vemv

2
@vemv. YAGNI에 반대하는 사람은 없습니다. S.Lott는 OP의 두 가지 목표 사이에 상충되는 모순이 실수라고 말했다. BTW, 오늘날 소프트웨어 업계 에서 YAGNI 에 반대 하는 적극적인 개발자 를 알고 있습니까? 실제 프로젝트에서 작업하는 경우 요구 사항이 지속적으로 변화하고 있으며 사용자와 관리자는 일반적으로 요구 사항이 무엇인지 원하지 않는지 알 수 있습니다. 미래를 예측하는 코드를 작성하여 시간, 에너지 및 돈을 낭비하거나 직업을 위험에 빠뜨리는 이유는 무엇입니까?
벡터

6
내 요지는 YAGNI에 관한 것이 아니라 응답 품질에 관한 것입니다. 나는 특히 누군가가 뛰어 다니고 있다고 생각하지 않으며, 그것은 내 추론의 일부였습니다. 다시 읽어주십시오.
vemv

74

대부분의 경우 필요하지 않은 코드를 피하면 더 나은 디자인으로 이어집니다 . 가장 유지 관리 가능하고 미래에 대비할 수있는 디자인은 요구 사항을 충족하는 가장 잘 알려진 간단한 코드를 사용하는 것입니다.

가장 단순한 디자인은 가장 진화하기 쉽습니다. 쓸모없고 과도하게 설계된 추상화 계층과 같은 유지 관리 기능을 죽이는 것은 없습니다.


8
'YAGNI 코드를 피하는 것'이 어렴풋이 모호합니다. 필요하지 않은 코드 또는 YAGNI 원칙을 준수하는 코드를 의미 할 수 있습니다 . (Cf. 'KISS code')
sehe

2
@sehe : "YAGNI 원칙을 고수하는 것은 명백하게 자기 모순적이지만"전혀 모호하지는 않습니다. 당신은 필요하지 않을까요?
Michael Borgwardt

1
이 답변을 큰 글꼴로 인쇄하고 모든 건축 우주 비행사가 읽을 수있는 곳에 매달겠습니다. +1!
kirk.burleson

1
+1. 나는 여전히 새로운 기능을 지원하고 추가하기 위해 주어진 첫 번째 기업 프로젝트를 기억할 수 있습니다. 내가 한 우선은 손실없이 40,000 줄 프로그램에서 쓸모없는 코드의 32,000 라인을 제거했다 어떤 기능을. 그 후 원래 프로그래머가 해고되었습니다.
EJ 브레넌

4
@vemv : "사소한 것을 제외하고는 현재 사용되지 않음", "YAGNI의 경우"로 "useless"를 읽습니다. "과도 공학적"은 "나쁜"보다 훨씬 더 구체적입니다. 구체적으로 말하면 "구체적인 현재 요구 사항이 아니라 이론적 인 개념이나 상상 가능한 요구 사항으로 인한 복잡성"을 의미합니다.
Michael Borgwardt

62

YAGNI와 SOLID (또는 기타 설계 방법)는 상호 배타적이지 않습니다. 그러나 그것들은 거의 극과 반대입니다. 어느 쪽이든 100 %를 준수 할 필요는 없지만,주고받을 것이 있습니다. 한 장소에서 한 클래스에서 사용하는 고도로 추상적 인 패턴을 더 많이보고 YAGNI를 말하고 단순화할수록 디자인의 솔리드가 줄어 듭니다. 반대의 경우도 마찬가지입니다. 여러 번 개발에서 디자인은 "신념에 따라"SOLIDly 구현되었습니다. 어떻게 필요할지 알지 못하지만 직감이 있습니다. 이것은 사실 일 수 있으며 (더 많은 경험을 쌓을수록 사실 일 가능성이 더 높음), 또한 "무슨 일을하는"접근 방식만큼 많은 기술적 부채를 줄 수 있습니다. DIL "스파게티 코드"코드베이스 대신 "라그나 코드"로 끝날 수 있습니다. 단순히 메소드 나 새로운 데이터 필드를 추가하는 계층이 너무 많으면 서비스 프록시와 느슨하게 연결된 종속성을 하나의 구현으로 처리하는 데 며칠이 걸리는 프로세스가됩니다. 또는 "라비올리 코드"로 끝날 수 있습니다. 아키텍처에서 위, 아래, 왼쪽 또는 오른쪽으로 이동하면 각각 3 줄씩 50 가지 방법이 사용됩니다.

나는 다른 답변으로 그것을 말했지만 여기에 있습니다 : 첫 번째 패스에서 작동시킵니다. 두 번째 패스에서는 우아하게 만드십시오. 세 번째 단계에서는 SOLID로 만듭니다.

세분화 :

코드를 처음 작성할 때는 간단하게 작동해야합니다. 이 시점에서, 당신이 아는 모든 것은 일회성입니다. 따라서 2와 2를 추가하기 위해 "상아탑"아키텍처를 구축 할 수있는 스타일 포인트는 없습니다.해야 할 일을하고 다시는 보지 못할 것이라고 가정하십시오.

다음에 커서가 해당 코드 줄에 들어가면 이제 처음 작성했을 때의 가설을 반박했습니다. 해당 코드를 다시 방문하여 코드를 확장하거나 다른 곳에서 사용할 수 있으므로 일회성이 아닙니다. 이제 DRY (반복하지 말 것)와 같은 몇 가지 기본 원칙과 코드 디자인에 대한 다른 간단한 규칙을 구현해야합니다. 반복되는 코드에 대해 메소드 및 / 또는 루프를 추출하고, 일반적인 리터럴 또는 표현식에 대한 변수를 추출하고, 주석을 추가 할 수 있지만 전체 코드는 자체 문서화해야합니다. 이제는 코드가 잘 결합되어 있으면 잘 정리되어 있으며 코드를 보는 사람은 코드를 한 줄씩 추적하는 대신 코드를 읽음으로써 자신이하는 일을 쉽게 배울 수 있습니다.

커서가 해당 코드를 세 번 입력하면 아마도 큰 문제 일 것입니다. 다시 확장하거나 코드베이스의 다른 세 곳에서 유용하게 사용할 수 있습니다. 이 시점에서 핵심은 시스템의 핵심 요소가 아닌 핵심 요소이므로 이와 같이 설계되어야합니다. 이 시점에서, 일반적으로 지금까지 어떻게 사용되었는지에 대한 지식이 있으며,이를 통해 디자인을 설계하여 사용법과 새로운 디자인을 능률화하는 방법에 대한 올바른 디자인 결정을 내릴 수 있습니다. 이제 SOLID 규칙이 방정식을 입력해야합니다. 특정 목적을 가진 코드를 포함하는 클래스를 추출하고, 유사한 목적이나 기능을 가진 클래스에 대한 공통 인터페이스를 정의하고, 클래스간에 느슨하게 연결된 종속성을 설정하고, 쉽게 추가, 제거 또는 교체 할 수 있도록 종속성을 디자인하십시오.

이 시점부터이 코드를 더 확장, 재 구현 또는 재사용해야하는 경우 모두 우리가 알고 사랑하는 "블랙 박스"형식으로 멋지게 패키지되고 추상화됩니다. 필요할 때마다 연결하거나 인터페이스의 사용법을 변경하지 않고도 인터페이스의 새로운 구현으로 테마에 새로운 변형을 추가하십시오.


나는 굉장함 두 번째.
Filip Dupanović

2
예. 재사용 / 확장을 사전에 설계 할 때, 재사용 또는 확장을 원할 때 예상했던 것과 다른 방식 일 것입니다. 특히 미래에 대한 예측은 어렵다. 그래서 나는 당신의 3- 스트라이크 규칙을지지합니다-그때까지, 당신은 그것이 어떻게 재사용 / 확장 될지에 대한 합리적인 생각을 가지고 있습니다. 주의 : 예전의 프로젝트, 도메인 지식 또는 이미 지정되어있는 방법을 이미 알고있는 경우는 예외입니다.
13ren

네 번째 패스에서 굉장합니다.
Richard Neil Ilagan

@KeithS : John Carmack이 비슷한 것을 한 것 같습니다. "Quake II의 소스 코드 ... Quake 1, Quake World 및 QuakeGL을 하나의 아름다운 코드 아키텍처로 통합하십시오." fabiensanglard.net/quake2/index.php
13ren

"실용 리팩토링": :) 하나는 내가 통해 UR 규칙 이름 것 같아요
Songo

31

그 중 하나 대신 WTSTWCDTUAWCROT를 선호합니까?

(우리가 할 수있는 가장 간단한 일은 무엇이고 목요일에 릴리스 할 수 있습니까?)

더 간단한 약어가 할 일 목록에 있지만 우선 순위는 아닙니다.


8
그 약어는 YAGNI 원칙을 위반합니다 :)
riwalk

2
나는 필요한 문자를 정확하게 사용했다. 그런 식으로 저는 모차르트와 같습니다. 네. 나는 약어의 모차르트입니다.
Mike Sherrill 'Cat Recall'9

4
나는 모차르트가 두문자어를 만드는 것이 끔찍하다는 것을 결코 알지 못했습니다. 나는 SE 사이트에서 매일 새로운 것을 배웁니다. : P
Cameron MacFarland

3
@Mike Sherrill 'CatRecall': 어쩌면 WTSTWCDTUWCROTAWBOF = "우리가 할 수있는 가장 간단한 방법은 무엇입니까? 우리는 목요일에 릴리스 할 수 있으며 금요일에는 중단되지 않습니까?" ;-)
조르지오

1
@ Stargazer712 no :) POLA를 위반합니다.
v.oddou

25

YAGNI와 좋은 디자인은 충돌하지 않습니다. YAGNI는 미래의 요구를 지원하는 것이 아닙니다. 좋은 디자인은 소프트웨어가 현재 하는 일과 그 작업을 투명하게 만드는 것 입니다.

팩토리를 도입하면 기존 코드가 더 간단 해 집니까? 그렇지 않은 경우 추가하지 마십시오. 예를 들어 테스트를 추가 할 때 (예 : 수행해야 할 경우) 추가하십시오.

YAGNI는 향후 기능을 지원하기 위해 복잡성을 추가하지 않습니다 .
좋은 디자인은 모든 현재 기능을 계속 지원하면서 복잡성을 제거 하는 것입니다.


15

충돌하지 않고 목표가 잘못되었습니다.

무엇을 성취하려고합니까?

양질의 소프트웨어를 작성하고 코드 기반을 작게 유지하면서 문제가 없도록하려고합니다.

이제 우리는 갈등을 겪습니다. 우리가 사용하지 않을 사례를 쓰지 않으면 어떻게 모든 사례를 다룰까요?

문제는 다음과 같습니다.

여기에 이미지 설명을 입력하십시오 (관심있는 사람, 이것을 증발 구름 이라고 함 )

그래서,이게 뭐야?

  1. 당신은 당신이 필요하지 않을 것을 모른다
  2. 당신은 시간을 낭비하고 코드를 부풀고 싶지 않습니다

이 중 어느 것을 해결할 수 있습니까? 글쎄, 그것은 시간을 낭비하고 싶지 않은 것처럼 보이며 팽창 코드는 큰 목표이며 의미가 있습니다. 첫 번째는 어떻습니까? 코딩해야 할 것을 알 수 있습니까?

나는 직장에서 프로젝트를 진행하고 있고 동료들에게 좋은 코드 표준을 천천히 소개하고 싶다. 우리가이 수업 중 일부를 확장 할 필요가 없다는 것을 확실히 알고 있기 때문에 YAGNI를 위반한다고 생각했습니다.

그 모든 것을 다시 말합시다

  • 코드 표준 없음
  • 진행중인 프로젝트 계획 없음
  • 카우보이들은 도처에 자신의 망할 일을하고 (와일드 와일드 웨스트에서 보안관을하려고 노력하고 있습니다), yee haw.

적절한 소프트웨어 설계와 솔루션을 오버 아키텍트하지 않는 것 사이에 타협 할 수있는 좋은 방법이 있습니까?

타협 할 필요가 없으며, 유능하고 전체 프로젝트에 대한 비전을 가진 팀을 관리 할 사람이 필요합니다. 미래에 대해 너무 불확실하기 때문에 필요하지 않은 것들을 던지는 대신에 당신이 필요로하는 것을 계획 할 수있는 사람이 필요합니다. 왜? 왜 그런지 말해주지. 왜냐하면 아무도 당신들 사이에서 망할 계획이 없기 때문입니다. 완전히 별도의 문제를 해결하기 위해 코드 표준을 도입하려고합니다. 해결해야 할 주요 문제는 명확한 로드맵과 프로젝트입니다. 그런 다음 "코드 표준은 팀으로서이 목표를보다 효과적으로 달성하는 데 도움이됩니다"라고 말할 수 있습니다. 이는 절대적이지만이 질문의 범위를 벗어납니다.

이 작업을 수행 할 수있는 프로젝트 / 팀 관리자를 확보하십시오. 지도가 있으면지도를 요청하고지도가없는 YAGNI 문제를 설명해야합니다. 이들이 무능한 경우, 계획을 직접 작성하고 "필요한 사항에 대한 보고서가 여기 있으니 검토하고 결정 사항을 알려주십시오."라고 말합니다.


슬프게도 하나도 없습니다. 개발 관리자는 표준 / 품질보다 빠른 작업 수행에 관심이 있거나 클래스에서 직접 반환되는 모든 곳에서 원시 데이터 세트 사용, VB6 스타일 코딩 및 모든 코드를 복사하여 붙여 넣은 중복 로직이있는 코드 숨김의 모든 것과 같은 표준 사례를 수행합니다. 위에.
Wayne Molina

괜찮습니다. 조금 느려질 것입니다. 그러나 걱정에 대해 이야기해야합니다. 이 YAGNI / 쓸모없는 코드 문제는 시간을 낭비하고 로드맵을 제안하고 로드맵을 제공하며 더 빨리 작업 할 수 있다고 설명합니다. 그가 매입 할 때 빈약 한 표준이 개발 속도에 미치는 문제를 해결하고 더 나은 표준을 제안하십시오. 그들은 프로젝트를 완수하기를 원하고, 그 일을 관리하는 방법을 모른다면, 그를 대체하거나 그를 태워야하거나 ... 종료해야합니다.
시크릿

음 ..... 추진 목표는 '귀중하고 가치있는 제품을 갖고 싶다'고 생각하십니까?
sehe

그의 결정이 아닌 @sehe : p.
시크릿

3
좋은 대답입니다. 그는 오르막 전투에 직면하고 있습니다. 경영진이없는 경우에는이를 달성하기가 어려울 수 있습니다. 그리고 귀하는 질문이 너무 이른 것이기 때문에 실제 문제를 다루지 않는 것이 맞습니다.
세스 스피어 맨

10

당신이 있기 때문에 코드를 허용하는 것은 단위 테스트로 확장 될 수는 결코 YAGNI 대상이 될 것하지 않습니다 필요. 그러나 CustomerFactory가 이미 인터페이스에서 상속되어 언제든지 MockCustomerFactory로 교체 할 수 있기 때문에 단일 구현 인터페이스로의 디자인 변경 사항이 실제로 코드의 테스트 가능성을 높이고 있다고 확신하지 않습니다.


1
Good Design과 YAGNI 간의 우주 전투 및 / 또는 사랑에 대한 것이 아니라 실제 문제에 대한 유용한 의견을 +1하십시오.
psr

10

이 질문은 잘못된 딜레마를 제시합니다. YAGNI 원칙을 올바르게 적용하는 것은 관련이 없습니다. 좋은 디자인 의 한 측면 입니다. 각 SOLID 원칙은 훌륭한 디자인 측면이기도합니다. 모든 원칙에 항상 모든 원칙을 적용 할 수는 없습니다. 실제 문제는 코드에 많은 영향을 미치며 일부는 반대 방향으로 나아가고 있습니다. 디자인 원칙은이 모든 것을 설명해야하지만, 모든 상황에 맞는 소수의 원칙은 없습니다.

자, 때로는 다른 방향으로 이끌 수 있지만 본질적으로 충돌하는 것은 아니라는 점을 이해하고 각 원칙을 살펴 보겠습니다.

YAGNI는 개발자가 특정 종류의 재 작업, 즉 잘못된 것을 구축함으로써 발생하는 재 작업을 피하도록 돕기 위해 고안되었습니다. 이것은 우리가 미래에 변화하거나 필요할 것으로 생각되는 것에 대한 가정이나 예측에 기초하여 잘못된 결정을 너무 일찍 내리지 않도록 안내함으로써 이루어집니다. 집단적 경험은 우리가 이것을 할 때 일반적으로 잘못되었음을 알려줍니다. 예를 들어, YAGNI는 여러 구현자가 필요하다는 것을 지금 알지 않는 한 재사용 가능성을 위해 인터페이스를 만들지 말라고 지시 합니다. 마찬가지로 YAGNI는 지금 화면이 두 개 이상 있다는 것을 알지 않는 한 응용 프로그램에서 단일 양식을 관리하기 위해 "ScreenManager"를 만들지 않는다고 말합니다 .

많은 사람들이 생각하는 것과는 달리 SOLID는 재사용 성, 일반성 또는 추상화에 관한 것이 아닙니다 . SOLID는 특정 변경 내용에 대해 아무 말도하지 않고 변경 준비 코드를 작성하도록 도와줍니다 . SOLID의 5 가지 원칙은 지나치게 일반적이지 않고 유연하고 순진하지 않고 코드를 작성하는 전략을 만듭니다. SOLID 코드를 올바르게 적용하면 잘 정의 된 역할과 경계를 가진 작고 집중적 인 클래스가 생성됩니다. 실제로 필요한 요구 사항을 변경하려면 최소한의 클래스 만 터치해야합니다. 마찬가지로 모든 코드 변경에도 다른 클래스에 대한 "리플"의 양이 최소화됩니다.

현재 상황의 예를 살펴보면 YAGNI와 SOLID의 의견을 살펴 보겠습니다. 모든 저장소가 외부에서 동일하게 보이기 때문에 공통 저장소 인터페이스를 고려하고 있습니다. 그러나 일반적인 일반 인터페이스의 가치는 구현자가 무엇인지 알 필요없이 모든 구현자를 사용할 수있는 능력입니다. 앱에 이것이 필요하거나 유용한 곳이 없다면 YAGNI는 그렇지 않다고 말합니다.

살펴볼 5 가지 SOLID 원칙이 있습니다. S는 단일 책임입니다. 인터페이스에 대해서는 아무 것도 말하지 않지만 구체적인 클래스에 대해서는 말할 수 있습니다. 리포지토리의 책임은 암시 적 컨텍스트 (CustomerRepository는 암시 적으로 리포지토리에 대한 리포지토리)에서 고객 항목 유형을 지정하는 일반화 된 데이터 액세스 API.

O는 공개 폐쇄입니다. 이것은 대부분 상속에 관한 것입니다. 공통 기능을 구현하는 공통 기반에서 리포지토리를 파생 시키려고하거나 다른 리포지토리에서 더 파생 할 것으로 예상되는 경우에 적용됩니다. 그러나 당신은 그렇지 않으므로 그렇지 않습니다.

L은 Liskov 대체 성입니다. 공통 리포지토리 인터페이스를 통해 리포지토리를 사용하려는 경우에 적용됩니다. 인터페이스와 구현에 제한을 두어 일관성을 보장하고 다른 요소를 처리하지 않도록합니다. 그 이유는 이러한 특수 처리가 인터페이스의 목적을 손상시키기 때문입니다. 공통 리포지토리 인터페이스를 사용하지 않도록 경고 할 수 있으므로이 원칙을 고려하는 것이 유용 할 수 있습니다. 이것은 YAGNI의 지침과 일치합니다.

나는 인터페이스 분리입니다. 리포지토리에 다른 쿼리 작업을 추가하기 시작한 경우에 적용될 수 있습니다. 인터페이스 분리는 클래스 멤버를 두 개의 서브 세트로 나눌 수있는 곳에서 적용됩니다. 하나는 특정 소비자가 사용하고 다른 하나는 다른 서브 세트가 사용하지만 소비자는 두 서브 세트를 모두 사용하지 않을 것입니다. 지침은 하나의 공통 인터페이스가 아닌 두 개의 별도 인터페이스를 작성하는 것입니다. 귀하의 경우 개별 인스턴스를 가져오고 저장하는 것이 일반적인 쿼리와 동일한 코드로 소비 될 가능성이 낮으므로 두 개의 인터페이스로 분리하는 것이 유용 할 수 있습니다.

D는 의존성 주입입니다. 여기서 우리는 S와 같은 시점으로 돌아갑니다. 데이터 액세스 API 소비를 별도의 객체로 분리 한 경우,이 원칙에 따르면 해당 객체의 인스턴스를 새로 작성하는 것이 아니라 생성시이를 전달해야합니다. 저장소. 이를 통해 데이터 액세스 구성 요소의 수명을보다 쉽게 ​​제어 할 수 있으므로 단일 경로를 만들지 않고도 리포지토리간에 참조를 공유 할 수 있습니다.

대부분의 SOLID 원칙이 앱 개발의이 특정 단계에 반드시 적용되는 것은 아니라는 점에 유의해야합니다. 예를 들어, 데이터 액세스를 분리해야하는지 여부는 데이터의 복잡도 및 데이터베이스에 영향을주지 않고 리포지토리 논리를 테스트할지 여부에 따라 다릅니다. 이것이 (아쉽게도 내 의견으로는) 가능성이없는 것처럼 들리므로 아마도 필요하지 않을 것입니다.

따라서 YAGNI와 SOLID는 실제로 즉각적이고 관련성이 높은 하나의 일반적인 조언을 제공한다는 사실을 알게되었습니다. 공통 일반 리포지토리 인터페이스를 만들 필요는 없습니다.

이 모든 신중한 생각은 학습 연습으로 매우 유용합니다. 배우면서 시간이 많이 걸리지 만 시간이 지남에 따라 직관이 발달하고 매우 빠릅니다. 당신은 옳은 일을 알게 될 것입니다. 그러나 누군가가 왜 당신에게 설명을 요구하지 않는 한이 모든 단어들을 생각할 필요는 없습니다.


이 페이지에서 대부분의 논의는 GRASPrinciples의 "낮은 커플 링"과 "높은 응집력"이라는 2 개의 큰 경쟁자를 제외하고 있다고 생각합니다. 비용이 많이 드는 설계 결정은 "낮은 결합"원리에서 비롯됩니다. 낮은 커플 링을 위해 SRP + ISP + DIP를 "활성화"할 때와 같습니다. 예 : MVC 패턴의 한 클래스-> 3 개의 클래스. 또는 더 비쌉니다. .dll / .so 모듈 / 어셈블리로 분할하십시오. 빌드 시사점, 프로젝트, makelists, 빌드 서버, 소스 버전 파일 추가로 인해 비용이 많이 듭니다 ...
v.oddou

6

'좋은 디자인'은 쓸모없는 경우에도 항상 적용되어야하는 일종의 아이디어와 공식 규칙을 따르는 것을 의미한다고 생각합니다.

나쁜 디자인의 IMO. YAGNI는 좋은 디자인의 구성 요소이며 결코 모순되지 않습니다.


2

귀하의 예에서, YAGNI가 우선해야한다고 말하고 싶습니다. 나중에 인터페이스를 추가해야하는 경우 비용이 많이 들지 않습니다. 그건 그렇고, 목표가 전혀 없다면 클래스별로 하나의 인터페이스를 갖는 것이 정말 좋은 디자인입니까?

한 번 더 생각하면, 때로는 필요한 것은 좋은 디자인이 아니라 충분한 디자인입니다. 다음은 주제에 대한 매우 흥미로운 게시물 순서입니다.


첫 번째 링크와 세 번째 링크는 같은 위치로 이동합니다.
David Thornley

2

어떤 사람들은 인터페이스 이름이 I로 시작해서는 안된다고 주장합니다. 구체적으로 한 가지 이유는 주어진 유형이 클래스인지 인터페이스인지에 대한 종속성을 실제로 유출하는 것입니다.

무엇이 당신을 금지 CustomerFactory중 하나에 의해 구현 될 것이다, 처음에는 클래스되고 나중에 인터페이스로 변경 DefaultCustormerFactory하거나 UberMegaHappyCustomerPowerFactory3000? 변경해야 할 유일한 것은 구현이 인스턴스화되는 장소입니다. 그리고 더 좋은 디자인을 가지고 있다면, 이것은 대부분 소수의 장소입니다.

리팩토링은 개발의 일부입니다. 모든 단일 클래스에 대해 인터페이스와 클래스를 선언하는 것보다 작은 코드, 즉 리팩토링하기 쉬운 것이 더 좋으며, 동시에 적어도 두 곳에서 모든 메소드 이름을 변경해야합니다.

인터페이스 사용의 실제 포인트는 모듈성을 달성하는 것인데, 이는 아마도 좋은 디자인의 가장 중요한 기둥입니다. 그러나 모듈은 외부 세계와의 분리 (외부 관점에서 인식하는 방식 임)에 의해서만 정의 될뿐만 아니라 내부 작업에서도 동일하게 정의됩니다.
내가 지적하고자하는 것은 본질적으로 함께 속하는 것들을 분리하는 것이 의미가 없다는 것입니다. 어떤 식 으로든 컵 당 개별 선반이있는 찬장을 갖는 것과 같습니다.

크고 복잡한 문제를 더 작고 간단한 하위 문제로 고안하는 것이 중요합니다. 그리고 더 세분화하지 않고 간단 해 지거나 실제로는 더 복잡해 질 때까지 멈추어야합니다. 이것은 YAGNI의 목록으로 볼 수 있습니다. 그리고 그것은 확실히 좋은 디자인을 의미합니다.

단일 리포지토리와 단일 팩토리에서 로컬 문제를 해결하는 것이 목표는 아닙니다. 목표는이 결정이 나머지 응용 프로그램에는 영향을 미치지 않는다는 것입니다. 그것이 모듈성에 관한 것입니다.
동료가 모듈을보고 소수의 자명 한 설명이 포함 된 정면을보고 자신감을 느끼면 잠재적으로 정교한 내부 배관에 대해 걱정할 필요없이 사용할 수 있다고 확신 할 수 있습니다.


0

당신은 만드는 interface미래의 예측 여러 구현을. I<class>코드베이스의 모든 클래스를 가질 수도 있습니다 . 하지마

YAGNI에 따라 단일 콘크리트 클래스를 사용하십시오. 테스트 목적으로 "모의 (mock)"객체가 필요하다면, 원래 클래스를 두 개의 구현 (하나는 원래의 구체적인 클래스와 다른 하나는 모의 구현)을 가진 추상 클래스 로 바꾸십시오 .

새 콘크리트 클래스를 인스턴스화하려면 원래 클래스의 모든 인스턴스를 업데이트해야합니다. 정적 생성자를 사용하면 문제를 해결할 수 있습니다.

YAGNI는 코드를 작성하기 전에 코드를 작성하지 말라고 말합니다.

좋은 디자인은 추상화를 사용한다고 말합니다.

둘 다 가질 수 있습니다. 클래스는 추상화입니다.


0

마커가 왜 인터페이스입니까? "태그 지정"이상의 작업을 수행하지 않는다고 생각합니다. 모든 공장 ​​유형에 대해 다른 "태그"를 사용하면 요점이 무엇입니까?

인터페이스의 목적은 클래스에 "처럼 작동"동작을 제공하고 "저장 기능"을 제공하는 것입니다. 따라서 모든 구체적인 리포지토리 유형이 동일한 IRepository처럼 작동하면 (모두 IRepository를 구현 함) 다른 코드에서 동일한 코드로 동일한 방식으로 처리 할 수 ​​있습니다. 이 시점에서 디자인을 확장 할 수 있습니다. 더 일반적인 리포지토리 유형을 모두 추가하면 일반 IRepository (ies)로 처리됩니다. 동일한 코드는 "일반"리포지토리와 같은 모든 콘크리트 유형을 처리합니다.

인터페이스는 공통성을 기반으로 작업을 처리하기위한 것입니다. 그러나 사용자 정의 마커 인터페이스 a) 동작을 추가하지 않습니다. 그리고 b) 당신이 그들의 독창성을 다루도록 강요하십시오.

유용한 인터페이스를 디자인 할 때까지 구체적인 클래스, 유형 또는 콘크리트 클래스와 1 : 1 상관 관계가있는 사용자 정의 마커 인터페이스를 처리하기 위해 특수 코드를 작성할 필요가 없다는 장점이 있습니다. 무의미한 중복성입니다.

예를 들어, 많은 다른 클래스의 강력한 형식의 컬렉션이 필요한 경우 마커 인터페이스를 볼 수 있습니다. 컬렉션에서 그것들은 모두 "ImarkerInterface"이지만 당신이 그것들을 뽑을 때 그것들은 그것들을 적절한 타입으로 캐스팅해야합니다.


0

막연하게 합리적인 ICustomerRepository를 적을 수 있습니까? 예를 들어 과거에 고객이 실제로 PayPal을 사용한 적이 있습니까? 아니면 회사의 모든 사람들이 알리바바와 연결하는 것에 대해 헷갈리는가? 그렇다면 지금 더 복잡한 디자인을 사용하고 상사에게 멀리 보이는 것처럼 보일 수 있습니다. :-)

그렇지 않으면 기다립니다. 하나 또는 두 개의 실제 구현이 있기 전에 인터페이스를 추측하면 일반적으로 실패합니다. 다시 말해, 일반화 할 몇 가지 예가있을 때까지 멋진 디자인 패턴을 일반화 / 추상화 / 사용하지 마십시오.

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