🔎

Greppability, 코드 가독성에 대한 또 다른 기준

Created
Sep 4, 2024 05:59 AM
Tags
readability
greppability
개발
 
Greppability라는 개념을 처음으로 알게 되었다. 소프트웨어 엔지니어라면 grep 이라는 명령어는 한번쯤 들어봤을 텐데, grep 가능성을 의미한다고 한다. 알다시피 텍스트 검색에 많이 사용하는 명령어인데, 정리해 보자면 코드에서 검색을 통해 얼마나 빨리 원하는 것을 찾을 수 있는가에 대한 지표라고 할 수 있겠다.
 
아무리 마이크로서비스로 시작했다고 하더라도, 서비스는 시간이 흐를수록 복잡도가 증가하게 되며, 코드 라인수는 지속적으로 증가한다. 점차 늘어나는 코드 속에서 필요한 로직이나 요소를 빠르게 찾아야 하는 경우는 생각보다 빈번하게 발생한다.
 
특히 마이크로서비스로 잘게 쪼갤수록, 담당자 1명당 커버해야 하는 서비스의 갯수가 늘어나고 하나의 서비스를 제대로 이해하는 개발자가 1-2명에 지나지 않게 되는 경우도 흔히 봤다. 결국, 그 개발자가 부재 중인 상황에 코드를 파악해야 하는 경우 동료 개발자는 필요한 로직을 찾기 위해 검색 기능을 적극 활용하게 되곤 한다.
 
어느 상황에서든, 코드베이스에 대해 필요한 요소들을 검색하며 찾는 경우는 생각보다 빈번하게 발생한다. 따라서, 검색이 쉽게 개발을 한다는 Greppability의 관점은 주목할만 하다.
 
위 링크를 읽으며 몇가지 공감가는 코딩 원칙이 있어 옮겨 적어본다.
 

의미론적으로 명확한 구조체, 변수, 함수명 정의

코드에 대한 이해가 떨어지는 개발자일수록 의미론적인 단어부터 검색할 가능성이 높다. 따라서 되도록이면 주요 변수나 구조체, 함수명 등은 최대한 의미가 드러나게 정하는 것이 좋다.
 
# ❌ BAD func Finish() {} # ✅ GOOD func FinishUserScoreCalculation() {}
 

컨벤셔널한 변수, 함수명을 유지

ORM 등에서 일반적으로 사용되는 작명 패턴이 있다. FindByID같은 케이스가 그 예가 될텐데 이왕이면 FindOne, GetOne, FindByID처럼 상대적으로 일반적인 방향으로 작명하는 것이 검색에 도움이 될 것 같다.
 
FindGet이 repository 메서드로는 일반적인 prefix라고 생각하고, Fetch, Search, Query는 상대적으로 덜 일반적이라고 느낀다. 일반적인 패턴을 웬만하면 유지하는 게 검색가능성을 개선하는 데 도움이 될 것 같다.
 

식별자를 분할하거나 동적으로 구성하는 것은 주의

아래 코드는 너무 인위적인 느낌이 강하지만, 종종 이런식으로 string interpolation과 같은 방법을 통해 핵심적인 문구가 조합되는 경우가 있다.
// addressType: "shipping" / "billing" func TableName(addressType string) string { return fmt.Sprintf("%s_address", addressType) }
 
만약 address라는 단어로 검색했는데 검색결과가 너무 많다면, 하나하나 확인해 shipping_address라는 값을 찾는 데 시간이 많이 걸릴 수 있고, 심지어는 이런 값이 사용된다는 것을 놓칠수도 있다.
 
 

중첩보다는 flat하게

directory의 depth를 재귀적으로 나눠 두는 것보다는 아래처럼 flat한 것이 한 눈에 확인하기도 좋고 검색도 용이하다고 한다.
# ❌ BAD ./components/attribute/filter/Combobox.tsx ./components/attribute/filter/Dialog.tsx ./components/attribute/filter/Rating.tsx ./components/attribute/filter/Select.tsx # ✅ GOOD ./components/AttributeFilterCombobox.tsx ./components/AttributeFilterDialog.tsx ./components/AttributeFilterRating.tsx ./components/AttributeFilterSelect.tsx
물론 이는 호불호가 있는 영역이라고 생각하며, 개인적으로는 꼭 동의하진 않는다.
 
특히 go에서는 디렉토리명으로 패키지명을 결정하는 경우가 많기 때문에, 종종 디렉토리를 재귀적으로 혹은 잘게 나누는 경우가 많은 것 같다.
 

결론

평소에 전혀 고려하지 않았던 요소이지만 문득 글을 읽고 보니 생각보단 중요할 수 있겠다는 생각이 들었다. 코드를 작성하는 기준으로 Greppability라는 요소를 머릿 속에 넣어두고, 종종 고려해야 겠다.
 

참고자료