유연한 플러그인 아키텍처를 만드는 방법?


154

개발 작업에서 반복되는 주제는 사내 플러그인 아키텍처를 사용하거나 작성하는 것이 었습니다. 구성 파일 (XML, .conf 등), 상속 프레임 워크, 데이터베이스 정보, 라이브러리 등 여러 가지 방법으로 접근하는 것을 보았습니다. 내 경험상 :

  • 데이터베이스는 특히 데이터와 함께 구성 정보를 저장하기에 좋은 장소가 아닙니다.
  • 상속 계층 구조로 이것을 시도하려면 플러그인에 대한 지식이 필요합니다. 플러그인 아키텍처가 그다지 역동적이지는 않습니다.
  • 구성 파일은 간단한 정보를 제공하는 데 효과적이지만 더 복잡한 동작을 처리 할 수 ​​없습니다
  • 라이브러리는 잘 작동하는 것처럼 보이지만 단방향 종속성은 신중하게 만들어야합니다.

함께 일한 다양한 아키텍처에서 배우려고 노력하면서 커뮤니티에도 제안을 구하고 있습니다. SOLID 플러그인 아키텍처를 어떻게 구현 했습니까? 최악의 고장은 무엇입니까? 새로운 플러그인 아키텍처를 구현하려는 경우 어떻게 하시겠습니까? 함께 작업 한 SDK 또는 오픈 소스 프로젝트 중 가장 좋은 아키텍처의 예는 무엇입니까?

내가 직접 찾은 몇 가지 예 :

이 예제는 다양한 언어 강점으로 재생되는 것 같습니다. 좋은 플러그인 아키텍처는 반드시 언어와 연결되어 있습니까? 플러그인 아키텍처를 만들거나 자신의 다음 모델에서 도구를 사용하는 것이 가장 좋습니까?


플러그인 아키텍처가 일반적인 주제 인 이유를 말할 수 있습니까? 어떤 문제를 해결하거나 목표를 해결합니까? 많은 확장 가능한 시스템 / 응용 프로그램은 어떤 형태의 플러그인을 사용하지만, 해결되는 문제에 따라 형태가 상당히 다릅니다.
mdma

@mdma-좋은 질문입니다. 확장 가능한 시스템에는 몇 가지 공통된 목표가 있다고 말하고 싶습니다. 어쩌면 목표는 모든 것이 공통적 일 수 있으며 최상의 솔루션은 시스템의 확장 성, 시스템 작성 언어 등에 따라 달라집니다. 그러나 IOC와 같은 패턴이 많은 언어에 적용되는 것을 보았고 비슷한 플러그인 (동일한 기능 요청에 응답하는 조각을 위해)을 반복해서 반복하도록 요청 받았습니다. 다양한 유형의 플러그인에 대한 모범 사례에 대한 일반적인 아이디어를 얻는 것이 좋습니다.
justkt

답변:


89

이것은 잠재적으로 유용한 발언 / 예만큼 대답 이 아닙니다 .

  • 응용 프로그램을 확장 가능하게 만드는 효과적인 방법 중 하나는 내부를 스크립팅 언어로 노출하고 해당 언어로 모든 최상위 항목을 작성하는 것입니다. 이를 통해 수정 가능하고 실질적으로 미래의 증거가 될 수 있습니다 (원본이 잘 선택되고 구현 된 경우). 이런 종류의 성공 사례는 Emacs입니다. 기능을 확장하려는 경우 API를 배우고 별도의 플러그인을 작성 / 컴파일 할 필요가 없기 때문에 이클립스 스타일 플러그인 시스템을 선호합니다. 현재 버퍼 자체에 3 줄 스 니펫을 작성하고 평가하여 사용할 수 있습니다. 매우 부드러운 학습 곡선과 매우 즐거운 결과.

  • 내가 조금 확장 한 응용 프로그램은 Trac 입니다. 이 상황에서 확장 아키텍처를 알리는 모듈에 작업이 위임됨을 의미하는 구성 요소 아키텍처가 있습니다. 그런 다음 이러한 지점에 맞는 다른 구성 요소를 구현하고 흐름을 변경할 수 있습니다. 위의 Kalkie의 제안과 약간 같습니다.

  • 또 다른 좋은 방법은 py.test 입니다. "최상의 API는 API가 아닙니다"라는 철학을 따르고 있으며 모든 수준에서 호출되는 후크에 전적으로 의존합니다. 규칙에 따라 명명 된 파일 / 함수에서 이러한 후크를 무시하고 동작을 변경할 수 있습니다. 사이트에서 플러그인 목록을보고 얼마나 빠르고 쉽게 구현할 수 있는지 확인할 수 있습니다.

