코드를 보면 API가 무엇을하고 있는지 항상 알아야합니까?


20

최근에 저는 자체 API를 개발하고 있으며 API 디자인에 대한 관심을 바탕으로 API 디자인을 개선 할 수있는 방법에 관심이있었습니다.

몇 번 등장한 한 가지 측면은 (API 사용자가 아니라 주제에 대한 관찰 토론에서) : API를 호출하는 코드를보고 수행하는 작업을 확인하는 것만으로도 알 수 있습니다 .

예를 들어 담론 리포지토리에 대한 GitHub에 대한 다음 토론을 참조하십시오 .

foo.update_pinned(true, true);

매개 변수 이름, 문서 등을 알지 않고 코드를 살펴보면 수행 할 작업을 추측 할 수 없습니다. 두 번째 인수는 무엇을 의미합니까? 제안 된 개선 사항은 다음과 같습니다.

foo.pin()
foo.unpin()
foo.pin_globally()

그리고 그것은 일을 정리합니다 (두 번째 인수는 전 세계적으로 foo를 고정시킬 것인지, 나는 추측하고 있습니다).이 경우 나중에 나중에 확실히 개선 될 것이라는 데 동의합니다.

그러나 나는 코드를 보아서 무엇을하고 있는지 알지 못하더라도 서로 다르지만 논리적으로 관련된 상태를 설정하는 메소드가 별도의 메소드가 아닌 하나의 메소드 호출로 더 잘 노출 될 수 있다고 생각합니다 . (따라서 매개 변수 이름과 설명서를 살펴보아야합니다. API에 익숙하지 않은 경우 항상 개인적으로 중요합니다.)

예를 들어 FalconPeerSetVisibility(bool, string, bool) 에서 한 가지 방법 을 노출 하고 다음 줄을 보면 인정합니다.

falconPeer.SetVisibility(true, "aerw3", true);

당신은 그것이 무엇을하고 있는지 전혀 모른다. falconPeer논리적 의미에서 "가시성"을 제어하는 ​​세 가지 다른 값을 설정 합니다. 비밀번호 만 사용하여 결합 요청을 수락하고 발견 요청에 응답합니다. 이것을 3 개의 메소드 호출로 나누면 API 사용자는 "가시성"의 한 측면을 설정하게되어 "가시성"의 모든 측면을 설정하기 위해 한 가지 방법 만 노출시킴으로써 생각해야하는 다른 것을 설정하는 것을 잊어 버릴 수 있습니다 . 또한 사용자가 한 측면을 변경하려고 할 때 거의 항상 다른 측면을 변경하기를 원하며 이제는 한 번의 호출로 변경할 수 있습니다.


13
이것이 바로 일부 언어에 매개 변수 이름이 지정된 이유입니다 (때때로 명명 된 매개 변수 도 적용됨 ). 예를 들어 간단한 update방법 으로 많은 설정을 그룹화 할 수 foo.update(pinned=true, globally=true)있습니다. 또는 : foo.update_pinned(true, globally=true). 따라서 질문에 대한 답변은 언어 기능도 고려해야합니다. 언어 X에 대한 좋은 API는 언어 Y에 적합하지 않으며 그 반대도 마찬가지입니다.
Bakuriu

합의-부울 사용을 중단하자 :)
Ven


@Bakuriu C조차도 변장 된 정수라도 열거 형을 가지고 있습니다. 부울이 좋은 API 디자인 인 실제 언어는 없다고 생각합니다.
Doval

1
@Doval 나는 당신이 말하려는 것을 얻지 못합니다. OP가 사용했기 때문에 그 상황에서 부울을 사용했지만 내 요점은 전달 된 값과 완전히 관련이 없습니다. 예를 들어 : 또는 setSize(10, 20)처럼 읽을 수 없습니다 . 강제 명명 된 매개 변수가있는 언어에서 부울은 열거 형 / 명명 된 상수를 사용하는 것과 정확히 같은 양의 정보를 전달할 있으므로 API에 적합 할 있습니다. setSize(width=10, height=20)random(distribution='gaussian', mean=0.5, deviation=1)
Bakuriu

