본문 바로가기

잡담

어려운 소스코드를 이해할 것인가 vs 어려운 소스코드를 쉽게 수정할 것인가

이번 프로젝트를 진행하면서 느낀 점이 있다면 어려운 소스코드를 이해할 것인가 아니면 어려운 소스코드를 쉽게 수정할 것인가에 대한 부분이다.

 

프로젝트에 투입되어 소스코드를 분석하다 보면 덩어리가 아주 큰 녀석들의 경우 구조가 제대로 잡혀있지 않은 소스코드들이 보인다.
내가 맡았던 소스코드도 구조가 엉망이었던 소스코드였다.
소스코드의 총 라인은 대략 1만 줄 정도 되었던 것으로 기억하고 있다. 변수의 경우에는 모두 다 전역 변수로 선언되어 있었고 짧은 소스마저 함수로 만들어져 있어서 읽는데 상당한 혼란을 줬다.

 

 

1.전역변수의 문제점

흔히 개발 기초 서적들을 보면 전역변수를 쓰지 말고 지역변수를 사용하라는 글을 본 적이 있을 것이다.
기초 서적의 경우 소스코드가 몇 줄 안되기 때문에 전역변수로 사용하거나 지역변수로 사용하거나 큰 차이점을 못 느끼게 된다.
오히려 전역변수가 접근이 쉬워서 더 좋다고 느끼는 사람도 있을 것이다. 나도 학부생 시절에는 그렇게 생각했다.
하지만 소스코드가 길어질 경우 상당한 문제를 일으키게 된다.
1만 줄짜리 소스코드가 있다고 가정했을 때 7100번 라인에서 전역 변수를 가지고 어떤 연산을 하고 있다고 생각해 보자.
이 변수가 무슨 값인지 확인하기 위해 전역변수가 선언되어 있는 대략 100번째 라인으로 이동을 해야 한다.
100번째 라인으로 갔다가 다시 7100번째 라인으로 돌아와 다시 소스코드를 읽어야 하는데 자기가 읽던 소스코드 라인이 7100번이라고 외워야 한다. 그리고 단축키로 바로 7100번 라인으로 이동을 하면 그나마 괜찮은데 단축키를 잘 모르는 개발자들의 경우 드래그하여 다시 7100번 라인으로 이동한다. 시간을 낭비하게 된다. 심지어 드래그하여 7100번 라인으로 이동하는 동안 방금 전에 봤던 전역변수의 값이 어떤 값이 담겨있었는지 까먹는 경우도 빈번히 일어난다.
만약에 지역변수를 사용했었다면
7080번 라인쯤에 지역변수가 선언되어 있었을 것이고 그 변수에 어떤 값이 담겨있는지가 작성되어 있었을 것이다. 그렇다면 7100번 라인에서 100번 라인으로 이동할 필요 없이 소스코드를 읽어내려갈 수 있다.

 

 

2.기능을 함수로 만들어라의 함정

이 내용도 프로그래밍 기초 서적에서 볼 수 있다. 기능을 함수로 만들어라라는 내용이 담겨 있다 보니 한 줄짜리 소스코드마저 함수로 만드는 경우가 있다. Java의 경우 콘솔을 출력할 때 대표적으로 System.out.println(); 를 사용하게 되는데 이 한 줄짜리 소스코드를 함수로 만든다.

public static void print(String str){

    System.out.println(str); 

}

 

print("안녕");

 

이런 식의 소스코드다. 다른 개발자가 소스코드를 읽다가 print();를 만나게 되면 이 print()가 무슨 기능을 하는지

메서드 선언부까지 이동하여 소스를 읽고 다시 읽고 있던 소스코드로 돌아와야 한다.

 

areaCode = str.substring(0,3); //지역번호

custNo     = str.substring(3,10); //고객번호

custSeq    = str.substring(10,14); //고객일련번호

와 같은 기능을 하는 소스코드가 있다고 가정하자.

 

굳이 저 코드를

public static String getAreaCode(){

        return str.substring(0,3);

}

 

public static String getCustNo(){

        return str.substring(4,10);

}

 

public static String getCustSeq(){

        return str.substring(10,14);

}

와 같은 형식으로 선언을 하고

areaCode = getAreaCode();

custNo     = getCustNo();

custSeq    = getCustSeq(); 

와 같이 사용한다.

 

그러면 개발자는 소스코드를 읽다가 함수가 선언된 부분으로 이동하여
해당 함수가 어떤 기능을 하는지 확인을 하고 다시 읽고 있던 소스코드로 돌아와야 한다.
심지어 소스코드를 읽어내려가는 동안 해당 함수가 Strin의 몇 번째 자리까지 잘라내는지도 외우고 있어야 한다.

 

areaCode = str.substring(0,3); //지역번호

custNo     = str.substring(3,10); //고객번호

custSeq    = str.substring(10,14); //고객일련번호

