사람답게 살기 위한 한 달 한 권(2022/06)
궁극적으로 코드는 요구사항을 상세히 표현하는 언어다.
필요에 따라 요구 사항에 더 가까운 언어를 만들 수 있고 정형 구조를 뽑아내는 도구를 만들 수도 있다.
그러나 정밀한 표현은 항상 필요하고 이 필요성은 없앨 방법이 없으므로 코드도 항상 존재할 수 밖에 없다.
코드 작성 시 시간을 들여 깨끗한 코드를 만드는 노력이 결국에는 비용 절감 뿐 아니라 전문가로서 살아남는 길이라고 한다.
일정에 쫓기더라도 대다수의 관리자는 좋은 코드를 원하며 좋은 코드를 사수하는 일은 바로 프로그래머의 책임이다.
정해진 기한을 바꾸는 유일한 방법은 언제나 코드를 깨끗하게 유지하는 습관이고 깨끗한 코드는 보기에 즐거운 코드다.
깨끗한 코드는 보는 사람에게 즐거움을 선사해야 하고 세세한 사항까지 꼼꼼하게 처리하는 코드다.
깨끗한 코드는 한 가지를 잘한다.
나쁜 코드는 너무 많은 일을 하려고 애쓰다가 의도가 뒤섞이고 목적이 흐려지게 된다.
깨끗한 코드는 단순하고 직접적이며 잘 쓴 문장처럼 읽히고 설계자의 의도를 숨기지 않는다.
크기가 큰 코드보다는 작은 코드가 가치있으며 코드는 작을수록 좋다.
깨끗한 코드는 주의깊게 작성한 코드다.
시간을 들여 깔끔하고 단정하게 정리한 코드다.
세세한 사항까지 꼼꼼하게 신경쓴 코드다.
프로그램을 단순하게 보이도록 만드는 열쇠는 언어가 아니라 프로그래머다.
변수, 함수, 클래스 네이밍 시 의미있는 이름을 사용해야 한다.
의도를 분명히 해야 하고 좋은 이름을 지으려면 시간이 걸리지만 최종적으로는 이 이름을 통해 절약하는 시간이 더 많다.
변수, 함수, 클래스 이름은 존재 이유와 수행 기능, 사용 방법을 나타내도록 하여 주석이 필요가 없도록 한다.
당연하게도 그릇되거나 오해를 불러일으킬 수 있는 이름은 피한다.
예를 들면 실제는 List가 아니지만 itemList를 사용하거나 O(대문자 o), l(소문자 L)를 사용하여 헷갈리게 만들거나 prevGetNameAndAgeData, prevGetNameAndSexData 등과 같이 한 눈에 구분하기 어려운 이름이다.
항상 의미를 갖고 구분을 해야 하며 컴파일러나 인터프리터만 통과하려는 의도로 코드를 구현하면 안된다.
연속된 숫자를 덧붙이거나 의도를 드러내지 않는 이름은 작성하지 말고 읽는 사람이 차이를 알도록 지어야 좋은 이름이다.
의미 이외에도 사용자가 발음하거나 검색하기 쉬운 이름을 사용한다.
예를 들면 GenYrDt보다 GenerateYearDate가 훨씬 낫다.
이름 길이는 범위 크기에 비례해야 한다.
왜냐하면 나중에 코드가 복잡해졌을 때 ab와 같은 단순한 이름은 검색이 거의 불가능하기 때문이다.
항상 남들이 이해하기 쉽게 코드를 작성한다.
전문가라고 불리는 프로그래머는 명료함을 최우선으로 하여 항상 남들이 이해하는 코드를 작성한다.
클래스와 객체 명명 시에는 명사, 명사구가 적합하며 동사는 사용하지 않는 것이 좋다.
그러나 메서드는 동사나 동사구가 적합하다.
명명 시 기발하거나 보편적으로 이해하기 어려운 이름은 피하는 게 좋으며 예를 들어 특정 문화를 이해해야만 알 수 있는 단어나 구어체, 속어 등이 있다.
한 개념에서는 하나의 이름만 선택하고 get, retrieve, bring, fetch, take 등 같은 기능의 메서드는 이름을 통일한다.
이름이 다르면 클래스와 타입도 다르게 여기기 쉬우므로 일관성있는 어휘를 사용하고 일관성 속에서 맥락을 알 수 있도록 해야 한다.
예를 들어 두 값을 더하는 메서드가 add라면 하나의 값 만을 더하는 메서드는 insert, append로 짓는 것이다.
해법 영역은 기술 개념에서 가져온 이름이 이해하기 쉬운데 알고리즘, 수학 용어, 패턴 이름 등 이미 익숙한 개념이 이해하기 쉽다.
하지만 문제 영역은 해당 영역에서 가져온 이름도 문제가 없다.
의미 있는 맥락context을 사용하여 클래스, 함수에 맥락을 부여하거나 접두어를 사용해 의미를 분명하게 한다.
또한 불필요한 맥락context은 사용하지 말고 의미가 분명한 경우에 한해 짧은 이름이 긴 이름보다 좋으므로 불필요한 부분을 추가하지 않도록 한다.
문장이나 문단처럼 읽히는 코드가 아니면 표나 자료구조처럼 읽히는 코드를 짜는 데 집중하는 것이 좋다.
함수는 무조건 작게 만드는 것이 좋고 중첩 구조가 생길만큼 함수가 커지는 것은 좋지 않다.
함수는 한 가지만을 해야 한다.
중복은 모든 소프트웨어에서 악의 근원이다.
하위 루틴을 발명한 이래로 소프트웨어 개발에서 지금까지의 혁신은 소스 코드의 중복을 제거하려는 지속적인 노력으로 볼 수 있다.
소프트웨어를 짜는 것은 글짓기와 비슷하다.
처음에는 길고 복잡하고 정리가 안된 상태지만 코드를 다듬고 정리하여 최종적으로 사용할 수 있는 코드를 만드는 것이다.
프로그래밍의 기술은 언제나 언어 설계의 기술이다.
프로그래밍의 대가(大家)는 시스템을 구현할 프로그램이 아니라 풀어갈 이야기로 여긴다.
주석은 언제나 실패를 의미하며 코드로 의도를 표현하지 못한 실패를 만회하기 위해 사용하는 것으로 본다.
따라서 주석이 필요한 상황에 처하면 코드로 의도를 표현할 방법을 먼저 찾는다.
주석은 오래될수록 코드에서 멀어지며 내용이 잘못될 가능성도 커진다.
코드를 유지보수해도 주석까지 유지보수하기는 힘들기 때문이다.
진실은 오직 한 곳, 코드에만 존재한다.
처음부터 바르게 시스템을 만들 수 없다.
대신 오늘 주어진 사용자 스토리에 맞춰 시스템을 구현하고 내일은 새로운 스토리에 맞춰 시스템을 조정하고 확장한다.
이것이 반복적이고 점진적인 애자일(Agile) 방식의 핵심이다.
켄트 벡(Kent Beck)이 제기하는 단순한 설계 규칙 네 가지는 순서대로 다음과 같다.
- 모든 테스트를 실행한다.
- 중복을 없앤다.
- 프로그래머의 의도를 표현한다.
- 클래스와 메서드 수를 최소화한다.
테스트 가능한 시스템을 만들려고 애쓰면 설계 품질이 더불어 높아지므로 테스트는 클린 코드를 위한 필수 요소이다.
테스트 케이스가 많을수록 개발자는 테스트가 쉽도록 코드를 작성하게 되고 철저히 테스트 가능한 시스템을 만들면 더 나은 설계를 얻을 수 있다.
결합도가 높으면 테스트 케이스 작성이 어려우므로 결합도를 낮추면 설계 품질은 더욱 높아진다.