Weird Advent Calendar 2016 Review

November 13, 2016

이상한 모임 대림절 달력 2016가 11월 11일 공개되었습니다. 이번에 개발을 하면서 생전 처음 보는 기술을 도입해봤는데요, 각각에 대한 감상을 간단하게 남겨볼까 합니다. 사용했던 기술들은 다음과 같습니다.

그럼 하나씩 살펴보죠.

Firebase

Firebase는 나름대로 유명한 BaaS(Backend as a Service)로 NoSQL 형식의 접근을 취하고 있는 서비스입니다. 2014년 10월 구글에 합병된 뒤 웹 뿐만이 아닌 앱의 백엔드 역할도 접수하기 위해서 여러가지로 노력하고 있는 중이죠.

도입

이번에 도입하게 된 이유는

한국 루비 대림절 달력에서도 Firebase를 백엔드로 사용하는 것을 보았기 때문에 결정내리는 것은 그렇게 어렵지 않았습니다.

개발기

쉽고 편하게 구글 인증을 도입한 시점까진 좋았습니다[..]

리소스를 통째로 긁어올 때의 주의사항

예를 들어서 /days/ 라는 키로 해당 키 밑에 있는 모든 버킷을 들고 온다고 합시다. 가져오는 것까지는 아무런 문제가 없습니다. 네. 가져온 결과가 Object라는 점만 제외하면 말이죠. 코드로 보여드리자면,

Object {"1": Object, "2": Object} # => `/days`의 패치 결과

잘 생각해보면, 키로 어떤 값이 들어올지도 모르는 상황이므로 당연한 반환 형식입니다만 날짜를 사용하다보니 당연한 사실을 망각하고 배열처럼 접근하려다 신나게 말아먹는 상황이 발생. 그리고 즐거운 라이브 디버깅의 현장이 벌어졌더랬습니다.

권한 관리의 귀찮음

백엔드를 서비스 형태로 관리하고 있다보니 아무래도 권한이나 검증에 관하여 여러가지로 귀찮음이 발생합니다.

예를 들어, 대림절 달력에서는 다음과 같은 권한 설정이 필요했습니다.

그리고 이걸 보면 보통은 이런 구조를 생각할 겁니다. 저만 그러는게 아닐거라고 굳게 믿고 있습니다.

{
  "rules": {
    ".read": true,
    ".write": "auth.uid != null",
    "days": {
      "$day": {
        ".write": "필요한 더 많은 권한"
      }
    }
  }
}

이처럼 사용할 수 없습니다. 기본적으로 권한은 가장 마지막에 있는 것만 적용되기 때문입니다. 그래서 실제로는,

{
  "rules": {
    ".read": true,
    "days": {
      "$day": {
        ".validate": "newData.hasChildren(['day', 'author', 'title', 'url', 'uid'])",
        ".write": "auth.uid != null && 필요한 더 많은 권한"
      }
    }
  }
}

이런 느낌으로 작성하게 됩니다. 이것만 보면 별 문제가 없어보입니다. 좀 길게 쓸 수도 있지. 그런데 저기에 적어둔 필요한 더 많은 권한을 다 작성한다면?

{
  "rules": {
    ".read": true,
    "days": {
      "$day": {
        ".validate": "newData.hasChildren(['day', 'author', 'title', 'url', 'uid'])",
        ".write": "(auth.uid != null && !data.exists()) || (data.child('uid').val() == auth.uid && (!newData.exists() || newData.child('uid').val() == auth.uid))"
      }
    }
  }
}

이처럼 됩니다. 저 기나긴 내용이 무엇이냐하면, 버킷 변경 요청이 왔을 때 전후 상태를 비교하고, 사용자가 누구인지 확인하여 이 요청을 허가할 것인지 아닌지를 판단합니다. 여기도 잘 생각해보면 당연했던 점이, 요청 받은 시점에 구 객체와 새 객체를 비교하지 않으면 삭제를 할 수 없거든요. 그래서 권한 override 불가능 & 전후 객체 참조값 비교를 하다보면 쓸모없이 길어지고, 읽기 힘들어지는 결과를 가져옵니다.

그래도 쓸만합니다

기능은 심플하고, API도 깔끔하고 무엇보다 작은 규모에서는 비용도 싸니까요. 저는 대림절 달력 정도의 애플리케이션이라면 써도 괜찮겠다는 결론을 내렸습니다.

