Eclipse 플랫폼
API 사용 규칙
버전 0.15 - 마지막 수정 시간: 2001년 5월 30일 12:00
다음은 Eclipse 플랫폼 API(및 기타 컴포넌트)의 클라이언트용 사용 규칙입니다.
API 정의
Eclipse 플랫폼은 클라이언트별 사용할 API 요소(즉, 플러그인을 작성 중인 ISV)를 정의합니다. 그러면 플러그인은 해당 클라이언트에 대해 API 요소를 정의할 수 있습니다. API 요소는 공용 요소로서,
해당 API 요소가 수행하게 될 작업 및 사용되는 방식에 대한 스펙을 포함합니다. API 요소는 계속 지원되므로
Eclipse 플랫폼 팀에서는 지정된 동작에서 벗어나는 구현 버그가 있을 경우 이 문제를 수정할 것입니다. 또한 API 변경사항 중단에 관련하여 많은 비용이 들기 때문에 Eclipse 플랫폼 팀에서는 연속적인
주 릴리스를 통해 API 요소를 발전시키려고 노력할 것입니다.
API와 비API의 구별 방법
본질적으로, API 요소는 문서화되고 스펙이 있는 반면, 비API 요소는 내부 구현 세부사항으로서
보통 공개된 문서나 스펙이 없습니다. 따라서 특정 문서를 찾을 수 없는 경우, 그것은 대개
해당 항목이 API가 아님을 나타냅니다.
분명하게 구별하면, 플랫폼의 코드 베이스는 API 패키지와 비API 패키지로 구분되며,
모든 API 요소는 지정된 API 패키지에서 선언됩니다.
-
API 패키지 - 적어도 하나의 API 클래스 또는 API 인터페이스를 포함하는 Java 패키지입니다. API 패키지 이름은 해당 컴포넌트의 문서에서 공개되며, 공개 가능한 경우 구현 세부사항만 포함하는 다른 모든
패키지에는 패키지 이름에 "internal"이라는 문자열이 들어 있습니다. API 패키지 이름은 클라이언트
코드에 정식으로 나타날 수 있습니다. 올바른 Eclipse 플랫폼의 경우, 다음과 같이 나타납니다.
-
org.eclipse.foo.* - 예: org.eclipse.swt.widgets,
org.eclipse.ui 또는 org.eclipse.core.runtime
-
org.eclipse.foo.internal.* - 비API, 내부 구현 패키지
-
org.eclipse.foo.examples.* - 비API, 예
-
org.eclipse.foo.tests.* - 비API, 테스트 스위트
-
API 클래스 또는 인터페이스 - API 패키지에 있는 public 클래스 또는 인터페이스, 그렇지 않으면,
다른 API 클래스나 인터페이스에 선언되었거나 상속된 public이나
protected 클래스 또는 인터페이스 구성원입니다.
API 클래스 및 인터페이스의 이름은 클라이언트 코드에 정식으로 나타날 수 있습니다.
-
API 메소드 또는 생성자 - API 클래스 또는 인터페이스에서 선언되었거나
상속된 public이나 protected 메소드 또는 생성자입니다. API 메소드 이름은 클라이언트 코드에 정식으로 나타날 수 있습니다.
-
API 필드 - API 클래스 또는 인터페이스에서 선언되었거나 상속된
public 또는 protected 필드입니다. API 필드 이름은 클라이언트 코드에 정식으로
나타날 수 있습니다.
기타 모든 항목은 내부 구현 세부사항으로 간주되며 모든 클라이언트에 액세스할 수 없습니다. 올바른 클라이언트 코드는 Java 리플렉션을 사용하는 경우에도
비API 요소의 이름을 인용해서는 안됩니다. 일부 경우, 잘못된 참조를 허용하지 않기 위해 Java 언어의 이름에 대한 내게 필요한 옵션 규칙이 사용됩니다.
그러나 대부분의 경우에 이 규칙을 사용할 수 없습니다. 즉, 하나의 단순한 규칙으로 문제점을 완전히 해결할
수는 없습니다.
-
공식적으로 문서화된 API를 유지하십시오. 해당 컴포넌트의 공개된 API Javadoc에
문서화된 패키지만 참조하십시오.
이름에 "internal"이 포함된 다른 컴포넌트에
속하는 패키지는 API가 아니므로 참조하지 마십시오. 공개된 API
Javadoc이 없는 패키지도 API가 아니므로 참조하지 마십시오.
일반 규칙
API 요소의 스펙은 해당 요소의 Java 소스 코드에 있는 Javadoc 주석에서 생성됩니다. 일부 유형의 요소에서는
스펙이 계약 형식으로 되어 있습니다. 예를 들어, 메소드의 경우에서 이는 메소드 호출자와 메소드 구현자
간의 계약입니다. 기본적인 규칙은 다음과 같습니다.
-
모든 계약사항을 준수하십시오. 계약은 사용 중인 API 요소의 공개된 Javadoc에 설명되어 있습니다.
API 계약에서 "반드시"라는 표현이 사용되면, 이는 해당 조건에 항상 만족하는 계약 당사자에게
책임이 있음을 의미합니다. 조건에 만족하지 못하면 이는 특정되지 않은(예기치 않은) 결과를 발생시키는
프로그래밍 오류로 간주됩니다.
-
"반드시"라고 표현된 사항을 준수해야 합니다. "반드시"라는 표현이 사용되는 조건에는 특별히
주의하십시오.
다른 일반적인 규칙은 다음과 같습니다.
-
부수적 작동에 의존하지 마십시오. 부수적 작동은 실험 또는 실습에서 관찰되는 작동으로서
모든 API 스펙에서 보장되지는 않습니다.
-
널을 오브젝트로 취급하지 마십시오. 널은 오브젝트가 없음을 나타냅니다.
API 스펙에서 달리 언급하지 않으면 모든 항목을 널이 아닌 것으로 가정하십시오.
-
편법으로 Java 리플렉션을 사용하지 마십시오. Java 리플렉션을 사용하여 Java 컴파일러 검사를
회피하는 것은 아무런 이득이 되지 않습니다. 리플렉션 사용에 대한 추가 API 계약이 없는 경우, 리플렉션을
사용하면 지정되지 않은 동작 및 내부 구현 세부사항에 의존하게 될 가능성이 커집니다.
-
사용자 고유의 패키지를 사용하십시오. 다른 컴포넌트에 속한 패키지에 코드를 선언하지
마십시오. 항상 사용자 고유의 패키지에 고유 코드를 선언하십시오.
public API 메소드 호출
대부분의 클라이언트의 경우, 대부분의 Eclipse API는 클라이언트가 적절할 때 호출하면,
API 인터페이스 또는 클래스의 public 메소드 형식을 취합니다.
-
전제조건 확인. API 메소드를 호출하기 전에 메소드의 전제조건을 만족하는지
확인하십시오. 반대로, 호출자는 호출에서 리턴되는 즉시 해당
메소드의 사후조건이 성취된 것으로 가정합니다.
-
널 매개변수. 매개변수가 널을 허용하는 것으로 명시적으로 문서화되지 않은 경우에는 API 메소드에
매개변수로서 널을 전달하지 마십시오. 이는 가장 자주 발생하는 프로그래밍 오류입니다.
-
제한된 호출자. 특정 호출자만 사용할 수 있는 것으로 문서화된 API 메소드는 해당 호출자가 아니면
호출하지 마십시오. 일부 경우, 메소드는 호출자의 특정 클래스(대개, 내부)를 위해 public API의
일부이어야 합니다. 이들 메소드 중 하나를 적당하지 않은 때에 호출하면 특정되지 않은(예기치 않은)
결과가 생깁니다.
-
메소드 디버깅. "디버깅 전용"이라는 레이블의 API 메소드를 호출하지 마십시오. 예를 들어,
대부분의 toString() 메소드는 이 카테고리 안에 있습니다.
-
매개변수 캡처. 배열, 콜렉션 또는 기타 가변적인 오브젝트를 매개변수로서 API 메소드에 전달하지 마십시오.
그리고 전달된 오브젝트를 수정하지 마십시오. 문제가 될 수 있습니다.
플랫폼 API 클래스의 인스턴스화
사람들이 모두 구체 API 클래스를 인스턴스화하려 하지는 않습니다.
API 클래스에는 인스턴스를 작성할 수 있는 조건을 표시하는 인스턴스화 계약이 있습니다. 이 계약에서는 나머지 초기화 책임(예: 해당 인스턴스가 완전히 활성화되기 전에 특정 특성을 구성하는 책임) 및
연관된 라이프 사이클 책임(예: dispose()를 호출하여 해당 인스턴스에서 사용하는 OS 자원을
해제하는 책임) 등의 항목을 다룰 수도 있습니다. 클라이언트에서 인스턴스로 설계된 클래스는
Javadoc 클래스 주석("클라이언트가 인스턴스화할 수 있습니다."와 같은 말)을 사용하여 명시적으로
플래그되어야 합니다.
-
제한된 인스턴스 생성자. 특정 당사자만 사용할 수 있는 것으로 문서화된 API 클래스의 경우 해당 당사자가
아니면 인스턴스화하지 마십시오.
일부 경우, 클래스는 특정 당사자(보통, 내부)를 위해
public API의 일부이어야 합니다. 이러한 클래스 중 하나를 올바르지 않게 인스턴스화하면 특정되지
않은(예기치 않은) 결과가 발생합니다.
플랫폼 API 클래스의 서브클래스화
API 클래스의 서브세트만 서브클래스로 설계할 수 있습니다. API 클래스에는 서브클래스를 선언할 수 있는 항목을
표시하는 서브클래스 계약이 있습니다. 이 계약에서는 초기화 책임과 라이프 사이클 책임도 포함합니다. 클라이언트에서 서브클래스로 설계된 클래스는 Javadoc 클래스 주석("클라이언트가 서브클래스화할
수 있습니다."와 같은 단어)을 사용하여 명시적으로 플래그되어야 합니다.
-
제한된 서브클래스 생성자. 서브클래스로 의도되지 않은 API
클래스를 서브클래스화하지 마십시오. 이러한 클래스는 final 클래스로 선언된 것처럼 처리하십시오(이들 클래스를
"soft final" 클래스라고도 함).
protected API 메소드 호출
대개 서브클래스 내에서는 상속된 protected 메소드 및 public 메소드를 호출할 수 있습니다. 그러나
이 경우 메소드를 올바르게 호출하려면 계층 구조 외부에서 public 메소드를 호출할 때보다 더 많은 주의가
필요합니다.
API 메소드 대체
public API 메소드와 protected API 메소드의 서브세트만 대체되도록 설계할 수 있습니다. 각 API 메소드에는 서브클래스가 해당 메소드를 대체할 수 있는 항목을 표시하는 서브클래스 계약이 있습니다. 기본적으로 대체는 허용되지 않습니다.
따라서 대체되는 실제 메소드 구현에 대한 서브클래스 계약을
확인하는 것이 중요합니다. 서브클래스 계약 항목은 메소드가 대체될 때 자동으로 전달되지 않습니다.
-
명시적으로 허용되지 않은 경우에는 public API 메소드 또는 protected API 메소드를 대체하지
마십시오. 달리 표시되지 않은 경우 이러한 메소드는 final 메소드로 선언된 것처럼 처리하십시오(이러한
메소드를 "soft final" 메소드라고도 함).
다음과 같이 대체가 허용되면,
- "구현" - 서브클래스에 선언된 abstract 메소드는 구체 서브클래스에 의해 구현되어야 합니다.
- "확장" - 서브클래스에 선언된 메소드는 수퍼클래스에서 메소드를 호출해야 합니다(한 번).
- "재구현" - 서브클래스에 선언된 메소드는 수퍼클래스에서 메소드를 호출하면 안됩니다.
- "대체" - 서브클래스에 선언된 메소드는 적절한 경우 수퍼클래스에서 메소드를 자유롭게 호출할 수 있습니다.
-
사후조건을 확인하십시오. 리턴되면 API 메소드에 대해 지정된 사후조건이 해당 구현에서
만족되는지 확인하십시오.
-
사전에 전제조건을 확인하십시오. 입력 시 API 메소드에 대해 지정된 전제조건이 반드시 만족된 것으로
가정하지 마십시오. 해당 메소드 구현이 지정된 전제조건을 확인하지 않는 권한 내에
있는 경우라도, 호출자가 올바르지 않게 작동하지 못하도록 하려면 보통 전제조건을 확인하는 것이
좋습니다(가능하고 비용이 많이 들지 않는 경우).
-
널 결과. 지정된 인터페이스 또는 수퍼클래스에 대한 결과로 널을 리턴할 수 있도록 명시적으로
문서화되지 않은 경우에는 API 메소드에서 결과로서 널을 리턴하지 마십시오.
-
사본 리턴. 바꿀 수 없는 배열, 콜렉션 또는 기타 가변적 오브젝트를 API 메소드에서 결과로서
리턴하지 마십시오. 호출자가 오브젝트를 수정할 경우 발생하는 문제를 방지하려면 항상 사본을 리턴하십시오.
플랫폼 API 인터페이스 구현
API 인터페이스의 서브세트만 클라이언트에서 구현하도록 설계할 수 있습니다. API 인터페이스에는
구현될 수 있는 항목을 표시하는 계약이 있습니다. 클라이언트에서 구현하도록 설계된 인터페이스는
Javadoc 클래스 주석("클라이언트가 구현할 수 있습니다."와 같은 단어)을 사용하여 명시적으로 플래그되어야
합니다. 클라이언트에서는 구현이 허용되는 API 인터페이스에 대해서만 서브인터페이스를 선언할 수 있습니다.
-
제한된 구현자. 특정 당사자만 사용할 수 있는 것으로 문서화된 API 인터페이스는 해당 당사자가
아니면 구현하지 마십시오. 대부분의 경우, 인터페이스는 보기에서 내부 구현 세부사항을 숨기는 데 사용됩니다.
public API 메소드 구현
"API 메소드 대체"를 참조하십시오.
API 클래스 및 인터페이스의 필드에 액세스
클라이언트에서는 대부분 final 필드인 API 필드를 읽을 수 있습니다. 구조체와 유사한 특정 오브젝트에는
final이 아닌 public 필드가 있을 수 있으며, 클라이언트에서는 달리 표시하지 않는 경우 이러한 필드를 읽고
쓸 수 있습니다.
-
널 필드. 명시적으로 허용되지 않은 경우에는 API 필드를 널로 설정하지 마십시오.
알려진 API 유형의 오브젝트 캐스트
알려진 API 유형의 오브젝트는 해당 API에서 명시적으로 허용하는 경우 다른 API 유형으로
캐스트하거나 instanceof를 사용하여 조건부 캐스트할 수 있습니다.
-
cast 및 instanceof. instanceof 및 cast 표현식을 사용하여, 알려진 오브젝트 개념을
API가 지원하는 것 이상으로 증가시키지 마십시오.
사용법이 적절하지 않으면 API에서
부수적인 구현 세부사항을 보장할 수 없게 됩니다.
또한 임의 오브젝트를 비API 클래스 또는 인터페이스로 캐스트하는 것은 항상 올바르지 않습니다.
규칙을 따르지 않는 경우
고의적이든 우발적이든 규칙을 위반하는 데는 몇 가지 결과가 따릅니다. 규칙을 위반할 경우 이를 감시하는
API 단속자라도 있다면 모든 사람이 이 규칙을 지키기가 더 쉬울 것입니다. 그러나 이러한 경우는
없습니다.
대부분의 경우, API 규칙은 자율적으로 준수하는 규칙이며, 이 규칙을 이해하고
준수하는 것은 각 클라이언트의 책임입니다.
API 요소에 대한 계약에서는 지원 및 허용되는 동작의 범위를 제한합니다. Eclipse 플랫폼이 발전할수록
이는 이러한 발전이 일어나는 방식을 안내하는 API 계약이 될 것입니다. 이러한 계약 이외의 모든 사항은 지원되지 않으며 언제든지 예고 없이 변경될 수 있습니다(릴리스 중간이나
다른 OS 플랫폼 간에도 해당). 위의 규칙에 따르지 않는 클라이언트 코드는 플랫폼의 서로 다른
버전 및 패치 레벨에서 실패할 수 있으며, 다른 기본 운영 체제에서 실행되는 경우, 함께 상주하는
플러그인을 다르게 결합시켜 실행하는 경우 또는 다른 Workbench Perspective와 함께 실행하는
경우에도 실패할 수 있습니다. 사실, 지금까지는 관련자들 조차 특정 사항을 위반할 경우 발생할 수
있는 결과에 대해 특별한 관심을 두지 않았습니다. 규칙을 무시하기로 선택하는 사용자는 규칙을 무시할 경우 발생할 수 있는 결과에 대해 충분히 경고를 받았습니다. 따라서 이로 인한 결과에 대해 책임이 있음을 기억해야 합니다.
반면, 위의 규칙에 따라 작성된 클라이언트 플러그인 코드는 플랫폼의 서로 다른 버전과 패치 레벨 및
다양한 기본 운영 체제에서도 계속해서 작동하며 다른 플러그인과도 아무 문제 없이 상존할 수 있습니다. 모든 사용자가 이 규칙을 따르는 경우,
Eclipse 플랫폼에서는 뛰어난 신제품을 빌드하는 데 안정적이고 지속적인 기반을 제공할 것입니다.