똑같이 차선책으로 디자인을 반복적으로 피하는 방법은 무엇입니까?


10

그래서 아마도 많은 사람들처럼, 나는 종종 문제를 직감적으로 맞추고 원하는 이점을 갖는 디자인 패턴 / 접근법이있는 디자인 문제로 두통을 겪고 있습니다. 종종 어떤 종류의 작업없이 패턴 / 접근을 구현하기 어렵게 만드는 몇 가지주의 사항이있어 패턴 / 접근의 이점을 무효화합니다. 거의 모든 패턴 / 접근 방식을 반복하는 것은 매우 쉬운 일이 될 수 있습니다. 거의 모든 패턴 / 접근법은 실제로는 쉬운 해결책이없는 실제 상황에서 매우 중요한 경고가 있기 때문입니다.


예:

최근에 본 실제 사례를 기반으로 한 가설적인 예를 드리겠습니다. 상속 계층이 과거에 코드의 확장 성을 방해했기 때문에 상속보다 컴포지션을 사용하고 싶다고 가정 해 봅시다. 코드를 리팩터링했지만 수퍼 클래스 /베이스 클래스가이를 피하려는 시도에도 불구하고 서브 클래스에서 기능을 호출해야하는 컨텍스트가 있다는 것을 알 수 있습니다.

다음으로 가장 좋은 방법은 수퍼 클래스가 동작을 위임 할 수 있도록 또는 서브 클래스가 수퍼 클래스 이벤트를 관찰 할 수 있도록 절반 델리게이트 / 관찰자 패턴 및 절반 컴포지션 패턴을 구현하는 것 같습니다. 그런 다음 클래스의 확장 성 및 유지 관리 성이 떨어 지므로 확장 방법이 명확하지 않으며 기존 청취자 / 위임을 확장하기가 까다 롭습니다. 또한 주석을 광범위하게 사용하지 않는 한 슈퍼 클래스를 확장하는 방법을 보려면 구현을 알아야하기 때문에 정보가 잘 숨겨져 있지 않습니다.

따라서이 후 나는 단순히 관찰자 또는 대리자를 완전히 사용하여 접근 방식을 크게 혼합하는 데 따른 단점을 피할 수 있습니다. 그러나 이것은 자체 문제가 있습니다. 예를 들어, 거의 모든 행동에 대해 관찰자 / 위임자가 필요할 때까지 점점 더 많은 양의 행동을 위해 관찰자 또는 대리자가 필요하다는 것을 알 수 있습니다. 하나의 옵션은 모든 동작에 대해 하나의 큰 리스너 / 델리게이트를 갖는 것이지만 구현 클래스는 많은 빈 메소드 등으로 끝납니다.

그런 다음 다른 접근법을 시도 할 수도 있지만 그와 관련된 많은 문제가 있습니다. 다음은, 그다음은


이 반복 프로세스는 각 접근 방식이 다른 접근 방식만큼 많은 문제가있는 것처럼 보이며 설계 결정 마비로 이어질 때 매우 어려워집니다 . 또한 어떤 디자인 패턴이나 접근 방식이 사용되는지에 관계없이 코드가 똑같이 문제가된다는 것을 받아들이 기는 어렵습니다. 이 상황에서 결국 문제 자체를 다시 생각해야한다는 의미입니까? 다른 사람들이이 상황에 직면했을 때 무엇을합니까?

편집 : 내가 지우고 싶은 질문에 대한 많은 해석이있는 것 같습니다.

  • 나는 OOP가 실제로 OOP에 국한되지 않았기 때문에 OOP를 완전히 제거했습니다.
  • 어떤 사람들은 반복적 인 접근 방식을 취해 다른 패턴을 시도해야하거나 패턴이 작동을 멈출 때 버려야한다고 주장했습니다. 이것이 처음부터 언급하려는 프로세스입니다. 나는 이것이 예제에서 분명하다고 생각했지만 더 명확하게 만들 수 있었으므로 그렇게하기 위해 질문을 편집했습니다.

