저 개인적으로는 오래된 명령줄 인터페이스 기반의 툴을 매우 사랑합니다. 가끔 GUI로 채워지지 않는 부족함을 명령줄 인터페이스 기반의 툴을 통하여 채울 수 있기 때문입니다. 비유하자면 효자손과 같은 존재이지요. :-)
오늘은 그 중에서도 SQL Azure를 관리하기 위한 목적으로 OSQL 도구를 사용하는 방법을 설명하고자 합니다. 요즈음은 SQL Management Studio 덕분에 그 수요가 많이 줄어들었지만, 아직 OSQL 도구가 유용하게 사용될 수 있는 여지는 매우 많습니다. 저의 경우, Sync Framework와 SQL Server Agent를 사용하여 쉽게 동기화할 수 있는 상황이 아닌 이기종 데이터베이스간 데이터 마이그레이션 시나리오에서 매우 유용하게 사용하고 있습니다. C#을 이용하여 실제 데이터를 insert하는 구문을 SQL 스크립트로 덤프를 생성하여 이것을 OSQL 도구에 매개 변수로 전달하는 방법을 선호합니다. BLOB이나 CLOB, 개행 문자를 포함하지 않는 데이터로 구성되어있는 경우 이 방법은 매우 유용한 것 같습니다.
그렇다면 OSQL을 통해서 SQL Azure에 접속하려면 어떻게 해야 할까요? 방법은 다음과 같습니다.
SQL Azure에 접속하는 방법은 일상적으로 우리가 사용했던 SQL Express Edition이나 SQL Server에 접속하는 방법과 조금 다릅니다. 각 스위치별로 필요한 항목들을 하나씩 살펴보겠습니다.
-S 스위치: 접속 대상 서버를 지정합니다. SQL Azure의 호스트 이름은 주로 xxxx.database.windows.net과 같은 형태로 되어있고, 이 부분의 정확한 주소는 SQL Azure Portal에서 확인할 수 있습니다.
-U 스위치: 사용자 ID를 지정합니다. 통상 사용하는 SQL Server와는 다르게, 사용자 이름 뒤에 서버 이름을 명시적으로 @ 기호와 함께 지정해야 합니다. 예를 들어, <your_server>에 들어가는 식별자가 abcd라고 한다면 <your_database_id>@abcd가 이 스위치에 지정되어야 합니다.
-P 스위치: 사용자 비밀 번호를 지정합니다. 띄어쓰기가 있는 비밀 번호의 경우 -P"<your_password>"와 같은 형식으로 따옴표를 이용하여 비밀 번호 문자열 주변을 포장하여 인수로 전달합니다.
-d 스위치: -D 스위치가 아닌 -d 스위치로, 대/소문자 구분에 유의합니다. 이 부분에서는 사용하려는 데이터베이스 이름을 지정해야합니다. SQL Azure의 특성 상 한번 연결이 완료되면 다른 데이터베이스로는 문맥 전환을 할 수 없으며, 따라서 USE 문의 사용은 허용되지 않습니다.
위와 같이 지정하여 성공적으로 접속하였다면 프롬프트가 나타날 것입니다. 하지만 대부분의 경우 방화벽 설정에 의하여 연결이 차단될 수 있습니다. 이 때에는 SQL Azure Portal로 접속하여 현재 여러분이 접속을 시도하는 IP 주소를 SQL Azure에서 접속할 수 있도록 허용해야 합니다. 여기서 주의할 것은, NAT나 인터넷 공유기와 같이 하나의 외부 IP 주소를 여러 PC가 공유하는 환경에서 SQL Azure를 접속하려는 경우 보안 상 위험이 발생할 수 있다는 점입니다.
이제 대량의 query문을 실행하기 위한 스위치를 하나 더 알아보겠습니다. 바로 -i 스위치입니다. 이 스위치를 이용하여 실행하려는 SQL 문장이 포함된 스크립트 파일을 지정하고, -o 스위치를 사용하여 실행 결과를 텍스트 파일로 갈무리할 수도 있습니다.
이번 강좌에서는 Mono를 이용하여 Hello World 콘솔 응용프로그램을 만들어보고 MonoDevelop와 Visual Studio의 차이점을 살펴보기로 하겠습니다. Visual Studio가 Windows용 응용프로그램을 위하여 최적화된 환경을 제공한다면 MonoDevelop는 Linux 응용프로그램, 정확하게는 Gnome Desktop을 위하여 최적화된 환경을 제공합니다.
이번 강좌에서는 지난번에 이어 VMware 기반 Mono 패키지를 이용합니다. 다음의 웹 사이트에서 Mono 패키지와 VMware Player를 무료로 다운로드받으실 수 있습니다.
VMware 패키지를 부팅한 이후에 바탕 화면에 MonoDevelop 아이콘이 있을 것입니다. 이것을 더블 클릭하면 MonoDevelop IDE가 시작됩니다.
위의 화면에서 Start New Solution을 클릭하면 아래와 같은 대화 상자가 나타납니다.
Visual Studio의 새 프로젝트 만들기 대화 상자와 거의 비슷합니다. 하지만 Visual Studio와는 달리 Boo와 같은 신흥 닷넷 기반 스크립트 언어와 MSIL에 대한 직접 지원 (ILAsm), Java 프로그래밍, NUnit 프로젝트 등을 지원합니다. 패키징 프로젝트는 Visual Studio가 제공하는 설치 프로젝트의 성격을 가지지만 오픈 소스 프로젝트를 진행하는 사례가 많음을 감안하여 소스 코드 패키징까지 지원합니다.
Packaging
C# Console 프로젝트를 선택하고 프로젝트 이름을 HelloWorld로 입력하여 프로젝트 생성을 시작하면 새 프로젝트에 대한 상세 설정 대화 상자가 나타납니다. 크게 세 가지 설정이 존재하는데 일단 Packaging 설정부터 살펴보기로 하겠습니다.
Archive of Sources
프로젝트 소스 코드를 패키징하는 방법을 정의합니다. 오픈 소스 프로젝트를 많이 진행하는 경우를 감안한 MonoDevelop만의 독특한 설정입니다.
MonoDevelop Project Model Sources: 패키지의 압축을 풀었을 때 바로 MonoDevelop에서 열 수 있도록 패키징합니다.
SharpDevelop 1.0 Project Model Sources: 패키지의 압축을 풀었을 때 바로 무료 Windows/.NET 기반 오픈 소스 IDE인 SharpDevelop에서 열 수 있도록 패키징합니다. 여기에는 만드려는 MonoDevelop 프로젝트 파일의 형식 변환이 같이 포함됩니다.
Visual Studio .NET 2005 Sources: 패키지의 압축을 풀었을 때 바로 Visual Studio 2005 이상의 IDE나 msbuild 유틸리티에서 열 수 있도록 패키징합니다. 여기에는 만드려는 MonoDevelop 프로젝트 파일의 형식 변환이 같이 포함됩니다.
Archive of Binaries
Linux Binaries: GTK# 등의 크로스 플랫폼 라이브러리나 런타임이 있을 경우 이것들의 리눅스 버전을 모아서 패키징하기 위한 설정입니다. 이후에 패키징 대상을 수기로 변경할 수 있습니다.
Windows Binaries: GTK# 등의 크로스 플랫폼 라이브러리나 런타임이 있을 경우 이것들의 Windows 버전을 모아서 패키징하기 위한 설정입니다. 이후에 패키징 대상을 수기로 변경할 수 있습니다.
Tarball: 관련 소스 코드와 바이너리를 타르볼 파일 (.tar 시리즈)로 압축합니다.
Unix Integration
Generate Launch Script: PE 기반 MSIL 혼용 이미지를 만들어내는 것이므로 사실 만들어진 exe 파일 자체는 여전히 mono 런타임에 의하여 별도로 취급되어야 합니다. 이 과정을 단순화하기 위하여 별도의 스크립트를 생성할 수 있는 데 이 작업을 자동화해줍니다. 프로젝트 이름과 다르게 스크립트 이름을 지정할 수 있습니다.
Generate .desktop File: GNOME 노틸러스를 위한 단축 아이콘 파일 (Windows의 Explorer Shell과 대응됩니다. Windows의 단축 아이콘이 .lnk 확장자를 가지는 것과 같습니다.)을 생성하도록 할 수 있습니다. 이 설정 또한 스크립트를 만드는 것과 같은 용도이지만 GNOME 노틸러스를 위한 부가 설정이 포함됩니다.
Translation
Mono는 다른 Linux 기반 응용프로그램들과 같은 방법으로 지역화 기능을 제공합니다. Microsoft .NET Framework가 사용하는 지역화와는 다른 방법으로 프로그램과 함께 배포되는 PO (Portable Object) 파일을 i18n 라이브러리로 가져오는 방식입니다. 이 설정을 통하여 국적 및 국가 코드 별로 PO 파일을 미리 구성할 수 있습니다.
언어와 국적 코드를 설정하는 단계에서 User Defined Locale 설정을 이용하여 단순한 언어 번역을 위한 용도 외에도 사용자 정의 메시지 테이블을 구성할 수 있습니다.
Gtk# Support
프로젝트에 Gtk# 설정을 추가하고 대상 라이브러리 버전을 지정할 수 있습니다. 별도로 Mono SVN Repository에서 소스 코드를 체크아웃하여 가져오거나 Night Build (개발자에 의하여 짧은 시간 내에 Commit되는 검증 수준이 약한 최신 빌드)를 설치한 경우가 아니면 버전이 보통 한 개입니다.
여러 설정이 있었지만 우리는 여기서 아무런 설정을 택하지 않고 프로젝트를 만들어보기로 합니다. 하나씩 하나씩 다음 Chapter에서 짚어보기로 합시다.
첫 프로젝트 프로그래밍
우리가 예상하던것과 다르지 않게 프로젝트가 만들어지고, 편집과 테스트가 가능한 환경이 생성되었습니다. 리눅스 환경이라고는 해도 C# 코드를 보니 별로 어색하지 않습니다. Visual Studio와 유사한 Keyboard Scheme를 제공하므로 Console.WriteLine 메서드에 출력할 메시지를 Hello World!로 바꾸고 F5키를 눌러보기로 하겠습니다.
Visual Studio와는 조금 다르게 하단에 콘솔 프로그램의 실행 결과가 표시됩니다. GNOME의 경우 Windows에서처럼 기본 콘솔 인터프리터가 통일되지 않습니다. 하나도 설치되지 않았을 수도 있고, 수십 개가 설치된 상태일 수도 있습니다. 그래서 기본 설정은 이와 같이 표준 출력과 표준 오류 출력 스트림 (stdout, stderr)을 리디렉션하여 출력 결과를 보여주는 방식을 사용합니다.
프로젝트 디렉터리 구성 살펴보기
그러면 우리가 만든 프로젝트 파일들의 구성이 어떻게 되는지 한 번 살펴보기로 하겠습니다. 프로젝트 디렉터리는 위와 같이 사용자 프로파일 디렉터리 (이 가상 머신의 경우 /home/linux입니다.)에 솔루션 이름과 동일한 디렉터리가 생성된 것을 볼 수 있습니다.
mds 파일이 보입니다. 이 파일은 Visual Studio의 sln 파일과 같은 것이고 같은 솔루션 파일로 여러 프로젝트에 대한 정보가 mds 파일에 서술됩니다. 그리고 하위 프로젝트 디렉터리들도 이 디렉터리 아래에 생성되겠지요.
우리가 만든 C# 프로젝트가 저장되어있는 디렉터리로 들어가보면 이번엔 mdp 파일이 보입니다. Visual Studio의 csproj, vbproj, vdproj와 대응되는 것이 mdp 파일입니다. AssemblyInfo.cs, Main.cs 파일도 보이는군요. bin 폴더에 우리가 컴파일한 바이너리가 들어있을 것입니다.
Debug, Release 디렉터리가 마찬가지로 존재합니다. 디버그 모드와 릴리즈 모드를 프로젝트 작업 도중 IDE 도구 모음에서 설정할 수 있으며 여기에 맞추어 빌드하고 테스트할 수 있습니다.
Debug 폴더의 경우 exe 파일 외에 exe.mdb 파일 혹은 dll.mdb 파일이 생성될 수 있습니다. 이것은 Microsoft .NET Framework 환경에서의 pdb 파일과 같은 용도로 디버거가 문맥을 탐색할 수 있도록 정보를 저장한 Program Database 파일이지만 Mono Debugger를 위하여 생성된 것입니다.
요약
오늘 단원에서는 MonoDevelop로 프로젝트를 만들었을 때의 실제 디렉터리 및 파일의 배치, 소스 코드의 특성, 새 프로젝트를 만들 때 사용할 수 있는 설정들에 대하여 간략히 알아보았습니다. 다음 단원에서는 패키징 개념에 대하여 살펴보기로 하겠습니다.
Visual Studio 2005에서 가장 획기적인 기능으로 표현되었던 것들 중 하나는 Object Test Bench라고 불리는 창이다. 사실 이것은 수동적인 의미이기는 하나 디버깅과 단위 테스팅에 대한 또 하나의 방법으로 충분한 가치가 있다. 하지만 이 Object Test Bench와 짝이 잘 맞는 또 하나의 옛 파트너가 있다는 사실을 사람들은 잘 모르는듯 하다. Visual C++의 어셈블리 코드/메모리 상태 등을 조회함은 물론 Visual Basic 6.0 시절부터 인터프리팅 언어이기 때문에 지원해왔던 간단한 커맨드 라인까지 다양한 모습으로 우리에게 선을 보여왔던 '직접 실행 창'을 아는가? 오늘 이 글에서는 '직접 실행 창'이 Visual Studio 2005에서 어떻게 유용하게 쓰일 수 있는지를 보고자 한다. (닷넷 프레임워크 밖의 영역에 대해서는 다루지 않는 글임을 주지하기 바란다.)
이 직접 실행 창이 가지는 의미는 실로 크다. 직접 실행 창은 꼭 디버거가 돌고 있는 상태가 아니라도 닷넷 프로젝트나 닷넷 솔루션이 열려있는 시점이라면 언제나 사용이 가능하다는 것이 중요하다. 또한, 직접 실행 창의 내용이 정말 실행이 되는가 역시 문제일텐데, 이것을 어떻게 보증할까? 그렇다. 체크섬을 비교, 언제곧 내용이 바뀌면 스스로 컴파일러를 호출하여 직접 실행 창의 결과가 유효할 수 있도록 맞춘다. 코드 체크섬의 생성에 관해서 궁금하다면 C# 2.0의 새로운 지시자 기호인 #pragma를 참조하라.
직접 실행 창이 확실히 동작할 것이라는 점에 대해서는 직접 다루어보면 안다. 그렇다면 직접 실행 창에다가 대고 뭐라고 이야기를 해야 할까? 의외로 간단하다. 현재 프로젝트에서 사용하는 언어를 가지고 대화를 시작하면 된다. (컴파일 언어가 갑자기 인터프리팅 언어가 되버린다는게 달갑지 않을 수도 있지만 참고 해보기 바란다.
몇 가지 예를 들어보기로 하겠다. 여기서 사용하는 언어는 C#이 되겠다. (사실 C#에 대해서 전혀 모르는 개발자라도 냉큼 이해하기 쉬울정도로 극명한 구문이다.
* 특정 형식에 대한 정보 보기: 특정 형식의 상수, 정적 필드, 정적 프로퍼티, 부모 형식을 확인할 수 있는데 네임스페이스 이름을 포함하여 형식 이름을 써주면 대강의 정보를 나열해준다. 인터페이스의 경우 이런 정보를 명시적으로 출력해주지는 않는다. 만약 제네릭 기반의 형식이라면 형식 인수를 기입해주어야 한다. (형식 인수에 대해서도 네임스페이스 이름이 필요하다. 이런 면은 꽤 거추장스럽다.
* 특정 형식에 대한 인스턴스 생성하기: 역시 이것이 핵심이다. 하지만 이렇게 생성된 인스턴스를 어떻게 사용할 것인가? 그것이 바로 Object Test Bench가 되겠다. (물론 이름을 잘 알고 있다면 직접 실행 창에서 매개 변수로 전달하는 등의 일은 얼마든지 가능하다.)
다음의 스크린 샷을 참고하기 바란다. (스트링을 더하고 이것을 직접 실행 창 콘솔에 출력하는 방법까지 같이 설명하고 있다. System.Diagnostics.Debug 클래스의 WriteLine이라는 정적 메서드는 이럴 때 사용한다.)
굉장히 하찮아보이는 메서드 중에 하나인 .ToString() 메서드는, 사실 NUnit에서 굉장히 중요한 역할을 해냅니다. 바로 NUnit GUI를 좀 더 편리하게 쓰는 비법이 여기에 숨어 있습니다. (Java에서도 비슷한 일을 해낼 수 있을 것입니다.)
NUnit GUI는 어셈블리 코드를 호스팅하는 일반 프로세스이기때문에 표준 출력의 내용을 가져올 수 있습니다. 이 점을 효과적으로 활용하려면 Console.WriteLine / Console.Write 메서드의 특성을 잘 알아야 하는데, 지금 말한 두 개의 메서드는 Object 형식을 받으면 자동으로 ToString() 메서드를 호출하여 출력할 내용을 결정합니다.
ToString() 메서드를 구현하면서 사용하면 효과적인 클래스도 있습니다. 바로 StringBuilder 클래스입니다. 표현해야 할 정보가 많아서 문자열이 길어진다고 생각되면 그저 String을 더하기만 하지 말고 StringBuilder를 이용하는 것이 좋습니다. 특히, 이진 데이터의 표현이 필요하다면 StringBuilder는 필수입니다!
만약 이진 데이터를 NUnit GUI를 통하여 출력하길 원한다면 ToString() 메서드를 잘 구현하도록 합니다. 이진 데이터를 프레젠테이션하는 방법은 Programming Windows with C# (Charles Petzold 저, Microsoft Press)의 OLE 관련 Chapter에 서술되어있으며 Code Project나 Code Guru에서 찾으셔도 좋습니다.
ToString() 메서드의 구현이 잘 되었다면 테스트 루틴 안에서 Console.WriteLine 이나 Console.Write 메서드를 호출하여 테스트도중 변경되는 변수의 내용이나 데이터, 객체의 내용을 조사할 수 있게됩니다.
보너스 하나 더: ToString() 메서드를 잘 구현해두면 디버거에서도 그 역할을 톡톡히 다 해냅니다. 디버거는 요약 정보를 표현하기 위하여 마찬가지로 ToString() 메서드를 이용합니다. :-)