최소 놀랍게도 (POLA)와 인터페이스의 원리


17

1 세기 전 C ++을 배울 때 인터페이스는 용서해야하며, 소비자가 소스 나 문서 대신 소스 나 문서에 액세스 할 수 없기 때문에 메소드가 호출 된 순서를 신경 쓰지 않아야한다는 점을 배웠다. 이.

그러나 내가 멘토링 할 때마다 프로그래머 나 고위 개발자들이 저를 듣게 될 때마다 놀랍게 반응하여 이것이 실제로 일인지 아니면 막 유행한지 궁금해졌습니다.

진흙만큼 맑습니까?

데이터 파일 작성을 위해 다음 메소드가있는 인터페이스를 고려하십시오.

OpenFile
SetHeaderString
WriteDataLine
SetTrailerString
CloseFile

이제 이것들을 순서대로 진행할 수는 있지만 파일 이름 (생각 a.out)이나 포함 된 헤더 및 트레일러 문자열에 신경 쓰지 않았다고 하면 호출 할 수 있습니다 AddDataLine.

덜 극단적 인 예는 헤더와 트레일러를 생략하는 것일 수 있습니다.

또 다른 파일은 파일을 열기 전에 헤더와 트레일러 문자열을 설정하는 것일 수 있습니다.

이것이 인터페이스 설계의 원칙입니까, 아니면 이름이 부여되기 전에 POLA 방식으로 인식됩니까?

NB는이 인터페이스의 축소에 얽매이지 않고이 질문을위한 예 일뿐입니다.


10
"가장 놀랍다"원리는 "응용 프로그램 프로그래머 인터페이스"디자인보다 사용자 인터페이스 디자인 에서 훨씬 더 널리 퍼져 있습니다. 그 이유는 웹 사이트 나 프로그램의 사용자가 읽을 것으로 예상 할 수 없다는 것입니다 어떤 프로그래머가 예상되는 동안 적어도 원칙적으로, 사용하기 전에 모든에서 지침을 그들과 함께 프로그래밍하기 전에 API의 문서를 읽을 수 있습니다.
Kilian Foth


7
@KilianFoth : 나는 Wikipedia가 이것에 대해 틀렸다고 확신한다-POLA는 사용자 인터페이스 디자인에 관한 것이 아니라 "최소한 놀람의 원리"라는 용어는 Bob Martin에 의해 그의 기능과 클래스 디자인에 사용된다. "클린 코드"책.
Doc Brown

2
어쨌든 불변의 인터페이스가 더 좋습니다. 생성시 설정하려는 모든 데이터를 지정할 수 있습니다. 모호한 부분이없고 수업이 더 간단 해집니다. (때로는이 계획은 가능하지 않습니다.)
usr

4
POLA가 API에 적용되지 않는 것에 대해서는 완전히 동의하지 않습니다. 인간이 다른 인간을 위해 만드는 모든 것에 적용됩니다. 예상대로 작동하면 개념화가 쉬워지고 인지력이 낮아져 사람들이 적은 노력으로 더 많은 일을 할 수 있습니다.
로봇 고트

답변:


25

가장 놀랍게도하는 원칙을 고수 할 수있는 한 가지 방법은 ISPSRP 또는 DRY 와 같은 다른 원칙을 고려하는 것 입니다.

당신이 제시 한 특정 예제에서, 파일을 조작하기위한 순서에 대한 의존성이 존재하는 것으로 보인다; 그러나 API는 파일 액세스와 데이터 형식을 모두 제어하므로 SRP 위반과 같은 냄새가납니다.

편집 / 업데이트 : 또한 API 자체가 사용자에게 API를 사용할 때마다 동일한 단계를 반복해야하므로 DRY를 위반하도록 요청하고 있음을 나타 냅니다.

IO 작업이 데이터 작업과 별 개인 대체 API를 고려하십시오. API 자체가 주문을 '소유'하는 경우 :

ContentBuilder

SetHeader( ... )
AddLine( ... )
SetTrailer ( ... )

FileWriter

Open(filename) 
Write(content) throws InvalidContentException
Close()

위의 분리를 통해 ContentBuilder실제로 라인 / 헤더 / 트레일러를 저장하는 것 외에는 아무것도 할 필요가 없습니다 ( ContentBuilder.Serialize()주문을 아는 방법 일 수도 있습니다 ). 다른 SOLID 원칙을 따르면 행을 추가하기 전이나 후에 헤더 나 트레일러를 설정할지 여부가 더 이상 중요하지 않습니다 .에 ContentBuilder전달 될 때까지 실제로 파일에 아무것도 기록 되지 않기 때문 FileWriter.Write입니다.

또한 좀 더 유연하다는 이점이 있습니다. 예를 들어, 진단 로거에 내용을 쓰거나 파일에 직접 쓰지 않고 네트워크를 통해 전달하는 것이 유용 할 수 있습니다.

API를 디자인하는 동안 상태, 반환 값, 예외, 콜백 또는 기타 오류에 대한 오류보고도 고려해야합니다. API 사용자는 계약 위반 또는 파일 I / O 오류와 같이 제어 할 수없는 기타 오류를 프로그래밍 방식으로 감지 할 수있을 것으로 예상합니다.


정확히 내가 찾던 것-감사합니다! ISP 기사에서 : "(ISP)는 클라이언트가 사용하지 않는 방법에 의존해서는 안된다고 말합니다"
Robbie Dee

5
그럼에도 불구하고 이것은 잘못된 대답은 아니지만 여전히 컨텐츠 빌더는 호출 순서 SetHeader또는 AddLine중요한 방식으로 구현 될 수 있습니다 . 이 순서 의존성을 제거하는 것은 ISP 나 SRP가 아니며 단순히 POLA입니다.
Doc Brown

