타사 라이브러리 사용-항상 래퍼를 사용합니까?


78

내가 참여한 대부분의 프로젝트는 여러 오픈 소스 구성 요소를 사용합니다. 일반적으로 코드의 모든 구성 요소를 타사 라이브러리에 바인딩하지 말고 캡슐화 래퍼를 사용하여 변경의 고통을 피하는 것이 좋습니다.

예를 들어, 대부분의 PHP 프로젝트는 log4php를 로깅 프레임 워크로 직접 사용합니다. 즉, \ Logger :: getLogger ()를 통해 인스턴스화하고-> info () 또는-> warn () 메소드 등을 사용합니다. 그러나 어떤 방식으로 더 나은 가상 로깅 프레임 워크가 나타날 수 있습니다. log4php 메소드 서명과 밀접하게 관련된 모든 프로젝트는 새로운 서명에 맞추기 위해 수십 곳에서 변경되어야합니다. 이것은 분명히 코드베이스에 큰 영향을 미치며 모든 변경은 잠재적 인 문제입니다.

이런 종류의 시나리오에서 미래를 보장하는 새로운 코드베이스를 위해 필자는 종종 래퍼 클래스를 고려하여 로깅 기능을 캡슐화하고 최소한의 변경으로 로깅이 작동하는 방식을 변경하기가 쉽지는 않지만 완벽합니다. ; 코드는 래퍼를 호출하고 래퍼는 호출을 로깅 프레임 워크 du jour 로 전달합니다 .

다른 라이브러리에는 더 복잡한 예제가 있다는 것을 명심하십시오. 나는 너무 공학적입니까, 아니면 대부분의 경우 현명한 예방책입니까?

편집 : 추가 고려 사항-종속성 주입 및 테스트 두 배를 사용하려면 실제로 대부분의 API를 추상화해야합니다 ( "코드를 실행하고 상태를 업데이트하지만 로그 주석을 작성하거나 실제 데이터베이스에 액세스하지는 않습니다"). 이것은 결정자가 아닌가?


3
log4XYZ는 강력한 상표입니다. 연결된 목록에 대한 API가 변경 될 때보 다 더 빨리 API가 변경됩니다. 둘 다 이제 오랫동안 해결 된 문제입니다.
Job

1
이 SO 질문의 정확한 중복 : stackoverflow.com/questions/1916030/...
마이클 Borgwardt

1
당신이 그것을 내부적으로 사용한다면, 포장 여부는 현재 알려진 작업과 나중에 가능한 작업 사이의 균형입니다. 판결 요청. 그러나 다른 응답자들이 이야기를 소홀히 한 것으로 보이는 것은 API 의존성인지 구현 의존성 인지 여부 입니다. 즉, 자체 API를 통해이 타사 API에서 클래스를 유출하여 사용자에게 노출하고 있습니까? 이 경우 더 이상 다른 라이브러리로 이동하기가 쉽지만 문제는 이제 자체 API를 손상시키지 않으면 불가능하다는 것 입니다. 이것은 매우 나쁘다!
Elias Vasylenko 2016 년

1
더 참고 :이 패턴이라고 양파 아키텍처 인터페이스 뒤에 숨겨져 외부 인프라 (외부 lib 디렉토리를 호출)
K3B

답변:


42

타사 API의 작은 하위 집합 만 사용하는 경우 래퍼를 작성하는 것이 좋습니다. 이는 캡슐화 및 정보 숨기기에 도움이되므로 큰 API를 자신의 코드에 노출시키지 않습니다. 또한 사용 하지 않으려 기능 이 "숨겨져" 있는지 확인하는 데 도움이 될 수 있습니다 .

당신이 경우 래퍼에 대한 또 다른 좋은 이유는 기대 타사 라이브러리를 변경할 수 있습니다. 이것은 당신이 인프라의 조각 인 경우 알고 당신이 변경되지 않습니다, 그것은 래퍼를 작성하지 않습니다.


좋은 지적이지만, 우리는 잘 이해 된 많은 이유로 (테스트하기 어렵고, 리팩토링하기 어려운 등) 밀접하게 연결된 코드가 나쁘다는 것을 배웁니다. 이 질문의 다른 표현은 "커플 링이 나쁘면 왜 API에 연결해도 되는가?"입니다.
lotsoffreetime