3
"OO 철학을 구독하지 마십시오". 중요한 삶의 결정이 아니라 도구입니다. 도움이 될 때 사용하고 도움이되지 않을 때는 사용하지 마십시오.
user253751

특정 패턴의 관점에서 생각이 들지 않으면 C로 약간 복잡한 프로젝트를 작성해보십시오. 그런 패턴없이 얼마나 많은 일을 할 수 있는지 경험하는 것이 흥미로울 것입니다.
user253751

2
오 C는 패턴이 있습니다. 그들은 매우 다른 패턴입니다. :)
candied_orange

편집에서 이러한 오해의 대부분을 해결했습니다.
Jonathan

이러한 문제가 한 번에 나타나는 것은 정상적인 현상입니다. 자주 발생하는 것은 사실이 아닙니다. 문제에 대해 잘못된 프로그래밍 패러다임을 사용하거나 디자인이 잘못된 위치에 패러다임을 혼합 한 것 같습니다.
Dunk

답변:


8

그런 어려운 결정을 내리면 보통 세 가지 질문을합니다.

  1. 사용 가능한 모든 솔루션의 장단점은 무엇입니까 ?

  2. 아직 고려하지 않은 해결책이 있습니까?

  3. 가장 중요한 것은
    내 요구 사항이 정확히 무엇입니까? 종이에 대한 요구 사항이 아니라 실제 기본 요구 사항입니까?
    어떻게 든 문제를 재구성하고 요구 사항을 조정하여 간단하고 간단한 솔루션을 사용할 수 있습니까?
    데이터를 다른 방식으로 표현하여 간단하고 간단한 솔루션을 제공 할 수 있습니까?

    이것은 인식 된 문제의 기본에 관한 질문입니다. 실제로 잘못된 문제를 해결하려고 한 것 같습니다. 문제에는 일반적인 경우보다 훨씬 간단한 솔루션을 허용하는 특정 요구 사항이있을 수 있습니다. 문제의 공식화에 의문을 제기하십시오!

계속하기 전에 세 가지 질문을 모두 열심히 생각하는 것이 매우 중요합니다. 산책, 사무실 속도 조정, 이러한 질문에 대한 답변을 진정으로 다루기 위해 필요한 모든 것을하십시오. 그러나 이러한 질문에 대답하는 데 시간이 오래 걸리지 않아야합니다. 적절한 시간은 15 분에서 1 주일 정도이며, 이미 찾은 솔루션의 단점과 전체에 미치는 영향에 따라 다릅니다.

이 방법의 가치는 놀랍도록 훌륭한 솔루션을 찾을 수 있다는 것입니다. 우아한 솔루션. 이 세 가지 질문에 답하는 데 투자 할 가치가있는 솔루션입니다. 다음 반복을 즉시 입력하면 해당 솔루션을 찾을 수 없습니다.

물론 때로는 좋은 해결책이없는 것 같습니다. 이 경우 질문 하나에 대한 답이 고착되어 있으며 선은 가장 나쁘지 않습니다. 이 경우 이러한 질문에 대답하는 데 시간이 걸리는 것은 실패 할 수있는 반복을 피할 수 있다는 것입니다. 적절한 시간 내에 코딩으로 돌아가십시오.


나는 이것을 대답으로 잘 표시 할 수 있으며, 이것은 나에게 가장 의미가 있으며 단순히 문제 자체를 재평가하는 것에 대한 합의가있는 것처럼 보입니다.
Jonathan

또한 나는 당신이 그것을 단계로 나누는 방법을 좋아하므로 상황을 평가하기위한 느슨한 절차가 있습니다.
Jonathan

OP, 코드 솔루션의 역학에 갇힌 것을 보았으므로 "이 답변을 표시 할 수도 있습니다." 우리가 작성한 최고의 코드는 요구 사항, 파생 된 요구 사항, 클래스 다이어그램, 클래스 상호 작용 등을 매우 신중하게 분석 한 후였습니다. 감사합니다. 우리는 값 비싼 시트 (관리 및 동료 읽기)의 모든 헤 클링에 저항했습니다. "디자인에 너무 많은 시간을 소비하고 있습니다.", "서두르고 코딩하세요!", "너무 많은 클래스입니다!"등. 일단 우리가 그것에 도달하면 코딩은 즐거움 이상의 즐거움이었습니다. 객관적으로 그것은 전체 프로젝트에서 가장 좋은 코드였습니다.
radarbob

