나는 RP 환자가 아니야

하드렌즈를 한 번 착용해 볼까 하다가, 야맹증을 조사해 보다가, 망막 변성을 조사하고, 그러다가 RP (Retinitis Pigmentosa, 망막색소변성)라는 질환을 알게 되었다. 나는 망막 변성에 의한 야맹증으로 군 면제를 받았기에, 혹시나 이 질환에 해당하는 것은 아닌가 하는 걱정이 들어서 요 며칠 사이 많은 스트레스를 받고 있었다. 덕택에 눈도 매우 피로해지고, 일도 잘 되지 않았다. 게다가 주 초에는 한동안 열심히 일한 것을 자축하며 일을 하지 않고 오랜 만에 좋아하는 ‘테트리스’ 에 손을 대는 바람에 지난주에는 아무 일도 하지 못하게 되었다.

어찌 하였든, 오늘 병원 검사 결과 RP 가 아니라는 사실을 알게 되어 기쁘다. 한편으로는 지난 며칠간 내가 바로 그 3000명 중 1명 꼴로 발명하는 RP 환자라면 어떻게 될까 하는 막막한 심정을 돌이켜 보게 된다. 최악의 상황을 상상한다는 것은 정말 괴로운 일이다. 내가 앞을 볼 수 없게 된 뒤에도 나는 유명한 해커 영화에서처럼 멋진 소프트웨어를 개발할 수 있을까? 어떤 유명한 소프트웨어 엔지니어라도 이 질문에 쉽게 대답할 수는 없을 것이다. 건강보다 중요한 것은 없다는 생각이 들지 않을 수가 없다.

오늘밤도 누군가 24시간 모니터를 바라보며 일정이 초과된 프로젝트에 자신의 몸을 맡기고 있다고 생각하면 마음이 아프다. 그들 중 어느 누군가는 오늘 밤 가족을 그리며 떨리는 손으로 목을 맬 수도 있고, 찜질방의 수면실에서 원치 않게 심장이 멎어 버릴지도 모르니까.

이제 막 시작해 얼마 안가 끝나버릴 한 주, 다시 태어난 소중한 몸과 함께 즐겁게 일하고 싶다.

The Innovator’s Dilemma

자바 서블릿 프로그래밍의 저자 Jason Hunter 가 얼마 전 Servlets.com의 블로그를 통해 Java 가 혁신자의 딜레마에 빠졌다는 의견을 피력한 바 있습니다. 그는 Java 5에 추가된 Generics, Autoboxing, Annotation 과 같은 기능들은 얼핏 보기에는 편리해 보이지만, 제대로 사용하기 위해서는 상당한 수준의 자바 지식이 필요하다는 점, 그리고 현재 Java 웹 어플리케이션 프레임워크들이 너무 복잡하다는 점을 지적하고 있습니다.

‘혁신자의 딜레마’라는 용어는 클레이튼 크리스텐슨의 성공기업의 딜레마 (The Innovator’s Dilemma)에서 비롯되었습니다. 저자는 기술 (단순한 산업 기술 뿐만이 아니라, 경영, 마켓팅, 심지어는 태도에 이르기까지 어떤 일을 수행하는데 필요한 총체적인 국면에서의 기술) 및 혁신을 존속성 (Sustaining) 과 와해성 (Disrupting) 으로 나누고, 와해성 혁신의 특징과 위력, 그리고 적용 원칙을 설명했습니다.

참고자료:

C# 의 Nullable Types

프로그래밍을 하다 보면 성가신 것 중 하나가 null이 나 범위를 벗어난 데이터와 같은 잘못된 데이터의 처리입니다. 저 같은 경우 Jakarta Commons Lang이나 TL-Util, 그도 아니면 그냥 직접 일일이 코딩하곤 합니다.

