추상화 : 문제 해결과 일반적인 해결책 사이의 전쟁 [폐쇄]


33

프로그래머로서 저는 프로그램을 추상적이고 가능한 한 일반적으로 만들고 싶은 딜레마에 빠져 있습니다.

그렇게하면 일반적으로 코드를 재사용 할 수 있고 다시 발생할 수있는 문제에 대한보다 일반적인 해결책을 얻을 수 있습니다.

그런 다음 내 머리 속의이 목소리가 말합니다. 문제를 해결하기가 쉽지 않습니다! 왜 필요한 시간보다 더 많은 시간을 보내십니까?

우리는 모두 추상화가 오른쪽 어깨에 있고 Solve-it-stupid가 왼쪽에있는이 질문에 직면했습니다.

어느 것을 듣고 얼마나 자주? 이것에 대한 당신의 전략은 무엇입니까? 모든 것을 추상화해야합니까?


1
"추상적이고 일반적으로"는 일반적으로 프로그래머의 허브로 알려져 있습니다. 그러나 Murphy의 법칙으로 인해 다음 작업을 수행 할 때 필요한 적응 수준은 제공하지 않은 것입니다.
Matthieu M.

1
최고의 질문 중 하나!
탐색

1
당신은 항상 잘못 추측하므로 간단하게 알아 봅니다. 간단한 경우를 "충분히"확장하면 패턴이 보이기 시작합니다. 그때까지는하지 마십시오.

답변:


27

어느 것을 듣고 얼마나 자주?

반드시 추상화해야합니다.

예를 들어 Java에서는 인터페이스를 사용해야합니다. 그것들은 추상화입니다.

파이썬에는 인터페이스가없고, 오리 타이핑이 있으며, 높은 수준의 추상화가 필요하지 않습니다. 그래서 당신은하지 않습니다.

이것에 대한 당신의 전략은 무엇입니까?

세 번 썼을 때까지 추상화하지 마십시오.

한 번은-한 번은-한 번입니다. 그냥 해결하고 계속하십시오.

여기에 패턴이있을 수 있음을 두 번 나타냅니다. 또는 없을 수도 있습니다. 우연의 일치 일 수 있습니다.

세 번째는 패턴의 시작입니다. 이제 우연의 일치를 초월합니다. 이제 성공적으로 추상화 할 수 있습니다.

모든 것을 추상화해야합니까?

아니.

실제로, 올바른 종류의 추상화를하고 있다는 절대적인 증거가 될 때까지 어떤 것도 추상화해서는 안됩니다. "세 개의 반복 규칙"이 없으면 도움이되지 않는 방식으로 쓸데없이 추상화 된 내용을 작성하게됩니다.

그렇게하면 일반적으로 코드를 재사용 할 수 있습니다.

이것은 종종 잘못된 가정입니다. 추상화는 전혀 도움이되지 않을 수 있습니다. 잘못 할 수 있습니다. 따라서 반드시해야 할 때까지하지 마십시오.


1
"필요할 때까지 추상화하지 마십시오." -클래스, 메소드, 루프 또는 if 문을 사용하지 않는 것이 좋습니까? 이것들은 모두 추상화입니다. 당신이 그것에 대해 생각하면, 고급 언어로 작성된 코드는 당신이 그것을 좋아하든 아니든 매우 추상적입니다. 문제는 추상화할지 여부가 아닙니다. 사용할 추상화입니다.
Jason Baker

9
@Jason Baker : "클래스, 메소드, 루프 또는 if 문을 사용하지 마십시오." 그것은 그 질문에 관한 것이 아닌 것 같습니다. 디자인을 지나치게 강조하지 않으면 모든 프로그래밍이 불가능하다는 터무니없는 주장을하는 이유는 무엇입니까?
S.Lott

1
한 남자가 여자에게 백만 달러를 주겠다고 물어 보는 옛 농담이 생각납니다. 그녀가 '예'라고 말하면, 그녀는 그와 함께 5 달러를 자야하는지 묻습니다. 그녀가 "어떤 종류의 여자를 데려가?"라고 말할 때 응답은 "음, 우리는 당신이 섹스를 위해 누군가와 자게 될 것이라고 이미 설정했습니다. 이제 우리는 가격에 대해 흥정하고 있습니다." 내 요점은 결코 추상을 결정하지 않는 결정에 관한 것이 아니라는 것입니다. 추상화해야 할 부분과 선택할 추상화에 관한 것입니다. 순수한 어셈블리를 작성하지 않는 한 추상화를 보류하도록 선택할 수 없습니다.
Jason Baker

