코드 리뷰를 통해 리뷰어들에게 자신이 구현한 코드를 보여준 경험이 있으신가요? 혹은 스스로가 작성한 코드에 아쉬움을 느낄 때가 있으신가요?
코드를 작성하는 것에는 표준이 없습니다. 그래서인지 어떤 코드가 주어졌을 때 읽는 사람에 따라 코드에 대한 평가가 달라질 수 있습니다. 다음 코드를 예시로 들어보겠습니다.
1. 3항 연산자를 이용한 구현
return isTrue ? true : (isPossible ? true : false);
2. 기본 구현
if(isTrue) {
return true;
}
return isPossible ? true : false;
둘 중에 어떤 코드가 더 좋은 코드라고 할 수 있을까요? 이번 시간에는 어떤 코드가 Clean Code인지, 또 우리는 Clean Code를 작성하기 위해 어떤 부분을 고려해야 하는지에 대해 알아보는 시간을 가져보겠습니다.
사실 우리는 코드를 작성하는 것보다 코드를 읽는데 더 많은 시간을 사용합니다. 레거시 코드, 라이브러리 코드, 팀 동료 코드, 몇 달 전에 작성한 코드(기억나지 않음), 퇴사한 사람이 작성한 코드, 스택 오버플로의 코드 등... 다양한 코드를 읽고 있습니다. Clean Code
의 창시자 Robert Martin은 다음과 같은 이야기를 했습니다.
“Indeed, the ratio of time spent reading versus writing is well over 10 to 1” — Robert C. Martin, Clean Code
실제로 읽기와 쓰기는 10:1이 훨씬 넘는 비율로 이루어지고 있다는 것이었죠. 따라서 우리는 나를 위해서도, 팀원을 위해서도 Clean한 Code를 작성해야할 필요가 생깁니다.
컴파일은 컴파일러가 진행하지만, 실제로 코드를 작성하고 수정하는 주체는 사람입니다. 그렇기에 우리는 인간이 쉽게 읽을 수 있는 코드를 작성하는 것에 대해 고민하고 노력해야만 합니다.
앞서 말했듯이 Clean Code에는 정의가 없습니다. 하지만 개발자들이 보편적으로 생각하는 Clean Code들은 다음과 같은 요소들을 모두 충족시켰습니다.
Clean Code를 위해 가장 먼저 노력해야될 것은 naming입니다. 변수, 클래스, 파일, 함수 등 모든 부분에서 개발자는 이름을 작명해야 합니다. 다음 함수를 한 번 확인해 볼까요? 두가지 모두 동일한 기능을 수행합니다.
public Phone make(int number, String type, Person person) {
return new Phone(number,type,human);
}
public Phone makeNewPhone(int phoneNumer, String telephoneCompany, Person personInfo){
return new Phone(phoneNumer,telephoneCompany,personInfo);
}
두 가지 함수에서 볼 수 있듯 우리는 함수가 어떤 기능을 수행하는지 좀 더 구체적인 상황을 네이밍을 통해 보여줄 수 있습니다. 그렇다면 네이밍을 고려할 때 어떤 부분을 중요하게 봐야 할지 알려드리겠습니다.
주석을 통해 변수의 역할을 정의하는 방법은 지양합니다. 변수명은 해당 변수가 어떤 역할을 수행하는지 의도를 분명히 해야 합니다.
대면으로 코드를 설명할 경우 해당 변수에 대해 발음하기가 어려우면 대화에 지장이 생깁니다. 아래 변수를 이야기할 때 지앤티엠에스템프 변수는...
보단 제너레이션타임스탬프 변수는
이 훨씬 좋겠죠?
명칭이 보편적일수록, 짧아질수록 IDE를 통해 검색되는 숫자가 더더욱 많아집니다. 이는 해당 변수를 확인하고 싶을 때 시간이 오래 소요될 수 있습니다. 최대한 손쉽게 검색이 가능한 이름을 사용합니다.
약어는 해당 약어에 대한 지식이 있는 사람들에게만 쉽게 이해되는 문제가 존재합니다. 약어는 최대한 지양하고 풀어서 전체 명칭을 이용하시는 것을 권장드립니다.
변수명에 시간을 투자하는 것은 이후 다시 해당 코드를 이해하는데 소요되는 시간보다 훨씬 적게 들 것입니다. 지금 당장에야 오랜 시간이 걸리더라도 이후 코드 유지보수 및 팀원들의 빠른 이해를 위해서라도 좋은 이름을 위해 아낌없이 시간을 투자해야 합니다.
함수를 개발할 경우 다음과 같은 요소들을 고려합니다.
가장 기본적인 내용으로, 함수는 한 가지 기능만 수행하도록 개발을 진행해야 합니다. 한 가지 기능만 수행해야 개발자는 해당 함수가 어떤 기능을 수행하는지 기억하기 쉬워집니다.
두 가지 이상의 기능을 수행할 경우 side effect 및 유지 보수가 점차 어려워집니다.
기능은 가능한 짧아야 합니다. 하지만 얼마나 짧아야 할까요?. 일반적으로는 3단계 이상이 되는 들여쓰기 부터는 가독성이 점점 나빠집니다. 따라서 함수를 작성할 때는 2단계 이하의 들여쓰기로만 진행되는 함수를 작성합니다.
팀원들간의 논의를 통해 함수의 들여쓰기를 최대 n회 이하로 제한하고 개발을 진행하시는 것을 권장드립니다.
가장 이상적인 함수는 인수가 없는 것입니다. 함수의 인자가 많아질수록 해당 함수를 이해하기 위해서는 각 인수에 대한 지식이 선행되어야만 하기 때문입니다. 따라서 최대한 적은 인수의 함수를 개발하는 것을 목표로 코드를 작성합니다.
주석과 Clean Code는 굉장히 상반되는 개념을 가지고 있습니다. Clean Code라면 과연 주석이 필요할까..? 라는 의문을 가장 먼저 가져야만 합니다. 왜냐면 주석은 코드를 위한 부연설명이기 때문이죠. 따라서 무조건 코드를 설명하는 주석은 피하는 것을 권장드립니다.
주석에는 다음과 같은 경우 의미있는 주석이 될 수 있습니다.
주석을 작성하는 경우
1~3은 중요한 Clean Code에 대한 요소라 할 수 있습니다. 하지만 과연 1~3을 한 번에 고려하면서 하는 개발이 쉬울까요..? 따라서 우리는 일단 스타일 대로 작성하고 리팩토링을 통해 Clean Code로 정리합니다.
하지만.. 리팩토링을 했을 때 기존에 정상적으로 동작하던 코드 로직들이 계속해서 올바르게 동작한다는 것을 보장할 수는 없습니다. 따라서 우리는 문제없이 리팩토링을 수행하기 위해 테스트를 진행합니다.
자동화 테스트를 통해 리팩토링한 코드에 대한 정합성을 보장합니다. 테스트 도구로는 대표적으로 Junit과 같은 테스트 도구가 존재하는데 이를 작성해 리팩토링에 안전한 환경을 준비할 수 있습니다.
코드 리팩토링 도구로는 대표적으로는 Intellij IDEA가 있습니다. IDE에서도 리팩토링 도구를 제공하기 때문에 가장 마음에 드는 리팩토링 도구를 찾아서 도구를 이용한 리팩토링을 수행하거나, 스스로 리팩토링을 수행하시는 것을 추천드립니다.
리팩토링 도구 목록
오늘은 Clean Code를 작성하는 법에 대해 알아보았습니다. 이 외에도 Clean Code를 작성하는 방법에 대해 다양한 내용들이 존재하지만 해당 내용들은 좀 더 심층적인 내용이라 생각해 해당 포스트에서는 제외하였습니다. 좀 더 자세한 clean code에 대해 알아보고 싶으시다면 Clean Code를 구매하셔서 읽어보시는 것을 추천드립니다.
코드 구현간 네이밍, 함수, 주석 관련된 부분만이라도 스스로 개선을 하기 위해 노력한다면 Clean Code에 대해 한 걸음 더 나아갈 수 있을 것이라 확신합니다. 표준이 무엇이고 뭘 말하는지 모르겠다면 구글 자바 스타일 가이드를 참고하시면서 개발을 하시는 것도 좋은 하나의 방법이라 생각합니다.
감사합니다.
https://medium.com/clarityai-engineering/clean-code-a-practical-approach-896546435235
https://google.github.io/styleguide/javaguide.html