YARN

한달 전, 10월 12일 페이스북은 YARN이라는 새로운 패키지 매니저를 발표했습니다. 이는 npm의 문제점과 부족한 부분을 커버하기 위한 새 패키지 매니저인데요, YARN은 npm의 슈퍼셋으로 구현되어 있기 때문에 npm으로 의존성을 관리하고 있다면 곧바로 도입할 수 있습니다.

도입기

YARN은 딱히 큰 고민 없이 도입했습니다. npm의 슈퍼셋이고, 이를 도입해서 손해볼 부분은 하나도 없었거든요.

설치하고 yarn 명령을 통해서 의존성을 설치할 수 있으며, npm에서 사용하는 명령을 거의 다 사용할 수 있습니다. 더 궁금하신 점이 있다면 NPM vs YARN Cheat Sheet를 참고해주세요.

좋았던 점

Riot.js

Riot.js는 본인들의 말을 빌리자면 “React-like user interface micro-library”입니다.

커스텀 태그를 제공하며, VDOM을 사용하여 랜더링을 합니다. 그리고 극단적으로 작은 사이즈를 가지고 있죠. 덕분에 API 문서도 하루 카페에 가서 커피 한 잔 마시면서 가볍게 읽을 수 있을 정도로 짧습니다.

도입기

등을 이유로 이번이 딱 좋은 기회라고 생각하고 도입해보았습니다.

개발기

정작 개발에 들어가서 몇가지 지뢰를 밟았습니다. 이건 라이브러리에 대한 충분하지 못한 이해를 가지고 개발을 시작하여 생긴 사태입니다만, 혹시라도 도입을 고려하시는 분들을 위해 간단한 기록을 남깁니다.

named DOM 자동 바인딩

Riot.js는 커스텀 태그 내에서 name 속성을 가지고 있는 DOM을 컨택스트에 자동으로 바인딩해주는 기능을 가지고 있습니다.

<day>
  <input type="text" name="author">

  <script>
    this.author # => DOM("input[name='author']") 객체를 반환
  </script>
</day>

이런식으로 DOM을 컨텍스트에 자동으로 할당해줍니다. 잘 사용하면 편리하지만 만약 내부에서 이걸 잊고 이 이름에 다른 값을 할당한다면 골때리는 상황이 발생합니다. 예를 들자면 이런 느낌이죠.

<day>
  <input type="text" name="author" onchange={this.handleChange}>

  <script>
    this.author # => DOM("input[name='author']" 객체를 반환
    this.handleChange = e => {
      this.author = e.target.value
    }
  </script>
</day>

input의 값을 모델에 반영하기 위해서 React인 것처럼 코드를 작성하다 보면 왜 동작하지 않는지 이해할 수 없는 정체불명의 상황이 됩니다.

data-is

문서는 부실하지만 반드시 알고 있어야 하는 프로퍼티 중 하나입니다.

riot.js는 React와는 달리 커스텀 html 태그가 그대로 문서에 삽입되는 특징이 있습니다. 문제는 최신 브라우저가 html DOM 트리를 검증하고 자동으로 고치게끔 되어 있다는 부분입니다. 테이블을 생성하는 코드 예제를 살펴보죠.

<!-- Code -->
<table>
  <week></week>
</table>

<!-- Template -->
<week>
  <tr>
	<td>TEST</td>
  </tr>
</week>

이와 같이 작성할 텐데 이를 크롬에서 랜더링해보면,

<!-- Code -->
<week>
  <tr>
    <td>TEST</td>
  </tr>
</week>
<table>
</table>

이런 코드를 생성합니다. 크롬은 weektable 안에 들어갈 수 없는 태그라고 판단하고, 자동으로 밖으로 끌어내는 것이죠. 그래서 이런 사태를 회피하기 위해서는

<!-- Code -->
<table>
  <tr data-is="week"></tr>
</table>

<!-- Template -->
<week>
  <td>TEST</td>
</week>

이런 식으로 data-is라는 속성을 사용하여, 커스텀 태그대신 정규 태그를 사용하도록 선언해야 할 필요가 있습니다.

Conclusion

이상으로 세 가지 도구에 대해서 간단한 감상과 주의해야 했던 부분을 정리해봤습니다. 다른 도구들은 취향에 따라서 사용할 수 있겠지만, YARN은 정말로 추천드립니다. 꼭 한번 사용해보세요!