9
@Jason Baker : "순수한 어셈블리를 작성하지 않으면 추상화를 중단 할 수 없습니다." 어셈블리는 기계어에 대한 추상화입니다. 하드웨어 회로에 대한 추상화입니다. 처음에는 문제가되지 않은 답변을 너무 많이 읽지 마십시오. 문제는 개념이나 지적 도구로서 "추상"에 관한 것이 아닙니다. OO 설계 기법으로서의 추상화에 관한 것이 었습니다. 내 대답은 추상화가 불가능하다는 것이 아니었다. 그러나 "과도한 추상화"는 나쁘다.
S.Lott

1
@JasonBaker 누군가와 자고있는 전례없는 이유는 아닙니다. 아마도 당신은 "돈"을 생각하고 있었습니까?

19

아, 야니 가장 남용 된 프로그래밍 개념.

코드를 일반화하는 것과 추가 작업을하는 것에는 차이가 있습니다. 코드를 느슨하게 결합하고 다른 작업에 쉽게 적용 할 수 있도록 추가 시간을 소비해야합니까? 전혀. 불필요한 기능을 구현하는 데 시간을 소비해야합니까? 아직 코드를 작성하지 않은 다른 코드와 함께 코드를 작성하는 데 시간을 보내야합니까? 아니.

"가장 간단한 일을하라"는 말이있다. 문제는 사람들이 항상 단순 하고 쉽게 혼동한다는 것입니다 . 단순성이 작동합니다. 그러나 노력할 가치가 있습니다.

배 밖으로 갈 수 있습니까? 당연하지. 그러나 저의 경험은 "지금 해보자"라는 태도를 이미 갖고있는 회사가 거의 없다는 것입니다. 대부분의 회사는 미리 생각할 사람들이 더 필요합니다. 그렇지 않으면, 그들은 항상 아무것도 할 시간이없고, 모든 사람이 항상 서두르고, 아무것도 할 일이없는 자기 유지 문제를 겪게됩니다.

이런 식으로 생각하십시오 : 코드가 어떻게 든 다시 사용될 가능성이 높습니다. 그러나 당신은 그런 식으로 정확하게 예측하지 않을 것입니다. 따라서 코드를 깨끗하고 추상적이며 느슨하게 결합하십시오. 그러나 아직 존재하지 않는 특정 기능을 사용하여 코드를 작동시키지 마십시오. 알고 계시더라도 앞으로 존재할 것입니다.


사이 좋은 구별 simpleeasy!
Matthieu M.


"그러나 나의 경험은 소수의 회사라는 것"입니다. 흥미롭게도 학계에서는 그 반대가 사실 일 수 있습니다.
Steve Bennett

12

음절 :

  1. 일반성은 비싸다.

  2. 당신은 다른 사람들의 돈을 쓰고 있습니다.

  3. 그러므로 일반성의 비용은 이해 당사자들에게 정당화되어야한다.

당신이 경우 자신에게 물어 정말 당신은 단지 그것을 불필요하게 일반적인 솔루션을 만들기 위해 지적 도전을 발견하면 나중에 이해 관계자의 비용을 절감하거나하기 위해 더 일반적인 문제를 해결.

일반성이 바람직한 것으로 판단되면 다른 기능과 마찬가지로 설계하고 테스트해야합니다 . 구현 한 일반성이 사양에 필요한 문제를 해결하는 방법을 보여주는 테스트를 작성할 수 없다면 그렇게하지 마십시오! 설계 기준을 충족하지 않고 테스트 할 수없는 기능은 아무도 신뢰할 수없는 기능입니다.

그리고 마지막으로, "가능한 한 일반적인 것"은 없습니다. 인수를 위해 C #으로 소프트웨어를 작성한다고 가정하십시오. 모든 클래스가 인터페이스를 구현하게 하시겠습니까? 모든 클래스마다 추상 메소드가있는 추상 기본 클래스? 그것은 일반적인 일이지만 "가능한 한 일반적인 것"근처에는 없습니다. 이를 통해 사람들은 서브 클래 싱을 통해 모든 메소드의 구현을 변경할 수 있습니다. 서브 클래 싱없이 메소드 구현을 변경하려면 어떻게해야합니까? 사람들이 모든 메소드를 다른 것으로 변경할 수 있도록 세터를 사용하여 실제로 모든 메소드를 대리자 유형의 속성으로 만들 수 있습니다. 그러나 누군가 더 많은 메소드를 추가하려면 어떻게해야합니까? 이제 모든 객체를 확장 할 수 있어야합니다.

