본문 바로가기
Etc.

개발자의 글쓰기 2장 - 개발 시간을 줄여주는 이름 짓기와 주석 쓰기

by takoapps 2023. 1. 15.

01 네이밍 컨벤션, 이유를 알고 쓰자

 

개발자의 가장 큰 고민은 이름 짓기

모든 개발자는 자기 코드를 읽는 사람이 주석 없이도 금방 이해하게 코드를 작성하고 싶어 한다. 이름 하나 잘못 지었다간 일이 몇 배가 되기도 한다. 무슨 뜻인지, 무슨 기능을 하는지 알아낼 수 있는 이름을 작성해보자

 

이름 짓기는 창조가 아니라 조합

이름 짓기는 무에서 유를 창조하는 것이 아닌, 라이브러리를 사용하는 것처럼 기존 방식 및 이름을 차용해서 새로운 이름을 짓는 경우가

대부분이다.

창조가 아닌 정해진 원칙으로 적절한 단어를 선택해 조합하는 과정일 뿐이다.

 

인기 자바 소스를 분석한 '오픈소스의 네이밍 특징들'

  • 자바 네이밍 컨벤션을 철저히 준수한다
    • 클래스는 UpperCamelCase
    • 함수와 변수는 lowerCamelCase
    • 상수는 UPPER_DELIMITER_CASE
  • 네이밍은 보통 16글자, 3단어를 조합한다
    • 클래스 네임: 3.18 단어
    • 함수 네임: 3.36 단어
    • 변수 네임: 2.57 단어
  • 품사는 주로 명사, 동사, 형용사의 조합이다.
    • 명사 + 명사 + 명사
    • 동사 + 명사 + 명사
    • 형용사 + 명사 + 명사 등

패키지와 모듈은 모두 소문자로 쓴다

패키지와 모듈은 분명히 클래스나 함수보다 더 높은 위치다. 하지만 실제로는 소문자로만 쓴다. 클래스를 모으거나 함수를 담아놓은 통에 불과하기 때문이다.

[안 좋은 예]
import DeveloperWriting

[좋은 예]
import developerwriting

 

BEM표기법

CSS에서 사용하는 BEM(Block Element Modifier)표기법은

‘대상-요소_상태’를 의미한다.

대상의 요소나 부분을 의미할 땐 언더스코어 두 개 (__)로 연결,

대상이나 요소의 상태나 속성을 의미할 땐 하이픈 두 개 (—)로 연결한다.

[BEM표기법]

.form {}
.form__button {}
.form__button--disabled {}

 

가독성과 소통이 먼저다

같은 부서의 개발자, 하나의 프로그램과 관련된 개발자들끼리는

코딩하기 전에 기본적인 컨벤션 규칙을 정하는 것이 우선이다.

그래야 가독성과 소통이라는 두 마리 토끼를 동시에 잡을 수 있다.

 

02 변수 이름을 잘 짓는 법

 

a나 d와 같이 아무런 의미가 없는 글자를 변수로 쓰는 것은 좋지 않다.

day를 d로 표현할 때가 많다. 하지만 d를 보고 어떤 개발자는 date, double을 떠올릴지도 모른다.

일자를 뜻하는 변수를 설정하고 싶다면 그냥 day를 사용하면 된다. 그런데 그냥 day는 없다.

임의의 날을 뜻한다면 someday, 오늘은 today, 특정한 날은 thisDay다.

 

[안 좋은 예]

const d
const m
const y

[좋은 예]

const someday
const today
const thisMonth
const finalYear

// 며칠이 지났는지 알려주는 변수라면

const daysSinceCreated
const monthsSinceUpdated
const yearsSinceRegisterd

 

복수형을 나타내는 s를 붙일까 말까?

배열을 복수로 나타내는 방법이 있다. 변수명에 복수형을 나타낼땐 -s가 끝에 붙어 있기 때문에 쉽게 알아볼 수 있다. 하지만 다음과 같이 함수명 중간에 사용할 때는 -s가 눈에 잘 띄지 않는다.

