인터페이스를 어떻게 발전시키고 버전을 관리합니까?


22

인터페이스가 있다고 가정 해보십시오 IFoo.

public interface IFoo {
    void Bar(string s);
    int Quux(object o);
}

API 버전 2에서는 Glarg이 인터페이스에 메소드 를 추가해야합니다 . 기존 API 사용자를 중단하고 이전 버전과의 호환성을 유지하지 않고 어떻게 수행합니까? 이것은 주로 .NET을 목표로하지만 다른 프레임 워크 및 언어에도 적용될 수 있습니다.


문제없이 추가 할 수 있습니다. 이미 존재하는 것을 변경 / 제거 할 때 문제가 발생합니다.
Rig

1
@Rig : C #에서는 인터페이스에 메소드를 추가하고 해당 인터페이스를 구현하는 클래스에 메소드를 추가하지 않으면 컴파일 오류가 발생합니다.
Malice

사실입니다. 메소드 서명을 변경하거나 삭제하는 것에 비해 혼란이 최소화 될 수있는 사용자 클래스 시나리오에서 더 많이 생각하고있었습니다. 따라서 인터페이스에 추가 해야하는 경우 약간의 작업이 발생할 수 있다고 생각합니다.
Rig

답변:


9

API 버전 2에서는 Glarg이 인터페이스에 메소드 를 추가해야합니다 .

왜?

API와 함께 사용하도록 정의 된 인터페이스에는 완전히 다른 두 가지 역할이 있습니다.

  1. 종속성 반전-이러한 인터페이스는 API에서 사용합니다. 그들은 클라이언트 코드가 플러그인 등을 만들 수있게합니다.
  2. 추상화-이러한 인터페이스는 API에 의해 리턴되며 리턴 된 오브젝트의 구현 세부 사항을 숨 깁니다.

이제 특정 버전 의 API에 대해 동일한 인터페이스가 둘 다로 작동 할 수 있습니다. 그러나 이후 버전에서는이 연결이 분리 될 수 있습니다.

  1. 사용하는 인터페이스에서 추가 정보를 추출하려고합니다. 성능 향상 또는 유연성 추가 등 이전 인터페이스에서 파생 된 새 인터페이스를 정의하고 별도의 메소드를 사용하여 빌드하십시오. AFAIK 대부분의 .NET 언어는 메서드 오버로딩을 허용하므로 많은 혼란을 초래하지 않고도 발생할 수 있습니다.
  2. API에서 "더 풍부한"객체, 즉 "더 풍부한"객체의 추상화를 원합니다. 여기 두 가지 선택이 있습니다.

    • 클라이언트 코드에는 자체 인터페이스 구현자가 없을 것이라고 합리적으로 가정 할 수 있습니다. 이 가정 하에서 기존 인터페이스에 확장을 추가하는 것이 안전합니다.
    • 가능하면 이전 인터페이스에서 파생 된 새 인터페이스를 정의하십시오. 이러한 파생이 불가능한 경우 새 인터페이스의 인스턴스를 쿼리하거나 컴포지션을 사용하는 별도의 메소드를 작성하십시오.

      interface MyNewInterface extends MyOldInterface { 
           FancyNewInterface getFancyShit();
      }
      

15

DirectX는 인터페이스에 버전 번호를 추가했습니다. 귀하의 경우 솔루션은 다음과 같습니다.

public interface IFoo2 : IFoo
{
    void Glarg();
}

API는 여전히 IFoo를 참조하고 IFoo2 기능이 필요한 방법 등에서 만 IFoo2를 참조합니다.

API 구현은 IFoo2에 대해 메소드 의미가 다른 경우 IFoo 매개 변수 객체가 실제로 IFoo2를 구현하는지 여부를 기존 (= 버전 1) 메소드에서 확인해야합니다.


3

API에 새 메소드를 추가하는 것은 기존 API에 부작용이없는 방식으로 수행해야합니다. 가장 중요한 것은 새 API가 존재하지 않는 것처럼 이전 API를 계속 사용하는 사람은 영향을받지 않아야합니다. 이전 API를 사용하면 새 API에 예기치 않은 부작용 이 없어야 합니다.

API의 기존 메소드 중 하나가 새 메소드로 대체 된 경우 바로 제거하지 마십시오. 더 이상 사용되지 않는 것으로 표시하고 대신 사용해야하는 것에 대한 설명을 제공하십시오. 따라서 코드 버전 사용자는 경고없이 코드를 손상시키는 대신 향후 버전에서 더 이상 코드를 지원하지 않을 수 있음을 경고합니다.

새로운 API와 기존 API가 호환되지 않고 원치 않는 부작용없이 함께 살 수없는 경우 분리하고 새 API를 채택하려면 이전 API를 완전히 폐기해야한다고 문서화하십시오. 둘 다 사용하려고 시도하고 작동하지 않을 때 좌절하는 사람이 항상 있기 때문에 이것은 바람직하지 않습니다.

.NET에 대해 구체적으로 물었으므로 .NET 에서 더 이상 사용되지 않는 (이 예제에서 사용 되는) 링크에 대한 이 기사 를 읽으십시오 ObsoleteAttribute.

using System;

public sealed class App {
   static void Main() {      
      // The line below causes the compiler to issue a warning:
      // 'App.SomeDeprecatedMethod()' is obsolete: 'Do not call this method.'
      SomeDeprecatedMethod();
   }

   // The method below is marked with the ObsoleteAttribute. 
   // Any code that attempts to call this method will get a warning.
   [Obsolete("Do not call this method.")]
   private static void SomeDeprecatedMethod() { }
}

2

공용 인터페이스 변경에는 파손이 포함됩니다. 일반적인 전략은 메이저 버전과 동결 기간 후에 만 ​​수행하는 것입니다 (따라서 변덕스럽지 않습니다). 새 인터페이스에 추가를 추가하는 경우 클라이언트를 중단하지 않고도 벗어날 수 있습니다 (구현이 동일한 클래스에서 둘 다 제공 할 수 있음). 그것은 이상적이지 않으며, 계속해서하면 엉망이 될 것입니다.

그래도 다른 종류의 수정 (메서드 제거, 서명 변경)을 사용하면 문제가 발생합니다.


2
미래의 메소드 이름에 대한 접두사를 선점 적으로 예약하고 모든 사용자에게 해당 네임 스페이스를 사용해서는 안되며, 그렇지 않으면 우아하지 않은 API를 만들도록 경고 할 수 있습니다. 일반적으로 부모는 절대적으로 옳습니다. 방법을 제거하면 (그리고 종종 추가하는 경우) 기존 사용자 중단되며 현명하게 계획하는 것 외에는 할 수있는 일이 없습니다.
Kilian Foth

1

인터페이스는 계약이므로 버전 관리가 없어야합니다. 축구 선수가 새로운 계약을 받으면 어떻게됩니까? 오래된 것이 여전히 유효합니까? 아니요. 인터페이스를 변경하면 계약이 변경되고 이전 계약 (인터페이스)이 더 이상 유효하지 않습니다.

IFoo2 전략을 사용할 수는 있지만 결국 다음과 같은 경우에는 혼란스러워집니다.

  • IFoo2
  • IFoo3
  • IFoo4
  • 기타

왝.

API가 다릅니다. 사용할 코드 라이브러리를 제공합니다. 다음 달에는 업데이트 된 라이브러리를 제공합니다. 다른 포스터가 말했듯이, 이미 사용중인 것을 중단하지 말고 새로운 기능 / 방법을 추가하십시오.

버전을 변경하려면 인터페이스 대신 abtract 클래스를 사용하십시오.

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