이 시점에서 C #을 포기하고 JavaScript를 채택해야합니다. 그러나 당신은 여전히 ​​일반적으로 충분히 얻지 못했습니다. 누군가이 특정 개체에 대한 멤버 조회 작동 방식을 변경하려면 어떻게해야합니까? 어쩌면 파이썬으로 모든 것을 작성해야 할 수도 있습니다.

일반성을 높이는 것은 구현 된 일반성이 실제 사용자 요구를 충족시키는 데 실제로 성공할 수 있도록 예측 가능성을 포기하고 테스트 비용을 크게 증가시키는 것을 의미합니다 . 그 비용 은 비용을 지불하는 이해 관계자에게 이익 으로 정당화 되는가? 아마도 그들은; 이해 관계자와 논의하는 것은 당신에게 달려 있습니다. 내 이해 관계자는 전혀 불필요하고 매우 비싼 수준의 일반성을 추구하면서 정적 타이핑을 기꺼이 포기하지 않지만 아마도 귀하의 것입니다.


2
유용한 원칙은 +1, 돈에 대해서는 -1입니다.
메이슨 휠러

4
@Mason : 에 관한 것이 아니라 노력 에 관한 것 입니다. 돈은 노력의 실질적인 척도입니다 . 효율성은 생산 된 노력마다 발생하는 이점입니다. 다시 말하지만 돈의 이윤은 실질적인 이익의 척도이다 . 노력, 비용 및 이익을 측정하는 방법을 찾는 것보다 돈의 추상화에 대해 논의하는 것이 더 쉽습니다. 다른 방법으로 노력, 비용 및 이익을 측정하고 싶습니까? 더 나은 방법을 제안 해 주시기 바랍니다.
Eric Lippert

2
@Mason Wheeler의 의견에 동의합니다. 여기서 해결책은 프로젝트의 해당 수준에 이해 관계자를 참여시키지 않는 것입니다. 분명히 업계에 크게 의존하지만 클라이언트는 일반적으로 코드를 보지 않습니다. 또한이 모든 대답은 노력을 기울이지 않고 게으른 것처럼 보입니다.
Orbling

2
@Orbling : 가치 있고 중요한 프로젝트에서 자원을 빼앗아가는 불필요하고 비싸고 낭비적인 노력에 강력히 반대합니다. 이것이 "게으른"것이라고 제안하는 경우, 나는 당신이 비정상적인 방식으로 "게으른"이라는 단어를 사용하고 있다고 제출합니다.
Eric Lippert

1
내 경험상 다른 프로젝트는 사라지지 않는 경향이 있으므로 일반적으로 진행하기 전에 현재 프로젝트에 필요한 시간을 투자 할 가치가 있습니다.
Orbling

5

명확하게하기 위해, 일반화 된 것을 만들고 추상화를 구현하는 것은 완전히 다른 두 가지입니다.

예를 들어, 메모리를 복사하는 기능을 고려하십시오.

이 함수는 4 바이트가 복사되는 방식을 숨기는 추상화입니다.

int copy4Bytes (char * pSrc, char * pDest)

일반화는이 함수가 임의의 바이트 수를 복사하게합니다.

int copyBytes (char * pSrc, char * pDest, int numBytesToCopy)

추상화는 재사용하기에 적합하지만 일반화는 추상화를 더 유용한 경우로 만듭니다.

더 구체적으로 귀하의 질문과 관련하여 추상화는 코드 재사용 관점에서만 유용하지 않습니다. 종종 올바르게 수행되면 코드를 더 읽기 쉽고 유지 보수하기가 쉽습니다. 위의 예제를 사용하면 코드 copyBytes ()를 통해 스키밍하거나 한 번에 한 인덱스 씩 데이터를 이동하는 배열을 반복하는 for 루프를 읽고 이해하는 것이 더 쉬운 방법은 무엇입니까? 추상화는 코드를 다루기 쉽게 만드는 일종의 자체 문서를 제공 할 수 있습니다.

내 자신의 경험의 규칙으로, 내가 의도하는 코드를 정확히 설명하는 좋은 함수 이름을 생각해 낼 수 있다면 다시 사용할지 여부에 관계없이 함수를 작성합니다.


추상화와 일반화의 차이를 만들기위한 +1
Joris Meys

4

이런 종류의 일반적인 규칙은 Zero, One, Infinity입니다. 즉, 작성하는 내용이 두 번 이상 필요한 경우 더 많은 시간이 필요하다고 일반화 할 수 있습니다. 이 규칙은 처음으로 무언가를 작성할 때 추상화를 방해하지 않음을 의미합니다.

