새롭게 추가된 Extension Manager

이번 Visual Studio 2010 에서는 새로운 Visual Studio 확장 가능한 기능을 제공합니다. 이전의 Visual Studio Extensibility(VSX) 는 그 개발하기 위한 환경을 갖추는 것도 힘들었지만, 아마도 좋은 확장 기능을 찾는 것이 더 힘들었었지요.

이러한 Visual Studio 확장 기능과 Industry Partner 의 제품을 소개하고 검색할 수 있는 Visual Studio Gallery 웹 사이트가 아마도 가장 신뢰할 수 있고 유일한 곳이었습니다. 지금 보이는 웹 사이트는 Visual Studio 2010 과 서비스를 통합하기 위하여 얼마 전에 개편이 되었습니다. 그리고 새롭게 확장된 기능들로 카테고리도 새롭게 정비하고 추가가 되었네요.

[그림1] Visual Studio Gallery 웹 사이트 리뉴얼

 

새로운 표준적인 배포 패키징

그리고 Visual Studio 2010 은 확장 기능을 신뢰할 수 있고, 쉽게 배포하고 사용할 수 있는 배포 방법으로 VSIX 배포 패키징을 지원하게 되었습니다. VSIX 는 .NET Framework 에서 제공하는 패키징 방법으로 System.IO.Packaging 으로 신뢰할 수 있고 범용적인 ZIP 압축 방법을 통한 패키징 방법입니다.

System.IO.Packaging 은 .NET Framework 3.0 부터 지원하는 XPS Document 를 배포하기 위해 지원이 되었고 최근에는 실버라이트의 XAP 에도 표준적인 패키징 기술이 적용된 것으로 알고 있습니다.

System.IO.Packaging 은 아래의 링크를 통해 자세한 내용을 확인하세요.

A New Standard For Packaging Your Data
http://msdn.microsoft.com/en-us/magazine/cc163372.aspx

 

Visual Studio Extension Manager

Visual Studio 2010 에서는 확장 기능을 개발하기 위해 MEF Component 를 제공합니다. 개발자가 Visual Studio 의 코드 편집기를 가장 많이 사용하고, 그래서인지 Visual Studio 2010 의 WPF 기술은 코드 편집기가 주 타겟이 되었던 것 같습니다. 그래서 코드 편집기는 WPF 를 통해 화려한 모습으로 변신하였고 내부적인 코드 편집기의 아키텍처링도 완전히 바뀐 모습입니다.

새로운 코드 편집기는 기존의 인터페이스를 모두 버리고, Wpf 접두어가 붙힌 IWpfTextView 등의 인터페이스가 대거 등장하게 되었습니다. 그리고 대부분의 확장 기능은 코드 편집기를 쉽게 확장할 수 있는 인터페이스를 제공합니다. 여기에 MEF(Managed Extensibility Framework) 를 사용하여 인터페이스가 원하는 표준적인 메타데이터(Metadata) 만 선언해 주면 쉽게 확장 기능을 개발도 할 수 있습니다.

사설은 여기까지 마치고 Visual Studio 2010 의 Extension Manager 를 구경해 볼까요?

[그림2] Tools>Extension Manager

   

[그림3] 쉬운 확장 기능 검색과 설치

Online Gallery 를 통해 Visual Studio Gallery 사이트에 등록된 Visual Studio 2010 을 지원하는 컴포넌트를 자동으로 검색하고 DownLoad 버튼을 누르면 바로 설치를 할 수 있습니다.

[그림4] Demo Dashboard 확장 기능을 설치한 모습

아직은 많은 확장 기능 컴포넌트가 등록되지 않았지만, Beta 1 버전이 출시가 된지 몇 일 안된것을 고려한다면 그리 적은 양은 아닌 것 같네요. 현재까지 제공되는 확장 기능을 가지고 노는 것만으로 쏠쏠한 재미가 될 듯 하네요...

   

Visual Studio 2010 SDK 와 Readme

VIsual Studio Extensibility 2009. 5. 22. 09:30 Posted by POWERUMC
Visual Studio 2010 Beta 1 이 Microsoft MVP 에게 공개되는 것을 시점으로 지난 20일에는 일반인들에게도 공개가 되었습니다. 이미 구글 검색을 해보면 알겠지만 이번 Beta 1 릴리즈에 대한 소식이 미어 터질 정도로 쏟아져 나오고 있습니다.
 
Visual Studio 2010 Beta 1 SDK 도 Microsoft Download Center 에서 Shell-Integrated 만을 먼저 공개하였습니다. SDK 까지 내놓았다는 것은 이미 Visual Studio 2010 Beta 1 버전임에도 왠만한 IDE 의 아키텍트는 구현이 되었다는 증거겠죠?
 
Visual Studio 2010 SDK Beta 1
 
 
Microsoft MVP 에게는 이번 Beta 1 버전이 나오기 전에 신청자에 한해서 이와 유사한 버전이 공개가 되었었습니다. 이번 Beta 1 과는 빌드 버전이 크게 차이는 없습니다만 이번 Beta 1 에서는 내부적으로 훨씬 많은 기능 향상이 있었습니다. Parallel Debugging 도 완성이 되었고 Visual Studio Gallery 의 리뉴얼과 함께 Extension Manager 도 정상적으로 가동이 되는 듯 합니다.
 
특히나 이유 없이 뻗어버리던 거센 반항은 이번 Beta 1 에서는 겪어보지 못했습니다. (MSDN Forum 에서는 Hang 하신 분들이 몇 분 계시더군요)
 
그런데 문제는 내부적으로 크게 변화된 점은 눈에 띄지 않습니다만, VSX 쪽에서는 미미하게, 그리고 많은 폭으로 (도대체 무슨 의미? -_-) 변화가 찾아왔습니다. 이번 Visual Studio 2010 Beta 1 는 Managed Extensibility Framework 의 Plugin Architect 로 만들어졌으며 Managed Extensibility Framework 을 모르고서는 Visual Studio 2010 을 안다고도 할 수 없어졌습니다. 이미 Beta 1 의 상당한 확장 기능은 MEF 로 구현되었고 이번에 새롭게 추가된 Extension Manager 의 확장 기능도 MEF 가 그 기본이 되고 있기 때문입니다.
 
 
어쨌든 기존의 Visual Studio 2008 의 Package 들을 Visual Studio 2010 으로 마이그레이션 하면서 파악하기 힘든 오류를 턱턱 뱉어냈는데 다행히도 아래의 링크에서 그 문제 해결 방법을 가이드하고 있네요.
 
[그림1] Visual Studio 2008 Package 마이그레이션 오류
 
Visual Studio 2010 SDK Beta 1 Readme
 
 
일단 Visual Studio 2010 의 출발은 굉장히 시원시원 한 것 같습니다. 아직은 기존의 Visual Studio 2008 버전의 대부분이 Visual Studio 2010 으로 컨버팅 된 수준입니다만 2010 버전을 시점으로 IDE 도 Managed 환경으로 탈바꿈 할 준비를 하려는 모양입니다.
 
약간의 거부 반응을 일으켰던 2010 버전의 UI 도 이제는 포근해져가네요. 얼른 기존의 프로젝트를 2010 버전으로 변환해야겠네요^^
 
알아 두면 피가 되고 살이 되는 닷넷엑스퍼트 사람들의 포스트
 
기타 참고
 


Visual Studio Team System 2010 Beta 1 이 다가오는 월요일(2009-05-18) 에 MSDN 을 통해 공개가 되고 다운로드 할 수 있다고 합니다. 단, 일반인들에게는 20일에 다운로드가 가능하다고 합니다.
 
 
 
Visual Studio Platform 팀에서 개발 리드를 담당하고 있는 Pedro Silva 씨는 블로그에 이번 Beta 1 에는 Visual Studio SDK 도 포함이 된다고 합니다. SDK 도 포함이 된 것으로 추정하면 대부분의 Visual Studio 2010 의 기능은 이전 버전보다 완성도가 상당히 높아졌으리라 생각합니다. 이전 버전에서는 Visual Studio 2010 이 이전 버전과의 비호환적인 부분이 많았는데 어떻게 변했을지 더욱 궁금해지네요.
 
Visual Studio 2010 에 대한 공식 Product 는 여기 에서 참고하시면 됩니다.
 
References
 
 


Welcome to F#(8) - 은총알과 엄친아.

F# 2009. 5. 10. 20:56 Posted by 알 수 없는 사용자
-넌 제목이 왜 맨날 이 모냥이냐.

은총알과 엄친아. 과연 전 무슨생각으로 제목을 맨날 이렇게 짓는 걸까요? 개인적으로 포스트에서 이야기 하고자 하는걸 비유적으로 설명하는걸 좋아합니다. 그래서 일까요? 늘 글을 쓰기 전에 이야기 하고자 하는 내용을 심사숙고합니다. 그렇게 해서 나오는게 고작 요정도 인거죠.

은총알. 은초딩도 아니고 이건 뭘까요? 들어보신분들도 많으시겠지만, 소프트웨어 공학에서 이야기하는 모든 문제가 이거하나면 해결된다고 하는 그런 어떤 경우에도 쓸 수 있는 만능의 해결책? 그정도 느낌을 생각하시면 될거 같습니다. 즉, 많은 사람들을 파닥파닥 낚이게 만드는 주범이지요. 엄친아도 못하는게 없는 만능의 엄마친구아들을 뜻하죠. 적어도 프로그래밍 세계에선 은총알이나 엄친아 같은 프로그래밍언어는 없는거 같습니다. 아무리 C#이 발전했다 한들, 하자면 할 수 있지만 어색한 부분이 있다는 거죠. 그럼 오늘은 거기에 대해서 좀 이야기 해보겠습니다.


- 이거슨 F# 코드!

아래 코드는 Expert F#에 나오는 코드입니다.

open System.Collections.Generic

let devideIntoEquivalenceClasses keyf seq =
    let dict = new Dictionary<'key, ResizeArray<'a>>()
    
    seq |> Seq.iter(fun v ->
        let key = keyf v
        let ok, prev = dict.TryGetValue(key)
        if ok then prev.Add(v)
        else 
            let prev = new ResizeArray<'a>()
            dict.[key] <- prev
            prev.Add(v))
            
    dict |> Seq.map(fun group -> group.Key, Seq.readonly group.Value)

즉, 어떤 데이터의 집합과 그 데이터에 대해 수행할 함수를 받아서 각각의 데이터에 대해 그 함수를 수행합니다. 그리고 같은 결과 끼리 집합을 만들어서, 결과값과 결과값이 같은 데이터들의 집합을 Dictionary로 만들어서 리턴해주는 프로그램이죠. 즉, 함수형언어의 장점이 잘 드러나는 데이터처리부분의 예제입니다. 실행결과는 아래와 같습니다. 

> devideIntoEquivalenceClasses (fun x -> x % 3) [1..10];;
val it : seq<int * seq<int>>
= seq [(1, seq [1; 4; 7; 10]); (2, seq [2; 5; 8]); (0, seq [3; 6; 9])]

숫자를 3으로 나눈나머지를 구하는 함수와, 1부터 10까지의 숫자를 넘겨주면, 이렇게 나머지값이 같은 숫자별로 그룹을 지어서 리턴해줍니다. 여기서 Dictionary는 닷넷의 클래스를 그대로 사용한 거구요, ResizeArray는 닷넷에서의 System.Collections.Generic.List<T>의 줄임말입입니다. 이름그대로 mutable한, 사이즈를 조절가능한 Array라는 거죠. 

코드를 보면, 전체데이터를 포함할 dict라는 Dictionary를 선언하구요, 입력으로 들어온 seq의 각요소에 대해서 사용자가 넘겨준 함수(keyf)를 수행합니다. 그리고 그 결과값이 이미 존재하는지 확인해서 존재한다면, 그 결과값을 key로 하는 ResizeArray에 숫자값을 추가하고 존재하지 않는다면, 새로운 ResizeArray를 만들어서 숫자를 추가하고, 그 ResizeArray를 dict에 추가해주는 방식입니다.

그리곤 마지막으로 key에 해당하는 ResizeArray를 읽기전용인 시퀀스로 만들어서 리턴해주고 있습니다. 이 예제는 어떤 함수에서 내부적으로는 side-effect를 가진 자료구조를 쓰더라도 그 side-effect를 오직 내부에서만 나타나게 격리한다면, 그 함수는 pure하고 functional한 함수라는 이야기를 하면서 나온 예제입니다. 그래서 마지막에 읽기전용 시퀀스로 리턴을 해주고 있는거지요. 


- 이거슨 C#코드!

이 코드를 C# 3.0버전으로 그대로 옮겨 보겠습니다. 

