GomJu's Coding Blog

[JS] 21. 기본 포맷 본문

WEB/JavaScript

[JS] 21. 기본 포맷

GomJu 2018. 12. 1. 13:06

기본 포맷

스타일 가이드의 핵심은 기본 포맷 규칙입니다. 규칙에 따라 코드를 어떻게 작성할지 큰 틀에서 정합니다. 개발자가 중요하지 않게 생각하는 문법들을 다루기도 하지만 코드를 일관되게 작성하려면 이런 모든 규칙이 중요합니다.

1.1 들여쓰기

들여쓰기는 자바스크립트 뿐만아니라 거의 모든언어에서 첫번째로 결정하는 부분입니다. 마치 종교적 논쟁처럼 소프트웨어 엔지니어들끼리 몇 시간동안 논쟁할 수 있는 주제입니다. 들여쓰기가 재대로 되어있지 않으면 일관성이 없기 때문에 코드를 빠르게 이해할 수 없게됩니다.

들여쓰기에는 크게 두 가지 의견이있습니다.

탭을 이용한 들여쓰기

들여쓰기를 탭으로 처리합니다. 즉 한 단계 들여쓰기는 탭 한번이고, 두 단계 들여쓰기는 탭 두번, 이런식으로 사용됩니다. 이 방법에는 여러 장점이 있습니다. 먼저, 탭과 들여쓰기 단계가 일대일로 대응되어 '논리적'입니다. 또한 각 텍스트 에디터에서 탭 크기를 원하는 대로 설정할 수 있어서 들여쓰기를 좁게 설정하는 개발자나 넓게 설정하는 개발자 모두 원하는 대로 볼 수 있습니다. 하지만 탭에는 큰 단점이 있습니다. 그것은 바로 코드를 수정하는 시스템 마다 탭 크기를 다르게 표현하기 때문에 개발자 마다 같은 방식으로 코드를 보기 힘듭니다.

들여쓰기를 할 때 공백을 2개 또는 4개로 지정할 수 있습니다. 저는 WEB FrontEnd 개발자를 목표로하고 있기 때문에 들여쓰기의 공백을 두칸으로 합니다. 하지만 들여쓰기의 공백을 4칸으로 지정하는 것이 옳다고 말합니다. 왜냐하면 공백 2개로 들여쓰면 확대 및 축소를 했을때 들여쓰기를 했는지 구분하기 어려울 수 있기 때문입니다. 공백을 두칸으로 지정하면 코드의 가독성이 좋아지고, 한줄에 많은 코드를 작성할 수 있게 됩니다.

들여쓰기를 탭으로 할 것인가 공백으로 할 것인가는 스타일가이드라인을 지정하면서 결정하면 되는 일 입니다. 하지만 분명히 중요한 점은 탭과 공백을 함께 사용하면 절대 안됩니다. 끔찍한 코드가 탄생해서 나중에 누군가가 코드를 보며 정리 작업을 하느라 불필요한 고생을 하게 될 것 입니다.

1.2 줄 길이

줄길이는 들여쓰기와 깊은 관계가 있습니다. 코드의 가로 스크롤이 생길 만큼 길면 읽기 꽤 불편합니다. 요즘은 큰 모니터를 많이 쓰는데, 넓은 화면에서도 줄 길이를 적당히 유지하는 편이 생산성 면에서 더 좋습니다. 줄 길이 최대 80자는 다른 언어에서도 많이 사용되는 코딩 규칙입니다. 과거에는 텍스트 어디터에서 한 줄에 최대 80자밖에 보이지 않아서 80자 제한을 둬야 했습니다. 80자가 넘으면 예상치 못하게 겹쳐지거나 사라져버렸기 때문입니다. 물론 최신 텍스트 에디터는 예전보다 훨씬 성능이 좋아졌지만, 여전히 최대 80자 제한을 많이 사용합니다. 다음은 일반적으로 추천하는 줄 길이 입니다.

  • 자바 코딩 규칙에서는 소스 코드의 최대 줄 길이는 80자, 문서화 주석의 경우 70자로 명시했습니다.
  • 안드로이드 코드 스타일 가이드 배포본에는 최대 100자로 명시했습니다. 루비 사용법 가이드(비공식)에서는 최대 80자로 명시했습니다.
  • 파이썬 스타일 가이드라인에서는 라인당 79자로 명시했습니다.

자바스크립트 스타일 가이드라인에서는 대부분의 줄 길이를 정의하지 않지만, '크락포드'의 코드컨벤션에서는 최대 80자로 정의했습니다.

