태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.

달력

05

« 2017/05 »

  •  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  •  
  •  
  •  
2011.10.18 09:21

MVVM에서 IoC의 중요성 분류없음2011.10.18 09:21

MVVM 패턴을 사용할 때 초기화하는 패턴만 대략 10가지 정도의 패턴이 있습니다. 그중에 Expression Blend와 VisualStudio의 디자인 타임에 잘 보이게 하려면 리소스에 ViewModel Locator를 넣는게 가장 좋습니다.

당연히 중복을 피하고 싶고 컨트롤마다 로케이터가 생성될 필요는 없으니 Window나 UserControl 모두에 Locator 리소스를 넣기보다는 App의 리소스(글로벌 리소스)에 넣는 방법이 먼저 시도되는 것이 바람직합니다.

그런데 여기서 디자인타임 지원에 문제가 생깁니다. Blend에서 윈도우나 사용자컨트롤에 포함되어 있는 사용자컨트롤을 생성할 때, 글로벌 리소스에는 접근할 수가 없는거죠. 검색을 좀 해보면 이것을 Blend의 버그로 보는 경향이 많습니다. 몇가지 해결책도 제시하고 있는데 완벽하지는 않습니다.

결국 컨트롤마다 XAML의 리소스 사전에 로케이터를 정의하는 방식으로 선회할 수 밖에 없었습니다. 이때 우리를 구해준 것이 IoC 컨테이너였습니다. MVVM Light를 사용하는 프로젝트라서 사실은 이미 SimpleIoc라는 내장 IoC 컨테이너가 사용되고 있는 상황이었지요.

IoC 컨테이너 자체가 이미 싱글턴이고, 이 싱글턴 인스턴스가 하는 일은 사용자가 등록해둔 타입별 인스턴스를 관리하는 일입니다. 즉 프로그램의 어느 부분에서나 쓰고 싶은 타입만 지정하면 그 타입의 동일한 인스턴스를 얻을 수 있다는 거죠.

그래서 ViewModel Locator를 모든 컨트롤에서 매번 생성하는게 아무 문제 없는 거였습니다.

MVVM 패턴을 쓸 때 걱정했던 부분이 패턴 자체의 학습 곡선이었습니다. 그리고 부가적으로 따라올 것처럼 보이는 다른 패턴들에 대한 학습이었습니다. 확실히 학습에 시간을 좀 더 쓰게 되는 것 같기는 합니다. 하지만 다행히 MVVM Light 프레임워크가 적절한 수준에서 문제 범위가 너무 커지는 걸 막아주었다는 생각이 듭니다.

iPhone 에서 작성된 글입니다.


신고
Posted by wafe

댓글을 달아 주세요

자이닉스 개발부 블로그에 커맨드 패턴 연재 중 두 번째 글을 썼다. 다음 번에 좀 더 상세한 내용을 다루도록해야겠다.
2010년에는 적어도 한 주에 포스트 하나씩은 작성하려는 목표를 세웠다. 이미 12월부터 시작해서 12월에는 한 주에 하나씩 쓰는 데 성공했다. 기세를 몰아서 1년간 계속 유지해보자.

이 연재처럼 개발부 블로그에 쓰는 포스트까지 포함시키는 꾀를 조금 부리고는 있지만, 영양가 없는 포스트로 채우기보다는 조금이나마 의미있는 포스트로 채우는 게 좋다는 생각으로 그 정도는 허용해주기로 했다.

화이팅!
신고
Posted by wafe

댓글을 달아 주세요

이번 스프린트에서 맡은 작업에서 혼자 MVVM 패턴과 Command 패턴을 적용해본다며 삽질을 했다. 덕분에 예상보다 많은 일정을 소모하고, 다른 팀원들 도움도 받고... 빡빡한 일정임을 알면서 그것도 남들 몰래 이런 모험을 하는 건 웬 못되먹은 심보란 말인가. 함께 한 팀원들께 죄송스럽고 고마울 따름이다.

그런 의미에서라도 이번에 알게된 내용은 꼭! 잘 기록해서 남겨둬야겠다. 그리하여 시리즈 중 첫 번째. Commands in Silverlight with SLExtensions - 1
신고
Posted by wafe