7
@lotsoffreetime API에 대한 일부 연결을 피할 수 없습니다. 따라서 자신의 API에 연결하는 것이 좋습니다. 이렇게하면 라이브러리를 변경할 수 있으며 일반적으로 랩퍼에서 제공하는 API를 변경할 필요가 없습니다.
George Marian

@ george-marian 주어진 API를 사용 하지 않으면 터치 포인트를 최소화 할 수 있습니다. 문제는, 내가 항상 이것을 시도해야 하는가 아니면 그것을 과장하는 것입니까?
lotsoffreetime

2
@lotsoffreetime 답하기 어려운 질문입니다. 나는 그 끝까지 내 대답을 확장했다. (기본적으로, 그것은 많은 경우에 달려 있습니다.)
George Marian

2
@lotsoffreetime : 자유 시간이 많으면 둘 중 하나를 수행 할 수 있습니다. 그러나이 조건을 제외하고는 API 래퍼를 작성하지 않는 것이 좋습니다 .1) 원래 API는 매우 낮은 수준이므로 특정 프로젝트 요구에 더 적합하도록 더 높은 수준의 API를 작성하거나 2) 가까운 장래에 라이브러리를 전환하려면 현재 라이브러리를 더 나은 라이브러리를 찾는 동안 디딤돌로만 사용합니다.
Lie Ryan

28

미래에 개선 된 로거로 추정되는이 새로운 기능이 무엇인지 모른다면 어떻게 래퍼를 작성하겠습니까? 가장 논리적 인 선택은 래퍼가 일종의 로거 클래스를 인스턴스화하고 ->info()또는 같은 메소드를 갖는 것 ->warn()입니다. 다시 말해, 현재 API와 본질적으로 동일합니다.

변경할 필요가 없거나 어쨌든 피할 수없는 재 작성이 필요한 미래 보장 코드가 아니라 "과거 방지"코드를 선호합니다. 그건 내가 크게 구성 요소를 변경하려면 어떻게해야합니까 드문 경우에,이다 그건 내가 과거의 코드와 호환되도록하는 래퍼를 쓸 때. 그러나 모든 새 코드는 새 API를 사용하며 어쨌든 동일한 파일을 변경하거나 일정이 허용 할 때마다 이전 코드를 리 팩터하여 사용합니다. 몇 개월 후 래퍼를 제거 할 수 있으며 변경 사항이 점차적이고 강력 해졌습니다.

다시 말해서, 랩퍼는 랩해야하는 모든 API를 이미 알고있을 때만 의미가 있습니다. 응용 프로그램이 현재 다양한 데이터베이스 드라이버, 운영 체제 또는 PHP 버전을 지원해야하는 경우를 예로들 수 있습니다.


"... 래퍼는 래핑해야하는 모든 API를 이미 알고있을 때만 의미가 있습니다." 래퍼의 API와 일치하는 경우에도 마찬가지입니다. 아마도 "포장"이라는 용어를 래퍼보다 더 강력하게 사용해야 할 것입니다. 이 API 호출을 추상화하여 "이 매개 변수로 foo :: log ()를 호출"하는 대신 "이 텍스트를 어떻게 든 로깅"하는 것입니다.
lotsoffreetime

"향후 개선 된 로거로 추정되는이 새로운 기능이 무엇인지 알지 못하면 래퍼를 어떻게 작성하겠습니까?" 아래 @ kevin-cline은 새로운 기능보다는 더 나은 성능을 갖춘 미래의 로거를 언급합니다. 이 경우 랩핑 할 새 API가없고 다른 팩토리 메소드 일뿐입니다.
lotsoffreetime

27