몇 가지 일반적인 사항.

  • 확장 가능하지 않거나 사용자가 수정할 수없는 코어를 가능한 작게 유지하십시오. 확장 성을 높이려면 가능한 한 모든 것을 상위 계층에 위임하십시오. 잘못된 선택의 경우 코어에서 수정해야 할 사항이 적습니다.
  • 위의 요점과 관련하여 처음에 프로젝트 방향에 대해 너무 많은 결정을 내려서는 안된다는 것입니다. 가장 작은 필수 서브 세트를 구현 한 후 플러그인 작성을 시작하십시오.
  • 당신이 스크립트 언어를 내장하는 경우, 반드시 그 전체는 일반적으로 프로그램을 작성할 수있는 일이 아닌 장난감 언어의 수 있도록 단지 응용 프로그램에 대한.
  • 상용구를 최대한 줄이십시오. 서브 클래 싱, 복잡한 API, 플러그인 등록 및 이와 유사한 것들을 신경 쓰지 마십시오. 그것에게 그것의 간단하므로 유지하려고 쉽게 만이 아니라 가능한 확장 할 수 있습니다. 이를 통해 플러그인 API를 더 많이 사용할 수 있으며 최종 사용자가 플러그인을 작성할 수 있습니다. 플러그인 개발자 만이 아닙니다. py.test가 이것을 잘합니다. 내가 아는 한 이클립스는 그렇지 않다 .

1
나는 스크립트 언어 포인트를 파이썬이나 펄과 같은 기존 언어를 포함시키는 것을 고려할 가치가 있다는 점으로 확장 할 것이다
Rudi

진정한 루디. 많은 언어들이이 언어를 포함하도록 설계되었습니다. 예를 들어 Guile은 임베딩 용으로 만 만들어졌습니다. 앱을 스크립팅 가능하게 만들면 시간이 절약됩니다. 이 언어 중 하나를 사용하면됩니다.
Noufal Ibrahim

24

필자의 경험에 따르면 실제로 두 가지 유형의 플러그인 아키텍처가 있습니다.

  1. 하나 Eclipse model는 자유를 허용하기위한 것이며 개방형입니다.
  2. 다른 하나 narrow API는 플러그인이 특정 기능 을 수행하기 때문에 일반적으로 플러그인을 따라야 합니다.

이것을 다른 방식으로 설명 하기 위해 하나 는 플러그인이 애플리케이션에 액세스하도록 허용 하고 다른 하나 는 애플리케이션이 플러그인에 액세스하도록 허용합니다 .

구별은 미묘하고 때로는 혼란이 없습니다 ... 당신은 응용 프로그램에 대해 둘 다 원합니다.

Eclipse에 대한 경험이 많지 / 플러그인 모델로 앱 열기 (Kalkie의 게시물의 기사는 훌륭합니다). 나는 일식이하는 방식에 대해 조금 읽었지만 그 이상은 아닙니다.

Yegge의 속성 블로그 는 속성 패턴을 사용하여 플러그인 및 확장 성을 허용하는 방법에 대해 설명합니다.

내가 한 대부분의 작업은 플러그인 아키텍처를 사용하여 내 앱이 플러그인, 시간 / 디스플레이 / 맵 데이터 등과 같은 것들에 액세스 할 수 있도록했습니다.

몇 년 전에 팩토리, 플러그인 관리자 및 구성 파일을 만들어 모든 것을 관리하고 런타임에 사용할 플러그인을 결정할 수있었습니다.

  • 이제 저는 보통 DI framework그 일을 대부분합니다.

타사 라이브러리를 사용하려면 여전히 어댑터를 작성해야하지만 일반적으로 그렇게 나쁘지는 않습니다.


@Justin 예, DI = 의존성 주입.
파생

14

내가 본 최고의 플러그인 아키텍처 중 하나는 Eclipse에서 구현됩니다. 플러그인 모델이있는 애플리케이션을 사용하는 대신 모든 것이 플러그인입니다. 기본 애플리케이션 자체는 플러그인 프레임 워크입니다.

http://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html