13

우선 가장 먼저-패턴은 유용한 추상화입니다. OO 디자인은 물론 디자인이 끝이 아닙니다.

둘째-현대 OO는 모든 것이 객체가 아니라는 것을 알만큼 똑똑합니다. 때로는 평범한 오래된 함수 또는 일부 필수 스타일 스크립트를 사용하면 특정 문제에 대한 더 나은 솔루션을 얻을 수 있습니다.

이제 사물의 고기에 :

각 접근 방식이 다른 접근 방식과 마찬가지로 많은 문제가있는 것처럼 보이면 매우 어려워집니다.

왜? 비슷한 옵션이 많으면 결정이 쉬워집니다! "잘못된"옵션을 선택해도 크게 잃지 않습니다. 그리고 실제로 코드는 고정되어 있지 않습니다. 좋은 것을 시도하십시오. 반복 합니다.

또한 어떤 디자인 패턴이나 접근 방식이 사용되는지에 관계없이 코드가 매우 문제가 될 수 있음을 받아들이 기는 어렵습니다.

거친 견과류. 어려운 문제-실제 수학적으로 어려운 문제는 어렵습니다. 아마 열심히. 말 그대로 그들에게 좋은 해결책은 없습니다. 그리고 쉬운 문제는 실제로 가치가 없다는 것이 밝혀졌습니다.

그러나 조심하십시오. 사람들이 특정 방식으로 문제를보고 있거나 문제에 부 자연스러운 방식으로 자신의 책임을 깎아 놓았 기 때문에 좋은 선택에 의해 좌절감을 느끼는 경우가 너무 많습니다. "좋은 옵션이 없습니다"는 접근 방식에 근본적으로 문제가있는 냄새 일 수 있습니다.

"깨끗한"코드가 때때로 옵션이되지 않기 때문에 동기가 상실됩니다.

완전은 선의 적입니다. 작동하는 것을 얻은 다음 리팩터링하십시오.

이 문제를 최소화하는 데 도움이되는 디자인 방법이 있습니까? 이와 같은 상황에서해야 할 일에 대해 받아 들여지는 관행이 있습니까?

앞에서 언급했듯이 반복 개발은 일반적으로이 문제를 최소화합니다. 무언가 효과가 있으면 문제를보다 잘 해결하여 문제를 해결할 수 있습니다. 제대로 보이지 않는 추상 디자인이 아닌 실제 코드를보고 평가할 수 있습니다 .


편집에서 약간의 잘못된 해석을 해결했다고 말해야한다고 생각했습니다. 나는 일반적으로 "작동"과 리팩터링 접근을한다. 그러나 종종 이것은 내 경험에 많은 기술적 부채를 초래합니다. 예를 들어, 내가 작동하는 것을 얻었지만 저 자신이나 다른 사람들이 그 위에 쌓인다면, 그러한 것들 중 일부는 피할 수없는 의존성을 가질 수 있으며, 따라서 많은 리팩토링이 필요합니다. 물론 항상 미리 알 수는 없습니다. 그러나 이미 접근 방식에 결함이 있음을 알고 있다면 코드를 작성하기 전에 접근 방식을 반복적으로 리팩터링해야합니까?
Jonathan

@Jonathan-모든 디자인은 일련의 트레이드 오프입니다. 예. 디자인에 결함이 있고 개선 할 수있는 명확한 방법이 있다면 즉시 반복해야합니다. 분명한 개선이 없다면, 그만해
Telastyn

