[번역]고전적인 코드 규약과 라이브러리에서 배우는 JavaScript 네이밍 테크닉(상급편)

doakuma·2022년 10월 30일
0

CodingConvention

목록 보기
4/4
post-thumbnail

이 글은 ICS MEDIA에 등록된 定番のコード規約とライブラリから学ぶJavaScriptの命名テクニック(上級編)을 번역한 내용입니다

일반적으로 프로그래머는 코딩하는 시간보다 분석하는 데에 시간이 더 걸린다고 하며, 쉽게 이해할 수 있는 네이밍은 가독성이나 유지보수 측면에서 매우 중요합니다.

이 글은 Google이나 Airbnb 등의 기업에서 채용하고 있는 스타일가이드나 전 세계에서 쓰이고 있는 JavaScript 라이브러리인 React와 Vue.js의 코드를 조사하는 과정에서 발견한 이해하기 쉬운 네이밍을 위한 테크닉을 초급편과 상급편으로 2회에 걸쳐 소개합니다.

이전 글인 초급편에서는 이해하기 어려운 네이밍을 한 경우의 문제점이나 JavaScript에서 공통적으로 인식하고 있는 규칙, 바로 사용할 수 있는 네이밍 테크닉을 소개하였습니다.

상급편인 이번 글에서는 초급편에서 소개한 것만으로는 표현하기 어렵고 보다 복잡한 처리를 수행할 때에 도움이 되는 표현을 모았습니다.


네이밍 테크닉 상급편

1. 유효 / 무효 상태의 표시

객체나 상태값이 유효인지 무효인지 표현하는 단어입니다.

설명예시
valid유효isValidName: 유효한 이름인가 아닌가(boolean)
invalid무효invalidMessage: 유효하지 않은 메세지(문자열 형태)
const response = awat fetchData();

// response가 유효하지 않으면 isInvalid = true
if (response.isInvalid) {
  // 유효하지 않은 상세 내용 표시
  window.alert(`유효하지 않은 요청입니다. 내용: ${response.inVAlidMessage}`);
}

2. value 검증

validate는 입력 값 체크나 대상이 올바른 상태인지 아닌지를 검승하는 경우 등에 자주 사용되는 표현입니다.
| | 설명 | 예시 |
|:----------:|:----------|:----------|
|validate|검증|validateProps: props가 올바른 값인지 검증(함수)|

/** 대상자의 최저 연령 */
const TARGET_MIN_AGE = 7;
/** 보호자의 최저 연령 */
const GUARDIAN_MIN_AGE = 18;

/**
 * 대상자와 보호자의 연령을 검증합니다
 *
 * @param targetAge {number} 대상자 연령
 * @param guardianAge {number} 보호자 연령
 */
const validateAge = (targetAge, guardianAge) => {
  if (targetAge < TARGET_MIN_AGE && guardianAge < GUARDIAN_MIN_AGE) {
    // 대상자와 보호자 모두 최소연령 미만일 경우에 경고 표시
    window.alert(`대상자가 ${TARGET_MIN_AGE}세 미만인 경우, 보호자는 ${GUARDIAN_MIN_AGE}세 이상이어야 합니다.`);
  }
}

3. 유효 / 무효 상태의 변경

객체 등의 유효 무효의 상태를 변경할 때 아래와 같은 표현으로 사용할 수 있습니다

설명예시
activate~을 활성화activateChildComponent: 자식 컴포넌트 활성화(함수)
deactivate~을 비활성화deactivateComponent: 컴포넌트 비활성화(함수)
enable~을 제어 / 조작을 가능하게 한다enableSound: 소리가 나게한다(함수)
disable~을 제어 / 조작을 불가능하게 한다disablePicture: 이미지가 표시되지 않게 한다(함수)
// 사운드 활성화
const enableSound = () => {
  // 사운드 활성화 처리
};

// 이미지 표시 활성화
const enablePicture = () => {
  // 이미지 표시가 가능하도록 처리
};

if (window.confirm('음악을 좋아하시나요?')) {
    enableSound();
}
if (window.confirm('사진이나 그림을 좋아하시나요?')) {
  enablePicture();
}