확실히 좋은 예이지만 많은 응용 프로그램이 필요로하는 것보다 더 크고 복잡합니까?
justkt

그렇습니다. 유연성의 증가에는 비용이 따릅니다. 그러나 나는 그것이 다른 견해를 보여주고 있다고 생각합니다. 애플리케이션의 메뉴가 플러그인 또는 기본보기가 아닌 이유는 무엇입니까?
Patrick

6
Symfony 프레임 워크의 새 버전에서는 동일한 접근 방식 (모든 것이 플러그인 임)이 사용됩니다. 그것들을 번들이라고하지만 원리는 동일합니다. 아키텍처는 상당히 단순하다. 아마도 살펴보아야한다 : symfony-reloaded.org/quick-tour-part-4
Marijn Huizendveld

@Marjin Huizendveld-답변을 찬성하려면 별도의 답변으로 추가해야합니다. 흥미로운 프레임 워크처럼 보입니다!
justkt

11

과거에 사용했던 상당히 간단한 기술에 대해 설명하겠습니다. 이 방법은 C # 리플렉션을 사용하여 플러그인 로딩 프로세스를 도와줍니다. 이 기술은 C ++에 적용 할 수 있도록 수정 될 수 있지만 리플렉션을 사용할 수 있다는 편의성을 잃게됩니다.

IPlugin인터페이스는 플러그인을 구현하는 클래스를 식별하는 데 사용됩니다. 애플리케이션이 플러그인과 통신 할 수 있도록 메소드가 인터페이스에 추가됩니다. 예를 들어, Init애플리케이션이 플러그인을 초기화하도록 지시하는 데 사용할 방법입니다.

플러그인을 찾기 위해 응용 프로그램은 플러그인 폴더에서 .Net 어셈블리를 검색합니다. 각 어셈블리가로드됩니다. 리플렉션은 구현하는 클래스를 검색하는 데 사용됩니다 IPlugin. 각 플러그인 클래스의 인스턴스가 작성됩니다.

(또는 Xml 파일은로드 할 어셈블리와 클래스를 나열 할 수 있습니다. 이는 성능에 도움이 될 수 있지만 성능 관련 문제는 찾지 못했습니다).

Init방법은 각 플러그인 객체에 대해 호출됩니다. 응용 프로그램 인터페이스를 구현하는 객체에 대한 참조가 전달됩니다 IApplication(또는 ITextEditorApplication과 같이 앱에 고유 한 이름이 지정된 항목).

IApplication플러그인이 애플리케이션과 통신 할 수 있도록하는 메소드가 포함되어 있습니다. 예를 들어 텍스트 편집기를 작성하는 경우이 인터페이스에는 OpenDocuments플러그인이 현재 열려있는 문서의 모음을 열거 할 수 있는 속성이 있습니다.

이 플러그인 시스템은 파생 플러그인 클래스 (예 : 함수 및 애플리케이션 인터페이스를 Lua 스크립트로 LuaPlugin전달) 를 생성하여 Lua와 같은 스크립팅 언어로 확장 될 수 있습니다 IPlugin.

이 기술은 반복하여 구현할 수 있습니다 IPlugin, IApplication개발 과정 및 기타 응용 프로그램 별 인터페이스를. 애플리케이션이 완성되고 리팩토링되면 노출 된 인터페이스를 문서화 할 수 있으며 사용자가 자신의 플러그인을 작성할 수있는 멋진 시스템이 있어야합니다.


7

평소에는 MEF를 사용합니다. Managed Extensibility Framework (또는 간단히 MEF)는 확장 가능한 응용 프로그램 작성을 단순화합니다. MEF는 응용 프로그램 확장을로드하는 데 활용할 수있는 검색 및 구성 기능을 제공합니다.

당신이 관심이 있다면 읽기 ...


고마워, 재미있어 보인다. 다른 언어로 유사한 원칙을 적용하는 것이 얼마나 쉬운가요?
justkt

실제로 MEF는 .NET 프레임 워크만을위한 것입니다. 다른 프레임 워크에 대해서는 아무것도 모릅니다.
BALKANGraph

7

한 번은 각 고객이 시스템을 설정할 수있는 방식으로 매우 유연해야하는 프로젝트를 수행 한 결과, C # 컴파일러를 고객에게 제공하는 것이 가장 좋은 디자인이었습니다!

사양이 다음과 같은 단어로 채워져있는 경우 :

  • 융통성 있는
  • 플러그인
  • 맞춤형