"이들은 당면한 문제에 부 자연스러운 방식으로 자신의 책임을 삭감했습니다. 어떤 좋은 방법도 당신의 접근 방식에 근본적으로 문제가있는 냄새가 될 수 없습니다." 나는 이것에 내기를 걸었다. 일부 개발자는 OP 설명 문제를 겪지 않으며 다른 개발자는 자주 수행하는 것처럼 보입니다. 원래 개발자가 문제를 해결하는 방식으로 이미 설계를 편향했기 때문에 솔루션을보기가 쉽지 않은 경우가 종종 있습니다. 때로는 분명한 솔루션을 찾는 유일한 방법은 디자인 요구 사항부터 완전히 시작하는 것입니다.
Dunk

8

설명하는 상황은 상향식 접근법과 같습니다. 당신은 잎을 가지고 고치려고 노력하고 그 자체가 다른 가지 등에 연결된 가지에 연결되어 있는지 확인하십시오.

타이어로 시작하여 자동차를 만드는 것과 같습니다.

필요한 것은 물러서서 더 큰 그림을 보는 것입니다. 그 잎은 전반적인 디자인에 어떻게 자리 잡고 있습니까? 여전히 최신 상태입니까?

처음부터 모듈을 디자인하고 구현한다면 모듈은 어떻게 보일까요? 현재 구현에서 "이상적인"거리는 얼마나됩니까?

그렇게하면 무엇을해야하는지 더 큰 그림을 볼 수 있습니다. (또는 너무 많은 일이라고 결정하면 문제가 무엇인지).


4

이 예는 일반적으로 더 큰 레거시 코드에서 발생하는 상황과 "너무 큰"리팩토링을 시도 할 때의 상황을 설명합니다.

이 상황에서 내가 줄 수있는 최선의 조언은 다음과 같습니다.

  • 하나의 "빅뱅"에서 주요 목표를 달성하려고 시도하지 마십시오 .

  • 작은 단계로 코드를 개선하는 방법을 배우십시오!

물론, 그것은 기록 된 것보다 작성하기 쉬우므로 실제로 이것을 달성하는 방법은 무엇입니까? 실습과 경험이 필요하며, 사례에 따라 크게 다르며, 모든 경우에 적합한 "이것 또는 저것"을하는 엄격한 규칙은 없습니다. 그러나 당신의 가상의 예를 사용하겠습니다. "상속 구성 (composition-over-herherance)"은 전부 또는 전혀 설계 목표가 아니며, 몇 가지 작은 단계로 달성 할 수있는 완벽한 후보입니다.

"상속 구성 (composition-over-herherance)"이이 경우에 적합한 도구라는 것을 알게되었다고 가정하자. 이 목표가 현명한 목표라는 표시가 있어야합니다. 그렇지 않으면이를 선택하지 않았을 것입니다. 따라서 서브 클래스에서 "호출"된 수퍼 클래스에 많은 기능이 있다고 가정하여이 기능은 해당 수퍼 클래스에 머 무르지 않는 후보입니다.

서브 클래스에서 수퍼 클래스를 즉시 제거 할 수없는 경우 먼저 수퍼 클래스를 위에서 언급 한 기능을 캡슐화하는 더 작은 컴포넌트로 리팩토링하는 것으로 시작할 수 있습니다. 가장 낮은 과일부터 시작하여 더 간단한 구성 요소를 먼저 추출하면 이미 슈퍼 클래스가 덜 복잡해집니다. 슈퍼 클래스가 작을수록 리팩토링이 더 쉬워집니다. 서브 클래스와 수퍼 클래스에서이 구성 요소를 사용하십시오.

운이 좋으면이 프로세스 전체에서 수퍼 클래스의 나머지 코드가 너무 단순 해져서 더 이상 문제없이 서브 클래스에서 수퍼 클래스를 제거 할 수 있습니다. 또는 상속없이 재사용하려는 구성 요소에 충분한 코드를 이미 추출했기 때문에 수퍼 클래스를 유지하는 것이 더 이상 문제가되지 않습니다.

리팩토링이 간단한 지 알 수 없기 때문에 시작 위치를 잘 모를 경우에는 스크래치 리팩토링 을 수행하는 것이 가장 좋습니다 .