댓글을 달아 주세요

Silverlight Model-View-ViewModel Pattern 1에 이어서.



눈치챘을지도 모르겠지만, 이 코드는 의존성 주입(dependency injection)의 필요성을 외치고 있고, 내가 다음 블로그 포스트에서 다루려고 하는 게 바로 그것이다. 우리는 현재 어플리케이션 개체의 타입을 체크한다. Blend는 그것 스스로의 어플리케이션 개체를 제공하는 반면, 실제로 실행되는 어플리케이션은 우리가 만든 어플리케이션 개체를 우리에게 준다.

리팩토링이 필요한 다음 부분은 메인 사용자 인터페이스이다. 여기서 내가 말하는 것은 카드 주위의 모든 것이다. 어플리케이션은 Twitter 계정을 넣는 텍스트 상자 하나와 새 카드를 추가하기 위한 추가 버튼을 가지고 있다. 클릭 이벤트 핸들러에서 우리는 새 YouCard 사용자 컨트롤의 인스턴스를 만들어서 스택 패널에 넣는다. 또한 YouCard 컨트롤에서 발생하는 클로즈 이벤트를 리스닝하는 이벤트 핸들러를 작성한다. 이런 접근 방법은 몇 가지 이유 때문에 좋지 않은 방법이다. 주요한 문제는 너무 많은 행동(behavior)과 로직을 뷰(XAML 페이지의 코드 비하인드)에 넣는 것이다. 예를들어 디자이너는 코드를 수정하지 않고서는 스택 패널에서 플로우 패널로 바꿀 수가 없다. 또한 어플리케이션 로직의 너무 많은 부분이 특정 UI 컨트롤과 UI 이벤트에 종속되어 있어 코드를 유닛 테스트하기가 어렵다.

이런 문제를 해결하기 위해서 우리는 YouCardData 개체의 옵저버블 컬렉션(Users)을 포함하는 새로운 뷰-모델을 만들 것이다. 이 컬렉션은 YouCard 사용자 컨트롤을 데이터 템플릿으로 사용하는 items presenter control에 바운드된다.


이제 우리는 뷰-모델에 바운드된 UI들을 가지고, 데이터를 어떻게 표시할 것이지 콘트롤하게 되었다. 하지만 이것은 아직 절반 정도밖에 안된다. 아직 사용자가 카드를 추가/삭제할 때 뷰-모델과 인터랙션하게 할 방법이 필요하다.

YouCard 어플리케이션에는 뷰-모델에 영향을 주는 인터랙션 포인트가 두 군데 있는데, 텍스트 상자와 새 사용자 추가 버튼, 목록에서 카드를 제거하는 빨간 버튼이 그것이다. 사용자는 사용자 이름을 입력하고 엔터 키를 누르거나, 추가 버튼을 클릭하여 Users 컬렉션에 새 아이템을 추가한다. 추가 버튼은 입력된 사용자 이름이 올바른 경우에만 활성화되어야 한다. 사용자가 카드에 있는 닫기 버튼을 클릭하면 우리는 뷰-모델에 있는 컬렉션으로부터 그 아이템을 제거해야 한다.

가장 뻔한 해답은 추가 버튼에 클릭 이벤트 리스너를 추가해주고, 새 사용자를 추가하기 위해서 뷰-모델에 있는 메서드를 호출하는 방법일 것이다. 우리는 텍스트 상자의 text changed 이벤트를 받아서 입력을 검증하고 텍스트에 따라서 텍스트 상자를 활성화/비활성화 할 수 있을 것이다. 또한 우리는 빨간 버튼을 클릭했을 때 발생하는 이벤트를 YouCard 컨트롤에 추가할 수도 있을 것이다. 메인 뷰는 이 이벤트를 받아서 해당하는 카드를 뷰-모델로부터 제거할 수 있을 것이다. 이 방법의 문제점은 디자이너가 소유해야만 하는 뷰에 또 다시 로직과 행동(behavior)을 넣게 된다는 것이다. 그렇게 되면 검증 규칙 같은 것들과 추가되거나 제거된 사용자를 로컬 컴퓨터의 isolated storage에 저장하는 것(우리 어플리케이션은 당신이 추가한 카드들을 저장한다) 같은 일들을 유닛 테스트하기가 더 힘들어진다.