내 경험에서와 같이 시스템을 어떻게 지원할 것인지 (각 고객이 자신의 사례를 정상적인 경우라고 생각하고 플러그인을 필요로하지 않기 때문에 지원 비용이 청구되는 방법)에 대해 많은 질문을한다.

플러그인을 작성하는 고객 (혹은 지원자 지원)의 지원은 아키텍처보다 훨씬 어렵습니다.


5

필자의 경험에 따르면 유연한 플러그인 아키텍처를 만드는 가장 좋은 두 가지 방법은 스크립팅 언어와 라이브러리입니다. 이 두 개념은 직교하는 마음에 있습니다. 함수형 프로그래밍이나 객체 지향 프로그래밍과 같이 어떤 비율로든 혼합 할 수 있지만 균형을 잡을 때 가장 큰 장점을 찾을 수 있습니다. 라이브러리는 일반적으로 동적 기능 으로 특정 인터페이스 를 수행하는 반면 스크립트는 동적 인터페이스로 기능 을 강조하는 경향이 있습니다.

라이브러리를 관리하는 스크립트를 기반으로 한 아키텍처 가 가장 잘 작동하는 것으로 나타났습니다 . 스크립팅 언어를 사용하면 하위 수준 라이브러리를 높은 수준으로 조작 할 수 있으므로 라이브러리에 특정 인터페이스가 없어 모든 응용 프로그램 수준의 상호 작용이 스크립팅 시스템의 유연성을 향상시킵니다.

이것이 작동하려면 스크립팅 시스템은 애플리케이션 데이터, 로직 및 GUI에 대한 후크와 라이브러리에서 코드를 가져오고 실행하는 기본 기능을 갖춘 상당히 강력한 API를 가져야합니다. 또한 스크립트는 일반적으로 응용 프로그램에서 잘못 작성된 스크립트를 정상적으로 복구 할 수 있다는 점에서 안전 해야합니다 . 스크립트 시스템을 간접 계층으로 사용하면 Something Bad ™의 경우 응용 프로그램을보다 쉽게 ​​분리 할 수 ​​있습니다.

플러그인을 패키징하는 방법은 개인 취향에 따라 크게 다르지만 PluginName.ext루트 디렉토리 와 같이 간단한 인터페이스를 가진 압축 된 아카이브에서는 잘못 될 수 없습니다 .


3

먼저 "어떤 컴포넌트가 플러그인이 될 것으로 예상됩니까?"라는 질문에 먼저 대답해야한다고 생각합니다. 이 숫자를 절대 최소값으로 유지하거나 테스트해야하는 조합 수를 유지하려고합니다. 핵심 기능 (너무 유연하지 않아야 함)을 플러그인 기능과 분리하십시오.

IOC (Inversion of Control) 보안 주체 (스프링 프레임 워크 읽기)는 유연한 기반을 제공하는 데 효과적이며 플러그인 개발을 간소화하기 위해 전문화를 추가 할 수 있습니다.

  • 컨테이너에 "플러그인 유형 광고로 인터페이스"메커니즘이 있는지 스캔 할 수 있습니다.
  • 컨테이너를 사용하여 플러그인에 필요할 수있는 공통 종속성 (예 : ResourceLoaderAware 또는 MessageSourceAware)을 주입 할 수 있습니다.

1

플러그인 패턴은 깨끗한 인터페이스로 클래스의 동작을 확장하기위한 소프트웨어 패턴입니다. 파생 클래스가 클래스의 일부 가상 메서드를 덮어 쓰는 클래스 상속으로 클래스의 동작이 확장되는 경우가 많습니다. 이 솔루션의 문제점은 구현 숨기기와 충돌한다는 것입니다. 또한 파생 클래스가 관련없는 행동 확장의 모임 장소가되는 상황으로 이어집니다. 또한, 스크립팅은 위에서 언급 한 것처럼 "내부를 스크립팅 언어로 만들고 해당 언어로 모든 최상위 레벨의 내용을 작성합니다.이를 통해 수정 가능하고 실질적으로 미래의 증거가됩니다"라는 스크립팅이 사용됩니다. 라이브러리는 스크립트 관리 라이브러리를 사용합니다. 스크립팅 언어를 사용하면 하위 수준 라이브러리를 높은 수준으로 조작 할 수 있습니다. (또한 위에서 언급 한 바와 같이)

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