(내용 추가) WPF Prism 프레임워크의 장점과 단점?

여러분이 생각하시는 Prism 프레임워크의 장점과 단점에는 무엇이 있을까요?

실제로 사용해보신 분
사용해보진 않았지만 간접적으로 알고 계신 내용

사소한 부분부터 중요한 부분까지 폭넓게 정보를 모아보는 계기를 만들어보고자 합니다!

image

제가 외부적으로 수집한 내용을 조금 더 추가해보겠습니다. (출처: 동료들, 인터넷 검색)

장점

  • Prism 숙련도가 올라갈수록 퍼포먼스를 낼 수 있다.
  • 느슨한 결합으로 인해 분리된 업무 개발에 적합하고 MVVM을 다소 쉽게 구현할 수 있다.
  • Prism을 사용하면 Unity 및/또는 MEF를 IoC/DI 프레임워크로 사용할 수 있는 옵션이 있습니다. 또한 확장 가능합니다. 따라서 원하는 경우 다른 IoC 컨테이너를 플러그인할 수 있습니다.
  • MVVM, CompositeView, Event Aggregator 제공을 통해 각각의 object를 손쉽게 연결할 수 있다. (느슨한 결합)
  • MVVM 패턴을 편리하게 사용할 수 있으므로 생산성이 우수하다.
  • 유지보수에 있어 더 유리하다

단점

  • 전체적인 프로젝트 가독성에 영향을 준다. 느슨한 결합으로 인해 WPF 고유의 DataContext 흐름을 파악하기 어려울 수 있다.
  • 개발 과정에서 디버깅이 불편해진다. (호출스택 등)
  • DependencyProperty와 Turnneling을 활용한 이벤트 처리를 고민할 필요가 없어진다.
  • 느슨하게 처리해주는 부분이 되려 WPF 학습과 이해도를 떨어트릴 수 있는 우려가 있을 수 있다.
  • Prism 기술에 대한 숙련도를 올리기가 어렵다.
  • 구조적인 고민을 할 기회가 적어진다. 그러므로 나만의 프레임워크를 만들 기회를 만들기가 힘들 수 있다.
  • 신규 개발자가 유지보수를 하기가 더 힘들 수 있다.

그리고 프로그램 성격에 따라 도입 여부에 대한 생각도 궁금합니다.

  • 키오스크 애플리케이션
  • 모니터링 애플리케이션
  • 메신저 애플리케이션
  • 업무 화면이 수백 개인 데이터 관리 기반의 시스템
  • 깃허브 오픈소스 샘플 애플리케이션
  • 기타…
좋아요 3

장점은
CAB 형태로 개발을 할 수 있기에 기능 단위 또는 화면의 조각 단위로 분리해서 개발/설계가 가능하기 때문에
유지보수에 있어 더 효과적이라고 생각합니다. (특히 규모가 큰 프로젝트에서는요)
때문에 솔루션에 기능 활성/비활성 이 가능하도록 모듈단위로 쉽게 배포 가능케 해주는 것도 장점인듯하지만


단점은
무엇보다도 너무 무거운 프레임워크가 아닌가 생각합니다. 그렇게 때문에 개인적으로는
대형 프로젝트가 아닌 경우 굳이 프리즘을 사용할 필요는 없고
Microsoft.Toolkit.Mvvm 라이브러리 + 기타 필요한 부분 자체 제작
구성이 제일 베스트인 것 같습니다.

또 러닝커브가 약간 있는것도 단점이라고 생각합니다.

좋아요 3

Prism 으로 프로젝트를 하고 있습니다.

스택오버플로우에서도 언급하기도 했는데 Prism은 대형 프로젝트에 적합하다고 합니다.
저는 이 의견에 대해서는 조금 더 생각 해 볼 필요가 있다고 생각이 됩니다.

WPF/Winform에서 가장 작은 단위의 프로젝트라고 하면 간단한 window application을 작업하는 형태라고 생각 됩니다. 하지만 이런 형태의 소규모 프로젝트에서도 Prism은 아주 유용하다고 생각 됩니다. 특히나 연차가 쌓여 갈 수록 사용하게 되는 Component들이나 구성하게 되는 아키텍처가 정형화 됩니다.