써드 파티 라이브러리를 랩핑하여 그 위에 추가 추상화 계층을 추가합니다. 몇 가지 장점이 있습니다.

  • 코드베이스가 변경에보다 유연 해집니다

    라이브러리를 다른 라이브러리로 교체해야하는 경우 래퍼에서 구현 을 한곳 에서 변경하면됩니다 . 래퍼의 구현을 변경할 수 있으며 다른 것에 대해 변경할 필요가 없습니다. 즉, 느슨하게 연결된 시스템을 가지고 있습니다. 그렇지 않으면 전체 코드베이스를 살펴보고 어디에서나 수정해야합니다. 원하는 것은 아닙니다.

  • 라이브러리의 API와 독립적으로 랩퍼의 API를 정의 할 수 있습니다.

    다른 라이브러리는 매우 다른 API를 가질 수 있으며 동시에 필요한 것은 아닙니다. 일부 라이브러리는 모든 호출과 함께 토큰을 전달해야하는 경우 어떻게합니까? 라이브러리를 사용해야 할 때마다 앱에서 토큰을 전달하거나 더 중앙 어딘가에 안전하게 보관할 수 있지만 어쨌든 토큰이 필요합니다. 래퍼 클래스는이 모든 것을 다시 간단하게 만듭니다. 왜냐하면 토큰을 래퍼 클래스 내부에 유지하고 앱의 어떤 구성 요소에도 토큰을 노출시키지 않고 필요를 완전히 추상화 할 수 있기 때문입니다. 좋은 API 디자인을 강조하지 않는 라이브러리를 사용하면 큰 이점이 있습니다.

  • 단위 테스트가 훨씬 간단합니다

    단위 테스트는 한 가지만 테스트해야합니다. 클래스를 단위 테스트하려면 종속성을 조롱해야합니다. 해당 클래스가 네트워크 호출을하거나 소프트웨어 외부의 다른 리소스에 액세스하는 경우 더욱 중요합니다. 타사 라이브러리를 래핑하면 해당 호출을 조롱하고 테스트 데이터 또는 단위 테스트에 필요한 모든 것을 쉽게 반환 할 수 있습니다. 이러한 추상화 계층이 없으면이 작업을 수행하기가 훨씬 어려워집니다. 대부분의 경우 이로 인해 많은 추악한 코드가 생성됩니다.

  • 느슨하게 연결된 시스템을 만듭니다

    최소한 래퍼의 동작을 변경하지 않는 한 래퍼를 변경해도 소프트웨어의 다른 부분에는 영향을 미치지 않습니다. 이 래퍼와 같은 추상화 계층을 도입하면 라이브러리 호출을 단순화하고 해당 라이브러리에서 앱의 종속성을 거의 완전히 제거 할 수 있습니다. 소프트웨어는 래퍼 만 사용하므로 래퍼의 구현 방법이나 작동 방식에 차이가 없습니다.


실제 예

솔직 해지자 사람들은 몇 시간 동안 이와 같은 장점과 단점에 대해 논쟁 할 수 있습니다. 그래서 나는 단지 당신에게 예를 보여줍니다.

일종의 Android 앱이 있고 이미지를 다운로드해야한다고 가정 해 봅시다. Picasso 또는 Universal Image Loader 와 같이 이미지를로드하고 캐싱하는 바람이 많은 라이브러리가 있습니다 .

이제 우리가 사용하는 라이브러리를 래핑하는 데 사용할 인터페이스를 정의 할 수 있습니다.

public interface ImageService {
    Bitmap load(String url);
}

이미지를로드해야 할 때마다 앱 전체에서 사용할 수있는 인터페이스입니다. 이 인터페이스의 구현을 만들고 의존성 주입을 사용하여 우리가 사용하는 모든 곳에서 해당 구현의 인스턴스를 주입 할 수 있습니다 ImageService.

처음에 Picasso를 사용하기로 결정했다고 가정 해 봅시다. ImageService내부적으로 Picasso를 사용 하는 구현을 작성할 수 있습니다 .

public class PicassoImageService implements ImageService {

    private final Context mContext;

    public PicassoImageService(Context context) {
        mContext = context;
    }

    @Override
    public Bitmap load(String url) {
        return Picasso.with(mContext).load(url).get();
    }
}

당신이 나에게 물어 보면 꽤 똑바로. 라이브러리를 둘러싼 래퍼가 유용하기 위해 복잡 할 필요는 없습니다. 인터페이스와 구현은 25 줄 미만의 코드 라인을 가지고 있으므로 이것을 만들기위한 노력은 거의 없었지만 이미 우리는 이것을 수행하여 무언가를 얻습니다. Context구현 의 필드를 보시겠습니까? 당신이 선택한 의존성 주입 프레임 워크는 우리가 사용하기 전에 이미 의존성을 주입하는 것을 관리 할 것입니다. ImageService이제 앱은 이미지 다운로드 방법과 라이브러리가 가질 수있는 의존성을 신경 쓰지 않아도됩니다. 귀하의 모든 앱 ImageService은 이미지 load()이며 URL 이 필요한 이미지가 필요할 때 간단하고 간단합니다.