class Program
    {
        public Dictionary<T2, List<T1>> DivideIntoEquivalenceClasses<T1, T2>>(Func<T1,T2> func, List<T1> list)
        {
            Dictionary<T2, List<T1>> dict = new Dictionary<T2, List<T1>>();

            list.ForEach(l => {
                T2 key = func(l);
                if (dict.ContainsKey(key))
                {
                    dict[key].Add(l);
                }
                else
                {
                    List<T1> prev = new List<T1>();
                    dict[key] = prev;
                    prev.Add(l);
                }
            });

            return dict;
        }

        static void Main(string[] args)
        {
            Program program = new Program();

            var dict = program.DivideIntoEquivalenceClasses((x => x % 3), new List<INT> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            var resultSet = dict.Select(item => new { item.Key, item.Value });

            foreach (var result in resultSet)
            {                
                Console.Write("{0},", result.Key);
                result.Value.ForEach(item => Console.Write(" {0} ", item));
                Console.WriteLine();
            }
        }
    }

실행결과는 아래과 같구요.



역시 func<>를 이용한 higher-order와 LINQ덕분에 코드의 길이자체가 별로 차이가 없고, 오히려 C#의 문법에 익숙해서 그런지 더 깔끔해 보이는 부분도 있네요. 다만, 눈에 상당히 거슬리는게 있다면, T1,T2를 비롯한 파라미터타입과 리턴타입등을 명시한 부분이 상당히 거슬리는군요. 사실 짜면서도 아직 익숙하지 않아서 일까 좀 헷갈렸습니다. F#에서는 Type inference가 제대로 적용되어서 파라미터에도 타입을 명시할 필요가 없죠. 물론 C#에서도 변수수준에서는 var타입을 이용해서 Type inference를 지원하지만, 파라미터와 리턴타입에 대해서는 지원하지 않기 때문에 쫌 복잡해질 수 있습니다. 함수형 프로그래밍을 C#에서 하느라 복잡해지는 모냥은 여기에서도 확인하실 수 있습니다. @_@.

 
아래구절은 Expert F#에서 인용한 구절인데요, 제가 설명하려는 바를 아주 잘 요약해주시고 있습니다.

 A key feature of F# is the automatic generalization of code. The combination of automatic
generalization and type inference makes many programs simpler, more succinct, and more

general. It also greatly enhances code reuse. Languages without automatic generalization force programmers to compute and explicitly write down the most general type of their functions, and often this is so tedious that programmers do not take the time to abstract common patterns of data manipulation and control.

F#의 핵심기능중의 하나가 바로 코드를 자동으로 일반화시켜주는 것이다. 자동일반화와 타입유추를 조합하게 되면 많은 프로그램을 간단하고, 좀더 명확하게 그리고 좀 더 일반화시켜서 작성할 수 있다. 당연히 코드 재사용도 아주 편리해 진다. 자동일반화를 지원하지 않는 언어는 프로그래머가 명시적으로 일반적인 타입을 계산해서 명시해야 만 한다. 그리고 이런 것들은 데이터처리와 그 처리의 흐름을 공통적인 부분을 묶어서 추상화하는 작업을 매우 손이 많이가고 짜증나는 작업으로 만든다.



- 그래서~?

즉, LINQ를 통해 C#에서의 데이터처리와 흐름의 추상화가 가능해졌으며, 그 덕에 C#으로도 부분적으로 함수형언어와 버금가는 생산성을 내는일이 가능해졌습니다. 하지만, 명령형 언어의 한계점이 이런부분일까요? 일반화를 하기 위해서 무척이나 까다롭게 인자들의 타입을 잘 명시해줘야 하는거죠. 물론, 저렇게 하는게 옳은지에 대해서는 잘 모르겠습니다. 개인적으로는 저런부분을 굳이 C#을 이용해서 구현하려고 애쓰기 보다는 F#을 이용해서 조합하는게 더 옳지 않나 싶습니다. 사실 F#을 닷넷에 편입시키려는 의도도 그런부분을 가장 기대하는게 아닌가 싶기도 하구요. 


- 참고자료

1. Expert F#, Don Syme, Adam Granicz, Antonio Cisternino, APRESS
2. http://weblogs.asp.net/podwysocki/archive/2009/04/26/functional-c-forward-functional-composition.aspx

 

Welcome to Dynamic C#(1) - 첫만남.

C# 2009. 5. 4. 14:37 Posted by 알 수 없는 사용자

-너 F#쓰던 넘이자나, Dynamic C#은 뭐냐.

안녕하세요. Welcome to F#이라는 앞뒤도 안맞고 내용도 부실하며, 불친절한 포스트를 남발하고 있는 강보람(워너비)입니다. 원래 하던거에 약간 시들해지면, 새로운 자극을 찾는다고 하던가요. F#의 포스트를 쓰는게 점점 벽에 부딛히니 C#과 자극적인 외도를..... 생각하는건 아닙니다. 하지만, 의문이 생기니 그걸 찾아보고자 하는 호기심이 생기고, 그 호기심을 오래잠재워두면 없어질거 같아서 일단 시리즈를 시작해보자! 해서 일단 무작정 Welcome to Dynamic C#이라는 시리즈를 시작해볼까 합니다. 기존에 동적언어에 대한 경험이 일천하다보니 이 시리즈의 내용역시 상당히 불친절할걸로 예상되지만, 관심있으신 분들께선 따쓰한 피드백을 주시기 바랍니다. 이제 날씨가 더워지는데 따쓰한 피드백을 주면 제가 열사병으로 죽지는 않을까 하는 염려는 고이접어 간직하시고 따쓰한 피드백을....-_-


-Paul Graham아저씨와 실용주의 아저씨들?

Paul Graham을 아십니까? "Hackers and Painters"의 저자이며, 논쟁을 불러일으킬만한 말을 참 많이도 하는 Lisp빠돌이죠. 오랜만에 Hackers and Painter를 읽다가 아래와 같은 구절을 읽고는 '이 책에 이런구절이 있었나~?' 하면서 C# 4.0의 dynamic과 DLR이 떠올랐습니다. 

A programming language is for thinking of programs, not for expressing programs you've already thought of. It should be a pencil, not a pen. Static typing would be a fine idea if people actually did write programs the way they taught me to in college. But that's not how any of the hackers I know write programs. We need a language that lets us scribble and smudge and smear, not a language where you have to sit with a teacup of types balanced on your knee and make polite conversation with a strict old aunt of a complier. 

프로그래밍언어는 프로그램에 대해서 생각해나가기 위한 것이지, 이미 머리속에 짜여져있는 프로그램을 표현하기 위한 것이 아닙니다. 프로그래밍언어는 펜이 아니라 연필이어야 합니다. 정적타입은 제가 학교에서 배우던 것 처럼만 프로그램을 짠다면 괜찮은 아이이디어 일지도 모르겠습니다. 하지만 제가 아는 해커들중에 그렇게 짜는 사람은 한명도 없더군요. 우리는 명확하지 않은 아이디어를 흐릿한 형태 그대로 빠르게 묘사할 수 있게 해주는 언어가 필요합니다. 무릎에 타입이라는 찻잔을 떨어지지 않게 올려놓고, 나이많고 엄격하신 이모님이랑 공손하게 대화하려고 애쓰는 것 처럼 컴파일러와 대화할 필요가 없다는 거죠.


그리고는 예전에 사두었던 "Programming Ruby"를 꺼내서 읽어봤습니다. "실용주의 프로그래머"를 읽으면서 실용주의 학파로 유명한 데이비드 토머스와 앤디 헌트가  펄에서 루비로 관심사를 옮겼다는 사실은 알고 있었지만, 이 책을 읽으면서 이들의 동적언어에 대한 사랑이 확실하게 드러나더군요.

반면에 루비를 잠깐이라도 사용해본다면, 동적 타입을 갖는 변수가 많은 점에서 실질적으로 생산성을 향상시킴을 알게 될 것이다. 오랜 기간 실행되는 커다란 루비 프로그램이 중요한 작업을 수행하면서도, 타입과 관련된 오류는 하나도 던지지 않고 잘 돌아간다. 왜 일까? ..... 결론적으로 말해 '타입 안전성'에서 말하는 '안전성'이란 대개 허상에 불과하며, 루비 같은 동적 언어로 개발하는 것은 안전하면서도 생산적이다.

이런 호기심이 생기자, F#때문에 미뤄오던 C#4.0의 dynamic에 대한 탐구를 더 이상 미룰 수 없다는 생각이 들었습니다. 그래서 가끔 생각날때 마다 dynamic에 대한 생각을 정리해서 올리려고 지금 포석을 깔고자 하는 것이죠. 대뜸 F#에 대해서 쓰다가 C#으로 옮겨가면, 읽으시는 분들도 혼란을 느끼시지 않을까 해서 말이죠. 물론 그런분덜 한분도 없을거 압니다-_-. 


-반갑다! dynamic! 

일단, dynamic에 대해서 조금 알아보도록 하겠습니다. dynamic은 말 그대로 동적이라는 거구요, 타입체크를 컴파일 타임이 아니라 수행순간에 즉, 런타임에서 하겠다는 말이 됩니다. 여기서 Duck typing이라는 개념이 들어가게 되는데요, Duck typing은 객체의 타입에 따라서 가능여부를 결정하는 게 아니라, 그저 요건을 갖추고 있다면 모두다 가능하다고 보는 거죠. 즉, 비유를 하나 하자면 조선시대의 어떤 모임을 생각해 보겠습니다.

이 모임에서 양반집의 지체높은 어르신들과 그 어르신들의 자제들만 회원으로 받아준다면 이 모임은 정적타입검사(Static type check)를 하고 있는셈입니다. 특정 계급(Type)만 들여보내주기 때문이죠. 타입이 틀리면 아예들어갈 수가 없습니다. 하지만, 어떤 모임에서는 그림에 관심이 있는 사람이라면, 양반이나 상놈 가리지 않고 모두다 받아들여줬습니다. 이 모임은 바로 Duck typing을 충실히 따르고 있는셈입니다. 계급(타입)에 상관없이 그저 공통점(그림을 사랑하는 뜨거운 가슴!)만 있으면 들여보내주기 때문이죠. Duck typing은 이처럼 타입으로 가르지 않고, 요건을 갖췄다면 모두 묻지도 따지지도 않고 받아들여주는 걸 이야기 합니다.(Duck이 들어가 있는 이유는 애초에 이 개념을 설명하신 분께서 오리처럼 걷고 꽥거리면 전부다 오리로 봐주자고 말씀하셨기 때문이죠. 제가 안그랬습니다-_-. 오히려 제가 만들었다면, '동호회 타이핑' 같은용어를 썼을거 같은데... 제가 안만든게 다행이군요.) 

그럼 첫 예제를 한번 볼까요? 

static void Main(string[] args)
{
            dynamic num = 4;

            Console.WriteLine(num);
 

            Type type = num.GetType();
            MethodInfo method = type.GetMethod("ToString", new Type[] {});

            if (method != null)
            {
                Console.WriteLine(method.ToString());
            }
} 

위 예제는 dynamic타입의 num에 숫자인 4를 입력하고, 출력을 합니다. 그리고 WriteLine에 의해서 불려지는 ToString메서드의 유무를 검사하기 위해서, 타입에서 ToString메서드를 찾아서 출력하는 프로그램입니다. 결과는 아래와 같습니다. 



WriteLine에선 출력할 객체의 ToString을 호출하죠. 그래서 num의 값이 출력되는 것을 보면 런타임에 num이 ToString을 가지고 있는지 확인해서 있으니까 출력을 했다고 볼 수 있습니다. 그리고 확인을 위해서 dynamic타입인 num의 타입에서 ToString메서드를 찾아서 해당 메서드를 출력해봅니다. 결과를 보면 ToString이 있는 것을 볼 수 있습니다. 그리고 WriteLine의 오버로딩중에서 dynamic타입을 인자로 받아들이는 오버로딩이 없는걸로 봐서는, 런타임에 해당 dynamic객체가 ToString을 가지고 있는지 봐서 있으면 출력하고, 없으면 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException을 발생시키는 것을 유추할 수 있습니다.


-양반과 상놈의 이야기 

그럼 위에서 이야기 했던, 양반과 상놈의 이야기를 한번 구현해볼까요? 

class Yangban
    {
        public string Name {get; set;}

        public void YangbanSound()
        {
            Console.WriteLine("Yo, it's the yangban sound, baby :) ");
        }
    }

    class YangbanChild : Yangban
    {
        public void ILikeDrawing()
        {
            Console.WriteLine("I like Drawing");
        }
    }

    class Sangnom
    {
        public string Name { get; set; }

        public void SangnomSound()
        {
            Console.WriteLine("Yo, it's the sangnom sound, baby ;) ");
        }

        public void ILikeDrawing()
        {
            Console.WriteLine("I like Drawing");
        }
    }

    class Program
    {
        public void EnteringYangbanClub(Yangban yangban)
        {
            Console.WriteLine("Welcome yangban {0}!", yangban.Name);
        }

        public void EnteringDrawingClub(dynamic person)
        {
            try
            {
                person.ILikeDrawing();
                Console.WriteLine("Welcome {0}! who like drawing",person.Name);
            }
            catch (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException you_do_not_like_drawing)
            {
                Console.WriteLine("{0}. You can't come in. I'm sorry about that :)", person.Name);
            }
        }

        static void Main(string[] args)
        {
            Yangban yangban1 = new Yangban { Name = "chulsoo" };
            YangbanChild yangbanChild1 = new YangbanChild { Name = "chulsooAdeul" };
            Sangnom sangnom1 = new Sangnom { Name = "boram" };

            Program program = new Program();
            program.EnteringDrawingClub(yangban1);
            program.EnteringDrawingClub(yangbanChild1);
            program.EnteringDrawingClub(sangnom1);
        }
    }

위 코드를 보시면, 양반과 양반자식, 상놈이 있죠? 모두 이름을 가지고 있구요, 양반은 간지나는 양반사운드를 구사하며, 상놈은 상놈사운드 그리고 양반자식과 상놈은 자기가 그림그리는걸 좋아한다고 합니다. 그리고 두개의 클럽이 있습니다. 하나는 양반만 들어갈 수 있는 클럽이구요, 하나는 그림을 좋아하는 사람이 들어갈 수 있는 클럽입니다. 자 그럼, 양반과 양반자식인 철수와 철수아들, 상놈인 보람을 데리고 이야기를 해보겠습니다. 양반클럽에 철수와 철수아들, 보람 이렇게 셋이 들어가려고 합니다. 그런데, 양반클럽은 양반이거나 양반의 자제가 아니면 못들가게 엄격하게 막아놨습니다. 그래서 일까요? 아래 그림을 보면, 들어가고 싶다는 의사표시조차도 허용되지 않는 슬픈 모습입니다. 

뭐, 계급으로 딱 막혀있기 때문에 들어가는거 자체가 불가능하니까요. 이렇게 타입으로 조건을 걸게되면, 해당타입이거나 해당타입을 상속한 타입이 아니면 안됩니다. 그러면, 그림애호가 클럽에 들어가보도록 하겠습니다. 그림애호가클럽은 일단 다 들여보내주는 군요. 하지만, 들어가게되면 그림을 좋아하는지 크게 외쳐보라고 시킵니다. 근데, 철수는 그림을 좋아하지 않는군요. 그래서 철수는 쫓겨나고 철수아들과 보람은 환영받습니다. 실행결과는 아래와 같죠.


그렇습니다. 계급으로 나누것이 아니라 무엇을 할 수 있는지에 따라 니편 내편을 나누니깐 철수는 못들어가고 보람은 들어가게 되는 것이죠.


-근데 dynamic이거 어따 쓰면 조으까? 

도대체 이걸로 무엇을 할 수 있다는 걸까요? 왜 Paul Graham아저씨는 그토록 다이나믹을 부르짖었으며, 실용주의 아저씨들은 또 왜그랬을까요? 불행히도 저는 그동안 정적인 명령형 언어만 다뤄봤기 때문에 잘 모르겠습니다. 뭐 좀 알아보려고 하는데, 그 과정에서 느끼는 점들을 이곳을 통해 나눠보려고 하는거구요. 그럼 F#뿐만 아니라 C#을 통해서 최대한 자주 찾아뵙겠습니다.


-참고자료

1. Hackers and Painters, Paul Graham, O'Reilly
2. Programming Ruby, 데이비드 토머스, 앤디 헌트, 차드파울러, 인사이트
3. http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=csharpfuture&DownloadId=3550

Welcome to F#(6) - 비교본능.

F# 2009. 4. 23. 09:27 Posted by 알 수 없는 사용자
-지난시간에 이어서.
잘들 지내셨는지요. 어느새 수요일이 다 지나가는 군요. 오늘은 어제에 비해서 일이 잘 되셨나요? 그렇습니다. 사람은 자연스럽게 비교를 하려는 본능비스무리 한게 있는거 같습니다. 여친과 다른 사람들을 비교하고, 자기 자식이랑 친구아들을 비교하고, 심지어는 별 찌질한것까지도 비교하면서 그 우위에서 오는 만족감을 느끼려는게 사람이 아닐까요.

하지만, 비교는 좋은 이해의 틀이기도 합니다. 뭔가가 틀리다는 건, 다른 것들과 부딪히면서 비로소 틀린점들이 눈에 들어오기 시작하고 형체를 갖추기 시작합니다. 이번 포스트에서는 지난 포스트에서 봤었던 F#예제와 같은 일을 하는 C#예제를 통해서 차이점을 좀 찾아보고자 합니다. ........늘 느끼는 거지만, 참 서두를 번지르르하게 써놓고 시작을 하네요.-_-



- C#코드부터 보자!

넵. 보여드리겠습니다. 보여드려야죠~. 다만, 아래의 코드는 제가 짠 코드일뿐 모범적인 코드라고는 볼 수 없다는 걸 생각하고 봐주시기 바랍니다.


class Demo
    {
        private string destDir;
        private List<STRING> finalFiles;

        public Demo(string destDir)
        {
            this.destDir = destDir;
            finalFiles = new List<STRING>();
        }

        private List<STRING> GetSthAll(Func<STRING, string[]> GetSth, string path)
        {
            return GetSth(path).ToList();
        }

        public void PrintAllFilesCount(string ext)
        {
            GetAllFiles(destDir);
            List<STRING[]> filesWithExt = finalFiles.Select(file => file.Split('.')).ToList();
            int countOfExt = filesWithExt.Where(file => (file.Length == 2) && (file[1] == ext)).Count();

            Console.WriteLine(countOfExt);
        }

        private void GetAllFiles(string destDir)
        {
            finalFiles.AddRange(GetSthAll(Directory.GetFiles, destDir));
            foreach (string currentDir in GetSthAll(Directory.GetDirectories, destDir))
            {
                GetAllFiles(currentDir);
            }
        }
    }

그리고 위 코드는 아래처럼 실행할 수 있습니다.


class Program
    {
        static void Main(string[] args)
        {
            Demo demo = new Demo(@"c:\ATI");
            demo.PrintAllFilesCount("txt");
        }
    }

위의 코드는 이전 포스트의 코드와 같은 결과를 내는 코드입니다. F#에서는 중간결과를 따로 저장하지 않고 |>를 통해서 바로바로 다음함수로 연결했었기 때문에 중간값의 상태저장에 대한 고려가 필요없었습니다. 그 때문에 제귀호출 과정의 데이터를 어디에 저장해야 할지 역시 고려하지 않아도 되었습니다. 즉, 데이터가 어디에서 어디로 가는지에 대한 데이터의 흐름이 추상화 되어 있었던 것이죠. 위의 코드를 보시면, 명령형언어에서 오는 한계점이 분명히 존재하지만, 특별히 복잡해보인다거나 코드가 길어졌다거나 하는 모습은 볼 수 없습니다. 왜그럴까요?

바로 LINQ때문입니다. 함수형언어의 장점을 녹인 LINQ덕분에 데이터추출과정이 추상화되어서 코드가 큰 차이없이 작성될 수 있었습니다. 최근 추세는 명령형언어와 함수형언어가 조금씩 융화되어 가는 것 같습니다. C#에도 점점 함수형언어의 장점과 동적언어의 장점이 녹아들어가고 있습니다. 물론 C#의 설계자인
Anders Hejlsberg는 static한 언어가 가지는 강점을 여전히 높게 평가하고 있습니다만, 필요하다면 점점 융화되어 가는거겠죠. 그럼, 어디한번 계급장떼고(?)...아니아니 LINQ떼고 한번 해보죠!


- 계급장떼고 붙여봐!
넵, 계급장테고 붙여보겠습니다. LINQ없이 C#2.0의 익명메서드 기능을 이용해서 동일한 코드를 작성해 보겠습니다.


class Demo2
    {
        private string destDir;
        private List<STRING> finalFiles;

        public Demo2(string destDir)
        {
            this.destDir = destDir;
            finalFiles = new List<STRING>();
        }

        private List<STRING> GetSthAll(Func<STRING, string[]> GetSth, string path)
        {
            return GetSth(path).ToList();
        }

        private List<STRING[]> GetSplitedList(List<STRING> data, Func<STRING,STRING[]> splitMethod)
        {
            List<STRING[]> splitedList = new List<STRING[]>();
            foreach (string str in data)
            {
                splitedList.Add(splitMethod(str));
            }
            return splitedList;
        }

        private int GetFilesCountWithExt(List<STRING[]> data, Func<STRING[], bool> filterMethod)
        {
            List<STRING[]> filteredList = new List<STRING[]>();
            foreach (string[] fileStr in data)
            {
                if (filterMethod(fileStr))
                {
                    filteredList.Add(fileStr);
                }
            }
            return filteredList.Count;
        }
        public void PrintAllFilesCount(string ext)
        {
            GetAllFiles(destDir);
            List<STRING[]> filesWithExt = GetSplitedList(finalFiles, delegate(string str) { return str.Split('.'); });
            int countOfExt = GetFilesCountWithExt(filesWithExt, delegate(string[] fileStr) { return (fileStr.Length == 2) && (fileStr[1] == ext); });
            Console.WriteLine(countOfExt);
        }

        private void GetAllFiles(string destDir)
        {
            finalFiles.AddRange(GetSthAll(Directory.GetFiles, destDir));
            foreach (string currentDir in GetSthAll(Directory.GetDirectories, destDir))
            {
                GetAllFiles(currentDir);
            }
        }
    }

어떻습니까? 이젠 차이가 좀 드러나기 시작합니다. 익명메서드를 이용해서 람다를 흉내냈지만, 데이터추출과정을 추상화하진못해서 그 추출과정의 중간값저장이나 추출루프를 직접 제어해줘야 합니다. 이렇게 되면, 문제가 조금씩 복잡해질수록 코딩도 어려워 지겠지요.(Func<>는 .NET 3.5에서 추가된거지만 봐주셈요-_-)

즉, 단순히 LINQ라는 기술을 쓰고 안쓰고정도의 문제가 아니라, 추상화 단계가 낮아지는 것이기 때문에 생각의 복잡도는 높아질 수 밖에 없는 것입니다. 데이터의 흐름을 추상화해주는 함수형언어의 특징이 이런부분에서 굉장한 강점으로 작용하게 됩니다.



- 할말다했냐?
네 별로 대단치않은 예제이지만, 최선을 다해서 한번 비교를 해봤습니다. 물론, 예제가 완전히 적절한건 아니고 크기나 복잡도 역시 높은 수준이 아니라 명확한 비교라고 볼 수는 없지만, 하나의 예제가 될 수 있다고 생각합니다. 이번 포스트에서 함수형언어인 F#의 장점을 못 느끼셨다면 모두 제 책임이나 따뜻한 질타를 주시기 바랍니다. 끝으로 Expert F#의 저자인 Don Syme의 블로그에 올라온 사례하나를 소개하고 마치겠습니다.

-포스트 원문-

The first application was parsing 110GB of log data spread over 11,000 text files in over 300 directories and importing it into a SQL database. The whole application is 90 lines long (including comments!) and finished the task of parsing the source files and importing the data in under 18 hours; that works out to a staggering 10,000 log lines processed per second! Note that I have not optimized the code at all but written the application in the most obvious way. I was truly astonished as I had planned at least a week of work for both coding and running the application.

Ralf Herbrich, Microsoft Research
(http://blogs.msdn.com/dsyme/archive/2006/04/01/566301.aspx)


-제 맘대로 해석-_-;;;-

첫번째 프로그램은 300개가 넘는 디렉토리에 있는 11,000개의 텍스트파일에 저장되어있는 100GB나 되는 로그 데이터를 가져와서 분석해서 SQL데이터베이스에 저장하는 거였습니다. 어플리케이션은 전체 길이가 주석을 포함해서 딱 90줄이었고, 로그파일들을 읽어들여 분석하고 저장하는데 18시간이 채 안걸렸습니다. 1초에 1만줄의 로그를 처리한 셈이죠! 더 중요한건 코드를 최적하려고 하지도 않았고 그냥 제일 명확하게 보이도록 짰습니다. 제가 진짜 놀랐던건, 솔직히 전 그 프로그램 짜고 돌리는데 일주일은 걸릴 줄 알았었거든요.



- 참고자료

1. Expert F#, Don Syme, Adam Granicz, Antonio Cisternino, APRESS

2. http://blogs.msdn.com/dsyme/archive/2006/04/01/566301.aspx


 

[MEF] 9. Recomposition

Managed Extensibility Framework 2009. 4. 19. 22:47 Posted by POWERUMC

Recomposition

 

이전 포스트의 MEF 의 특징 중에 MEF 의 플러그인 모델(Plugin Model) 은 교체가 용이하다고 하였습니다. Composable Part 는 구성 요소로써 고유의 기능을 구현합니다. 그리고 MEF 는 각각의 Composable Part 를 조립하여 다양한 컴포넌트 또는 애플리케이션을 완성합니다.

 

어떠한 경우에는 특정한 구성 구성요소를 사용하다가 그것이 필요 없어질 경우 구성 요소를 언로드(Unload) 하거나 다른 구성요소로 교체할 필요가 있습니다.

 

MEF 의 이러한 유연함의 예를 들어보죠.

 

예를 들어, 어플리케이션의 로그(Log) 기능을 생각해볼 수 있습니다. 만약 어플리케이션이 동작하는 환경이 인터넷에 연결되지 않는 환경이라면 사용자의 컴퓨터 로컬에 로그를 기록하다가, 인터넷에 연결될 경우 외부 데이터베이스로 로그를 기록하는 시나리오를 가정할 수 있습니다. 그리고 이러한 기능 또는 요구 사항이 언제 변경될지도 모르는 일입니다.

 

일단 위의 시나리오를 구현하기 여러 가지 고려해야 할 사항이 있고, 기능 또는 요구 사항이 변경될 경우도 고려해야 합니다. 결국, MEF 는 이러한 변화에 굉장히 유연하게 대처할 수 있습니다.

 

MEF 에서 ImportAttribute AllowRecomposition 프로퍼티를 통해 구성 요소를 런타임(Runtime) 시 동적(Dynamic) 으로 교체할 수 있도록 합니다.

 

아래는 위의 예로 든 시나리오를 구현하기 위해 작성한 간단한 소스 코드 입니다.

 

ILogger 인터페이스

public interface ILogger

{

        void Write();

}

 

ILogger 인터페이스는 Write 메서드를 통해 로그를 기록할 수 있는 예입니다.

 

 

TextLogger 클래스

[Export(typeof(ILogger))]

public class TextLogger : ILogger

{

        public void Write()

        {

               Console.WriteLine("Logged TextLogger");

        }

}

 

 

DatabaseLogger 클래스

[Export(typeof(ILogger))]

public class DatabaseLogger : ILogger

{

        public void Write()

        {

               Console.WriteLine("Logged DatabaseLogger");

        }

}

 

 

LoggerContext 클래스

[Export]

public class LoggerContext

{

        [Import(AllowRecomposition=true)]

        public ILogger Context { get; set; }

 

        [ImportingConstructor]

        public LoggerContext(ILogger sender)

        {

        }

}

 

여기에서 ImportAttribute AllowRecomposition 프로퍼티의 값을 true 로 지정해 주었습니다. AllowRecomposition 프로퍼티가 true 일 경우 Imported 된 구성 요소를 동적(Dynamic)하게 교체할 수 있도록 합니다.

 

 

Main 어플리케이션

class Program

{

        static void Main(string[] args)

        {

               Program p = new Program();

               p.Run();

        }

 

        void Run()

        {

               var catalog    = new AggregateCatalog(new TypeCatalog(typeof(LoggerContext)));

 

               var container = new CompositionContainer(catalog);

                var batch = new CompositionBatch();

               var defaultPart = batch.AddPart(new TextLogger());

               container.Compose(batch);

 

               var obj = container.GetExportedObject<LoggerContext>();

 

               obj.Context.Write();

              

               batch = new CompositionBatch();

               batch.RemovePart(defaultPart);

               batch.AddPart(new DatabaseLogger());

               container.Compose(batch);

 

               obj.Context.Write();

        }

}

 

이 코드는 처음에 TextLogger 를 사용하다가, 필요 없어진 TextLogger 를 제거하고 DatabaseLogger 로 교체하는 코드입니다.

 

아래는 위의 소스 코드를 실행한 결과입니다.

 

[그림1] 소스 코드 실행 결과

 

 

Wow! Recomposition

 

사실 이러한 것이 기존에는 기능의 정의 또는 요구 사항에 따라 직접 구현할 수 있었지만, MEF 의 특징인 플러그인 모델(Plugin Model) 은 이러한 고민에 대해 좋은 방법을 제공해 줍니다. 개발자는 자신이 구현해야 할 기능에 더 충실하고, 비즈니스 로직에 대한 고민만을 하면 됩니다. 그리고 정책에 따라 그것을 집행하는 결정권을 가진 자는 구현된 구성 요소를 조립하고 교체하여 기존의 정적인(Static) 어플리케이션에게 동적인(Dynamic) 유연함을 제공합니다.

 

기존에 정적인 어플리케이션은 변화에 따라 유지 보수를 위해 지속적인 많은 리소스가 필요하였지만, 플러그인 모델(Plugin Model) 의 동적인 어플리케이션은 그러한 변화에 능동적으로 대처할 수 있는 큰 기쁨을 줄 수 있을 것입니다.

'Managed Extensibility Framework' 카테고리의 다른 글

MEF Preview 6 공개  (0) 2009.07.20
[MEF] 10. Querying the CompositionContainer  (0) 2009.05.18
[MEF] 8. Strongly Typed Metadata  (0) 2009.04.16
[MEF] 7. Exports and Metadata  (0) 2009.04.16
[MEF] 6. Lazy Exports  (0) 2009.04.13

지난 번 포스팅에서 말씀 드렸던 것처럼 Visual Studio Team System 2010에서 이루어진 Code Analysis 기능 개선에 대해서 더 깊게 다뤄 보겠습니다. 그 첫 번째로 새롭게 추가된 Rule Sets 개념에 대해서 알아보도록 하겠습니다.


Visual Studio 2005, 2008에서의 코드 분석 설정

Visual Studio의 코드 분석 시스템에는 약 200개 정도의 규칙이 있습니다. 하지만, 사실 이 규칙들을 모두 준수를 해야 하는 것은 아닙니다. 모든 규칙이 나름의 이유와 정당성을 갖고 있다고 해도, 프로젝트의 성격에 따라, 모듈의 성격에 따라서 꼭 지켜야 할 규칙, 그렇지 않은 규칙, 심지어는 어쩔 수 없이 위반해야 하는 규칙도 있을 수 있습니다.

그래서 코드 리뷰를 할 때, 대부분의 경우 모든 규칙을 다 검사하지는 않습니다. 각각 케이스 바이 케이스로 규칙을 적절하게 조절하게 됩니다.

Visual Studio Team System 2005와 2008 버전에서는, 이런 설정을 Visual Studio Project Configuration에서 각 프로젝트 별로 할 수가 있습니다.

이 규칙 설정은 프로젝트 파일(.vbproj 혹은 .csproj)에 CodeAnalysisRules라는 Property 이름으로 아래와 같이 저장되게 됩니다. 내용을 보면 아시겠지만, “-“ 기호와 규칙 ID를 붙여 놓은 모양으로 되어있습니다. 즉, 거기에 열거된 규칙 ID를 Analysis Rules에서 빼는 형태로 저장이 되는 것입니다. 아래 샘플은 그래서 이 프로젝트는 코드 리뷰를 할 때에 Design Rule의 CA1000번 규칙을 검사하지 않는다라는 의미가 됩니다.

<CodeAnalysisRules>-Microsoft.Design#CA1000</CodeAnalysisRules>

이런 형태로 Visual Studio 프로젝트마다 다른 규칙을 적용할 수 있다는 것은 대단히 유연한 디자인이긴 하지만, 많은 수의 Visual Studio Project가 존재한다면, 관리가 참으로 어렵습니다. 그래서 예전에 Visual Studio Team System 2005 를 사용했던 프로젝트에서 전체 Visual Studio 프로젝트의 분석 규칙들을 통일하기 위해서, 개별 개발자들에게 위임하지 않고 제가 직접 모든 프로젝트를 텍스트 에디터로 열어서 저 부분만 Copy & Paste로 넣어서 Check-In하는 엄청난 단순 반복 작업을 한 적도 있습니다.

 

Visual Studio Team System 2010의 Rule Sets Feature

그래서 새롭게 출시될 Visual Studio Team System 2010에서는 Rule Sets라는 개념이 도입되었습니다. 이 Rule Sets 기능은 이름에서도 알 수 있듯이 Rule들을 미리 정해진 Set으로 관리할 수 있는 기능입니다. 이제 Visual Studio 프로젝트 별로 Rule을 하나 하나 빼는 수고를 할 필요가 없이 Visual Studio 프로젝트에 Rule Set을 지정하는 것으로 Code analysis를 커스터마이징할 수 있게 된 것입니다. 아래 그림에서 볼 수 있듯이, 하나 이상의 Rule Set을 선택하는 것도 가능합니다. (가장 아래의 Choose Multiple Rule sets를 선택하면 됩니다.)


Visual Studio Solution 전체에 Rule Set을 적용하는 것도 가능합니다. Solution Property에서 아래와 같이 설정할 수 있습니다.

 

위 그림에서 보시는 것처럼 마이크로소프트는 기본적으로 7개의 기본 Rule Set을 제공합니다. 이 기본 Rule Set의 목록은 다음과 같습니다.

  • Microsoft All Rules – 전체 Rule이 모두 포함된 Rule Set입니다.
  • Microsoft Basic Correctness Rules – 로직 에러와 자주 저지르는 실수를 예방하는 규칙들로 이루어진 Rule Set입니다.
  • Microsoft Basic Design Guideline Rules – Framework API 작성 상의 Best Practice에 집중된 Rule Set입니다.
  • Microsoft Extended Correctness Rules – Basic Correctness Rules를 확장하여, COM Interop이나 Mobile Application에도 사용 가능하도록 만들어진 Rule Set입니다.
  • Microsoft Extended Design Guideline Rules – Basic Design Guideline Rules를 확장해서, 사용성이나 유지 보수성도 체크할 수 있도록 만들어진 Rule Set입니다.
  • Microsoft Globalization Rules – Application의 Globalization에 있어서 문제가 있는지 검증하는데 집중된 Rule Set입니다.
  • Microsoft Minimum Recommended Rules - MS가 제안하는 최소한의 Rule Set입니다. 50개 정도의 규칙으로 이루어져 있습니다. 다른 대부분의 Rule Set들이 이 Rule Set을 포함하고 있습니다.
  • Microsoft Security Rules – 이름 그대로 보안에 집중된 Rule Set으로, 모든 Security 관련 규칙들이 모두 포함되어 있습니다.

 

물론 이 외에도 사용자가 직접 Rule Set을 편집할 수 있습니다. Rule Set은 .ruleset이라는 확장자를 가지는 XML 파일 포맷으로 되어 있습니다. 기본적으로 Visual Studio 2010에서 아래와 같은 UI를 통해서 편집할 수 있도록 되어 있습니다.


 

아래는 Rule Set 파일을 직접 Notepad로 열어본 것입니다.

<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Microsoft Basic Correctness Rules" Description="These rules focus on logic errors and common mistakes made in the usage of framework APIs. Include this rule set to expand on the list of warnings reported by the minimum recommended rules." ToolsVersion="10.0">
  <Localization ResourceAssembly="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.dll" ResourceBaseName="Microsoft.VisualStudio.CodeAnalysis.RuleSets.Strings.Localized">
    <Name Resource="BasicCorrectnessRules_Name" />
    <Description Resource="BasicCorrectnessRules_Description" />
  </Localization>
  <Include Path="minimumrecommendedrules.ruleset" Action="Default" />
  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
    <Rule Id="CA1008" Action="Warn" />
    <Rule Id="CA1013" Action="Warn" />
    <Rule Id="CA1303" Action="Warn" />
    <Rule Id="CA1308" Action="Warn" />
    <Rule Id="CA1806" Action="Warn" />
    <Rule Id="CA1816" Action="Warn" />
    <Rule Id="CA1819" Action="Warn" />
    <Rule Id="CA1820" Action="Warn" />
    <Rule Id="CA1903" Action="Warn" />
    <Rule Id="CA2004" Action="Warn" />
    <Rule Id="CA2006" Action="Warn" />
  </Rules>
</RuleSet>

 

Team Foundation Server Check-In Policy

이 Rule Set 기능은 Team Foundation Server의 Check-In Policy에도 쓰이게 됩니다.

 

맺으며..

이번 Rule Set Feature를 통해서 확실히 이전 버전보다는 Code Analysis를 사용하는 것이 쉬워지고 편리해진 것 같습니다. 하지만, Code Analysis에서 중요한 것은 편의성보다는, Rule의 문제라고 생각됩니다. 그런 면에서 아직 FxCop이 처음 나왔을 때의 200개 정도의 Rule에서 많은 추가가 없다는 것은 굉장히 아쉽습니다. 특히 직접적인 경쟁 제품이라고 볼 수 있는 Compuware의 DevPartner Code Review가 처음 버전부터 600개 이상의 Rule을 가지고 있다는 점에 비교해 본다면 더욱 그렇습니다.

이어지는 포스팅에서는 새롭게 Code Analysis에 추가된 Phoenix 엔진과 그에 따라 다시 복귀한 Data Flow 관련 규칙들에 대해서 한 번 알아보겠습니다.

Visual Studio Team System 2005 에서 코드 분석(Static Code Analysis) 기능이 처음 소개된 바가 있습니다. 이 코드 분석은 Microsoft에서 제안하는 닷넷 프레임워크에서의 디자인 가이드라인과 성능이나 보안, 신뢰성 등의 요소에 대한 Best Practice 등으로 이루어진 200개 이상의 Rule을 기반으로 Code를 검사하고 결함을 발견해 줍니다.

 

원래 이 Code Analysis는 FxCop이란 이름의 독립된 툴로써 세상에 먼저 선을 보인 바 있습니다.

이 FxCop이 Visual Studio 2005 Team System에서 통합되면서 현재의 코드 분석 기능이 나오게 된 것입니다. 실제로 비주얼 스튜디오에서 코드 분석 기능을 담당하는 실행 파일의 이름은 아직도 FxCopCmd.exe입니다.

앞으로 나오게 될 Visual Studio Team System 2010에서는 현재까지 알려진 바로는 다음 세 가지 부분에서 코드 분석의 기능 향상이 이루어 졌습니다. (출처: http://blogs.msdn.com/fxcop/archive/2008/10/30/new-code-analysis-features-in-visual-studio-2010-september-08-ctp.aspx)

  1. Rule Sets – 드디어, 규칙을 프로젝트 별로 하나 하나 빼던 수고스러움을 덜 수 있게 된 것 같습니다. DevPartner Code Review와 같은 상용 툴에서는 진작에 제공되던 기능이었지만, 이제 드디어 Visual Studio 2010에서는 Rule들을 Set으로 만들고 그 Rule Set 기반으로 코드 리뷰를 할 수 있게 되었습니다.
  2. Check-In Policy – 당연한 말이겠지만, 바로 위에서 소개한 Rule Sets 기능이 Team Foundation Server의 Check-In 정책에도 적용할 수 있게 됩니다.
  3. 8개의 새로운 Data-Flow 규칙MSDN Code Gallery의 VS2005와 VS2008 코드 분석 비교 문서를 보시면 아시겠지만, VS2008에서 7개의 규칙이 빠진 바 있습니다. Data-Flow Analysis Engine의 각종 버그와 낮은 성능으로 말미암은 결과라고 하는데, 이번 Visual Studio Team System 2010에서는 Phoenix라는 새로운 분석 엔진의 탑재와 함께 다시 7개의 규칙들이 복귀했고, 새롭게 추가된 하나를 합쳐서 총 8개의 새로운 규칙이 추가되었습니다. 그리고 이번에 추가된 Phoenix 분석 엔진은 당연히 기존 엔진이 가지고 있었던 버그나 성능 문제를 해결한 새롭고 강력한 엔진입니다.

그러면 다음 포스팅을 통해서 이 세 가지 개선점들에 대해서 더 자세히 다뤄보도록 하겠습니다.

Strongly Typed Metadata
 
지난 포스트의 [MEF] 7. Exports and Metadata를 통해 Export 의 Contract 에 Metadata 를 제공하는 방법을 알아보았습니다.
 
MetadataAttribute 을 선언하여 Export 의 Metadata 를 제공하는 방법입니다.
 
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Email")]
[ExportMetadata("Logging", true)]
public class EmailMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import EmailMessageSender");
        }
}
 
Export 에 Metadata 를 제공해 주어서 무척 고맙지만, 위의 방법처럼 MetadataAttribute 를 선언하는 방법을 사용하기에 그다지 내키지 않는 구석이 있습니다.
 
아무래도 아래와 같은 이유 때문이겠죠?
 
l 메타데이터의 타입 불안정
l 빌드 시 오류를 해결이 어려움
l 사용상 모든 키값을 외우기 어렵고, 오타 발생 위험
 
위의 이유 때문에 Metadata 를 사용하기 위해 강력한 타입을 원하게 될 것입니다. 그리고 강력한 타입의 Metadata 를 사용하길 권장 드립니다.
 
 
Declaring Strongly Typed Metadata
 
Attribute 을 상속받아 Export 의 Metadata 를 Strongly Typed 으로 확장시키는 방법입니다.
 
아래의 Stringly Typed Metadata 를 위해 Attribute 클래스를 만드는 소스 코드 입니다.
 
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MessageSenderTypeAttribute : Attribute
{
        public MessageSenderTransport Transport { get; set; }
        public bool IsSecure { get; set; }
 
        public MessageSenderTypeAttribute() { }
 
        public MessageSenderTypeAttribute(MessageSenderTransport transport)
               : this(transport, false)
        {
        }
 
        public MessageSenderTypeAttribute(MessageSenderTransport transport, bool isSecure)
        {
               this.Transport = transport;
               this.IsSecure = IsSecure;
        }
}
 
public enum MessageSenderTransport
{
        Email,
        Phone,
        Sms
}
 
Strongly Typed Metadata 를 위한 Attribute 클래스를 완성하였으면, 이것을 그대로 ExportAttribute 과 함께 추가적으로 선언하면 됩니다.
 
그리고 ExportAttribute 을 선언한 코드에 위의 Attribute 특성을 부여합니다. 아래는 그 소스 코드의 일부입니다.
 
[Export(typeof(IMessageSender))]
[MessageSenderType(MessageSenderTransport.Email)]
public class EmailMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import EmailMessageSender");
        }
}
 
