API 디자인 : 구체적 vs 추상 접근-모범 사례?


25

시스템 간 (비즈니스 레벨에서) API를 논의 할 때, 우리 팀에는 종종 두 가지 관점이 있습니다. 어떤 사람들은 일반적인 추상 접근 방식을 선호하고 다른 하나는 "구체적인"접근 방식을 선호합니다 .

예 : 간단한 "개인 검색"API 설계. 구체적인 버전은

 searchPerson(String name, boolean soundEx,
              String firstName, boolean soundEx,
              String dateOfBirth)

구체적인 버전을 선호하는 사람들은 다음과 같이 말합니다.

  • API는 자체 문서화입니다
  • 이해하기 쉽다
  • 검증하기 쉽다 (컴파일러 또는 웹 서비스 : 스키마 검증)
  • 키스

우리 팀의 다른 사람들은 "그건 검색 기준의 목록 일뿐"이라고 말합니다.

searchPerson(List<SearchCriteria> criteria)

SearchCritera {
  String parameter,
  String value,
  Map<String, String> options
}

아마도 열거 형의 "매개 변수"를 만들 수 있습니다.

지지자들은 다음과 같이 말합니다.

  • API를 변경하지 않으면 (예 : 더 많은 기준이나 옵션 추가) 구현이 변경 될 수 있습니다. 배포시 이러한 변경 내용을 동기화하지 않아도됩니다.
  • 구체적인 변형에서도 문서화가 필요합니다
  • 스키마 유효성 검사가 과대 평가되었습니다. 종종 추가 유효성 검사를 수행해야합니다. 스키마는 모든 사례를 처리 할 수 ​​없습니다.
  • 우리는 이미 다른 시스템과 비슷한 API를 가지고 있습니다-재사용

반론은

  • 유효한 매개 변수 및 유효한 매개 변수 조합에 대한 많은 문서
  • 다른 팀에서는 이해하기 어렵 기 때문에 더 많은 의사 소통 노력

모범 사례가 있습니까? 문학?


3
반복 된 "문자열 이름 / 이름, 부울 soundEx"는 명백한 dry 위반이며이 디자인은 이름이 soundEx와 함께 진행될 것이라는 사실을 해결하지 못했음을 나타냅니다. 이와 같은 단순한 설계 실수에 직면하여보다 정교한 분석을 진행하기가 어렵다고 생각합니다.
gnat

"콘크리트"의 반대는 "일반적인"것이 아니라 "추상적 인"입니다. 추상화는 라이브러리 나 API에 매우 중요하며,이 논의는 진정으로 근본적인 질문을하지 않고 오히려 솔직한 스타일에 관한 문제를 고치지 않습니다. 옵션 B에 대한 반론 인 FWIW는 FUD의 부하처럼 들리므로 API 설계가 반쯤 깨끗하고 SOLID 원칙을 따르는 경우 추가 문서 나 통신이 필요하지 않습니다.
Aaronaught

@Aaronaught 지적 해 주셔서 감사합니다 ( "추상"). 독일어 사운드의 "generisch"는 여전히 번역 문제 일 수 있습니다. 당신에게 "정말 근본적인 질문"은 무엇입니까?
erik

4
@Aaronaught : 문제는 초록에 관한 것이 아닙니다. 올바른 수정은 "일반"의 반대가 "콘크리트"가 아니라 "특정"이라는 것입니다.
Jan Hudec

이것에 대한 또 다른 투표는 일반 대 추상이 아니라 일반 대 특정입니다. 위의 "콘크리트"예제는 실제로 이름 firstName 및 dateOfBirth에 고유하며 다른 예제는 모든 매개 변수에 일반적입니다. 특히 추상적 인 것도 아닙니다. 제목을 편집했지만 편집 전쟁을 시작하고 싶지 않습니다 :-)
matt freake

답변:


18

그것은 당신이 말하는 필드의 수와 사용 방법에 달려 있습니다. 필드는 몇 개의 필드 만있는 고도로 구조화 된 쿼리에 적합하지만 쿼리가 매우 자유로운 형식 인 경우에는 3 ~ 4 개가 넘는 필드에서 콘크리트 접근 방식이 빠르게 다루기 어려워집니다.