1.3 줄 바꿈

줄이 최대 글자수에 도달하면 두 줄로 나누어야 합니다. 보통은 연산자 다음에 줄을 바꾸고 두 단계 들여쓰기를 합니다. 다음은 공백 2개로 들여쓴 예제를 살펴봅시다.

// 좋은 예 : 연산자 이후 줄을 바꿈. 다음 줄은 들여쓰기를 두번함.
callAFunction(document, element, window, "some string value", true, 123,
    navigator);

이 예제에서 콤마는 연산자이므로 이전 줄에 있어야 합니다. 연산자의 위치는 세미콜론의 ASI 메커니즘과 연관이 있는데 연산자가 다음 줄로 넘어가면 ASI가 자동으로 세미콜론을 삽입할 수 도 있어 굉장히 중요합니다. 따라서 줄을 바꿀 때 연산자를 마지막에 찍는 습관을 들이면 ASI 에러를 방지할 수 있습니다.
또한 줄 바꿈을 한 뒤에는 들여쓰기를 두번 해야 합니다. 두번의 들여쓰기를 통해 가독성을 높일 수 있습니다.

다음 문장에도 줄 바꾸기 패턴을 적용할 수 있습니다.

if (isLeapYear && isFebruary && day === 29 && itsYourBirthday &&
    noPlans) {

      waitAnotherFourYears();
    }

예제와 같이 if 조건문은 && 연산자 이후에 줄을 바꿔 두 줄로 나눕니다. 이 때 if문 안에 문장은 줄 바꿈과 무난하게 한 단계 들여쓰기를 하는 편이 가독성이 더 높습니다.

줄을 바꿀 때는 한 가지 예외 사항이 있습니다. 변수를 다른 변수에 대입할 때 두 번째 줄의 들여쓰기는 첫 번째 줄의 변수와 열을 맞춥니다.

let result = something + anotherThing + yetAnotherThing + somethingElse +
             anotherSomethingElse;

이 코드와 같이 변수 anotherSomethingElse는 첫 번째 줄의 something과 열을 맞춰 들여 쓰면 첫 번째 줄과 관련이 있다는 것을 쉽게 알 수 있어 가독성이 높아집니다.

변수에서의 줄 바꿈은 space를 이용해서 맞춰줍니다.

1.4 빈 줄 넣기

빈 줄은 코드 스타일에서 자주 간과하는 부분입니다. 코드는 하나의 커다란 더엉리보다는 여러개의 문단으로 구성되어야 합니다. 그래서 연관된 코드와 그렇지 않은 코드를 구분하는 데 빈 줄을 사용합니다. 예를 들면 '1.1 들여쓰기'에서 문제를 언급한 기존 코드에 빈 줄을 추가하면 가독성이 향상됩니다. 다음은 빈 줄을 넣은 코드입니다.

if(wl && wl.length) {

  for (i = 0, l = wl.length; i < l; ++i) {
    p = wl[i];
    type = Y.Lang.type(r[p]);

    if (s.hasOwnProperty(p)) {

      if (merge && type == 'object') {
        Y.mix(r[p], s[p]);
      } else if (ov || !(p in r)) {
        r[p] = s[p];
      }
    }
  }
}

이 예제에서는 if문과 for 문 같은 제어문 앞에 빈 줄을 추가 했습니다. 이처럼 빈 줄을 추가하면 코드를 더 쉽게 읽을 수 있습니다. 보통 다음의 경우 빈 줄을 추가하는 것이 좋습니다.

  • 메서드 사이
  • 메서드 내 지역 변수와 첫 번째 문장 사이
  • 한 줄 또는 여러줄 주석 전
  • 가독성을 높이기 위해 메서드 내에서 논리적으로 구분되는 곳

1.5 이름 규칙

"컴퓨터 과학에서 가장 어려운 두 가지 문제는 캐시 무효화와 네이밍이다." - 필 칼튼

우리가 짜는 코드 대부분은 변수와 함수를 사용합니다. 따라서 변수명과 함수명에 대한 이름 규칙은 이해하기 쉬운 코드를 작성하는 데 꼭 필요하고 중요합니다. 자바스크립트의 기반이 되는 ECMAScript는 낙타 표기법 으로 작성되었습니다. 낙타 표기법은 소문자로 시작하고 새로운 단어를 사용할 때마다 첫 문자는 대문자로 입력되는 방식입니다. 예제를 살펴보면

const thisIsMyName;
const anotherVariable;
const aVeryLongVariableName;

