'POWERUMC'에 해당되는 글 178건

  1. 2016.02.20 데이터를 표로 표현해주는 Flip-Tables-Net
  2. 2015.02.25 [MonoDevelop] v5.7.2.2 한글 버전 배포 공지
  3. 2014.04.08 [Mac] DeskBoard 앱 할인 이벤트, 프레젠테이션을 위한 앱
  4. 2013.09.11 [Objective-C] 아름다움을 추구하는 오브젝티브-C 언어 1/ 2- 언어적 특성
  5. 2013.08.15 SharePoint 데이터베이스로 부터 모든 문서를 백업 및 추출하기 (2)
  6. 2013.08.05 [MonoDevelop] MonoDevelop 한글 버전 Github 병합 완료 (8)
  7. 2013.07.25 [MonoDevelop] MonoDevelop 통합 개발 도구를 한글화 진행 중입니다. (7)
  8. 2013.07.22 [JavaScript] JS-Lambda 자바스크립트 라이브러리를 공개합니다.
  9. 2013.07.17 [VS2013] VSGesture for Visual Studio 2013 Preview 배포 완료 (1)
  10. 2013.07.08 [퀴즈] 프로그래머를 위한 문제 #3 - 미로 찾기
  11. 2013.07.05 [퀴즈] 프로그래머를 위한 문제 #2 - 스택 프레임(Stack Frame) (1)
  12. 2013.07.02 [퀴즈] 프로그래머를 위한 문제 #1 - 1부터 8만까지 8의 개수 (9)
  13. 2013.07.01 [Javascript] jQuery 1.7.1 버그 패치를 공유합니다.
  14. 2013.06.20 [Google] 구글에서 활동한 내 모든 정보 백업 받자
  15. 2013.06.17 [JavaScript] Javascript Array Extensions 소스코드 오픈 (웹브라우저, Node.js 사용 가능) (2)
  16. 2013.06.03 [Javascript] 자바스크립트(Javascript) 개발 팁과 가이드 (Tips & Guide) (6)
  17. 2013.05.31 [ALM] 13. 불완전한 통합, 팀 파운데이션 서버(Team Foundation Server)
  18. 2013.05.24 Umc Core IoC 통합 컨테이너 #1
  19. 2013.05.23 Umc.Core 프레임워크 다이나믹 프록시(Dynamic Proxy) #1
  20. 2013.05.20 memcached, 분산 캐시를 이용하여 분산 Session 성능 향상 (1/2)
  21. 2013.03.18 [페이스북 알리미] Facebook Tray v0.1
  22. 2013.03.11 [Qt] Qt 5.0의 webkitwidgets 사용 (3)
  23. 2013.02.20 [ALM] 11. 부하테스트 이야기, 테스트 데이터 분석 문제 풀어보세요. (1)
  24. 2013.01.24 [팁] 우분투(Ubuntu) 12.10 설치 중 창이 잘림 현상
  25. 2013.01.17 [Eclipse] STS 설치 실패 오류 유형 및 GEF(Graphical Editing Framework)
  26. 2013.01.17 [Java] Java 8 의 Lambda(람다) 표현식에 대한 고찰 (1)
  27. 2013.01.15 [Eclipse] Eclipse 에서 MinGW GCC 컴파일러로 C++11 사용하기
  28. 2013.01.15 [Eclipse] Eclipse Visual C++을 MinGW GCC 프로젝트로 변환하기
  29. 2012.10.30 윈도우 8, 반토막짜리 WinRT와 WinRT SDK (1)
  30. 2012.09.11 Windows 8 스타일 앱 개발에 대한 고찰

Flip-Table-Net 은 자바 코드로 작성된 flip-table 을.NET 코드로 포팅한 프로젝트로, 콘솔에 데이터를 표로 표현해 줍니다.

설치

Command Line 에서 다음처럼 입력하거나,

nuget install flip-tables-net

Visual Studio Package Manager Console 에서 다음처럼 입력합니다..

Install-Package Flip-Tables-Net

또는 Nuget 패키지 관리자에서 flip-table-net 으로 검색합니다.

기존 자바에서 지원하던 기능

FlipTable은 헤더 정보와 데이터 정보가 필요합니다.

string[] headers = { "Test", "Header" };
string[][] data =
{
    new[] {"Foo", "Bar"},
    new[] {"Kit", "Kat"}
};
Console.WriteLine(FlipTable.Of(headers, data));
+======+========+
| Test | Header |
+======+========+
| Foo  | Bar    |
+------+--------+
| Kit  | Kat    |
+======+========+

데이터에 개행 문자열도 지원합니다.

string[] headers = { "One Two\nThree", "Four" };
string[][] data = { new[] { "Five", "Six\nSeven Eight" } };
Console.WriteLine(FlipTable.Of(headers, data));
+=========+=============+
| One Two | Four        |
| Three   |             |
+=========+=============+
| Five    | Six         |
|         | Seven Eight |
+=========+=============+

그리고 테이블 안의 테이블도 지원합니다.

string[] innerHeaders = { "One", "Two" };
string[][] innerData = { new[] { "1", "2" } };
string inner = FlipTable.Of(innerHeaders, innerData);
string[] headers = { "Left", "Right" };
string[][] data = { new[] { inner, inner } };
Console.WriteLine(FlipTable.Of(headers, data));
+===============+===============+
| Left          | Right         |
+===============+===============+
| +=====+=====+ | +=====+=====+ |
| | One | Two | | | One | Two | |
| +=====+=====+ | +=====+=====+ |
| | 1   | 2   | | | 1   |   2 | |
| +=====+=====+ | +=====+=====+ |
|               |               |
+===============+===============+

.NET 으로 포팅하면서 추가된 기능

flip-tables-net 버전은 .NET 이 지원하는 객체를 사용할 수 있습니다.

DataTableDataSet 을 사용하는 방법입니다.

var dt = new DataTable();
dt.Columns.Add("FirstName");
dt.Columns.Add("LastName");
dt.Columns.Add("Age");
var row1 = dt.NewRow();
row1["FirstName"] = "Junil";
row1["LastName"] = "Um";
row1["Age"] = 37;
dt.Rows.Add(row1);

Console.WriteLine(dt.FlipTablesFrom());
+===========+==========+=====+
| FirstName | LastName | Age |
+===========+==========+=====+
| Junil     | Um       | 37  |
+===========+==========+=====+

.NET nested entity object 객체는 다음과 같이 정의되어 있다면,

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int Age { get; set; }
    public List<Person> Children { get; set; }
    public List<Name> Names { get; set; }

    public Person() { }
    public Person(string firstName, string lastName, int age)
    {
        FirstName = firstName;
        LastName = lastName;
        Age = age;
        Children = new List<Person>();
        Names = new List<Name>() { new Name("A", "B") };
    }
}

public class Person2
{
    public Name Name { get; set; }
    public int Age { get; set; }
}

public class Name
{
    public string First { get; set; }
    public string Last { get; set; }

    public Name() { }

    public Name(string first, string last)
    {
        First = first;
        Last = last;
    }
}
var person2 = new Person2()
{
    Name = new Name("Junil", "Um"),
    Age = 37
};
Console.WriteLine(person2.FlipTablesFrom());
+==================+=====+
| Name             | Age |
+==================+=====+
| +=======+======+ | 37  |
| | First | Last | |     |
| +=======+======+ |     |
| | Junil |   Um | |     |
| +=======+======+ |     |
|                  |     |
+==================+=====+

복합적인 데이터가 담긴 entity model 와 List<> 객체입니다.

var personList = new List<Person>
{
    new Person("Junil", "Um", 37),
};
personList[0].Children.Add(new Person("A", "B", 12));
Console.WriteLine(personList.FlipTablesFrom());
+===========+==========+=====+==============================================================+==================+
| FirstName | LastName | Age | Children                                                     | Names            |
+===========+==========+=====+==============================================================+==================+
|     Junil |       Um |  37 | +===========+==========+=====+==========+==================+ | +=======+======+ |
|           |          |     | | FirstName | LastName | Age | Children |            Names | | | First | Last | |
|           |          |     | +===========+==========+=====+==========+==================+ | +=======+======+ |
|           |          |     | |         A |        B |  12 |          | +=======+======+ | | |     A |    B | |
|           |          |     | |           |          |     |          | | First | Last | | | +=======+======+ |
|           |          |     | |           |          |     |          | +=======+======+ | |                  |
|           |          |     | |           |          |     |          | |     A |    B | | |                  |
|           |          |     | |           |          |     |          | +=======+======+ | |                  |
|           |          |     | |           |          |     |          |                  | |                  |
|           |          |     | +===========+==========+=====+==========+==================+ |                  |
|           |          |     |                                                              |                  |
+===========+==========+=====+==============================================================+==================+

FlipTablePad 옵션

var person2 = new Person2()
{
    Name = new Name("Junil", null),
    Age = 37
};
Console.WriteLine(person2.FlipTablesFrom(FlipTablesPad.Right));
+====================+=====+
|               Name | Age |
+====================+=====+
| +=======+========+ |  37 |
| | First |   Last | |     |
| +=======+========+ |     |
| | Junil | (null) | |     |
| +=======+========+ |     |
|                    |     |
+====================+=====+


Posted by 땡초 POWERUMC

댓글을 달아 주세요

- MonoDevelop v5.7.2.2 한글 버전 빌드 업데이트

2013년부터 꾸준히 진행해 오던 MonoDevelop v5.7.2.2 한글 버전의 새로운 빌드를 업데이트 했습니다.

MonoDevelop v5.7.2.2 한글 버전은 다음의 링크에서 다운로드 받을 수 있습니다.


- 왜 MonoDevelop을 써야하나?

외국 Xamarin 기업에서 Mono 오픈소스 재단을 인수하면서 Mono 가 폭풍성장을 하고 있습니다.

이제 따른 부작용이 Xamarin이 Mono를 통해 수익을 얻으려 하는 것이죠. 물론 돈은 벌어야 하니까요. 따라서 Xamarin Studio 를 사용하고 Xamarin.*.dll 라이브러리에도 GPL 라이선스 제한을 받게 됩니다.

이에 반해 Mono와 MonoDevelop은 MIT/X11 & LGPL2 라이선스이므로 적절한 전략을 통해 크로스 플랫폼 데스크탑/모바일 개발이 가능할 수 있습니다. Unity 게임 개발에도 MonoDevelop 이죠. ^^

더 궁금하신 점이 있으시면 언제든지 이메일 주시기 바랍니다. (댓글이나 방명록 잘 확인을 안해요;;)

Posted by 땡초 POWERUMC

댓글을 달아 주세요

DeskBoard 앱은 프레젠테이션 등으로 발표를 자주 하는 분들을 위해 필자가 만든 앱입니다. (지난 블로그 글)

이번에 $9.99의 앱 가격을 이달 4월 말까지 $2.99 로 할인합니다.

DeskBoard 앱은 유료/무료 버전 두 가지가 있습니다.
무료 버전도 모든 기능을 지원 하지만 멀티 모니터(두 대 이상 모니터)를 지원하지 않습니다.
그러므로 외부 모니터에 연결하거나 멀티 모니터 지원이 필요한 분만 유료 버전을 구매하시면 됩니다.

자세한 사항은 아래의 AppStore 아이콘을 클릭하면 됩니다.

DeskBoard (유료 $2.99 <- $9.99)
DeskBoard Free (무료)

[동영상] DeskBoard 앱을 사용하는 예

이하 앱에 대한 설명입니다.


여러분의 성공적인 발표나 세미나를 위해 당신에게 더 집중할 수 있도록 DeskBoard 앱을 사용해 보세요.
여러분이 전달하고자 하는 메시지를 다양한 도형을 사용하여 청중들에게 정확하게 전달할 수 있어요.
그럼 청중들은 당신이 무엇을 강조하는지 쉽게 알 수 있답니다.
DeskBoard 앱은 다음과 같은 분들이 사용하는 것을 권장합니다. ^_^

  1. 여러 사람 앞에 발표할 기회가 많은 분
  2. 맥을 프로젝터나 원격으로 공유하여 회의 하시는 분
  3. 강의를 하거나 직업을 가지신 분
  4. 개발자, 프로그래머 중 라이브 코딩을 해야 하는 분


Posted by 땡초 POWERUMC

댓글을 달아 주세요

아름답고 자연스러운 오브젝티브-C

필자가 오브젝티브-C(Objective-C)를 접한 것은 올해 초, 갑갑한 문법적인 표현(Syntax)을 보니 코드를 보기가 싫어졌었다. 하지만 많은 iOS 개발자가 생겨나고 맥킨토시(Macintosh)를 쓰면서 자연스럽게 맥용 응용 프로그램에 관심이 생기기 시작했다. 처음에는 리눅스와 대부분의 운영체제를 지원하는 Qt(큐티) 프레임워크를 봐오다가, 코코아(Cocoa) 를 알게 되면서 맥킨토시에 가장 아름다운 UI 프레임워크인 것을 느끼게 되었다고 할까.

오브젝티브-C는 매우 깊은 역사가 있다. 이 역사에 대해서는 다음의 위키피디아(Wikipedia) 를 참고하기 바란다. 필자도 이 언어에 대한 깊은 역사를 이렇다 할 만큼 자신 있게 설명해 주기 힘들 것 같다.

.. 생략 .. [1]
오브젝티브-C는 스텝스톤(Stepstone)이라는 회사에서 일하고 있던 브래드 콕스(Brad Cox)와 톰 러브(Tom Love)라는 두 연구원이 만들었다. 역시 1980년대 초의 일이다. 이 두 사람은 1981년 ITT의 프로그래밍 기술 센터(Programming Technology Center)에서 일하던 시절 스몰토크를 처음 접했다. 콕스는 소프트웨어 설계와 프로그래밍에 있어서 재사용성의 문제에 흥미를 느끼게 되었고, 스몰토크같은 프로그래밍 언어가 ITT 시스템 개발자들이 개발을 진행할 강력한 환경을 만드는 데 필요불가결한 요소임을 깨닫게 되었다. 콕스는 C 컴파일러를 고쳐 스몰토크의 기능 일부를 추가하기 시작했고, 곧 그 스스로 OOPC라고 불렀던 C의 객체지향 버전을 내놓게 되었다. 한편 러브는 1982년에 Schlumberger Research에 채용되었고, Smalltalk-80의 최초 상업적 버전을 써 볼 기회를 가지게 되었다. Smalltalk-80은 이후 그들이 낳은 정신적 자식의 성장에 큰 영향을 끼쳤다.
.. 생략 ..

필자가 오브젝티브-C를 접하면서 ‘빙고!’를 외쳤다. 현대적인 언어의 대부분이 C언어, 그리고 바로 이 오브젝티브-C 언어의 영감을 받았다고 해도 무리는 아니다. (단, 현대적인 언어의 정의는 스스로 정의를 내리기 바란다.)

그렇다면 왜 오브젝티브-C 언어가 아름다운지 보자.

아름다움을 만들어 준 메시지 기반 언어

오브젝티브-C의 가장 기초적인 문법을 일반적인 객체 지향 언어의 문법과 비교해 보자.

// 일반적인 객체지향 언어들의 표현
void* obj = data->get_data(); // 또는
void* obj = data.get_data(); // 또는
Object obj = data.get_data();

// 오브젝티브-C 언어
NSObject* obj = [data get_data];

위의 일반적인 객체지향 언어와 오브젝티브-C 언어는 표현하는 방법에 있어 다른 점이 보인다. 자, 무엇이 다른지 한번 살펴보자.

  1. 문법 표현 방법 : 가장 차이가 나는 점은 식의 표현을 대괄호([ ])로 묶여 있다. (메서드 호출 시)
  2. 메서드 호출 방법 : 포인터(->) 또는 참조(.)를 통해 호출하지 않고 공백(a space)으로 메서드를 가리켜 호출한다.

위 코드가 컴파일 된다면 더욱 명확하게 차이점을 볼 수 있다.

일반적인 객체지향 언어의 경우 컴파일 된 어셈블리(기계어) 코드는 메서드가 메모리 상에 상주하고 있는 주소를 통해 직접 메모리를 엑세스하여 메서드를 실행한다.
오브젝티브-C의 경우 바로 이것이 오브젝티브-C 언어의 특징인 메시지를 통해 메서드를 호출하는 방법이다. data 객체는 get_data() 메서드를 직접 호출하지 않고 다른 대리자(위임)를 통해 메서드를 실행한다.

그렇다면 오브젝티브-C는 대리자를 통해 메서드의 실행을 위임함으로서 장점은 뭘까?

  1. NullPoint 예외(오브젝티브-C의 nil 또는 NULL)나 기타 치명적인 오류를 언어적인 레벨에서 차단한다.
  2. 관리언어(Managed Languages)인 자바, C# 등에서 즐겨 쓰는 Code Interception 등의 기법과 유사한 것들을 쉽게 확장할 수 있는 포인트를 제공한다.
  3. LLVM과 같은 가상 머신(Virtual Machine) 매커니즘을 손쉽게 적용할 수 있다. (clang)
딱히 바로 생각나는 것은 몇 안되지만, 더 많은 장점이 있음은 분명하다. 그리고 오브젝티브-C의 메시지 기반으로 작동하는 언어적인 특성을 분석해보자

오브젝티브-C 메시지 기반 메서드 호출

1. objc_msgSend 함수의 메커니즘

오브젝티브-C는 objc_msgSend() 함수를 이용하여 메시지를 보낸다. 이것은 함수만 해당되는 사항은 아니다. 위에서 살펴본 것과 같이 식의 표현을 대괄호([ ... ]) 안에 코드로 표현하는데 이 대괄호 안에 들어가는 모든 객체건 뭐건 간에 메시지를 통해 값을 가져오거나 메서드를 호출하게 된다.

아래 보이는 어셈블리 코드는 필자가 오브젝티브-C로 작성한 맥용 데스크탑 응용 프로그램 중 일부를 어셈블리 레벨에서 디버깅 하는 스크린샷이다. 다음에 사용된 코드의 일부는 다음과 같다.

[self.sidebar setTarget:self];

sidebar는 인스턴스화 된 객체(Object)이다. 오브젝티브-C는 메서드 호출에서만 메시지를 보내는 것이 아니라는 것이다. 그리고 objc_retainAutoreleasedReturnValue() 함수는 매우 긴 이름이지만, 맨 앞 글자의 retain만 주목해서 보면 된다. sidebar 인스턴스는 현재 컨텍스트(Context)에서 참조하므로 참조 카운터(References Count)를 1 증가 시킨다.


2. objc_msgSend 함수 내부에서 전달받은 메시지

아래의 스크린샷은 objc_msgSend() 함수의 내부에서 RIP 레지스터가 가리키는 메모리 주소의 HEX 이다. '73 69 64 65 62 61 72 00'(sidebar) 문자열은 objc_msgSend() 함수에 의해 RTTI(Run-time Type Information) 정보로 객체를 가져오기 위한 메시지라고 보면 된다. lldb의 're r' 명령을 통해 레지스터의 값들을 확인할 수 있다.

얼핏 보아도 아래의 스크린샷의 메모리 공간은 인스턴스 객체의 메시지와 메서드의 메시지들을 몰아서 외부에서 참조할 수 있도록 나열한 것임을 알 수 있다.


3. objc_msgSend() 메서드의 시그너처가 선언된 곳에서 objc_msgSend 호출

lldb 디버거를 통해 ni 명령으로 objc_msgSend() 함수에 진입하면 메시지 전달 함수가 메모리 상에 상주해 있는 곳으로 이동 시킨다.


4. 컨텍스트(Context)에서 전달된 메시지를 순회하여 검색/실행

전달되는 메시지를 통해 인스턴스의 메타데이터를 사용하여 실제로 객체를 가져오게 된다. 아래의 네모난 상자의 명령들이 바로 객체를 찾아오기 위한 루프(Loop)이다. 


5. 메시지에 의해 처리된 객체는 일부 캐싱하여 성능 향상을 꾀함

재미있는 점은 매번 메시지의 정보를 순회하면서 찾지 않고, 한번 찾은 정보는 별도로 캐싱 하고 있는 공간에서 검색하게 된다.


지금까지는 sidebar 인스턴스를 가져오기 위한 과정이었다. 이제 이 인스턴스 객체의 메서드를 호출하는 과정인데, objc_sendMsg()를 통해 메시지를 전달하여 찾은 메서드를 실행하게 된다.



Posted by 땡초 POWERUMC

댓글을 달아 주세요

SharePoint 데이터베이스로 부터 모든 문서를 백업 및 추출하기

개요

필자는 SharePoint 서버 제품을 이용해서 문서를 관리해 왔다. SharePoint를 이용하면 수 천개의 문서를 종류별로 분류하고 데이터베이스화할 수 있다. 문서의 종류와 문서의 내용도 인덱싱(indexing)되므로 문서 내용과 다양한 메타 데이터로 문서를 검색할 수 있다는 점 때문에 많은 문서를 쉽게 관리하고 검색할 수 있다는 장점이 있다.