반면에 일반 API를 순수하게 유지하는 것은 매우 어렵습니다. 많은 곳에서 간단한 이름 검색을 수행하면 누군가가 동일한 5 줄의 코드를 반복하는 것에 지칠 줄 아는 사람들이 그것을 함수로 감쌀 것입니다. 이러한 API는 가장 일반적으로 사용되는 쿼리에 대한 구체적인 래퍼와 함께 일반 쿼리의 하이브리드로 변하지 않습니다. 그리고 나는 그것에 아무런 문제가 없습니다. 그것은 당신에게 두 세계의 최고를 제공합니다.


7

좋은 API를 디자인하는 것은 예술입니다. 시간이 지나도 좋은 API가 인정됩니다. 제 생각에는 추상 콘크리트 라인에 일반적인 편견이 없어야합니다. 일부 매개 변수는 요일과 같이 구체적 일 수 있으며, 일부 매개 변수는 확장 성을 위해 설계되어야하며 (예를 들어 함수 이름의 일부를 구체적으로 작성하는 것은 매우 어리 석습니다), 다른 매개 변수는 더 나아가서 우아하게하기 위해 더 진행될 수 있습니다. API는 콜백을 제공하거나 도메인 특정 언어를 제공하여 복잡성을 방지하는 데 도움이됩니다.

달 아래에 거의 새로운 일이 일어나지 않습니다. 기존 기술, 특히 확립 된 표준 및 형식을 살펴보십시오 (예 : 피드 후에 모델링 할 수있는 많은 것들, 이벤트 설명은 ical / vcal로 정교화 됨). 빈번하고 다양한 개체가 구체적이고 계획된 확장이 사전 인 경우 API를 쉽게 추가 할 수 있습니다. 특정 상황을 처리하기 위해 잘 설정된 패턴도 있습니다. 예를 들어, HTTP 요청 (및 유사) 처리는 요청 및 응답 오브젝트를 사용하여 API에서 모델링 될 수 있습니다.

API를 디자인하기 전에 포함되지는 않지만 알아야 할 사항을 포함하여 측면을 브레인 스토밍하십시오. 그러한 예로는 언어, 쓰기 방향, 인코딩, 로캘, 시간대 정보 등이 있습니다. 배수가 나타날 수있는 곳에주의하십시오. 단일 값이 아닌 목록을 사용하십시오. 예를 들어, 비디오 채팅 시스템 용 API를 삭제하는 경우 현재 참가자의 사양이 그런 경우에도 두 명의 참가자가 아니라 N 명의 참가자를 가정하면 API가 훨씬 유용합니다.

때로는 추상적이기 때문에 복잡성을 크게 줄이는 데 도움이됩니다. 3 + 4, 2 + 2 및 7 + 6 만 추가하도록 계산기를 설계하더라도 X + Y를 구현하는 것이 훨씬 간단 할 수 있습니다 (X 및 Y이며 ADD_3_4 (), ADD_2_2 () 대신 ADD (X, Y)를 API에 포함합니다.

대체로 어떤 방법 으로든 선택하는 것은 기술적 인 세부 사항 일뿐입니다. 문서는 빈번한 사용 사례를 구체적으로 설명해야합니다.

데이터 구조 측면에서 무엇을 하든지 API 버전에 대한 필드를 제공하십시오.

요약하면 API는 소프트웨어를 다룰 때 복잡성을 최소화해야합니다. API를 이해하려면 노출 된 복잡성 수준이 적절해야합니다. API의 형태를 결정하는 것은 문제 영역의 안정성에 달려 있습니다. 따라서이 정보가 복잡성에 영향을 줄 수 있기 때문에 소프트웨어와 API가 어느 방향으로 커질 지에 대한 추정이 필요합니다. 또한 사람들이 이해할 수있는 API desing이 있습니다. 사용중인 소프트웨어 기술 영역에 좋은 전통이있는 경우 이해를 돕기 위해 많은 전통을 벗어나지 마십시오. 당신이 쓴 사람을 고려하십시오. 숙련 된 사용자는 일반 성과 유연성을 높이 평가하지만 경험이 적은 사용자는 콘크리트에 더 편할 수 있습니다. 그러나 API 사용자 대부분은

문학적인 측면에서 나는 "아름다운 법칙"을 이끌고있는 프로그래머들을 추천 할 수있다. 저자들은 Andy Oram, Greg Wilson은 아름다움이 숨겨진 최적 성 (그리고 어떤 목적에 대한 적합성)을 인식하는 것에 관한 것이라고 생각한다.


1

개인적 취향은 추상적이지만 회사의 정책은 나를 구체화시킵니다. 저에 대한 토론의 끝입니다 :)