일반적으로 자신이 사용하는 언어의 표준 라이브러리에서 따르는 이름규칙을 사용해야 합니다. 대부분의 낙타 표기법을 사용합니다. 구글 자바스크립트 스타일 가이드 및 SproutCore스타일 가이드, Dojo 스타일 가이드 모두 낙타 표기법을 사용하라고 명시하고 있습니다.

1.5.1 변수와 함수

변수명은 낙타 표기법을 사용하고 명사로 시작해야 합니다. 변수명은 명사로, 함수명은 동사로 시작하면 서로 구분하기 쉬워집니다. 예시를 살펴보겠습니다.

// 변수명의 좋은 예
let count = 10;
const myName = 'JunWoo';
let found = true;

// 변수명의 나쁜 예 : 함수와 혼동하기 쉽다.
let getCount = 10;
let isFound = true;

// 함수의 좋은 예
function getName() {
  return myName;
}

//함수의 나쁜 예 : 변수와 혼동하기 쉬움
function theName() {
  return myName;
}

변수명은 변수 이름만으로 데이터 타입을 알 수 있도록 만듭니다. 예를 들어 count, length, size와 같은 이름은 데이터 타입이 숫자인 것을 알 수 있습니다. 또 name, title, message같은 이름은 데이터 타입이 문자열임을 알 수 있습니다. i, j, k와 같이 한 글자로 된 변수는 보통 반복문에서만 사용합니다. 이런 식으로 변수명을 정하면 코드를 작성한 사람이나 다른 사람이 코드를 볼 때 이해하기 쉽습니다.

함수명과 메서드명의 첫 번째 단어는 동사로 시작해야 합니다. 보통 많이 사용하는 동사는 다음과 같습니다.

  • can : 불린 값을 반환하는 함수
  • has : 불린 값을 반환하는 함수
  • is : 불린 값을 반환하는 함수
  • get : 불린 이외의 값을 반환하는 함수
  • set : 값을 저장하기 위해 사용하는 함수

이러한 규칙을 따르는 것은 읽기 좋은 코드를 작성하는 시작점이 됩니다.

1.5.2 상수

자바스크립트에서 상수를 선언할 때에는 모든 문자를 대문자로 사용하고, 띄어쓰기를 할 시 _(언더스코어)를 붙입니다.

const MAX_COUNT = 10;
const URL = 'http://google.com';

이 때, 지금 다루는 상수가 단순히 이름을 달리하고, 값을 변경할 수 없는 변수라는 점을 유의해야 합니다. 다음 예제와 같이 이름 규칙을 달리하면 변수와 상수를 쉽게 구분할 수 있습니다.

if (count < MAX_COUNT) {
  doSomething();
}

이 예제에서 count는 마음대로 변경해도 되는 변수고, MAX_COUNT는 변경하면 안되는 변수라는 걸 쉽게 인지할 수 있습니다. 구글 자바스크립트 스타일 가이드 및 SproutCore스타일 가이드, Dojo 스타일 가이드 모두 상수로 사용할 변수는 반드시 앞에서 설명한 방법으로 선언해야 한다고 명시하고 있습니다.

1.5.3 생성자

자바스크립트에서 new 연산자로 새로운 객체를 생성하는데 사용됩니다. 하지만 생성자는 단순히 함수입니다. 자바스크립트에는 Object나 RegExp와 같은 내장된 생성자가 많이 있습니다. 또 개발자가 새로운 타입을 만들려고 새로운 생성자를 추가할 수도 있습니다. 생성자도 다른 이름 규칙처럼 언어의 표준 라이브러리에서 따르는 규칙을 사용해야 합니다. 자바스크립트에서 생성자는 파스칼 표기법을 사용합니다.

파스칼 표기법은 낙타표기법과 유사하지만 첫글자를 대문자로 사용합니다. 이렇게 하면 변수나 함수와 쉽게 구분가능 합니다. 생성자는 인스턴스를 만드는데 사용되므로 이름은 명사로 짓습니다.

// 좋은 예
function Person(name) {
  this.name = name;
}

Person.prototype.sayName = function() {
  alert(this.name);
};

const me = new Person("Nicholas");

여기서 설명한 생성자 이름 규칙을 따르면 이ㅔ러 위치를 찾기가 쉬워집니다. 파스칼 표기법의 명사로 된 함수 앞에는 new연산자가 있어야 합니다. 예제를 살펴봅시다.

const me = Person('Nicholas');
const you = getPerson('Michael');

첫 번째 줄을 보자마자 문제가 있음을 알 수 있습니다. 그리고 두 번째 줄은 이름 규칙에 따라 문제가 없다는 것을 쉽게 알 수 있습니다.