잘못된 데이터가 들어왔을 경우 취할 수 있는 행동은

  • 예외를 던진다
    • NullPointerException – null 인 경우
    • IllegalArgumentException – null은 아니나 규약 위반인 경우
    • 기타 사용자 정의 예외 – RuntimeException 상속
    • AssertionError – assert 문 사용시
      • 매우 편리
      • 외부 노출시 사용 불가
      • JDK 1.4 이상에서만 사용 가능
  • 예외를 던지지 않고 기본 값으로 조용히 치환해 처리한다

정도가 있겠습니다.

그런데, 이번 Visual Studio 2005 에서 등장한 C# 의 Nullable 타입은 예외를 던지지 않고 null 값을 적절히 처리할 수 있도록 돕고 있습니다. 모든 타입 선언은 타입명 뒤에 ? 오퍼레이터를 붙여 Nullable 이 될 수 있습니다:

int? x = 123;
int? y = null;
if (x.HasValue) Console.WriteLine(x.Value); // Printed
if (y.HasValue) Console.WriteLine(y.Value); // Not Printed

Nullable 과 일반 타입 간의 변환은 자유롭습니다:

int i = 123;
int? x = i; // int –> int?
double? y = x; // int? –> double?
int? z = (int?)y; // double? –> int?

// DOWNCAST: Throws exception if z is null.
int j = (int)z; // int? –> int

Nullable 간 연산은 매우 유용해 보입니다:

int? x = GetNullableInt();
int? y = GetNullableInt();

// Two statements do the same job.
int? z = x.HasValue && y.HasValue ? x.Value + y.Value : (int?)null;
int? z = x + y;

?? 연산자를 이용한 디폴트 값 치환은 손가락을 덜 피곤하게 하겠군요:

string s = GetStringValue();

// Print ‘Unspecified’ if s is null
Console.WriteLine(s ?? “Unspecified”);

한편으로는 물음표 하나 늘어났을 뿐이지만 언어가 점점 더 복잡해 지고 있는 것은 아닌가 싶은 생각도 듭니다. 하지만 시간이 지날 수록 언어의 구성 요소가 위와 같이 API 와 결합하여 더 강력한 효과를 내는 것이 요즘의 추세이고, 그에 따라 언어와 API 의 경계가 모호해고 있습니다. 남이 작성한 코드를 읽다가 모르는 API 가 나오면 이해하기 위해 학습해야 하듯, 이런 새로운 언어 요소들도 마찬가지가 아닌가 생각해 봅니다.

S5: A Simple Standards-Based Slide Show System

S5는 XHTML, JavaScript, CSS 만으로 작성된 슬라이드 쇼 시스템입니다.
  • HTML 에 대한 기초적 지식만으로 작성
  • 하나의 파일로 슬라이드 쇼와 프린트용 버전을
  • 엄청나게 작은 용량
  • XHTML 을 통한 accessibility 지원
  • 스타일시트로 테마를 만들 수 있음
  • 여러 브라우저에서 동작

S5 로 작성된 소개 슬라이드는 S5 의 기능들을 시연하고 있습니다.

Java SPI 소개: Service Provider Interface

Java 1.3 에서 ‘SPI (Service Provider Interface)’ 라는 기능이 소개되었습니다. JDK 패키지 목록을 보면 ‘java.nio.charset.spi‘ 와 같이 ‘spi‘ 로 끝나는 패키지들이 여럿 보입니다. 여러 곳에서 알게 모르게 쓰이고 있지만 큰 관심은 두지 않고 있었는데, Lorentz 3.0 을 개발하면서 JAR만 클래스패스에 넣으면 자동으로 Converter 가 등록되게 하고 싶어 관심을 갖게 되엇습니다.

설명을 읽어 보면 특정한 역할을 하는 서비스 컴포넌트를 사용자가 구현할 수 있도록 해 주는 확장 메커니즘 (extension mechanism) 임을 알 수 있습니다. 이제 대한 자세한 설명은 JAR File SpecificationService Provider 섹션에서 찾아볼 수 있습니다:

1. JAR 의 META-INF/services/<프로바이더 인터페이스 클래스명> 텍스트 파일에 해당 인터페이스 (또는 추상 클래스) 를 구현하는 클래스들의 목록을 적습니다:

META-INF/services/net.gleamynode.conversion.ConverterPack:
net.gleamynode.conversion.convert.jmx10.Jmx10ConverterPack
net.gleamynode.conversion.convert.jdk14.Jdk14ConverterPack
......

2. SPI 를 사용하는 어플리케이션에서 Service.providers(Class providerType) 를 호출하여 구현 클래스들의 디폴트 컨스트럭터로 생성된 인스턴스들의 목록을 얻어낼 수 있습니다:

static {
   // Register all service providers when this class is loaded.
   registerServiceProviders();
}

public static void registerServiceProviders() {
   // Register all ConverterPack providers.
   for (Enumeration e = Service.providers(ConverterPack.class);
        e.hasMoreElements();) {
       ConverterPack p = (ConverterPack) e.nextElement();
       register(p);
   }

   // Register all Converter providers.
   for (Enumeration e = Service.providers(Converter.class);
        e.hasMoreElements();) {
       Converter c = (Converter) e.nextElement();
       register(c);
   }
}

만약 JDBC 도 이러한 방법으로 구현한다면 단순히 JAR 파일을 클래스 패스에 집어넣는 것만으로도 드라이버가 자동 등록될테고, 따라서 설정 파일에 JDBC 드라이버 클래스 이름을 궂이 적지 않아도 되지 않았을까 합니다.

주의: Service 는 JDK 공식 API 가 아닌, sun.misc 패키지가 제공하는 플랫폼 종속적 클래스입니다. 따라서 그 대안인 Jakarta Commons-Discovery를 이용하셔야 합니다.

줄지 않는 할 일 목록

요즘은 MS Outlook 으로 할 일 목록을 정리한다. 그리고 자기 전에 다음날 할 일을 정하고, 정한 항목들을 일정표에 드래그-앤-드롭해 일정표를 채워 넣는다. 조금 불편한 면이 있지만 내가 지금 당장 나에게 맍는 일정 관리 프로그램을 짤 수도 없으니 요긴하게 쓰고 있다.

그런데 이 할 일 목록이 도통 줄어들 생각을 않는다. 지금 등록된 할 일만 해도 28가지로, 아티클은 9편, 책은 9권, 개발 업무는 4가지, 그 외 6가지다. 여러 블로그와 개발 사이트를 매일 순회하면서 관심이 가는 자료나 책이 있으면 계속해서 추가해 넣기 때문에, 매일 두 세가지 일을 해결해도 그 끝이 보이지 않는 것이다. 그렇다, 늘어나지 않는 것이 천만 다행이다! (웃음)

많은 연봉을 받게 되더라도 좀 더 많은 연봉을 원하게 되는 사람의 심리처럼, 아마도 나의 할 일 목록은 탐욕스럽게 늘어날 것 같아서 뿌듯한 하루를 보내고 난 뒤에도 조금은 찝찝하다. 나의 분야를 잘 한정할 수 있게 되고, 그래서 눈에 띄게 줄어든 할 일 목록을 보게 될 날이 오면 좋겠다.

PS: 내가 원하는 일정 관리 프로그램에 대한 노트:

어떤 일을 얼마나 오래 수행했는지, 할 일 목록 증가량 대비 해결량 등을 통계화할 수 있다면 좋겠다. 그리고 할 일을 드래그-앤-드롭했을 때 단순히 할 일의 내용이 복사되는 것이 아니라, 연결 형태로 처리되어 해당 작업의 수행 이력이나 진행 상황도 유기적으로 업데이트 할 수 있으면 좋겠다.

Scalability 와 Performance, 그리고 언어 (PHP vs. Java)

‘스케일러빌러티’란 더 많은 시스템 자원 (e.g. 하드웨어) 을 제공하면 할 수록 전체적인 성능이 비례해 증가할 수 있는 어플리케이션의 특성을 말한다. 보통 어떤 어플리케이션이 스케일러빌러티가 있다면 그 어플리케이션은 ‘스케일러블’ 한 것이다. 그렇다면 언어와 스케일러빌러티는 어떤 관계가 있는가?