뷰와 뷰-모델 간의 인터랙션 문제를 해결하기 위해서 우리는 커맨드 패턴을 적용할 것이다. 커맨드 패턴을 사용하면 액션을 커맨드 개체로 캡슐화할 수 있게 된다. 커맨드 개체는 보통 실행 메서드, 이름과 설명, 커맨드가 활성화되었는지 아닌지에 대한 몇몇 정보를 포함한다. 하나의 커맨드 개체가 여러 UI 엘리먼트에 붙을 수 있다. 당신은 버튼, 키보드 단축키, 메뉴 아이템으로부터 open-file-command를 호출하고 싶을 지도 모르겠다. WPF는 Commands에 대한 지원을 내장하고 있지만 Silverlight 2에는 포함되지 않았다.

Nikhil은 Silverlight behavior를 통해서 어떻게 커맨드 같은 기능을 만들 수 있는지에 대해서 멋진 아이디어를 소개했다. 그것은 ASP.NET 컨트롤을 AJAX behavior로 확장하는 데 사용된 것과 같은 개념이다. 첫번째 ViewModel 포스트에서 Nikhil은 XAML에서 커맨드를 호출하는 데에 다음과 같은 문법을 사용했다.


첨부 속성(attached property)를 이용해서, 뷰-모델에 있는 Search 메서드에 검색 텍스트 상자의 text 속성을 인자로 전달하면서 메서드를 호출하는 행동을 버튼에 추가했다. 이어지는 포스트에서 Nikhil은 Dynamic Language Runtime을 사용하여 더욱 컴팩트한 문법을 사용하는 방법을 보여주었다.

이 접근 방법의 멋진 점은 첨부된 클릭 이벤트에 모든 동적 언어 표현을 사용할 수 있다는 점이다. 메서드 호출이나 페이지에 있는 다른 엘리먼트로부터 파라미터를 얻는 것 등을 사용할 수 있는 것이다. 이 방법으로 뷰를 뷰-모델에 연결하게 되면 놀라운 유연성을 얻게 된다. 이 방법의 문제점은 동적 언어 런타임에 의존성이 생겨서 Silverlight 어플리케이션 크기가 늘어나게 된다는 것이다. 하지만 내가 더 중요하게 생각하는 부분은 이 방법을 쓰게 되면 Blend 2.5에서 제공하는 디자인 타임 지원을 사용할 수 없다는 점이다. 따라서 우리는 다른 접근법을 찾아야 한다.

나는 CodePlex에 있는 "Silverlight Extensions" 프로젝트에서 발견한 좀더 고전적인 커맨드 패턴 구현을 사용하기로 했다. 그 프로젝트는 컨트롤, 헬퍼 클래스, 확장 메서드 등을 포함하고 있다. 우리는 커맨드 패턴 구현에만 관심이 있으므로, 구현 클래스들을 YouCard 프로젝트로 옮기기로 했다. 이제 텍스트 상자와 버튼의 XAML 코드는 아래와 같다.

텍스트 상자는 뷰-모델의 Username 속성에 바운드된다. 두 컨트롤은 모두 뷰-모델의 Username을 파라미터로 사용하여 AddCard 커맨드를 호출한다.

커맨드는 다음과 같이 정의된다.

정적 Commands 클래스는 우리 어플리케이션에서 사용할 수 있는 모든 커맨드에 대한 참조를 유지한다. 새 Command 개체 인스턴스를 만들 때 그것은 Command 개체에 있는 정적 사전(static dictionary)에 추가된다. 어플리케이션에서 만들어진 모든 커맨드 개체는 그 사전에 캐싱된다. XAML에서 CommandService attribute를 사용할 때 CommandService 클래스는 CommandSubscription 클래스를 사용하여 올바른 커맨드를 가진 UI 엘리먼트에 연결된다. 사용자가 사용자 추가 버튼을 클릭했을 때 혹은 텍스트 상자에서 엔터 키를 입력했을 때, CommandSubscription 클래스는 UI 이벤트를 받아서 해당하는 Command 개체의 Executed 이벤트를 발생시킨다. 커맨드가 실행되었을 때 무언가 행동을 취하기를 원하는 클래스는 단순히 Command 개체의 Executed 이벤트를 받기만 하면 된다. 지금같은 경우 우리는 뷰-모델 클래스에서 카드를 추가하고 삭제하는 작업을 처리하기를 원한다.