SharePoint의 장점을 나열하지면 많겠지만, 모바일 트랜드 시대에서는 에버노트가 최고이지 쉽다. 필자의 에버노트와 DropBox는 땡전 한푼 안들이고 프리미엄 서비스를 받고 있는데, 필자가 문서를 사용하고 관리하는 패턴에선 SharePoint 보다는 에버노트DropBox 조합이 더 접근성이 좋고 사용하기도 편하다. 데스크탑은 물론이고 브라우저, 다양한 모바일 기기에서 에버노트 클리핑과 DropBox 동기화 등을 지원하기 때문이다.

그래서 이번에 필자가 가지고 있는 수 천개의 모든 문서를 이전하고자 SharePoint의 모든 파일을 추출해야 했다. 여기에서 여러 Site Collections/Sites/Doc Libs의 각각의 문서를 한 번에 추출하는 작업을 진행했다.

1. WSS_Content 데이터베이스 연결

원하는 툴을 이용해서 SharePoint가 사용하는 데이터베이스에 연결한다. SharePoint에 저장된 문서가 많을 수록 데이터베이스에 연결해야 하는 시간이 늘어난다. 그러므로 Timeout이 발생하지 않도록 주의해야 한다. 필자는 여기에서 SSMS(Sql Server Management Studio) 2012 버전을 사용했다.

2. 파일 추출하기

2.1. 데이터베이스 구성 변경 쿼리 실행

sp_configure 'show advanced options', 1;  
GO

RECONFIGURE;  
GO

sp_configure 'Ole Automation Procedures', 1;  
GO

RECONFIGURE;  
GO

2.2. 데이터베이스 추출 쿼리 실행

아래의 쿼리는 이 사이트의 링크[1]를 참고하였으나, 일부 오류가 발생하여 필자가 수정한 부분이 있으니 이점 참고하기 바란다.

그리고 SharePoint에 저장되는 파일들은 다양한 타입이 존재한다. 가령, 메타데이터의 Binary 파일, _private 폴더, *.aspx, 시스템에 필요한 파일 등 필자가 저장한 문서와 상관 없는 찌꺼기 들도 함께 저장이 된다.

파일의 다양한 플래그 값은 MSDN의 Document Store Type, Doc Flags 문서[2]를 참고 하면 된다.


  
[그림1] WSS_Content 데이터베이스의 모든 문서를 파일 시스템으로 추출한 결과 화면


USE WSS_CONTENT;  

DECLARE @PATH_PREFIX  NVARCHAR(1024);  
SET @PATH_PREFIX = 'C:\BACKUP\';  -- 이곳에 백업할 경로를 입력, 반드시 뒤에 '\' 문자 추가하셈'


--DECLARING THE CURSOR, THIS IS THE ITEMS YOU WANT TO RUN THE EXTRACTING ON  
DECLARE CURSOR_Images CURSOR FOR (SELECT Id FROM [dbo].[AllDocs])  

--DECLARE THE TYPE OF THE COLUMN YOU SELECTED ABOVE  
DECLARE @ImageID uniqueidentifier;  

