코드의 네이밍과 코딩 컨벤션은 왜 중요한가?
우테코 수업을 듣다가 코드에서 효과적인 네이밍이 왜 중요한가? 라는 질문을 들었다.
효과적인 네이밍은 왜 중요한가?
모두들 흔히 좋은 네이밍으로써 코드의 가독성과 이해도를 향상시키고 유지보수성을 높이는데 도움이 된다고 말한다.
하지만 이것에 대해 다시 왜? 냐고 물으면 쉽게 입이 떼어지지 않았다.
좋은 네이밍이 중요한 이유
Eddy 님의 글에서는 아래처럼 말한다.
프로그래밍은 문제 해결이 전부가 아니다.
프로그래밍은 다른 사람과의 커뮤니케이션이고 협업이다.
내가 만든 코드를 읽는 것은 컴퓨터 뿐만이 아니라 '다른 프로그래머들'이, 그들과 다를 바 없는 '미래의 나' 이다.
그래서 코드는 그 사람들에게 이 프로그램이 어떤 동작을 하는지(어떤 책임을 갖는지)를 명료하게 전달해야 한다.
또 우테코 코치 제이슨의 말로는 '어떤 개발자가 팀에 새로 합류하게 된다면, 처음부터 새 프로그램을 만들게 되는 경우는 거의 없다' 고 했다.
기존 코드를 리팩토링하거나 약간의 동작을 추가/수정 하는 경우가 대부분이라고 한다.
개발자들은 이직이 잦기 때문에 기존 사람이 남기고 간 코드를 읽고 수정하는 일이 잦다.
즉, 기존 코드를 읽어야 새 코드를 짜기 때문에 코드를 읽기 쉽게 하여 새 코드를 짜기도 쉽게 해야 한다.
실제로 많은 경우, 코드를 읽는 시간과 코드를 짜는 시간의 비율은 10 : 1 이라고 한다.
좋은 네이밍 뿐 아니라, 읽기 쉬운 코드를 만들기 위한 여러 가이드들을 가리키는 말이 있다.
그것이 클린 코드이다.
(클린 코드는 가독성, 간결화, 모듈화, 일관성, 테스트 가능성, 예외 처리 등의 특징도 포함한다.)
워드 커닝햄은 클린 코드에 대해 '코드를 읽으면서 짐작했던 기능을 각 루틴이 그대로 수행하는 코드' 라고 한다.
클린 코드에 대해서는 내용이 방대하므로 나~중에 따로 정리하겠다.
좋은 네이밍의 습관 10
SOOHWAN KIM 님의 글에서는 좋은 네이밍을 위한 습관 10 가지를 설명한다.
매우 간단하게 정리해보겠다.
구체적인 내용은 원문의 내용을 직접 참고하길 바란다.
- 변수, 클래스명에는 동사를 넣지 않는다.
- 클래스 `FeatureExtract` (❌) -> `FeatureExtractor` (👍)
- 변수 `work` -> `worker`
- 함수명에는 동사를 넣는다.
- `id()`(❌) -> `getId()`(👍)
- `trainer()` (❌) -> `train()` (👍)
- 변수명에 굳이 관사를 넣지 않는다.
- ` a_cat` (❌) -> `cat` (👍)
- 변수명에 전치사는 최대한 생략한다.
- `theNumberOfWorker` (❌) -> `workerCount` (👍)
- 단수와 복수를 구분한다.
- 사용하는 언어의 코딩 컨벤션을 지킨다.
- ex: [코틀린 코딩 컨벤션]
- 통상적으로 사용되는 변수명/규칙을 사용한다.
- 상수는 모두 대문자로 표시해준다.
- `const main_width = 1024` (❌) -> `const MAIN_WIDTH = 1024`(👍)
- 로직이 끝나면 한줄 띄어준다.
- 코드에 규칙이 있어야 한다.
- 위 규칙을 지키지 않더라도, 네이밍과 코드에는 일정한 규칙이 있어야 한다. 이 규칙은 팀과 협의된 규칙이어야 한다.
코딩 컨벤션이 필요한 이유
사실 위 좋은 네이밍의 습관에서 '사용하는 언어의 코딩 컨벤션을 지킨다' 라고 했다.
즉, 코딩 컨벤션이 필요한 이유는 좋은 네이밍이 중요한 이유와도 일맥상통한다.
이 영상에서 코딩 컨벤션에 대해 친절히 설명한다.
코딩 컨벤션?
코딩 컨벤션은 프로그래밍에서 일반적으로 사용되는 가이드라인이나 규칙을 말한다.
이는 프로그래밍 스타일, 프로그래밍 관행 및 프로그래밍 수명 주기의 모든 측면에 대한 방법에 대해 주로 다른다.
코드 컨벤션을 사용하는 이유는 대표적으로 아래와 같다.
- 모든 사람이 코드 컨벤션을 따르면 모두가 동일한 방식으로 작업하게 되어 협업이 원활해지고 코드의 일관성이 유지됩니다.
- 코딩 컨벤션은 시간이 지나면서 개발자들의 경험과 기여를 바탕으로 만들어졌기 때문에 안정적이며,
실제 세계에서의 경험을 토대로 구성되었다.
따라서 코드 컨벤션을 따를 때는 개인이나 팀의 개발 경험보다는 이러한 안정성을 고려해야 한다.
한가지 예시를 보여주겠다.
코틀린 컨벤션 문서에서는 아래와 같은 순서로 클래스 내부 코드를 배치하도록 권고한다.
class
프로퍼티 선언
init 블록
부 생성자
메소드 선언
companion object
아래 lazy 프로퍼티를 가지는 클래스를 보자.
class LazyInitializationExample {
val lazyProperty: String by lazy {
println("Lazy property initialized")
"Initialized Lazy Property"
}
init {
println("Init block executed")
println("Accessing lazy property inside init block: ${lazyProperty}")
}
}
fun main() {
val example = LazyInitializationExample() // 객체 생성
}
이는 정상적으로 작동한다.
출력
Init block executed
Lazy property initialized
Accessing lazy property inside init block: Initialized Lazy Property
그런데 만약 init 블록을 프로퍼티 위로 올리면 어떻게 될까?
class LazyInitializationExample {
init {
println("Init block executed")
println("Accessing lazy property inside init block: ${lazyProperty}")
}
val lazyProperty: String by lazy {
println("Lazy property initialized")
"Initialized Lazy Property"
}
}
에러 발생
Variable 'lazyProperty' must be initialized
코틀린의 lazy 프로퍼티는 선언되고 나서 실제로 사용되는 시점에서 초기화되는 기능이다.
그래서 두번째 코드에서는 에러가 발생하는 것이다.
이것은 고치기 어려운 에러는 아니지만, 쉽게 실수할 수도 있다.
하지만 만약 class layout 순서를 코틀린 코딩 컨벤션을 습관적으로 지킨다면, 이러한 에러를 만날 가능성이 현저히 줄어들 것이다.
이것이 코틀린 컨벤션이 개발자들의 경험과 기여를 바탕으로 만들어졌기 때문에 안정적이며,실제 세계에서의 경험을 토대로 구성되었다는 증거 중 하나이다.
만약 당신이 코틀린 개발자라면, 코틀린 공식 문서의 코딩 컨벤션을 읽어보기를 바란다.
https://kotlinlang.org/docs/coding-conventions.html
코딩 컨벤션에 정답은 없다.
말 그대로 컨벤션(규약, 약속)이기 때문이다.
심지어 어떤 회사의 컨벤션은 코틀린에서 제공하는 코딩 컨벤션을 지키지 않는 경우도 있다.
(물론 크게 벗어나지는 않을 것이다.)
각 회사의 코드 컨벤션을 연구하여 새로운 코드가 기존 코드와 매우 유사하게 작성해야 한다!
당연한 이야기지만, 코드가 코틀린 공식 코딩 컨벤션에 어긋난다고 해서 회사가 정한 코드 컨벤션을 찾아보지 않고, 수정하는 것은 위험할 수 있다!
출처:
https://velog.io/@eddy_song/why-naming-matters
https://yoondii.tistory.com/88
https://sooftware.io/coding-habit/
https://kotlinlang.org/docs/coding-conventions.html#class-layout
https://www.youtube.com/watch?v=VHAXJxcHA1k