관리하기 쉬운코드 작성하기
최근의 웹앱은 수천 줄의 자바스크립트로 이루어져 있습니다.
다른사람의 코드를 관리하는데도 많은 시간을 보내므로 관리하기 쉬운 코드를 만들어야 합니다.
이번포스트에서는 그런 주제를 다룹니다.
관리하기 쉬운 코드란?
- 이해하기 쉬움
- 직관적임
- 적용하기 쉬움
- 확장하기 쉬움
- 디버그하기 쉬움
코드 표기법
코드 표기법을 정하는 것입니다.
자바스크립트는 특히 느슨한 데이터타입을 채택했기 때문에 다른 언어보다 이런점이 중요하게 작용합니다.
일반적인 코드 표기법에서 지켜야 할 것을 알아 보겠습니다.
가독성
관리하기 쉬운코드는 가독성이 좋아야 합니다.
그렇기 때문에 들여쓰기와 주석은 많은 부분을 차지 합니다.
- 함수와 메서드 : 각 함수나 메서드에는 그 목적을 반드시 주석으로 남겨야 합니다.
메서드에서 가정하는것, 매개변수의 의미, 함수가 값을 반환하는지에 대한 여부가 있어야 합니다. - 코드 블록 : 한가지 작업을 처리하는데 코드를 여러행 썼다면 주석을 남깁시다.
- 복잡한 알고리즘 : 문제해결을 위해 독특한 접근법을 썼다면 주석으로 남겨야 합니다.
- 핵 : 브라우저 차이때문에 무언가 핵을 썼다면 그에따른 주석을 남겨야 합니다.
변수와 함수 이름
올바른 이름을 붙여야 이해하고 관리하기 쉬워집니다.
foo, bar, doSomething같은 무의미한 이름을 붙이지 말아야 합니다. 이런 습관을 고쳐야 하며 일반적인 규칙은 아래와 같습니다.
- 변수이름은 car, person처럼 명사 사용
- 함수 이름은 getName()처럼 동사로 시작
- 불리언 값을 반환하는 함수는 isEnabled()처럼 is로 시작
- 변수나 함수이름은 길이를 신경쓰지 말고 논리적으로 정함(길이는 전처리 압축이 가능)
내용과 표현, 동작의 분리
한부분이 다른부분과 밀접하기 얽히면 코드 관리가 어려워집니다.
이런점을 염두하고 가능한 서로 분리해야 합니다.
HTML과 Javascript분리
html에 요소에 element로 javascript가 들어있다거나, javascript에서 innerHtml로 html을 삽입하는 경우가 이에 해당합니다.
이런경우는 최대한 줄이고
가능한한 HTML렌더링과 자바스크립트를 분리해야 합니다.
HTML과 자바스크립트를 분리하면 자바스크립트 파일은 동작만 담당, 마크업 파일이 렌더링을 담당하므로 에러를 찾기가 쉽습니다.
CSS와 JavaScript 분리
element.style.collor = “red”; 와같이 자바스크립트에서 처리할 경우 CSS에 문제가 있을 때 자바스크립트도 함께 살펴야 하는 어려움이 있습니다.
직접 자바스크립트에서 설정하지 않고 느슨하게 연결하는 방법을 사용해야 합니다.
//CSS와 자바스크립트의 느슨한 연결
element.className = "edit";
CSS에서 edit 클래스에 대한 스타일을 추가 해놓는다면 클래스를 변경하는 것만으로 CSS를 변경할 수 있습니다.
이렇게 하면 CSS문제는 CSS파일에서 해결 할 수 있습니다.
애플리케이션 로직과 이벤트 핸들러의 분리
일반적으로 많이 분리하지 않는 부분이긴하지만, 분리하기를 권장하고 있습니다.
이벤트 핸들러 내부에서 이벤트 처리외의 애플리케이션 로직은 따로 함수로 만들어서 호출하는 방법입니다.
이렇게 할 경우 애플리케이션 로직에 재활용도 가능하기 때문에 권장합니다.
프로그래밍 사례
코드 형식을 잘 갖춘다고만해서 자바스크립트를 관리하기 쉬워지는건 아닙니다.
브라우저 환경에서 고정 불변의 규칙을 지킵시다.
객체의 소유권 존중
- 인스턴스나 프로토타입에 프로퍼티를 추가하지 마십시오
- 인스턴스나 프로토타입에 메서드를 추가하지 마십시오
- 존재하는 메서드를 재정의하지 마십시오
stopEvent()라는 함수가 이벤트의 기본동작을 취소하도록 만들어졌는데 이걸 수정한다면 반드시 문제가 생길것입니다.
일반적으로 원래의 기능만 하는 메서드들을 수정하지 맙시다.
- 필요한 기능이 들어있는 새 객체를 생성하고 원하는 객체와 상호작용하게 함.
- 수정하려는 타입을 상속하는 커스텁타입 생성, 이후 그 커스텀타입에 기능 추가
위와같이 처리하길 권하며 보통 자바스크립트 라이브러리들은 이 이론을 따라 개발하고 있습니다.
전역을 피하자
전역변수나 함수사용을 가능한 피해야 합니다.
//전역에 추가하지말고
var name = "Kendrick";
function sayName(){
alert(name);
}
//아래처럼 객체를 만들어서 사용합시다.
var MyApplication = {
name: "Kendrick",
sayName: function(){
alert(this.name);
}
}
비교할때 null을 사용하지 말자
만약 배열을 받아 정렬을 하는 함수가 있다면 아래와 같이 하는게 낫습니다.
좋은 예와 나쁜예를 봅시다
//나쁜예
function sortArray(values){
if(values != null){ //undefined, number등이 들어온다면?
//정렬
}
}
//좋은예
function sortArray(values){
if (values instanceof Array){ //배열 외 잘못된 값 걸러냄
values.sort(comparator);
}
}
null을 비교했다면 아래중 하나를 대신 할 수 있는지 확인합시다.
- 값이 참조 타입이라면? instanceof 연산자를 써서 생성자 확인
- 값이 원시 타입이라면? typeof 연산자를 써서 타입 체크
- 특정 메서드를 가진 객체를 예상한다면? typeof를 써서 객체에 원하는 이름의 메서드가 존재하는지 확인
상수를 확인하자
공식적으로는 상수를 지원하지 않지만 아래와 같이 임의로 지정해서 사용할 수 있습니다.
var Constants = {
INVALID_VALUE_MSG : "Invalid value!",
INVALID_VALUE_URL : "/errors/invalid.php"
}
alert(Constants.INVALID_VALUE_MSG);
핵심은 데이터와 로직을 분리하는 것입니다.
- 반복되는 값 : 값이 한 곳 이상에 쓰이면 상수로 분리
- 사용자 인터페이스 문자열 : 사용자에게 표시하는 문자열은 상수로 분리해야 국제화작업이 쉬움
- URL : 자원의 위치가 자주 바뀌므로 URL한곳에 저장 권장
- 값 : 리터럴 값을 쓸 때마다 나중에 이 값을 바꿀 가능성이 있는 값은 상수로 분리
위와같이 한다면 코드를 관리하기 쉬워지고 안전하게 데이터를 수정할 수 있습니다.
성능
스코프를 유념
스코프체인을 이따라 이동하는 시간을 줄이면 스크립트 성능도 좋아집니다.
전역변수를 사용하면 스코프 체인을 따라 이동해야 하므로 로컬 변수에 비해 상당히 느립니다.
전역 검색을 피하자
document를 자주 참조하거나 반복문안에 있다면 항상 전역으로 스코프 체인검색을 하게 됩니다.
그렇기 때문에 document를 직접쓰지말고 로컬 변수를 생성해서 참조해줍시다.
var doc = document;
이렇게 사용할 경우 전역 검색을 한번만 수행하므로 성능이 좋아집니다.
with문을 피하자
with문은 자신만의 스코프를 생성하기 때문에 스코프 체인이 더 길어집니다.
위와같이 with문에서 사용할 스코프를 변수로 할당하여 사용하는 방법이 있습니다.
올바른 방법을 택하자
불필요한 프로퍼티 검색 피하자
일반적으로 알고리즘은 가능한 단순하게 만들어야 합니다.
프로퍼티는 가능한 로컬변수에 저장해야 합니다.
어떤 값에 접근 시 NodeList 객체러럼 인덱스와 이름 붙은 프로퍼티를 모두 쓸 수 있으면 인덱스를 사용합시다.
루프를 최적화하자
- 계수 감소
- 종료 조건 단순화
- 루프 본문을 단순하게
- 평가 전 루프를 사용하자 - do-while
루프 해체
루프 횟수가 많지 않다면 루프를 아예 없애고 함수를 여러번 호출하는 편이 빠릅니다.
속도 개선이 필요한 경우 아래와 같은 테크닉도 가능합니다.
반복문의 실행을 8로 나눠서 8번에 대한 실행 즉 8개의 함수를 호출하는것입니다.
이중 해석을 피하자
이중해석이란 자바스크립트에서 자바스크립트 코드를 해석하는 일입니다.
eval()이나 “alert(‘hello world!’)” 이런식의 스트링을 넘겨서 처리하게 하면 안됩니다.
파서를 중간에 새로 기동해야 되서 네이티브 코드에 비해 느리게 실행됩니다.
기타 성능 고려
- 네이티브 메서드가 더 빠름
- switch 문을 활용
- 비트 연산자 활용
문장을 최소한으로 줄이기
변수선언
var count = 2,
color = "red",
values = [1,2,3];
var를 각각 안하고 한번에 선언해서 문장을 줄여주었습니다.
쉬우면서도 효과가 확실한 최적화 방법입니다.
계수삽입
var name = values[i];
i++;
//위를 아래와 같이 변경
var name = values[i++];
객체와 배열 리터럴 사용
권장하지 않는 방법
//권장하지 않는 방법입니다.
//배열 생성 초기화를 따로합니다.
var values = new Array();
values[0] = 123;
values[1] = 234;
values[2] = 355;
var person = new Object();
person.name = "kendrick";
person.age = 29;
권장하는 방법
//권장하는 방법입니다.
//한번에 해줍시다
var values = [123, 234, 355];
var person = {
name : "kendrick",
age : 29
}
DOM 상호 작용 최적화 하기
자바스크립트에서 제일 느린 부분이 DOM입니다.
페이지를 다시 그리는 작업과 요소가 많은 정보를 가지고 있기 때문에 오래걸립니다.
동적 업데이트 최소화
예를 들어 for문에서 10번 반복하면서 select의 option을 추가 하는 코드가 필요 하다고 합시다.
이때 for문에 innerHtml로 option하나마다 DOM을 추가 해주지 말고
var html = ‘’등의 문자열로 추가할 html을 for문을 돌면서 문자열로 생성 후. 반복이 종료되면 DOM에 추가하는 방법입니다.
이벤트 위임 사용
일반적으로 핸들러를 많이 사용하기 때문에 이벤트 위임을 최대한 많이 사용합니다.
HTMLCollection에 유의
이 객체는 웹 애플리케이션의 성능을 크게 떨어뜨릴 위험이 있습니다.
HTMLCollection은 아래와 같을떄 반환됩니다.
- getElementByTagName() 호출
- childNodes 프로퍼티 호출
- attributes 프로퍼티 호출
- document.forms, document.images같은 컬렉션 접근
마치며
여기까지가 About javascript의 마지막 세션입니다.
하지만 아직 다룰 심도있는 주제가 많기 때문에 (ES6 등) 기존 넘버링이 아닌 포스트들이 추후에도 올라올 수 있습니다 :)
여기까지 봐주시느라 수고하셨습니다.
좋은 하루 되세요!