CNS Story

사람이 읽기 쉬운 코드

2015.07.09 09:37



LG CNS의 신입사원 기술교육은 힘든 것으로 유명합니다. 물론 힘든 만큼 빠르게 많은 것을 얻을 수 있습니다. 대학교 때 컴퓨터를 전공하지 않은 신입사원들도 얼마든지 ‘코딩의 신’이 될 수 있게 만들어 주는 마법의 교육이죠. 하지만 저는 2011년 당시 컴퓨터 관련 전공자들을 대상으로 신설된 ME(Mobile Embedded) 과정에 배정되었고, 그만큼 교육의 난이도도 더 높았습니다.

 

그 당시에 회사 안팎에서 훌륭한 강사님들이 오셨고 다양한 내용을 배울 수 있었습니다. 대학교에서 배운 것에서 훨씬 심화된 내용이었습니다. 이후 해당 과정의 실습강사로 일할 기회가 있었고, 다시 한번 기본기를 탄탄하게 다질 수 있었는데요. 그 시기에 저의 흥미를 불러 일으켰던 실습문제 하나를 소개하고자 합니다.

 

물건 가격을 계산해서 화면에 출력하는 문제로, 숫자의 경우 세자리 마다 콤마(,)를 출력 해줘야 하는 조건이 있었습니다. 이미 존재하는 API[각주:1] 를 이용해서는 안되고, 수강생이 직접 콤마를 문자열에 추가해야 했죠.

 

그때 수강생 중 한 명이 자신만의 창의적인 방법으로 코드를 짰다면서 신나했습니다. 일반적인 방식대로 콤마를 뒤에서부터 채우지 않고 앞에서부터 채워 나가는 코드였고, 누구도 시도하지 않았던 방식이었습니다. 아래는 그 수강생이 짠 코드입니다. 




물론 개개인의 생각에 차이가 조금 있을 수 있지만, 읽기 좋은 코드라는 관점에서 한번 살펴 볼까요?


메소드명 짓기


1번 라인의 ’commaForm’이라는 메소드 명부터 살펴보겠습니다. 여러분은 이 메소드[각주:2]명을 보고 어떤 기능을 할 지 유추할 수 있으신가요? 콤마…서식… 콤마와 관련이 있다… 정도는 알겠지만 구체적인 기능을 유추하기는 힘드시죠? 메소드명 만으로 기능을 쉽게 유추할 수 있다면 누구나 이름만 보고 그 메소드의 기능을 금방 파악할 수 있을 것입니다. 프로그램의 크기가 작은 경우에는 문제가 없겠지만, 기업용 애플리케이션과 같이 방대한 양의 메소드를 여러 개발자가 개발하는 경우에는 가독성이 훨씬 중요해 집니다. 유사한 이름의 메소드들이 많이 나올 수 있고, 여러 명의 개발자가 함께 프로그램을 작성하기 때문이죠.

 

위의 메소드명  ‘commaForm’을 ‘insertCommaEveryThirdPosition’으로 바꾸면 어떨까요? 이렇게 하면 메소드명만 보고도 기능을 한번에 알 수 있습니다. 보통 메소드는 데이터 가공 등의 기능을 수행하기 때문에 동사형으로 이름을 짓는 경우가 많습니다. 자바(Java)에서는 「동사 + 명사」 형태로 짓는 것을 권장합니다.


제가 작성한 메소드명이 너무 길다고 생각하시나요? 물론 너무 길면 가독성이 떨어지죠. 메소드명을 줄여야 할지의 기준은 ‘어떤 이름이 알아보기 쉬운가’ 입니다. 읽기 좋고 메소드의 역할이 잘 전달 된다면 길어도 문제가 없습니다. 너무 길어서 읽기 힘들다면 프로젝트에서 약어 규칙을 정하고, 긴 단어들은 약어로 사용하면 더 읽기 쉽게 작성할 수 있습니다.



변수명 짓기


변수명 역시 아주 중요합니다. 예전에 변수명 짓는 것을 강조했었던 ’건강한 소프트웨어’에 대한 강의를 들은 적이 있습니다. 하나의 프로그램에는 수 많은 변수가 있고 위에서 설명한 메소드명과 마찬가지로 가독성이 아주 중요합니다. 


그런 관점에서 수강생이 작성한 <코드1>을 다시 보겠습니다. 4번 라인을 보면 String 형의 변수 이름을 ‘tmp’로 선언하였습니다. 그러나 ‘tmp’라는 이름은 변수의 역할을 충분히 나타내지 못합니다. 이 경우, Integer 형의 ‘num’ 변수의 String 버전이므로 ‘strNum’을 추천합니다.

 



알고리즘 구성


다음은 알고리즘입니다. 수강생은 9번에서 13번 라인까지가 콤마를 넣을 위치를 검사한 뒤에 Char 배열에 콤마가 포함된 숫자의 문자열을 넣는 것으로 작성했습니다. 3이라는 숫자를 보고 “3자리마다 넣겠구나”라고 예측은 정도는 할 수 있습니다. 하지만 다른 사람들에게 이 코드를 보여주니 앞에서부터 콤마를 넣는다는 것을 잘 파악하지 못했습니다. 


또 뒤에서 4자리마다 콤마를 찍는 것으로 과제가 변경되었을 때 코드에 있는 숫자 3을 4로 바꾸기만 하면 되는지 한눈에 알 수 없습니다. 그래서 저는 코드를 머릿속으로 실행해 봤지만 앞에서부터 숫자와 콤마를 채워나가는 배열이라 결과 예측이 쉽지 않았습니다. 헷갈리는 이유는 보통 사람이 생각하고 행하는 방식과 알고리즘이 반대였기 때문입니다. 