그러나 우리가 변화를 시작할 때 진정한 이점이 있습니다. Picasso가 현재 우리에게 절대적으로 필요한 기능을 지원하지 않기 때문에 Picasso를 Universal Image Loader로 교체해야한다고 상상해보십시오. 이제 코드베이스를 훑어보고 Picasso에 대한 모든 호출을 정중하게 바꾼 다음 몇 개의 Picasso 호출을 잊었 기 때문에 수십 개의 컴파일 오류를 처리해야합니까? 아닙니다. 우리가해야 할 일은 새로운 구현을 만들고 ImageService의존성 주입 프레임 워크에 지금부터이 구현을 사용하도록 지시하는 것입니다.

public class UniversalImageLoaderImageService implements ImageService {

    private final ImageLoader mImageLoader;

    public UniversalImageLoaderImageService(Context context) {

        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .build();

        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
                .defaultDisplayImageOptions(defaultOptions)
                .build();

        mImageLoader = ImageLoader.getInstance();
        mImageLoader.init(config);
    }

    @Override
    public Bitmap load(String url) {
        return mImageLoader.loadImageSync(url);
    }
}

보시다시피 구현은 매우 다를 수 있지만 중요하지 않습니다. 우리는 앱의 다른 곳에서 한 줄의 코드를 변경할 필요가 없었습니다. 우리는 완전히 다른 기능을 가지고 있거나 매우 다르게 사용될 수있는 완전히 다른 라이브러리를 사용하지만 앱은 신경 쓰지 않습니다. 우리 앱의 나머지 부분과 마찬가지로 ImageService인터페이스가 load()메소드와 인터페이스를 보지만 이 메소드는 더 이상 중요하지 않습니다.

적어도 나에게는이 모든 것이 이미 꽤 훌륭하게 들리지만 기다리십시오! 아직도 더 있습니다. 작업중인 클래스에 대해 단위 테스트를 작성하고이 클래스에서를 사용한다고 가정하십시오 ImageService. 물론 단위 테스트가 다른 서버에있는 일부 리소스에 대한 네트워크 호출을 할 수는 없지만 이제는 사용하고 있으므로 모의 객체를 구현하여 단위 테스트에 사용되는 정적을 ImageService쉽게 load()반환 할 수 있습니다 .BitmapImageService

public class MockImageService implements ImageService {

    private final Bitmap mMockBitmap;

    public MockImageService(Bitmap mockBitmap) {
        mMockBitmap = mockBitmap;
    }

    @Override
    public Bitmap load(String url) {
        return mMockBitmap;
    }
}

타사 라이브러리를 래핑하여 요약하면 코드베이스가 변경에보다 유연 해지고, 전체적으로 간단하고, 테스트하기가 쉬워지고, 소프트웨어의 여러 구성 요소의 결합을 줄일 수 있습니다.


1
이것은 불안정한 API에도 적용됩니다. 우리의 코드는 기본 라이브러리가 변경 되었기 때문에 1000 곳에서 변경되지 않습니다. 아주 좋은 대답입니다.
RubberDuck

매우 간결하고 명확한 답변. 웹에서 프런트 엔드 작업을합니다. 그 풍경의 변화량은 미쳤다. 사람들이 자신의 변화가 없다고 "생각"한다고해서 아무런 변화가 없음을 의미하지는 않습니다. 나는 YAGNI에 대한 언급을 보았다. 나는 새로운 약어 YDKYAGNI를 추가하고 싶습니다. 특히 웹 관련 구현의 경우. 원칙적으로 나는 항상 작은 API (예 : select2) 만 노출시키는 라이브러리를 래핑합니다. 더 큰 라이브러리는 아키텍처에 영향을 미치며 랩핑하면 아키텍처가 변경 될 것으로 예상되지만 변경 가능성은 적습니다.
Byebye

