2014년 6월 6일 금요일

다언어 프로그래밍 2014

예전에 다언어 프로그래밍이란 주제로 블로그에 글을 쓴 적이 있다. 그 글에서는 같은 일을 하는 프로그램을 세 가지 언어로 짠 것을 비교했었다1:

그루비:

def number=0
new File (args[0]).eachLine { line ->
    number++
    println "$number: $line"
}

C#:

using System;
using System.IO;

class LineNumbers {
    static void Main(string[] args) {
        int number = 1;
        Array.ForEach(File.ReadAllLines(args[0]),
                      line => Console.WriteLine("{0}: {1}", number++, line));
    }
}

자바:

package com.nealford.polyglot.linenumbers;

import java.io.*;
import static java.lang.System.*;

public class LineNumbers {
    public LineNumbers(String path) {
        File file = new File(path);
        LineNumberReader reader = null;
        try {
            reader = new LineNumberReader(new FileReader(file));
            while (reader.ready()) {
                out.println(reader.getLineNumber() + ":"
                        + reader.readLine());
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException ignored) {
            }
        }
    }

    public static void main(String[] args) {
        new LineNumbers(args[0]);
    }
}

지금 봐도 자바 코드가 약간 더 길다. ^^

그리고 나서는 C#이 여러 모로 제일 편하니까 그냥 하나의 언어로 통일하는 것은 어떨까하는 물음으로 글을 끝맺었었는데, 그로부터 5년 동안 나는

C#보다 자바를 더 많이 쓰게 되었다.

아…

물론 과장을 좀 보태서 말이다. ^^ 그리고 여러가지 일들을 파이썬으로 하는 법도 익히게 되었다. 결과적으로 나는 글에서의 바램과는 정반대로 5년 사이 C/C++/C#/자바/파이썬 다언어 프로그래머가 된 것이다.

2014년에도 다언어 프로그래밍의 중요성은 여전히 유효할까? 아이러니컬하게도 이건 그때보다도 더 아니라는 생각이 드는데, 왜냐하면

C#이 그때보다 더 강력해졌다.

dynamic

C# 4.0부터는 dynamic 타입이라는 게 생겼다. 이 타입을 쓰면 컴파일 타임에 하던 타입 체크를 런타임으로 미루게 된다. 예를 들어 dynamic 타입을 사용한 아래 C# 코드는

class Dog {
    void Run() { }
}

class Robot {
    void Run() { }
}

static void Do(dynamic obj) {
    obj.Run();
}

Do(new Dog());
Do(new Robot());

어떤 타입이든 void Run()을 구현하기만 하면 Do()의 파라미터가 될 수 있다. 굉장히 간단한 규칙이고, 어떻게 보면 안 되는 게 더 이상해 보이지만 C# 4.0 이전이나 일반적인 정적 타입 언어로는 불가능하다. DogRobot 사이에 공통 인터페이스가 없기 때문이다.

async/await

C# 5.0부터는 복잡하고 어려웠던 비동기 프로그래밍을 혁명적으로(!) 쉽고 편하게 짤 수 있게 되었다. 예를 들어 아래 같은 코드는

void FetchWebPage(string uri) {
    var client = new WebClient();
    string page = client.DownloadString(uri);
    Console.WriteLine(page);
}

client.DownloadString(uri)를 호출할 때 프로그램이 잠깐 멈추게 된다. 웹 사이트에서 페이지를 가져오는데 시간이 걸리기 때문이다. 최악의 경우—회선이 느리거나 사이트에 문제가 있는 등—페이지 다운로드에 수십 초가 걸렸다면, 프로그램도 그 시간 동안 멎어 있게 된다.

이런 문제는 현실에서 자주 일어나기 때문에 당연히 개발자들은 해결책을 마련해 두어야 한다. 한가지 방법은 저런 코드를 별도의 쓰레드로 분리하는 것이다:

handler.post(new Runnable() {
    @Override
    public void run() {
        WebClient webClient = new WebClient();
        string page = client.DownloadString(uri);
        text.setText(page);
    }
});

