현인

네이밍 치트시트(Naming Cheatsheet) with JavaScript 본문

기술 학습/ETC

네이밍 치트시트(Naming Cheatsheet) with JavaScript

현인(Hyeon In) 2023. 8. 20. 19:19

들어가며

개발을 할 때 네이밍은 언제나 골칫거리 입니다. Github에 관련된 치트시트가 있어서 내용을 알아보게 되었습니다.

참고로 자바스크립트를 예제로 사용하기에 자바스크립트가 주 언어가 아니시라면 가볍게 개념만 읽어주셔도 좋을 것 같습니다.

영어 사용

/* Bad */
const primerNombre = 'Gustavo'
const amigos = ['Kate', 'John']

/* Good */
const firstName = 'Gustavo'
const friends = ['Kate', 'John']

식별자 네이밍은 영어를 활용합니다.

좋든 싫든 영어는 프로그래밍에서 지배적인 언어입니다. 모든 프로그래밍 언어의 구문은 영어로 작성되며 수 많은 문서와 교육 자료도 영어로 작성 되기에 코드를 영어로 작성한다면 응집력이 크게 향상됩니다.

한국에서는 몇몇 기업에서 한글로 코드를 짜는 추세인 것 같던데.. 일단 영어가 지배적인 언어임은 맞으니까요 :)

네이밍 컨벤션

하나의 네이밍 컨벤션을 선택하고 따릅니다. camelCase , PascalCase, snake_case 이나 다른 컨벤션이 있다면 일관성 있게 유지합니다. 대부분의 프로그래밍 언어에는 네이밍 컨벤션과 관련된 고유한 전통이 있습니다. 자신의 사용하는 언어에 대한 공식 문서나 GitHub에서 인기 있는 레포지토리를 연구해보시면 어떤 네이밍 컨벤션을 주로 사용하는지 확인하실 수 있습니다.

/* Bad */
const page_count = 5
const shouldUpdate = true

/* Good */
const pageCount = 5
const shouldUpdate = true

/* Good as well */
const page_count = 5
const should_update = true

SID

네이밍은 짧고 직관적이며 설명적(descriptive)이어야 합니다.

  • 짧게
    • 타이핑 하는데 오래 걸리지 않아야 합니다
  • 직관적
    • 가능한 일반적인 언어를 사용해야 자연스럽게 읽힙니다.
  • 설명적
    • 함수가 하는 일이나 변수가 담고 있는 내용을 설명할 수 있어야 합니다.
 /* Bad */
const a = 5 // "a" could mean anything
const isPaginatable = a > 10 // "Paginatable" sounds extremely unnatural
const shouldPaginatize = a > 10 // Made up verbs are so much fun!

/* Good */
const postCount = 5
const hasPagination = postCount > 10
const shouldPaginate = postCount > 10 // alternatively

 “주석이 필요한 변수명은 좋은 변수명이 아니다.”  - 모던 자바스크립트 딥다이브 中

축약표현 피하기

변수명이 길어져서 줄임말로 사용할 수 있는데, 코드의 가독성만 떨어뜨리는 것 외에는 아무것도 기여하지 않습니다. 짧고 설명적인 이름을 찾는 것이 어려울 수 있지만, 축약 표현이 대신이 되면 안됩니다.

/* Bad */
const onItmClk = () => {}

/* Good */
const onItemClick = () => {}

별다줄 금지입니다 :) 저도 가끔 줄일 때가 있었어서 뜨끔하더라고요 ㅎㅎ

컨텍스트 중복 피하기

이미 정의된 컨텍스트를 중복하여 사용하는 것은 피해야 합니다. 컨텍스트를 지워도 가독성이 떨어지지 않는다면 네이밍을 할 때 가급적이면 중복 컨텍스트를 지워주세요.

class MenuItem {
  /* Method name duplicates the context (which is "MenuItem") */
  handleMenuItemClick = (event) => { ... }

  /* Reads nicely as `MenuItem.handleClick()` */
  handleClick = (event) => { ... }
}

예상 결과가 반영되도록

네이밍은 예상 결과를 반영해야 합니다.

 /* Bad */
const isEnabled = itemCount > 3
return <Button disabled={!isEnabled} />

/* Good */
const isDisabled = itemCount <= 3
return <Button disabled={isDisabled} />

함수 네이밍

A/HC/LC 패턴

함수 네이밍을 할 때 유용한 패턴이 있습니다.

prefix? + action (A) + high context (HC) + low context? (LC)

아래 표를 보며 실제로 어떻게 적용되는지 보겠습니다.

Name prefix Action (A) High context (HC) Low context (LC)

getUser   get User  
getUserMessages   get User Messages
handleClickOutside   handle Click Outside
shouldDisplayMessage should Display Message  

참고: 컨텍스트 순서는 변수(함수)의 의미에 영향을 줍니다. 예를 들어, 컴포넌트를 업데이트 하려고 한다는 의미라면 shouldUpdateComponent , 컴포넌트가 자체적으로 업데이트 되며 업데이트 해야 하는 시기만 제어한다는 의미라면 shouldComponentUpdate 라고 표기하는 것이 바람직합니다. 즉, 상위 컨텍스트는 변수(함수)의 의미를 강조합니다.

Action (A)

get

데이터에 즉시 접근합니다. (내부 데이터의 getter의 속기 표현)

function getFruitCount() {
  return this.fruits.length
}

비동기 작업을 수행할 때도 사용할 수 있습니다.

async function getUser(id) {
  const user = await fetch(`/api/user/${id}`)
  return user
}

set

어떤 변수의 A라는 값을 B라는 값으로 설정할 때 선언적 방식으로 설정합니다.

let fruits = 0

function setFruits(nextFruits) {
  fruits = nextFruits
}