귀하의 답변은 매우 도움이되었으며 예를 들어 개념을 제시하면 개념이 더욱 명확 해졌습니다.
Anil Gorthy

24

내일 더 좋은 일이 발생할 경우를 대비하여 오늘날 타사 라이브러리를 래핑하는 것은 YAGNI를 매우 낭비하는 것이라고 생각합니다. 응용 프로그램 고유의 방식으로 타사 코드를 반복해서 호출하는 경우 반복을 제거하기 위해 해당 호출을 랩핑 클래스로 리팩토링해야합니다. 그렇지 않으면 라이브러리 API를 완전히 사용하고 있으며 래퍼는 라이브러리 자체와 같습니다.

이제 새로운 라이브러리가 우수한 성능 또는 다른 것으로 나타납니다. 첫 번째 경우 새 API의 래퍼를 다시 작성하기 만하면됩니다. 문제 없어요.

두 번째 경우에는 기존 인터페이스를 적용하여 새 라이브러리를 구동하는 래퍼를 만듭니다. 랩퍼를 먼저 작성한 경우에는 더 많은 작업이 필요하지만 문제가 없으며 더 이상 할 일이 없습니다.


4
나는이 상황에서 YAGNI가 반드시 적용된다고 생각하지 않습니다. 미래에 필요할 경우를 대비하여 기능을 구축하는 것이 아닙니다. 아키텍처에 유연성을 구축하는 것입니다. 유연성이 필요하지 않다면 YAGNI가 적용됩니다. 그러나 그 결정을 내리는 것이 어려울 때 언젠가는 그 결정이 내려지는 경향이 있습니다.
George Marian

7
@ 조지 마리안 (George Marian) : 문제의 시간은 95 %이므로 변경하는 데 유연성이 필요하지 않습니다. 성능이 우수한 미래의 새 라이브러리로 전환해야하는 경우 호출을 검색 / 교체하거나 필요할 때 래퍼를 작성하는 것이 매우 간단합니다. 반면, 새 라이브러리에 다른 기능이 제공되는 경우 래퍼는 이제 두 가지 문제가 있습니다. 이전 코드를 이식하여 새 기능을 활용하고 래퍼를 유지하는 두 가지 문제가 있습니다.
Lie Ryan

3
@lotsoffreetime : "좋은 디자인"의 목적은 수명 동안 응용 프로그램의 총 비용을 최소화하는 것입니다. 미래의 미래 변화에 대한 간접적 인 계층을 추가하는 것은 매우 비싼 보험입니다. 나는 아무도 그 접근 방식으로 어떤 절약 효과를 깨닫는 것을 보지 못했습니다. 고객 별 요구 사항에 훨씬 더 많은 시간을 할애하는 프로그래머에게는 사소한 일을 만듭니다. 대부분 고객에게 고유하지 않은 코드를 작성하는 경우 시간과 비용이 낭비됩니다.
kevin cline

1
@George : 이러한 변화가 고통 스럽다면 프로세스 냄새라고 생각합니다. Java에서는 이전 클래스와 동일한 이름으로 새 클래스를 작성하지만 다른 패키지에서는 이전 패키지 이름의 모든 발생을 변경하고 자동화 된 테스트를 다시 실행합니다.
케빈 클라인

1
@kevin 그것은 단순히 래퍼를 업데이트하고 테스트를 실행하는 것보다 더 많은 작업이므로 더 많은 위험을 수반합니다.
George Marian

9

타사 라이브러리 주위에 랩퍼를 작성하는 기본 이유는 해당 라이브러리를 사용하는 코드를 변경하지 않고 해당 타사 라이브러리를 교환 할 수 있기 때문입니다. 무언가에 대한 연결을 피할 수 없으므로 작성한 API에 연결하는 것이 좋습니다.

이것이 노력할 가치가 있는지 아닌지는 다른 이야기입니다. 그 논쟁은 오랫동안 계속 될 것입니다.

그러한 변경이 필요할 가능성이 적은 소규모 프로젝트의 경우, 아마도 불필요한 노력 일 것입니다. 대규모 프로젝트의 경우 이러한 유연성이 라이브러리를 감싸는 추가 노력보다 훨씬 뛰어납니다. 그러나 그것이 사전에 해당되는지 여부를 아는 것은 어렵습니다.