4. 처리 조건이나 결과 표시

처리 실행에 조건이 있거나, 실행 결과를 명확하게 하고 싶을 때 사용하는 표현입니다.

설명예시
if!인 경우 처리 수행warnIfUnsupported: 지원하지 않는 경우에 경고(함수)
warnIfFailed: 실패한 경우에 경고(함수)
with~에 따라 / ~와 함께 처리를 수행closeWithError: 에러 표시후 닫기(함수)
runWithPriority: 우선 순위에 따라서 실행(함수)
without특정 조건 이외의 것
특정 조건을 사용하지 않고 처리
nameWithoutWhitespace: 공백을 포함하지 않는 이름(문자열)
as처리의 결과 표현getAsString: 문자열로서 값을 가져오기(함수)
sotreAsGlobal: 전역 객체로 저장(함수)
const animals = [
  {name:'고양이', type:'felidae'},
  {name:'호랑이', type:'felidae'},
  {name:'팬더', type:'ursidae'},
  {name:'치타', type:'felidae'},
];

/**
 * 고양이과가 아닌 경우 경고
 *
 * @param animal ({name: string, type: strihg}) 동물
 */
const warnIfNotFelidae = (animal) => {
  if (animal.type !== 'felidae') {
    console.warn(`${animal.name}은 고양이과가 아닙니다!`);
  }
}

warnIfNotFelidae(animals[0]); // 고양이는 고양이과
warnIfNotFelidae(animals[2]); // 팬더는 곰과

5. 한 번만 수행하는 처리임을 강조

주의를 더해야하는 처리등에서 두 번 이후로는 표시하지 않도록 하는 요건이 자주 있습니다. "한 번만"을 표현하고 싶을 때에는 once를 사용합니다

설명예시
once한 번만warnOnce: 한 번만 경고(함수)
const suggestion = {
  isSuggested: false,
  message: '좋은 날씨에요. 밖으로 나가실래요?',
}

// 한 번만 제안
const suggestOnce = () => {
  if (!suggestion.isSuggested) {
    window.alert(suggestion.message);
    suggestion.isSuggested = true;
  }
}

for (let i = 0; i < 5; i++) {
  // 5번 반복해도 제안은 한 번만 수행
  suggestOnce();
}

6. 주의해야 할 처리 표시

주의를 필요로하는 처리를 실행할 때 각 함수명에 정보를 부여하는 것으로 호출할 때 주의를 더하는 것이 가능합니다.

또한 네 번째 예시처럼 함수명을 의도적으로 길게 네이미으 하는 것으로 주의를 끌거나 구체적으로 어떤 위험이 있는지 표시하는 것도 사용하는 방법에 따라서 유효할 것 같습니다.

설명예시
dangerous위험한dangerouslySetInnerHTML: inner HTML을 설정(함수)
(이 처리는 위험을 동반)
force강제로forceUpdate: 강제 업데이트(함수)
urgent긴급, 우선 순위가 높은urgentCall: 긴급 호출
-구체적인 위험도를 표현하는 패턴autofixThisMayCauseInfiniteLoops: 자동 수정(함수)
(무한 루프를 일으킬 수 있음)
const tasks = [
  {title: '저녁 식사 재료 사기', done: false},
  {title: '은행 가기', done: true},
  {title: '방 청소 하기', done: false},
  {title: '빨래 하기', done: true},
];

/**
 * 완료된 태스크만 삭제
 *
 * @param index { number } 삭제할 태스크 index
 */
const deleteTaskAt = (index) => {
  if(!tasks[index].done) {
    console.warn('완료되지 않은 태스크는 삭제할 수 없습니다.');
  } else {
    forceDeleteTaskAt(index);
  }
};

/**
 * 상태와 상관없이 태스크를 강제로 삭제
 *
 * @param index { number } 삭제할 태스크
 */
const forceDeleteTaskAt = (index) => {
  tasks.splice(index, 1);
}