두 가지 접근 방식에 대한 장단점을 모두 잘 작성했으며 파고 계속하면 양쪽에 유리한 주장을 많이 찾을 수 있습니다. API 아키텍처가 제대로 개발되어 있다면, 오늘날 사용되는 방법과 향후 어떻게 발전하고 성장할 수 있는지에 대한 생각을 갖게되었으므로 어느 쪽이든 괜찮을 것입니다.

반대 견해를 가진 두 개의 책갈피가 있습니다.

유리한 클래스

유리한 인터페이스

"API가 비즈니스 요구 사항을 충족합니까? 성공을위한 잘 정의 된 기준이 있습니까? 확장 할 수 있습니까?" 그것들은 따라야 할 간단한 모범 사례처럼 보이지만 솔직히 콘크리트보다 일반보다 훨씬 중요합니다.


1

추상 API가 반드시 검증하기가 더 어렵다고 말하지는 않습니다. 기준 매개 변수가 충분히 단순하고 서로 종속 관계가 거의없는 경우 매개 변수를 개별적으로 전달하든 배열로 전달하든 크게 차이가 없습니다. 여전히 모두 확인해야합니다. 그러나 이는 기준 매개 변수와 객체 자체의 디자인에 달려 있습니다.

API가 충분히 복잡하면 구체적인 메소드를 갖는 것은 선택 사항이 아닙니다. 어떤 시점에서는 매개 변수가 많은 메소드 나 필요한 사용 사례를 모두 다루지 않는 너무 간단한 메소드가 생길 수 있습니다. 소비하는 API를 디자인하는 개인적인 경험에 비추어 볼 때 API 레벨에서보다 일반적인 메소드를 사용하고 애플리케이션 레벨에서 특정 필수 랩퍼를 구현하는 것이 좋습니다.


1

변경 인수는 YAGNI와 함께 해제해야합니다. 기본적으로 제네릭 API를 다르게 사용하는 적어도 3 개의 다른 유스 케이스를 가지고 있지 않는 한, 다음 유스 케이스가 나올 때 (그리고 사용시 경우에 따라 일반적인 인터페이스, 기간이 필요합니다). 따라서 변경을 시도하고 준비하지 마십시오.

두 경우 모두 배포를 위해 변경 내용을 동기화 할 필요는 없습니다. 나중에 인터페이스를 일반화하면 이전 버전과의 호환성을 위해보다 구체적인 인터페이스를 항상 제공 할 수 있습니다. 그러나 실제로 모든 배포에는 변경 사항이 너무 많아서 동기화 할 수 있으므로 중간 상태를 테스트 할 필요가 없습니다. 나는 그것을 논쟁으로 보지 않을 것입니다.

문서에 관해서는, 어느 솔루션이든 사용하기 쉽고 명확 할 수 있습니다. 그러나 그것은 중요한 주장으로 서있다. 실제 사례에서 사용하기 쉽도록 인터페이스를 구현하십시오. 때로는 구체적이 더 좋을 수도 있고 때로는 일반적인 것일 수도 있습니다.


1

추상 인터페이스 접근 방식을 선호합니다. 이러한 종류의 (검색) 서비스에 쿼리를 넣는 것은 일반적인 문제이며 다시 발생할 수 있습니다. 또한보다 일반적인 인터페이스를 재사용하기에 적합한 더 많은 서비스 후보를 찾을 수 있습니다. 해당 서비스에 대해 일관된 공통 인터페이스를 제공 할 수 있도록 인터페이스 정의에서 현재 식별 된 쿼리 매개 변수를 열거하지 않습니다.

이전에 지적했듯이 인터페이스를 수정하지 않고 구현을 변경하거나 확장 할 수있는 기회가 마음에 듭니다. 다른 검색 기준을 추가해도 서비스 정의에 반영되지 않아야합니다.

명확하고 간결하며 표현적인 인터페이스를 디자인하는 것은 의심의 여지가 없지만 항상 몇 가지 문서를 제공해야합니다. 유효한 검색 기준에 대한 정의 범위를 추가하는 것은 그렇게 부담이되지 않습니다.


1

