코딩 시간과 코드 품질

내 이 세상 도처에서 쉴 곳을 찾아보았으나, 마침내 찾아낸, 컴퓨터가 있는 구석방보다 나은 곳은 없더라.

코딩 시간과 코드 품질

시간이 충분하면 좋은 코드를 작성할 수 있지만, 코드 품질 따지느라 개발 기간이 늘어지는 것 보다는 빨리 개발해 서비스를 시작하는 게 중요하다는 주장을 볼 수 있다. 옳은 말이다. 요즘 같이 비즈니스 환경이 급변하는 세상에 속도가 중요한 요소임엔 틀림 없다. 그러나 코딩에 들이는 시간과 코드 품질이 비례한다는 주장에는 동의하지 않는다.

간단한 예를 살펴보자. MS 워드에 자동고침(AutoCorrect)이란 기능이 있다. 입력한 단어가 특정 문자열과 일치하면 미리 정의한 대체 문자열로 바꿔주는 기능이다. 예전에, 그러니까 JDK 버전이 1.2, 1.3이었던 시절, Java로 오피스를 만드는 회사에서 일했다. 회사에서 처음 맡은 일 중 하나가 자동고침 모듈을 만드는 일이었다. 정확히 말하면, 새로 만드는 것은 아니었고 전임자가 만든 모듈을 인계받아 버그를 수정하고 기능을 추가하는 일이었다.

자동고침은 문자열이 주어지면 대체 문자열을 찾아 리턴하면 되는 아주 단순한 모듈이다. 항목을 추가, 삭제, 저장할 수 있어야 하므로 이를 위한 다이얼로그도 있어야 한다. 자동고침 항목을 저장하는 데는 여러 방법이 있을 수 있겠지만, 그 당시에는 텍스트 파일에 다음과 같은 구조로 저장하고 있었다.

abbout
about
abotu
about
abouta
about a
aboutit
about it
...

홀수 행은 키에 해당하고 짝수 행은 대체할 문자열(값)에 해당한다. 행이 0부터 시작한다고 생각하면 짝수 행이 키, 홀수 행은 값이 될 것이다. 프로그램이 파일을 읽을 때는 문제가 없겠지만, 항목을 손으로 편집해야 할 때는 신경을 써야 했다.

키와 값 사이에 구분자를 넣어 키, 값을 한 행에 저장하는 방법도 생각할 수 있다. 그렇게 하면 파일 구조를 눈으로 파악하기가 쉬워질 테지만, 구분자로 뭘 쓸지 고민을 해야 한다. 입력 문자열이나 대체 문자열에 구분자와 같은 문자가 나오면 파일을 읽을 때 오류가 발생할 것이다. 그런 점을 고려하면 위 파일 구조가 꼭 나쁘다고만 할 수는 없을 것이다.

놀라웠던 것은 위 파일을 읽는 코드였다. 오래 전 일이었지만 하도 어이가 없었기에 지금도 기억하고 있다. 그때는 Java에 try-with-resources는 물론 제너릭조차 없었지만, 핵심 로직을 쉽게 알아볼 수 있도록 현대 Java의 기능을 활용해 코드를 옮기면 다음과 같다.

private Map<String, String> items = new HashMap<>();

// 개선 전 (원래 코드)
private void init() throws IOException {
  try (BufferedReader r = new BufferedReader(new FileReader(...))) {
    int line = 0;
    String str, key = null, val = null;
    while ((str = r.readLine()) != null) {
      if (line % 2 == 0) {
        key = str;
      } else {
        val = str;
        items.put(key, val);
      }
      line++;
    }
  }
}

readLine()으로 파일을 한 줄씩 읽을 때마다 line을 1씩 증가시킨다. line이 짝수면 파일에서 읽은 값을 key에, 홀수면 파일에서 읽은 값을 val에 할당한다. 그리고 line이 홀수일 때 맵에 key, val을 넣는다. 동작하긴 하지만, 단순한 작업을 복잡하게 처리했다. 이렇게 복잡하게 생각할 이유가 없다.

어차피 키와 값은 항상 쌍이어야 하므로, 다음과 같이 readLine()을 두 번 연달아 호출하면 코드가 단순해진다. line을 증가시키면서 홀수인지 짝수인지 구분해 if로 분기할 필요가 없다.

// 개선 후
private void init() throws IOException {
  try (BufferedReader r = new BufferedReader(new FileReader(...))) {
    while (true) {
      String key = r.readLine();
      String val = r.readLine();
      if (key == null || val == null) break;
      items.put(key, val);
    }
  }
}

위 두 코드를 살펴보자. 코드를 개선 후와 같이 작성하는 시간이 개선 전과 같이 작성하는 시간보다 오래 걸릴까? 내가 보기엔 개선 전과 같이 작성하는 게 시간이 더 걸릴 것 같다. 로직도 복잡하고 길이도 길기 때문이다.

시간을 탓하며 거지 같은 코드를 작성하는 사람이라면 시간이 충분해도 아름다운 코드를 작성하지 못할 것이다. 새로운 기술과 아이디어를 익히고 어떻게 하면 더 좋게 만들 수 있을까 고민하는 사람만이 좋은 코드를 작성할 수 있는 능력을 얻을 수 있다. 그런 능력이 있는 사람이라면 시간이 촉박해도 거지 같은 코드를 양산하지 않을 테고, 시간이 충분하면 아름다운 코드를 작성할 수 있을 것이다.