Prism은 여기서 아주 큰 힘을 발휘 합니다. 코드 재사용성에 있어서는 정말 미쳤다고 생각이 듭니다.

예를 들어보죠. 저는 visual studio 형태의 메뉴바를 선호 하는데 메뉴바 자체를 Prism의 Module로 만들어 버리고 나중에 새로운 프로젝트를 할 때 그냥 모듈만 불러옵니다. 고객의 요구사항에 따라서 해당 메뉴바의 기능만 조금 고칩니다. 더해서, 모듈을 불러오는 코드도 단 몇줄이면 import 됩니다.

Prism 이전의 프로젝트 방식은 다시 한번 코딩 하는 것이였다면, Prism 사용 이후로는 단지 모듈을 import 하는 것만으로도 프로젝트를 진행 할 수 있습니다. (미리 만들어둔 dll을 사용한다는 느낌과는 좀 다릅니다.)

결론은 Prism의 숙련도가 올라가면 올라갈수록 작은 프로젝트에서도 훨씬더 빠른 작업이 가능하다고 말하고 싶습니다. 프로젝트의 크기와 상관없이 유지보수와 생산성이 엄청나게 올라간다고 생각하고 있습니다.

다만, Prism의 단점은 배워야할게 너무 많다는 것 입니다. 러닝커브가 오기까지 정말 시간이 너무 오래걸립니다.

Dependency injection과 Inversion of Control 의 이해는 물론이고 이를 프로젝트에서 자유자재로 다룰 수 있어야 합니다. 또 WPF/Winform의 깊은 이해와 C#언어에 대한 이해도 같이 필요하구요. 언어 뿐만이 아니라 기본적인 OOP 지식과 디자인 패턴을 숙지하고 있어야 합니다. 거기다가 MVVM의 이해도까지… 여기서 WPF가 아니라 Xamarin으로 넘어간다면 지식의 요구사항이 더 올라갑니다. 더해서 Document가 생각보다 친절하지 않아서 정말 고생 고생하면서 삽질을 해야 한다는 거죠.

예를 들어볼까요?
버튼 클릭 → 화면 출력 형태의 구조를 만든다면

기본 WPF에서는 xaml에서 button을 만들어주고 code-behind나 ViewModel로 기능을 연결 해줍니다.

Prism은 xaml에서 region을 먼저 잡아주고 button이 region에 주입(dependency injection)되어 동작합니다. 기능은 ViewModel에서 동작합니다.

버튼의 기능 하나를 구현하는데 필요한 지식이 기존에 WPF를 이용해서 코딩하는 것과는 차원이 다릅니다.
아마 이런 문제 때문에 대규모 프로젝트에 어울리고 소규모에는 적합하지 않다는 말이 나오는 것 같습니다. 하지만 이건 숙련도의 문제지 프로젝트의 규모와는 상관이 없다고 생각이 듭니다.

저의 주장은 같은 숙련도라면 Prism으로 작업하는게 더 유지보수도 좋고 생산성도 높다는 의견입니다.

말로하면 잘 이해가 안가죠?

코드로 보도록 합시다.
Infragistics의 component들을 이용하여 간단하게 RibbonWindow를 만들어 보겠습니다.

  • 버전: vs2022 pro
  • .net: .net Core 6.0

image

MainWindow.xaml

<igRibbon:XamRibbonWindow x:Class="prismTesting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:igRibbon="http://infragistics.com/Ribbon"
                          Width="600" Height="400">
    <Grid>
        <igRibbon:RibbonWindowContentHost>
            <igRibbon:RibbonWindowContentHost.Ribbon>
                <igRibbon:XamRibbon>
                    <igRibbon:RibbonTabItem Header="Hello">
                        <igRibbon:RibbonGroup>
                            <igRibbon:ButtonTool Caption="world" />
                        </igRibbon:RibbonGroup>
                    </igRibbon:RibbonTabItem>
                </igRibbon:XamRibbon>
            </igRibbon:RibbonWindowContentHost.Ribbon>
        </igRibbon:RibbonWindowContentHost>
    </Grid>