“없다.”

일반인들의 중요한 실수는 ‘스케일러빌러티 = 성능’ 이라고 단정하는 것이다. 그러나 이는 사실과 전혀 다르다. 스루풋이 매우 높은 어플리케이션이 자원을 더 할당해 주어도 스루풋이 더 높아지지 않는 경우가 있고, 스루풋이 낮은 어플리케이션이 자원을 더 할당해 주는 것에 비례해 높은 성능을 보여주는 경우도 있다. 이는 전적으로 그 어플리케이션이 어떻게 개발되었는가에 달려 있다. 언어 자체와는 별 상관 없다.

하지만 J2EE 라는 막강한 플랫폼을 고려한다면 개발 복잡성 측면에서 이야기가 달라진다. J2EE 는 미들웨어다 — 위에서 이야기한 문제들 (i.e. 엔터프라이즈 컴퓨팅의 문제들) 을 개발자들이 쉽게 해결할 수 있도록 표준화된 형태로 제공한다. 따라서 이렇다 할 표준화된 모듈 셋이 없는 PHP 에 비해, 표준화가 많이 진행되었고 컴포넌트 모델이 잘 확립된 J2EE 가 많은 개발자들이 협업하여 수행하는 큰 프로젝트에 더 적합하다.

한편 언어와 성능은 어떤 관계가 있을까?

“없다.”

어플리케이션의 성능은 일반적으로:

* 외부 자원의 조심스러운 사용 및 최적화
(e.g. 파일 입출력, 외부 시스템과의 소켓 통신, 데이터베이스 액세스)
* 공격적인 데이터 캐싱

에 의해 결정된다.

우선, 적절한 데이터베이스의 사용과 외부 자원의 조심스러운 사용은 당연히 언어와 전혀 관계가 없다. (물론 언어 위의 플랫폼과는 관계 있다.)

공격적인 데이터 캐싱은 주로 자바 진영에서 사용하는 가장 강력한 기술 중 하나다. 캐싱은 데이터베이스에서 한 번 읽었던 데이터를 메모리에 갖고 있다가, 추후에 필요한 경우 데이터베이스 접근 없이 재사용하는 기법이다. PHP 의 경우도 이를 인지하고 다양한 캐싱 모듈들이 개발되었고, 또 개발되고 있다. 따라서 이를 적절하게 사용하면 PHP 에서도 캐싱을 통해 성능을 극대화할 수 있다.

혹자는 스크립트 언어의 실행 성능을 의심스러워 하기도 한다. 하지만 일반적으로 우리가 말하는 성능은 지극히 상대적이다. 데이터베이스에서 데이터를 가져오는 데 0.3 초가 걸렸고, 스크립트 언어를 해석/실행하는 데 0.05 초가 걸렸다고 가정해 보자. 자바의 경우 스크립트 언어의 해석이 불필요하므로 실행하는데 0.02 초가 걸렸다면, PHP 는 0.35초, 자바는 0.32 초가 걸린 셈이다. 이 수치는 PHP 가 자바에 비해 약 9% 정도 밖에 느리지 않다는 결론에 이른다. 즉, 프로파일링 결과 발견한 병목 지점 (i.e. 데이터베이스) 튜닝에 시간을 투자하는 것이 훨씬 이득이다. (만약 9% 조차 용인하기 힘들다면 ZendOptimizer 와 같은 최적화 모듈을 탑재해 PHP 구문 해석에 소요되는 시간을 몇 배 이상 절감시킬 수 있다.)

여러분의 비즈니스 어플리케이션이 느리게 반응하는가? 그것은 그 어플리케이션이 Java나 PHP 로 짜여졌기 때문이 아니다. C/C++ 로 다시 짜야 한다는 신호도 아니다. 바로 프로파일링하고 병목 지점을 제거하라는 신호 외에 다름 아니다.