--START THE CURSOR AND RUN THROUGH ALL THE ITEMS IN CURSOR_Images  
OPEN CURSOR_Images  
FETCH NEXT FROM CURSOR_Images INTO @ImageID  
WHILE (@@FETCH_STATUS <> -1)  
BEGIN  
  --DECLARE THE VARIABLE THAT WILL KEEP THE BINARY DATA  
  DECLARE @ImageData varbinary(MAX);  
  --SELECT THE BINARY DATA AND SET IT TO @ImageData.  THE BINARY DATA FOR ALLDOCS ARE LOCATED IN ALLDOCSTREAMS  
  --AND THE ID IS THE SAME AS IN ALLDOCS  
  SELECT @ImageData = (SELECT TOP 1 CONVERT(varbinary(MAX), Content, 1) FROM [dbo].[AllDocStreams] WHERE Id = @ImageID ORDER BY InternalVersion ASC);

  --GET THE LOCATION OF THE DIRECTORY THE FILES WAS SAVED IN AND CHANGE REPLACE THE / WITH \ TO BE USED IN FILESYSTEM  
  DECLARE @DIRPATH NVARCHAR(MAX);  
  SET @DIRPATH = REPLACE((SELECT  DirName FROM [dbo].[AllDocs]  WHERE Id = @ImageID),'/','\');

  --SET THE PATH  
  DECLARE @Path nvarchar(1024);  
  --SELECT @Path = 'C:\Export\' + @DIRPATH + '\';  
  SELECT @Path = @PATH_PREFIX + @DIRPATH + '\';
-- '\

  --CREATE THE DIRECTORIES  
  EXEC master.dbo.xp_create_subdir @Path;

  --GET THE FILE NAME OF THE FILE FROM LEAFNAME  
  DECLARE @Filename NVARCHAR(1024);  
  DECLARE @DocFlags INT;  
  DECLARE @Type     TINYINT;  
  SELECT @Filename = (SELECT LeafName FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @DocFlags = (SELECT DocFlags FROM [dbo].[AllDocs] WHERE id = @ImageID);  
  SELECT @Type     = (SELECT [Type]    FROM [dbo].[AllDocs] WHERE id = @ImageID);

  -- 폴더를 0바이트 파일로 생성하므로 파일이 아닌 경우 파일 저장 루틴 진입 금지  
  IF (@Type = 1 AND @DocFlags = 0) OR (@DocFlags & 0x100) <> 0x100 BEGIN  
CONTINUE;  
  END   
  ELSE BEGIN

  --SET THE FULL PATH FOR WHERE THE FILES WILL BE STORED  
  DECLARE @FullPathToOutputFile NVARCHAR(2048);  
  SELECT @FullPathToOutputFile = @Path + '\' + @Filename;

  --SAVE THE FILE TO THE FILE SYSTEM  -'
  DECLARE @ObjectToken INT  
  EXEC sp_OACreate 'ADODB.Stream', @ObjectToken OUTPUT;  
  EXEC sp_OASetProperty @ObjectToken, 'TYPE', 1;  
  EXEC sp_OAMethod @ObjectToken, 'OPEN';  
  EXEC sp_OAMethod @ObjectToken, 'WRITE', NULL, @ImageData;  
  EXEC sp_OAMethod @ObjectToken, 'SaveToFile', NULL, @FullPathToOutputFile, 2;  
  EXEC sp_OAMethod @ObjectToken, 'Close';  
  EXEC sp_OADestroy @ObjectToken;

  END

  --LOOP TO THE NEXT ENTRY IN THE CURSOR  
  FETCH NEXT FROM CURSOR_Images INTO @ImageID  
END  
CLOSE CURSOR_Images  
DEALLOCATE CURSOR_Images  

2.3. 참고 사항

위의 쿼리는 다양한 메타데이터와 시스템 파일(*.aspx, _private 등..)을 모두 저장한다. 이런 쓰레기 데이터를 파일로 저장하지 않길 원한다면 아래의 쿼리를 이용해서 조건절을 추가해 주면 된다.

각각의 플래그 값의 의미는 Document Store Type 문서를 참고하면 된다. 그러면 여러분이 원하는 데이터만 파일 시스템으로 추출하여 저장하도록 커스터마이징이 될 것이다.

SELECT LeafName, DocFlags  
  FROM [dbo].[AllDocs]  
 WHERE (DocFlags & 0x100) = 0x100
   AND (DocFlags & 0xFFFF0000) <> 0xFFFF0000
   AND (DocFlags & 0x80) <> 0x80
   AND (DocFlags & 0x10) <> 0x10
   AND (DocFlags & 0x8) <> 0x8  

결론

만약 SharePoint에 저장되었던 많은 파일 또는 데이터를 전혀 다른 솔루션으로 이전하고 싶은 경우가 있다. SharePoint는 Microsft SQL Server 데이터베이스에 바이너리를 저장하는데 파일 시스템을 단일 데이터베이스에 저장한다는 것이 좀 아이러니 한 구조이다.

많은 기업내 담당자들의 SharePoint에 대한 피드백을 물어보면 빠지지 않는 것은 ‘느리다’ 라는 것인데, 기하급수적으로 늘어나는 데이터베이스 용량과 웹 응용 프로그램의 SPSites/DocLibs 등이 생성되면서 시간이 지날 수록 점점 느려지는 것은 어쩔 수 없는 구조인 듯 하다. 더불어 SharePoint는 과거의 아키텍처가 현재까지도 트랜드의 변화에 대응되지 못하고 전반적으로 과거와 동일한 아키텍처에 새로운 기능만 계속 붙여나가다 보니 솔루션 자체의 구조적인 면에서 악순환이 되풀이 되는 형세이다.

하지만, 이 아티클을 통해 SharePoint 데이터베이스에서 직접 파일을 추출하여 파일 시스템으로 저장할 수 있다. 이 방법을 통해 추출된 다량의 파일을 다른 솔루션으로 옮기거나 업로드하면 끝이다.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 억사마 2014.02.03 18:00 신고 Address Modify/Delete Reply

    안녕하세요~ 연락처가 어디 없으셔서 이렇게 댓글 남깁니다. SharePoint를 파일시스템에 백업을 받아야하는 급박한 회사업무가 생겼습니다. 좀 도움을 얻을수 있을까요? 부탁드리겠습니다. 혹시 몰라 제 이메일 주소를 남깁니다. e.joe@samsung.com 연락 부탁드리겠습니다. 감사합니다.

  2. 2014.02.03 18:14 Address Modify/Delete Reply

    비밀댓글입니다

MonoDevelop 한글판이 곧 업데이트 됩니다.

다운로드 : http://monodevelop.co.kr

MonoDevelop 통합 개발툴의 한글화를 위해 Github에 Pull Request로 게시하였고, 몇 일 후 특별한 문제 없이 MonoDevelop Master 브랜치에 병합이 완료 되었습니다.

[Ide] Translate to Korean language

차후 공식적인 배포에 의해 Xamarin Studio, MonoDevelop, MonoDevelop for Unity 와 같은 개발툴에서 한글 버전을 만나뵐 수 있을 것 같네요.

GitHub MonoDevelop Korean Repository

오탈자 및 버그 신고

Xamarin의 공식적인 버그 신고는 https://bugzilla.xamarin.com/ 에서 신고할 수 있습니다. 다만, 한글 번역과 관련된 버그를 처리해 줄지 모르겠네요.

  1. http://monodevelop.co.kr/ 에서 신고해 주시거나

    또는

  2. GitHub MonoDevelop Korean Repository 에 신고해 주시거나

    또는

  3. 직접 MonoDevelop Repository 에서 Fork 하셔서 작업하시면 됩니다.


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 컴포지트 2013.08.05 09:09 Address Modify/Delete Reply

    군말없이 merge 시켜주다니..ㅋㅋ
    노고에 감사드립니다.

  2. hellojin 2014.02.11 17:33 Address Modify/Delete Reply

    맥용 xamarin studio 를 사용하려하는데. 한글을 입력하면. 그냥 죽어버리는 군요.. 그래서. 한글화 된걸 사용해보고 싶은데.. 어떻게 해야되는지 통 감이 안오네요.. 어떻게 해야되는지 좀 알려주세요..~ 부탁드립니다.

    • 땡초 POWERUMC 2014.02.12 09:23 신고 Address Modify/Delete

      오 그래요?
      저는 같은 맥에서 죽지 않고 잘 써지는데요...

      기본 내장 외 한글 입력기를 쓴다거나 다른 이유가 있을 것 같은데,
      덤프를 떠주시면 제가 한번 봐 드리겠습니다.

  3. oiziee 2014.03.07 18:07 Address Modify/Delete Reply

    안녕하세요 위에 링크가 죽어있네요
    한글버전을 꼭 구하고 싶은데
    한글버전을 보내주실수 있으신가요?
    부탁드립니다
    pijunyel@naver.com

    • 땡초 POWERUMC 2014.03.07 18:24 신고 Address Modify/Delete

      한글버전은 Xamarin Studio에 함께 배포 되고 있습니다.
      아래의 링크에서 받으시고,
      환경 설정의 Language에 'Korean' 으로 변경해 주시면 됩니다.

      http://xamarin.com/download

  4. 지나가던이 2014.08.05 10:24 Address Modify/Delete Reply

    한글 버전 주석은 너무나도 감사드립니다.
    하지만, 버그가 있더군요... 조금 아쉽습니다.

    '아'를 입력할경우 '아'를 입력한 후에도 한번 더 무언가를 입력해주어야만 해결되는 현상이 있습니다.

    더 좋은 버전 기대하겠습니다.

  5. TeemoSoft 2015.01.07 01:37 신고 Address Modify/Delete Reply

    안녕하세요 맥에서 유니티 모노디벨롭 을 사용중인데 http://monodevelop.co.kr에서 받아서 사용해보니
    Assembly-UnityScript 로드 실패
    Assembly-UnityScript-firstpass 로드 실패

    이렇게 뜨네요 작업하는데는 큰 문제는 없지만 어딜 고치면 될까요?

MonoDevelop for Korean version..!

MonoDevelop은 ECMA 표준을 가장 완벽하게 구현한 Mono 플랫폼을 개발하기 위한 통합 개발 도구 입니다.

2011년경, Xamarin 기업에 인수합병 되면서 모바일에 강력하게 대응되는 플랫폼으로 한 단계 진화하였습니다. iOS, Android 외에 콘솔 게임 개발도 지원하게 되었습니다.

https://github.com/powerumc/monodevelop_korean

현재 진행 사항입니다.

  • POSIX에서 재정한 Gettext API에 대응되는 .po 한글화 작업이 거의 완료가 되었습니다.
  • 한글을 지원하기 위해 MonoDevelop 내부 코드가 변경되었습니다.
  • 한글화에 따른 알 수 없는 크래시가 발생하여 디버깅 중입니다.
  • 다음 주 중으로 안정성 테스트 및 한글화 품질 테스트를 진행할 예정입니다.
  • 테스트 이후 공식적인 배포 사이트를 개설할 예정이며,
  • Mono Community 에 제출될 예정입니다.

많은 응원과 기대 부탁 합니다.

진행중인 MonoDevelop (Xamarin Studio) 스크린 샷




Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 김영환 2013.07.25 14:54 Address Modify/Delete Reply

    앗!!!!

    감사합니다.
    화이팅!!!

  2. 컴포지트 2013.07.25 17:01 Address Modify/Delete Reply

    일본어와 중국어 번역은 이미 끝났는데 오늘 한글화 소식을 들으니 이런 꿀같은 소식이!
    정말 감사합니다.

    근데 이툴이 한글 깨져요. 맥이나 리눅스나 둘다 한글 깨져요..
    이건 어떻게 해결 됐나요?

  3. 컴포지트 2013.07.26 18:19 Address Modify/Delete Reply

    인코딩 어떻게 지정하던 한글 입력이 안됩니다. 출력도 문제고 입력조차 어려운 실정입니다. 아예 이스케이프 해야지 됩니다..

    • 엄준일 2013.07.27 00:24 Address Modify/Delete

      한글 입력이 깨진다는게
      입력할 때 'ㅎㅏㄴㄱㅡㄹ' 이렇게 입력 되는 것을 말씀하시는 거죠?

  4. kmshts 2013.07.31 01:06 Address Modify/Delete Reply

    저도 이파일을 받아봤음좋겠는데 어디서 받아볼수있습니까? po파일만

    • 엄준일 2013.07.31 04:19 Address Modify/Delete

      Github에서 monodevelop_korean 브랜치에 있습니다.
      https://github.com/powerumc/monodevelop_korean/tree/monodevelop_korean

      위의 링크 파일 4개 중에 하나예요.

JS-Lambda 자바스크립트 라이브러리를 공개합니다.


JavaScript Array Extensions 자바스크립트 오픈 소스를 개발한 데 이어 JS-LambdaLGPL 라이센스로 공개합니다.

JavaScript 에서 람다 표현식(Lambda Expression)을 사용할 수 있도록 만든 라이브러리 입니다. 자세한 내용은 아래의 소스 코드를 참고 하시면 됩니다.

Github: https://github.com/powerumc/js-lambda

JS Lambda

  • It is possible lambda expression that can be used JavaScript.
  • you just got a function F();

Simple Examples

// Before  
function func(a,b) {
    return a + b;
}  
console.info( func(4,6) );


// ** After with JS-Lambda **  
var func = F("a,b => a + b");  
console.info( func(4,6) );  

// Result  
10

Or you can invoke directly

// Before  
function anonymousMethod(a,b) {
    return a + b;
}  
console.info( anonymousMethod(4,6) );  

// ** After with JS-Lambda **  
console.info( F("a,b => a + b")(4,6) );  

// Result  
10

Callback Examples

// Before  
function callback( func ) {
    if( func ) func();
}  

callback( function() { console.info('My name is Junil Um'); } );  

// ** After with JS-Lambda **  
callback(  F("() => console.info('My name is Junil Um');")  );  

// Result  
My name is Junil Um  

With jQuery

// Before  
var li = $("item li");  

li.each( function(i, o) {
    $(o).addClass("some");
} );


// ** After with JS-Lambda **  
var li = $("item li");  

li.each( F("(i, o) => $(o).addClass('some');") );  


Posted by 땡초 POWERUMC

댓글을 달아 주세요

VSGesture for Visual Studio 2013 Preview 배포 완료

Visual Studio 2013 Preview 버전 배포 완료

기능적으로 향상된 것은 없습니다. 이번 버전의 Visual Studio 2013의 Extension Schema가 골때리게 바껴서 ;;

Visual Studio 2013의 Tools -> Extension Manager 에서 다운로드 받으실 수 있습니다. (검색: vsgesture)

Download : http://visualstudiogallery.msdn.microsoft.com/e03c91ff-e20d–4dcc–822b–172a68c40f5b

  • Version 12.0 [2013/07/17]
    Support Visual Studio 2013 Preview

  • Version 11.11 [2012/03/01]
    Modified wrong display texts.

  • Version 11.1
    Resolved compativility bug between VS2012 and VS2010.

  • Version 11.0
    Support Visual Studio 2012, 2010

VSGesture shipped for Github. https://github.com/powerumc/vsgesture
VSGesture for VS2012, VS2010 is now available for download.
http://blog.powerumc.kr/305

VSGesture can execute command via mouse gestures within Visual Studio.
If you have any feedback, please send me an email to powerumc at gmail.com.

Visual Studio 2005, 2008 version : http://visualstudiogallery.msdn.microsoft.com/en-us/F5007932–0720–492B–8A51–631D5265F6B7




Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 설치가 안됩니다 2013.09.04 22:37 Address Modify/Delete Reply

    안녕하세요
    확장 관리자를 통해서 다운 받을려고 하는데,
    종속성 경고 - 다음 참조가 있어야 설치를 계속 할 수 있습니다. - Visual studio MPF 라는 팝업창이 뜨면서 설치가 안됩니다. 이거 어떻게 해야 하나요?

    참고로 윈도우7 64bit, visual studio 2010사용하고 있습니다.

[퀴즈] 프로그래머를 위한 문제 #3

요즘 퀴즈를 풀다보니 재미가 들렸나, 필자가 문제를 하나 내보려고 한다. 어려울 수도, 그렇지 않을 수도 있는 문제이며, 효율적인 코드를 작성하는 것 보다 최대한 짧게 짜는 것이 목적이다.

문제의 유형과 정답의 유형은 지난 문제를 참고하면 된다.

미로 찾기 게임

문제는 미로 찾기 게임이다.

  1. 10 x 6 (가로, 세로) 크기에 * 문자가 채워진 직사각형
  2. 미로의 크기가 변해도 실행 가능해야 한다.
  3. 문자 S 는 입구 위치, 문자 E는 출구 위치이다.
  4. S 문자와 E 문자 사이에는 공백으로 연결된 길이 있고, 길은 여러 갈래일 수 있다.
  5. 길(공백)은 2x2(가로, 세로) 이상의 공간을 가질 수 없다.
  6. 미로 찾기를 시작하는 함수가 호출되기 이전의 초기화를 위한 코드는 코드 길이에서 제외된다.
  7. 코드 길이는 최대한 짧게 작성한다. (알고리즘 효율성은 측정 안함)
  8. 개발 언어는 무관, 언어별로 가장 짧게 작성한 코드가 우승(?)



미로 찾기 게임 예제 코드

// 아래의 변수의 초기화는 코드 길이에서 제외된다.  
map = """  
**********  
** **    E
*   * ****
* * * *  *
* *    * *
S ****   *  
**********"""

y = map.indexof("S") / maxX
x = map.indexof("S") % maxX  

// 아래 코드 부터 코드 길이를 잰다. 개행 문제는 코드 길이에서 제외  
void explore(x,y)
{
    // ...생략...
}  

정답

아래는 필자가 작성한 코드이다. 짧게 작성하는 방법은 여러 가지이므로 혹시 여러분들께서 C++ 또는 자바스크립트, C# 등으로 작성하신 코드는 댓글로 달아주세요.

Python( 파이썬 )

아래 주석의 begin code/end code 사이의 문자는 총 273 문자. 방향에 대한 가중치를 주면 훨씬 빠르게 길을 찾을 수 있지만, 여기에선 구현을 제외했다.

#123456789
m = """  
**********  
** **    E
*   * ****
* * * *  *
* *    * *
S ****   *  
**********"""

X = m.index("\n", 1) - 1
Y = m.count("\n") - 1
m = m.replace("\n", "")  

(y, x) = divmod(m.index("S"), X)  

### 총 273 바이트 ###  
########### begin code ############  
def E(x,y,a):  
 n=m[x+(y*10)]  
 if n=="*"or x<0 or x>X or y<0 or y>Y:return None

 # print "%d, %d" % (x, y)  
 if n=="E": print("END");quit()

 while a!=2 and E(x+1,y,1)!=None:pass  
 while a!=1 and E(x-1,y,2)!=None:pass  
 while a!=8 and E(x,y+1,4)!=None:pass  
 while a!=4 and E(x,y-1,8)!=None:pass  

E(x,y,0)  
############# end code ##############


## 실행 결과 ##  
0, 5  
1, 5  
1, 4  
1, 3  
1, 2  
2, 2  
3, 2  
3, 3  
3, 4  
4, 4  
5, 4  
6, 4  
6, 5  
7, 5  
8, 5  
8, 4  
8, 3  
7, 3  
5, 3  
5, 2  
5, 1  
6, 1  
7, 1  
8, 1  
9, 1  
END  


Posted by 땡초 POWERUMC

댓글을 달아 주세요

프로그래머를 위한 문제 #2

얼마 전 OKJSP 를 통해 이런 문제를 보았다.

문제는 아래의 코드 중 /* INPUT */ 주석에 알맞은 코드를 넣어, victory() 메서드가 호출되도록 완성하여라.

필자의 컴퓨터에서는 답이 (function-48)(); 로 나왔다. 

typedef int (*f)(); 
int variable = 1;   

int function() {     
   if(variable == 1 ) return 
      /* INPUT */       
   5; 
   victory();  
}   

int main() 
{     
   function();
   return 0; 
}  

[문제 코드] 위의 INPUT 주석에 알맞은 코드를 넣어라.

단 제약 조건이 있습니다.

  • 다음의 문자는 사용할 수 없음 : main, victory, asm, %, *, _, #, /, “, ‘
  • 최대 11자
  • 세미콜론(;)은 한 번만 써야 함

문제 해결 과정 #1

일단 Visual Studio 2012 C++ 로 작성한 코드인데, 이 코드는 답을 찾아가기 위한 중간 코드이다.

이 코드를 보자마자 ‘스택 프레임(Stack Frame)’을 이용해야겠다는 맘을 먹고 코드를 작성했다. Visual Studio에서 만든 C++ 프로젝트의 속성으로 들어가서 RTC 런타임 체크 기능을 꺼야 한다. 그렇지 않으면 스택을 덮어 쓸 수가 없이, AccessViolation 오류가 발생할 것이다.

프로젝트 속성 -> 구성 속성 -> C/C++ -> Code Generation -> Basic Runtime Checks -> Default 로 변경

#include "stdafx.h"  
#include <iostream>  

using namespace std;  

int victory()
{
    cout << "victory" << endl;
    return 0;
}  

typedef int (*f)();  
int variable = 1;  

int function()
{
    int a;
    int n = (int)(&a) + 8;// 일반적으로 스택은 위로 자라므로,  EBP + 4 의 위치를 구함

    // victory 메서드 시작 위치는 현재로 부터...  765임
    cout << (int)(&victory) - (int)(&function) << endl;  
    *(void**)n = (void*)((int)(&function) - 765);    

    if(variable == 1 ) return
    /* INPUT */ 
    5;
    victory();
}  

int _tmain(int argc, _TCHAR* argv[])
{
    function();
    return 0;
}  

// 실행 결과  
// -765  
// victory  

대충 그림이 나왔으니 코드를 /* INPUT */ 에 들어갈 수 있도록 예쁘게 다듬어주면 될거라고 생각했다. 그런데 VC++은 타입체크가 너무 강한지 몰라도 어떻게 예쁘게 다듬어도 오류가 난다. 줸장~ 문제와는 상관 없이 좀 더 만져봐야 겠다.

문제 해결 과정 #2

오늘 정성태 과장님이 이 문제를 보고 이야기를 나누었고 답을 보여주셨다. 답은 링크를 통해 방문하면 된다.

과장님 왈, VC++ 에서는 컴파일이 안될거라고, GCC에서 컴파일 했다고 알려주셔서 나도 얼른 GCC로 바꿨다. 궁극적으로 위의 문제 해결 과정 #2 방법을 GCC로 간결하게 표현했다. 어쨌든 정성태 과장님과 답이 거의 같다.

정성태 과장님이 아니었으면 VC++만 가지고 매달렸을텐데, 문제를 풀 수 있도록 도와주신 울 과장님께 ㄱㅅ ㄱㅅ ^^

# include <stdio.h>  

int victory()
{
    printf("victory\n");
    return 0;
}


typedef int (*f)();  
int variable = 1;  

int function()
{
    // victory 메서드가 얼마만큼 떨어져있나 찍어봄... 48만큼...
    printf("%d\n", &function - &victory);  


    if(variable == 1 ) return

        (function-48)();      /* <------- INPUT CODE */
    ;

    5;

    victory();

}  

int main(int argc, const char * argv[])
{
    printf("---------------\n");
    function();
    return 0;
}   

// 실행 결과  
48
victory  


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. orbit 2016.12.20 14:16 Address Modify/Delete Reply

    재미있는 글이네요
    저는 VS2015에서 이렇게 풀었습니다.

    #include "stdafx.h"
    #include "victory.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #endif

    #include <iostream>

    int victory()
    {
    std::cout << "victory" << std::endl;

    return 0;
    }

    typedef int(*f)();
    int variable = 1;

    int function() {

    f foo = (f)((int)function - ((int)function - (int)victory));

    if (variable == 1) return
    /* INPUT */ foo();
    5;
    victory();
    }

    int main()
    {
    function();
    return 0;
    }

프로그래머를 위한 문제

프로그래머라면 알쏭달쏭한 논리적인 문제를 좋아하는 편인 것 같다. 답이 팍~ 나오는 문제보다 역량에 따라 코드의 아름다움이 달라지는 것을 추구하는 프로그래머라면 더욱 그렇다.

문제: 1부터 1만까지 8은 모두 몇 개가 나오나?

문제는 쉽다. 1부터 1만까지 8이라는 문자 개수만 카운팅하면 된다. 그런데 이렇게 간단한 문제를 코딩해 놓고 보면 맘에 안든다. 더 짧게…. 아래의 문제를 각 언어별로 풀어보았는데, 바이트 수는 캐러지 리턴(carriage return) 문자를 모두 제거한 바이트 수이다.

참고로, 이 문제는 ‘닷넷(.NET) 프로그래머 모임’ 에서 처음 본 문제인데, 오래 전의 일이라 게시글의 링크를 도저히 찾기가 힘들어서 링크를 남기지 못했다.

여러분 중 문제를 풀어보려고 한다면, 바로 아래에 답이 있으니 브라우저를 먼저 종료하길 바란다.

파이썬(python)

파이썬을 배운지 얼마 안되던 때에 이 문제를 만나서 파이썬으로 풀어보았다. 누가 짜도 최종적으로 아래의 코드가 될거다. 처음에는 이렇게 짧게 가능한 파이썬이 맘에 안들었지만, 이제는 맘에 든다. ㅋ;

더 이상은 짧게 안되지 싶다.

# 총 38 바이트   
(str(list(range(1,10001))).count('8'))  

C#

C# 코드로 짜면 아래처럼 된다. 아래의 코드는 확장 메서드와 람다 표현식이 전부다.

혹시나 요걸 비트 연산으로 풀어봤는데, 아래 코드보다 길어지더라. 뭐 내가 짠 코드라 길어질 수도 있겠다.

// 총 84 바이트  
Console.WriteLine(Enumerable.Range(1,10000).Sum(o=>o.ToString().Count(n=>n=='8')));   

Java

Java 8 정식이 나오면 Lambda 지원. 다만 C#의 확장 메서드를 언어상 지원하지 않으므로 Where, Select, Take, Skip 과 같은 확장 메서드는 사용하지 못할 것 같다. 어쨋든 Java 로 이 문제를 짧게 풀수 있는 경쟁력이 없으므로 패스!

C++ Update - 2013-07-04

C++에 대해 조예가 깊지 않아서 내 머리로는 더 짧게 안된다. 이 코드는 위의 파이썬과 C#과는 알고리즘(?)이 좀 틀리다. 어쩔 수 없다. 짧게 하려면…

// 총 146 바이트  
vector<int> v(10000);  
auto n=1,s=0;  
generate(v.begin(),v.end(),[&n, &s](){  
auto m=to_string(n);  
s+=count(m.begin(),m.end(),'8');  
return n++;});  
cout<<s;

아래 댓글에 더 짧은 C++ 코드를 올려주신 HATENA [링크] 님께서 올려주신 코드 입니다. Update - 2013-07-04

// 총 94 바이트
int c=0;
for(int i=1;i<10001;i++){
auto s=to_string(i);
c+=count(s.begin(),s.end();'8');}
cout<<c;

JavaScript - Update 2013-07-03

본 코드는 아래 댓글의 ddd 님께서 작성하신 자바스크립트 코드 입니다.

// 총 94 바이트  
var a=[];
for (var i=1;i<10001;i++)
a[i]=i;
console.info(a.join("").replace(/[^8]/gi,"").length);
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 황정현 2013.07.02 09:33 Address Modify/Delete Reply

    예전에 자바스크립트로 한번 풀어봤었네요... 근데 너무 길어요...
    for(var i = 0, len = 10000, count = 0, tmp = ""; i < len; i++){
    var arr = [];
    tmp = (""+i);
    for (var j = 1, len2 = tmp.length; j <= len2; j++)
    {
    arr[j] = tmp.substring((j - 1), j);
    if(arr[j].indexOf("8";) > -1) count++;
    }
    }
    console.log(count);

  2. ddd 2013.07.03 17:53 Address Modify/Delete Reply

    javascript 는 이정도 면 될듯한데
    var a = [];
    for (var i = 1; i < 10001; i++)
    a[i] = i;
    alert(a.join("";).replace(/[^8]/gi, "";).length);

    javascript 는 반복문 안쓸수 없나요 ㄷㄷ

    • 엄준일 2013.07.04 10:28 Address Modify/Delete

      댓글로 적어주신 소스 코드를 제 포스트에 업데이트 했습니다.
      ddd 님 사이트 링크를 남기고 싶었는데,
      링크가 없어서 아쉽네요 ㅠ

  3. HATENA 2013.07.04 11:27 Address Modify/Delete Reply

    항상 블로그 잘 보고 갑니다.
    C++은 vector, generate 안써도 쉽게 풀릴거같은데요 ㅎㅎ.

    int c=0;
    for(int i=1;i<10001;i++){
    auto s=to_string(i);
    c+=count(s.begin(),s.end();'8');}
    cout<<c;

    요거면 100byte 이내로 끝날거같습니다.
    파이선 코드길이 ㅎㄷㄷ하내요 ㄷㄷㄷ

  4. java론 2014.01.07 15:46 Address Modify/Delete Reply

    자바로는 아래처럼....
    int a=0;
    for(int i=0;i<10001;i++) {
    a+=(""+i).replaceAll("[^8]","";).length();
    }

  5. 김인혜 2014.04.06 03:56 Address Modify/Delete Reply

    마이너한 스크립트 언어입니다.
    AutoHotkey

    Loop 10000
    _ .= A_Index
    Msgbox % RegExReplace( _, "8", "", @ ) ? @ :

  6. 지나가다 2015.12.15 15:03 Address Modify/Delete Reply

    만들고 나니 위분거랑 같네요 ㅡㅡ;
    int result = 0;
    for (int i=0; i<=10001; i++) {
    result += String.valueOf(i).replaceAll("[^8]", "";).length();
    }
    return result;

  7. 행인 2016.11.20 15:28 Address Modify/Delete Reply

    Acm 문제에서 간간히 등장하는 유형이네요.
    그 당시 풀때 속도 문제 때문에 reject떠서 수학적으로
    규칙을 찾아서 accept 받았던 기억이 나네요

  8. 재밌네요 2016.11.29 16:02 Address Modify/Delete Reply

    Javascript 좀더 짧게~
    --------------------------------------
    var i,s,r; for (i = 1; i < 10001; i++) s += '' + i; r = s.split('8').length-1;
    console.log(r);

jQuery 1.7.1 버그 패치를 공유합니다.

jQuery 1.7.1 의 정식 버전은 인터넷 익스플로러(IE; Internet Explorer) 10 버전에서 런타임 버그가 존재한다. 이 버그는 jQuery 1.7.1 내부적으로, 그리고 jQuery UI 에 영향을 미친다.

그러므로 현재 jQuery 1.7.1 버전을 사용하는 버전에서는 필자가 공유한 코드를 사용하거나 패치 방법으로 코드를 수정하면 된다.


다운로드 및 추가정보






Posted by 땡초 POWERUMC

댓글을 달아 주세요

구글에서 활동한 내 모든 정보 백업 받기

최근 구글이 리더 서비스를 종료하면서 필자도 구글 리더 백업을 시작했다.

구글 리더는 OPML로 RSS 목록을 내보내려면 구글이 아닌 다른 서비스의 도움이 필요합니다만, 다음과 같은 방법으로 구글에서 활동한 자신의 모든 정보까지 백업 받을 수 있다. 구글리더, 구글 플러스, 구글 드라이브, 유튜브에 업로드한 동영상, 주소록, 리더 OPML 등 거의 모든 데이터를 다운로드 받을 수 있다.

  1. 구글 사이트에 로그인 후 ‘계정’ 클릭
      

  2. ‘내 데이터 다운로드’ 클릭
      

  3. ‘내 데이터 다운로드’ 클릭
      

  4. 테이크 아웃의 하단에 ‘보관함 만들기’ 클릭
      

  5. 구글이 내 데이터를 모으는 중…
      

  6. 준비가 되면 ‘다운로드’ 클릭
      

  7. 다운로드 된 압축 파일을 풀면 된다.
      


Posted by 땡초 POWERUMC

댓글을 달아 주세요

Javascript Array Extensions

Array Extensions는 Node.js 와 브라우저에서 사용할 수 있는 배열 라이브러리이다.

요즘 자바스크립트(JavaScript) 를 만지는 날이 많아져서 JavaScript 로 뭘 만들 수 있을까 하는 생각에 기억을 더듬어 보니 JavaScript 에서 배열을 다루는 일이 많았다. jQuery의 selector 등으로 DOM을 다루는데 효과적이지만, 배열을 다룰 때는 모라는 점이 많았다.

인터넷에 찾아보면 자바스크립트(JavaScript)로 배열을 다루는 오픈 소스를 발견하였다. 그 중 가장 호감이 가는 자바스크립트(JavaScript) 오픈 소스를 발견하였다. 자바스크립트로 C#과 가장 비슷하게 Enumerable과 LINQ를 구현한 자바스크립트다.

사실, 필자가 만들고 싶었던 디자인이 linq.js와 비슷했지만, 역시나 이미 나와있으므로 좀 더 Lightweight 하게 쓰도록 만들어 보았다. 요 몇일 3~4일 동안 틈틈히 만들었고, 더 큰 디자인으로 갈 생각은 없다.

완성도를 좀 더 높이면 npm, nuget 등에서 패키지로 배포할 예정이다.

설치하기

Nuget

PM> Install-Package JS.Array.Extensions

Node.JS

$ npm install js-array-extensions

required('js-array-extensions');

from Github

Array Extensions는 Github를 통해 배포하고 있다.

https://github.com/powerumc/array-extensions

git 를 이용하여 다음과 같이 소스 코드를 받을 수 있다. 소스 코드를 받을 디렉토리로 이동한 후 다음의 명령을 실행하면 된다.

git init  
git clone https://github.com/powerumc/array-extensions.git  

사용 방법은 매우 간단하다. README.md 에 포함한 예제 하나만 보면 쉽게 이해할 수 있을 거라 생각한다.

var arr = Array.range(1, 10)
               .select(function(i) { return { number:i, name:"POWERUMC " + i } })
               .where(function(o) { return o.number >= 5 })
               .take(3);  

// results var arr  
POWERUMC 5  
POWERUMC 6  
POWERUMC 7  

현재까지 지원하는 Array Methods 는 십여가지가 넘지만 부족한 것 같아서 좀 더 보강할 계획이다. 함께 코드를 개선하실 분은 Fork 하셔서 작업 후에 저에게 알려주시면 됩니다.

  • any
  • first
  • firstOrDefault
  • firstOrNew
  • last
  • lastOrDefault
  • lastOrNew
  • where
  • select
  • foreach
  • orderBy
  • take
  • skip
  • sum
  • average
  • range and Array.range
  • union
  • clone

image-1

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 황정현 2013.06.17 17:51 Address Modify/Delete Reply

    자바스크립트 학습용으로도 좋네요. ^^


필자는 최근 자바스크립트(Javascript)를 자주 만지게 되면서 몇 가지 팁 또는 가이드 정보를 공유하고자 한다. 자바스크립트(Javascript)를 좋아하지만 잘 하지는 못한다. 그래서 먼저 개념적으로 잘못된 부분이 있으면 정중하게 미리 양해를 구하고자 한다.

1. 익명의 즉시 실행 함수로 스크립트를 시작하자

익명(Anonymous)의 즉시 실행 함수(Immediately Invoked Function Expression)는 다음의 코드와 같이 정의된다.

(function() {
       // ... 코드 생략 ...  
}());  

익명 함수(Anonymous Function)는 자바스크립트(Javascript)가 런타임(Runtime)에 구문을 해석하여 실행한다. 이는 외부의 접근을 제한함을 의미한다. 그러므로 외부 코드에서 익명 함수의 내부 코드를 임의적이나 악의적으로 수정할 수 없다.

즉시 실행 함수(Immediately Invoked Function Expression)는 선언과 동시에 실행이 된다. 익명 함수가 런타임에 사용될 준비가 되면 즉시 함수의 초기화 코드를 실행할 수 있기 때문이다. 예를 들어, 아래와 같은 코드는 악의적으로 전역 변수의 영향을 받지 않도록 함수(Function) 을 보호할 수 있다.

만약 익명 함수에 정의된 undefined 매개 변수에 진짜 undefined 가 전달되기를 기대하는 경우가 있는데, 즉시 실행 함수(Immediately Invoked Function Expression) 중간에 undefined = true 에 의해 원하는 결과를 얻을 수 없게 된다.

var undefined = true;  

(function(undefined) {
   console.info(undefined);
   console.info(undefined === true);  
})(undefined)  

// 실행 결과  
true  
true  

만약, 외부 코드에 의해 undefined 가 완벽하게 변경되길 바라지 않는 경우 다음과 같이 undefined 가 반환되는 결과를 매개변수로 사용하여 외부 코드에 의한 원치 않는 결과의 충격에서 보호할 수 있게 된다.

var undefined = true;  

(function(undefined) {  

console.info(undefined);  
console.info(undefined === true);  

})( function() {}() );  

// 실행 결과  
undefined  
false  

2. 모듈화 패턴은 한 가지만 사용하라

Javascript 를 모듈화하기 위한 패턴은 여러 가지 방법이 있다. 그런데 여러 패턴을 섞어 사용하다 보면 코드를 보기가 더 난해해 진다. 때문에 필자는 private과 public 접근 제한 방법을 제공하는 모듈 패턴(Module Pattern)을 주로 사용한다. [1]

이 외에도 효과적인 패턴들이 많이 존재하므로 적당한 패턴을 선정하여 모두가 함께 같은 패턴으로 사용하는 것이 현명할 것 같다.

var umc = umc || (function() {

    var privateFunction1 = function() {
        // ... 생략 ...
        return true;
    };

    return {
      "version"   : "3.0.0.0",
      "name"      : "Umc.Core Frameworks",
      "getObject" : function() {
          var result = (privateFunction1() ? "POWERUMC" : "HTTP://BLOG.POWERUMC.KR");
          return result;
      }  
};
})();  

console.info( umc.version );    // 결과 : 3.0.0.0  
console.info( umc.name );      // 결과 : Umc.Core Frameworks  
console.info( umc.getObject() );    // 결과 : POWERUMC     
console.info( umc.privateFunction1() );    // 오류  

[코드1] Self-Contained 모듈화 패턴

var umc = umc || (function() {  

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   return {
      "version"   : _version,
      "name"      : _name,
      "getObject" : _getObject
   }  
})();  

[코드2] Imports 모듈화 패턴

var umc = umc || (function() {  

   var module = { };

   var _version = "3.0.0.0";
   var _name = "POWERUMC";
   var _getObject = function() { /* 코드 생략 };

   module.version = _version;
   module.name = _name;
   module.getObject = _getObject;

   return module;  
})();  

[코드3] Exports 모듈화 패턴

모듈 패턴(Module Pattern)을 정의하는 방법은 몇 가지가 있다.

  1. Self-Contained
    바로 위의 예시로 제시한 코드가 바로 Self-Contained 인데, public 함수를 직접 구현하는 방법이다.

  2. Imports-mixin
    아래와 같은 코드가 Imports 하는 방법으로 정의하는 모듈 패턴(Module) 패턴이다. 코드는 return 코드 부분만 보면 된다.

    1번과 2번의 경우는 함수가 익명(Anonymous) 함수로 정의 된다.

  3. Exports
    아래와 같은 코드는 module 을 외부로 공개하여 쉽게 확장이 가능하도록 한다.

3. 함수의 매개변수는 맨 먼저 초기화 하라

자바스크립트(Javascript)는 매우 관대하다. ‘오래 꽥꽥(Duck Typing)’은 동적 언어(Dynamic Languages)의 가장 큰 매력이라고 할 수 있다. 혹시라도 강아지가 ‘꽥꽥’ 거리면 자바스크립트는 강아지를 오리로 취급한다.

정의되지 않은 변수나 매개변수(Arguments), 아래의 코드 처럼 write("ERROR"); 와 같이 매개 변수의 개수가 맞지 않아도 너그럽게 실행이 된다. 하지만 코드에 정의되지 않은 undefined에 의해 실행은 얼마든지 오동작이 가능하므로, 가능하면 매개변수는 항상 올바르게 넘겨주지 않는다는 가정하에 작성하는 것이 좋다.

만약, message = message || "-";과 같이 초기화 또는 방어 코드가 없다면 로그는 ''Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / undefined 와 같은 결과를 보여준다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    var date = new Date();;

    console.info( date + " : " + category + " / " + message );  
};

write("INFO", "시작 메시지");  
write("WARN", "경고 메시지");  
write("ERROR");  

// 실행 결과  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : INFO / 시작 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : WARN / 경고 메시지  
Sun Jun 02 2013 13:05:38 GMT+0900 (KST) : ERROR / -  

4. 매개변수가 있지만 없어도 동작하도록 해라

함수의 매개변수는 맨 먼저 초기화 하라’ 에서 본 write("ERROR"); 와 같이 매개 변수가 맞지 않아도 잘 동작하도록 방어적인 초기화 코드를 작성하였다.

하지만, write(); 의도적으로 호출을 할 경우 다음의 코드처럼 올바르게 로그 기록이 남지 않게 된다.

write("실행 종료");  

// 실행 결과  
Sun Jun 02 2013 13:14:01 GMT+0900 (KST) : 실행 종료 / -  

category 에 로그 형식이 전달되어야 하는데, 로그 메시지 ‘실행 종료’가 category 항목으로 초기화되어 엉뚱한 결과가 나오게 된다.

이런 경우는 좀 더 매개 변수가 전달되는 가능성을 좀 더 열어두어, 매개 변수의 개수에 따라 매개 변수를 직접 할당하도록 하는 아래의 코드와 같은 방법을 사용하면 된다.

var write = function(category, message) {

    category = category || "INFO";
    message  = message  || "-";

    if( arguments.length === 1 ) {
        message = category;
        category = "INFO";
    }

    var date = new Date();;
    console.info( date + " : " + category + " / " + message );
}  

write("INFO", "실행 시작");  
write("WARN", "실행 중 경고");  
write("실행 종료");  
write();  

// 실행 결과  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 시작  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : WARN / 실행 중 경고  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / 실행 종료  
Sun Jun 02 2013 23:20:44 GMT+0900 (KST) : INFO / -  

5. 띄어쓰기 스타일(Intent Style)은 반드시 K&R Style 을 사용하자.

K&R 스타일은 전세계의 커뮤니티에 따라 다르지만, C, C++, C#, Java 등의 언어에서 사용된다고 한다. 참고로, 마이크로소프트(Microsoft)가 추천하는 띄어쓰기 스타일은 ‘Allman Style’ 이라고 부른다.

위키피디아(Wikipedia)에 따르면 K&R 스타일은 다음과 같은 유래가 있다고 한다.

The K&R style, so named because it was used in Kernighan and Ritchie’s book The C Programming Language, is commonly used in C. It is also used for C++, C#, and other curly brace programming languages.

K&R 스타일의 이름의 유래는 Kernighan씨와 Ritchie씨의 저술서 The C Programming Language의 C 코드에서 일반적으로 사용했다. 또한 C++, C#, 그리고 중괄호(curly brace)를 사용하는 프로그래밍 언어에서도 K&R 스타일을 사용한다.

자바스크립트(Javascript)는 K&R 스타일의 띄어쓰기 스타일을 사용한다.

필자는 자바스크립트에서 K&R 스타일을 추천하는 것이 아닌, 반드시 K&R 을 쓰는 것이 좋다고 믿는다. 다음의 코드를 보면 왜 K&R 스타일을 사용하는지 알 수 있다.

// K&R 띄어쓰기 스타일  
function getdata\_1() {  
return {
    name: "POWERUMC"  
};
}  

// Allman 뜨어쓰기 스타일  
function getdata\_2()
{  
return
{
    name: "POWERUMC";
}
}  

console.info("getdata_1() - " + getdata_1());  
console.info("getdata_2() - " + getdata_2());  

// 실행 결과  
getdata_1() - [object Object]     // 올바른 결과  
getdata_2() - undefined     // 올바르게 return 되지 않은 결과  

결론

이 외에도 몇 가지 더 있지만, 자바스크립트(Javascript) 내공을 좀 더 쌓은 후에 더 정확하게 쓰는 것이 낫겠다고 생각하여 5개의 팁 정도를 공유했다. 하지만, 예제로 제시한 코드에 대해 성능적인 면이나 익명 함수 또는 즉시 실행 함수 등의 메모리 누수 등에 대해서는 언급하지 않을 예정이다.

내용면으로 부족한 부분이 있겠지만, 이 정도의 팁과 가이드면 바로 현업에서 깔끔하고 잘 동작하는 자바스크립트(Javascript) 코드를 작성하기에는 전혀 문제가 없다고 생각한다.

디자인 패턴(Design Pattern) 부분에서 더 많은 정보를 얻길 원한다면, 필자의 언급한 ‘Learning JavaScript Design Patterns A book by Addy Osmani Volume 1.5.2’ 를 참고하기 바란다.


  1. Module Pattern 참고 : Learning JavaScript Design Patterns
    http://addyosmani.com/resources/essentialjsdesignpatterns/book/#modulepatternjavascript  ↩


Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 2013.06.24 11:41 Address Modify/Delete Reply

    비밀댓글입니다

  2. 2015.05.22 23:56 Address Modify/Delete Reply

    비밀댓글입니다

    • 땡초 POWERUMC 2015.06.13 21:38 신고 Address Modify/Delete

      함수 안에 매개변수를 선언하는 것이 아닙니다.
      변수에 대입(assign) 하는 것이죠 ^^
      변수는 이미 함수 매개변수에 선언이 되어있으니까요.

  3. 2015.08.07 14:27 Address Modify/Delete Reply

    비밀댓글입니다

  4. 나그네 2017.09.15 13:13 Address Modify/Delete Reply

    [코드3] Exports 모듈화 패턴 에 name 오타가 있네요. 감사합니다

불완전한 통합, 모든 것을 만족할 수 있지만, 어느 것도 만족시킬 수 없다.

팀 파운데이션 서버(Team Foundation Server)는 모든 것을 통합한 마이크로소프트(Microsoft)의 ALM(Application Lifecycle Management) 솔루션이다.

통합… 모든 것을 만족할 수 있지만, 어느 것도 만족시킬 수 없다.이 통합이라는 것은 이 시대엔 단점으로 작용될 수도 있다는 생각이 든다. 지난 2005년부터 2010년까지 ‘통합’ 이라는 것이 장점이라고 생각했었다. 모든 것을 올인원(All in One) 해 놓았다는 것만으로 주목을 끌 수 있었지만, 2013년 최근에는 이제 더 이상 ‘통합’이 장점이 될 수 없다는 결론을 내렸다.


[이미지] 통합... 현실적인 통합과 이상적인 통합


(현실적인 통합?)
출처 : 이미지 링크

(이상적인 통합?)
출처 : 이미지 링크


필자는 비주얼 스튜디오 팀 시스템(Visual Studio Team System) 2005 버전부터 팀 파운데이션 서버(Team Foundation Server)를 사용해왔다. 필드에서는 이와 관련된 다수의 기업 컨설팅과 강의를 진행하였고, 그 외 레거시 개발 환경과 소스 컨트롤(Source Control)을 커스터마이징한 소프트웨어를 납품하는 등 대략 8년을 넘게 비주얼 스튜디오(Visual Studio)와 팀 파운데이션 서버(Team Foundation Server)와 동거동락하며 지냈다. 물론, 8년을 넘게 사용하면서 좋은 점도 많지만 그렇지 않은 점도 확실히 있다.

그 동안 한 가지 ALM 솔루션만 사용할 때는 미처 몰랐던 것들이 많았지만, 여러 가지 ALM 제품을 접하면서 ALM 솔루션 간에 장/단점을 필자의 기준에 좀 더 객관적으로 판단할 수 있는 계기가 되었다.

과거 ALM은 오픈 소스 진영을 중심으로 조금씩 발전해 왔다. SVN 소스 제어 컨트롤을 중심으로 각각 독립적인 유닛(Unit)으로 배포가 되고 플러그인 등을 활용하여 조금씩 연동을 할 수 있었다. 그런 와중에 마이크로소프트(Microsoft)는 개발툴과 ALM을 통합한 ‘팀 시스템(Team System)’ 발표하였고, 그 당시 여러 오픈 소스가 가진 것들을 한 곳에 통합하여 사용할 수 있었다. 이 때까지는 ‘통합’ 이라는 것 자체가 장점이던 시대이다.

하지만, 최근 ALM은 조직의 성숙도에 맞는 전문적인 ALM 툴을 사용하는 추세이다.

아쉽게도 팀 파운데이션 서버(Team Foundation Server)는 각각의 모든 기능들이 전문성을 갖추기에는 매우 부족한 것도 사실이다. ‘이슈 관리, 빌드, 소스 제어’, 아마도 딱 떠오르는 대표적인 벤더 및 오픈 소스들이 있을 것이다. 이슈 관리(Issue Managements), 빌드(Builds), 소스 제어(Source Control) 등, 타 벤더의 전문적인 툴과 비교하면 각각의 기능은 타 벤더에 비해 열악하다.

대표적인 ALM 벤더들과 차이가 나는 것은 마이크로소프트(Microsoft)의 팀 파운데이션 서버(Team Foundation Server)는 범용성을 추구하고, 전문적인 것들은 SDK(Software Development Kit)를 사용하여 커스터마이징을 하거나, 3rd party 벤더의 몫으로 남긴다. 대인배적인 모습이긴 하지만, 현재까지도 여전히 팀 파운데이션 서버(Team Foundation Server)를 중심으로 한 생태계가 형성되지 않았다는 것 또한 단점으로 작용한다.

필자는 최근 아틀라시안(Atlassian)의 ALM 제품에 매력을 느끼고 있다. 각각의 기능들이 매우 뛰어나고, 필요하다면 언제든지 필요한 기능의 소프트웨어와 통합이 가능하다. 설치부터 통합까지 매우 간단하다. 그리고 어떤 운영체제에서도 설치와 운영이 가능한 ‘크로스 플랫폼(Cross-Platform)’ 이라는 점은 팀이나 조직에서 선택의 폭이 넓고, 또 하나, 데이터베이스, 웹 서버 등 선택의 폭도 넓다. (반면, 팀 파운데이션 서버(Team Foundation Server)는 설치는 쉽지만 구성(Configuration)이 복잡하고 운영(Operation)에 더 많은 리소스가 필요하다)

그리하여 앞으로 필자는 여러 ALM 솔루션을 벤치 마킹하면서 ALM 솔루션들 간에 장단점 등을 비교/분석하여 함께 공유할 예정이다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

객체지향 프로그래밍 이야기

IoC(Inversion of Contol)[1], 우리말로는 ‘역전제어’라고 한다. 객체지향 프로그래밍의 기본은 만들어진 객체를 잘 쓰는 것 부터 시작한다. 이 경우 개체(Object)를 인스턴스화(Instance)하기 위해 개체(Object)를 직접 참조해야 한다.

개체(Object)는 class 로 선언되는 빌딩의 명세서(설계도?)와 같고, 인스턴스(Instance)는 만들어진 빌딩(Building-건물)을 의미한다. 전자를 개체(Object)라고 부르며, 후자를 객체(Object) 또는 인스턴스라고 부른다.

명세서를 찍어내는 방법은 매우 간단하다. Building b = new Building() 이것이 객체지향에서 개체를 인스턴스화 하는 코드가 되겠다. 그런데 현실에서의 건물은 매우 다양하다. 아파트도 있고, 오피스텔도 있고, 고층빌딩도 있다. 어떤 건물은 지하 주차장이 완비되어 있고, 어떤 건물은 주차장이 옥상에 있다. 물론 없는 건물도 있다. 어떤 건물은 건물 전체가 주차장이다.

하나의 객체로 건물의 모든 기능을 담기란 힘들다. 방, 화장실, 출입문, 엘리베이터 등 각각 작은 객체들을 기능 단위로 쪼개야 나중에 다른 건물을 지을 때도 재사용성이 높아진다. 여러개로 쪼개진 기능을 한대 묶어 복합적으로 배치하면(Complex + Composition) 오피스텔이 되기도 하고, 원룸텔이 될 수 있다. 이 얼마나 아름다운 객체지향의 세계인가.

그런데 어느 엘리베이터 업체가 가장 최신의 기능을 넣기 위해 독자 표준으로 만들었다. 이 엘리베이터는 총 중량도 검사해서 작동 여부가 결정되고, 중량이 넘어서면 목적지 까지 중간에 서지도 않는 똑똑한 지성도 갖추었다. 환풍 설비도 갖추고, 향기도 나고, 내부 벽은 고급스러운 스테인레스로 쫙 깔았다.

공포 영화에나 나올 법한 허름한 구닥다리 병원의 삐그덕 거리는 엘리베이터와는 차원이 다르다. 이 병원 건물은 환상적인 저 엘리베이터 업체의 객체를 샀다. 젠장, 안맞는다. 크기도 국제 표준의 규격과 다르고, 외벽과 연결되는 환풍 설비는 꽉 끼어 찌그러질 판이다. 마치 38인치 바지를 입는 사람이 30인치 바지를 억지로 입으려는 것과 같다.

인터페이스 지향적인 프로그래밍 이야기

이 엘리베이터 업체는 최첨단 기술이 도입되는 건설사의 수주를 받아 개발한 엘리베이터인데, 건설사와 계약이 끝나니 손가락만 빨게 생겼다. 독자 표준의 엘리베이터를 국제 표준에 맞게 다시 만들었고 이제야 다시 매출이 조금씩 오르기 시작했다.

국제 표준 규격에 맞게 정해진 규약을 지켜서 만들었다. (말도 안되는 ISOxxxxElevatorOutputV1 이라는 인터페이스가 규약이라고 치자)

public interface IStarbucksElevator
{  
    ISOxxxxElevatorOutputV1 Open();  
    ISOxxxxElevatorOutputV1 Close();

    ISOxxxxElevatorOutputV1 Up();  
    ISOxxxxElevatorOutputV1 Down();
}  

세상이 변하고 살기 좋아지면서 새로운 기술도 쏟아진다. 국제 표준 기구는 엘리베이터에 범죄 예방을 위해 CCTV 규격을 V2 에 포함시켰고, V3 버전에는 어린이들도 쉽게 버튼을 누를 수 있도록 버튼의 위치와 비상벨의 위치가 매우 낮아졌다.

이 엘리베이터 업체는 모든 최신 규격을 지키기 힘들다. 기술력 확보를 위해 인재도 뽑아야 하고, 최신 표준 규격에 맞는 부품을 수입도 해야하고, 아직 모든 준비는 되지 않았지만, 국제 표쥰은 지킬 수 있다. 이렇게 말이다.

public interface IStarbucksElevator
{  
    ISOxxxxElevatorOutputV1 Open();  
    ISOxxxxElevatorOutputV3 Close();

    ISOxxxxElevatorOutputV1 Up();  
    ISOxxxxElevatorOutputV2 Down();
}  

그리고 국제 표준 인터페이스는 하위 호환을 지켜야 하므로 이렇게 생겨먹었다.

public interface ISOxxxxElevatorOutputV1
{  
    // ... 생략 ...
}  

public interface ISOxxxxElevatorOutputV2 : ISOxxxxElevatorOutputV1
{  
    // ... 생략 ...
}  

public interface ISOxxxxElevatorOutputV3 : ISOxxxxElevatorOutputV2
{  
    // ... 생략 ...
}  

국제 표준을 지키기 때문에 명확하게 인터페이싱이 가능하지만, 이 업체의 내부 구현 코드는 점점 엄망이 되어 간다. 내부적으로 지나치게 코드의 버전이 많아지고, 또 갈리게 된다.

이 업체는 표준 규격에 맞게 제작된 엘리베이터의 종류가 여럿 있다. 소형, 중형, 대형 건물마다 필요한 엘리베이터 버전들이 많다.

이제는 엘리베이터 내부 개발자들은 객체를 생성하는 것이 점점 무서워질 정도다. 가끔 헷갈리기도 하는데, 소형 엘리베이터의 코드에서 return new ISOxxxV1LargeBuildingInternalV2_5 이렇게 대형 건물용 엘리베이터 객체를 반환했다간 아작이 난다.

인터페이스 기반의 프로그래밍은 분명한 장점이 많다. 특히 인터페이스 기반으로 다른 객체를 쓸 때 편하다. 내부적인 코드의 개선이 필요하거나 인터페이스에 살짝 변화가 온다던가, 분석이 필요한 경우 인터페이스 기반으로 구현된 코드를 보면 난독증이 올 지경이다. 특히, 인터페이스나 객체들을 이용하여 다형성을 가지는 개체들은 디버깅 기능이 떨어지는 개발툴(IDE)에서는 거의 시간과 씨름하는 노가다와 같다.

국내의 엘리베이터 적용에 관한 법이 바뀌었다. CCTV 기능이 있는 국제 표준 버전 2(ISOxxxxElevatorOutputV2) 기능이 없으면 대형 건물에 엘리베이터를 설치할 수 없다. 또 구현해서 바꿔야 한다. return eturn new ISOxxxV1LargeBuildingInternalV2_5_RequiredCCTV

객체의 생성과 파괴는 간접적 컨테이너(Container)에 의해

그렇다. 객체를 직접 생성하려고 하면 강하게 응집력이 생긴다. 그래서 인터페이스를 활용하여 응집력을 낮추었다. 근데 매우 복잡한 객체지향적인 코드에서는 인터페이스 기반은 너무 힘들다. 인터페이스가 변하지 않음을 보장하고 인터페이스의 상속의 스택이 없거나 매우 짧다면 쉽지만, 스택이 깊어지면 당연히 더 어려워질 수 밖에 없다. 디버깅 경험을 떠올려 보라. 메서드 안의 메서드(Inner Method), 또 그 안에서 또 다른 메서드 호출이 깊어지면 복잡해질 수 밖에 없다.

그래서 IoC(Inversion of Control-역전 제어)는 직접 개체를 핸들링 하던 것을 간접 참조를 통해 제어 방향을 완전히 반대로 바꾸는 방법이다.

기존의 객체를 직접 핸들링 하던 방식과 인터페이스 기반의 방식을 표현하면 아래와 같이 표현할 수 있겠다.


아래의 그림은 각각의 장점과 단점을 기술한 표이다.

IoC(Inversion of Control)에 대해 필자와 같은 돌팔이가 아닌 ‘집단 지성’의 명쾌하고 깔끔한 정의는 링크를 통해 확인하기 바란다.


Umc Core IoC 통합 컨테이너의 탄생 배경

Umc Core IoC는 여러 개의 서로 다른 프레임워크의 인터페이스와 스키마, 그리고 Dependency & Injection, AOP Weaving 의 인터페이스를 모두 통합한 프레임워크이다.

오픈 소스의 시대이다. 객체를 다루는 트랜드도 바뀌어 이 전에 아티클의 내용인 다이나믹 프록시(Dynamic Proxy) 와 AOP(Aspect Oriented Programming) 등과 같은 기법들을 사용한다.


아래 현재 버전의 오픈 소스가 참조하는 IoC 컨테이너 오픈 소스는 2011년 당시와 다를 수 있음.


문제는 오픈 소스들마다 사용하는 다이나믹 프록시 오픈 소스, IoC 컨테이너 오픈 소스가 제각기 다르다는 문제에서 출발하게 된다. NHibernate, iBatis.NET(현 myBatis.NET)Castle Windsor 프레임워크의 다이나믹 프록시 및 IoC 컨테이너를 사용하고, Enterprise LibraryUnity Application Block 프레임워크를 사용한다.

만약, Enterprise Library를 기반으로 ORM 프레임워크로 NHibernate 조합으로 사용한다고 치자. 내부적으로 객체를 생성하는 곳이 두 군데가 된다. 이 객체의 생명 주기를 관리하는 곳도 두 곳이 된다. 다이나믹 프록시(Dynamic Proxy) 개체가 생성된다면 똑 같은 개체가 두 군데에서 생성하므로 괜한 메모리 공간만 차지하게 된다.

아래의 그림은 2011년 당시 수집한 자료를 기반으로 작성이 되었다.



하나의 응용 프로그램의 레이어(Layer) 안에서 두 개의 컨테이너와 프록시 객체가 생성되는 것도 문제지만, 두 개의 프레임워크가 제공하는 인터페이스도 판이하게 다르다는 것은 코딩 스타일에 문제가 된다. 당연히 응용 프로그램 차원에서는 더 큰 문제로 보아야 된다.

아래의 그림에선 두 개의 IoC 프레임워크가 전혀 다른 XML 스키마와 인터페이스를 제공하는 것을 알 수 있다.



Umc Core IoC 프레임워크의 소스 코드는 https://github.com/powerumc/UmcCore/tree/master/Src/Base%20Frameworks/Src/Core/IoC 에서 먼저 확인할 수 있다.

To be continue #2…


  1. In software engineering, inversion of control (IoC) is a programming technique, expressed here in terms of object-oriented programming, in which object coupling is bound at run time by an assembler object and is typically not known at compile time using static analysis.  ↩

    http://en.wikipedia.org/wiki/Inversion_of_control


'Umc Projects > Umc.Core' 카테고리의 다른 글

Umc Core IoC 통합 컨테이너 #1  (0) 2013.05.24
Umc.Core 프레임워크 다이나믹 프록시(Dynamic Proxy) #1  (0) 2013.05.23
Umc.Core 미공개 Preview  (6) 2008.05.14
Umc.Core 란?  (0) 2007.12.01
Posted by 땡초 POWERUMC

댓글을 달아 주세요

요즘 참 할일도 많은데 할 수 있는 일이 점점 줄어든다. 필자는 블로그 버킷 리스트(bucket list)를 작성하는데 블로그가 사망하기 전에 꼭 해야 할 일을 목록으로 만들어 놓고 하나 하나씩 글을 써 나간다. 근데 할 일이 늘어만 간다. ㅠ

  • 당장 쓸 수 있는 글 39개
    사소한 개발 기술부터 심도있는 내용으로 흐리멍텅한 개념을 글을 쓰면서 잡아 나가는 것들

  • 개발 후 산출물로 쓸 글 37개
    오픈소스로 내놓을 계획, 또는 알고 있는 것들에 대한 증명이 필요하고 그 후에 쓸 수 있는 글

  • 연구개발 11개
    배우고 싶은 것, 하고 싶은 것, 해야 하는 것들이고 공부해야 쓸 수 있는 글들

아무튼 점점 쓸 것들이 늘어만 가지만, 하나 하나 하다보면 쓸게 없어 지는 날이 올거라 믿는다 >.,<

#1 - Umc.Core 프레임워크 다이나믹 프록시(Dynamic Proxy)

다이나믹 프록시(Dynamic Proxy)는 최근 IoC(Inversion of Controls)라는 개념으로 확장되고 객체지향 프로그래밍(OOP)의 효율성을 극대화한다. 다이나믹 프록시 기법은 이미 오래 전부터 존재해 왔다.

C++의 스마트 포인터(Smart Pointer) 처럼 직접 포인터를 건들이지 않고 레퍼런스 카운팅이나 객체의 생명주기를 프록시 개체(Proxy Object)를 통해 관리하는 기법이 있고, RPC(Remote Procedure Call)과 같은 원격 프로시저 호출을 위해 프록시 패턴(Proxy Pattern)이 기반에 깔려 직접 원격 구현을 숨기고 간단한 인터페이스만 제공해 주는 패턴 등 매우 다양하다.

최근의 다이나믹 프록시(Dynamic Proxy)는 IoC(Inversion of Control), DI(Dependency Injection), ORM(Object Relation Mapping), AOP(Aspect Oriented Programming) 등 객체를 다루는 프레임워크에서 기본적으로 채용할 만큼 객체를 다룸에 있어 가장 기본적인 기법 또는 기술에 속한다.

필자가 오늘 다루어 볼 내용은 이런 프록시 패턴(Proxy Pattern)이 기반이 되는 개체 제어를 위한 기법이다.

먼저 다이나믹 프록시(Dynamic Proxy)에 대해 예전에 잠깐 쓴 글을 참고하자.

과거 2009년도 닷넷엑스퍼트 재직 시절에 다이나믹 프록시(Dynamic Proxy)를 만들었다가, 2011년 좀 더 나은 객체 디자인으로 완전히 다시 만든 다이나믹 프록시(Dynamic Proxy) 프레임워크가 지금 설명할 Umc.Core.Dynamic.Proxy 이다.

Umc Core 프레임워크는 오픈 소스로 공개되어 있으며 누구든지 소스 코드를 열람할 수 있다. 현재 소스 코드는 다음의 링크를 통해 제공된다.

그 외에 필자가 공개한 소스 코드도 여럿 있으니 관심있는 분들은 참고하기 바란다.

 

 







#2 - 코드부터 보자.

만약 관리 언어(Managed Language)의 동작 매커니즘을 이해하지 못했다면 마치 마법과도 같은 기법으로 보일 것이다. 아래의 코드는 완벽하게 돌아가는 소스 코드이다.

using System;  
using Umc.Core.Dynamic;  

namespace ConsoleApplication1
{  
public interface IPerson
{
    string Name { get; set; }
    string Email { get; set; }
}  

class Program
{
    static void Main(string[] args)
    {
        var type   = DynamicProxyObject.InterfaceImplementationType<IPerson>();
        var person = (IPerson)Activator.CreateInstance(type);

        person.Name  = "POWERUMC";
        person.Email = "powerumc at 지멜";

        Console.WriteLine("Name : {0}, Email : {1}", person.Name, person.Email);
    }
}
}  

한번 위의 코드를 보자. IPerson 인터페이스는 IPerson을 구현하는 클래스가 반드시 있어야 객체를 생성할 수 있다. 다음과 같이 말이다.

public class Person : IPerson
{
    public string Name { get; set; }
    public string Email { get; set; }
}   

C#의 상식으로 보아도 인터페이스(Interface)는 인스턴스를 생성할 수 없으며, 인스턴스를 생성하기 위해 구현 클래스가 반드시 존재햐여 하는 것 쯤은 알고 있을 것이다. 즉, Person 클래스가 있어야 IPerson person = new Person(); 으로 객체를 생성할 수 있다. 분명, 처음 코드의 DynamicProxyObject.InterfaceImplementationType<IPerson>(); 가 뭔가의 마법을 부리는 것이 확실하다고 보면 된다.

#3 - 다이나믹 프록시(Dynamic Proxy) 의 다른 구현 방법들

방금 언급한 DynamicProxyObject.InterfaceImplementationType<IPerson>(); 코드가 바로 class 로 구현조차 되지 않은 클래스를 동적(Dynamic)으로 런타임에 생성한다. 이 동적 클래스를 런타임에 생성하기 가장 쉬운 방법이 있는데, 그것은 .NET Framework에서 제공하는 CodeDomProvider 이다.

간단히 CodeDomProvider를 언급만 하고 넘어가보자. CodeDomProvider는 C#, VB.NET의 객체 표현을 Code Dom으로 표현할 수 있는데, 각각 CSharp, VB.NET Provider를 제공해 주고, 런타임에 컴파일을 한다. 다만, 컴파일 시간이 동적 객체 생성 기법 중에 가장 느리다.

그리고 C# 3.0부터 지원하는 람다 표현식(Lambda Expression)을 이용하는 방법이다. 이 람다 표현식도 내부적으로 CodeDom과 매우 유사하다. 단점이라면, 객체의 이름(Class Name)과 주소(Namespace) 등을 원하는데로 줄 수 없다. LambdaExpression 클래스의 맴버들이 많은데, 이것들로 모든 구현이 가능하다. 간단한 예제 코드를 보자.

Expression<Func<string, string>> expression = (s) => "Hello " + s;               
var func = expression.Compile();               
var ret = func("POWERUMC");   
Console.WriteLine(ret);

이 코드를 실행하면 “Hello POWERUMC” 라는 결과가 나오는 것을 확인할 수 있다.

이렇게 알게 모르게 이미 .NET Framework에서 다이나믹 프록시(Dynamic Proxy) 기법을 쓰는 곳이 의외로 많다. C# 컴파일러는 익명의 표현식들을 내부적으로 컴파일하면서 메서드로 만들어 버리기도 한다. 이렇게 똑똑한 컴파일러 덕분에 람다 표현식이나 LINQ의 성능이 매우 좋다는 것이다.

이 외에 동적메서드(DynamicMethod) 방법이 있는데, 얘는 그냥 넘어가도 무관하다.

#4 - 다이나믹 프록시(Dynamic Proxy) 개체가 생성되는 일련의 순서

동적 개체가 만들어지려면 어떤 순서가 필요할까?

먼저 객체지향 언어라는 점을 생각해볼때, 객체의 주소(Namespace)와 이름(Type Name)이 필요하다. 필자의 프레임워크 코드 중 Umc.Core.Dynamic.Proxy.Builder 네임스페이스의 ModuleBuilderExtension와 TypeBuilderExtension이 그 역할을 한다.

Type을 생성하기 위해서는 생성자 하나 이상이 반드시 필요한데, Object를 상속하는 타입을 만들어야 한다. 아시다시피 public class Person 클래스는 암묵적으로 public class Person : Object 를 상속하게 된다. 그래서 타입을 생성하고 하나의 생성자를 만들고 나면, 부모 객체인 Object의 생성자(Constructor)를 호출을 해주어야 한다. 당연히 부모가 있어야 자식이 있는 것과 같다.

이 때 반드시 주의해야 하는 것이 있다. 생성자는 인스턴스를 생성하는 생성자가 있고, static 생성자가 있다. 만약 static 생성자인 경우는 부모 객체인 Object 생성자(Constructor)를 호출하면 안된다.

Object 생성자를 타입의 생성자 안에서 호출하려면 다음과 같은 코드를 이용하면 된다.

il.Emit(OpCodes.Ldarg_0);  
l.Emit(OpCodes.Call, typeof(object).GetConstructors([0\]);  

이제 IPerson의 프로퍼티(Property)를 구현한다.

IPerson의 프로퍼티 목록은 리플랙션(Reflection)을 이용하여 쉽게 얻어낼 수 있다. 간단히 typeof(IPerson).GetProperties(); 면 된다. (프레임워크 내부에선 더 복잡할 수 있음)

C#의 프로퍼티는 컴파일을 하게 되면 프로퍼티가 메서드로 치환된다. 예를 들어, public string Name { get; set; } 코드는 다음 처럼 컴파일러가 치환한다.

public string get_Name() { ... }  
public void set_Name(string name) { ... }  

그러므로, 다이나믹 프록시를 구현할 때도 프로퍼티를 선언해 준 후에 get, set 메서드를 구현해 주어야 한다. 이를 Umc.Core에서 다음고 같이 구현하였다.

public ICodeLambda Get()
{  
var type       = new TypeBuilderExtension(null, this.TypeLambda.TypeBuilder);  
var methodAttr = this.TypeLambda.MethodAccessor.MethodAttribute | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;  
var method     = type.CreateMethod(methodAttr, propertyBuilder.PropertyType, String.Concat("get_", propertyBuilder.Name), Type.EmptyTypes, null, false);  

propertyBuilder.SetGetMethod(method);  

return new CodeLambda(this.TypeLambda, method.GetILGenerator());
}  

public ICodeLambda Set()
{  
var type = new TypeBuilderExtension(null, this.TypeLambda.TypeBuilder);  

var methodAttr = this.TypeLambda.MethodAccessor.MethodAttribute | MethodAttributes.NewSlot | MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig;  
var method     = type.CreateMethod(methodAttr, typeof(void), String.Concat("set_", propertyBuilder.Name), new Type[] { propertyBuilder.PropertyType }, null, false);  
method.DefineParameter(1, ParameterAttributes.HasDefault, "value");  

propertyBuilder.SetSetMethod(method);  

return new CodeLambda(this.TypeLambda, method.GetILGenerator());

}  

그리고 get, set 메서드의 내부 코드는 다음과 같이 구현된다.

public ITypeLambda GetSet()
{  
this.TypeLambda.FieldAccessor.FieldAttribute = FieldAttributes.Private;  
var field = this.TypeLambda.Field(this.propertyBuilder.PropertyType, String.Concat("__", propertyBuilder.Name));  

var get = this.Get();
{
    get.Return(field);
}  

var set = this.Set();
{
    set.IL.Emit(OpCodes.Ldarg_0);
    set.IL.Emit(OpCodes.Ldarg_1);
    set.IL.Emit(OpCodes.Stfld, ( (IValuable<FieldBuilder>)field ).Value);

    set.Return();
}  

return this.TypeLambda;
}  

위의 코드가 그 흔한 프로퍼티의 구현부인 public string Name { get { return this._name; } set { this._name = value; } } 를 구현하는 코드가 되겠다. 별거 아닌 코드지만 내부적으로 프로퍼티와 메서드를 생성하고, 그 구현 코드를 IL 코드로 재구현 하면 역시 조금 난이도가 높아진다.

메모리에서 개체 포인터의 엑세스를 방지하기 완료 방법

지금까지는 메모리에 동적인 코드들을 IL 코드들로 구현하였다. 모든 구현이 완료되었으면 더 이상 메모리에서 IL 코드가 위변조 되거나 .NET 코드 정책에 위배되지 않도록 엑세스 접근을 막아야 한다.

이 코드는 Umc.Core.Dynamic.Proxy.Lambda.TypeLambda 클래스의 CreateType() 메서드가 완료시킨다. 이 코드는 다음과 같이 구현 되었다.

public Type ReleaseType()
{  
if (this.TypeBuilder == null)
{
    throw new NullReferenceException(this.TypeBuilder.GetType().Name);
}  

return this.TypeBuilder.CreateType();
}   

코드 구현의 완료를 알렸다면 이제 동적 타입(Dynamic Type) 개체가 완성이 된다. 즉, 맨 처럼 IPerson 인터페이스를 구현하는 동적 개체(Dynamic Object)인 Person 개체의 타입이 되는 것이다. 즉, 이 Person 개체는 런타임에서 메모리상에 만들어진 것이 되겠다.

이리하여 Activator.CreateInstance(type) 으로 메모리상에 만들어진 Person 클래스를 생성할 수 있게 되는 것이다.

다이나믹 프록시(Dynamic Proxy) 개체의 모습

메모리상에서 만들어진 Person 개체의 타입은 내부적으로 규칙을 정해서 만들었다. Person 객체를 생성하여 이 객체의 타입을 보면 괴상한 이름으로 지어졌다.

var type   = DynamicProxyObject.InterfaceImplementationType<IPerson>();  
var person = (IPerson)Activator.CreateInstance(type);  

// 결과 -> dynamic_46c8ecaab09b41cbaa814511f69f1974

이 타입이 속한 주소(Namespace)와 모듈(Module)을 직접 디스크에 저장할 수도 있는데, 이런 방법을 이용하여 코드 난독화(Code Obfuscation) 처럼 사용할 수도 있다.

또 다이나믹 프록시(Dynamic Proxy)를 활용해 중간에 로깅(Logging)을 하거나 트랜잭션(Transaction) 처리를 할 수 있는 AOP 를 구현할 수도 있는 것이다. (AOP 구현 기법 중 하나이며, 다른 방법이 더 있다.)

또, 사용 편의성을 위해 고안된 것이 체이닝(Chaining) 방법을 이용하여 런타임 코드를 더 쉽게 만드는 방법을 Umc Core 프레임워크에서 제공한다. 다음의 코드를 보면 쉽게 이해가 될 것이다.

using System;  
using System.Linq;  
using System.Reflection;  
using Umc.Core.Dynamic.Proxy.Lambda;  

namespace ConsoleApplication1
{  
internal class Program
{
    private static void Main(string[] args)
    {
        string typeName = Guid.NewGuid().ToString("N");
        string methodName = Guid.NewGuid().ToString("N");

        var assembly = new AssemblyLambda().Assembly();
        {
            var module = assembly.Module();
            {
                var type = module.Public.Class(typeName);
                {
                    var constructor1 = type.Public.Constructor();
                    {
                        constructor1.Emit.EmitWriteLine("This is constructor");
                        constructor1.Return();
                    }

                    var constructor2 = type.Private.Static.Constructor();
                    {
                        constructor2.Emit.EmitWriteLine("This is (private static) constructor");
                        constructor2.Return();
                    }

                    var method = type.Public.Static.Method(methodName);
                    {
                        method.Emit.EmitWriteLine("This is emitted writeline");
                        method.Return();
                    }
                }

                var releaseType = type.ReleaseType();
                var obj = System.Activator.CreateInstance(releaseType);
                var releaseMethod = releaseType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);

                Console.WriteLine("Release type is {0}", releaseType.AssemblyQualifiedName);
                Console.WriteLine("Release method is {0}", releaseMethod.Name);

                releaseType.GetMethod(methodName).Invoke(null, null);

                Console.WriteLine("".PadLeft(50, '-'));

                releaseType.GetMethods().ToList().ForEach(m => Console.WriteLine("Method Name is " + m.Name));
            }
        }
    }
}
}



// 결과 ->  
This is (private static) constructor  
This is constructor  
Release type is bdfd27e5e7ed446d8702fe172733d937, 4a8f6dd24e1f4054b551cca95ad0870b, Version=0.0.0.0, Culture=neutral,  PublicKeyToken=null  
Release method is 389b4a43a1ba4dc1b1391b5b06633645  
This is emitted writeline  
Method Name is 389b4a43a1ba4dc1b1391b5b06633645  
Method Name is ToString  
Method Name is Equals  
Method Name is GetHashCode  
Method Name is GetType  

위의 코드와 같이 좀 더 직관적으로 동적 코드를 만드는 방법을 Umc Core에서는 제공해 주고 있다.

재미있는 것은 메서드의 이름이다. 결과 출력 중 Method Name is 389b4a43a1ba4dc1b1391b5b06633645 이 있는데, 놀랍게도 메서드의 이름이 숫자로 시작한다. C# 언어 사양 중 변수의 타입, 변수 등의 이름은 반드시 알파벳 문자로 시작해야 함에도 불구하고, 숫자로 시작하다니…

이는 C#의 언어 사양과 CIL(Common Intermediate Language) 언어의 사양이 다르기 때문이다. 심지어 숫자가 아닌 특수문자로 시작해도 된다. 앞서 말했다시피 이런 방법을 이용하여 코드 난독화(Code Obfuscation) 가 가능하다.

비록 대부분의 Umc Core 소스 코드를 공개하지 않았지만, 미공개 코드 중 코드 난독화 툴도 함께 포함이 되어있고, Junk Assembly를 만드는 툴, AOP based Compile 툴 등도 포함이 되어있다. ㅎㅎㅎ; 아쉽지만 여전히 미공개 분은 공개하지 않을 예정이다. 더불어, 관심있는 독자라면 CIL 언어 스팩의 사양을 살펴보는 것도 좋을 것이다.

결론

지금까지 살펴본 다이나믹 프록시(Dynamic Proxy)를 살펴보았다. 이 기법은 IoC, DI, AOP, ORM 등 최신 객체 제어 기술들의 가장 근간이 되는 기법이다. 여러분들이 최신 기술들로 IoC, DI, AOP 등을 구현하고 싶다면 당장 오픈소스를 이용하면 될 것이다.

아마 필자처럼 .NET 기반으로 다이나믹 프록시(Dynamic Proxy)를 직접 구현해서 쓰는 것은 매우 드문 일이다. 이미 검증된 오픈 소스들도 많기 때문에 굳이 이를 구현해서 쓸 필요는 없다.

하지만 이런 오픈 소스를 이용하여 쓰는 것은 그리 어렵지 않겠지만, 이런 오픈 소스를 이용하여 어떻게 코드를 만드느냐는 성능이나 내부적으로 동작하는 효율성에 영향을 미칠 수 있다. 즉, 자신이 오픈 소스를 이용하여 만든 코드가 효율적인 코드, 그리고 메모리상에서 Clean Code로 동작하느냐는 별개의 문제이다.

필자와 같이 다이나믹 프록시(Dynamic Proxy)를 구현해 보았다면 여러분들이 얼마나 위험한 코드를 많이 만드는지 알 수 있다. 즉, 오픈 소스를 써보기만 했다면 절대로 알 수 없는 고급 기술이다.

ASP.NET MVC 등과 같은 프레임워크에 IoC 등이 통합되면서 내부적으로 이와 유사한 방법을 쓴다. 특히 웹 개발에 있어 IoC와 같은 프레임워크는 굉장히 위험할 수 있다. 설명하자면 지금까지 쓴 내용보다 더 복잡하고 많은 내용으로 설명이 필요할지도 모른다.

만약 관리 언어(Managed Language) 등으로 만들어진(자바도 구현 기법이 유사함) 응용 프로그램의 고성능 튜닝, 트러블 슈팅, .NET 플랫폼에 관심이 많은 독자라면 반드시 이해하고 넘어가야 할 내용들이다. 그리고 오픈 소스를 이용하여 다이나믹 프록시(Dynamic Proxy)를 간접적으로 사용만 한다면 가볍게 읽고 넘어가도 좋다. 소소한 개발 일상의 이야깃 거리도 될 것이다.


필자는 이 외에도 다이나믹 프록시(Dynamic Proxy)를 바탕으로 이를 IoC와 통합하고 AOP, ORM 등을 구현하는 방법도 알아볼 것이다. Umc Core는 오픈 소스로 공개되어 있으며 위키 페이지를 만들겸 하나씩 정리하고자 한다. 

'Umc Projects > Umc.Core' 카테고리의 다른 글

Umc Core IoC 통합 컨테이너 #1  (0) 2013.05.24
Umc.Core 프레임워크 다이나믹 프록시(Dynamic Proxy) #1  (0) 2013.05.23
Umc.Core 미공개 Preview  (6) 2008.05.14
Umc.Core 란?  (0) 2007.12.01
Posted by 땡초 POWERUMC

댓글을 달아 주세요

필자는 일전에 이와 관련되어 상당한 분량의 포스팅을 올린 적이 있다. 총 5회의 아티클 중 마지막 회를 모두 작성하지는 못했지만, 지금 이 내용이 그 마지막 회의 내용과 어느 정도의 내용과 유사하다고 보면 된다.


그 중, 4회 아티클 ‘[실전 ASP.NET Session [4] - 세션상태 마이그레이션]5’의 내용은 본 아티클의 내용에서 매우 중요한 기초 내용이 된다. 이 글을 읽고 있는 독자 중 잘 이해가 되지 않는다면 필자가 이전에 작성한 포스팅을 반드시 읽어보기를 바란다.

그리고 위의 필자가 작성한 링크의 아티클은 5년전에 작성된 글임을 인지해 주길 바란다. 그 때는 필자가 지금보다도 더 실력이 형편 없었을 뿐더러 현재 추구하는 웹 개발의 트랜드와 상이한 면이 있을 수도 있을 것이다. .NET Framework 버전과 개발툴의 버전도 지금 사용하는 버전과는 한참 예전 버전이었다. 하지만 5년이 지난 글임에도 기초적인 내용은 모두 탄탄하게 짚고 넘어가므로 한번씩 보는 것도 나쁘지 않다.

ASP.NET이 지원하는 분산 세션 상태(Session State)

일반적으로 1대 1의 물리적인 관계는 분명 분산환경이긴 하지만 분산 환경이라고 말하지 않는다. 어떤 물리적인 환경에 배치하든, 통계학의 분산에 대한 기대값이나 편차의 해는 변하지 않기 때문이다.

분산 환경에서 더 나은 성능을 내기 위한 알고리즘과 휘발성인 메모리 안에서 데이터가 유실되지 않도록 원자성(Atomicity)을 유지할 수 있는 방법을 제공해야 한다. 또 웹 서버의 세션이라는 특징은 매우 빈번하게 엑세스 되고, 업데이트와 삭제 작업도 매우 많이 발생한다.

하지만, 안타깝게도 memcached[1]는 ‘get’ 명령의 원자성(Atomicity)를 보장하지 않는다고 한다.

A series of commands is not atomic. If you issue a 'get' against an item, operate on the data, then wish to 'set' it back into memcached, you are not guaranteed to be the only process working on that value. In parallel, you could end up overwriting a value set by something else.


하지만 괜찮다. 웹 서버의 세션은 동시다발적인 병렬 작업으로 요청이 들어올 수 없는 구조이다. 웹 서버로 사용자의 요청이 들어올 때, 사용자의 웹 브라우저에 가진 쿠키 값이 신원보증을 하는 값, 또는 해시된 세션의 키 값이다. 그러므로 한 세션에 대해 동시에 여러 클라이언트(사용자 웹 브라우저)의 요청은 있을 수 없는 일이다.

하지만 불가능한 것도 아니다. 예전에는 자바스크립트가 허용되는 게시판이나 이와 유사한 환경에서 악성 스크립트를 심어 놓으면, 그 글을 보는 누군가는 브라우저의 쿠키 값을 취득하여 해커에게 보내고, 해커는 세션이 만료되는 20분(일반적인 세션 만료 시간) 전에 취득한 세션 값으로 재 요청을 하게 되면 다시 세션이 연장되고, 세션이 로그인된 상태인 경우 해커도 로그인된 상태로 입장하는 것이 가능하다

때문에 완전히 같은 해시된 세션의 키 값으로 여러 클라이언트(사용자의 웹 브라우저)의 요청이 온다는 것은 사용자의 세션 값이 털려서, 누군가 악용하고 있다고 보는 것이 맞다.

그러므로 아주 정상적이고 일반적인 환경에서 원자성을 제공하지 않는 ‘get’ 명령은 전혀 문제가 되지 않으며, 오히려 원자성을 보장할 수 없는 문제로 더 좋은 Read 성능을 낼 수 있기 때문에, memcached 가 세션 서버로 사용하기에 redis[2] 보다 더 좋을 수 있다.

ASP.NET이 제공하는 세션 관리 요약

아무런 설정이 없다면 In-Proc, 즉 로컬 머신의 메모리를 사용하게 된다. 만약 불행히도, Win32 DLL을 참조하는 웹 응용 프로그램이라면 웹 서버의 메모리의 크기 따윈 무시하고 최대 2GB 밖에 사용할 수 없게 된다.

이를 극복하는 방법으로 윈도우 서비스로 백그라운드로 실행되는 ASP.NET Session State Service 서비스를 사용하면 좋다. 여러 웹 응용 프로그램이 하나의 Session State Service에 연결되더라도 웹 응용 프로그램마다 고유의 Identity Key(Guid)가 할당되고, 이를 Primary Key로 구분하게 된다. 이 NT Services가 다운되거나 재시작하지 않는 이상 웹 서버의 세션은 항상 유지할 수 있다.

긴급한 패치로 웹 응용 프로그램을 업데이트 해야 하는 경우, IIS가 재시작 되는 경우가 발생할 수 있는데 이 때 Worker Process에 의해 구동되는 In-Proc 세션 정보는 모두 초기화된다. 웹사이트에서 뭔가를 구매하려는 사용자가 있었다면 큰 사고로 이어질 수 있지만, Session State Service에 세션 정보가 저장이 되므로 IIS 재시작 후에도 웹 응용 프로그램은 세션 정보를 모두 안전하게 유지할 수 있다.

보통 웹 서버와 Session State Service간에 통신을 하기 위해 방화벽의 특정 포트를 개방해야 하고, 내부적으로 서로 간에 소켓 통신에 사용되는 전용 프로토콜이 존재하므로 Session State Service를 확장하기란 쉽지 않을 것이다.

이런 경우, ASP.NET에서 MS SQL Server를 이용하여 세션 정보를 저장하는 방법을 제공해 준다. 세션 정보에 추가하고 싶은 정보나 DB상에 기록되어질 특정 필드를 추가하여 사용할 수 있고, Oracle 또는 MySQL을 사용하여 세션 상태를 저장할 수도 있다.

위의 링크 중 ‘[실전 ASP.NET Session [4] - 세션상태 마이그레이션]13’에 예제로 구현된 Oracle Session Store Provider 예제가 있으니 참고하길 바란다.

memcached를 이용하는 세션 저장소

memcached를 세션 저장소로 이용하는 것은 ASP.NET Session State Services의 역할과 구현만 다를 뿐이지 매우 유사하다. memcached도 메모리를 저장소로 이용하여 빠르게 캐시하고 요청에 빠르게 응답할 수 있는 간결한 구조로 구현된 오픈소스이다.

특히 memcached를 이용할 경우 ASP.NET Session State Services로 불가능한 클러스트링이 가능하기 때문에 수평적으로 세션 서버를 확장할 수 있다. 한 대의 세션 서버만 있는 경우보다 로드벨런싱의 자유도가 더 높고, 세션 서버의 장애에도 대처가 가능하다. 또 하나의 장점이라면 저가형 장비를 병렬로 구성이 가능하기 때문에 세션 서버를 구성하기 위한 금전적이거나 물리적인 많은 제약이 사라지게 된다.

memcached와 redis, 두 가지 오픈소스를 고려하고 있었는데, 세션 서버에 memcached가 더 적합하다고 생각하여 memcached만 다룬다. memcached의 소스 코드가 더 가볍고 취향이나 요구사항에 따라 코드를 변형하기에 더 적합하지 않을까 생각한다. 그리고 자칫 복잡해질 수 있는 구조적인 아키텍처를 좀 더 간결한 memcached로 표현하는 것이 글을 보는 입장이나 쓰는 입장에서 편하다고 믿는다.

memcached는 C언어로 구현이 되어있고, GNU C 표준 라이브러리를 사용하므로 여러 운영체제에서 사용이 가능하다. (ASP.NET Session State Services는 윈도우 환경에서만 사용이 가능하다) 물론 필자는 맥킨토시, 리눅스, 윈도우에서 memcached를 컴파일, 구동이 잘 됨을 확인하였다.

간단하게 사용자의 세션 정보를 저장할 클래스를 하나 간단하게 만들었다. 외부에서는 오직 참조만 하여 사용할 수 있도록 internal 생성 메서드를 하나 가지고 있다.


다음은 ASP.NET MVC 프로젝트로 만든 간단한 예제이다.

web.config
1
2
3
4
5
6
<sessionState mode="Custom" customProvider="MemcachedSessionStateStore">
    <providers>
        <add name="MemcachedSessionStateStore"
             type="Umc.Core.Web.SessionState.Memcached.MemcachedSessionStateStore, Web.SessionState.Memcached, Version=1.0.0.0, PublicKeyToken=eed8f2bc3bfc4c7a, Culture=neutral"/>
    </providers>
</sessionState>

  

HomeController.cs
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
public class HomeController : Controller   
{
   private static readonly string KEY_OF_USER_SESSION = "__USER_SESSION_KEY__";
   public UserIdentity SessionStore
    {
        get { return (Session[KEY_OF_USER_SESSION] as UserIdentity) ?? UserIdentity.Empty; }
        set { Session[KEY_OF_USER_SESSION] = value; }
    }
 
 
    public ActionResult Index()
    {
        Session[KEY_OF_USER_SESSION] = UserIdentity.New("POWERUMC"
                                                        , "Junil, Um"
                                                        , "powerumc at gmail.com");
 
 
         /*
          // 맴버쉽 사용자 인증 설정 생략...
        var ticket = new FormsAuthenticationTicket(...);
        var user = new GenericPrincipal(new FormsIdentity(ticket), ... )
         * */
 
 
        return View();
    }
}

 

위와 같이 클라이언트의 세션 키를 이용하여 memcached의 서버에 세션 키를 이용하여 세션 값을 저장한다.

telnet 'get' 명령 결과
MPOWERUMC:~ powerumc$ telnet 192.168.0.23 11211
Trying 192.168.0.23...
Connected to 192.168.0.23.
Escape character is '^]'.
get laaymm13uyu03bofhdydi4iq
VALUE laaymm13uyu03bofhdydi4iq 0 477
AAEAAAD/////AQAAAAAAAAAMAgAAAF1XZWIuU2Vzc2lvblN0YXRlLk1lbWNhY2hlZCwgVmVyc2lvbj0xLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWVlZDhmMmJjM2JmYzRjN2EFAQAAAEpVbWMuQ29yZS5XZWIuU2Vzc2lvblN0YXRlLk1lbWNhY2hlZC5NZW1jYWNoZWRTZXNzaW9uU3RhdGVTdG9yZStTZXNzaW9uRGF0YQQAAAATPElkPmtfX0JhY2tpbmdGaWVsZBg8TG9ja0FnZT5rX19CYWNraW5nRmllbGQYPEV4ZmlyZXM+a19fQmFja2luZ0ZpZWxkFzxMb2NrSWQ+a19fQmFja2luZ0ZpZWxkAQAAAgwNAgAAAAYDAAAAGGxhYXltbTEzdXl1MDNib2ZoZHlkaTRpcQC8oGUBAAAAAPAWAzAi0IgJAwAAAAs=
END

 

 

ASP.NET의 세션이 실제로 저장이 되었는지 확인해보자. telnet을 통해 memcached 포로토콜의 명령을 입력하여 확인하면 된다.

현재 브라우저에서 연 세션 값은 쿠기에 저장이 되어 있다. 쿠키에 저장된 세션의 키 값은 ‘laaymm13uyu03bofhdydi4iq’ 이다.


telnet에 접속하여 memcached에 저장된 세션 키의 값을 조회된다.

memcached 세션 저장소로써 활용

memcached 오픈 소스 솔루션을 이용하여 메모리 캐시를 이용하여 ASP.NET 세션 상태를 저장할 수 있도록 구성해 보았다. 이제 얼마나 좋은 성능을 낼 수 있는지 측정이 필요한데 본 아티클에서는 memcached를 세션 서버로 활용할 때에 대한 성능의 문제는 다음에 기회가 되면 더 심도있게 다루어 보도록 하겠다.

그리고 ASP.NET 뿐만 아니라, JSP 또는 Servlet, 그 외에 여러 웹 개발 프레임워크에서 쉽게 사용할 수 있다. memcached는 C#, Java, Python 등 여러가지 언어로 memcached서버에 연결할 수 있는 클라이언트 라이브러리를 어렵지 않게 찾을 수 있다.

이번 아티클에서는 MemcachedSessionStoreProvider 소스 코드를 제공하지 않았다. 물론, 필자의 위 코드를 실행하기 위해 MemcachedSessionStoreProvider 소스 코드가 있어야 한다. 이 코드는 다음 아티클에서 조금씩 작성해 나갈 예정이다.

memcached 에 대한 자세한 내용은 아래 링크의 구글 코드에 들어가면 컴파일 및 실행 방법과 유지관리 방법에 대한 위키가 있다.

memcached wiki, https://code.google.com/p/memcached/wiki/NewStart



[1]: C언어로 구현된 고성능 분산 메모리 객체를 캐시하는 서버. Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

[2]: 키/값을 저장할 수 있는 분산 서버로 데이터의 구조체 뿐만 아니라 문자열, lists, 빠른 검색을 위한 hashes 등을 지원. Redis is an open source, BSD licensed, advanced key-value store. It is often referred to as a data structure server since keys can contain stringshasheslistssets and sorted sets.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

TV 프로에서 어떤 조사를 통해 재미있는 사실이 밝혀졌습니다.

페이스북 오래 하는 직원, 업무성과 더 높아

회사에서 페이스북... 대놓고 하기에도 그렇고, 숨어서 하기에도 그렇고...



맥에서 즐겨 사용하는 페이스북 알리미 프로그램이 Shareware로 자꾸 돈내라고 팝업이 뜬다.
$2.99 짜리 맥OS 앱인데, 결제를 하려다가 주말을 이용해 그냥 만들어 보기로 했습니다.

 

아직 초라한 0.1 버전이므로 감안하고 사용하길 바랄뿐입니다. ^^;
차후 업그레이드를 해야 하는 사명감이 좀 더 생기면 버전업을 할 예정입니다.

(Mac OS, Linux 배포 패키지가 완성되면 다운로드 링크에 추가하겠슴돠)


 

 

  Facebook Tray v0.1 

 

다운로드 링크 (SkyDrive)

https://skydrive.live.com/redir?resid=8B8DDD0D9FFC25E1!5800&authkey=!APgYk8Dtt5YV3r4

 

스크린 샷

 

 

지원 운영체제

  • Windows
  • Mac OS
  • Linux

 

특징

  • 트레이 아이콘에서 페이스북의 새로운 알람 개수 표시
  • 네트워크를 통한 페이스북 API 없이 실시간 알람
  • 모바일 화면의 페이스북 윈도우 제공
  • 외부 링크는 데스크탑 브라우저와 연결
  • 내부 링크는 FacebookTray 내부 브라우저와 연결
  • 여러 운영체제 지원


실행 방법

  • 윈도우
    기본 설치 경로인 윈도우 데스크탑에 FacebookTray 폴더의 FacebookTray.exe 를 실행
  • 맥 OS
    기본 설치 경로인 /Applications (응용프로그램)에서 FacebookTray.app 을 실행
  • 리눅스


설치되는 컴포넌트

  • 실행 파일
  • Qt Runtime (Qt Core/OpenGL/WebKit)
  • C++ 10.0 재배포(Redistributable) 패키지 (설치 안됨)
  • OpenSSL (설치 안됨)


Posted by 땡초 POWERUMC

댓글을 달아 주세요

발생 배경

Qt를 가장 잘 개발할 수 있는 개발 도구 Qt 개발 플랫폼인 Qt 5.0(Qt 5.0 / Qt Creator 2.6.2) 에서 QWebView 위젯을 제대로 link 및 include 할 수 없는 현상이 발생한다. 이전 환경에서는 물론 발생하지 않는, 이전 release에 보고된 버그이다. 

오류 유형은 일치하지 않으나 발생하는 환경은 유사하다고 볼 수 있다. widgets 모듈에 포함되었던 QWebView가 다른 모듈로 분리가 되었기 때문이다. 

:-1: error: symbol(s) not found for architecture x86_64

 

 

해결 방법

해결 방법은 의외로 간단하다. .pro 파일(qmake) 의 속성을 다음과 같이 추가한다.

QT      +=core gui webkitwidgets 


QT 속성은 qmake가 빌드할 때 사용하는 모듈을 지정하는 속성인데, link 또는 dll 개념과 유사하다고 보면 된다. 

그렇다면 정상적으로 다시 컴파일이 가능하고, Code Completion도 정상적으로 동작할 것이다. 아래는 간단한 샘플 소스 코드를 첨부한다.

.pro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#-------------------------------------------------
#
# Project created by QtCreator 2013-03-11T20:44:09
#
#-------------------------------------------------
QT       += core gui webkitwidgets
 
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 
TARGET = FacebookNotify
 
TEMPLATE = app
 
SOURCES += main.cpp\
        mainwindow.cpp
 
HEADERS  += mainwindow.h
FORMS    += mainwindow.ui
MainWindow.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QWebView>
  
MainWindow::MainWindow(QWidget*parent): QMainWindow(parent), ui(newUi::MainWindow)
{
    ui->setupUi(this);
  
    this->onLoad();
}
  
MainWindow::~MainWindow()
{
    delete ui;
}
  
voidMainWindow::onLoad()
{
    ui->webView->load(QUrl("http://blog.powerumc.kr"));
}

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 2013.03.24 21:56 Address Modify/Delete Reply

    비밀댓글입니다

  2. knocki 2013.06.14 17:03 Address Modify/Delete Reply

    Qr Creator 2.7.0(32 bit) / Qt 5.0.2 / Windows 7 환경에서는 pro파일에 위의 옵션을 넣어주지 않아도 되네요.

    그런데 프로젝트를 생성할 때 "Qt Gui Application"으로 하면 안 되고 "HTML5 Application"으로 해야만 QWebView를 정상적으로 include하여서 실행이 되네요.

    혹시 두 프로젝트간의 차이점에 대해 아시나요?
    그리고 Qt Gui Application에서는 QWebView를 사용할 수 없을까요?

부하테스트 이야기, 테스트 데이터 분석 문제 풀어보세요.

부하테스트 이야기

부하 테스트는 테스트 분류 상 '비기능 테스트'에 속하는 매우 정교한 테스트 중의 하나다. 부하 테스트는 수치화된 데이터를 통해 성능 지표를 도출한다. 대부분 부하 테스트는 클라이언트 응용 프로그램보다 서버 응용 프로그램에 주로 사용한다. 웹 서버나 통신과 관련된 서버, 그리고 데이터베이스가 대표적이다.

일반적으로 테스트라고 하면 '성공/실패'가 매우 명확하다. 그리고 '성공/실패'라는 결과에 대해 객관적으로 판단할 수 있고, 특별한 경우가 아니고서 '성공/실패'를 재연할 수 있는 시나리오를 가지고 있다.

반면 부하 테스트는 '성공/실패'는 경험적으로 판단해야 하며, 성공인지 실패인지에 대해 다른 사람과 의견이 일치하지 않는 경우가 대부분이다. 그래서 경험적으로 성공과 실패의 기준점을 정하곤 한다. 하지만 매번 성공/실패가 같은 결과를 내지 않으며, 환경적인 요건에 따라 얼마든지 결과가 뒤바뀔 수 있다. 실패한 테스트를 다시 수행 했을 때, 재연할 수도, 못할 수도 있는 있다. 결과적으로 테스트 대상의 환경적인 요건과 더불어 누가, 어떻게 테스트를 수행하였는지도 테스트 결과에 반영이 될 수 있다.

필자는 4년이 넘도록 현장에서 수많은 부하 테스트를 수행해왔다. 매우 재미있는 것은 어떤 서버 응용 프로그램도 성능 요건을 통과한 적이 단 한번도 없었다. 수 년 동안 문제 없이 잘 써왔다는 서버 응용 프로그램도 부하테스트를 통해 문제를 발견하고 더 나은 성능을 낼 수 있도록 개선된 사례들도 매우 많다.

숨겨진 많은 버그나 이슈들이 부하 테스트를 통해 여실히 드러난 것이다. 그로 인해 이전에 다니던 N모 게임사의 인프라는 부하테 스트로 성능 요건을 반드시 통과해야 라이브로 서비스할 수 있는 엄격한 규칙도 생겼다. 물론, 이 때에는 필자가 전담하여 테스트를 수행했었을 때였다.

부하 테스트라는 주제 하나 만으로도 책 한 권 정도의 분량이 넘을 것 같다. 그 만큼 현장에서 부하 테스트에 대한 오해도 많았으며, 개발자와 실무진 간의 성공/실패에 대한 이해관계, 테스트 데이터 분석, 또 이를 보고서화 및 시각화 하는 과정의 자동화 등 많은 재미있는 경험이다.

왜 부하 테스트가 중요할까? 그 이유는 아무것도 눈에 보이지 않기 때문이다. 문제가 있어도 금전적/물질적으로 어떠한 손해를 입었는지 조차 알 수 없다. 테스트를 통해 문제를 발견하지 않는 이상 아무런 문제가 되지 않는다. 그러므로 '비기능 테스트'인 부하 테스트 자체의 필요성 조차 느끼지 못할 것이라 생각한다. 하지만 전문적인 '비기능 테스트' 활동을 시작함과 동시에 많은 문제들을 발견할 수 있을 것이다.

재미로 풀어보는 부하테스트 분석 문제

부하 테스트는 테스트 활동 자체에 큰 의미를 부여할 수 있지만, 부하 테스트 데이터를 분석하는 것도 테스트를 수행하는 것 만큼이나 중요하다. 아니, 이 분석 과정이 더 중요한 경우도 많았다.

이 데이터들은 테스트 툴이 보여주는 성능 지표 뿐만 아니라, 디스크 IO와 네트워크 대역폭과 같은 하드웨어적인 측면과 쓰레드(Thread), 프로세스(Process) 등과 같은 운영체제와 소프트웨어적인 측면 모든 것을 분석해야 한다. 놓칠 수 있는 많은 데이터들이 문제나 이슈의 원인과 직결되는 경우도 있기 때문이다.

가령, 데이터베이스 서버의 병목의 원인을 규명하고자 할 때 대부분 많은 트랜잭션과 락(Lock)이 걸리는 이유일 것이다. 하지만 간혹 디스크 IO가 권장하는 임계치를 벗어난다면 병목의 원인을 구진 디스크로 밝혀질 수도 있기 때문이다.

필자가 재미있는 문제 하나 준비했다!

아래의 그림은 .NET WCF(Windows Communication Foundation)의 부하 테스트 결과이다. 딱 보고 '무엇이 문제인지' 원인을 안다면 당신은 충분히 멋진 개발자이다. 하지만 뚫어져라 쳐다봐도 문제점이 보이지 않는다면 기본기가 부족한 개발자인 스스로를 자책하기 바란다.

이 테스트 결과의 분석 결과는 무엇이 문제인지는 다음 아티클을 기대하기 바란다.

  • Smoke 테스트 결과

  • Stress 테스트 결과

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. shunman 2013.04.03 13:29 Address Modify/Delete Reply

    결과가 어떻게 나오는지 궁금하네요. 어서 다음 아티클 부탁드립니다 ㅋ

최신 우분투(Ubuntu) 12.10 64비트 버전을 제 노트북에 설치하였다. 노트북의 해상도는 1600*900로 세로 길어가 짧은 전형적인 와이드형 LCD 모니터이다. 이전 우분투 12.04 LTS에서는 없었던 문제였는데, 이번에는 설치 중 설치 창이 화면을 넘어서서 창이 잘리는 현상이 발생하였다.

   

화면 잘림 현상은 파티션 나누는 단계에서 고급 설정을 선택했을 때 발생한다.

아래의 이미지는 창이 길어져서 항목을 선택하거나 '계속' 버튼을 누를 수 없게 된다. 설치 중 창의 크기를 줄일 수 없기 때문에 이 문제로 조금 난감했다.

이런 현상이 발생하는 경우 창의 타이틀 부분(위쪽)을 ''Alt+마우스 좌 클릭+마우스 이동 ' 하면 두 번째 이미지 처럼 잘린 창 밑 부분을 스크롤 할 수 있다.

[이미지1] 창이 잘린 이미지

   

[이미지2] 창이 잘려 창을 ' Alt+마우스 좌 클릭+마우스 이동 ' 한 이미지

Posted by 땡초 POWERUMC

댓글을 달아 주세요

개요

SpringSource Tool Suite for Eclipse Juno(이하 STS) 를 Eclipse Marketplace 를 통해 설치를 하고자 할 때, Dependencies 체크 후에 아래와 같은 메시지와 함께 설치가 되지 않는다.

Cannot complete the install because one or more required items could not be found. Software being installed: Spring IDE Security Extension (optional) 3.1.0.201210040510-RELEASE
...
...
이하 생략    

이 문제는 인터넷을 통해 필자와 같은 문제의 Thread를 찾을 수 있었다.

  • Thread: cannot install Spring Tool Suite (STS) for Eclipse Juno (3.8 + 4.2) 3.1.0.RELEASE     필자와 같은 문제가 발생하는 경우 위 링크의 답변처럼 GEF(Graphical Editing Framework) 를 설치/업데이트 하면 된다고 한다. 아래의 원문의 링크를 이클립스에서 Help -> Install New Software를 이용하여 설치/업데이트를 할 수 있다. 뭐가 뭔지 잘 모르겠다면 Releases 의 링크를 통해 업데이트하면 된다.

GEF Update-Sites
Using the Eclipse Update Manager (see Eclipse Help for detailed instructions) GEF can be installed from the following update sites:

GEF(Graphical Editing Framework)의 정보는 IBM 사이트에서 찾을 수 있다. 모델링이나 이미지/그래픽 기반으로 Editing 할 수 있는 오픈 소스 프레임워크이다. STS에서 GEF를 이용한 기능적인 향상이나 종속적인 바이너리 등이 변경이 된 듯 싶다.


[이미지 1] GEF Extension 예시 / 이미지 출처 - http://www.eclipse.org/gef/


[이미지 2] Visual Studio DGML / 이미지 출처 - http://msdn.microsoft.com/en-us/library/vstudio/jj739835.aspx  

마치 Visual Studio 의 DGML(Directed Graph Markup Language)과 비슷하게 보인다. 하지만, Eclipse에서의 GEF와 Visual Studio에서의 DGML의 가장 큰 차이점이라고 하면 DGML은 정의된 스키마(Defined Schema)이고, GEF는 확장 가능한 프레임워크라는 점이다. 그 점에서 Eclipse의 GEF에 더 좋은 점수를 주고 싶다..    

GEF와 DGML의 자세한 내용은 아래의 링크를 참고하기 바란다.

Eclipse에서 GEF를 설치/업데이트가 성공하였다면 다시 Eclipse Marketplace에서 STS을 설치한다. 그럼 아래와 같이 못 보던 추가 구성 요소들이 더 많아진다. 그리고 계속 진행하면 설치가 성공할 것이다.    

Posted by 땡초 POWERUMC

댓글을 달아 주세요

개요

Java 8 버전에서 Lambda 표현을 지원한다. 아직 Java 8은 Beta 버전이다. 여러 언어 중에서 Lambda 표현을 지원하지 않는 언어로 손꼽힌다. Wikipedia에서 Anonymous Function을 참고해보면 Java 언어가 언어의 표현력에 있어서 추세를 따라가지 못하는 것이 아닐까 생각한다.

반면,

  • C#은 2007년도에 C# 3.0 버전에 LINQ 라는 대주제를 중심으로 Lambda, Anonymous Class, Extension Methods를 내놓았고,
  • C# 4.0은 2010년도에 Dynamic이라는 대주제를 중심으로 동적 프로그래밍이 가능해졌다.
  • C# 5.0은 2012년도에 비동기 라는 대주제를 중심으로 비동기 프로그래밍을 언어적으로 지원한다.

Wikipedia에서 C# 역사에 대해 더 자세히 알고 싶은 분은 'C# (programming language)' 를 참고하면 좋겠다.

Java를 이용하여 프로그래밍을 하려고 하면 정말 C#이 많이 생각난다. C#에서 한 줄짜리 문장을 Java에서는 십여 줄 넘는 경우가 많기 때문이다. 굳이 예를 들자면, 우리나라에서 유행하는 줄임말 '엄친아'를 풀어서 '엄마 친구의 아들' 로만 말해야 하는 것과 같은 느낌이랄까… 어쨌든 Java는 Java만의 매력이 있는 법. 그 매력을 찾아보는 것도 재미있겠다.

각설하고, 먼저 Java 8을 사용하여 개발할 수 있는 환경부터 간단히 살펴보자.

현재 Java 8 버전은 베타 버전이다. 현재 Java 8은 Sun사의 JDK를 칭한다. 그러므로 Oracle 사이트에서 Java 8 버전을 다운로드 받을 수 없다.

그리고 Project Lambda를 지원하는 개발 툴을 사용해야 한다. 다음의 링크의 NetBeans와 IntelliJ IDEA 12 버전에서 Project Lambda를 사용해볼 수 있다. 아래의 링크에서 다운로드 받을 수 있다.

설치와 JDK 1.8 버전의 환경 구성이 완료되었으면 Lambda 표현을 Java 에서 사용할 수 있다.

Java 8 의 Lambda 샘플 예제 간단한 예제만 소개하겠다.

(Java에서 권장하는 네이밍이나 코드 구현 방식에 맞지 않는 부분이 있더라도 양해 바란다.) 간단한 더하기 계산을 Lambda 표현으로 작성하면 다음과 같다. 



위의 코드로 말미암아 Lambda 표현은 (arguments) -> { … } 로 표현할 수 있겠다.

간단하게 Thread를 돌리는 코드를 Lambda 표현식으로 작성해보자. 




다음은 ExecutorService를 Lambda 표현으로 작성하였다. 





Java의 Lambda 이야기가 나온 김에 어떻게 Lambda 표현으로 발전하였는지도 짤막하게 보자.

원래 이런 코드가 있었다. Runnable Interface를 구현하는 코드이다. 




또는 Java의 Local Class를 이용할 수 있다. Local Class는 메서드 구현부에서 Class를 선언하여 이를 인스턴스화 할 수 있다.

위의 Runnable Interface를 구현한 코드를 Anonymous Class(익명 클래스)로 표현할 수 있게 되었다. 그래서 아래의 예제와 같이 Interface를 구현하는 Class를 만들지 않아도 된다. 



위 Anonymous Class를 Lambda 표현으로 작성하면 더 간결하게 표현할 수 있다. 


단, Java 8의 Lambda 표현에 제약이 있다.

그리고 Project Lambda를 소개하는 페이지의 Functional Interfaces 에서 제약에 대한 설명이 있다. 하지만 이는 근본적으로 Java에서는 C/C++의 Pointer를 표현할 방법이 없는 이유이다. 그러므로 함수를 가리키는 Pointer도 있을 수 없다. 반면, C#에서는 함수포인터를 표현하기 위해 Delegate(대리자)를 지원한다. C#에서는 함수포인터를 안전하게 다룰 수 있다.

그래서 Java에서는 함수포인터를 표현하기 위해서 Listener 형태의 패턴을 주로 사용한다. 다른 말로 Observer 패턴이라고 부른다. Java의 Thread가 대표적이다. Java의 Thread는 Runnable을 인자로 받는 생성자가 있다. 위의 코드에서도 볼 수 있듯이 Runnable은 void run() 메서드만 달랑 가지고 있는 Interface이다. Java의 Thread는 이 Runnable Interface만 알고 있으면 되고, Runnable Interface를 구현하는 인스턴스를 Thread에게 넘겨주면 된다.

반면, C#의 Thread는 Delegate(대리자-안전한 함수 포인터)를 이용하여 Thread를 실행한다. C# 컴파일러는 Delegate를 결국 Class 로 취급한다. 이로 말미암아 Java와 C#에서 포인터라는 것은 언어적으로는 전혀 메커니즘으로 작동하지만 런타임 입장에서는 유사한 메커니즘으로 동작한다는 것을 알 수 있다. 하지만 Java에서 함수포인터를 흉내를 낼 수 있는 방법은 있다. 키/쌍의 컬렉션을 이용하여 참조를 전달하는 방법이다. 아래는 간단한 예제 코드이다. 



어찌되었든 결국, Java의 Lambda는 Interface를 이용하여 Lambda 함수를 만듦으로써 Interface의 함수가 단 1개만 있어야 Lambda 표현을 할 수 있는 제약이 생겼다. Interface를 이용하여 Lambda를 표현한다고 함은 내부적으로 Proxy 객체를 생성하여 그 안에 Lambda 표현을 메서드로 만든다.

아래의 익명 클래스를 보자. 아래의 runnable 로컬 변수를 리플랙션을 이용하여 getMethods() 의 목록이다. 



아래의 Lambda 표현을 보자. 마찬가지로 runnable 로컬 변수를 리플랙션을 이용하여 getMethods() 의 목록이다. 


이를 통해 Java의 Lambda 표현식은 내부적으로 Proxy 클래스가 생성됨이 확인되었다. 그런데 이 Proxy 클래스가 언제 생성이 될까? 컴파일 타임에 생성이 될까, 아니면 런타임에 생성이 될까?

이를 JD-GUI 도구를 이용하여 Decompile 결과를 확인하려고 하였으나, Java 1.8.0 버전에 대해서 JD-GUI 가 올바르게 인식을 하지 못해 전혀 class 파일을 전혀 읽을 수 없다. 대신 .class 파일을 Text Editor 로 열어서 대략적인 내용을 확인할 수 있는데, Text Editor 에서는 Lambda 표현으로 구현된 Proxy Class 를 찾을 수 없었다. 따라서 Lambda 표현은 런타임에 구현 객체 Proxy 가 생성된다는 것을 알 수 있다. (다만, 확신은 못하겠다.)

한가지, Java 8의 Lambda 표현의 다른 점이라면 Lambda 표현의 Proxy 객체는 java.lang.invoke.MagicLambdaImpl 클래스를 상속한다는 점이다. 앞서 얘기했듯이 JD-GUI 도구가 Java JRE 1.8.0 의 rt.jar 파일을 상위 호환성이 아직 지원되지 않아 구현 내용을 알 수는 없었다. 이는 좀 더 Java 8의 Release 시기가 다가오기를 기다려야 할 것 같다. 



결론은 Java 8의 Lambda 표현을 하기 위해서는 Interface 의 구현 함수는 반드시 1개여야 한다는 점이다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 짜두 2013.01.17 08:59 Address Modify/Delete Reply

    이제 베타버전이니 좀더 발전해야 겠네요. 굉장히 빠른 속도로 발전해나가지 않을까하는 생각이 드네요.ㅎ

개요

간단하게 작성한 C++ 코드가 컴파일이 되지 않는다. auto 키워드와 lambda 식을 제대로 해석을 하지 못하는 모양이다.

인터넷을 통해 쉽게 문제를 해결할 수 있었다. 아래의 원문의 링크를 참고하면 된다. 필자는 아래의 링크를 참고하여 스샷좀 뜨고, 예제 샘플 정도만 만들었으니 설정에 어려움이 없다면 아래의 참고 링크만으로 충분할 것이다.

필자가 받은 GCC 4.7.2 버전의 Release 변경 사항을 보면 도움이 될 것이다.

그리고 몇 가지 std 함수 중 to_string 함수에 버그가 있는데, 아직도 Pending 상태라 되도록 사용하지 말고(사용자체가 안된다 ^^;), stringstream 등을 사용하도록 권장한다. SourceForge에서 GCC 버그 항목을 찾아보면 2011년도에 버그가 등록되었지만, 우선순위가 낮아 당분간 고칠 생각이 없는것 같다. (SourceForge GCC to_string 버그 링크)

MinGW-GCC 에서 C++11 컴파일 환경 구성

Project Explorer -> Project Properties -> C/C++ Build 탭 -> Settings 탭 -> Tool Settings 탭 -> Miscellaneous 항목 -> Other Flags 에 -std=c++0x 를 추가한다.

그리고 C/C++ General 탭으로 이동한 후 Paths and Symbols 탭 -> Symbols 탭 -> __GXX_EXPERIMENTAL_CXX0X__ 항목의 Value 값을 0 으로 설정한다.

모두 완료되었다면 Clean Project를 해서 다시 컴파일하자. 아래와 같이 auto 키워드와 lambda 구문에 더 이상 경고와 오류 문구가 뜨지 않고 컴파일도 성공한다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요

Qt 개발 환경을 만들려는 참에 Eclipse에서 Visual C++로 만든 프로젝트를 MinGW GCC로 변환해야 할 필요가 생겼다. '인터넷 검색 링크를 잊어버려서… 다시 참고 원문 링크는 찾으려니 찾아지지 않아서... 패스....'

우선 프로젝트를 변환하는 방법은 크게 두 가지가 있는데, 예를 들어, 첫 번째는 전혀 다른 프로젝트를 Dynamic Web Application으로 바꾼다거나… 이런 경우에는 Project Explorer에서 -> Propject Properties -> Project Facet에서 변경하면 된다고 한다.

   

두 번째, 필자가 필요한 것은 이 방법이다. Eclipse에서 Visual C++로 만든 프로젝트를 MinGW로 변경하고자 한다.

Project Explorer -> Project Properties -> C/C++ 탭 -> Tool Chain Editor에서 변경할 수 있다.

   

이제 MinGW GCC 컴파일러를 이용하여 컴파일이 되도록 환경을 수정해야 한다. 이 방법은 아래의 링크를 참고하면 된다.


참고로 필자의 MinGW GCC 환경 변수의 경로이다.

  • INCLUDE - D:\Program Files\MinGW\include
  • LIB/LIBPATH - D:\Program Files\MinGW\lib
  • PATH - D:\Program Files\MinGW\bin

   

여기에서 주의해야 할 것은 Environment 옵션에서 'Append variables to native environment' 항목을 선택한다.

   

Posted by 땡초 POWERUMC

댓글을 달아 주세요

윈도우 8, 요즘 인기가 많다. 일반 사용자들의 후기도 많이 보이고, 더불어 개발자들에게도 기존의 개발 경험을 살려 그래도 개발이 가능해서 인기가 많다. 더불어 C++/CX와 HTML5로 개발이 가능하다.

   

WinRT와 WinMD

그 중에서 C#/XAML을 이용하여 앱을 개발할 경우 Windows 8 Runtime(WinRT)의 라이브러리를 이용하여 개발하게 되는데, 마이크로소프트에서는 이 WinRT를 관리 언어가(Managed 플랫폼 환경) 아닌 C++로 만들어진 네이티브(Native)로 컴파일 되어 있다. 확장된 COM 기반이기 때문에 C#과 HTML5에서 모두 이 라이브러리 APIs 집합을 사용할 수 있다. 이것은 매우 큰 장점이 분명하다.

그런데 말이다. 이 WinRT 자체가 매우 성급하게 만들어진 라이브러리라는 것이 여럿 보인다. 그 중 네이티브로 컴파일된 환경에서 C#과 유사하게 런타임상의 객체나 타입 정보를 알아내기 위해 RTTI(RunTime Type Identification)을 C++/CX 컴파일 시에 자동으로 구현이 된다. 그리고 RTTI를 위해 사용되는 WinRT의 API 정보의 일부는 .WinMD 파일로 저장이 된다. 이를 윈도우 런타임 라이브러리(Windows Runtime Library)라고 하며, 이 라이브러리는 윈도우 8 앱을 개발하는 환경 모두에서 사용할 수 있다.

   

   

   

   

윈도우8 WinRT, XAML의 미완성을 의미하는 IXamlMetadataProvider와 IXamlType 인터페이스

여기에서 문제가 발생한다. 모든 객체들은 C++/CX과 C#에서 XAML(eXtensible Application Markup Language)에서 다룰 수 있다. 그리고 Windows.UI.Xaml 네임스페이스에 XAML과 관련된 APIs 집합이 있다. 그런데 WinRT는 XAML을 핸들링 할 수 있는 라이브러리를 완벽하게 구현해 놓지 못했다.

그래서 WinRT의 IXamlMetadataProviderIXamlType 인터페이스가 생겼다. 이 인터페이스가 WinRT가 XAML을 (꽁수로) 핸들링하기 위해 만들어진 인터페이스로 보인다.

코드에서 새로운 객체를 생성해서 사용하고 싶으면 var obj = new LoginView(); 와 같이 새로운 객체를 생성하는 new 키워드를 사용하면 된다.

객체지향을 완벽하게 표현하는 XAML에서도 마찬가지다. XAML에서 다음처럼 LoginView 객체를 생성할 수 있다.

   

   

여기에서 IXamlMetadataProvider가 미완성 XAML임을 증명해 준다. 윈도우8 모던 앱(Modern App)에서 XAML에서 객체가 생성되는 경우 컴파일 시에 자동으로 생성되는 XamlMetadataProvider.g.cs 파일에서 객체를 생성해 준다. (g는 Generated를 의미한다). 자동으로 생성되는 이 코드는 다음과 같은 코드가 포함이 되어있다.   

   

XAML에서 LoginView 객체 생성을 요청할 경우 IXamlMetadataProvider를 구현한 코드를 통해 객체를 대신 생성한다. 다시 말해, 하드 코딩이 되어있다.   

이는 매우 유감이다. 이는 즉, 런타임상에 동적으로 생성되는 객체나 앱 컴파일 시에 해당 클래스가 포함이 되어 있지 않다면, XAML은 객체를 생성하지 못하게 된다. 동적인 무언가에 의해 생성되는 객체는 XAML에서 명시적으로 객체를 생성할 수 있는 방법이 없어진 것이다. (단, 명시적인 호출)

   

   

사용자가 구현하는 IXamlMetadataProvider

일단 WinRT가 이렇게 구현되어 있으니, 어쩔 수 없다. 동적으로 생성되는 객체에 대해서 XAML에서 명시적으로 객체를 생성하기 위해서는 Custom IXamlMetadataProvider를 구현해 주어야 한다.   

아래는 필자가 개발 중인 Umc.Core.WinRT.dll 에 포함된 Custom IXamlMetadataProvider이다. 윈도우8 모던 앱을 컴파일할 때 MSBuild는 참조되는 어셈블리의 메타데이터를 검색하여 IXamlMetadataProvider 인터페이스를 구현한 객체를 XamlMetadataProvider.g.cs 코드에 자동으로 추가를 해준다. 그리고 컴파일이 된다.

   

   

   

IXamlMetadataProvider가 필요한 경우의 예시

아마 일반적으로 윈도우8 앱을 개발할 때 이 인터페이스를 구현할 필요는 없다. 하지만, 앱을 캡슐화하려고 하고, IoC(Inversion of Control) Container 등을 활용하고자 하고, 동적인 객체가 필요한 경우라면 이 인터페이스를 구현해야 할 필요가 있을 것이다.   


C#이 지원하는 System.Dynamic.ExpandoObject 객체를 생성한다면 이 객체는 XAML에서 명시적으로 호출을 할 수 없다.   

또, System.Dynamic.DynamicObject 를 구현하는 객체도 마찬가지이다. 아래는 Umc.Core.WinRT에 포함된 코드의 일부이다.

   

위와 같은 코드를 이용하여 동적인 객체를 생성하였다면, 명시적으로 구현한 클래스가 없으므로 당연히 XAML에서도 이 객체를 생성할 수 없다.   

이와 같은 경우에 IXamlMetadataProvider를 구현하면 된다.

   


그 밖에 필요한 것들

아마 WinRT는 윈도우폰7 의 API 보다 더 작다. 작은 만큼 없는 것이 많고, 포기해야 하는 것이 많다. 아래에 나열되는 구현체는 http://umcore.codeplex.com 의 필자가 만든 코드를 WinRT용으로 마이그레이션한 것들이다. 조만간 Umc.Core.WinRT도 공개할 것을 약속한다.   

1. WinRT 설계 자체가 IoC Container를 활용하기 매우 너그럽지 못한 구조이다. 그래서 기본적인 WinRT 구조를 많이 벗어난 구조를 직접 구현해야 했다.      


2. MarkupExtension등을 지원하지 않아 Markup 확장이 불가능하여 다른 형태의 XAML답지 못한 요소나 속성들을 따로 만들어야 한다. MarkupExtension등으로 IoC Container 등과 통합을 쉽게 할 수 있으나, 어쩔 수 없이 필자는 Attached Property로 아래와 같이 구현해야 했다.

또는 아래와 같이 LambdaExpression을 이용하여 동적 Compile() 하여 사용하는 형태로 다음과 같이 사용이 가능토록 할 것이다. 이 경우, 위의 방법보다 더 나은 성능을 보여줄 것이다.

 

3. Frame.Navigation은 객체의 Type으로 뷰를 이동한다. 하지만, 하나의 타입에 두 개의 뷰를 만들 수 있는 APIs 를 제공해 주지 않는다 따라서 INavigationService와 NavigationServiceFrame을 직접 구현하여 다음과 같이 하나의 Type 으로 생성되는 뷰는 여러 개의 뷰 객체를 생성할 수 있도록 했다.

다음과 같이 인터페이스를 정의하였고, 기존의 Windows.UI.Xaml.Controls.Frame은 Umc.Core.ModernApp.NavigationServiceFrame으로 대체하도록 하였고, UniquqKey로 구분하여 하나의 Type에 여러 뷰를 생성하여 네비게이션 할 수 있도록 했다.

   

4. IoC Container와 통합된 EventAggregator

뷰에 이벤트를 전달하거나 전역 이벤트를 전달하기 위해서 좀 쉬운 구조로 가기 위해 IoC Container에 EventAggregator를 함께 넣어보았다. Message 방식을 통해 뷰의 이벤트나 전역 이벤트를 구독할 수 있다.

   

그리고 구독을 뷰에서 제어할 수 있도록 하였다.

   

5. IoC Container와 통합된 인젝션. 객체의 인젝션(Injection-주입)은 다음과 같이 이루어진다.

   

6. IoC Container의 Configuration File 구성

이건 이전에 http://umccore.codeplex.com 에 구현해 놓은 것을 WinRT 용으로 마이그레이션 하였다. patterns & practices - Unity의 경우 Configuration을 지원하지 않지만, UmC Core의 IoC는 이를 한번 더 Wrapping 하였기 때문에 구성 파일로 만드는 것이 가능하다.

   

7. IoC Container에서 지원하는 AOP

이는 WinRT 구조상 이를 구현하기가 그리 쉽지는 않다. WinRT에서는 직접 MSIL(MS Intermediate Language)을 이용하여 런타임에 Instructions을 생성할 수 없다. 다만, APIs 가 모자란 만큼 모자란 대로 구현을 할 수 밖에 없다.

예를 들면, C#의 dynamic 을 이용하여 다음과 같이 구현 가능하겠다.

   

   

다음 버전의 윈도우8 앱 SDK 구조는 또 얼마나 바뀔까 걱정!

실버라이트의 일부와 윈도우 폰7에서도 그러하듯 이번 WinRT도 초기 버전이라는 생각이 든다. 생각해보라. 실버라이트 1,2까지 얼마나 개발자의 Needs를 만족해주지 못하였는지. 앞으로 등장할 윈도우 폰8 개발 SDK도 하위 호환성을 일부 포기한다고 알고 있다.   

현재까지 윈도우8 앱 개발 SDK 환경을 본다면, 기존에 가능하던 것들이 WinRT 환경에서 매우 많은 제약이 따른다는 것이 불편하다. 현재 WinRT와 윈도우8 앱 개발 플랫폼의 구조를 본다면, 차기 개발 SDK에서는 WinRT를 얼마나 개선할 수 있을지 알 수는 없다. 아마 WinRT/SDK를 만드신 분들도 참 많이 고민을 했을 것이다.   

다만 WinRT/SDK를 사용하는 개발자에게 그 동안 밟아왔던 원망스러웠던 수순을 밟지 않기를 바랄 뿐이다. 

어쨌든, 윈도우8 WinRT/SDK의 불합리하거나 불편했던 부분을 필자가 구현한 이전에 공개했던 http://umccore.codeplex.com 에 추가로 공개할 예정이다.

'O/S > Windows 8' 카테고리의 다른 글

윈도우 8, 무서운 드라이버와 궁합  (0) 2013.06.05
윈도우 8, 반토막짜리 WinRT와 WinRT SDK  (1) 2012.10.30
Posted by 땡초 POWERUMC

댓글을 달아 주세요

  1. 김종남 2016.05.15 21:03 Address Modify/Delete Reply

    글 잘 보았습니다.

Windows 8 스타일 개발이 한창 유행이다. 물론 모바일 생태계 전반전인 유행은 아니더라도 Microsoft 기술을 하는 사람들에게는 관심 대상이다. Windows 8 운영체제가 탑재되는 테블릿도 출시가 되고, New iPad 보다 하드웨어 스팩이 좋은 테블릿 출시도 준비중인 곳이 많다고 들었다. 새로운 마켓이 열리는 만큼 테블릿 사용자에게는 새로운 재미를 선사해줄 것은 분명한 사실일 것이다.

Windows 8 스타일 ! 개발을 위해 가지 알아야 구조적인 개념이나 유의사항 정도만 언급하기 위해 글을 나간다. C++/CX, C#,VB XAML(eXtensible Application Markup Language) 이용하여 WPF 데스크탑 응용 프로그램처럼 프로그래밍을 있다. 그리고 HTML/JavaScript 조합으로 개발 환경과 유사하게 개발을 있다. 아마 대부분의 Windows 8 스타일 개발자라면 알고 있는 내용일 것이다. 그리나 포스팅에서는 C++/CX C# 개발 언어를 기준으로 아티클 내용을 채울 것이다.

 

Windows 8 스타일 런타임 관점의 구조

[이미지 링크]

   

WinRT(Windows Runtime) 플랫폼의 구조적 아키텍처 이미지이다. 기존 Windows Desktop 응용 프로그램 환경과 다른점은 WinRT APIs 중간에 끼어있다. WinRT Windows 8 스타일 앱의 핵심이며, Windows 시작하는 Namespace 모두 WinRT 이다.

C#,VB 개발 환경은 그나마 편리한 Library Subset 제공한다. .NET Framework 최소화 버전이라고 보면 된다. 이를 .NET for Windows Store apps 이라고 부르며, 위의 이미지에는 내용이 빠져있다.

C++/CX 잘라 .NET for Windows Stores apps 제공되지 않는다. .NET 개발자라면 System(mscorlib.dll) 으로 시작하는 Namespace 얼마만큼 편한지 알텐데, Library Subset 제공되지 않으니 다른 방법을 사용해야 한다. 쉬운 예로 HttpClient 같은 클래스도 C++/CX MsXml COM 컴포넌트를 이용하는 편이 낫다. 그렇다고 모든 C++ 라이브러리를 사용할 있는 것도 아니다. 이 부분에서 특히 라이브러리의 제한이 있으므로 C:\Program Files (x86)\Windows Kits\8.0\Include\shared 폴더에서 사용가능한 Header 파일을 확인해보도록 하자.

만약 Header 파일의 pragma 선언이 Dektop Family 라면 Windows 8 스타일 앱에서는 사용할 없는 라이브러리이며, 상당한 Header들이 Desktop Family 속하여, 당장 .NET for Windows Stores apps 만큼 쓸만한 클래스들이 없다는 것이 조금 슬프다. 다만, 좋은 소식이라면 C++ boost Library 등이 C++/CX 용으로 컨버전을 시도하는 분들이 많으므로, 조금만 기다려보면 쓸만한 라이브러리들이 대거 출연할 것으로 보인다.

   

더불어 C#, C++ 개발자들도 알고 있어야 하는 중에 하나가 WinRT COM 컴포넌트 기반의 라이브러리라는 것쯤은 들어보았을 것이다. 그래서 Windows 8 스타일 개발자들은 COM 대한 개념과 나아가 이를 구현할 있다면 좋다. 특히 C#, VB 에서 WinRT 컴포넌트를 만드는 것은 가지 지켜야할 제약이 있으므로 다음의 링크를 참고하는 것이 좋다.

C# Visual Basic으로 Windows Runtime 구성 요소 만들기 http://msdn.microsoft.com/ko-kr/library/windows/apps/br230301.aspx

   

대신 C++/CX WinRT 컴포넌트를 만드는 것이 오히려 간단하다. 앞서 말했다시피 WinRT COM 컴포넌트 기반이지만, 기존 C++ 에서 COM 컴포넌트를 만드는 만큼 어렵지가 않다. C++ COM 구현의 첫번째는 IUnknown 인터페이스를 구현하는 것이지만, WinRT 에서는 Iunknown을 상속하는 IInspectable 인터페이스가 더 중요하다. IInspectable 인터페이스는 C++/CX 개발된 응용 프로그램이 런타임 해당 클래스의 정보를 제공하기 위한 인터페이스이다. 물론 기존 C++ 에서도 런타임상 클래스 정보가 필요하여 이를 직접 구현하는 방법도 있다. 하지만 C++/CX IInspectable 인터페이스는 C++/CX 컴파일 과정에서 자동으로 구현을 해준다. 이는 IUnknown 인터페이스까지 자동으로 구현해준다고 보면 된다. 그렇기 때문에 Iunknown 인터페이스의 AddRef, Release 메서드에 대한 객체 수명주기를 WeakReference 클래스를 통해 위임할 있다. WeakReference 통해 금방 해제될 있는 컴포넌트를 가비지 컬렉터 대상이 되도록 지정한다. 그러므로 사용 빈도가 매우 많고, 매번 자원 해제에 대한 비용이 반복되는 것은 WeakReference 효과적으로 객체 수명 주기를 다룰 있게 한다. 이러한 C++/CX 특별히 제공되는 라이브러리는 Microsoft.WRL Namespace 포함되어 있다.

아직 이러한 개념적인 부분이 어렵게 느껴진다면 월간 마이크로소프트 5월호 특집 기사로 기고한 필자의 다음의 글부터 참고 바란다.

[월간 마이크로소프트 5월호 특집기사] C++ 매트로 개발을 위한 C++/CX 언어 http://blog.powerumc.kr/378

   

   

Windows 8 스타일 응용 프로그램 관점

짧게 말해 Windows 8 스타일 개발은 쉽다. Visual Studio 2012에서 훌륭하게 대부분이 구현된 템플릿을 제공하기 때문에, 메서드 중간 중간 원하는 기능을 추가하고, 클래스나 XAML 만들면 된다. 다만, 이는 만든다는 것이 쉽다는 것이지 응용 프로그램 구조적인 측면에서는 전혀 쉽지 않다.

먼저 알아야 것이, Windows 8 스타일 페이지를 상태 관리 것인지, 것인지부터 결정해야 한다. 상태 관리를 유지할 필요가 없다는 것은 개발(ASP.NET/ASP/PHP/JSP) 같은 서버 사이드 개발 환경과 유사하다. 특히 IIS에서부터 ASP.NET까지 연결되는 Application Pipeline 매번의 Request마다 Pooling Thread 활성화되어 서버 랜더링을 통해 사용자에게 HTML Response 전달이 된다.

   

1. 상태 관리를 개별적으로 유지하고 싶다면

다음의 가지 메서드를 재정의하면 된다. ASP.NET Custom Control 구현해 보았다면 VIEWSTATE 상태 유지를 위해 이런 유사한 코드를 구현해야 하는 것을 것이다.

   

Frame.Navigate 메서드는 Page Type 인자로 받고, 매번 새로운 인스턴스를 생성한다. (구현을 다르게 한다면 인스턴스를 이용하도록 수도 있다.) 페이지의 상태 유지야 위의 메서드를 재정의하는 정도로 끝낼 있지만, 페이지에 포함된 UserControl 있다면 상황은 달라진다. 독자마다 구현하는 방법은 다르겠지만, 효과적으로 상태를 관리하기 위해 UserControl 조금 귀찮아지는 존재이다. 인스턴스의 재사용을 위해 자주 사용하는 UserControl 대한 상태 관리를 고민해야 하다니… (현재 아티클은 내용이 대해 오픈 소스 제공으로 효과적인 방법을 제안하도록 필자는 약속 하겠다.)

   

2. 상태 관리를 자동으로 캐싱하고 싶다면

상태 관리를 자동으로 캐싱하는 방법도 매우 쉽다. Page.NavigationCacheMode 프로퍼티를 Enabled 해주면 된다. 물론 XAML 코드에 속성을 추가해도 된다. 하지만 아쉽게도 Frame.Navigate 메서드를 통해 자동으로 상태 관리를 하도록 Page 새로운 인스턴스가 생성이 된다. 상태 관리 캐싱에 대한 조건은 GoBack(), GoFoward() 같은 Frame 이동에 대해서만 유효하다. 조금 이해할 없는 부분은 Page 포함된 UserControl 상태 관리 캐싱 대상에서 제외된다. (물론, 가능하도록 있지만 개념적으로 깊게 이해하고 구현해야 한다.)

   

3. 남발되는 async/await 의한 동기화 문제

Windows 8 스타일 앱을 사용하다가 자주 멈짓 멈짓 한다면 분명 사용자는 짜증날 것이다. 때문에 async / await 키워드를 더욱 자주 사용하는 편이다. 그렇기 때문에 UI 상태에 대한 비동기와 컴포넌트나 인스턴스 메서드 호출에 대한 비동기, 모두 정확하게 Threading 대한 지식이 필요하고, 자유 자재로 Threading 다룰 있다면 더욱 좋다. Windows 8 스타일 앱에서 가장 많이 발생하는 Threading 문제는 Thread 실행 인스턴스 해제에 대한 동기화와 Thread Cancel 대한 동기화다.

문제를 피하기 위해서는 클래스나 라이브러리를 만들때 부터 async / await 대한 고려가 필요하다. 쉽게 이야기하자면 자주 쓰지 않는 편이 좋고, 써야 곳에 써야 한다.

   

이를 판단하려면 Thread 동기화에 대해 적어도 가지는 반드시 익히는 것이 좋다. MSDN 아래의 글들을 번정도 필독하기 바란다.

관리되는 스레딩 기본 사항 http://msdn.microsoft.com/ko-kr/library/hyz69czz
스레딩(C# Visual Basic) http://msdn.microsoft.com/ko-kr/library/ms173178(v=vs.110)

   

      

Windows 8 스타일 배포와 라이브러리 배포 문제

부분은 매우 민감한 부분이고 조심스럽다. 실제 Windows App Store에서 테스트할 없을 뿐더러 개발 환경에서 발생하는 문제이므로, 실제 Windows App Store 통해 발생할 수도 있을 가능성이 있을 같다. COM 기반 라이브러리나 DLL 구성 요소 등은 공유 메모리에 로드가 된다는 것을 것이다. 특히 부분은 COM 컴포넌트에서 민감하게 다루는 IUnknown 인터페이스의 의미와 일맥 상통한다. , COM 객체의 참조 카운트(Reference Cout) 0 되지 않으면, 자원은 해제되지 않는다. 여기에서 COM 가장 고질적인 문제가 발생한다. 바로 DLL 지옥이다. Windows 8 스타일 앱의 메모리 위치는 메모리 영역이 아닌 공유되는 메모리 영역에 위치하고 있고, DLL Verserning 자유롭지 못하다. .NET 처럼 GAC(Global Assembly Cache)에서 DLL 버전별로 관리되지 않는다.

따라서, WinRT 런타임 라이브러리를 개발하여 배포된 Windows 8 앱이 활성화 상태일 새로운 앱에서 버전업 WinRT 런타임 라이브러리 배포시에 다른 프로세스가 점유하고 있다는 오류가 발생한다. 이는 앱이 초절전 유휴 상태에 진입되어도 마찬가지이다.

이찌되었든 개발 환경에서는 충분히 발생된 문제이니, 차후 Windows App Store에서도 발생할지는 지켜보아야 것이다.

   

Windows 8 Windows Runtime 재배포 정책 업데이트

런타임 라이브러리인 만큼 라이브러리 코드가 완벽하지는 않을 것이다. .NET Framework 1.0부터 4.5까지 버전업이 되어왔는데 과연 Windows 8 Windows Runtime 어떻게 버전업이 될까? 사용자의 동의 없이 업데이트나 패치는 불가능하다.

   

Windows 8 Features Pack 1,2,3… 시리즈로 업데이트가 될까?
Windows 8 Service Pack 1,2,3… 시리즈로 업데이트가 될까?

   

만약 이렇게 되면, Windows 8 스타일 간에 호환성 문제가 발생할 것이 분명하다. Apple iPhone 모바일 폰의 운영체제 업데이트가 실시간으로, 온라인으로 이루어진다. Windows 8 iPhone 업데이트와 차원이 달라진다. WinRT 지원하는 ARM 버전과 기존의 Windows 8 Desktop 지원하는 x86 버전 가지의 에디션이 있다.

혹시 부분에 대해서 알고 있는 정보가 있으면 공유 부탁 드립니다.

Posted by 땡초 POWERUMC

댓글을 달아 주세요