</igRibbon:XamRibbonWindow>

기존 코드라면 이렇게 xaml을 구성하게 됩니다. 물론 여기서 ribbontabitem을 다른 xaml 파일로 구성하여 import 할 수 있습니다. 하지만 여전히 mainwindow.xaml에 dependency가 있습니다. 또 Ribbon의 button은 code-behind나 ViewModel에서 처리 할 수 있습니다.

다음은 Prism code 입니다.

MainWindow.xaml

<igRibbon:XamRibbonWindow x:Class="prismTesting.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:igRibbon="http://infragistics.com/Ribbon"
                          Width="600" Height="400">

    <Grid>
        <igRibbon:RibbonWindowContentHost>
            <igRibbon:RibbonWindowContentHost.Ribbon>
                <igRibbon:XamRibbon prism:RegionManager.RegionName="{x:Static core:RegionNames.RibbonRegion}" />
            </igRibbon:RibbonWindowContentHost.Ribbon>
        </igRibbon:RibbonWindowContentHost>
    </Grid>

</igRibbon:XamRibbonWindow>

XamRibbon이라는 component를 Prism은 모르기 때문에 해당 component를 region으로 인식 시켜주어야 합니다. 여기서 Region adapter라는 파일을 하나 더 작성하게 됩니다.

XamRibbonRegionAdapter.cs

using Infragistics.Windows.Ribbon;
using Prism.Regions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace prismTesting.Core
{
    public class XamRibbonRegionAdapter : RegionAdapterBase<XamRibbon>
    {
        public XamRibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory) : base(regionBehaviorFactory)
        {
        }

        protected override void Adapt(IRegion region, XamRibbon regionTarget)
        {
            region.Views.CollectionChanged += (s, e) =>
            {
                if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
                {
                    foreach (var view in e.NewItems)
                    {
                        AddToRegion(view, regionTarget);
                    }
                }
                if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
                {
                    foreach (var view in e.OldItems)
                    {
                        RemoveFromRegion(view, regionTarget);
                    }
                }
            };
        }

        private void RemoveFromRegion(object view, XamRibbon regionTarget)
        {
            if (view is RibbonTabItem ribbonTabItem)
                regionTarget.Tabs.Remove(ribbonTabItem);
        }

        private void AddToRegion(object view, XamRibbon regionTarget)
        {
            if (view is RibbonTabItem ribbonTabItem)
                regionTarget.Tabs.Add(ribbonTabItem);
            if (view is ApplicationMenu applicationMenu)
                regionTarget.ApplicationMenu = applicationMenu;
        }

        protected override IRegion CreateRegion()
        {
            return new SingleActiveRegion();
        }
    }
}

이후 App.xaml.cs에서 XamRibbon은 XamRibbonRegionAdapter를 이용해서 region을 이용한다고 알려주어야 합니다.

protected override void ConfigureRegionAdapterMappings(RegionAdapterMappings regionAdapterMappings)
{
      base.ConfigureRegionAdapterMappings(regionAdapterMappings);
      regionAdapterMappings.RegisterMapping<XamRibbon, XamRibbonRegionAdapter>();
}

벌써 기존 WPF의 보다 작성해야 할 코드가 2개나 더 늘었습니다. 하지만 해당 XamRibbon이라는 component를 모듈화 한다면

protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
{
        moduleCatalog.AddModule<RibbonModule>();
}

단 한줄만으로 만들어둔 ribbon을 불러오고 region만 넣어주면 됩니다.

어쩌다보니 글이 길어 졌는데 한국에서 Prism 정보가 많이 공유 되었으면 하는 바람에 글을 길게 쓰게 되네요.
특히나 Prism은 MVVM을 더 좋게 만들어 주기 때문에 unit testing 또한 편리해집니다. view의 기능에 대해서도 testing 할 수 있습니다. 여러가지 쓸말들이 많지만 글이 너무 길어지니 다른 포스팅으로 대체하는것이 좋을 것 같습니다.

좋아요 10