그것을 보는 또 다른 방법은 변경 될 가능성을 추상화하는 기본 원칙입니다. 따라서 타사 라이브러리가 제대로 설정되어 있고 변경되지 않을 경우 랩핑하지 않는 것이 좋습니다. 그러나 타사 라이브러리가 비교적 새로운 라이브러리 인 경우 교체해야 할 가능성이 더 큽니다. 즉, 기존 도서관의 개발은 여러 번 포기되었다. 따라서 이것은 쉬운 질문이 아닙니다.


API 모형을 주입 할 수있는 단위 테스트의 경우 테스트중인 단위를 최소화하는 역할을하며 "전위 변경"은 중요하지 않습니다. 말했듯이, 이것은 내가 생각하는 방식에 가장 가깝기 때문에 여전히 내가 가장 좋아하는 대답입니다. 밥 아저씨가 뭐라고 하겠어? :)
lotsoffreetime

또한 소규모 프로젝트 (팀, 기본 사양 등)에는 이와 같은 모범 사례를 위반하고 어느 정도 벗어날 수있는 자체 규칙이 있습니다. 그러나 그것은 다른 질문입니다.
lotsoffreetime

1

@Oded가 이미 말한 것 외에도 로깅의 특별한 목적 으로이 답변을 추가하고 싶습니다.


항상 로깅을위한 인터페이스가 있지만 log4foo아직 프레임 워크 를 대체 할 필요는 없습니다 .

인터페이스를 제공하고 래퍼를 작성하는 데 30 분 밖에 걸리지 않으므로 불필요한 것으로 판명되면 너무 많은 시간을 낭비하지 않는 것 같습니다.

YAGNI의 특별한 경우입니다. 필요하지는 않지만 많은 시간이 걸리지 않으며 더 안전합니다. 로거를 교환하는 날이 다가 오면 실제 프로젝트에서 전화를 교환하는 하루 이상을 절약 할 수 있기 때문에 30 분을 투자하게되어 기쁩니다. 그리고 로깅을위한 단위 테스트를 작성하거나 보지 못했습니다 (로거 구현 자체 테스트 제외). 래퍼가없는 결함을 기대하십시오.


log4foo를 변경하지는 않지만 널리 알려져 있으며 예제로 사용됩니다. 또한 지금까지 두 가지 답변이 어떻게 보완 적인지 흥미 롭습니다. "항상 랩하지는 마십시오"; "경우에 따라 포장".
lotsoffreetime

@ 팔콘 : 당신은 모든 것을 포장합니까? ORM, 로그 인터페이스, 핵심 언어 클래스? 결국, 더 나은 HashMap이 언제 필요할지 알 수 없습니다.
케빈 클라인

1

현재 진행중인 프로젝트 에서이 정확한 문제를 다루고 있습니다. 그러나 필자의 경우 라이브러리는 그래픽을위한 것이므로 그래픽을 다루는 소수의 클래스로 사용하는 것을 전체 프로젝트에 뿌려주는 것보다 제한 할 수 있습니다. 따라서 필요한 경우 나중에 API를 전환하는 것이 매우 쉽습니다. 로거의 경우 문제가 훨씬 더 복잡해집니다.

따라서 나는 그 결정이 제 3 자 라이브러리가 정확히 무엇을하고 있는지와 그것을 바꾸는 데 얼마나 많은 고통이 있는지와 관련이 있다고 말합니다. 모든 API 호출을 쉽게 변경할 수 있다면 아마도 가치가 없을 것입니다. 그러나 나중에 라이브러리를 변경하는 것이 정말로 어려울 경우 아마 지금 포장 할 것입니다.


그 외에도 다른 답변이 주요 질문을 잘 다루었으므로 종속성 주입 및 모의 객체에 대한 마지막 추가 사항에 초점을 맞추고 싶습니다. 물론 로깅 프레임 워크가 정확히 작동하는 방식에 달려 있지만 대부분의 경우 래퍼가 필요하지 않습니다 (아마도 하나의 이점이 있지만). 모의 객체에 대한 API를 타사 라이브러리와 정확히 동일하게 만든 다음 모의 객체를 쉽게 교체하여 테스트 할 수 있습니다.

