부패 방지 계층이란 무엇이며 어떻게 사용됩니까?


151

반부패 계층이 실제로 무엇을 의미하는지 알아 내려고 노력 중입니다. 레거시 코드 또는 잘못된 API를 전환 / 해결하는 방법이라는 것을 알고 있습니다. 내가 이해하지 못하는 것은 작동 방식과 원하지 않는 층과 깨끗하게 분리되는 것입니다.

몇 가지 검색을 수행했지만 간단한 예나 설명을 찾을 수 없으므로이를 이해하고 간단한 예를 통해 설명 할 수있는 사람을 찾고 있습니다. 내 질문을 만족시키는 답변은 간단해야하며 반드시 짧지는 않지만 구현 및 사용에 대한 이해할 수있는 예를 제공해야합니다.

사용 사례는 이 질문을 참조하십시오 .

답변:


147

아래와 같이 설계된 다른 사람의 코드를 사용해야한다고 상상해보십시오.

    class Messy {
        String concat(String param, String str) { /* ... */ }
        boolean contains(String param, String s) { /* ... */ }
        boolean isEmpty(String param) { /* ... */ }
        boolean matches(String param, String regex) { /* ... */ }
        boolean startsWith(String param, String prefix) { /* ... */ }
    }

이제 코드에 의존하는 코드가 다음과 같다는 것을 알게됩니다.

String process(String param) {
    Messy messy = new Messy();
    if (messy.contains(param, "whatever")) {
        return messy.concat(param, "-contains");
    }
    if (messy.isEmpty(param)) {
        return messy.concat(param, "-empty");
    }
    if (messy.matches(param, "[whatever]")) {
        return messy.concat(param, "-matches");
    }
    if (messy.startsWith(param, "whatever")) {
        return messy.concat(param, "-startsWith");
    }
    return messy.concat(param, "-whatever");
    // WTF do I really need to repeat bloody "param" 9 times above?
}

... 특히 응용 프로그램에 필요하지 않은 반복적 인 매개 변수 사용을 없애기 위해 더 쉽게 사용할 수 있기를 원합니다.

자, 반부패 계층을 구축하기 시작합니다.

  1. 먼저 "메인 코드"가 Messy직접 참조되지 않는지 확인하십시오 . 예를 들어 액세스 시도 가 컴파일되지 않는 방식으로 종속성 관리 를 정렬 Messy합니다.

  2. 둘째, 액세스하는 유일한 "전용 레이어"모듈을 만들어서 Messy"메인 코드"에보다 적합한 방식으로 노출시킵니다.

레이어 코드는 다음과 같습니다.

    class Reasonable { // anti-corruption layer
        String param;
        Messy messy = new Messy();
        Reasonable(String param) {
            this.param = param;
        }
        String concat(String str) { return messy.concat(param, str); }
        boolean contains(String s) { return messy.contains(param, s); }
        boolean isEmpty() { return messy.isEmpty(param); }
        boolean matches(String regex) { return messy.matches(param, regex); }
        boolean startsWith(String prefix) { return messy.startsWith(param, prefix); }
    }

결과적으로, "메인 코드"는 다음과 같이 대신에를 Messy사용하여 엉망이되지 않습니다 Reasonable.

String process(String param) {
    Reasonable reasonable = new Reasonable(param);
    // single use of "param" above and voila, you're free
    if (reasonable.contains("whatever")) {
        return reasonable.concat("-contains");
    }
    if (reasonable.isEmpty()) {
        return reasonable.concat("-empty");
    }
    if (reasonable.matches("[whatever]")) {
        return reasonable.concat("-matches");
    }
    if (reasonable.startsWith("whatever")) {
        return reasonable.concat("-startsWith");
    }
    return reasonable.concat("-whatever");
}

여전히 엉망인 약간의 혼란 Messy이 있지만 이것은 이제 상당히 깊숙이 숨겨져 Reasonable있어 "메인 코드"를 합리적으로 깨끗하고 손상시키지 않고 Messy물건 을 직접 사용하여 가져올 수 있습니다 .


위의 예는 c2 wiki에서 반부패 계층 이 설명되는 방식을 기반으로합니다 .

응용 프로그램이 데이터베이스 또는 모델이 바람직하지 않거나 자신의 응용 프로그램 내에서 원하는 모델에 적용 할 수없는 다른 응용 프로그램을 처리해야하는 경우 AnticorruptionLayer를 사용하여 해당 모델과 사용자의 데이터베이스간에 변환합니다.

참고 예는 설명을 간단하게하기 위해 의도적으로 단순하고 요약 된 것입니다.

반부패 계층 뒤에서 다루기 위해 더 큰 API 엉망이있는 경우 동일한 접근 방식이 적용됩니다. 먼저 "주 코드"가 손상된 항목에 직접 액세스하지 않는지 확인하십시오. 사용 환경에서 편리합니다.

