Date 다루기
Google Calendar API를 연동하는 프로젝트에서 브라우저의 Date객체를 좀더 손 쉽게 다루고 날짜 연산을 하기위해 오픈소스 라이브러리를 사용하게 되었다. 그중 Moment와 date-fns 두개를 사용해보고 느낀점과 성능을 비교해보았다.
Moment는 가장 널리 알려져 있는 Date 라이브러리라고 생각한다. 사용하기도 편리하고, 다양한 날짜 연산을 위한 함수들을 제공한다. 객체 형태로 정의되어 new Date() 와 비슷하게 선언하여 사용한다. 또한 지금 버전에서는 deprecated 되었지만, 편의를 위해 함수호출 시 매개변수의 순서를 지키지 않아도 됬었다.
momentjs는 날짜/시간이라는 개념을 핸들링하기위해 만들어진 오브젝트이고 이 개념만을 위해 정의된 기능들의 집합이라는 점에서 OOP개념이 담긴 라이브러리라고 볼 수 있다.
date-fns는 moment와 달리 native Date객체를 함수를 이용해 핸들링 할 수 있도록 ‘함수들’이 정의된 라이브러리이다. 이 라이브러리 또한 많은 수의 함수들이 정의되어 있어 기능적으로 보면 moment 라이브러리 못지 않은 다양한 함수들을 제공한다. momentjs 와 달리 함수 단위로 라이브러리가 구성되어 있기 때문에 필요한 함수만 import하여 사용할 수 있다.
두 라이브러리는 여러 방면에서 차이를 보인다.
momentjs는 OOP개념이 담긴 라이브러리이다. moment객체 하나를 생성하고 그 객체의 멤버함수들을 이용해 날짜 연산 및 관련 기능을 실행 할 수 있다.
date-fns는 이와 달리 매개변수로 Date 객체를 받는 함수들의 집합이다. 내장 Date 객체를 사용하고 이 객체를 대상으로 연산을 수행하는 함수들의 집합이다.
또 다른 가장 큰 차이는 date-fns는 immutable 이고 moment는 mutable이다. date-fns의 경우 매개변수로 넘긴 Date객체를 함수에서 연산후 새로운 Date객체를 반환한다. 반면에 moment는 멤버함수 호출시 자기 자신의 상태를 변화시킨다. immutable과 mutable의 차이와 컨셉에 대해 논의하면 그 내용이 매우 방대하고 다양한 의견들이 있기에 여기서 언급하지는 않겠다.
momentjs는 moment객체 내에 모든 함수들이 멤버함수 형태로 들어가 있다. 때문에 내가 date 덧셈 연산만을 필요로 한다 하더라도 momentjs를 import하고 moment객체 하나를 생성하면 필요하지 않는 모든 함수와 기능들이 생성되게 된다.
date-fns는 모든 기능들이 함수 단위로 나눠져 있어 필요한 함수만 import하여 사용할 수 있다.
때문에 최종적으로 웹어플리케이션의 빌드 결과물을 본다면 momentjs보다 date-fns가 일반적으로 결과물의 크기가 작다.(tree shaking 적용하지 않음)
결론부터 말하면 성능을 위해서라면 date-fns를 사용하는 것을 추천한다. 일단 moment객체를 하나 생성하면 내부에서 사용하기 위한 멤버 변수들의 초기화 작업이 시작된다. 이 단계에서는 생각 보다 많은 변수 유효성 체크 코드가 수행된다. 그리고나서 네이티브 Date객체를 하나 생성하여 내부 갖고 있는다. 다시말해 객체 생성에 소요되는 시간은 네이티브 Date객체보다 더 많이 소요된다.
time of 'new Moment()' = time of 'new Date()' + α
일례로 add연산을 보면, moment의 add함수는 덧셈 작업을 하는데 소요되는 선행 작업들이 많다. 우선, deprecated되었지만, 아직까지 동작하고 있는 매개변수의 순서를 지키지 않아도 되는 옵션 때문에 매개변수의 유효성 검사가 선행된다. 또 day, month, year 등의 연산도 모두 add함수로 처리하기 때문에 어느 단위만큼 연산을 할지 결정해야하는 코드 또한 수행된다. 그렇다보니 date-fns와 비교할 때 add연산만으로도 많은 작업이 수행 되는 것을 확인 할 수 있다.
https://github.com/date-fns/date-fns/blob/master/src/addDays/index.js
실제로 date-fns는 add함수들은 day, month, year 등으로 구분되어 있어 매우 간단 명료하다. date-fns의 addDays 함수를 보면 몇줄 되지 않는다.
이런 작은 차이들이 쌓여 어플리케이션 개발에서 성능 차이를 보면 그 차이가 더 확연하다. 구글 캘린더 API 를 이용해 일별 일정과 월별 일정 파싱을 date-fns와 moment를 사용했을 경우의 차이가 8~10배 정도 차이난다.
OOP 컨셉의 라이브러리인 momentjs와 함수 단위의 라이브러리인 date-fns는 동일한 목적의 라이브러리이지만, 많은 면에서 차이가 있다. immutable과 mutable, OOP와 함수 등 본인의 컨셉에 맞게 사용하면 되겠지만, 성능은 date-fns가 우세인듯 하다. 최종 번들에서 두 라이브러리의 용량 비교를 할 경우, tree shaking만 잘한다면 momentjs와 date-fns는 큰 차이가 없지 않나 생각한다. 그리고 momentjs에서 locale 모듈도 사용하지 않는다면 제거하여 용량을 줄일 수 있지만, 그렇다 하여도 date-fns만큼 줄어들지는 않는다. 속도 또한 전체적으로 date-fns가 우세했다. (몇몇 기능에서는 차이가 있지만 전체적으로 date-fns가 우세) web에서는 전송되는 파일 사이즈 또한 속도면에서 성능으로 평가 될수 있으니 전체적으로 성능을 고려한 선택이라면 date-fns이다.