여기서 주요 요인은 타사 라이브러리가 종속성 주입 (또는 서비스 로케이터 또는 이와 같이 느슨하게 연결된 패턴)을 통해 구현되는지 여부입니다. 라이브러리 함수가 싱글 톤 또는 정적 메소드 또는 무언가를 통해 액세스되는 경우 종속성 삽입에서 작업 할 수있는 오브젝트로 라이브러리 함수를 랩핑해야합니다.


1

나는 래핑 캠프에 강력하게 참여하고 있으며 타사 라이브러리를 가장 우선 순위로 대체 할 수는 없습니다 (보상이지만). 포장을 선호하는 나의 주요 근거는 간단하다

타사 라이브러리는 특정 요구에 맞게 설계 되지 않았습니다 .

그리고 이것은 일반적으로 코드 복제의 보트로드 형태로 나타납니다. 개발자는 8 줄의 코드를 작성 QButton하여 응용 프로그램을 찾는 방식과 스타일을 지정하는 것입니다. 또한 전체 소프트웨어에 대해 완전히 변경되는 버튼의 기능으로 인해 수천 줄의 코드를 다시 작성하고 다시 작성해야하거나 렌더링 파이프 라인을 현대화하려면 서서히 다시 작성해야합니다. 실시간 렌더러 디자인을 중앙 집중화하고 OGL을 구현에 엄격하게 사용하지 않고 모든 곳에서 OpenGL 코드를 파이프 라인합니다.

이 디자인은되지 않습니다 맞는 우리의 특정 설계 요구에. 그들은 실제로 필요한 것의 거대한 수퍼 세트를 제공하는 경향이 있으며 (그리고 디자인의 일부가 아닌 것보다 중요하지 않은 것이 중요하지 않다), 그들의 인터페이스는 우리의 요구를 구체적으로 높은 수준의 "하나"로 처리하도록 설계되지 않았습니다. 생각 = 하나의 요청 "방식으로 직접 사용하는 경우 모든 중앙 디자인 제어가 필요하지 않습니다. 개발자가 필요한 것을 표현하는 데 필요한 것보다 훨씬 낮은 수준의 코드를 작성하는 경우 때로는 임시 방식으로 코드를 작성하여 수십 가지의 급하게 작성되고 조잡하게 작성 될 수 있습니다. 잘 디자인되고 잘 문서화 된 래퍼 대신 디자인되고 문서화 된 래퍼.

물론 래퍼가 타사 API가 제공하는 것의 거의 일대일 번역 인 라이브러리에는 강력한 예외를 적용합니다. 이 경우 비즈니스 및 디자인 요구 사항을보다 직접적으로 표현하는 더 높은 수준의 디자인을 찾을 필요가 없을 수 있습니다 ( "유틸리티"라이브러리와 더 유사한 것이있을 수 있습니다). 그러나 우리의 요구를 훨씬 더 직접적으로 표현할 수있는 훨씬 더 맞춤화 된 디자인이 있다면, 더 높은 수준의 기능을 사용하고 어셈블리 코드를 인라이닝하여 재사용하는 것을 강력하게 선호하는 것처럼 랩핑 캠프에 강력하게 참여합니다. 모든 곳에.

이상하게도 개발자가 버튼을 만들고 반환하는 기능에 대해 매우 불신하고 비관적 인 것처럼 보이는 방식으로 개발자와 충돌했습니다. 상기 기능의 설계 및 사용에 대한 버튼 생성 (향후에 반복적으로 변경 될 필요가 있음)에 대한 세부 사항. 우리가 이러한 종류의 포장지를 합리적으로 설계 할 수 있다고 믿지 않는다면 처음부터 무언가를 설계하려는 목적조차 보지 못합니다.

다른 방법으로는 제 3 자 라이브러리를 시스템 설계를 대신하는 것이 아니라 구현에서 막대한 시간을 절약 할 수있는 방법으로 생각합니다.


0

타사 라이브러리에 대한 나의 생각 :

최근 iOS 커뮤니티 에서 써드 파티 종속성 사용의 장단점 (주로 찬반 점)에 대한 토론 이있었습니다 . 내가 본 많은 주장은 다소 일반적인 것으로 모든 타사 라이브러리를 하나의 바구니로 묶습니다. 그러나 대부분의 경우와 마찬가지로 그렇게 간단하지 않습니다. 하나의 사례에 초점을 맞춰 봅시다