물론 실제 상황은 더 복잡 할 수 있습니다. 따라서 배우고 경험을 모으고 인내심을 가지십시오. 여기에 추천 할 수있는 두 권의 책이 있습니다.

  • Fowler의 리팩토링 : 매우 작은 리팩토링 의 전체 카탈로그를 설명합니다 .

  • Feathers의 레거시 코드효과적으로 작업 : 잘못 설계된 코드를 대량으로 처리하고 더 작은 단계에서 더 테스트 할 수있는 방법에 대한 훌륭한 조언을 제공합니다.


1
이것은 또한 매우 도움이됩니다. 작은 단계적 또는 스크래치 리팩토링은 너무 방해하지 않고 다른 작업과 함께 점진적으로 완료 될 수있는 것이되기 때문에 좋은 생각입니다. 여러 답변을 승인 할 수 있기를 바랍니다.
Jonathan

1

때로는 최고의 두 가지 설계 원칙이 KISS *와 YAGNI **입니다. 알려진 모든 디자인 패턴을 "Hello world!"를 인쇄하는 프로그램에 넣을 필요는 없습니다.

 * Keep It Simple, Stupid
 ** You Ain't Gonna Need It

질문 업데이트 후 편집 (및 Pieter B의 내용을 어느 정도 반영) :

때로는 아키텍처 결정을 일찍 수행하여 구현하려고 할 때 모든 종류의 추악함을 유발하는 특정 디자인으로 이어집니다. 불행히도 그 시점에서 "적절한"솔루션은 뒤로 물러서서 어떻게 그 위치에 도달했는지를 해결하는 것입니다. 아직 답을 볼 수 없다면, 답을 찾을 때까지 계속 물러서십시오.

그러나 그 일이 비례하지 않으면 문제에 대한 추악한 해결책을 찾기 위해서는 실용적인 결정이 필요합니다.


편집 에서이 중 일부를 정리했지만 일반적으로 사용 가능한 간단한 솔루션이없는 문제를 정확하게 언급하고 있습니다.
Jonathan

아 좋은 예, 물러나서 문제를 재평가하는 데 합의가있는 것 같습니다. 이것은 좋은 생각입니다.
Jonathan

1

이 상황에 처했을 때 가장 먼저하는 일은 중지입니다. 다른 문제로 전환하고 잠시 동안 작업합니다. 아마 한 시간, 아마 하루, 아마 더 많을 수도 있습니다. 그것은 항상 선택 사항은 아니지만 내 의식은 일에 작용하는 반면 내 의식적인 뇌는보다 생산적인 일을합니다. 결국 나는 신선한 눈으로 돌아와서 다시 시도합니다.

내가하는 또 다른 일은 나보다 똑똑한 사람에게 묻는 것입니다. 이는 Stack Exchange에 요청하거나, 주제에 대한 웹 기사를 읽거나,이 분야에 대해 더 많은 경험이있는 동료에게 요청하는 형식을 취할 수 있습니다. 종종 내가 옳은 접근법이라고 생각하는 방법은 내가하려는 일에 대해 완전히 틀린 것으로 판명되었습니다. 문제의 일부 측면을 잘못 묘사했으며 실제로 생각하는 패턴과 맞지 않습니다. 그런 일이 발생하면 다른 사람이 "이것이 더 좋아 보인다 ..."라고 말하게하는 것이 큰 도움이 될 수 있습니다.

위의 내용은 자백에 의한 디자인 또는 디버깅입니다. 동료에게 가서 "내가 겪고있는 문제를 말하고 내가 가진 해결책을 설명 할 것입니다. 각 접근법의 문제를 지적하고 다른 접근법을 제안합니다." " 내가 설명하는 것처럼 다른 사람이 말하기 전에 종종 다른 사람과 동등한 것처럼 보이는 한 경로가 실제로 원래 생각했던 것보다 훨씬 나쁘거나 나쁘다는 것을 깨닫기 시작합니다. 결과 대화는 그 인식을 강화하거나 내가 생각하지 않은 새로운 것을 지적 할 수 있습니다.

TL; DR : 휴식을 취하고 강요하지 말고 도움을 요청하십시오.

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