얘기할만한 가치가 있는 다른 부분으로는 사용자 추가 버튼을 활성화/비활성화하는 부분이 있다. 이 부분은 IsEnabled 버튼의 속성을 뷰-모델의 IsAddEnabled 속성에 데이터 바인딩하는 식으로 되어있다. IsAddEnabled 속성은 이렇게 되어있다.

텍스트 상자는 IsAddEnabled 속성에 대한 PropertyChanged 이벤트를 발생시키는 Username 속성에 바운드되어 있다. 속성의 get 부분에서 우리는 버튼이 활성화되어야 하는지 아닌지에 대한 검증 규칙을 적용한다.

이 포스트가 Model-View-ViewModel 패턴이 어떻게 UI로부터 가능한한 많은 코드를 분리해내는지 당신에게 알려주는 또다른 예제가 되기를 바란다. WPF와 Silverlight의 강력한 데이터 바인딩 지원은 이 패턴을 아주 흥미롭게 만들어준다. 뷰와 뷰-모델 사이의 동기화 코드를 직접 작성하는 부분에 대한 걱정을 하지 않아도 되기 때문이다. 커맨드 패턴을 사용하면 어플리케이션의 액션을 UI 엘리먼트로부터 분리할 수 있다. 이로써 디자이너는 여러가지 액션을 호출하는 데 사용하는 UI 엘리먼트를 선택할 수 있는 자유를 얻는다. 그리고 무엇보다도, 우리는 Blend에서의 디자인 타임 지원을 그대로 유지하면서 이 모든 것을 해냈다. 다음 포스트에서는 의존성 주입(dependency injection)을 도입함으로써 YouCard 어플리케이션의 테스트 가능성을 높이는 작업을 계속할 것이다.


실컷 열심히 번역을 하고 보니 뒷북이란 걸 알게됐다. ㅜ.ㅜ 이미 실버라이트 카페의 boxmile 님께서 번역을 해두셨네. 다음에는 이런 삽질을 하지 말도록 하자.

신고
Posted by wafe

댓글을 달아 주세요

  1. 네오군 2009.01.08 21:54 신고  댓글주소  수정/삭제  댓글쓰기

    헉!!!!!!!!!!!!!!! 저두 님 글 보구 알아챘는데여... 정말 제가 죽고 싶은건.. 님께서 링크해주신 번역글을 제가 전에 읽어봤다는 겁니다.. 그걸 까먹고 있었어여 ㅠㅠ;; 늙으면 죽어야지 ㅠ;

Silverlight의 MVVM 패턴을 소개하고 있는 YouCard Re-visited: Implementing the ViewModel pattern 라는 글을 번역한 글이다. 아직 1/3 정도라서 틈나는 대로 이어서 번역하려고 한다. 실력 부족/시간 부족으로 딱히 좋은 번역이라고 하긴 힘들겠지만.


Model-View-Control (MVC) 패턴은 더 이상 유명할 수가 없을 정도이다. ASP.NET MVC 프레임워크로 Microsoft도 이제 그 대열에 뛰어들었다. Ruby on Rails, Django (Python), Spring MVC (JAVA) 같은 다른 유명한 프레임워크들은 모두 이 유명한 패턴을 구현한 것이다. MVC 패턴은 요청-응답 기반이라는 웹의 본성에 아주 잘 들어맞는다. 요청이 들어오면, controller가 무엇을 해야하는지 결정하여, model에게 알려준다. 그리고 view 엔진에게 렌더링을 시킨다.