[Export(typeof(IMessageSender))]
[MessageSenderType(MessageSenderTransport.Phone, true)]
public class PhoneMessageSneder : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import PhoneMessageSneder");
        }
}
 
[Export(typeof(IMessageSender))]
[MessageSenderType(Transport=MessageSenderTransport.Sms, IsSecure=true)]
public class SmsMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import SmsMessageSender");
        }
}
 
그렇다면 아래와 같이 Metadata 를 Strongly Typed 으로 질의(Query) 할 수 있게 됩니다.
 
아래의 소스 코드는 지난 포스트의 소스 전체 소스 코드를 참고하십시오.
 
foreach (var export in program.Sender)
{
        if ((MessageSenderTransport)export.Metadata["Transport"] == MessageSenderTransport.Sms)
        {
               export.GetExportedObject().Say();
 
               if ((bool)export.Metadata["IsSecure"] == true)
               {
                       Console.WriteLine("Security message");
               }
        }
}
 
위의 소스 코드 실행 결과는 원하던 결과대로 다음과 같습니다.
 

[그림1] Strongly Typed 질의 결과
 
 
하지만 아직도 문제는 남아 있는 것 같아 보이네요. Strongly Typed 으로 Export Metadata 를 선언하였지만 여전히 질의(Query) 과정은 똑같은 문제점을 가지고 있습니다.
 