위의 간단한 예제를 넘어서 레이어를 "스케일링"할 때 API를 편리하게 만드는 것이 사소한 작업이 아니라는 점을 고려하십시오. 올바른 방법으로 레이어설계 하고 단위 테스트 등을 통해 의도 된 용도를 확인하기위한 노력 을 투자 하십시오 .

다시 말해, API가 실제로 숨겨 지는 API 보다 개선 된 것인지 확인하고 다른 손상 계층을 도입하지 않아야합니다.


완벽을 기하기 위해이 패턴과 관련 패턴 인 어댑터외관 사이의 미묘하지만 중요한 차이점에 주목하십시오 . 그 이름으로 표시된 바와 같이, 부패 방지 계층은 기본 API에 품질 문제 ( "손상됨")가 있으며 언급 된 문제의 보호를 제공하려고합니다.

당신은 그것을 이런 식으로 생각할 수 있습니다 : 당신이 그 기능을 노출 더 나을 것이라고 라이브러리 디자이너를 정당화 할 수있는 경우 Reasonable대신 Messy, 이것은 당신이, 반부패 층에서 작업하고있는 의미 자신의 일을, 고정 자신의 디자인 실수를.

이에 반해 Adapter and Facade 는 기본 디자인의 품질을 가정하지 않습니다. 이것들은 특정 요구에 맞게 조정하여 시작하도록 잘 설계된 API에 적용될 수 있습니다.

실제로 AdapterFacade 와 같은 패턴이 기본 코드가 잘 설계 되어 있다고 가정하는 것이 더 생산적 일 수 있습니다. 잘 설계된 코드는 특정 사용 사례를 조정하기가 너무 어렵지 않아야합니다. 어댑터 설계에 예상보다 많은 노력이 소요되는 경우 기본 코드가 "손상된"것일 수 있습니다. 이 경우 작업을 별도의 단계로 분할하는 것을 고려할 수 있습니다. 먼저, 기본 API를 올바르게 구조화 된 방식으로 표시하기 위해 반부패 계층을 설정 한 다음 해당 보호 계층 위에 어댑터 / 파사드를 설계하십시오.


1
종속 API 클래스의 전체 구조가있는 경우 어떻게 확장합니까? 애플리케이션의 나머지 부분을 보호하는 계층보다 여전히 관리하기 쉽습니까?
knownasilya

1
@Knownasilya 아주 좋은 질문입니다. 답변을 확대하기 위해 확장
gnat

4
In other words, make sure that your API is indeed an improvement over one it hides, make sure that you don't just introduce another layer of corruption.전체 섹션은 굵은 글씨로 표시됩니다.
Lilienthal

19
부패 방지 계층은 품질이 낮은 API를 처리하는 것과 관련이 없습니다. 그것들은 개념적 불일치를 다루고, 우리가 더 쉽게 사용할 수있는 도메인에 코드를 "손상"함으로써 만 사용할 수있는 도메인을 조정하는 것에 관한 것입니다.
Ian Fairman 2016 년

8
이안 페어 맨이 옳았지만이 답변의 저자는 확실히 그렇지 않았습니다. 당신이 개념합니다 (DDD 책)의 소스에 가면, 당신이 대답을 모순 적어도 두 가지를 찾을 수 있습니다 : 1) 반부패 층이 손상되지 않도록 만들어 우리가 개발하고 새로운 도메인 모델 요소를 기존 외부 시스템의 모델에서; 다른 시스템이 "손상"된 것은 아니며 실제로 완벽하게 우수하고 잘 설계되어있을 수 있습니다. 2) 부패 방지 계층은 일반적으로 종종 여러 클래스가 포함됩니다 포함 외관어댑터 뿐만 아니라, 서비스 .
Rogério

41

다른 출처를 인용하려면 :

클라이언트에게 자체 도메인 모델의 기능을 제공하기 위해 격리 계층을 만듭니다. 계층은 기존 인터페이스를 통해 다른 시스템과 통신하므로 다른 시스템을 거의 수정하지 않아도됩니다. 내부적으로 레이어는 두 모델간에 필요에 따라 양방향으로 변환됩니다.

Eric Evans, 도메인 기반 디자인, 16 번째 인쇄, 365 페이지

가장 중요한 것은 부패 방지 계층의 각 측면에 다른 용어가 사용된다는 것입니다. 한 번은 운송 물류 시스템을 작업했습니다. 라운드를 계획해야했습니다. 차량을 창고에 설치하고 다른 고객 사이트로 운전하여 서비스를 제공하고 탱크 정류장과 같은 다른 장소를 방문해야했습니다. 그러나 높은 수준에서 이것은 모든 작업 계획에 관한 것이 었습니다. 따라서보다 일반적인 작업 계획 용어를 매우 구체적인 운송 물류 용어와 분리하는 것이 합리적이었습니다.