그래서 변수명은 그냥 두더라도 함수명에선 -s 대신 ‘array’, ‘list of‘를 쓰는 편이 더 나을 수도 있다.

 

[-s가 눈에 잘 띄지 않는 경우]

checkUserNamesUnder2Characters()
checkUserNamesExistsInDB()

[array, listOf로 사용하는 경우]

checkUserNameArrayUnder2Characters()
checkListOfUserNameExistsInDB()

 

중요한 단어를 앞에 쓴다

변수 이름을 여러 단어로 조합할 때는 순서를 잘 정해야 한다.

총방문자 수를 나타내는 변수는 totalVistitor로 그대로 번역해 변수로 사용하곤 한다.

하지만 다시 사용할 때는 total보단 visitor로 검색을 시작하는 경우가 더 많을 것이다,

따라서 total이라는 수식어보단 본래 의미를 뜻하는 visitor를 앞에 쓸 것을 추천한다.

 

[안 좋은 예]

const totalVisitor
const totalRegister
const maxSizeOfWindow
const numberOfTotalVIP

[좋은 예]

const visitorTotal
const registerTotal
const windowSizeMax
const vipCount

 

항상 중요한 것이 앞에 와야 한다는 기본 원칙은 지키자.

 

함수 이름 짓는 순서

함수는 시스템이 할 일을 나타내는 것이지 사용자가 할 일을 나타내는 것이 아니다.

따라서 함수의 주체, 즉 주어도 없앤다.

사용자가 이름을 입력하고 등록 버튼을 클릭하면 시스템이 사용자 이름을 input 태그에서 가져와 입력 여부와 글자 수를 확인한 뒤 입력이 안 되었으면 스크립트를 중단하고 input 태그를 활성화해 사용자가 쓸 수 있게 하고, 글자 수가 한글 두 글자 이하면 확인을 요청해 사용자가 확인할 수 있게 한다.

->

“사용자 이름을 input태그에서 가져와 글자 수를 확인한 뒤 입력이 안 되었으면 input 태그를 활성화해 글자 수가 한글 두 글자 이하면 확인을 요청한다.”

 

문장을 조각내자.

  1. (함수1) 사용자 이름을 input 태그에서 가져온다.
  2. (함수2) 사용자 이름의 글자 수가 2글자 이하면 다음과 같이 처리한다.
    1. 만약 글자수가 0(=null)이면 input 태그를 활성화한다.
    2. 만약 글자 수가 1 또는 2이면 사용자에게 확인을 요청한다.

이제 함수 문장을 영어로 바꾸자.

  • (함수 1) get user’s name from the text input field
  • (함수 2) do something if user’s name contains under 2 characters

영문에서 정관사, 불필요한 단어를 빼고 of는 앞뒤 단어를 바꿈. 소유격 제거

Do something은 확인해 처리하는 check라는 단어로 변경

  • (함수 1) get user name from input field
  • (함수 2) check if user name contains under 2 characters

이제 띄어쓰기를 없애고, 두 번째 단어부턴 첫 철자를 대문자로 변경

  • (함수 1) getUserNameFromInputField()
  • (함수 2) checkIfUserNameContainsUnder2Characters()

함수를 사용할 때 의미상 없어도 되는 단어는 없애자.

  • (함수 1) getUserNameFromField()
  • (함수 2) checkUserNameUnder2Characters()

 

03 좋은 이름의 기준, SMART

 