주문이 중요한 경우, 후속 단계를 수행하려면 이전 단계에서 리턴 된 값이 필요하므로 유형 시스템에 순서를 적용하도록 조작을 정의하여 POLA를 여전히 충족시킬 수 있습니다. FileWriter그런 다음 메소드 의 마지막 ContentBuilder단계에서 값을 요구하여 Write모든 입력 컨텐츠가 완료되어 InvalidContentException불필요한 것을 방지 할 수 있습니다.
Dan Lyons

@ DanLyons 나는 그것이 asker가 피하려고하는 상황에 오히려 가깝다고 느낀다. 를 Where 사용자 는 API의 요구가 알거나 순서 걱정합니다. 이상적으로 API 자체는 주문을 시행해야하며, 그렇지 않으면 사용자에게 DRY를 위반하도록 요구합니다. 즉 밖으로 분할에 대한 이유 ContentBuilder및 수 FileWriter.Write지식의 비트를 캡슐화 할 수 있습니다. 콘텐츠에 문제가있는 경우 (예 : 누락 된 헤더) 예외가 필요합니다. 반환도 가능하지만 예외를 반환 코드로 바꾸는 팬은 아닙니다.
Ben Cottrell

그러나 DRY에 대한 메모를 추가하고 답변에 주문하는 것이 좋습니다.
Ben Cottrell

12

이것은 POLA뿐만 아니라 버그의 원인으로 유효하지 않은 상태를 방지하는 것입니다.

구체적인 구현을 제공하지 않고 예제에 몇 가지 제약을 제공하는 방법을 살펴 보겠습니다.

첫 번째 단계 : 파일을 열기 전에는 아무것도 호출하지 마십시오.

CreateDataFileInterface
  + OpenFile(filename : string) : DataFileInterface

DataFileInterface
  + SetHeaderString(header : string) : void
  + WriteDataLine(data : string) : void
  + SetTrailerString(trailer : string) : void
  + Close() : void

이제 실제 데이터를 쓸 수 CreateDataFileInterface.OpenFile있는 DataFileInterface인스턴스 를 검색하기 위해 호출해야합니다 .

두 번째 단계 : 헤더와 트레일러가 항상 설정되어 있는지 확인하십시오.

CreateDataFileInterface
  + OpenFile(filename : string, header: string, trailer : string) : DataFileInterface

DataFileInterface
  + WriteDataLine(data : string) : void
  + Close() : void

이제 DataFileInterface파일 이름, 헤더 및 트레일러 를 얻기 위해 모든 필수 매개 변수를 미리 제공해야합니다 . 모든 줄을 쓸 때까지 트레일러 문자열을 사용할 수없는 경우 트레일러 문자열 없이는 파일을 완료 할 수 없도록 이 매개 변수를 Close()(메서드의 이름을 바꿀 수 있음)으로 이동할 수도 있습니다 WriteTrailerAndClose().


댓글에 답장하려면 :

나는 인터페이스의 분리를 좋아한다. 그러나 집행에 대한 귀하의 제안 (예 : WriteTrailerAndClose ())이 SRP 위반에 대한 판단이라고 생각합니다. (이것은 여러 차례에 걸쳐 어려움을 겪었지만, 귀하의 제안은 가능한 예인 것 같습니다.) 어떻게 대답 하시겠습니까?

진실. 내 주장을하는 데 필요한 것보다 더 많은 예에 집중하고 싶지는 않지만 좋은 질문입니다. 이 경우 나는 그것을 부르고 그것이 Finalize(trailer)그렇게 많이하지 않는다고 주장합니다. 트레일러 작성 및 마감은 단순한 구현 세부 사항입니다. 그러나 의견이 다르거 나 다른 상황이 비슷한 경우 가능한 해결책은 다음과 같습니다.

CreateDataFileInterface
  + OpenFile(filename : string, header : string) : IncompleteDataFileInterface

IncompleteDataFileInterface
  + WriteDataLine(data : string) : void
  + FinalizeWithTrailer(trailer : string) : CompleteDataFileInterface

CompleteDataFileInterface
  + Close()

이 예제에서는 실제로는하지 않지만 결과적으로 기술을 수행하는 방법을 보여줍니다.

그건 그렇고, 많은 행을 순차적으로 쓰는 것과 같이 메소드를 실제로이 순서대로 호출해야한다고 가정했습니다. 이것이 필요하지 않은 경우 Ben Cottrel이 제안한대로 항상 빌더를 선호합니다 .


1
당신은 슬프게도 함정에 빠졌습니다. 파일 이름은 필요하지 않습니다. 헤더와 예고편도 아닙니다. 그러나 인터페이스 분할의 일반적인 주제는 좋은 것이므로 +1 :-)
Robbie Dee

오, 나는 당신을 오해했다. 이것은 구현이 아니라 사용자의 의도를 설명하는 것이라고 생각했다.
Fabian Schmengler

나는 인터페이스의 분리를 좋아한다. 그러나 집행에 대한 귀하의 제안 (예 WriteTrailerAndClose():)이 SRP 위반에 대한 판단이라고 생각합니다 . (이것은 여러 차례에 걸쳐 어려움을 겪었지만, 귀하의 제안은 가능한 예인 것 같습니다.) 어떻게 대답 하시겠습니까?
kmote

1
@kmote 답변이 너무 길어서 댓글을
달지 못했습니다.

1
파일 이름이 선택적인 경우 OpenFile필요하지 않은 오버로드를 제공 할 수 있습니다 .
5gon12eder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.