따라서 부패 방지 계층 격리는 복잡한 코드로부터 사용자를 보호하는 것이 아니라 다른 도메인을 분리하여 향후 분리 상태를 유지하는 것입니다.


6
이건 매우 중요합니다! ACL은 지저분한 코드와 함께 사용되는 것이 아니라 제한된 컨텍스트간에 통신하는 수단으로 사용됩니다. 한 컨텍스트에서 다른 컨텍스트로 변환되므로 각 컨텍스트의 데이터는 언어 및 해당 컨텍스트가 데이터에 대해 생각하고 이야기하는 방식을 반영합니다.
Didier A.

29

개 작자, 번안 자, 제작자

호환되지 않는 인터페이스가있는 경우 유사한 논리를 수행하여 다른 인터페이스를 조정하여 다른 인터페이스를 기대하는 것과 함께 하나의 구현을 사용할 수 있습니다.

예:

Car를 원하는 객체가 있지만 4WheelVehicle 클래스 만 있으므로 CarBuiltUsing4WheelVehicle을 만들어이를 Car로 사용하십시오.

정면

복잡하고 혼란스럽고 거대한 API가 있고 더 단순하고 명확하고 작게 만들고 싶을 때. 복잡성 / 혼동 / 추가 정보를 숨기고 새로운 단순 / 명확한 / 작은 API 만 노출하는 Facade를 작성합니다.

예:

100 가지 방법이있는 라이브러리를 사용하고 특정 작업을 수행하려면 초기화, 연결, 열기 / 닫기, 마지막으로 원하는 작업을 수행하기 위해 많은 작업을 수행해야하며 원하는 것은 1 가지 기능 중 하나입니다. 라이브러리는 모두 50 개가 수행 할 수 있으므로 필요한 1 가지 기능에 대한 방법 만 있고 모든 초기화, 청소 등을 수행하는 Facade를 작성하십시오.

반부패 레이어

도메인 외부에있는 시스템이 있지만 비즈니스 요구 사항에 따라 다른 도메인과 작업해야합니다. 이 다른 도메인을 자신의 도메인에 도입하고 싶지 않아 손상 시키므로 도메인 개념을이 다른 도메인으로 변환하거나 그 반대로 변환해야합니다.

예:

하나의 시스템은 각 트랜잭션마다 하나씩, 이름과 문자열 목록을 가진 고객을 봅니다. 프로파일은 이름이있는 독립형 클래스로, 트랜잭션은 문자열이있는 독립형 클래스로, 고객은 프로파일 및 트랜잭션 콜렉션을 갖는 것으로 간주합니다.

따라서 고객과 다른 시스템 고객간에 변환 할 수있는 ACL 계층을 만듭니다. 이런 식으로 다른 시스템의 고객을 사용할 필요가 없으며 ACL에 다음과 같이 간단히 말하면됩니다. "고객에게 프로파일 X를 제공하면 ACL이 다른 시스템에 고객에게 X.name이라는 이름을 부여하도록 지시하고 리턴합니다. 프로필 X를 보유한 고객

====================

세 가지 모두 모두 간접적 패턴이기 때문에 비교적 유사합니다. 그러나 서로 다른 구조, 클래스 / 객체, API 및 모듈 / 하위 시스템을 다룹니다. 필요한 경우 모두 결합 할 수 있습니다. 하위 시스템에는 복잡한 API가 있으므로 FACADE를 빌드하고 다른 모델을 사용하므로 모델에 맞지 않는 각 데이터 표현에 대해 해당 데이터를 모델링 방식으로 다시 변환합니다. 마지막으로, 인터페이스도 호환되지 않을 수 있으므로 ADAPTERS를 사용하여 서로 적응할 수 있습니다.


12

여기서 많은 답변에 따르면 ACL은 지저분한 코드를 래핑하는 것만이 아닙니다. 나는 더 나아가 그들이 전혀 그것에 대해 말하지 않았고, 그렇게한다면 그것은 부수적 인 이점입니다.

부패 방지 계층은 한 도메인을 다른 도메인에 매핑하여 두 번째 도메인을 사용하는 서비스가 첫 번째 개념에서 "손상"될 필요가 없도록하는 것입니다. ACL은 클래스에 대한 어댑터를 도메인 모델로, 다른 수준에서 발생합니다. 어댑터는 틀림없이 가장 중요한 디자인 패턴입니다. 항상 사용합니다. 그러나 랩핑 된 클래스를 지저분한 것으로 판단하는 것은 무의미합니다. 그것이 무엇인지, 다른 인터페이스가 필요합니다.

혼란에 초점을 맞추는 것은 오도의 소지가 있으며 DDD에 관한 요점을 놓치고 있습니다. ACL은 품질이 떨어지는 것이 아니라 개념적 불일치를 처리하는 것입니다.

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