타사 UI 라이브러리를 사용하지 않아야합니까?

써드 파티 라이브러리를 고려해야하는 이유 :

개발자가 써드 파티 라이브러리를 사용하는 두 가지 주요 이유는 다음과 같습니다.

  1. 기술이나 지식 부족. 사진 공유 앱을 만들고 있다고 가정 해 보겠습니다. 자신의 암호를 말아서 시작하지 마십시오.
  2. 무언가를 만들 시간이나 관심 부족. 무제한의 시간이 없다면 (아직 사람이없는) 우선 순위를 정해야합니다.

대부분의 UI 라이브러리 ( 모두는 아닙니다! )는 두 번째 범주에 속합니다. 이 물건은 로켓 과학이 아니지만 그것을 올바르게 구축하는 데 시간이 걸립니다.

핵심 비즈니스 기능인 경우 무엇이든 관계없이 직접 수행하십시오.

컨트롤 /보기에는 거의 두 가지 유형이 있습니다.

  1. Generic 을 사용하면 제작자가 생각하지 않은 다양한 컨텍스트에서 사용할 수 있습니다 (예 : UICollectionViewfrom) UIKit.
  2. 특정, 예를 들어 하나의 사용 사례에 대한 설계 UIPickerView. 대부분의 타사 라이브러리는 두 번째 범주에 속합니다. 또한 최적화 된 기존 코드베이스에서 추출되는 경우가 많습니다.

알려지지 않은 초기 가정

많은 개발자가 내부 코드에 대한 코드 검토를 수행하지만 타사 소스 코드의 품질을 당연한 것으로 간주 할 수 있습니다. 라이브러리 코드를 탐색하는 데 약간의 시간이 소요됩니다. 불필요하게 사용되는 스위 즐링과 같은 붉은 깃발을보고 놀랄 수도 있습니다.

아이디어를 배우는 것이 결과 코드 자체를 얻는 것보다 종종 유익합니다.

숨길 수 없어

UIKit이 설계된 방식으로 인해 타사 UI 라이브러리 (예 : 어댑터 뒤)를 숨길 수 없습니다. 라이브러리는 UI 코드와 얽혀 프로젝트의 사실상이됩니다.

미래 시간 비용

UIKit은 각 iOS 릴리스마다 변경됩니다. 상황이 깨질 것입니다. 타사 종속성은 예상보다 유지 보수가 필요 없습니다.

결론 :

개인적인 경험으로 볼 때 대부분의 타사 UI 코드 사용은 약간의 유연성을 위해 약간의 시간이 소요됩니다.

우리는 기성품 코드를 사용하여 현재 릴리스를 더 빨리 배송합니다. 그러나 조만간 우리는 도서관의 한계에 부딪 히고 어려운 결정 앞에 서 있습니다.


0

라이브러리를 직접 사용하는 것이 개발자 팀에게 더 친숙합니다. 새로운 개발자가 합류하면 사용 된 모든 프레임 워크에 대한 경험이 풍부하지만 자체 개발 API를 배우기 전에는 생산적으로 기여할 수 없습니다. 젊은 개발자가 그룹에서 진행하려고 할 때 더 유용한 일반 역량을 획득하는 대신 다른 곳에 존재하지 않는 특정 API를 학습해야합니다. 누군가가 원래 API의 유용한 기능이나 가능성을 알고있는 경우이를 모르는 사람이 작성한 계층에 도달하지 못할 수 있습니다. 누군가 구직 중에 프로그래밍 작업을하는 경우, 그가 래퍼를 통해 필요한 기능에 액세스했기 때문에 그가 사용한 기본 사항을 여러 번 시연하지 못할 수도 있습니다.

이 문제는 나중에 완전히 다른 라이브러리를 사용하는 원격 가능성보다 더 중요하다고 생각합니다. 래퍼를 사용하는 유일한 경우는 다른 구현으로의 마이그레이션이 확실히 계획되었거나 랩핑 된 API가 충분히 고정되지 않고 계속 변경되는 경우입니다.

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