l 메타데이터의 질의(Query) 과정의 타입 불안정
l 빌드 시 오류를 해결이 어려움
l 사용상 모든 키값을 외우기 어렵고, 오타 발생 위험
 
 
More Strongly Typed Metadata Query
 
Metadata 를 질의(Query) 하기 위해 MEF 는 보다 강력하게 Import 하는 방법을 제공해 줍니다. 확장된 MetadataAttribute 에 인터페이스(Interface) 를 구현하도록 하여 Import 시에 인터페이스(Interface) 를 통한 Metadata 를 질의(Query) 하는 방법입니다.
 
우선 Attribute 에 사용되는 프로퍼티를 인터페이스로 선언합니다.
 
public interface IMessageSenderTypeAttribute
{
        bool IsSecure { get; }
        MessageSenderTransport Transport { get; }
}
 
단, 여기에서 반드시 Getter 만 선언하셔야 합니다. Setter 를 선언하시면 MEF 는 Setter 프로퍼티로 인해 유효하지 않는 Attribute 으로 인식하여 예외를 발생하게 됩니다.
 
아래의 소스 코드는 Metadata Attribute 클래스에 위의 인터페이스를 구현한 코드 입니다.
 
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple=false)]
public class MessageSenderTypeAttribute : Attribute, IMessageSenderTypeAttribute
{
        public MessageSenderTransport Transport { get; set; }
        public bool IsSecure { get; set; }
 