deleteTaskAt(0); // 태스크가 완료되지 않았으므로 에러
forceDeleteTaseAt(0); // 강제로 태스크 삭제

7. 특정 값을 추출, 유출

특정 객체나 배열에서 필요한 정보만을 추출하는 처리에 사용하는 것이 extract입니다. 추출하는 행위와 추출 결과값에도 사용할 수 있습니다.

설명예시
extract추출extractId: ID 추출(함수)
extracted: 추출된 값
/**
 * 퇴직하지 않은 직원 추출하기
 *
 * @param employees {{name: string, department: string, isRetired: boolean}[]} 직원 리스트
 */
const extractCurrentEmployees = (employees) => {
  return employees.filter((employee) => !employee.isRetired);
};

const allEmployees = [
  {name: '정우성', department: '마케팅부', isRetired: true},
  {name: '이정재', department: '판촉부', isRetired: false},
  {name: '김태희', department: '경영지원부', isRetired: false},
];

// 추출된 직원
const extracted = extractCurrentEmployees(allEmployees);

8. 업데이트되거나 추가를 전제한 일시적인 값

일반적인 값을 저장하는 변수명의 안티패턴으로 잘 알려진 것은 tmptemp입니다. 이러한 변수명은 일시적이라는 것은 알아도 실태가 무엇인지 알 수 없습니다.

so far는 "지금", "지금까지의"라는 뉘앙스가 있는 표현입니다. tmp등과 같이 so far만 사용하면 일시적이라는 이외의 의미는 갖지 않게 되므로 구체적인 명사와 조합하여 "이후에 업데이트 되어도 지금은 이 값"이라는 경우에 사용합니다.

또한 일시적인 값은 가독성을 고려하여 스코프 안(for 루프 안 등)에서만 사용하는 것을 추천합니다. 업데이트 될 가능성이 있는 변수가 여기저기 있으면 가독성도 떨어지고 버그의 원인이 되기도 합니다.

설명예시
so far지금, 지금까지의pathSoFar: 현재 경로
nameSoFar: 현재 이름(문자열)
const names = ['Neo', 'Trinity', 'Morpheus', 'Oracle', 'Agent Smith'];

/**
 * 가장 긴 이름 찾기
 *
 * @params names {string[]} 이름 리스트
 */
const detectLongestName = (name) => {
  let nameSoFar = '';
  for (const name of names) {
    nameSorFar = nameSorFar.length >= name.length ? nameSoFar : name;
  }
  // 루프를 빠져나온 시점에 nameSoFar에 있는 값이 가장 긴 이름
  const longestName = nameSoFar;
  return longestName;
}

console.log(`문자 수가 가장 긴 이름은 ${dettectLongestName(names)}입니다.`);

9. 추가된 값이나 필수가 아닌 값

필수는 아니지만 추가적으로 처리를 수행하고 싶거나 없어도 문제가 되니는 않지만 "설정할 수 있는 값 등"을 표현하고 싶을 때느 extra를 사용할 수 있습니다.

설명예시
extra추가의(필수가 아님)extraWarning: 추가적인 경고
extraConfig: 추가적인 설정값
const isRaning = true;
const message = '안전운전 하세요';
let extratWarning = null;

if (isRaning) {
  // 비오는 날에만 경고
  extraWarning = '비오는 날에는 미끄러지기 쉬우니 주의하세요'
}

console.warn(message);
if (extraWarning) {
  console.warn(extraWarning);
}

10. 남은 값

extra와 비슷한 표현으로 remaining은 남은 값을 나타냅니다.

extra가 단순히 추가된 것 같은 뉘앙스라는 것에 반해, remaining은 빼고 남은 것 같은 이미지입니다.

설명예시
remaining남은, 나머지remainingWidth: 나머지 너비(숫자형)
remainingText: 나머지 텍스트(문자열)
const maxWidth = 600;

const innerWidth = window.innerWidth;

// 윈도우 화면 폭에서 최대 폭(600px)을 빼고 남은 폭
const remainingWidth = innerWidth - maxWidth;

11. ◯◯이 가능한 ◯◯