내가 본 최고의 요약은 Rusty의 규모이며, 이제 Rusty의 API 디자인 선언문이라고 합니다. 나는 그 것을 강력히 추천 할 수있다. 완벽을 기하기 위해 첫 번째 링크에서 스케일 요약을 인용합니다 (위에서 더 좋을수록 아래에서 더 나쁩니다).

좋은 API

  • 잘못하는 것은 불가능합니다.
  • 컴파일러 / 링커는 잘못 얻을 수 없습니다.
  • 컴파일러는 당신이 잘못하면 경고합니다.
  • 명백한 사용은 (아마도) 올바른 것입니다.
  • 이름은 사용법을 알려줍니다.
  • 올바르게 수행하지 않으면 항상 런타임에 중단됩니다.
  • 일반적인 관례를 따르면 올바르게 얻을 수 있습니다.
  • 설명서를 읽으면 올바르게 얻을 수 있습니다.
  • 구현을 읽으면 올바르게 얻을 수 있습니다.
  • 올바른 메일 링리스트 스레드를 읽으면 올바르게 얻을 수 있습니다.

잘못된 API

  • 메일 링리스트 스레드를 읽으면 잘못 될 것입니다.
  • 구현을 읽으면 잘못 될 것입니다.
  • 설명서를 읽으면 잘못 될 것입니다.
  • 일반적인 관례를 따르면 잘못 될 것입니다.
  • 올바르게 수행하면 때로는 런타임에 중단됩니다.
  • 이름은 사용하지 않는 방법을 알려줍니다.
  • 명백한 사용이 잘못되었습니다.
  • 컴파일러는 올바르게 이해하면 경고합니다.
  • 컴파일러 / 링커는 올바르게 얻을 수 없습니다.
  • 제대로하는 것은 불가능합니다.

여기여기에있는 세부 정보 페이지 에는 각 요점에 대한 심도있는 토론이 있습니다. API 디자이너에게는 꼭 읽어야 할 것입니다. 이 글을 읽어 본다면 Rusty에게 감사드립니다.


0

평신도의 말로 :

  • 추상적 접근 방식은 그 주위에 구체적인 방법을 만들 수 있다는 이점이 있습니다.
  • 다른 방법은 사실이 아닙니다

UDP는 신뢰할 수있는 스트림을 만들 수 있다는 장점이 있습니다. 그렇다면 왜 거의 모든 사람이 TCP를 사용합니까?
svick September

대부분의 사용 사례도 고려해야합니다. 일부 사례는 너무 자주 필요할 수 있으므로 해당 사례를 특별하게 만드는 것이 가능합니다.
Roman Susi

0

당신이 확장되면 SearchCriteria생각을 조금, 그러한 만드는 당신에게 유연성을 제공 할 수 있습니다 AND, OR등 기준을. 이러한 기능이 필요한 경우이 방법이 더 좋습니다.

그렇지 않으면 유용성을 위해 디자인하십시오. API를 사용하는 사람들이 쉽게 API를 사용할 수 있도록하십시오. 이름으로 사람을 검색하는 것과 같이 자주 필요한 일부 기본 기능이있는 경우 직접 제공하십시오. 고급 사용자에게 고급 검색이 필요한 경우 여전히을 사용할 수 있습니다 SearchCriteria.


0

API 뒤의 코드는 무엇을하고 있습니까? 유연한 것이면 유연한 API가 좋습니다. API 뒤의 코드가 매우 구체적이라면 유연하게 살펴보면 API 사용자는 API가 가능하지만 실제로는 달성 할 수없는 모든 일에 좌절하고 짜증이 날 것입니다.

귀하의 개인 검색 예제에는 세 가지 필드가 모두 필요합니까? 그렇다면 기준 목록은 잘못 사용되는 많은 용도를 허용하기 때문에 좋지 않습니다. 그렇지 않으면 사용자에게 비 필수 입력을 지정하도록 요구하는 것은 좋지 않습니다. V2에 주소 별 검색이 추가 될 가능성은 얼마나됩니까? 유연한 인터페이스는 융통성없는 인터페이스보다 쉽게 ​​추가 할 수 있습니다.

모든 시스템이 매우 유연 할 필요는 없으며, 아키텍처 우주 비행사 (Architecture Astronauting)도 모든 것을 만들려고합니다. 유연한 활은 화살을 쏘습니다. 유연한 칼은 고무 치킨만큼이나 유용합니다.

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