1.6 리터럴 값

자바스크립트에는 다양한 타입의 기본 리터럴 값이 있습니다. string, number, boolean, null, undefined, 객체 리터럴과 배열 리터럴도 있습니다. 그 중 boolean은 따로 설명이 필요 없지만, 그 외 다른 타입을 제대로 사용하기 위해서는 심사숙고 해야 합니다.

1.6.1 문자열

특별히 자바스크립트 문자열은 다음 예제처럼 큰 따옴표와 작은따옴표 모두 사용 가능합니다.

// 유효한 자바스크립트
const name = "Nicholas says, \"Hi.\"";

// 유효한 자바스크립트
const name = 'Nicholas says, "Hi."';

이 두 방식 중 어느 것을 선택해도 상관이 없습니다. 하지만 두 형식을 같이 사용하는 것은 절대 안됩니다. 하나를 선택해 코드 전체에 통일성 있게 사용해야 합니다.

하지만 크락포드의 코드 컨벤션과 제이쿼리 코어 스타일 가이드 모두 문자열에는 큰따옴표 사용을 권장합니다. 그런데 구글 자바스크립트 스타일 가이드에는 문자열에 작은따옴표를 사용을 권합니다. 개인적으로 작은 따옴표 사용을 주로 하는데, 좀더 가독성이 좋고, 편하기 때문입니다.

또 여러 줄에 걸쳐있는 문자열에 관해서도 더 생각해보아야합니다. 여러 줄에 걸친 문자열을 생성할 때 자바스크립트에 숨겨진 기능을 이용할 수 도 있습니다. 이 기능은 자바스크립트의 스펙은 아니지만 모든 엔진에 구현되어 있습니다.

// 나쁜 예
const longString = 'Here\'s the story, of a man \
                    named Brady.';

자바스크립트 문법으로는 좋은 방법은 아니지만 이 예제처럼 문자열을 여러 줄에 걸쳐 쓸 수 있습니다. 하지만 권장할 만한 방법은 아닙니다. 자바스크립트의 기능을 이용한 것이 아니라 언어의 특성을 이용했기 때문입니다. 구글 자바스크립트 스타일 가이드에서는 이 방법을 금지하고 있습니다. 여러 줄에 걸친 문자열을 사용하기보다는 문자열을 여러 개로 나눠 합치는 방법이 낫습니다.

// 좋은 예
const longString = 'Here\'s the story, of a man' +
                   'named Brady.';

1.6.2 숫자

자바스크립트에서 숫자는 정수, 실수에 상관없이 모든 타입이 숫자 타입에 저장됩니다. 다양한 숫자 형식을 표현하기 위해 다양한 숫자 선언 방법을 제공합니다. 긎 그 중 몇가지 문제가 될 수 있는 포맷이 있습니다.

// 정수
let count = 10;

// 십진수
let price = 10.0;
let price = 10.00;

// 십진수 선언의 나쁜 예 : 소수점이 뒤에 있음
let price = 10.;

// 십진수 선언의 나쁜 예 : 소수점이 앞에 있음
let price = .1;

// 나쁜 예 : 8진수는 사용하지 말 것
let num = 010;

// 16진수
let num = 0xA2;

// 지수 표기 
let num = 1e23;

10.과 같이 소수점을 마지막에 찍은 경우와 소수점을 맨 앞에 찍은 .1에는 모두 공통된 문제가 있습니다. 숫자 앞이나 뒤에 소수점이 있으면, 소수점을 인지하기 어려워 코드를 수정하다 빠뜨려도 알기 어렵습니다. 또한 다른 개발자가 봤을 때 오타로 생각할 수도 있습니다. 항상 숫자를 소수점 앞이나 뒤에 추가하면 이런 혼동을 방지할 수 있습니다. 10.과 .1 같은 두 가지 포맷 모두 여러 스타일 가이드에서 금지하고 있습니다.

8진수 포맷 사용에도 문제가 있습니다. 010값은 10을 의미하지 않고 8진수의 8을 의미합니다. 많은 개발자가 익숙하지도 않고, 쓰는 경우고도 거의 없기 때문에 8진수 리터럴을 허용하지 않는 경우가 많습니다.

1.6.3 null

보통 null에 대해 잘못 알고 있거나 undefined와 많이 혼동하는데 null 값은 다음과 같이 한정된 곳에서만 사용해야 합니다.

  • 나중에 값을 할당할 변수를 초기화할 때
  • 선언한 변수에 값이 할당되었는지 비교할 때
  • 인자 값으로 객체(Objec)를 넘기는 함수를 호출할 때
  • 함수를 호출한 곳에서 반환값으로 객체(Objec)를 기대할 때