setFruits(5)
console.log(fruits) // 5

reset

변수를 초기 값 또는 초기 상태로 재설정합니다.

const initialFruits = 5
let fruits = initialFruits
setFruits(10)
console.log(fruits) // 10

function resetFruits() {
  fruits = initialFruits
}

resetFruits()
console.log(fruits) // 5

remove

어딘가에서 무언가를 제거합니다.

예를 들어, 검색 페이지에서 여러 개 필터를 선택 한 경우 이 필터 중에서 하나를 제거하는 것은 removeFilter 입니다. deleteFilter 가 아닙니다.(그리고 자연스럽게 영어로도 이렇게 말할 수 있습니다).

function removeFilter(filterName, filters) {
  return filters.filter((name) => name !== filterName)
}

const selectedFilters = ['price', 'availability', 'size']
removeFilter('price', selectedFilters)

delete

무언가를 완전히 지웁니다.

당신이 콘텐츠 편집자이고 제거하고 싶은 악명 높은 게시물이 있다고 상상해 봅시다. 반짝이는 "게시물 삭제" 버튼을 클릭하면 CMS(Content Management System)가 deletePost 작업을 수행할 것입니다.

function deletePost(id) {
  return database.find({ id }).delete()
}

remove vs delete remove 와 delete 의 사용이 조금 모호하게 들릴 수 있습니다. 이럴 때 add 와 create 를 생각해보면 좋습니다. add 는 어딘가에 추가해야 하기에 ‘어딘가’라는 목적지가 필요한 반면에 create 는 목적지가 필요 없습니다. remove 는 add 의 느낌으로 사용하고 delete 는 create 의 느낌으로 사용하면 됩니다.

조금 더 상세한 내용은 여기를 참조해주세요

compose

기존 데이터에 새로운 데이터를 추가합니다. 대부분의 문자열, 객체 또는 함수에서 적용할 수 있습니다.

function composePageUrl(pageName, pageId) {
  return pageName.toLowerCase() + '-' + pageId
}

handle

액션에 대한 처리를 담당합니다. 보통 콜백 함수를 네이밍 할 때 사용합니다.

function handleLinkClick() {
  console.log('Clicked a link!')
}

link.addEventListener('click', handleLinkClick)

 


Context (HC/LC)

함수가 작동하는 도메인입니다.

함수는 대부분 무언가에 대한 조치를 담당합니다. 여기서 무언가를 명시할 때 예상되는 데이터 유형을 명시하는 것이 중요합니다.

/* A pure function operating with primitives */
function filter(list, predicate) {
  return list.filter(predicate)
}

/* Function operating exactly on posts */
function getRecentPosts(posts) {
  return filter(posts, (post) => post.date === Date.now())
}

일부 언어별 상세(Specific)를 보면 컨텍스트를 제외합니다. 예를 들어, 자바스크립트에서 filter 연산은 배열 객체에 사용하는 경우가 일반적이기에 filterArray 처럼 표기하지 않습니다.


Prefixes

접두사는 변수의 의미를 향상 시킵니다. 함수 이름에는 거의 사용되지 않습니다.

is

현재 컨텍스트의 특성 또는 상태를 설명합니다. (일반적으로 boolean 값을 가짐)

const color = 'blue'
const isBlue = color === 'blue' // characteristic
const isPresent = true // state

if (isBlue && isPresent) {
  console.log('Blue is present!')
}

has

현재 컨텍스트가 특정 값 또는 상태를 보유하는지 여부를 설명합니다. (일반적으로 boolean 값을 가짐)

/* Bad */
const isProductsExist = productsCount > 0
const areProductsPresent = productsCount > 0

/* Good */
const hasProducts = productsCount > 0

should

특정 작업과 결홥된 긍정적인 조건문을 반영합니다. (일반적으로 boolean 값을 가지거나 반환함)

function shouldUpdateUrl(url, expectedUrl) {
  return url !== expectedUrl
}

min / max

최소값 또는 최대값을 나타냅니다. 경계나 한계를 설명할 때 사용합니다.

/**
 * Renders a random amount of posts within
 * the given min/max boundaries.
 */
function renderPosts(posts, minPosts, maxPosts) {
  return posts.slice(0, randomBetween(minPosts, maxPosts))
}

prev / next

현재 컨텍스트에서 변수의 이전 또는 다음 상태를 나타냅니다. 상태 전환을 설명할 때 사용됩니다.

async function getPosts() {
  const prevPosts = this.state.posts

  const latestPosts = await fetch('...')
  const nextPosts = concat(prevPosts, latestPosts)

  this.setState({ posts: nextPosts })
}

단수와 복수

접두사처럼 변수 이름은 단일 값을 보유하는지 또는 다중 값을 보유하는지에 따라 단수 또는 복수로 만들 수 있습니다.

/* Bad */
const friends = 'Bob'
const friend = ['Bob', 'Tony', 'Tanya']

/* Good */
const friend = 'Bob'
const friends = ['Bob', 'Tony', 'Tanya']

 

마치며

이번 글이 앞으로 네이밍에 대해 고민하게 될 때 종종 찾아보면서 꾸준히 참고 할 수 있는 자료가 되었으면 합니다. 어디까지나 원본을 번역해서 작성한 것 뿐이라 오역이 있을 수도 있습니다. 이해가 잘 안되실 때 원본 글을 참고하셔도 좋을 것 같습니다. 원본 GitHub에 등록된 이슈들을 통해 다른 개발자들의 고민들도 확인 해볼 수 있습니다. 감사합니다 :D

참고 자료

- https://github.com/kettanaito/naming-cheatsheet

반응형

'기술 학습 > ETC' 카테고리의 다른 글

[Git] 브랜치 일괄 삭제  (0) 2024.06.27