이 규칙의 또 다른 좋은 이유는 코드를 처음 작성할 때 예제가 하나 밖에 없기 때문에 추상화해야 할 사항을 알 필요가 없기 때문입니다. 머피의 법칙은 처음 추상 코드를 작성하면 두 번째 예에는 예상치 못한 차이가 있음을 의미합니다.


1
리팩토링 규칙 : 스트라이크 2! 리팩터링!
Frank Shearar

@ 프랭크 : 아마도 당신의 리팩토링 규칙 일 것입니다. 그러나 두 번째 단락은 개인적인 경험에서 추가되었습니다.
Larry Coleman

+1 : 나는 이것이 Pragmatic Programmer에서 거의 그대로 IIRC로 상당히 일찍 언급되었다고 생각합니다 .
Steven Evers

아 그래. 하나의 예제만으로는 추상화 할 것이 없습니다. 두 번째 예제를 보자 마자 공통적 인 (공유 된) 것과 그렇지 않은 것을 볼 수 있으며 추상화 할 수 있습니다!
Frank Shearar

2의 샘플은 무한대로 일반화하기에는 너무 작습니다. 다시 말해서, 너무 일찍.

2

에릭 리퍼 트 ​​(Eric Lippert)는 앞으로 자신의 기사 에서 디자인을 교정하는 데 적용 할 세 가지 사항을 지적합니다 . 나는 당신이 그것을 따르는 경우에 당신은 좋은 모양 일 것이라고 생각합니다.

첫째 : 조기 일반성은 비싸다.

둘째 : 항상 문제 영역에 있고 클래스 관계가 변하지 않는 것들만 모델에 나타냅니다.

셋째 : 정책을 메커니즘에서 멀리하십시오.


1

코딩하는 이유, 프로젝트의 목적에 따라 다릅니다. 코드의 가치가 구체적인 문제를 해결한다면, 그 문제를 해결하고 다음 문제로 넘어 가기를 원합니다. 향후 코드 사용자 (자신 포함)가 더 쉽게 할 수있는 빠르고 쉬운 일이 있다면, 합리적인 편의를 제공하십시오.

반면에 작성하는 코드가보다 일반적인 목적으로 사용되는 경우가 있습니다. 예를 들어, 다른 프로그래머를 위해 라이브러리를 작성하는 경우 다양한 응용 프로그램에서 라이브러리를 사용하게됩니다. 잠재적 인 사용자를 알 수 없으므로 원하는 것을 정확하게 요청할 수 없습니다. 그러나 라이브러리를 광범위하게 유용하게 만들고 싶습니다. 그러한 경우 일반적인 솔루션을 지원하기 위해 더 많은 시간을 할애했습니다.


0

나는 KISS 원칙을 좋아합니다.

나는 최선의 해결책이 아니라 내가 요청한 것을 제공하는 데 중점을 둡니다. 내가 비참하게 만들었 기 때문에 나는 완벽주의 (그리고 OCD)를 놓아야했다.


완벽주의를 싫어하는 이유는 무엇입니까? (나는 당신을 투표하지 않았다)
Orbling

완벽을 목표로하지 않는 것이 저에게 효과적입니다. 왜? 내 프로그램이 절대 완벽하지 않다는 것을 알고 있기 때문입니다. 완벽에 대한 표준 정의는 없으므로 잘 작동하는 것을 제공하기로 선택합니다.
Pablo

-1

어디 추상화가 오른쪽 어깨에 있고 해결 -이 - 바보 왼쪽에 앉아있다.

나는 동의하지 않는다 "바보 해결" 내가 더 할 수 있다고 생각, "이 스마트 해결" .

더 똑똑한 것 :

  • 여러 사례를 지원할 수있는 복잡한 일반화 된 솔루션 작성
  • 로 해결할 손에서 문제 및 유지 관리가 쉽다는 것을 짧고 effecient 코드를 작성하고, 이는 수확장 미래에 IF 가 필요합니다.

기본 선택은 두 번째 선택입니다. 세대에 대한 필요성을 입증 할 수 없다면.

일반화 된 솔루션은 여러 다른 프로젝트 / 사례에서 사용될 솔루션이라는 것을 알고있을 때만 사용해야합니다.

일반적으로 일반화 된 솔루션이 "핵심 라이브러리 코드" 로 가장 적합하다는 것을 알았습니다.


여기서 모든 가정을 할 수 있다면 아무런 문제가 없을 것입니다. 짧고 유지 관리가 쉬운 것은 상호 배타적입니다. 무언가가 재사용 될 것이라는 것을 알고 있다면, 일반적인 해결책이이를 해결할 것입니다.
JeffO


컨텍스트에서 "Solve it Stupid"를 제거했습니다.
Bryan Harrington
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.