다음을 통해 공유


호환성이 손상되는 변경

.NET 라이브러리에서 기존 사용자를 위한 안정성과 미래를 위한 혁신 간에 균형을 맞추는 것이 중요합니다. 라이브러리 작성자는 코드가 완벽해질 때까지 리팩터링 및 재고하는 경향이 있지만, 특히 낮은 수준의 라이브러리의 경우에는 기존 사용자의 업무 중단에 부정적인 영향을 미칩니다.

프로젝트 형식 및 호환성이 손상되는 변경

.NET 커뮤니티에서 라이브러리를 사용하는 방법은 최종 사용자 개발자에서 호환성이 손상되는 변경의 효과를 변화시킵니다.

  • 직렬 변환기, HTML 파서, 데이터베이스 개체 관계형 매퍼 또는 웹 프레임워크와 같은 낮음 및 중간 수준의 라이브러리는 호환성이 손상되는 변경의 영향을 가장 많이 받습니다.

    빌딩 블록 패키지는 최종 사용자 개발자가 애플리케이션을 빌드하는 데 사용하고 다른 라이브러리는 NuGet 종속성으로 사용됩니다. 예를 들어 애플리케이션을 빌드하고 있고 오픈 소스 클라이언트를 사용하여 웹 서비스를 호출하는 경우입니다. 클라이언트가 사용하는 종속성에 대한 중요 업데이트는 수정할 수 있는 것이 아닙니다. 이는 변경해야 하는 오픈 소스 클라이언트이므로 제어할 수 없습니다. 호환 가능한 버전의 라이브러리를 찾거나 수정 사항을 클라이언트 라이브러리에 제출하고 새 버전을 기다려야 합니다. 최악의 상황은 서로 호환되지 않는 세 번째 버전의 라이브러리에 종속된 두 개의 라이브러리를 사용하려는 경우입니다.

  • UI의 도구 모음과 같은 고급 라이브러리는 호환성이 손상되는 변경에 덜 민감합니다.

    고급 라이브러리는 최종 사용자 애플리케이션에서 직접 참조됩니다. 호환성이 손상되는 변경이 발생한 경우 개발자는 최신 버전으로 업데이트하도록 선택하거나 호환성이 손상되는 변경에 맞게 해당 애플리케이션을 수정할 수 있습니다.

✔️ 라이브러리 사용 방법에 대해 생각해 보세요. 호환성이 손상되는 변경은 이를 사용하는 애플리케이션과 라이브러리에 어떤 영향을 주나요?

✔️ 낮은 수준의 .NET 라이브러리를 개발할 때 호환성이 손상되는 변경을 최소화합니다.

✔️ 새 NuGet 패키지로 라이브러리의 주 버전 재작성을 게시하는 것을 고려하세요.

호환성이 손상되는 변경의 형식

호환성이 손상되는 변경은 다른 범주로 분류되고 동일하게 영향을 주지 않습니다.

소스 주요 변경 내용

소스 주요 변경 내용은 프로그램 실행에 영향을 주지 않지만 다음에 애플리케이션을 다시 컴파일할 때 컴파일 오류가 발생합니다. 예를 들어 새 오버로드는 이전에 모호하지 않은 메서드 호출에 모호함을 만들거나 이름이 바뀐 매개 변수는 명명된 매개 변수를 사용하는 호출자의 연결을 끊을 수 있습니다.

public class Task
{
    // Adding a type called Task could conflict with System.Threading.Tasks.Task at compilation
}

소스 주요 변경 내용은 개발자가 애플리케이션을 다시 컴파일할 때만 해로울 수 있으므로 가장 방해가 적은 주요 변경 내용입니다. 개발자는 자신의 손상된 소스 코드를 쉽게 해결할 수 있습니다.

동작 주요 변경 내용

동작 변경 내용은 가장 일반적인 주요 변경 내용의 유형입니다. 거의 모든 동작의 변경 내용이 소비자에게 논리 오류를 일으킬 수 있습니다. 메서드 서명, throw된 예외, 입력 또는 출력 데이터 형식과 같은 라이브러리 변경 내용은 모두 라이브러리 소비자에게 부정적인 영향을 줄 수 있습니다. 사용자가 이전에 손상된 동작을 사용하는 경우 버그 수정도 주요 변경 내용으로 한정할 수 있습니다.