좋은 이름이 가진 5가지 특징

  • Easy to Search
    • 고전적 범주화를 이용해 한 단계 상위 범주의 이름을 태그처럼 덧붙인다.
    • 소나무, 감나무, 배나무 같은 개별적 대상을 나무라는 이름으로 범주화하여 이해
    • 에러 메시지를 저장할 상수 이름의 경우, 한 단계 상위 범주인 ERROR를 붙이면 이와 관련된 모든 것을 한 번에 찾을 수 있다.
    [안 좋은 예]
    
    SERVER_TIMEOUT
    NO_RESULT
    BAD_REQUEST
    
    [좋은 예]
    
    ERROR_SERVER_TIMEOUT
    ERROR_NO_RESULT
    ERROR_BAD_REQUEST
    
    // 사용자 구별할 때는 user를 붙이는 것도 좋은 방법이다.
    
    user
    userBuyer
    userPayer
    userRegister
    userRegisterButNoPayer
    

주의할 점은, 같은 접두어를 가진 함수 및 변수의 개수가 너무 많으면 안 붙이는 것만 못하다.

에러가 수백 개라면 ERROR를 접두어로 붙이기 전에 SERVER_ERROR, INTERFACE_ERROR 등으로 먼저 에러 구분 체계부터 만들어야 한다.

  • Easy to Mix
    • 개발 언어의 문법과 조합해 이름을 짓는다. 개발 언어 자체가 이미 이름에 대한 기본 체계를 갖고 있기 때문이다.
    [안 좋은 예]
    
    // 1. 텍스트 크기, 색과 같은 속성 기준으로 일일이 스타일 이름 짓기
    <div class="big_strong_text">개발자의 글쓰기</div>
    
    // 2. 위 보단 수고를 그나마 더는 개념으로 스타일 이름 짓기
    <div class="title">개발자의 글쓰기</div>
    
    [좋은 예]
    
    <h1 class="title">개발자의 글쓰기</h1>
    
    

이름 하나만 지으면 기존 태그와 조합해 h1.title, img.title과 같이 사용이 가능하다.

  • Easy to Agree
  • Easy to Remember
  • Easy to Type

 

04 좋은 코드에는 주석이 없다?

 

이름을 잘 지으면 주석을 줄일 수 있다

이름을 잘 지으면 주석을 대폭 줄일 수 있다. 이름이 주석이 할 일을 대신하기 때문이다.

[안 좋은 예]

//스크린 최대 높이를 480으로 지정함
const h = 480

//사용자 유형을 분류해서 등급 값을 리턴함
const levelUser()

[좋은 예]

const screenHeightMax = 480

const classifyUserAndReturnClass()

 

처음부터 주석 없이 코딩하는 연습을 하자

[안 좋은 예]