안드로이드 개발자라면 이런 코드들이 실제로 얼마나 개떡(?)같은지 잘 알고 있을 것이다. 코드를 좀 덜 지저분하게 만들기 위해 핸들러 대신 AsyncTask 같은 걸 쓰기도 하는데, 근본적으로 큰 차이는 없다.

두번째는 C/C++/자바에서 많이 쓰는 방법인데, 정교하게 설계된 비동기 I/O 프레임웍을 쓰는 것이다. 이 경우의 단점은 간단한 코드는 그냥 쓰레드 하나 만들어 돌리는 것보다 더 복잡해진다는 것이다. 물론 API를 배우고 쓰는 자체도 만만치 않다.

반면 C# 5.0에서는 그냥 단어 몇개 붙여주는 것으로 비동기 프로그래밍이 가능하다:

async void FetchWebPage(string uri) {
    var client = new WebClient();
    string page = await client.DownloadStringAsync(uri);
    Console.WriteLine(page);
}

FetchWebPage()는 호출되면 평상시처럼 실행되다가 await 지점에서 client.DownloadStringAsync(uri)을 호출하고 곧바로 리턴한다. 바로 이 점이 이전의 코드와 결정적으로 다른 점이다. 이전의 동기 코드에선 client.DownloadString(uri)이 리턴할 때까지 이 지점에서 무한정 머물러 있지만, 비동기 코드에선 FetchWebPage()를 호출한 곳으로 바로 리턴한다. 그리고 나서 얼마간의 시간이 흘러 client.DownloadStringAsync(uri)가 웹에서 가져온 페이지를 리턴하면 뒷부분의 남은 코드가 계속 실행된다. 별도의 쓰레드를 만드는 것, 리턴값을 보관하는 것, 남은 코드의 실행을 재개하는 것, 중간에 발생할 수 있는 예외 처리 등은 컴파일러가 자동으로 코드를 만들어 준다.

REPL

그렇지만 C#이 유일한 언어가 되려면 아직 넘어야 할 산이 많이 남아 있다. 그중 하나는 REPL의 부재다. REPL이란 read–eval–print loop의 약자로 파이썬 대화형 환경 같은 걸 말한다. 컴파일 과정없이 즉석에서 코드를 입력하고 결과를 바로 알 수 있기 때문에 아주 편리하다.

그런데 사실 C#에도 이미 REPL이 있다. 제일 잘 알려진 것은 LINQPad:

굉장히 강력하고 편리하니 C# 개발자라면 꼭 써보기 바란다.

두번째는 Mono 프로젝트의 CsharpRepl이 있는데 LINQPad 만큼 좋진 않은 것 같다(몇번 안써봄).

다만 문제는 이 두 REPL이 마이크로소프트에서 만든 게 아니다 보니 비주얼 스튜디오와 연동이 안된다는 것이다. 마이크로소프트에서 만든 REPL은 차기 비주얼 스튜디오에 포함될 예정으로 있다.

보일러플레이트 코드

지난번 글에서도 다루었지만 C#이 자바보단 보일러플레이트가 훨씬 적지만 다른 언어에 비하면 여전히 너무(!) 많다. 이 문제의 해결은 전적으로 C# 언어 개발팀에 달려 있는데, 어떻게 될지 모르겠다.

그래서…?

쓰고 보니 C# 하나로는 역시 부족하다. ^^ C#과 파이썬 조합이 제일 무난해 보인다. 따라서 2014년에도 다언어 프로그래밍의 중요성은 여전히 유효한 것으로 최종 결론.


  1. 그루비와 자바 코드는 The ThoughtWorks Anthology 책에서 가져 왔다.

댓글 없음:

댓글 쓰기

댓글을 입력하세요. 링크를 걸려면 <a href="">..</a> 태그를 쓰면 됩니다. <b>와 <i> 태그도 사용 가능합니다.

게시한지 14일이 지난 글에는 댓글이 등록되지 않습니다. 날짜를 반드시 확인해 주세요.