이렇게 작성해놓으면 String을 몇 번째 자리까지 잘라내는지 외울 필요도 없고 함수 선언부로 이동할 필요도 없다.

 

 

3.어려운 소스코드를 이해할 것인가

어려운 소스코드를 이해하기란 쉽지 않다.

나의 경우 1만 줄짜리 소스코드를 이해하기 위해 대략 3개월을 들였다. 

3개월 동안 저 소스코드를 붙잡고 읽었지만 읽는 순간에만 어느 정도 기억을 할 뿐 며칠 뒤에 다시 보면 이전과 똑같이

소스코드를 처음부터 읽고 다시 이해하는 것의 반복이었다. 어떤 어떤 기능을 한다정도는 머릿속에 남았지만

소스코드의 흐름은 계속 처음부터 다시 봐야 했다.

소스코드가 개판이다 보니 소스코드를 읽다가 함수가 나타나면 이 함수가 무슨 기능을 하는지 다시 확인하기 위해 함수 선언부로 이동하여 함수의 기능을 확인하고 다시 소스를 읽으로 돌아오는 과정의 반복이었는데 시간 낭비가 어마 무시 했다.

이대로는 도저히 안되겠다는 생각이 들었다.

AS-IS의 소스코드 그대로 사용하여 개발을 했지만 AS-IS 자체에도 문제가 있는데 그냥 운영에서 사용하는 경우가 제법 있고 내가 AS-IS대로 개발하는 과정에서 놓친 부분이 있다면 과연 그 부분을 찾아낼 수 있을까라는 생각이 들었다.

내가 내린 판단은 "이 소스코드를 그대로 사용했을 때 문제가 터지면 수습하는 것은 불가능하다"였다.

그리고 소스코드를 리팩토링하기 시작했다.

 

4.어려운 소스코드를 쉽게 수정할 것인가

나의 경우에는 남발된 전역변수와 함수가 문제였다.

이런 경우 비교적 안전하게 소스코드를 수정할 수 있다.

그래서 이 남발된 전역변수와 함수들을 수정하기로 했다.

제일 첫 번째 작업은 전역변수로 사용할 필요가 없는 변수들을 지역변수로 만드는 것이었다.

그 방법은 아래와 같다.

    1.우선 선언되어 있는 전역변수들을 하나하나씩 주석 처리를 한다.

    2.이클립스에 빨간 줄이 표시가 된다.

    3.빨간 줄이 1개만 뜬다면 전역변수로 사용할 필요가 없다.

    4.전역변수를 지우고 빨간 라인이 표시되는 함수로 이동하여 지역변수로 만든다.

이 작업이 끝난 뒤에 남발된 함수들을 정리하기로 했다.

    1.함수들의 목록을 뽑아낸다.

    2.해당 함수가 한 번만 호출되었는지 확인한다.(해당 함수가 한 번만 호출되었다면 함수로서 사용할 필요가 없는 함수인 경우가 많았다)

    3.한번만 호출된 함수라면 그 함수를 삭제하고 함수의 기능을 함수 호출부로 이동하여 사용한다.

    4.a()->b()->c()->d()와 같이 함수에서 함수를 호출하고 그 함수가 함수를 호출하는 함수를 찾는다.

    5.a(),b(),c(),d()함수를 하나의 함수로 합친다.

위와 같은 방식으로 소스들을 수정했다.

그렇게 하여 대략 1만줄이 되던 소스코드는 3천줄로 줄어들게 되었다.

3천줄로 줄이고 나서 소스코드를 읽어보니까 소스코드가 훨씬더 수월하게 이해되기 시작했다.

 

5.결과

처음에 엉망진창이었던 소스코드는 엄청난 시간을 빼앗아갔고 시간을 투자한 것에 비해서 소스코드에 대한 이해도는 턱 없이 낮았다.

불필요한 소스코드를 제거하고 난 뒤에는 소스코드의 이해가 쉬웠다. 소스코드의 이해가 쉬워져서 AS-IS의 문제점도 파악하기 쉬워졌고 그 부분을 수정할 수 있게 되었다. 전역변수와 남발된 함수만 제거를 해도 엄청난 효과를 가지고 온다.

기존 as-is시스템의 경우 스텍오버플로우가 발생했는데 그 부분도 해결을 할 수 있었고 대외기관으로부터 받은 데이터를 처리하는데 8시간 이상 걸렸는데 그 부분도 20분 이내에 처리되게 하도록 개선을 했다.

지금 돌이켜보면 소스코드를 정리하지 않았다면 이러한 개선은 불가능했을거라고 생각된다.

로버트 마틴C, 켄트백, 마틴파울러와 같이 유명한 저자들이 쓴 책을 읽어보면 개발자는 소스코드를 쓰는데 시간은 얼마 사용하지 않는다고 한다. 소스코드를 읽는데 시간을 많이 사용한다. 아주 공감되는 말이다.

어려운 소스코드를 이해하는 것 보다는 어려운 소스코드를 쉽게 수정하는 것을 추천한다.