네바로이렇게표시가되죠.^^ 그렇다면.. 바로위에있는 Enable loading of per user extensions를틀릭하면도구상자의옵션대화상자를열고그안에있는 Extension Manager 메뉴를호출합니다. 여기서 "Automatically check.." 하면자동으로자기가템플릿관련확장을체크하여업데이트를합니다.
이부분은 IE 에서많이보셨거나 Windows Desktop Search 를사용해보신분은아이거~ 하실겁니다.
바로 VS 프로젝트템플릿을찾아주는역활을합니다. 제가여기서 C 라고입력하면 C에관련된템플릿이표시됩니다.
cs를하면 C#관련내용일것입니다. 이것이중요한것은중간에파일을추가할때 class 파일을추가할때어떨가요? 해당프로젝트에서클래스하나추가할때에도도움이됩니다.(사실중간에강의하거나갑자기 class 파일하나만들때가끔어디있는지못찾을때가ㅠ.ㅠ)
네바로생각외로도움이될것입니다.(사실전정말도움이됩니다ㅋㅋㅋ)
오늘은 VS 에서새롭게프로젝트를생성하거나중간에프로젝트를추가또는 class 이나 cs 또는 aspx파일을같은것을추가하는대화상자를봤습니다. 사실여기서집고넘아가는것은개발자에게파일을찾기, 또는추가할때위치가어디있는지갑자기당황스럽거나또는기존에만들었던템플릿을다시만들고자할때쉽고빠르게만들수있도록도와준다는것입니다.
여기서는이동영상에서나온것을일단정리하면서 C# 개발자분들에게도움이될만한 IDE 환경에대하여한번써보겠습니다.
이화면을아시는지요??(헉.. 뭐냥. 이건.. 다아는건뎅. ㅜ.ㅜ) 이화면은모두아시겠지만여러분들이개발하는언어를선택하면그언어에맞는환경구성을한다는것입니다. 여기서환경이라고하면.. 당근개발환경이겠지요. 전 General Development Settings 으로합니다. 일반적인개발환경으로는개발속도가조금다를것입니다. 일단 C#이므로 C#으로선택합니다. 물론중간에설정변경을할수있습니다. 중간변경은 Tool 에서 Import and Export Settings 에서변경할수있습니다.
중간변경화면입니다.
처음설정을 C# 개발자하여환경설정을함해보죠^^(중간에변경가능아시죠?)
이렇게할경우 C# 개발환경으로변경이되는데변경되는것은키보드의단축키와 IDE 환경이변화게됩니다.
IDE 환경에서각개발언어또는관리자에맞게 IDE 환경을변경하여최적의개별환경을꾸미는것입니다. 그럼 C#이최적은무엇일가? 단축키?(전잘쓰지않습니다ㅠ.ㅠ) VS 시작할때시자화면? 네모두개발의생산성이나편리성에맞추어개발자가바로개발을할수있다는것입니다.
이렇게 C#으로선택하면초기에는왼쪽은툴박스, 오른쪽에는솔루션탐색기와, 팀탁색기, 속성만일단표시됩니다. 그다음여러분들이추가/변경하실수있습니다. 그다음은바로단축키입니다. 단축키부분이변경이되는데소스코드한줄할줄생성할때여러분들이이단축키를이용하면오타를많이줄일수있습니다.(내전사실오타땜시오타쟁이라고소문이좀ㅠ.ㅠ)
이제 위의 화면은 바로두번째메뉴입니다. 바로해당하는폴더를바로열어볼수있습니다.(사실전 TFS와연결시실제폴더를찾기위해소스제어에서폴더위치를가끔확인하곤합니다 ^.^ 역시바부팅ㅠ.ㅠ) 그리고하나씩삭제도가능하죠. ^^ 그다음이바로밑에있는두개의체크박스입니다.
이부분은시작페이지의표시여부와프로젝트로드시에작업을체크하는것입니다. 이것은그냥 Pass VS 2008에도있었던것이므로, 그렇지만. 여기서는시작페이지에표시되었다는것이조금다르지요옛날에는메뉴에서환경설정에서변경했는데편하게변경되었습니다. 그것이조금눈에들어오고, PDC의 PPT에서는첫번째체크항목에대하여나왔는데바로프로젝트를로드하고페이지를닫을것인지에대한체크입니다.
그다음이뉴스부분입니다. 이부분은조금쉽게변경되었다고볼수있습니다. Microsoft 에서그동안너무일방적인(?) 부분으로개발관련자료는웹이나로컬에 MSDN을설치해서봐야하고특정목차가초급자가쉽게접근할수없었습니다. 그런데오~ 처음에는 Welcome 으로초급자에게쉽게 VS 의사용법을접근할수있도록표시두었다는것입니다. 전에는? 네최신정보도좋았지만초급자가원하는정보는찾기가힘들었다는것입니다. 그렇다면고급자는뉴스메뉴에 Guidance and Resources 를선택하면조금고급으로넘어갑니다.
정리하면,초급자에게접근하기좋은화면 Get Started
중급자이상이보기에좋은화면 Guidance and Resources
이렇게정리할수있습니다.
물론 RSS feed를수저할수있거나 URL를변경, 최신정보로가져올수있습니다. 변경은 Latest News 에서수정또는갱신이가능합니다.
먼저 이전 포스트의 "MEF 는 Generic Type 을 지원하지 않는다!" 에서 언급했고, .NET CLR 2.0 부터 Generic Type 을 지원함에도 불구하고, .NET Framework 4.0 에 포함되는 MEF 가 Generic Type 을 지원하지 않는다는 것은 솔직히 납득하기가 어렵습니다. MEF 개발 PM 이 말하는 강력한 계약 기반(Strongly Contract Based) 의 모델이라는 점은 머리로는 이해는 되지만, 사실 안될 것도 없습니다. -_-;
MEF 가 갖는 대표적인 키워드인 Composable 은 현재 Generic Type 을 지원하지 않지만, 상당히 매력이 있습니다. 이미 현대적인 프레임워크는 Modular 에 집중하고 있고, MEF 는 더 나아가 Modular + Composite 이라는 상당한 매력을 가진 프레임워크입니다.
일단 서두는 이쯤에서 접어두고, MEF 가 Generic Type 을 지원하기 위한 몇 가지 공개되어 있는 방법을 알아보고, 다시 이야기를 나누어 봅시다.
How to support Generic Type of MEF ?
첫 번째 방법 - Factory Provider
가장 간단한 방법이 바로 Factory Pattern 을 이용한 방식입니다. 객체의 생성은 Factory 를 통해 생성하도록 하고, Factory 는 객체의 Type 을 받음으로써 객체의 생성을 Factory 에게 모두 의존하는 방법입니다. 우선 아래의 링크를 참고하세요.
ExportProvider 를 재정의하여 객체의 Type 을 등록하여 원하는 Type 의 객체를 생성하도록 합니다.
1: publicinterface IService { }
2: publicinterface IUserService : IService { }
3:
4: [Export]
5: publicclass UserController {
6: [ImportingConstructor]
7: public UserController(IUserService userService) { }
8: }
9:
10: // in your application
11: privatevoid Compose() {
12: var catalog = new AttributedAssemblyPartCatalog(Assembly.GetExecutingAssembly());
13: var factoryProvider = new FactoryExportProvider<IService>(GetService);
14: var container = new CompositionContainer(catalog, factoryProvider);
15: container.AddPart(this);
16: container.Compose();
17: }
18:
19: public IService GetService(Type type) { return ... }
하지만, 이 방법은 상당히 문제가 많은 방법입니다. 가장 즐겨쓰고, 흔히 볼 수 있는 Pattern 이기 때문에 추가되는 Factory 마다 객체 등을 Factory Provider 에 등록을 해 주어야 합니다. 그 뿐만이 아니죠. Factory Pattern 의 특성상 객체를 생성하는 Factory 는 일일이 각 객체의 타입을 체크하여 반환해 주어야 합니다.
그리고 위의 코드에서는 Type 인자가 1개이지만, 그 이상이라면??? 가령, Generic Type Class<T1,T2,T3,T4,T5> 가 된다면 대략 난감하겠죠. 일단 작은 코드에서는 쓸만할 수 있지만, 꾸준히 성장하는 코드라면 이러한 Factory 방식은 코드의 변경이 너무 잦아집니다.
두 번째 방법 - Type Mapping
MEF 는 Codeplex 에 공개가 되어있고, MEF Contrib 으로 불리우는 MEF 의 확장 라이브러리 입니다. MEF Contrib 의 가장 큰 특징 중에 하나인 ComposablePartCatalog 를 재정의 하는 Generic Catalog 를 지원해 줍니다. 이 링크에서 Type Mapping 을 통한 문서를 볼 수 있습니다.
Contract Type 와 Mapping Type 을 매핑하여 Locator 로 등록하여 주고, 각각 Mapping Class 를 통해 실제 계약의 Generic Type 매핑이 이루어 집니다.
다시 말해서, Generic Class 별로 Locator Class, Mapping Class, 그리고 Mapping Context Class 를 만들어주어야 합니다. 배보다 배꼽이 더 커지는 격입니다. 일단, 아이디어는 좋지만 안쓰고 말랍니다.
세 번째 방법 - MEF + Unity 조합
아마도 가장 이상적인 방법이긴 합니다. Unity Application Block 은 Unity Container Extension 을 지원하기 때문에 객체의 Register, Resolve 등의 이벤트를 가로채서 Unity 의 기능을 확장할 수 있습니다. 이 이벤트를 MEF 에서 받도록 하여 MEF 의 ExportProvider 의 GetExportsCore 를 통해 Unity 의 객체에서 Resolve 하도록 하는 방법입니다.
UnityContainerExtension 을 재정의하여, 아래와 같이 이벤트를 받고, 이것을 MEF ExportProvider 로 전달하는 방법입니다.
UnityContainerExntension 에서는 아래와 같이...
protectedoverridevoid Initialize()
{ this.Context.Registering += new EventHandler<RegisterEventArgs>(Context_Registering); this.Context.RegisteringInstance += new EventHandler<RegisterInstanceEventArgs>(Context_RegisteringInstance);
}
MEF 의 ExportProvider 에서는 아래와 같이…
protectedoverride IEnumerable<Export> GetExportsCore(ImportDefinition definition, AtomicComposition atomicComposition)
{ if (definition.ContractName != null)
{
Type contractType; if(Mapping.TryGetValue(definition.ContractName, out contractType))
{ if (definition.Cardinality == ImportCardinality.ExactlyOne || definition.Cardinality == ImportCardinality.ExactlyOne)
{ var export = new Export(definition.ContractName, () => serviceLocator.GetInstance(contractType)); returnnew List<Export> { export };
}
}
} return Enumerable.Empty<Export>();
}
일단 가장 완벽해 보입니다만, 이 속에는 그 이상 많은 문제들이 생기게 됩니다. MEF 도 내부적으로 Injection(주입) 기법을 사용하고, Unity 에서도 Injection 을 사용하는데 바로 이 Injection 방법이 달라지게 되는 것입니다. 즉, MEF 기반의 코드와 Unity 기반의 코드의 Injection 선언 방법이 틀려지고, 서로 호환할 수 없다는 것입니다.
결국 DI 프레임워크는 특정 DI Container 에 의존할 수 밖에 없어지고, 더불어 Compisite 과 Injection 은 두 가지의 사용 방법이 혼재될 수 밖에 없다는 것이죠.
Conclusion
MEF 에서 Generic Type 을 사용하고 싶어서 안달이 난 1人은 여러 가지 방법을 찾아보았지만, 사용성, 재사용성, 확장성, 유연성 등 모든 면에서 원하는 해답을 찾지 못했습니다. 그리고 현재까지 MEF 에서 Generic Type 을 지원하기 위한 대략적인 3가지 방법을 정리해보도록 하죠.
장점
단점
MEF Factory Export Provider
구현이 쉽다
Factory 의 관리가 힘들다
Factory 의 확장이 힘들다
모든 Factory 를 Catalog 로 관리해야 한다.
MEF Contrib Type Mapping
합리적이다
Type Mapping 코드가 복잡하다
Mapping/Locator/Context 클래스를 구현해야 한다
상속 기반이다
MEF + Unity Integrated
합리적이고 , 구현이 쉽다
Injection 기법이 서로 달라진다
Injection 코드가 서로 달라진다
Injection 이 호환되지 않는다
각각의 객체간의 Composite 이 불가능하다
이제 슬슬 머리가 아파옵니다. 향후 .NET Framework 4.0 에서 가장 큰 빛을 보게 될 MEF 이지만, Generic Type 을 지원하지 않는다는 것은 가장 큰 오점이 아닐까 생각합니다. 우선 이쯤에서 마무리하고 어떻게 해야 할지 생각해 보도록 하지요.
.NET Framework 4.0 에 포함이 될 Managed Extensibility Framework(이하 MEF) 는 Generic Type 을 지원하지 않습니다. ( MEF is not supporting Generic Type!!!! )
상당히 충격입니다. MEF 는 현재 Generic Type 을 지원하지 않습니다. 이것을 가지고 현재 중요한 프로젝트를 진행하기 위해 여러 가지 리뷰를 해 보고 있습니다만, MEF 가 Generic Type 을 지원하지 않는 것은 쉽게 말해 'MEF 는 아직…' 이라는 결론이 나는군요.
Managed Extensibility Framework Basic
이것을 이해하기 위해서는 MEF 의 기본부터 이해해야 할 필요가 있습니다. 자세한 내용은 아래의 필자의 블로그 링크를 클릭하시면 Managed Extensibility Framework 에 대한 아티클을 볼 수 있습니다.
우선 이러한 원인은 MEF 가 Contract Model(계약 모델) 기반이라는 있다는 이유 입니다. 우리가 흔히 사용하는 계약 모델은 쉽게 이야기하면 제공자와 소비자로 구분할 수 있습니다. 제공자와 소비자의 거래가 성립이 되기 위해서는 바로 계약이라는 것이 필요하죠. MEF 로 비유하자만 Import/Export 가 바로 그것이며 그 계약을 성립시켜 주는 것이 MEF Container 와 Composition Batch 로 볼 수 있습니다.
바로 이러한 계약 기반과 Composable Part 라는 개념으로 기존의 컴포넌트의 재사용성을 높일 수 있게 되며, 좀 더 동적이며, 추상화가 가능한 프레임워크 입니다. 더 쉽게 얘기하면, 새로운 C 라는 컴포넌트는 A 와 B 라는 컴포넌트와 계약하여 결합시키거나, 기존 컴포넌트를 변형시키는 등 Composable Application 을 만들기 위해 계약의 명세만 알면 다양한 컴포넌트를 재생산, 변형, 다양성, 재활용 등을 할 수 있습니다.
MEF 는 내부적으로 이러한 명확한 계약을 위해 여러 가지 방법으로 계약을 정의할 수 있습니다. 기본적으로 ExportAttribute 을 사용하여 String, CLR Type, ExportMetadata 를 사용하게 되어 있지요. 하지만 MEF 는 모든 계약의 명세는 바로 String 을 사용하는 데에서 문제가 발생하게 됩니다. 그리고 이것이 Dependency Injection(DI) 와 Inversion Of Control(IoC) 와 다른 점입니다. 대부분의 DI 프레임워크는 Object 의 Lifecycle 을 관리하고 객체의 의존성을 낮추기 위해 역제어 하는 것에 초점이 맞추어져 있기 때문에 CLR Type 기반으로 Container 에 등록이 됩니다.
예를 들어 보면, 아래와 같은 것이 MEF 에서는 계약 명세 규격에 어긋난다는 의미입니다. (특정 DI 프레임워크에 종속되지 않는 코드입니다)
var container = new Container(); container.Register<IUMC<>>();
var obj = container.Resolve<IUMC<string>>();
obj.SayHello();
Why MEF is not supporting Generic Type?
MEF 가 Generic Type 을 지원하지 않는 것에 이미 많은 사람들이 문제를 발견했고, 몇 가지 해결 방법이 있긴 있습니다.
이미 Ayende Rahien 이라는 사람의 블로그에는 MEF 가 Generic Type 을 지원하지 않는 것에 대한 이야기를 합니다. 내용을 보면 처음부터 Microsoft 의 MEF 개발 팀은 Generic Type 을 배제하고 있었던 것 같습니다. 하지만 Ayende Rahien 씨는 이 문제에 대해 반드시 해결해야 한다는 이야기를 MEF 개발 팀과 나누었습니다. 저도 이 문제가 반드시 해결 되리라 생각합니다만… 현재로써는 글쎄 ^^;
여기에서 MEF 개발 팀은 조금 구차한 변명을 합니다. 위에서 얘기한 MEF 의 기본은 계약 기반의 프레임워크라는 것입니다. 이 문제에 대해 추측을 해보면, MEF 가 Generic Type 을 지원한다는 것은 Strongly Contract Based 가 될 수 없기 때문이고, Generic Type 으로 인해 명확한 계약이 이루어질 수 없다는 것입니다. 특히 MEF 는 계약의 명세가 모두 MEF 가 내부적으로 관리하고 있기 때문에, Generic Type 에 의한 객체 의 계약 관리는 엄청난 메모리 사용량을 증가로 이어질 가능성이 충분합니다.
실제로 Microsoft 에서 MEF 개발 팀의 PM 을 맡고 있는 Glenn Block 씨는 이 아티클에서는 MEF v1 에서는 Generic Type 을 지원하지 못할 것이라고 합니다. 만약에 Generic Type 을 지원하게 된다면 차기 버전이 될 듯 합니다.
하지만, 다시 한번 MEF 는 계약 기반의 모델이라는 것을 생각하지 않을 수 없습니다. 만약 계약이 명확하지 않다면 계약 자체가 불명확하다는 의미입니다. C# 2.0 부터 지원하는 Generic Type 의 명확하지 않는 타입이 계약에 존재한다면 이것은 계약 자체가 성립되기 힘들다는 전제 조건을 포함하게 됩니다.
MEF 의 예를 들어 봅시다. 아래와 같은 Generic Type 의 계약이 존재합니다. (현재의 MEF 로는 전혀 불가능한 코드입니다^^;)
public interface IUMC<T>
{
void SayHello<T>();
}
[Export(typeof(IUMC<>))]
public class UMC<T> : IUMC<T>
{
public void SayHello()
{
// TODO Impl...
}
}
CLR(Common Language Runtime) 의 Generic Type 의 특성상 Generic T Parameter 는 굉장히 다형적입니다. UMC<string> 또는 UMC<int> 또는 모든 Class Type 이 T Parameter 에 대입될 수 있습니다. 단순히 어떤 타입도 올 수 있다는 것을 떠나 물건을 팔 사람은 도대체 소비자가 누구와 계약한 것인지 알 수 없고, 실제 상거래와 같은 상황이라면 사기와도 같다는 것이죠. 굳이 예를 들자면, 주민등록번호가 다름에도 불구하고, 주민등록증의 이름이 같은 동명인에게 언제든지 계약을 할 수 있다는 것이죠.
DI(Dependency Injection / IoC) 는 CLR Type 을 기반으로 합니다. 일부 DI 프레임워크는 Tag 와 같은 Contract Data 를 제공하기는 하지만 이것은 Metadata 그 이상의 역활을 하지 않습니다. 즉 Contract(계약) 와는 전혀 무관하다는 이야기 입니다. 객체를 질의(Query) 하기 위함이지 Composable 을 위한 것은 아닙니다.
OK! I'm understand. But…!!
처음부터 MEF 는 계약 기반의 Composable/Plugin Model/Contract Based 라는 용어를 자주 만나게 됩니다. 그리고 계약 자체라는 의미에서 Generic Type 은 가장 큰 장애 요소임이 확실합니다. 그렇기 때문에 현존하는 모든 DI(Dependency Injection) 프레임워크는 계약(Contract) 라는 용어를 절대 사용하지 않습니다. 목적 자체가 계약과는 전혀 무관하기 때문입니다.
하지만, MEF 의 계약 모델은 내부적으로 String Based Contract 를 사용하고 있고, Generic Type 또한 String 으로 표현이 가능하기 때문에, 문자열의 Parsing 만으로 어느 정도의 Generic Type 을 지원할 수 있을 거라고 생각했습니다.
필자는 처음 MEF 를 본 순간 "이것을 물건이다!" 라는 걸 느꼈습니다만, 아마도 MEF 개발 팀은 두 가지의 고민을 했을 거라고 생각합니다. Silverlight 를 지원할지, Generic Type 을 지원할지에 대한 범용성에 대해서 말입니다. 하지만, Generic 에 대해 많은 피드백을 받음에도 불구하고 MEF v1 에 지원하지 않을 듯한 대답은 사실 "구차한 변명" 으로 밖에 들리지 않는답니다. 결국, 현재 MEF 는 Silverlight 를 지원하는 등 .NET Framework 의 범용성에 치중하였고, 결국 Generic Type 은 현재 시점에서 릴리즈 시점까지 구현이 불가능할 거라고 예상합니다.
아쉽긴 하지만, 현재 MEF 가 불가능한 Generic Type 에 대한 영역은 몇 가지 Open Source 에서 제공을 하고 있습니다. 단지 실제 사용성에 대한 의구심과 필자의 견해로는 안쓰는게 나을 것 같다는 판단입니다.
다음에 당장 지원하지 않는 Generic Type 을 어떻게 사용할지 알아보고 함께 돌파구를 찾아보도록 하겠습니다.
이미 알고 계시겠지만 Visual Stuido 2010 Beta2에
새로운 C++0x 기능이 추가 되었습니다.
추가된 것은nullptr이라는 키워드 입니다.
nullptr은 C++0x에서
추가된 키워드로 널 포인터(Null Pointer)를 나타냅니다.
null_ptr이
필요한 이유
C++03까지는 널 포인터를 나타내기 위해서는 NULL 매크로나 상수 0을 사용하였습니다.
그러나 NULL 매크로나 상수 0을
사용하여 함수에 인자로 넘기는 경우 int 타입으로 추론되어 버리는 문제가 발생 합니다.
< List 1 >
#include <iostream>
using namespace std;
void func( int a )
{
cout << "func
- int " << endl;
}
void func( double *p )
{
cout << "func
- double * " << endl;
}
int main()
{
func( static_cast<double*>(0)
);
func( 0 );
func( NULL
);
getchar();
return 0;
}
< 결과 >
첫
번째 func 호출에서는 double* 로 캐스팅을 해서
의도하는 func이 호출 되었습니다. 그러나 두 번째와 세
번째 func 호출의 경우 func( doube* p ) 함수에
널 포인터로 파라미터로 넘기려고 했는데 의도하지 않게 컴파일러는 int로 추론하여 func( int a )가 호출 되었습니다.
바로 이와 같은 문제를 해결하기 위해서 nullptr 이라는 키워드가
생겼습니다.
nullptr 구현안
C++0x에서 nullptr의
드래프트 문서를 보면 nullptr은 아래와 같은 형태로 구현 되어 있습니다.
const class {
public:
template <class T>
operator T*() const
{
return 0;
}
template <class C, class T>
operator T C::*() const
{
return 0;
}
private:
void operator&() const;
} nullptr = {};
nullptr 사용 방법
사용방법은 너무 너무 간단합니다. ^^
그냥 예전에 널 포인터로 0 이나 NULL을 사용하던 것을 그대로 대처하면 됩니다.
char* p = nullptr;
<List1>에서 널 포인트를 파라미터로 넘겨서 func( double* p )가 호출하게 하기 위해서는
func( nullptr );
로 호출하면 됩니다.
nullptr의 올바른 사용과 틀린 사용 예
올바른 사용
char* ch = nullptr; // ch에 널 포인터 대입.
sizeof( nullptr ); // 사용 할 수 있습니다. 참고로
크기는 4 입니다.
typeid( nullptr ); // 사용할 수 있습니다.
throw
nullptr; // 사용할 수 있습니다.
틀린 사용
int n = nullptr; // int에는 숫자만 대입가능한데
nullptr은 클래스이므로 안됩니다.
Int n2 = 0
if( n2 == nullptr ); // 에러
if( nullptr ); // 에러
if( nullptr == 0 ); // 에러
nullptr = 0; // 에러
nullptr + 2; // 에러
nullptr 너무 간단하죠? ^^
VC++ 10에서는 예전처럼 널 포인터를 나타내기 위해서 0 이나 NULL 매크로를 사용하지 말고 꼭nullptr을 사용하여 함수나 템플릿에서 널
포인터 추론이 올바르게 되어 C++을 더 효율적으로 사용하기 바랍니다.^^
짜투리 이야기...... ^^
왜 nullptr 이라고
이름을 지었을까?
nullptr을 만들 때 기존의 라이브러리들과 이름 충돌을 최대한
피하기 위해서 구글로 검색을 해보니 nullptr로 검색 결과가 나오는 것이 별로 없어서 nullptr로 했다고 합니다.
제안자 중 한 명인 Herb Sutter은 현재 Microsoft에서 근무하고 있는데 그래서인지 C++/CLI에서는
이미 nullptr 키워드를 지원하고 있습니다.
C++0x 이야기
근래에 Boost 라이브러리의
thread 라이브러리가 C++0x에 채택 되었다고 합니다.
Boost에 있는 많은 라이브러리가 C++0x에 채택되고 있으므로 컴파일러에서 아직 지원하지
않는 C++0x의 기능을 먼저 사용해 보고 싶다면 꼭 Boost 라이브러리를
사용해 보기 바랍니다.
아주 오래 전 컴퓨터에는 GPU 라는 개념이 특별히 존재하지 않았습니다.
그저 화면에 얼마나 많은 픽셀을 나타낼 수 있는가 정도가 그래픽 카드의 성능을 나타내는 기준이였습니다.
그랬던 상황이 오늘 날에 이르게 된 것입니다.( 굳이 자세히 언급할 필요가 없을 것 같습니다.^^ )
오늘날의 GPU 의 성능은 가히 놀라울 정도입니다.
하지만 이런 놀라운 성능을 가진 GPU의 processing unit 들이 대부분의 시간을 놀면서 있다는 것이
우리의 신경에 거슬렸던 것입니다.
그래서 이들에게 일감을 분배시키기 위한 방안을 생각하게 되었고,
이를 배경으로 등장한 것이 바로 GPGPU 입니다.
GPU 를 활용한 일반적인 처리 방식을
GPGPU( General-purpose computing on graphics processing uints ) 라고 합니다.
범용성 있게 GPU 를 활용해서 처리하겠다는 것이지만,
사실 CPU 와 GPU 의 목적은 엄연히 다릅니다.
CPU 는 광범위한 영역에서도 효율적으로 이용될 수 있도록 설계를 된 것이지만,
GPU 는 그래픽 처리를 위한 산술 연산에 특화된 processing unit 입니다.
오늘 날 PC 는 멀티코어 형식이 많아지고 있는 추세인데,
하나의 CPU 는 기본적으로 특정 시간에 하나의 연산만 수행할 수 있습니다.
GPU 의 경우에는 병렬처리 형식에 완전히 특화된 형태입니다.
오늘날 GPU의 코어는 32개라고 합니다.
즉 32개가 연산이 동시에 실행될 수 있다는 얘기입니다.
아래 그림을 한번 보실까요?
GPU 에는 SIMD 라는 것이 굉장히 많은 것을 볼 수 있습니다.
SIMD( Single Instruction Multiple Data ) 라는 것은 병렬 프로세서의 한 종류입니다.
벡터 기반의 프로세서에서 주로 사용되는데,
하나의 명령어를 통해서 여러 개의 값을 동시에 계산할 수 있도록 해줍니다.
( http://ko.wikipedia.org/wiki/SIMD --> 여기서 참고 했습니다^^ )
벡터 기반이라는 사실에 우리는 주목할 필요가 있습니다.
GPU 는 광범위한 목적으로 설계된 processing unit 이 아닙니다.
즉, GPGPU 를 활용하는 목적은 주로 수치 연산에만 국한된 이야기 입니다.
일반적인 로직으로 GPGPU 를 활용하는 것은 그리 좋은 선택이 아니라는 것입니다.
현재 GPGPU 가 활용되고 있는 영역은 이미지 프로세싱, 비디오 프로세싱, 시뮬레이션 등과 같이
많은 수학 연산이 필요한 영역입니다.
분명한 것은 이들 수치 연산에 국한된 모델이라 할지라도, 그 성능이 무척 매력적이라는 것입니다.
이런 GPGPU 활용을 위해서 마이크로소프트는 어떤 준비물을 가지고 등장했을까요?
그것이 바로 'DirectCompute' 라는 것입니다.^^
아래 그림을 한번 보실까요?
DirectCompute 외에도 친숙한 이름이 보이시나요?
개인적으로 현재 GPGPU 분야에서 가장 앞서 있다고 보여지는 CUDA 가 있습니다.
이것들에 대한 우열을 가리기는 어려운 문제입니다.
여러분이 처한 상황에서 최선의 선택을 하면 되는 것입니다.
그 중에 DirectCompute 도 하나의 선택지일 뿐입니다.
CUDA 도 굉장히 훌륭한 GPGPU 모델입니다.
( 사실 저도 CUDA 를 공부하면서 GPGPU 의 개념을 잡았습니다.^^ )
CUDA 는 제가 지금 언급하지 않아도 될 정도로 많은 정보들이 공개되어 있습니다.
DirectCompute 는 마이크로소프트에서 가지고 나온 GPGPU 모델입니다.
앞으로 OS 의 강력한 지원을 가지고 등장하게 될 것입니다.
사실 GPGPU 와 DirectCompute 는 매우 혼란스럽게 사용될 수 용어들입니다.
그래서 오늘은 이들 두 용어를 확실히 구분하는 것으로 마무리 하겠습니다.^^
다음 시간부터는 DirectCompute 에 대해서 조금씩 살펴보겠습니다.
Team Foundation Server 2010 을 설치하는 중 TF255040 오류가 발생하였습니다. 아래의 그림과 같이 SQL Server 의 Reporting Services 와 관련된 컴포넌트가 설치 되지 않았다는 오류입니다. 훔...
SQL Server Analysis Services 인스턴스를 찾지 못한다는 오류 메시지가 나타납니다.
TFS 설치 오류 로그를 자세히 보면 아래와 같이 문제 지점의 예외 메시지를 찾을 수 없습니다.
[Error @12:07:34.650] Microsoft.TeamFoundation.Admin.TfsAdminException: TF255040: Install SQL Server Reporting Services or at a minimum SQL Client Connectivity Tools on the application tier to ensure Analysis Services object model is present for warehouse processing. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.AnalysisServices, Version=10.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91' or one of its dependencies. 지정된 파일을 찾을 수 없습니다.
왜냐하면 SQL Express 버전을설치하면되지만, 결국 SQL Server 인스턴스를만들어야하기때문에왠지 TFS 전용서버의순결함을잃는듯하군요.. 사용하지도않을 SQLEXPRESS 라는반갑지않은인스턴스와말이죠. 두번째 SQL Server 2008 Feature Pack 은 SQL Server 의구성요소일부만설치할수있습니다. 제가필요로하는 Analysis Service 관련어셈블리만설치되도록설치패키지를제공해주고있습니다.
그럼 Microsoft SQL 2008 관련구성요소를설치해주어야하는데, 아래의주소에서기본적인클라이언트가설치되도록합니다. 근데 Management Studio Express 를설치하게되면 SQLEXPRESS 라고하는인스턴스가설치가되는데 Team Foundation Server Application Tier 에 SQLEXPRESS 인스턴스가그다지필요해보이지도않고, 설치시간도오래걸리고요.
Configure Team Foundation Build Service 에서 Start Wizard 를 클릭합니다.
아래는 Build Service 설치 안내 페이지 입니다. 다음을 클릭합니다.
Team Build 를 수행한 Team Project Collection 을 지정해야 합니다. Browser 를 클릭하여 Team Project Collection 을 선택합니다. 만약 Team Foundation Server 와 연결되지 않은 상태일 경우 Team Foundation Server 와 연결해야 합니다.
기본 설정대로 Recommended 를 선택하고 다음을 클릭합니다.
Team Build 를 수행할 계정과 포트를 입력합니다. 필자는 TFSBUILD 계정으로 사용하였고, 환경에 따라 NETWORK SERVICE 등으로 사용하셔도 됩니다.
모든 설정이 완료 되었고, Verify 를 클릭하여 Team Build 환경을 점검합니다.
Team Foundation Server 2010 은 기존의 2008 버전에 비해 굉장히 설치가 간단해 졌습니다.
사실 설치과 구성 패키지 자체는 TFS 2008 이 간단하긴 했지만, 구성이 올바르게 완료되어야만 설치가 가능했었습니다. 이런 문제로 인해서 초기 설정이 유효하지 않을 경우 설치를 완료한들 다시 제거를 하고 재설정을 했던 경우가 많았습니다. 그리고 TFS 2008 에서는 설정 정보가 IIS 의 TFS Web Service 의 web.config 와 데이터베이스의 특정 필드를 직정 수정해야 하는 관리상의 불편함이 많았습니다.
하지만 이번 Team Foundation Server 2010 는 이런 면에서 초기 설치 단계에서 구성하는 단계까지 많이 편리해졌습니다. 설치와 구성을 따로 따로 하도록 말이죠.
아래는 Team Foundation Server 2010 을 설치하고, Team Foundation Server Administration Console 을 이용하여 TFS 환경을 구성하는 방법입니다.
아래의 설치 과정은 3-tier 로 구성된 서버에 TFS 2010 을 설치하는 단계입니다.
서버 1 : Active Directory, DNS 서버
서버 2 : MSSQL 2008
서버 3 : Team Foundation Server 2010
Team Foundation Server Administrator Console 을 실행하여 Configure Installed Features 를 클릭합니다.
다중 Tier 환경으로 설치할 예정이므로, Advanced 를 선택하고 Start Wizard 를 클릭합니다.
Wizard 안내 페이지입니다. 그냥 다음으로 넘어 갑니다.
SQL Server 의 인스턴스를 입력하고 Test 를 클릭합니다. 인스턴스가 유효하면 푸른색 V 표시가 나타나고, 다음으로 넘어 갑니다.
Service Account 계정을 입력하고 Test 를 클릭해보고, 계정이 유효하면 다음으로 넘어갑니다.
Team Foundation Server 2010 의 웹 서비스의 설정을 합니다. 그냥 기본 구성 그대로 다음으로 넘어갑니다.
보고서를 구성하는 페이지의 안내입니다. 필자는 보고서를 구성할 것이므로, Configure Reporting for use with Team Foundation Server 항목 체크 박스를 체크 한 후에 다음으로 넘어갑니다.
Reporting Service 인스턴스를 입력하고 Populate URLs 를 클릭하면 유효한 보고서 서비스를 찾아줍니다. 그리고 다음으로 넘어갑니다.
TFS Report 서비스의 실행 계정을 지정해 줍니다. 필자는 기본 계정인 NETWORK SERVICE 계정을 사용합니다.
아래는 Sharepoint 를 설치를 안내하는 페이지 입니다. 다음으로 넘어갑니다.
Sharepoint 서버의 계정을 입력하고 Test 를 클릭하여 유효성을 검사합니다. 그리고 다음으로 넘어갑니다.
기본적으로 Team Project Collection 이 체크되어 있습니다. 그대로 다음으로 넘어갑니다.
모든 설정이 완료 되었습니다. Verify 를 클릭하여 최종 점검을 진행합니다.
Verify 결과가 양호할 경우 설치를 진행하도록 합니다. Configure 를 클릭하여 설치를 진행합니다.
아래는 Team Foundation Server 2010 이 설치가 완료되었습니다.
이제 설치가 완료되었고, Team Foundation Server 관리를 위하여 관리 권한을 지정합니다.
Application Tier 의 Administer Group Membership 을 클릭합니다.
Team Foundation Administrators 그룹을 더블 클릭(또는 Properties 클릭) 하고, 관리자 계정을 지정해 줍니다.
이제 모든 설치와 구성을 마쳤습니다. 아래의 그림은 Visual Studio 2010 으로 Team Foundation Server 2010 에 연결된 모습입니다.
(네이X 사전에서 찾아보니 계약이란 의미 외에 살인 청부, 줄어들다, 수축하다,, 등의 의미가 있군요,,)
그럼, "계약"의 사전적 의미는 무엇일까요? (약간 글이 엉뚱한 방향으로 흐르는 것 같지만,, ^^;;)
역시, 네이X 국어 사전에서 찾아본 결과,,
"관련되는 사람이나 조직체 사이에서 서로 지켜야 할 의무에 대하여 글이나 말로 정하여 둠" 이라고 합니다.
잘 아시겠지만 계약은 약속이랑 비슷하지만 약속 보다는 좀 더 강력한 의미로 쓰입니다.(법적 효력도 있죠,,)
다시, 본론으로 돌아와서,, 그럼, WCF 에서의 Contract 는 무엇을 말하는 걸까요?
네,, 다들 예상 하셨겠지만, WCF 에서의 Contrat 역시 사전적 의미와 비슷하게 쓰이며, WCF 서비스와 클라어언트 사이에 어떤 계약을 정의할 때 사용하는 것을 말합니다.
좀 더 자세하게 설명을 하자면, 이 Contract 라는 것은 서비스와 클라이언트가 서로 통신할 때 사용하는 메세지의 명세(specification)를 정의하는 것을 말합니다.
WCF 는 총 세가지 타입의 Contract가 있으며, 다음은 이 타입들에 대한 정의입니다.
Service contract : 서비스에 의해 구현되는 기능들에 대해 설명하며, 서비스 계약(service contract)으로 정의 된 .NET 타입의 클래스는 WSDL의 services, port types의 엘리먼트로 매핑됩니다. 서비스 계약과 함께 Operation contract는 서비스 계약 내에서 정의되며, 서비스의 동작(operation)을 설명합니다.
Data contract : 서비스가 통신(communication)을 하는데 사용하는 데이터 구조를 나타냅니다. 이는 CLR 타입을 XSD(XML Schema Definitions) 로 매핑해주는 역할을 수행하는데, WCF 가 통신할 때 사용되어지는 데이터들을 어떻게 직렬화(serialization) 또는 역직렬화(deserialization)를 수행하는지를 설명합니다.
Message contract : 메세지 계약은 CLR 타입을 SOAP 메세지로 매핑해주며, SOAP 메세지의 포맷을 설명합니다. 메세지 계약은 SOAP 헤더에서 바디까지 컨트롤할 수 있게 해줍니다.
예전 포스팅에서 몇 번 언급한 점이기 때문에 다들 아실거라 생각하는데,, WCF 서비스는 많은 시스템과의 상호 운용성(interoperability)을 높이기 위해 WSDL을 사용합니다. 위에서 설명한 세 가지의 Contract 들은 WCF 서비스나 서비스에서 사용하는 여러 데이터들을 WSDL 또는 SOAP의 요소들로 매핑 시키는 역할을 수행합니다. 이 말은 곧, 서비스와 통신하기 위한 메세지의 포맷을 정의한다는 말이기도 하지요.(앞에서 언급했듯이,,)
이제 Contract의 정의에 대해선 조금 이해가 가시지요? ^^
그럼, 이러한 Contract들이 어떻게 쓰이는지 하나씩 살펴보겠습니다. 우선, Service Contract 와 Operation Contract에 대해 알아보구요, 한 두번에 걸쳐서 Data Contract와 Message Contract에 대해서도 알아보도록 하겠습니다.
서비스 계약은 지금까지 몇번 언급했던 것 같습니다. 다시 한번 더 얘기하자면, 서비스 계약은 서비스가 제공하는 여러 기능(동작)들을 정의하는 인터페이스이며, 서비스 자체를 정의한다고 생각하면 될듯 합니다. 그리고, 서비스에서 제공하는 기능들을 외부로 노출(?)하기 위해 사용하는 Operation Contract가 있습니다. 이는 Service Contract 내부에서 정의됩니다.
백문이 불여일견이니, 코드를 한번 보도록 하죠. 음,, 예전에 만들었던 코드를 다시 살펴 보면서 이해하는게 좋을 것 같네요 ^^
우리가 만들었던 첫 WCF 서비스의 코드 중 일부입니다. 서비스는 ServiceContract 특성을 인터페이스에서 선언하고, 그 메소드에 OperationContract 특성을 선언해줌으로써, 서비스 계약을 정의해주었습니다. 기억하시겠지만, 실제 구체적인 서비스의 기능은 Service Contract가 선언된 인터페이스를 상속 받아 구현해야 했었죠.
이것이 바로 WCF 서비스가 제공하는 WSDL입니다. 앞에서 언급했듯이 Service Contract로 정의 되어진 정보는WSDL의 "service", "port type" 엘리먼트로 매핑된다고 하였습니다. 또한 Operation Contract로 정의된 부분은 "operation" 엘리먼트로 매핑된다고 했었죠,, 이것 역시 다음과 같이 확인할 수 있었습니다.
이렇게 WCF를 이용하여 만들어진 서비스는 WSDL로 제공되어지며, 클라이언트에서 서비스를 사용할 수 있게 되는 것입니다.
그리고, ServiceContract 특성 클래스에는 Namespace 속성을 제공합니다. 이 속성은 WSDL과 SOAP 메세지의 Namespace의 값을 명시적으로 설정할 수 있게 합니다.
그리고, 다시 이 서비스의 WSDL을 확인해보면, 서비스의 네임스페이스가 다음과 같이 바뀌어져있는 것을 확인할 수 있습니다.
자~ Service Contract에 대한 설명은 여기까지 입니다. 이번에는 실습보다는 이론적인 설명이 위주였습니다. 그래서 조금 재미가 없을 수도 있을 것 같네요 ㅎ 하지만, 이론도 중요하다는 것,, 아시죠? ^^ 아무 생각없이 닷넷 인터페이스 만들고 ServiceContract 특성을 주는 것 보다 이러한 작업으로 서비스가 어떻게 클라이언트에 노출되는지를 알고 있는 것이 서비스를 구성하고, 클라이언트를 개발하는데 있어서 많은 도움을 줄 것이라 확신합니다.
이 글 역시, 많은 분들에게 조금이라도 도움이 되었으면 하는 바람을 가지면서 이만 줄이겠습니다 ^^ 다음 포스팅때 뵙죠~ ㅎ