초급편에서 "~이 가능한지"는 can이라고 소개하였습니다만, 그것만으로 표현을 다 할수 없는 경우에는 able을 사욜할 수도 있을 것 같습니다.

can은 다음에 이어지는 동사가 "지금 실행 가능한지"를 나타내므로 truefalse를 반환하는 메서드나 boolean을 저장하는 변수의 이름에 적합합니다.

반면 able은 "그 기능이 있는지 없는지"라는 뉘앙스입니다. 이후에 이어지는 명사를 수식할 수 있으므로 아래와같은 예시처럼 "읽어들일 수 있는 사이즈"등의 기능+대상을 나타내고 싶은 경우에 사용하는 표현입니다.

설명예시
able~이 가능readableSize: 읽을 수 있는 사이즈(숫자형)
draggableComponent: 드래그할 수 있는 컴포넌트

12. 기대값과 다른 값이 들어롤 가능성이 있는 값

서버에서 읽어오는 값이나 api 리턴값 등 아마 이 값이 들어오지만 경우에 따라 아닐 수도 있을 경우 사용하는 표현입니다.

이 표현을 사용하는 변수나 함수 뒤에는 값이 정확한지 검증할 필요가 있습니다.

설명예시
maybe일지도 모르는maybeId: ID일수도 아닐수도
maybeMessage: 메세지 일수도
const maybeId = prompt('ID를 입력해주세요');

if (isValidId(maybeId)) {
  const id = maybeId;
  const user = await fetchUser(id);
} else {
  window.alert('유효한 ID가 아닙니다');
}

13. 부족하거나 없는 경우

필수항목이 아니고 기대값에 대해 무언가 부족한 경우를 나타낼 때에는 missing을 사용하여 네이밍할 수 있습니다.

설명예시
missing부족한
~가 없다
missingDependencies: 부족한 의존관계
detectMissingProps: 모자란 프로퍼티 찾기
const missingProps = ['name', 'height'];

if (missingProps.length > 0) {
  // 모바란 프로퍼티에 관한 처리
}

14. ~을 할 예정인 것

지금부터 특정 처리를 수행할 예정인 것은 명사 + to + 동사의 형태로 표현할 수 있습니다.

설명예시
to~할 예정의 ~dataToMerge: 머지할 예정인 데이터
entryToSave: 저장할 예정의 엔트리
const diaryToSave = {
  title: '오늘 일기',
  date: '2022/10/30';
  content: '오늘 점심은 인도 커리였다.'
};

save(diaryToSave);

15. 묶음을 나누는 것

전화번호나 우편번호를 나누는 하이픈 등, 어떤 것과 어떤 것을 나누는 역할을 하는 것은 seperator라고 표현할 수 있습니다

const SEPERATOR = '-';

/**
 * 하이픈으로 구분된 전화번호를 하이픈이 없는 형태로 변환
 *
 * @param phone { string } 하이픈으로 구분된 전화번호 문자열
 */
const unhyphenate = (phone) => {
  return phone.split(SEPERATOR).join('');
};

const phone = '010-1234-5678';
const unhyphenated = unhyphenate(phone);

나가며

매일 코딩을 하고 있으면 이 변수는 어떻게 네이밍을 하지? 이 함수를 표시하는 최적의 네이밍은 뭘까? 라느 고민을 할 때가 많습니다. 그럴 때 문득 유명 라이브러리를 조사해 보면 힌트를 얻을 수 있을 것 같다는 생각이 이 글을 작성한 계기가 되었습니다.

이 글에서 소개한 것은 React와 Vue.js를 조사하여 찾아낸 것 중 단지 일부에 지나지 않으며, 무엇보다 네이밍에는(코딩과 마찬가지로) 정답은 없습니다. 하지만 공통 규약이나 자주 사용하고 있는 표현 등을 의식하는 것으로 보다 이해하기 쉬운 네이밍을 할 수 있지 않을까라는 생각이 듭니다.

이 글을 통해 소개한 테크닉이 네이밍에 약간이라도 도움이 되길 바랍니다.

profile
늦깎이 프론트 개발자

0개의 댓글