        public MessageSenderTypeAttribute() { }
 
        public MessageSenderTypeAttribute(MessageSenderTransport transport)
               : this(transport, false)
        {
        }
 
        public MessageSenderTypeAttribute(MessageSenderTransport transport, bool isSecure)
        {
               this.Transport = transport;
               this.IsSecure = IsSecure;
        }
}
 
 
이제 Export 의 MetadataView 로 질의할 수 있도록 MetadataView 의 인터페이스를 알려주도록 해야 합니다.
 
[Import(typeof(IMessageSender))]
ExportCollection<IMessageSender, IMessageSenderTypeAttribute> Sender { get; set; }
 
아래의 소스 코드는 MetadataView 를 통해 Strongly Typed 으로 Export Metadata 를 질의(Query) 하는 소스 코드 입니다.
 
[Import(typeof(IMessageSender))]
ExportCollection<IMessageSender, IMessageSenderTypeAttribute> Sender { get; set; }
                                             
static void Main(string[] args)
{
        Program program = new Program();
        program.Run();
 
        foreach (var export in program.Sender)
        {
               if (export.MetadataView.Transport == MessageSenderTransport.Email)
               {
                       export.GetExportedObject().Say();
               }
        }
}
 


'Managed Extensibility Framework' 카테고리의 다른 글

[MEF] 10. Querying the CompositionContainer  (0) 2009.05.18
[MEF] 9. Recomposition  (1) 2009.04.19
[MEF] 7. Exports and Metadata  (0) 2009.04.16
[MEF] 6. Lazy Exports  (0) 2009.04.13
[MEF] 5. Catalog 사용  (0) 2009.04.09

[MEF] 7. Exports and Metadata

Managed Extensibility Framework 2009. 4. 16. 01:11 Posted by POWERUMC
Exports and Metadata
 
Export 에 Metadata 를 등록하고 제어하는 방법입니다. 지난 포스트에서 알 수 있듯이 Export 는 구성 요소간에 Contact 를 제공하여 이들을 구성(Composition) 할 수 있는 플러그인 모델(Plugin Model) 을 제공해 줍니다.
 
하지만 Contract 가 제공되어 구성 요소를 확장하고 구성하는 것은 매우 용이하다는 것을 알게 되었으나 Contract 로 인해 파생된 다양한 구성 요소를 어떻게 제어하느냐의 고민을 하게 됩니다. 즉, 다양한 구성 요소 가운데 내가 필요로 하는 구성 요소를 골라낼 수 있도록 Metadata 를 제공하여 구성 요소를 질의(Query)할 수 있도록 하는 것입니다.
 

예를 들어 아래와 같은 Export 구성 요소 중 어떻게 EmailMessageSender 로 Say() 를 호출할 것인가가 문제인 것이죠.

[Export(typeof(IMessageSender))]
public class EmailMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import EmailMessageSender");
        }
}
 
[Export(typeof(IMessageSender))]
public class PhoneMessageSneder : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import PhoneMessageSneder");
        }
}
 
[Export(typeof(IMessageSender))]
public class SmsMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import SmsMessageSender");
        }
}
 
이런 경우, 원초적인 방법으로 리플랙션(Reflection) 을 이용하여 Type 검사를 통해 EmailMessageSender 를 골라내서 사용하면 되지만, 직접적으로 Type 을 검사하기 위해서는 Tightly Coupling 이 발생하여 결국 유연한 플러그인 모델을 구현하기 위해 아무런 도움이 되지 않습니다.
 
이러한 방법을 해소하기 위해 또 다른 우회 방법은 리플랙션을 통해 Modules Name 으로 비교하는 방법이지만, 이것 또한 플러그인 모델에서 구성 요소가 교체 되었을 경우를 생각하면 전혀 대응할 수 없는 방법입니다.
 
MEF 에서는 이런 문제를 해소하기 위해 Contract 에 Metadata 를 제공하며 정적/동적인 방법을 제공해 줍니다.
 
 
Attaching Metadata to an Export
 
Export 에 Metadata 를 제공해 주기 위해서 MEF 에서는 ExportMetadataAttribute 특성을 제공해 줍니다.
 
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Field,
                    AllowMultiple = true, Inherited = false)]
public ExportMetadataAttribute(string name, object value)
 
왜 ExportMetadata 클래스는 sealed 로 선언이 되었나요?
 
일반적으로 sealed 로 클래스를 봉인할 경우 리플랙션의 성능이 향상됩니다.
 
 
ExportMetadata 는 키와 값(Key/Value) 을 지정하여 Contract 에 Metadata 를 제공해 줄 수 있습니다. 그리고 하나의 Export 에 여러 개의 Metadata 를 제공할 수 있도록 AllowMultiple 을 지원합니다.
 
Metadata 는 여러 가지의 정보를 포함할 수 있습니다. Export 가 제공하는 기능의 특성을 기술할 수 있으며, 예를 들어, 권한, 로깅, 구성 요소 분류 방법 등이 될 수 있을 것입니다.
 
아래의 소스 코드는 Metadata 를 지정하는 예를 보여줍니다.
 
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Email")]
[ExportMetadata("Logging", true)]
public class EmailMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import EmailMessageSender");
        }
}
 
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Phone")]
public class PhoneMessageSneder : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import PhoneMessageSneder");
        }
}
 
[Export(typeof(IMessageSender))]
[ExportMetadata("SenderType", "Sms")]
public class SmsMessageSender : IMessageSender
{
        public void Say()
        {
               Console.WriteLine("Import SmsMessageSender");
        }
}
 
 
 
Constraining Imports statically
 
MEF Preview 5 에서는 ImportRequiredMetadataAttribute 클래스가 제거되었습니다.
 
MEF Preview 4 에서는 선언적인 방법으로 ImportRequiredMetadataAttribute 를 통해 Metadata 를 질의할 수 있었으나, MEF Preview 5 에서는 ImportRequiredMetadataAttribute 클래스가 제거되었습니다.
 
아마도 추측으로는 ImportRequiredMetadataAttribute 를 선언 시에 여러 개의 구성 요소가 검색될 경우 Exception 이 발생하는데, Exception 을 최소화 하고자 제거가 된 것 같습니다.
 
혹시 Statically 한 방법으로 ImportRequiredMetadataAttribute 에 대응되는 클래스를 아시면 저에게 알려주세요.
 
 
Constraining Imports dynamically
 
이 방법은 Export 의 ExportMetadata 를 런타임 시에 질의(Query) 하는 방법입니다.
 
Import 시 ExportCollection<T> 을 사용하여 Export 를 수동적으로 질의(Query) 하는 방법입니다. 이 방법은 지난 포스트의 Lazy Load 를 이용한 방법으로 단지 Metadata 만 질의(Query) 뿐이고, 객체의 생성에 대한 판단은 필요 시에만 GetExportedobject() 메서드를 이용하여 생성할 수 있습니다.
 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
 
namespace MetadataSample
{
        class Program
        {
               [Import(typeof(IMessageSender))]
               ExportCollection<IMessageSender> Sender { get; set; }
 
               static void Main(string[] args)
               {
                       Program program = new Program();
                       program.Run();
 
                       foreach (var export in program.Sender)
                       {
                              if ((string)export.Metadata["SenderType"] == "Email")
                                      export.GetExportedObject().Say();
 
                              if (export.Metadata.ContainsKey("Logging") &&
                                      (bool)export.Metadata["Logging"] == true)
                                      Console.WriteLine("Logged success");
                       }
               }
 
               void Run()
               {
                       var catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
 
                       var container = new CompositionContainer(catalog);
                       var batch = new CompositionBatch();
                       batch.AddPart(this);
                       container.Compose(batch);
               }
 
               public interface IMessageSender
               {
                       void Say();
               }
 
               [Export(typeof(IMessageSender))]
               [ExportMetadata("SenderType", "Email")]
               [ExportMetadata("Logging", true)]
               public class EmailMessageSender : IMessageSender
               {
                       public void Say()
                       {
                              Console.WriteLine("Import EmailMessageSender");
                       }
               }
 
               [Export(typeof(IMessageSender))]
               [ExportMetadata("SenderType", "Phone")]
               public class PhoneMessageSneder : IMessageSender
               {
                       public void Say()
                       {
                              Console.WriteLine("Import PhoneMessageSneder");
                       }
               }
 
