Clean Code Guide For Beginners
서론
클린 코드란 읽고 이해하기 쉬운 코드베이스 를 의미합니다. 우리는 개발 과정에서 개발만 하는것이 아닌 유지보수 활동도 같이합니다. 개발하는 동안 혹은 서비스 오픈 후에도 요구사항은 계속 바뀌며, 바뀐 요구사항을 적용하기 위해 자신의 코드를 수정하는 행위 자체가 유지보수하는 것입니다. 따라서, 유지보수성을 생각하는 개발자라면 클린 코드에 관심을 가져야 합니다.
이번 포스팅에서는 초보자들이 쉽게 클린 코드를 실천 할 수 있도록 몇 가지 방법과 나쁜 코드로 인해 겪은 경험 사례들을 소개해 드리고자합니다.
나쁜 코드
책 “클린 코드” 에서는 나쁜 코드를 다음과 같이 설명합니다.
나쁜 코드에 발목잡혀 고생하는 현상을 고행(wading)이라고 부른다.
안 돌아가는 프로그램보다 돌아가는 쓰레기가 좋다고 자기합리화를 하곤한다. 그리고 나중에 정리하겠다고 다짐하지만, 나중은 결코 오지 않는다.
빨리 가는 길은, 언제나 코드를 깨끗하게 유지하는 습관이다.
저 또한 빨리 가는 길은, 언제나 코드를 깨끗하게 유지하는 습관이라는 것에 완전히 동의합니다.
첫 회사(SI)에서 일하면서 나쁜 코드가 주는 영향에 대해 너무 많은 경험을 했습니다. 의미를 알기 힘든 변수, 함수명이나, 잘 못된 설계, 코드를 깨끗하게 작성해야겠다라는 마음 가짐없이 작성한 나쁜 코드들을 보면 일단 짜증부터 밀려옵니다. 분석하는데 시간이 상당히 소요될 것을 알기 때문입니다.
또한, 나쁜 코드는 중복 코드가 여러군데 존재할 수도 있고 테스트가 제대로 되어있지 않으면 기존 프로그램을 유지보수하는데에도 상당한 노력과 스트레스가 수반됩니다.
나쁜 코드로 인해 생산성과 유지보수성이 떨어진다는 것은 비용 문제 와도 직결됩니다. 대부분의 SI, Agency 회사에서 클린코드에 대한 중요성을 인지하지 못하는 회사 대표나, 개발팀들은 고객의 요구사항만을 빠르게 만드는데에만 집중합니다. 포커스가 개발 속도에만 치중되어있고, 대부분 유지보수성과 개발 후 코드를 검토하고 다듬는 과정에 대해서는 고민하지 않습니다.
개발 속도에만 집중하는 회사에서는 나쁜 코드로 인해 많은 비용을 손해보게됩니다. 프로젝트의 성향 마다 그 비용의 차이가 커지는데, 특히 복잡하거나, 요구사항이 자주 바뀌고, 연계, 프로젝트 기간이 짧은 프로젝트일 수록 그 비용이 커집니다.
경험상 대표적으로 정부사업들이 이에 해당합니다.
따라서, 저러한 성향을 띄는 프로젝트를 진행할 때에는 처음 부터 꼼꼼하게 서버 검증도 하고 코드를 깨끗하게 작성하고 유지하려고 해야, 나중에 유지보수나 요구사항이 바뀌어도 인건비를 많이 줄일 수 있습니다.
본인이 다니고 있는 회사가 저러한 성향을 띄고 있다면, 본인이 변화시키거나 그 마저도 안된다면 얼른 그 곳을 떠나시길 바랍니다.
클린 코드
클린 코드는 팀의 협업 관점 과 유지보수의 관점 에서 많은 순기능을 발생시킵니다. 클린 코드는 작동하는 코드를 작성하는 것이 아니라 장기적으로 읽고 유지 관리하기 쉬운 코드를 작성하는 것입니다.
아래 그래프를 보면 프에서 볼 수 있듯이 Dirty Code 기반 을 유지하는 비용은 시간이 지남에 따라 급격히 증가하는 반면 Clean Code 의 경우 상당히 일정하게 유지됩니다.
깨끗하고 더 나은 코드를 작성하는 방법
의도가 분명한 이름
일반적으로 회사에서는 개발팀 내에 Naming Convention 이 존재합니다. 네이밍 컨벤션이 존재하지 않는다는 것은, 그 개발팀은 클린 코드에 관심이 없다는 것을 나타내는 증거이기도 합니다.
축약어 금지
축약어는 읽는 사람으로 하여금 불편함을 느끼게 합니다. 예를 들어, vehicle 을 vhcl 로 줄여쓰게 되면 vhcl 라는 단어의 의미를 파악하기 위해 소스, 주석, 혹은 DB schema 까지 확인해야합니다. 축약어는 그 만큼 분석에 많은 시간을 투자하게끔 합니다. 단, 누구나 쉽게 유추할 수 있는 경우에는 사용해도 무관합니다.(Ex. idx, cnt)
하지만 개인적으로, 저는 추천하지 않습니다.
축약어를 즐겨 사용하는 사람들의 특징은 긴 이름을 싫어한다는 것인데, 오히려 긴 이름이 더 낫습니다. 긴 이름이 주는 서술성 때문에 불필요한 주석도 제거할 수 있고, 함수나 변수의 의미를 정확하게 전달할 수 있습니다.
하지만 무조건 긴 이름이 좋은건 아닙니다. 특히 스코프(scope)가 넓은 함수(Ex. public)일 수록 이름이 짧을 수록 좋습니다. 단, 필요한 의미를 잃어서는 안됩니다. public 함수들의 특징은 여러 클라이언트에서 재사용할 가능성이 높은 함수들입니다. 이름이 짧아야 하는 이유는 함수를 사용하는 클라이언트에서 public 함수의 내부 구현에 대해서 상세하게 알 필요가 없기 때문입니다.
즉, 함수의 이름에 상세한 내부 구현의 내용을 담을 필요가 없습니다.
이름을 짧게 만들기 위해서 불필요한 단어 가 들어있는지 또는 중복된 단어가 있진 않은지 확인하는 것도 하나의 방법입니다.
반면, private 함수와 같은 내부 함수의 경우에는 이름이 길어도 상관 없습니다. 내부 함수는 API 의 일부가 아니므로 구체적인 동작을 이름에 충분히 담아 서술성을 만족해줘야 합니다. 긴 이름의 내부 함수는 그 함수의 동작에 대한 documentation 역할을 하기 때문입니다.
따라서, 사용되는 빈도와 접근 제한자에 따라서도 함수의 이름을 적절하게 지어야 합니다.
일관성을 유지하라
예를 들어, 두 사람이 게시판 모듈을 개발하는데 어떤 사람은 article 이라는 단어를 선택하여 개발하고 다른 개발자는 board 라는 단어를 선택하여 개발한다면 유지보수하는 입장에서 두 단어의 차이를 이해하기 위해 쓸데없이 시간과 에너지 소모를 하게 됩니다.
SRP(Single Responsibility Principle)
SRP 란 단일 책임 원칙 을 의미합니다. 이 원칙은 다음과 같습니다.
- 단일 모듈은 변경의 이유가 하나, 오직 하나 뿐이어야 한다.
- 하나의 모듈은 하나의 특정 작업만 수행 해야 한다.
예를 들어, 가맹점 신청이라는 프로그램을 개발하는데 가맹점 신청을 등록하는 API 를 만들고 있다고 가정하겠습니다.
가맹점 신청 등록시 다음과 같은 과정을 거칩니다.
- 신청자 정보 등록
- 가맹점 업체 정보 등록
- 가맹점 신청 정보 등록
- 신청 이력 등록
위 4가지 프로세스는 하나의 서비스 등록 메서드에서 같이 트랜잭션으로 묶여 처리됩니다.
public void create(args..) { // public method
createApplier(applier); // private method
createCompany(company); // private method
createApplyInformation(applyInformaiton); // private method
createApplyHistory(applyHistory); // private method
}
스프링을 사용하고 있다면 컨트롤러(Controller) 에서는 위 서비스의 create 메서드를 호출하여 사용할 것입니다.
위 create 메서드는 4가지 일을 하고 있는데 SRP 를 안지킨거 아니냐 ? 라는 의문을 가질 수 있습니다.
하지만 함수 이름이 갖는 추상화 수준 에서 생각했을때 create 라는 함수는 등록만 수행하기 때문에 한 가지 역할만을 한다고 볼 수 있습니다.
함수 이름이 갖는 추상화 수준
create 메서드를 호출하는 컨트롤러(Controller)에서는 가맹점 신청시 가맹점 신청을 한다라는 정도만 알면되지, 내부 구현에 대해서 알 필요가 없기 때문에, 이름을 create 라고 명확하고 짧게 가져갔습니다. 그리고 내부 구현 코드에서는 각각 무슨 등록을 해주는지에 대한 동작을 이름에 충분히 담고 있어야 합니다.
즉, 함수가 하나의 일만 해야 한다는 것은 함수 이름이 갖는 추상화 수준 을 기준으로 판별해야 하며, 함수가 확실히 한 가지 작업만 하려면 함수 내 모든 문장의 추상화 수준이 동일 해야 합니다.
다른 예를 하나 더 들면, validate() 함수를 수행하는데 validate() 와 create() 를 같이하면 안된다는 의미입니다.
함수는 작게
함수는 가급적 작을 수록 좋습니다. 함수가 작다는 것은 그 만큼 자기가 맡고 있는 책임이 작다는 것이며, 재사용성 또한 높아집니다.
예를 들어, 함수에 try/catch/finally 문이 있는 경우 예외처리문만 포함하는 별도의 함수를 만드는 것도 함수를 작게 유지하는 방법 중 하나 입니다.
만약, 함수의 구현부가 너무 길면 내부 구현 중 일부분들을 private method 로 리팩터링 할 수 있는지 검토해봐야 합니다.
함수의 추상화 수준은 한 개
함수의 추상화 수준이 여러개이면 함수의 이름 또한 AandBandC 이런식으로 길어질 가능성이 높습니다. 함수의 이름이 and 로 묶일 가능성이 높다고 하면 and 를 빼기 위해 함수를 더 작게 분리할 수 있을지에 대해 고민해야 합니다.
함수의 이름은 동사
함수는 어떠한 동작/기능을 수행하기 위해 존재하기 때문에 이름을 동사로 짓습니다.
중복 줄이기
코드에서 중복은 개발자의 정신건강에 해롭습니다. 한 군데에서 코드의 수정이 일어난다면, 해당 모듈을 개발한 개발자는 쉽게 고치겠지만 다른 사람이 유지보수하는 경우 중복이 존재하는지에 대한 검증이 필요합니다. 함수의 재사용성을 높이기 위해서라도 중복을 줄이는 연습을 해야 합니다.
중복 줄이기는 DRY(Don’ t repeat yourself) 원칙으로도 불립니다.
중복 줄이기라고 표현한 이유는 중복이 필요한 경우도 있습니다. 예를 들어, 유효성 검증을 하는데 사용자 쪽과 관리자 쪽에서 처리해야하는 검증 로직이 동일할 수 있습니다. 하지만 이 둘은 언제든 한 쪽만 변경될 가능성이 있습니다. 사용자 쪽에 다른 유효성 검증 로직이 추가가 될 수도 있고, 혹은 제거가 될 수도 있습니다.
이 경우 두 위치에 유사한(또는 동일한) 코드가 있으면 다른 코드에 영향을 주지 않고 하나를 변경할 수 있기 때문에 코드베이스 를 유지 관리 하기 가 더 쉽습니다 .
중복을 줄일 때, 중복 코드를 사용하는 곳의 책임이 동일한지 확인하는 것이 좋습니다.
복제는 동일한 책임을 복제하지 않는 한 복제가 아닙니다 .
주석
책 “클린 코드” 의 주석 파트에서는 다음과 같은 내용을 포함하고 있습니다.
우리는 코드로 의도를 표현하지 못해, 즉, 실패를 만회하기 위해 주석을 사용한다. 주석은 실패를 의미한다. 때때로 주석 없이는 자신을 표현할 방법을 찾지 못해 할 수 없이 주석을 사용한다.
주석은 코드와 같이 관리되어야 하는 대상 중 하나입니다.
예를 들어, 클린 코드를 실천하지 않는 개발자가 변수/함수의 이름을 대충 짓고 함수가 하는 역할이 너무 커서 그에 대한 설명을 주석으로 덕지 덕지 작성했다고 가정하겠습니다. 프로그램의 요구사항이 변해서 자신이 작성한 코드를 수정했는데, 깜빡하고 주석을 수정하지 않았다고하면 나중에 유지보수하는 사람에게 상당한 혼란을 줄 수 있습니다.
주석은 꼭 필요한 경우에만 다는 것이 좋다고 생각합니다. 꼭 필요한 경우란 회사 내의 주석 작성 규칙이 존재하는 경우, 정보를 제공하거나 의도를 나타내는 주석, TODO 주석 등이 있습니다.
그 외의 경우에는 함수나 변수의 이름을 짓는데 충분한 시간을 투자하고 고민하여 불필요한 주석을 제거하도록 노력해야 합니다.
정리
클린 코드를 실천하기 위한 몇 가지 방법들을 소개해 드렸습니다. 만약, 이 글을 읽고 클린 코드에 관심이 생긴다면 책 “클린 코드” 를 구매하여 읽어보시는 것을 추천드립니다.