반면 Silverlight는 비록 Silverlight가 전통적인 웹 어플리케이션 속에서 실행되기는 하지만, 웹 어플리케이션 보다는 Windows Presentation Foundation 같은 리치 클라이언트 어플리케이션 프레임워크와 공통점이 더 많다. 그러므로 어플리케이션을 설계할 때 다르게 생각할 필요가 있다. 이 포스트에서 나는 View-Model-ViewModel (MVVM) 패턴, 혹은 마틴 파울러가 말한대로 Presentation Model에 대해서 얘기할 것이다. 예제로서 나는 내 YouCard 어플리케이션을 리팩터링하여 이 패턴을 쓰도록 만들 것이다.

Jon GossmanDan CrevierWPF에서의 MVVM 패턴에 대해서 포스팅을 했고, 최근 Nikhil KothariViewModel Pattern in Silverlight using Behaviors라는 제목의 훌륭한 글을 썼다. 마틴 파울러(Martin Fowler)도 이 패턴에 대해서 썼지만 Presentation Model이라는 다른 이름을 사용했다. ViewModel을 Silverlight와 WPF 어플리케이션에서 사용하는 것이 꽤 재미있는 이유는, 이 패턴이 Silverlight와 WPF의 강력한 데이터 바인딩의 장점을 최대한 살려주기 때문이다. MVVM 패턴의 한 가지 중요 컨셉은 특정한 뷰 (사용자 인터페이스)에 딱 맞춘 특정 모델을 정의한다는 것이다. 그 뷰-모델은 당신의 도메인 모델을 형성하는 하나 혹은 그 이상의 필드에 기반한 IsDiscountingEnabled, PageTitle 같은 특별한 필드를 포함할 수도 있다. 당신의 IsDiscoundEnabled 필드는 할인(discount) 권한을 가진 그룹에 소속된 사용자인지 아닌지를 나타내는 것일지도 모른다. 그러나 뷰는 이런 사실을 모를 뿐더러 관심도 없다. 뷰는 뷰-모델의 IsDiscountEnabled 필드에만 신경을 쓰고, 도메인 모델과는 커플링되지 않는다. 뷰와 뷰-모델은 높은 수준으로 동기화된다. 반면, 뷰-모델과 도메인 모델 사이의 동기화는 단지 특정 포인트에서만(사용자가 Apply나 Save 버튼을 클릭했을 때 같은 경우에만) 일어날 뿐이다. 당신이 뷰와 뷰-모델 사이의 동기화를 어떻게 구현할 것인지는 당신이 사용하는 기술에 달려있다. 그러나 마틴 파울러조차도 그 작업이 데이터 바인딩을 통해서 수행되는 것을 추천했다.

아마도 Presentation Model에서 가장 귀찮은 부분은 Presentation Model과 뷰의 동기화이다. 작성하기에 단순한 코드이기는 하지만, 나는 이렇게 지루하게 반복되는 코드를 최소화하는 것이 좋다. Ideally some kind of framework could handle this, which I'm hoping will happen someday with technologies like .NET's data binding.(막 해석 : 이론적으로는 몇몇 프레임워크가 이런 일을 할 수 있지만, 내가 바라는 것은 닷넷의 데이터 바인딩과 같은 기술과 함께 나타날 것이다.) – Martin Fowler

마틴 파울러가 말하는 동기화 코드는, name 텍스트 상자의 값을 Preson 개체의 name 속성으로 옮기는 코드 같은 것이다. 모든 개발자들은 이런 코드들을 작성한 경험이 있고, 우리 모두 그것이 지겹고 반복적인 작업이라는 점에 동의할 것이라고 나는 확신한다! 고맙게도 데이터 바인딩은 .NET 1.1 과 Windows Forms 때부터 많이 개선되었고, 동기화 코드를 작성할 때 WPF와 Silverlight 데이터 바인딩을 선택하는 것은 자연스러운 일이다.