다음은 null을 사용하면 안 되는 경우입니다.

  • 함수의 인자 값을 확인하기 위해 null로 비교해서는 안된다.
  • 초기화되지 않은 변수를 null로 비교해서는 안된다.

예제를 살펴보겠습니다.

// 좋은 예
let person = null;

// 좋은 예
function getPerson() {
  if (condition) {
    return new Person('Nicholas');
  } else {
    return null;
  }
}

// 좋은 예
let person = getPerson();
if (person !== null) {
  doSomething();
}

// 나쁜 예 : 인자값이 들어왔는지 null로 테스트하고 있음.
let person;
if (person !== null) {
  doSomething();
}

// 나쁜 예 : 인자값이 들어왔는지 null로 테스트하고 있음
function doSomething(arg1, arg2, arg3, arg4) {
  if (arg4 != null) {
    doSomethingElse();
  }
}

null은 Object를 대신한다고 생각하는 것이 가장 좋다고 말합니다. 주요 스타일 가이드에서 이 규칙이 다뤄지지는 않지만, 전체적인 유지보수성을 높이기 위해서는 중요합니다.

1.6.4 undefined

대부분 undefined와 null을 자주 혼동합니다. 이 둘을 잘 구분하지 못하는 이유는 null == undefined가 true이기 때문입니다. 그러나 undefined와 null의 사용법은 많이 다릅니다. 변수가 초기화 되지 않았을때 변수는 초기값을 undefined로 받습니다. 즉 변수가 실제 값으로 초기화 되기를 기다린다는 의미입니다.

// 나쁜 예
let person;
console.log(person === undefined);  // true

이 코드는 정상적으로 동작하지만, 코드에 undefined를 사용하는 것은 피해야 합니다. undefined에 typeof() 연산자를 실행시켜보면 'undefined'라는 문자열이 나타납니다. 실제로 초기화 되지 않은 변수에 typeof 연산자를 실행시켜보면 'undefined'문자열을 확인할 수 있습니다.

// 좋은 예
let person = null;
console.log(person === null);  // true

변수를 null로 초기화하면 자중에 값을 저장할 것이라는 의도를 명확히 할 수 있습니다. 또 typeof연산자는 null에 대해 'Object'문자열을 변환하여 undefined와 구분할 수 있습니다.

1.6.5 객체 리터럴

객체 리터럴은 Object의 인스턴스를 생성해 프로퍼티를 추가하는 방법에 비해, 간단히 추가할 프로퍼티를 정의하고 바로 객체를 생성할 수 있어 많이 사용됩니다.

다음 예제와 같은 방식은 거의 사용하지 않습니다.

// 권장하지 않음
let book = new Object();
book.title = 'Maintainable JavaScript';
book.author = 'Nicholas C. Zakas';

객체 리터럴은 중괄호 안에 모든 프로퍼티를 정의할 수 있습니다. 여러 스타일 가이드에서 이 방법을 권장합니다.

// 권장하는 방법
let book = {
  title : 'Maintainable JavaScript',
  author : 'Nicholas C. Zakas',
};

1.6.6 배열 리터럴

배열 리터럴은 객체 리터럴처럼 자바스크립트에서 배열을 간단히 선언하는 방법입니다. 다음 예제와 같이 Array 생성자를 사용하는 것은 권장하지 않습니다.

// 권장하지 않음
let colors = new Array('red', 'green','blue');
var numbers = new Array(1,2,3,4);

Array 생성자를 사용하는 방법 대신 2개의 대괄호를 사용하여 배열의 초기값을 설정합니다.

// 권장하는 방법
let colors = [ 'red', 'green', 'blue' ];
let numbers = [ 1, 2, 3, 4 ];

이 패턴은 자바스크립트에서 굉장히 많이 사용되고, 배열을 만들고 프로퍼티를 생성할 떄 괄호의 안쪽을 한칸 씩 띄웁니다. 또 콤마 뒤에 한칸을 뛰고 생성하는 것을 여러 스타일 가이드에서 권장합니다.


마무리

자바스크립트의 기본포맷에 대하여 설명드렸습니다. 이와 같은 규칙을 지키며 코딩하는 것이 협업에서는 무척 중요한 사항입니다. 제가 작성한 규칙을 제외하고도 여러규칙이 있습니다. 기호사항이니 참고하시기 바랍니다.

Comments