               [Export(typeof(IMessageSender))]
               [ExportMetadata("SenderType", "Sms")]
               public class SmsMessageSender : IMessageSender
               {
                       public void Say()
                       {
                              Console.WriteLine("Import SmsMessageSender");
                       }
               }
        }
}
 
 
실행 결과는 예상할 수 있듯이 아래와 같이 런타임 시에 결과를 보여줍니다.


'Managed Extensibility Framework' 카테고리의 다른 글

[MEF] 9. Recomposition  (1) 2009.04.19
[MEF] 8. Strongly Typed Metadata  (0) 2009.04.16
[MEF] 6. Lazy Exports  (0) 2009.04.13
[MEF] 5. Catalog 사용  (0) 2009.04.09
[MEF] 4. Import 선언  (0) 2009.04.07

안녕하세요. 이번에 Visual Studio Team System 2010 공식 블로그에 새롭게 참여하게 된 LazyDeveloper.Net의 kkongchi라고 합니다. Better Code 시리즈를 통해서 Code Analysis, Unit Test 등에 대한 포스팅을 해보도록 하겠습니다. 부족한 부분 많이 지적해 주시길 바랍니다.

 

TDD?

eXtreme Programming의 창시자 중 하나인 Kent Beck의 eXtreme Programming explained라는 책을 보면 Test를 작성하는 방법에 대해서 이렇게 기술하고 있습니다.

  • If the interface for a method is at all unclear, you write a test before you write the method. (메서드의 인터페이스가 클리어하지 않다면, 메서드를 작성하기 전에 테스트를 먼저 작성해라)

  • If the interface is clear, but you imagine that the implementation will be the least bit complicated, you write a test before you write the method. (메서드의 인터페이스가 클리어하더라도 당신이 생각하기에 구현이 조금 복잡할 것 같다면, 메서드를 작성하기 전에 먼저 테스트를 작성해라)

  • 이런 eXtreme Programming의 Test-Before-Writing 전략을 개발 프로세스에 전면적으로 도입하는 것을 Test Driven Development, 즉 TDD라고 합니다. TDD에 관한 위키피디아 페이지에서 소개하는 TDD의 개발 사이클은 다음과 같습니다. “Red, Green, Refactor”라고 표현하기도 합니다.

    다들 아시다시피, Visual Studio에서는 2005 버전에서부터 Team System의 일부로써 Testing Framework을 제공하고 지원해왔습니다. 그리고 드디어 이번 Visual Studio Team System 2010에서는 완벽하게 TDD의 개념이 Visual Studio Team System안으로 녹아 들어가게 된 것 같습니다. 바로 새롭게 추가된 기능 “Generate” 기능을 통해서, Test를 먼저 작성한 후에 그 Test로부터 코드를 자동으로 Generate해주는 기능이 추가된 것입니다.

     

    TDD Development in VSTS 2010 by “Generate”

    지난 11월에 나온 Visual Studio 2010 and .NET Framework 4.0 Training Kit의 Lab을 통해서 이 기능에 대해서 좀 더 자세히 알아보도록 하겠습니다.

     

    당연히 먼저 테스트를 작성하는 것부터 시작합니다. 하지만, 아직 만들어지지 않은 클래스이기 때문에 아래 그림처럼 빨간색 물결 라인으로 경고가 뜹니다. 여기서 마우스 오른쪽 버튼을 눌러보면, 새로운 “Generate” 기능을 볼 수가 있습니다.

    Generate class를 선택하면 같은 프로젝트에 Class가 추가됩니다. 하지만 Generate other..를 선택하면 아래와 같은 팝업 윈도우가 나옵니다. 클래스를 만들 수 있는 Wizard 개념이라고 보시면 되겠습니다.

    이 Wizard를 통해서 클래스의 Access 한정자, Type, 그리고 파일을 만들 프로젝트까지 설정을 할 수가 있습니다. 이 과정을 통해서 우리는 완벽하게 Test로부터 시작해서 뼈대 코드를 만들어 낼 수가 있습니다. 아래 그림처럼 말이죠..

    이제 이 자동으로 만들어진 뼈대 코드에 구현을 추가하게 되면 여러분들은 다음과 같이 Test를 통과했다는 기분 좋은 화면을 보실 수 있으실 것입니다.


    위에서 보신 Demo Code의 시연은 http://channel9.msdn.com/shows/10-4/10-4-Episode-5-Code-Focused-in-Visual-Studio-2010/#Page=4 에서 Video로도 감상하실 수 있고, http://www.microsoft.com/downloads/details.aspx?FamilyID=752CB725-969B-4732-A383-ED5740F02E93&displaylang=en 에서 Lab Document와 소스 코드도 얻으실 수 있습니다.
     

    지금까지 보신 것처럼 앞으로 출시될 VSTS 2010에서는 IDE 자체에서 완벽한 TDD 지원 기능이 통합되었습니다. TDD가 만능의 도구는 아닙니다. 하지만, 적어도 개발자가 자신의 코드에 대한 이해도가 통상적인 개발 방법보다는 훨씬 크고 깊을 것이라 기대합니다. 어설픈 문서보다는 잘 만들어진 테스트 코드들이 오히려 실제 구현 코드를 이해하는 데 더 도움이 되는 경우도 많습니다. Visual Studio Team System 2010은 효율적인 Test Driven Development를 가능하게 해주는 최고의 도구가 될 것 같습니다.

    부족한 글 읽어주셔서 감사하고, 많은 의견 부탁 드립니다.

    [MEF] 6. Lazy Exports

    Managed Extensibility Framework 2009. 4. 13. 00:38 Posted by POWERUMC
    일반적인 Exports
     
    Composable Part 를 구성하는 동안 특정 Part 에 대한 요청으로 객체 내부의 객체가 필요할 때가 있습니다. 만약 객체가 이런 연관 관계가 있을 경우 객체 내부에 ImportAttribute 을 선언하여 외부 Part 를 Import 할 수 있습니다. 이런 경우는 객체 내부에 Export 간의 Related 관계를 갖게 됨으로써 자동적으로 객체를 초기화할 수 있게 됩니다. ([MEF] 3. Export 선언 참조)
     
    일반적인 Export 를 통해 객체 내부에 Import 를 선언하는 방법입니다.
     
    class Program
    {
            static void Main(string[] args)
            {
                   Program p = new Program();
                   p.Run();
            }
     
            void Run()
            {
                   var catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
     
                   var container = new CompositionContainer(catalog);
                   var batch = new CompositionBatch();
                   batch.AddPart(this);
     
                   container.Compose(batch);
     
                   var obj = container.GetExportedObject<EmailMessageSender>();
                   obj.Sender.Say();
            }
    }
     
    [Export]
    public class MessageSender
    {
            public void Say()
            {
                   Console.WriteLine("Say Method");
            }
    }
     
    [Export]
    public class EmailMessageSender
    {
            [Import]
            public MessageSender Sender { get; set; }
    }
     
     
    Lazy Exports
     
    하지만 비용이 비싼 객체를 생성할 경우 위의 [일반적인 Exports] 는 매우 비효율적일 수 있습니다. 객체 내부의 Import Object 를 사용하지 않을 가능성이 크거나, 객체의 생성 비용이 클 경우는 Lazy Export 를 고려해야 합니다. 그리고 내부 객체가 동기적(Synchronicity)이 아닌 비동기성(Asynchronism) 성격의 객체일 경우에도 반드시 필요한 기법입니다.
     
    이런 경우 내부 객체의 생성을 선택적, 수동적으로 제어하여, 게으른 초기화(Lazy Initialization) 를 할 필요가 있습니다.
     
    아래의 굵은 표시의 코드가 Lazy Export 로 제어하는 코드입니다.
     
    class Program
    {
            static void Main(string[] args)
            {
                   Program p = new Program();
                   p.Run();
            }
     
            void Run()
            {
                   var catalog = new AggregateCatalog(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
     
                   var container = new CompositionContainer(catalog);
                   var batch = new CompositionBatch();
                   batch.AddPart(this);
     
                   container.Compose(batch);
     
                   var obj = container.GetExportedObject<EmailMessageSender>();
                   obj.Sender.Say();
     
                   var lazyObj = container.GetExportedObject<EmailMessageSenderByLazyExport>();
                   lazyObj.Sender.GetExportedObject().Say();
            }
    }
     
    [Export]
    public class MessageSender
    {
            public void Say()
            {
                   Console.WriteLine("Say Method");
            }
    }
     
    [Export]
    public class EmailMessageSender
    {
            [Import]
            public MessageSender Sender { get; set; }
    }
     
    [Export]
    public class EmailMessageSenderByLazyExport
    {
            [Import]
            public Export<MessageSender> Sender { get; set; }
    }
     
    ImportAttribute 의 프로퍼티를 Export<T> 타입으로 변경하면 내부 객체를 GetExportedObject() 메서드를 이용하여 지연하여 객체를 생성할 수 있습니다.

    'Managed Extensibility Framework' 카테고리의 다른 글

    [MEF] 8. Strongly Typed Metadata  (0) 2009.04.16
    [MEF] 7. Exports and Metadata  (0) 2009.04.16
    [MEF] 5. Catalog 사용  (0) 2009.04.09
    [MEF] 4. Import 선언  (0) 2009.04.07
    [MEF] 3. Export 선언  (0) 2009.03.29

    [Blueprints] S+S Blueprints

    VIsual Studio Extensibility 2009. 4. 12. 23:13 Posted by POWERUMC
    새로운 트랜드 Blueprints
     
    Blueprints 는 새로운 개념의 Software Factory 입니다. 언제나 우리는 반복되는 작업과 그것을 수행하기 위한 새로운 기술, 그리고 좋은 패키지를 만들기 위한 디자인, 그리고 버그를 수정하기 위한 작업을 팩토리(Factory) 라는 개념의 트랜드된 기술입니다. 팩토리(Factory) 는 Web Service, Rich Internet Application(RIA), Service Facade 를 쉽게 제공할 수 있으며 그것은 특정 프로세스, 리소스, 가이드라인, 패턴, 템플릿, 라이브러리 등이 포함됩니다.
     
    Blueprints 의 팩토리는 소프트웨어 생산 공정(Software product line-SPL) 의 형태입니다. 일관된 공통적인 프로세스를 통해 패턴을 정하여 또는 공통적인 프로세스를 정의함으로써 재사용성을 높이고 체계적인 생산 공정을 정의할 수 있습니다.
     
    Software Factory 는 특정 도메인 언어(Domain-Specific Language-DSLs) 를 통해 모델 기반 개발(Model-driven Development-MDD) 를 중요시하는 마이크로소프트 플랫폼을 위한 SPLs 입니다. MDD 는 Application, Services, Layers, Component 등의 복잡한 요소를 대상으로 하는데, Software Factory 는 이러한 복잡한 요소들을 단순화할 수 있습니다.
     
    [그림1] Software Factory 가 생성되고 적용되는 그림
     
     
    Blueprints 가 있기 까지
     
    Blueprints 는 Guidance Automation Toolkit(GAT) 가 그 기반에 존재합니다. GAT 는 Microsoft 의 Pattern & Practice 팀에서 Guidance Automation(GA) 를 쉽게 적용하기 위한 툴입니다. GAT 는 Guidance Automation Extension(GAX) 를 기반으로 Web Service, Web Client, Smart Client 등 Enterprise Library 와 통합시켰고 Guidance Cunsumer 를 통해 커스터마이징이 가능한 도구입니다.
     
    하지만 GAT 는 Guidance Automation(GA) 는 한계가 있었고, 이런 GAX/GAT 를 기반으로 RSS-based Factory 와 런타임 확장 및 업데이트가 가능한 새로운 서비스를 제공하게 되었습니다. 바로 이것이 S+S Blueprints 입니다.
     
    S+S 는 Software plus Services 라는 의미로 Web 2.0 과 SOA 양측 모두 적용할 수 있습니다. Web 2.0 은 나은 응답성을 요구하고 SOA 는 보안과 안정성을 요구하는데, 기업은 이런 SOA 에 Web 2.0 의 응답성과 유연함의 장점을 원합니다. 이러한 Server Software base 의 IT System 은 SaaS Base 의 Web 2.0 을 지원하기 위해 Loosely connected message-passing system 의 서비스를 추가할 것입니다. 기업은 이러한 데이터 보안, 가용성, 응답성과 유연함을 원할 것입니다.
     
    그리고 DSL Tools 입니다. DSL Tools 은 Visual Studio 2005 이상, Team Architect 버전에 포함된 Domain-Specific Language 를 쉽게 구현하기 위한 도구입니다. DSL 은 저렴한 비용으로 UML Modeling 을 할 수 있으며, 기업의 이해관계가 다른 (예를 들어 기업의 경영진과 실무진??) 사람과 통용할 수 있는 좋은 도구가 됩니다.
     
    [그림2] 오늘날 Factory 기술의 발전
     
     
    Blueprints 다운로드 받기
     
    Blueprints 는 Codeplex 에서 다운로드 할 수 있습니다. 현재 Blueprints 는 November CTP Refresh 2.1.2 버전입니다.
     
    Blueprints Download
     
     
    Blueprints 는 Visual Studio Extensibility(VSX) 로 제작되어 Visual Studio 에 Blueprints Manager(BPM) 를 통해 실행할 수 있습니다.
     
    [그림3] Blueprints Manager(BPM) 실행 화면
     
     
    오늘은 Blueprints 를 소개하는 단원에서 끝내며, 추후에 Blueprints 의 Factory 를 만들고 Publish, 그리고 프로세스의 Work flow 등 보다 근접한 S+S Blueprints 를 소개해 드리도록 하겠습니다.
     
    참고 문헌
     
     

    Visual Studio 2010 & .NET 4.0 참고 자료들

    Visual Studio 2010 2009. 4. 8. 16:37 Posted by 알 수 없는 사용자

    안녕하세요.
    아직 VSTS 2010 관련 한글 자료가 많지 않아 미리 보고 써보는게 쉽지는 않은 상황 입니다.
    그렇다고 계속 기다릴 수도 없고, 비록 영문 자료지만, 충분히 보고 따라 할 수 있는 자료를 소개 합니다.

    마이크로소프트의 개발자 동영상 사이트 중 절때 빠질 수 없는 채널9(Channel9)의 "Visual Studio Team System 2010 Week on Channel 9!" 시리즈가 있습니다.
    여기에서 VSTS 2010의 개발 철학이나 개선되거나 추가된 기능 등에 대한 인터뷰를 볼 수 있습니다.
    사실 영어가 좀 부담이 되는 부분이기는 합니다.

    다음으로 좀 더 볼게 많은 "Visual Studio 2010 and the .NET Framework 4.0 Week!" 시리즈가 있습니다. VSTS 2010 오버뷰 부터 C# 4.0, C++ 10 등 보다 풍부한 볼거리를 제공합니다.

    특히 C#의 아버지인 Anders Hejlsberg의 "C# 4.0 - Questions and reasons behind the answers"는 강력 추천 입니다.

    그리고 마지막으로 Visual Studio 10과 .NET 4.0의 주요 내용을 에피소드로 소개하는 10-4가 있습니다.
    계속 시리즈로 올라오고 있으니 꼭 참고 하시기 바랍니다. 좋은 내용들이 많이 있습니다.

    감사합니다.



     

    [MEF] 3. Export 선언

    Managed Extensibility Framework 2009. 3. 29. 21:03 Posted by POWERUMC
    Exports 선언
     
    MEF 는 Export 를 통해 외부로 구성요소를 노출할 수 있습니다. Export 는 System.ComponentModel.Composition.ExportAttribute 특성을 통해 선언합니다. 이 특성은 클래스 뿐만 아니라 프로퍼티와 메서드에도 선언을 할 수 있습니다.
     
     
    구성요소 Export 하기
     
    ExportAttribute 특성을 사용하여 아래와 같이 구성요소를 외부로 노출하게 됩니다. ExportAttribute 은 몇 가지의 시그너처(Signature) 를 제공하는데 매개변수를 생략하게 될 경우 MEF 은 클래스의 타입으로 Contract 를 매핑하게 됩니다.
     
    [Export]
    class MessageSender
    {
     
    }
     
     
    프로퍼티 Export
     
    프로퍼티를 Export 하는 방법입니다. 프로퍼티를 Export 할 수 있게 되어 여러 가지 면에서 유리할 수 있습니다.
     
    Core CLR 이 제공하는 타입(Type) 뿐만 아니라 외부의 다양한 타입(Type) 을 사용할 수 있습니다. 프로퍼티에 Export 를 선언할 수 있음으로써 Export 를 구조적으로 분리하여 단순화 할 수 있습니다. 그러므로 같은 구성요소 내에서 Export 간의 Related 관계를 가질 수 있습니다.
     
    아래의 코드와 같이 Timeout 프로퍼티는 Contract 를 맺게 됩니다.
     
    public class Configuration
    {
       [Export("Timeout")]
       public int Timeout
       {
           get { return int.Parse(ConfigurationManager.AppSettings["Timeout"]); }
       }
    }
     
    [Export]
    public class UsesTimeout
    {
       [Import("Timeout")]
       public int Timeout { get; set; }
    }
     
     
    메서드 Export
     
    구성요소의 메서드를 Export 할 수 있습니다. 메서드의 Export 는 기본적으로 대리자(Delegate) 를 통해 호출하게 됩니다. 메서드를 Export 하게되면 보다 더 세세한 제어를 가능하게 하고, 심플하게 방법으로 Code Generating 이 가능합니다.
     
    public class MessageSender
    {
       [Export(typeof(Action<string>))]
       public void Say(string message)
       {
           Console.WriteLine(message);
       }
    }
     
    [Export]
    public class MessageProcess
    {
       [Import(typeof(Action<string>))]
       public Action<string> MessageSender { get; set; }
     
       public void Send()
       {
           MessageSender("Call send process in MessageProcess");
       }
    }
     
    그리고 ExportAttribute 은 타입(Type) 대신 문자열을 사용하여 Contract 를 사용할 수 있습니다.
     
    public class MessageSender
    {
       [Export("MessageSender")]
       public void Say(string message)
       {
           Console.WriteLine(message);
       }
    }
     
    [Export]
    public class MessageProcess
    {
       [Import("MessageSender")]
       public Action<string> MessageSender { get; set; }
     
       public void Send()
       {
           MessageSender("Call send process in MessageProcess");
       }
    }
     
     
    아래의 소스 코드는 이번 예제에서 사용된 전체 소스 코드입니다.
    namespace ExportSample
    {
       class Program
       {
           [Import]
           MessageProcess MessageProcess { get; set; }
     
           [STAThread]
           static void Main(string[] args)
           {
                 Program p = new Program();
                 p.Run();
     
                 p.MessageProcess.Send();
           }
     
           private void Run()
           {
                 var catalog = new AggregateCatalog();
                 catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
     
                 var container = new CompositionContainer(catalog);
                 var batch = new CompositionBatch();
                 batch.AddPart(this);
                 container.Compose(batch);
           }
       }
     
       public class MessageSender
       {
           [Export("MessageSender")]
           public void Say(string message)
           {
               Console.WriteLine(message);
           }
       }
     
       [Export]
       public class MessageProcess
       {
           [Import("MessageSender")]
           public Action<string> MessageSender { get; set; }
     
           public void Send()
           {
                 MessageSender("Call send process in MessageProcess");
           }
       }
    }
     
     
    Export 요약
     
    이렇게 ExportAttribute 을 사용하여 Contract 를 제공하는 것은 굉장히 중요한 의미를 가지게 됩니다. 플러그인 모델(Plugin Model) 에서 Export 는 구성요소를 외부로 노출하는, 즉 Contract 의 방법을 제공해 주게 됩니다.
     
    http://blog.powerumc.kr/upload/Image/NET/NET-Framework/MEF1/capture1.jpg
     
    Contract 맺음으로써 개발자는 Contract Base 로 단지 Contract 만 제공받으면 됩니다. 이러한 Contract 는 제한된 상호작용을 극복하여 대부분의 커플링(Coupling)을 해소할 수 있으며, 플로그인 모델(Plugin Model) 에서 보다 쉽게 구성요소를 캡슐화 할 수 있습니다.

    'Managed Extensibility Framework' 카테고리의 다른 글

    [MEF] 6. Lazy Exports  (0) 2009.04.13
    [MEF] 5. Catalog 사용  (0) 2009.04.09
    [MEF] 4. Import 선언  (0) 2009.04.07
    [MEF] 2. Parts 와 Contracts 선언  (0) 2009.03.22
    [MEF] 1. Managed Extensibility Framework 이란?  (2) 2009.03.16
    Kirill Osenkov 은 새로운 Visual Studio 2010 의 Visual Studio 2010 의 언어와 IDE 를 다루는 약 30분 정도 동영상을 촬영하여 공개하였습니다. 이 동영상은 매우 기초적인 내용만을 다루며, 기능에 대한 상세한 부분은 다루지 않는다고 합니다.
     
    동영상에서 보는 Visual Studio 2010 은 WPF Shell 을 적용한 IDE 로 진행합니다. 그리고 이미 Visual Studio 2010 CTP 를 사용해본 분이라면 눈치 채셨겠지만, 동영상의 Visual Studio 2010 은 최근의 Internal Build 버전이라고 합니다. 그렇기 때문에, Visual Studio 2010 CTP 의 불안정한 WPF Shell 의 모습과 비교할 때 더욱 안정적이고 신선한 모습입니다.

    이제 Visual Studio 2010 의 베타 버전이 임박한 듯 합니다.
     
    Visual Studio 2010 Screencast: C# 4.0 Language + IDE + WPF Shell + Editor
     
     

     

    Task Parallel Library
     
    Parallel Extension 은 PLINQ 와 더불어 확장 가능한 Task Parallel Library 를 제공합니다. Task Parallel Library 는 PLINQ 를 이용하지 않고 개별적이고 수동적인 병렬 처리 작업을 위해 사용할 수 있습니다.
     
    Task Parallel Library 는 크게 세 가지 방법으로 병렬 처리를 위한 Library 를 제공합니다.
     
    Loops
     
     
     

     

    [그림1] Parallel.For 를 이용한 병렬 처리
     
     


    [그림2] Parallel.Foreach 를 이용한 병렬 처리
     
    Task Parallel Extension 으로 병렬 처리를 쉽게 처리할 수 있으며, 병렬 처리로 인자값을 넘기거나 하는 작업을 쉽게 할 수 있습니다.
     
    Statements
     

     


    [그림3] Parallel.Invoke 를 이용한 병렬 처리
     
     
    Task
     
    특히 Parallel Extension Library 에서 Task 는 수동적으로 병렬 처리를 하기 위해 다양한 기능을 지원합니다. 정교하게 스레드(Thread) 를 처리했던 것에 비하면 심플하고도 직관적으로 병렬 작업을 처리할 수 있습니다.
     
    Task 는 보다 정교하게 병렬 처리 작업을 할 수 있습니다.
    l 대기
    l 취소
    l 연장
    l 상하(부모/자식) 간의 관계
    l 디버그 지원
     
    아래는 ThreadPool.QueueUserWorkItem 처럼 바로 작업을 시작하도록 합니다.
     

    Task.StartNew(…);

     
    아래는 Task 에 대해 대기 및 취소 작업을 진행하도록 합니다.
     

    Task t1 = Task.StartNew(…);
    t1.Wait();
    t1.Cancel();
    Task t2 = t1.ContinueWith(…);

     
    아래는 작업에 대해 지속적인 병렬 처리를 가능하도록 합니다.
     

    var p = Task.StartNew(() => {
        var c = Task.StartNew(…);
    }

     
    아래는 특정 작업의 결과를 받아 올 수 있습니다.
     

    var p =
     Future.StartNew(() => C());
    int result = p.Value;
     

     
     
    Coordination Data Structures
     
    병렬 처리 작업은 PLINQ 와 TPL(Task Parallel Library) 를 지원하기 위해 기존의 데이터 컬렉션 등이 등장하였습니다. 내부적으로 동기화를 지원하지 않았던 문제들을 지원하게 되었고, 특히 오늘날 멀티 코어(Multi Core) 프로세스를 위해 많은 동기적인 문제를 고민해야 했습니다. .NET Framework 4.0 은 이러한 공통적인 문제들을 해결하기 할 수 있습니다.
     
    l Thread-safe collections
           ConcurrentStack<T>
           ConcurrentQueue<T>
           ConcurrentDictionary<TKey,TValue>
          
    l Work exchange
           BlockingCollection<T>
           IProducerConsumerCollection<T>
    l Phased Operation
           CountdownEvent
           Barrier
    l Locks
           ManualResetEventSlim
           SemaphoreSlim
           SpinLock
           SpinWait
    l Initialization
           LazyInit<T>
           WriteOnce<T>
    최근 대부분의 사용자들의 컴퓨터의 사양이 코어2 로 업그레이드 되고 있습니다. CPU 제품에 따라 코어에 대한 아키텍처가 다르지만, 기본적으로 이들 제품은 하나의 컴퓨터에 CPU 가 두 개인 제품들입니다. 인간과 비교하자면 뇌가 두 개인 사람인데 그다지 상상해서 떠올리고 싶지 않네요^^.
     
    컴퓨터는 CPU 두 개를 보다 효율적으로 이용하기 위해 바로 Parallelism Processing(병렬 처리)를 하게 됩니다. 하나의 CPU 의 성능을 향상시키는 방법이 아닌, 두 개의 CPU 에게 작업을 할당함으로써 데이터의 처리 성능을 극대화 시키게 됩니다. 우리에게 익숙한 운영체제인 윈도우(Windows) 의 멀티 쓰레딩(Multi Threading) 을 생각하면 병렬 처리(Parallelism Processing) 는 그렇게 어려운 개념은 아닙니다.
     
    [그림1] 어쨌든 뇌가 두 개 (여기에서 참조)
     
    원래 오픈 소스 프로젝트로 Parallel Extension 프로젝트를 CodePlex 에서 본 기억이 있는데, 지금은 링크의 주소를 찾을 수 가 없네요. 구글을 통해 “Parallel Extension” 을 검색하시면, .NET 에서의 Parallel Programming 의 흔적을 찾아볼 수 있습니다.
     
    우선 아래의 Person 클래스를 작성하여 테스트에 사용할 것입니다.
     
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
     
     
    General~
     
    코어(Core) 하나로 작업할 경우, 개발자는 아무것도 염려 하지 않아도 됩니다. 그 동안 우리가 배웠던 대로 코드를 작성하기만 하면 됩니다. 병렬 처리에 대한 고민을 하지 않고 개발한 코드라면 모두 이 범주에 속하겠네요. 이러한 방법은 가장 보편적으로 작성할 수 있습니다.
     
    private static void GeneralSort(List<Person> people)
    {
           List<Person> resultPeople = new List<Person>();
           foreach (Person person in people)
           {
                 if (person.Age >= 50)
                        resultPeople.Add(person);
           }
     
           resultPeople.Sort((p1, p2) => p1.Age.CompareTo(p2.Age));
     
           foreach (var item in resultPeople) { }
    }
     
    List<Person> 개체를 파라메터로 넘겨주고, Person 중에 Age 가 50이 넘는 개체를 정렬하는 코드입니다.
    바로 이 코드를 병렬 처리를 하고자 합니다. 이 코드를 병렬 처리를 하고자 한다면 코드의 양은 훨씬 늘어나고, 복잡한 처리를 해야 합니다.
     
     
    Manual Parallelism
     
    일반적으로 데이터의 처리를 병렬 처리로 전환하기 위해서는 쓰레드(Thread) 를 사용합니다. 쓰레드(Thread) 가 생성이 되면 커널 또는 물리적인 프로세서에 의해 의해 유휴 상태 또는 처리가 가능한 코어(Core) 로 작업이 할당되어 다중 작업(Multi Process) 을 가능하게 됩니다.
     
    이러한 방법의 병렬 처리는 프로세서(Processor) 개수만큼 쓰레드(Thread) 를 생성하여 비동기 작업을 합니다.
     
    private static void ThreadSort(List<Person> people)
    {
           var resultPeople = new List<Person>();
           int partitionsCount = Environment.ProcessorCount;
           int remainingCount = partitionsCount;
           var enumerator = (IEnumerator<Person>)people.GetEnumerator();
           try
           {
                 using (var done = new ManualResetEvent(false))
                 {
                        for (int i = 0; i < partitionsCount; i++)
                        {
                               ThreadPool.QueueUserWorkItem(delegate
                               {
                                     var partialResults = new List<Person>();
                                     while (true)
                                     {
                                            Person baby;
                                            lock (enumerator)
                                            {
                                                  if (!enumerator.MoveNext()) break;
                                                  baby = enumerator.Current;
                                            }
                                            if (baby.Age >= 50)
                                            {
                                                  partialResults.Add(baby);
                                            }
                                     }
                                     lock (resultPeople) resultPeople.AddRange(partialResults);
                                     if (Interlocked.Decrement(ref remainingCount) == 0) done.Set();
                               });
                        }
                        done.WaitOne();
                        resultPeople.Sort((p1, p2) => p1.Age.CompareTo(p2.Age));
                 }
           }
           finally
           {
                 if (enumerator is IDisposable) ((IDisposable)enumerator).Dispose();
           }
     
           foreach (var item in resultPeople) { }
    }
     
    중요한 부분은 추출된 데이터의 정렬(Sort) 작업입니다. 이 작업을 하기 위해서는 모든 쓰레드(Thread) 의 작업이 끝나야 합니다. 만약 모든 쓰레드(Thread) 가 종료되지 않은 시점에서 정렬 작업을 하게 되면, 과연 정렬된 데이터를 신뢰할 수 있을까요?? ( 왜 그런지는 여러분의 상상에 맡기도록 합니다. )
     
    정렬 작업을 하기 전 ManualResetEvent 의 WaitOne() 메서드를 호출하여 모든 쓰레드(Thread) 의 WaitHandle 이 작업이 신호를 받을 때까지(동기화 작업) 기다려야 합니다. 예를 들어, 두 개의 쓰레드(Thread) 가 생성 되고 첫 번째 쓰레드는 이미 작업을 종료하였지만, 두 번째 쓰레드는 아직 작업이 완료되지 않았다면, 작업을 마친 모든 쓰레드(Thread) 는 가장 늦게 처리가 완료되는 쓰레드를 기다려야 정렬 작업을 진행할 수 있습니다.
     
    마지막으로, 위의 코드의 병렬 처리 작업은 성능에 한계가 있습니다. 프로세서(Processor) 개수만큼 쓰레드(Thread) 를 생성하여 작업을 분배하는 방식이기 때문에, 병렬 처리 작업의 성능은 곧 프로세서(Processor) 개수가 될테니까요!
     
     
    Parallel Extension
     
    C# 4.0 은 병렬 처리를 하기 위해 코드의 양을 획기적으로 줄일 수 있습니다.
     
    private static void ParallelSort(List<Person> people)
    {
           var resultPerson = from person in people.AsParallel()
                                        where person.Age >= 50
                                        orderby person.Age ascending
                                        select person;
     
           foreach (var item in resultPeople) { }
    }
     
    LINQ 식을 사용하여 데이터 처리와 정렬 작업을 간단하게 할 수 있습니다. 감격이네요^^ 바로, .NET Framework 4.0 의 Parallel Extension 을 사용하여 LINQ 처럼 사용하는 것을 PLINQ 라고 합니다.
     
    Q : foreach (var item in resultPeople) { } 코드를넣었나요?
     
    A: 동일한 테스트를 하기 위함입니다. LINQ 식은 내부 구조의 특성상 “쿼리식”에 불과합니다.
    보다 자세한 내용은 필자의 블로그를 참고하세요.
     
    Parallel Extension 은 Manual Parallelism 보다 더 복잡하고 좋은 성능을 낼 수 있는 알고리즘으로 구현이 되어 있습니다. 그렇기 때문에 아무리 많은 코어를 가진 컴퓨터에서 동일한 테스트를 한다고 하여도 결코 Manual Parallelism 은 Parallel Extension 의 병렬 처리 성능을 기대할 수 없습니다.
     
    이제 살며시 그 내부 구조도 궁금해 집니다. (다음에 계속…)

    Visual Studio 2010 의 특징

    Visual Studio 2010 2009. 2. 8. 23:55 Posted by POWERUMC

     

    통합 개발 도구인 Visual Studio IDE 는 보다 사용하기 쉽고, 다양한 플랫폼을 쉽게 개발할 수 있으며, 더 많은 고급 기능이 포함되어 있습니다. 처음 Visual Studio IDE 를 접하는 개발자에게도 쉽게 사용할 수 있는 접근성과 비주얼이 보다 강화되었고, 이제는 IT 조직에서 개발자 뿐만이 아닌, 관리자, 아키텍쳐, 데이터베이스 개발자 들이 모두 사용할 수 있는 편한 툴이 되었습니다.

     

    New IDE Improvements

    • Visual Studio 환경
      • WPF 로 개발된 에디터
      • 멀티 모니터 지원
    • 네비게이터
      • 빠른 검색
      • 하이라이트 레퍼런스(Highlight Reference) 기능
    • 프로젝트 시스템
      • 다양한 버전의 소스 코드 사용성
      • 멀티 타게팅(Multi Targeting)

    새로운 Visual Studio IDE 와 다수의 패키지(Package) 가 WPF 로 개발이 되었습니다. 현재 CTP 버전에서도 레지스트리를 설정하여 WPF Based Shell 로 동작시킬 수 있습니다. HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\10.0\General\EnableWPFShell 의 DWord 값을 1로 설정하면 Visual Studio 를 WPF Based Shell 로 시작하도록 설정할 수 있습니다. 하지만, 그 동작이 아직은 불안정하며 WPF Based Shell 의 사용을 권장하지 않습니다.

    코드를 개발하기 위해 자주 사용하는 에디터도 WPF 로 개발이 되었고, 코드에 하이라이트 레퍼런스(Hightlight Reference) 와 같은 비주얼 요소를 다수 적용하였습니다. 단순히 코드의 컬러로 코드의 시각적인 효과를 주는 이상의 다이나믹한 시각 효과가 다수 추가가 되었습니다. 그리고, Visual Studio 의 시작 페이지도 WPF 기반으로 변경이 되었으며, 아래의 필자의 Umc Blog 에서 참고하세요.

    참고
    VSTS 2010 – 새로워진 UI

    VSTS 2010 – Visualize Code RelationShip ( 코드 관계 시각화 )

    또한 멀티 모니터를 지원하여 더 넓고 크게 IDE 를 활용할 수 있습니다. Visual Studio 2010 CTP 버전에서는 Virtual PC 이미지로 제공되기 때문에 멀티 모니터 지원을 확인할 수 없었지만, CTP 이후 버전에서는 멀티 모니터 기능을 확인할 수 있을 것 같습니다.

     

     

    Code Focused Development

    • 먼저 사용하고, 나중에 선언 (Consume First, Declare Later)
    • 코드 통찰력(Code insight)
      • Call Hierarchy 기능
      • Inline call tree 기능
    • 레이어
      • 코드 서식
      • 문맥의 정보 제공
    • Document Map Margin 기능

    개발자가 코드를 개발하기 위해 좀 더 높은 레벨의 작업이 가능하고, 코드를 이해하기 쉽도록 다양한 기능을 제공합니다. 그 중, 먼저 사용하고, 나중에 선언 (Consume First, Declare Later) 기능은 특정 기능을 구현하기 위해 흐름을 깨지 않고, 지속적으로 기능을 구현할 수 있도록 도와줍니다. 아직까지는 작성중인 프로젝트 외부에 코드의 선언을 추가할 수 없기 때문에 TDD(Test-Driven-Development) 로 사용하기에 부족함이 있지만, 앞으로 더욱 개선되어질 것으로 보입니다.

    참고
    VSTS 2010 – 똑똑해진 에디터

    그리고 메서드 및 클래스의 호출을 관계를 쉽게 이해할 수 있도록 Call Hierarchy 를 제공하여, 이러한 관계를 트리 형태로 보여줍니다. 복잡한 구조의 스텍 정보를 순차적으로 접근할 수 있고, 복잡한 인터페이스 프로그래밍 시에 호출 연관 관계를 구조적으로 표현해 주어 선언과 구현부를 쉽게 검색할 수 있습니다. 또한, 코드 구조 전체를 비주얼하게 파악할 수 있는 Document Map Margin 기능도 유용합니다.

     

    Web Development

    • Javascript tooling 강화
    • HTML 스니펫
    • 새로운 MVC 와 Dynamic Data Tooling
    • 웹 개발의 통합

    이제 더 이상 Visual Studio 에서의 웹 개발 플랫폼은 ASP.NET 이 아닙니다. ASP.NET 뿐만 아니라 다양한 웹 개발 플랫폼을 통합하게 되었습니다. PHP/RoR 그리고 웹 환경에서의 엔터프라이즈 RIA 를 개발하기 표준적인 개발 환경을 제공해 줍니다.

    그리고 ASP.NET MVC 를 개발하기 위해 많은 자동화 기능을 제공합니다. MVC 의 어플케이션 초기 구조를 만들기 위한 마법사가 제공되며, Controller, Action, View 등을 코드 에디터에서 쉽게 추가 하고, MVC 프로젝트의 테스트 프로젝트도 자동으로 생성해 줍니다.

    이제는 HTML 도 코드 스니펫(Code Snippet)을 제공합니다. CSS 리팩토링을 지원하게 되며, 외부 스타일시트(CSS) 를 내 프로젝트에 쉽게 추가할 수 있습니다.

     

    Office Development

    • 차기 오피스 버전을 위한 Tooling
    • 오피스 배포의 ClickOnce

    차기 오피스 버전을 개발하기 위해 Tooling 을 제공합니다. 그리고 이러한 추가 기능을 배포하기 위해 ClickOnce 의 기능도 개선이 됩니다. 다양한 추가 기능(Addin) 솔루션을 생성하고, 유지, 배포하기 쉬워집니다.

     

    Sharepoint Development

    • Sharepoint Tooling 과 공통 사용자 정의
      • 개발 –> 디버그 –> 배포 지원

    앞으로 Sharepoint 의 개발이 용이하도록 Tooling 을 제공합니다. Sharepoint 기능을 개발하기 하고 배포하기 위해 복잡한 과정을 거쳐야 했습니다. Visual Studio 는 이러한 기능을 개발하기 용이하고 쉽게 디버깅하고 배포할 수 있도록 지원합니다.

     

    Debugger

    • 다양한 플랫폼 지원
      • 64 Bit Mixed-Mode 디버깅
      • Managed 와 Mixed-Mode 의 Minidump 디버깅
    • 브레이크 포인트 개선
      • 그룹핑(Grouping)과 레이블(Labeling) 지원
      • 내보내기/가져오기 지원
    • Historical Debugger
      • 디버그 내용을 기록, 재생

    Visual Studio 2010 에서 64 비트 플랫폼을 개발할 수 있게 됨으로써, 64 Bit 어플케이션의 디버깅을 지원합니다. 디버깅을 위해 브레이크 포인터를 관리할 수 있는 기능이 강화됩니다. 브레이크 포인트에 레이블을 표시할 수 있으며, 그룹핑을 통해 관련 있는 브레이크 포인트를 쉽게 관리할 수 있고, 관리되는 브레이크 포인트를 내보내고 가져올 수 있습니다.

    그리고, 막강한 Historical Debugger 기능이 추가되어, 디버깅 이력을 쉽게 조사할 수 있습니다. 이러한 디버깅 이력을 기록하고 재생하여 반복적인 작업을 최소화 할 수 있고, 시나리오 별로 브레이크 포인트를 관리하는 등 다양한 용도로 이용할 수 있습니다.

     

    Team System: Business Alignment

    • 프로젝트 관리
      • 프로젝트 서버
      • 클라이언트 통합
      • 경량의 프로젝트 계획 도구
    • 요구 사항 추적
    • 레포트
    • 개발 대시보드
    • 프로세스 사용자 지정
      • 다양한 예제 제공

    프로젝트를 관리하기 위해 프로젝트 서버(Project Server) + 클라이언트 통합 + 경량의 프로젝트 계획 도구를 통해 다양한 팀 프로젝트를 관리할 수 있습니다. 그리고 다른 사람들의 중요한 정보를 검색하기 위해 대시보드도 추가됩니다.

    더불어 마이크로소프트와 커뮤니티를 통해 다양한 예제가 포함됩니다. 자신의 팀 조직에 맞는 커스텀 프로세스를 적용하기만 하면 됩니다.