내가 예제로 사용할 어플리케이션은 내가 호주 REMIX에서 만든 YouCard 이다. REMIX에서 나는 디자이너를 위한 Silverlight 2에 대해서 이야기했다. 이야기의 초점은 어플리케이션을 빌드하고 디자인하기 위해서 Blend 2.5를 사용하는 방법에 대한 것이었다. 어플리케이션의 코어는 YouCard 사용자 컨트롤이었다. 그 컨트롤은 YouCardData 클래스에 데이터 바운딩되는 것이다. YouCardData 클래스는 Twitter와 Flickr에서 데이터를 받아오는 기능을 갖고 있고, 어플리케이션에서 모델과 뷰-모델의 역할을 한다. 이 클래스는 Tweet, Name, Bio같이 뷰에 관련된 필드를 갖고 있는데, 이 정보들은 HTTP 요청을 사용해서 Twitter로부터 얻은 Twitter-feed에서 추출한 것이다. YouCardData 클래스는 주어진 시간 간격으로 트위터와 플리커로부터 데이터를 다운로드하는 타이머를 시작시킨다. 단일 책임 원칙 같은 좋은 프로그래밍 원칙을 따르기 위해서 나는 트위터와 플리커 관련 기능을 외부 클래스로 분리시킬 것이다. 이 클래스들이 우리의 Model이 될 것이다. 이 클래스의 책임은 다운로드하고 XML을 분석해서 개체를 만드는 일이 될 것이다. YouCardData 클래스는 우리의 ViewModel이 될 것이고, 트위터와 플리커 서비스를 View의 논리에 맞게 사용하는 책임을 맞게 된다. 또한 UI에 필요한 필드들을 노출시키는 책임도 지게 된다. YouCardData 클래스는 원래 Blend 2.5가 제공하는 강력한 데이터 바인딩과 디자인 타임 지원을 강조하기 위해 설계되었기 때문에, 우리는 리팩토링을 위한 좋은 시작점을 가지고 있는 셈이다. 아래 도표의 왼쪽은 현재의 설계이고, 오른쪽은 리팩토링 후 기대하고 있는 디자인이다.


처음으로 해야 할 일은 외부 서비스를 위한 몇 가지 인터페이스를 정의하는 일이다. ITwitterIFlickr 인터페이스를 만드는대신, 나는 IMicroBlog와 IPhotoService 라는 좀 더 일반적인 이름을 사용하기로 했다. 이 결정은 우리가 FriendFeed, Picasa 또는 Windows Live Photo Gallery를 지원하려고 한다면 좀 더 의미있는 결정일 것이다. 나는 원래의 코드를 리팩토링하여 각각의 인터페이스를 구현하는 두 개의 구상 클래스로 만드려고한다. 하나는 진짜 온라인 서비스를 위한 것이고, 하나는 더미 데이터를 가진 목(mock) 구현이다. 앞에서 언급한대로 이 어플리케이션은 REMIX의 크리에이티브 트랙을 위한 데모로서 작성되었고, Blend에서의 멋진 디자인 타임 사용자 경험을 제공하기 위해서 작성되었기 때문에, 우리는 코드가 디자이너에 의해 사용될 때를 위해 더미 데이터를 생성할 필요가 있다. 만약 당신이 XAML이 가능하게 해주는 디자이너-개발자 업무 흐름으로부터 이익을 얻을 생각이라면, 당신의 코드가 디자인 도구에서 어떻게 동작할 지 생각해보아야 한다. 현재 구현에서 더미 데이터는 YouCardData 클래스 생성자에서 Blend에서 실행되는 것인지 아닌지 체크하는 if 문을 통해 제공된다. 만약 YouCardData 클래스가 Blend에서 실행되면 Twitter와 Flickr 서비스의 목 구현이 사용된다. 브라우저 안에서 실행되면 타이머를 시작시키고 Twitter와 Flickr에서 데이터를 받아오기 시작하는 실제 구현이 사용된다. YouCardData 클래스 생성자의 중요한 부분은 이제 이렇게 보일 것이다.



[Translation] Silverlight Model-View-ViewModel Pattern 2에서 계속.



신고
Posted by wafe

댓글을 달아 주세요

  1. 네오군 2009.01.08 21:53 신고  댓글주소  수정/삭제  댓글쓰기

    노고에 진심으로 감사드립니다. 앞으로도 부탁드려용 ^^;