"success": [// 구독자 추가 성공.],
"update": [// 이미 있는 구독자, 나머지 필드를 업데이트함.]
"failDeny": [//수신 거부 상태의 구독자, 추가하지 않음.],
...

 

Success라 이름 짓고 주석엔 ‘구독자 추가 성공’이라고 함.

그럼 뒤에 나오는 update는 실패인가? 분명 아니다.

여기선 구독자가 없으면 새로 등록하고, 구독자가 있으면 구독자 정보를 갱신하는 것이므로,

success와 update가 아닌 create와 update로 표한하는 것이 옳다.

 

[좋은 예]

"created": [
],
"updateInformationExceptEmail": [
],
"noCreatedBecauseUnsubscriber": [
],
"noCreatedBecauseWrongEmail": [
],
...

 

주석이 필요한 때도 많다

‘사용자 이름이 3글자 이하인지 체크’하는 경우

checkUserNameUnder3Characters()

라고 작성했다면?

3글자 이하는 다음과 같이 쓴다

  • 3 and under
  • 3 or less
  • 3 or below

3글자 미만은 다음과 같이 쓴다

  • under 3
  • below 3
  • less than 3

예문의 경우엔 3글자 미만을 의미한다. 이런 점이 불안하다면 함수 옆에 주석을 붙이는 것이 좋다.

주석이 코드의 정확성을 높이고 버그를 줄이는 계기가 될 수 있다.

주석이 제 역할에만 충실하다면 많고 적고는 사실 상관없다.

 

 

05 다른 개발자를 배려하는 주석 쓰기

 

코드는 의미를, 주석은 의도를

글은 의미를 전달하는 수단이다. 코드도 마찬가지다.

밥 먹자는 의미를 가진 함수 이름을 letsEatSomething() 으로 지었다고 하자.

  • “나는 배가 고프다. 밥 먹자”
  • “네가 배가 고파 보인다. 밥 먹자”
  • “심심하다. 밥이나 먹자”

문제는 상위의 함수명으로 개발자의 의도를 전달할 수 없다는 것이다.

그렇다고 일일이 의도를 함수 이름에 포함하자니 코드 자체가 지저분해지며 가독성이 현저히 떨어지게 된다.

그래서 코드에 표현하지 못한 어떤 의도를 전달해야 할 경우 주석을 쓸 수밖에 없다.

letsEatSomething() // 내가 배가 고픈 상황
letsEatSomething() // 네가 배가 고픈 상황
letsEatSomething() // 내가 심심한 상황

주석을 사용하는 이유?

  • 코드를 왜 이렇게 작성했는지 설명
// 모바일에서 테스트했더니 0.5 이상은 품질 차이가 없었다.
// 로딩 속도는 2배 빨랐다.
  • 새롭게 발견한 것
// 놀랍게도 이 방식이 기존보다 결괏값을 2배 빠르게 보여준다.
// 난 단지 순서만 바꿨을 뿐이다.
  • 예상 질문과 답
// 잘 보면 왜 마지막 대화 ID를 기록하는지 궁금할 것이다.
// 팀 사이트에서 LastTalkId 변수를 검색해서 확인하자. 
  • 할 일이나 주의, 개선 아이디어 제공
// TODO: 동영상이 아닌 동영상 확장자를 확인하는 기능을 넣을 것
// XXX: null이 입력되면 무한 루프가 발생할 가능성이 있음
// 이 버튼은 한 번만 호출하면 됩니다.
  • 다른 사람에게 보완을 요청
// 전역변수를 잘못 쓰면서부터 이 클래스는 엉망이 되었다.
// 누가 좀 고쳐서 깃허브에 올려달라.
  • 개발자의 속마음 표현
// 솔직히 이 코드는 마음에 안 든다.
// 팀의 컨벤션만 아니라면 클래스명부터 바꿨을 것이다.

 

주석의 반복

개발 가이드 문서를 읽다 보면 같은 주석이 수없이 반복되는 것을 볼 수 있다.

Ex. 카카오 개발 문서의 “사용할 앱의 js 키를 설정해 주세요.”

효율적이지 않아 보이지만 코드를 처음부터 읽지 않고, 필요할 때 특정 함수를 검색해서 보는 경우도 생각해봐야한다.

네이버 및 카카오 개발자센터에서 제공하는 개발 가이드 문서는 보통 처음부터 차근차근 읽는 경우보다 목차를 보고 원하는 페이지로 바로 이동하는 경우가 많다.

그 주석이 언제 어떻게 읽히는지에 따라 반복해서 쓸 것인지를 결정해야 한다.

 

주석의 발췌와 요약

// 사용자가 레벨업하려면 로그인을 10회 이상하고 게시물을 5개 이상 작성해야 한다.

if(user.getLoginCount() > = 10 && user.getOwnArticleCount() >= 5) {
	
	const level = user.getlevel();
	user.setLevel(level++);
}

 

예문의 주석은 함수의 조건문을 그대로 설명한다. 그런데 잘 보면 승급 조건을 설명한 것이다.

승급 조건과 승급이라는 상위 개념을 사용하면 불필요한 주석 없이도 빠르게 이해가 가능하다.

 

// 승급 조건이 되면 승급한다

..상위와 같은 코드

// 하지만 실제로는 다음과 같이 리팩토링하여 주석을 없애는 편이 더 좋다

if(user.enoughToLevelUp())
{
	user.levelUp();
}

 

반응형