답변:


27

세 가지 메소드 호출로 나누지 않으려는 욕구는 완전히 이해할 수 있지만 부울 매개 변수 외에도 다른 옵션이 있습니다.

열거 형을 사용할 수 있습니다.

falconPeer.SetVisibility(JoinRequestOptions.Accept, "aerw3", DiscoveryRequestOptions.Reply);

또는 플래그 열거 형 (언어가 지원하는 경우) :

falconPeer.SetVisibility(VisibilityOptions.AcceptJoinRequests | VisibilityOptions.ReplyToDiscoveryRequests, "aerw3");

또는 Parameter Object를 사용할 수 있습니다 .

var options = new VisibilityOptions();
options.AcceptJoinRequests = true;
options.ReplyToDiscoveryRequest = true;
options.Password="aerw3";
falconPeer.SetVisibility(options);

Parameter Object 패턴은 도움이 될만한 몇 가지 다른 이점을 제공합니다. 매개 변수 집합을 쉽게 전달하고 직렬화 할 수 있으며 지정되지 않은 매개 변수에 "default"값을 쉽게 지정할 수 있습니다.

또는 부울 매개 변수를 사용할 수 있습니다. Microsoft는 .NET Framework API를 사용하여 항상 그렇게하는 것처럼 보이므로 "충분히 좋다면 나에게 충분합니다."


매개 변수 객체 패턴에는 여전히 OP가 언급 한 문제가 있습니다. " 이를 3 개의 메소드 호출로 분리하면 API 사용자가"가시성 "의 한 측면을 설정하여 다른 것을 설정하는 것을 잊을 수 있습니다 ".
Lode

사실, 그것이 상황을 더 좋게 만든다고 생각합니다 (완벽하지 않은 경우). 사용자가 VisibilityOptions 객체를 인스턴스화하고 전달해야하는 경우 VisibilityOptions 객체에 설정하려는 다른 속성이 있음을 알 수 있습니다. 세 가지 메소드 호출 접근 방식을 사용하면 호출하는 메소드에 대한 주석 만 상기시킵니다.
BenM

6

분명히 규칙에는 예외가 있지만, 스스로 잘 설명했듯이 읽을 수있는 API를 사용하면 특정 이점이 있습니다. 부울 인수는 1) 의도를 밝히지 않고 2) 부울 플래그에 따라 다른 일이 발생하기 때문에 실제로 두 개가 있어야하는 함수를 호출 함을 의미하므로 귀찮습니다.

주요 질문은 오히려 : API를 더 읽기 쉽게하기 위해 얼마나 많은 노력을 기울이고 싶은가? 외향이 많을수록 더 많은 노력을 쉽게 정당화 할 수 있습니다. 다른 하나의 장치에서만 사용되는 API라면 그렇게 큰 문제는 아닙니다. 전 세계가 잃게 할 REST API에 대해 이야기하고 있다면 이해하기 쉽도록 더 많은 노력을 기울일 수 있습니다.

귀하의 예를 들어, 간단한 해결책이 있습니다 : 분명히, 귀하의 경우 가시성은 사실이거나 거짓된 것이 아닙니다. 대신, "가시성"으로 간주되는 모든 것들이 있습니다. 하나의 해결책은 Visibility이러한 모든 종류의 가시성을 다루는 클래스 와 같은 것을 소개하는 것 입니다. 이를 작성하기 위해 빌더 패턴을 추가로 적용하면 다음과 같은 코드가 생길 수 있습니다.

Visibility visibility = Visibility.builder()
  .acceptJoinRequests()
  .withPassword("aerw3")
  .replyToDiscoveryRequests()
  .build();
falconPeer.setVisibility(visibility);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.