기능을 추가하고 잘못된 동작을 개선하는 것은 좋은 것이지만, 주의하지 않으면 기존 사용자가 업그레이드하기가 매우 어려울 수 있습니다. 개발자가 동작 주요 변경 내용을 처리하는 데 도움이 되는 한 가지 방법은 설정 뒤에 숨기는 것입니다. 설정을 통해 개발자가 최신 버전의 라이브러리로 업데이트하는 동시에 주요 변경 내용을 옵트인하거나 옵트아웃하도록 선택할 수 있습니다. 이 전략을 사용하면 개발자는 소비 코드를 시간 경과에 따라 조정하면서 최신 상태로 유지할 수 있습니다.

예를 들어 ASP.NET Core MVC는 MvcOptions에서 활성화 및 비활성화 기능을 수정하는 호환성 버전의 개념을 가지고 있습니다.

✔️ 기존 사용자에게 영향을 줄 경우 기본적으로 새 기능을 사용하지 않고 개발자가 설정을 사용하여 기능을 옵트인하도록 허용하는 것을 고려하세요.

.NET API의 동작 호환성이 손상되는 변경에 대한 자세한 내용은 .NET 동작 변경 호환성을 참조하세요.

이진 주요 변경 내용

라이브러리의 공용 API를 변경할 때 이진 주요 변경 내용이 발생하므로, 라이브러리의 이전 버전에 대해 컴파일된 어셈블리는 더 이상 API를 호출할 수 없습니다. 예를 들어 새 매개 변수를 추가하여 메서드의 서명을 변경하면 이전 버전의 라이브러리에 대해 컴파일된 어셈블리가 MissingMethodException을 throw할 수 있습니다.

이진 주요 변경 내용으로 인해 전체 어셈블리도 손상될 수 있습니다. AssemblyName을 사용하여 어셈블리 이름을 바꾸면 어셈블리의 강력한 이름 지정 키가 추가, 제거 또는 변경되므로 어셈블리의 ID가 변경됩니다. 어셈블리 ID가 변경되면 이를 사용하는 모든 컴파일된 코드가 중단됩니다.

❌ 어셈블리 이름을 변경하지 마세요.

❌ 강력한 이름 지정 키를 추가, 제거 또는 변경하지 마세요.

✔️ 인터페이스 대신 추상 기본 클래스를 사용하는 것을 고려하세요.

인터페이스에 어떤 것도 추가하면 이를 구현하는 기존 유형이 실패하게 됩니다. 추상 기본 클래스를 사용하면 기본 가상 구현을 추가할 수 있습니다.

제거하려는 형식 및 멤버에 ObsoleteAttribute를 배치하는 것을 고려하세요. 이 특성에는 더 이상 사용되지 않는 API를 사용하지 않도록 코드를 업데이트하는 지침이 있어야 합니다.

ObsoleteAttribute로 형식 및 메서드를 호출하는 코드는 특성에 제공된 메시지로 빌드 경고를 생성합니다. 이 경고는 사용되지 않는 API 노출 시간을 사용하는 사용자에게 마이그레이션을 허용하므로 사용되지 않는 API를 제거하면 대부분 더 이상 사용하지 않습니다.

public class Document
{
    [Obsolete("LoadDocument(string) is obsolete. Use LoadDocument(Uri) instead.")]
    public static Document LoadDocument(string uri)
    {
        return LoadDocument(new Uri(uri));
    }

    public static Document LoadDocument(Uri uri)
    {
        // Load the document
    }
}

✔️ 낮은 수준 및 중간 수준 라이브러리에서 ObsoleteAttribute를 무기한으로 형식 및 메서드를 유지하는 것을 고려하세요.

API를 제거하는 것은 이진 호환성이 손상되는 변경입니다. 사용되지 않는 형식 및 메서드를 유지 관리하는 것이 비용이 저렴하고 라이브러리에 많은 기술적 문제가 추가되지 않은 경우 이를 유지하는 것을 고려해 보세요. 형식 및 메서드를 제거하지 않으면 위에서 언급한 최악의 시나리오를 방지할 수 있습니다.

.NET API 변경 내용이 이진 호환성을 손상하는 것에 대한 자세한 내용은 .NET 퍼블릭 계약 호환성을 참조하세요.

참고 항목