그러면 일반적인 방식대로 수정해볼까요? 사람은 숫자에 3자리마다 콤마를 찍을 때 보통 뒤에서부터 찍습니다. 아래 코드를 한 번 보시기 바랍니다.



<코드2>는 콤마를 뒤에서부터 채워 나갑니다. 일반적인 방식이죠. 콤마를 넣을 위치를 검사하는 조건도 ‘cnt'라는 변수를 하나 만들어서 직관적으로 알아 볼 수 있도록 보완하였습니다. 여기서 의문을 가지는 사람이 있을 수 있습니다. 변수 하나가 더 늘어나서 성능이 나빠진게 아니냐는. 17번 라인도 <코드1>과 비교해 trim() [각주:3]이라는 메소드가 추가되었습니다. 


이 두 가지 차이가 과연 효과적이냐는 문제는 성능과 가독성의 관점에서 판단할 수 있습니다. 먼저 cnt 변수의 경우 정보를 저장 할 수 있는 공간이 하나 늘어나 성능면에서는 손해지만, 코드를 알아보기가 훨씬 쉬워졌습니다. 


추가된 trim()의 역할은 Char 배열 앞의 공백은 제거하는 것입니다. 적당히 큰 배열을 할당한 후, 뒤에서부터 숫자와 콤마를 채워 넣고 숫자가 다 작성되었다면 빈 공간을 지우면 끝! 하지만 trim()이라는 메소드 안에서 루프(loop)를 통해 배열을 돌며 공백을 검사해야 하니 성능 면에서는 <코드1>보다 손해입니다. 반면, 앞에서부터 들어갈 인덱스를 정확하게 계산해 낼 필요가 없기 때문에 가독성은 훨씬 좋아졌습니다. 보통 사람이 생각하는 자릿수 계산방법과 같기 때문이죠. 


그렇다면 성능, 가독성 중에 무엇이 우선일까요? 먼저 성능만 뛰어나게 작성했다고 가정해 봅시다. 대부분 가독성은 무너지기 마련입니다. 가독성이 무너지는 이유는 성능을 위해서 한 루프 안에서 많고 축약된 코드를 작성하는 경우가 많기 때문입니다. 이때 고객이 기능을 변경해달라고 요청한다면, 가독성이 낮은 코드는 수정이 어렵습니다. 또한 새로 작성한 코드가 성능이 나오지 않을 때 어느 부분이 문제인지 찾아내기도 어렵습니다. 


하지만 가독성 위주로 코드를 작성한다면, 코드가 역할 별로 잘 나눠져 있기 때문에 어디가 문제인지 알아내기도 쉽고 가독성도 높아 개선하기도 쉽습니다. 「리팩토링」의 저자인 유명 프로그래머 ‘마틴 파울러’(Martin Fowler)는 성능 문제는 대부분이 한 지점에서 나온다고 했습니다. 즉 코드가 메소드나 클래스 별로 잘 나누어 작성되었다면 어느 지점이 문제인지 더욱 알아내기 쉽다는 것입니다. 물론 원치 않는 성능이 나올 경우에 가독성을 포기하고 성능을 높여야겠지만요. 하지만 부득이한 경우가 아니라면 가장 먼저 고려해야 할 것은 가독성이라고 말하고 싶습니다.

 

개개인 마다 이견이 있을 수 있지만 여러 사람이 공동으로 참여하는 대형 프로그램은 가독성이 중요하다는 것이 중론인 것 같습니다. 가독성의 기준에 대한 논쟁이 있을 뿐이죠. 물론 가독성 위주로 코딩하는 습관이 글이나 말로만 들어서만은 크게 공감되지 않을 수 있습니다. 프로젝트에서 다른 사람이 작성한 복잡한 코드를 맡게 되면 한숨이 나올 때가 있습니다. 어디를 수정해야 할지 막막하고 이 곳을 수정하면 다른 곳도 영향이 미치지 않는지 파악하기 어려울 때면 참 힘듭니다. 따라서 코드를 작성하는 본인 뿐만 아니라 다른 개발자를 위해서도 읽기 쉽게 작성하는 것이 중요합니다.

 

신입사원 혹은 컴퓨터 관련 전공 학생들도 읽기 쉬운 코드를 먼저 염두해 둔다면 더 빨리 훌륭한 프로그래머가 될 수 있을 것입니다. 마지막으로 뛰어난 프로그래머 두 분의 말로 글을 마무리할까 합니다. 


컴퓨터가 이해할 수 있는 코드는 어느 바보나 다 짤 수 있다. 좋은 프로그래머는 사람이 이해할 수 있는 코드를 짠다. - 마틴 파울러(Martin Fowler) -

 

프로그램은 사람이 이해할 수 있어야 한다. 실행은 부차적인 문제다. - 도널드 크누스(Donald Knuth)-


글 ㅣ LG CNS 의료솔루션2팀 



  1. API(Application Programming Interface): 운영체제와 응용프로그램 사이의 통신에 사용되는 언어나 메시지 형식 [본문으로]
  2. 메소드(Method): 메시지에 따라 실행시킬 프로시저로서 객체 지향 언어에서 사용되는 것 [본문으로]
  3. trim(): space ,tab, new line 과 같은 공백을 제거하는 메소드 [본문으로]
Posted by IT로 만드는 새로운 미래를 열어갑니다 LG CNS

댓글을 달아 주세요

위로