'그 외'에 해당하는 글 32건

제목: Product Design Exercises We Use At WeWork Interviews
저자인 Artiom Dashinsky@hvost와 dashinsky.com에서 만날 수 있습니다.

제품을 생각하는 스킬을 연습하고기위해 이 예제들을 사용해보고, 디자인 지원자들을 어떻게 시험하는지 배우자.

디자인 커뮤니티는 운좋게도 DribbbleBehanceDaily UI등과같은 많은 훌륭한 리소스들이 있다. 이 리소스들은 다른 비주얼 작업을 볼 수 있게 해주고, 여러분의 것들을 보여주고 피드백을 받을 수 있다. 이에반해 체계적인 비주얼-중심의 디자인 커뮤니티 시장은 디자인의 Dribbble화(어떻게 생겼고 어떻게 동작할지에 사로잡힌)를 만들어낸다. 이 프로세스 입문의 디자이너들의 생각에 잘못된 이해를 만들어줬다. 바로 "제품 디자인 = Dribbble" 이다.

입문 디자이너들은 제품을 생각하는 스킬로 작업해야한다.

Julie Zhuo가 이야기하는 커리어 단계와 그녀의 놀라운 The Beginning of your Design Career글Julie Zhuo가 이야기하는 커리어 단계와 그녀의 놀라운 The Beginning of your Design Career글


오늘날 최고의 비지니스는 디자이너들이 미학보다는 회사가 옳은 사람들을 위한 옳은 기능을 만드는 것을 보장하는 역할을 해야한다고 이해하고있다. 불행히도 이런 비지니스들은 주니어 디자이너들을 고용해서 어떤 과제를 해결할지 적절하게 소통하고 있지 않았다.

제품 생각을 연습할 수 있는 리소스가 부족하기도하고, 이것은 개선하기위해 작업하는 디자이너 스킬과 최고 회사들이 그들에게 기대하는 스킬 사이에서 갭을 만들었다.

만화 저작권: Andrew Hwang만화 저작권: Andrew Hwang



디자인 커뮤니티가 어떻게 도와줄 수 있을까
디자인 커뮤니티가 이 갭을 최소화시키는데 좋은 일을 할 수 있으므로, 그 결과 우리는 시장에서 디자이너를 더 잘 준비할 수 있고 산업 앞으로 갈 수 있다. 여기에 우리가 도울 수 있는 몇가지가 있다.

디자이너:
  • 제품 생각을 연습하기위한 리소스를 만들기
  • 인터뷰에서 해볼 수 있는 디자인 테스크 숙제를 공유하기. 그러나 여러분이 공유하는 것이 회사 작업과 관련된 민감한 정보를 드러내지 않도록 조심해라.

회사:
  • 도전과제 종류의 명확성을 높히기위해 케이스 연구 만들기
  • 당신의 고용 프로세스에 더 투명성을 넣어, 신입 디자이너들이 고용되고서 어떤 종류의 문제를 제품 디자이너들이 풀것을 기대하는지 배울 수 있게 할 수 있다.

첫걸음 떼기


WeWork Digital 디자인 팀의 창의적인 리드: Stephanie Wu and Andrew Couldwell. 사진: Nina Robinson for Inside Design: WeWorkWeWork Digital 디자인 팀의 창의적인 리드: Stephanie Wu and Andrew Couldwell. 사진: Nina Robinson for Inside Design: WeWork


기술 회사들은 제품 디자이너 직군에서 조금 다른 접근법의 인터뷰를 가진다. 그러나 이들 모두 지원지의 제품 생각을 확인하는 목적이다. 페이스북은 제품에대해 디자인 논평을 물어보고, 구글은 제품 생각과 관련된 화이트보드 과제를 한다 인터렉션 디자인에 아주 초점을 두면서 말이다.

WeWork에서는 제품 디자이너 인터뷰 프로세스 중 일부분은 화이트보드 과제도 포함된다. 우리는 커뮤니티에 그 몇가지를 공유하기로 결정했다.

이 과제를 어떻게 사용할까

우리는 왜 화이트보드 과제를 하는가?



제품 생각을 테스트하면서, 화이트보드 과제는 지원자를 아래와같은 능력에대해 테스트하기 좋은 도구이다.
  • 팀과 효율적으로 의사소통하기
  • 비판적으로 생각하고 좋은 질문 하기
  • 피드백/건설적 비판 다루기
  • 데드라인이 다가올때 새로운 문제에대해 높은 압박의 환경에서의 능력
  • 팀이 매일매일 이 사람과 협력하고 싶은 종류의 사람인지

결과물에는 이것을 포함할 수 있다



모든 과제들은 우리 사무실 현장에서 시행되는 것이다. 지원자들은 60분이 주어지며, 곧 15-20분 발표와 토론을 한다.


과제 목록

아래에는 당신이 해볼 수 있는 17가지 과제가 있다.

1. 룸메이트
: 전세계 인구의 54%는 도시에 살며, 남자의 평균 결혼 나이는 29살이고(20년전 26세 이상) 여자는 27살이다(같은 기간의 23세 이상). 이런 트렌드에서, 도시 거주자들은 20대의 대부분을 룸메이트와함께 사는 경향이 있다. 그러나 더 많은 사람들이 도시로 들어오기 때문에 좋은 룸메이트를 찾고 유지하는 것은 더 힘들다.

모바일 제품 경험을 디자인하는데, 서울에서 이상적인 룸메이트를 안전하게 찾을 수 있게 해주어 밀레니얼 세대를 찾을 수 있어야한다. 룸메이트를 찾고 있을 뿐만 아니라 아파트도 찾고 있는 사람의 관점에서 경험을 디자인하라. 이상적인 룸메이트가 발견되고나면 이 제품이 더 나은 룸메이트 경험을 만들기위해 어떤 다른것을 할 수 있을까?

"좋은 룸메이트를 찾기/유지하기"같은 행로에서 고통스러운 지점을 확인해보고 이 고통스런 점을 해결하는 방법을 찾는 당신을 지켜보고있다.

제약사항: iOS와 안드로이드의 현재 모바일 기능을 붙여야한다.

2. GoPro는 새로운 앱이 필요하다
GoPro의 미칠듯한 성곡적 액션카메라는 세계적인 발자취를 가졌다. 아제 카메라의 비용은 5만원 이하고 수많은 사람들은 그들의 삶에 모험을 기록하는데 사용하고 있다.

그러나 GoPro는 문제를 가지고 있는데, 현재 모바일 앱이 3가지에만 좋다는 것이다. 그들의 카메라로 찍은 사진을 보는데, 이 사진을 편집하는데, 세계의 다른 사람들이 찍은 사진을 보는데. 세계를 바꾸고있는 카메라를위해, 이 앱은 인정하는바와같이 무디며 표면을 밀어내지 못한다.

GoPro 회사는 당신에게 새롱누 모바일 앱을 만들 임무를 주었고, 하나는 사진 환경에서 뛰어나고(인스타그램, Vsco cam, snapchat), 하나는 밀레니얼 세대를 어필할 것이다. 이렇게 새롭고 개척적인 것에서 완벽한 GoPro 앱은 어떤 일을 해야할까?

제약사항: 이것은 iOS 앱이며, 제안된 모든 기술은 오늘이나 12달안에 시장에서 사용할 수 있어야한다.

3. 구글 엔터프라이즈 판매 깔때기(Google Enterprise Sales Funnel)
(역자: 번역하다가.. 힘들어서 원문 넣었어요.)
You are consulting Google on an important strategic decision for their enterprise offerings; they want to know whether it’s worth introducing a sales funnel management tool onto their Enterprise Gmail interface. Google believes that because a majority of their enterprise users discuss business on their email platform and because they are the lexicon of most people’s business contacts, that they are in a position to both make the sales process more efficient and make the likelihood of closing business higher.

26% of Google’s Enterprise users engage in sales weekly, 40% engage in some sort of funnel management (whether sales, hiring, or some other decision funnel).

A typical sales funnel includes Leads, Inquiries, Prospects, Quotes and finally a new customer.

Recommend a funnel management flow to Google. Make sure the flow accounts for a user making initial contact with a lead from within gmail and then managing that lead through the entire funnel. What else can gmail do to put the odds of closing business in favor of their user?

제약사항: 없음

4. 비지니스 승객
자동차가 스스로 운전하는 세상에서 살고있다고 가정하자. 집집마다의 경험을 디자인하자. 이것은 4명의 비지니스 직원이 주일에 뉴욕에서 볼티모어까지 최대 4시간 여행할 수 있게 만들 수 있다.

제약사항: 우리가 허용하는 기술 도약은 모든 자동차자 스스로 운전할 수 있는것 뿐이다. 제안된 다른 기술들은 반드시 오늘날 존재하거나 6-12개월엔에 현실적으로 존재해야한다.

가정: 비지니스 직원과 "새로운 클라이언트"의 어떤 종류도 고를 수 있다. 비지니스 직원의 나이는 28살부터 45살이다.

5. Spotify Artist Actalogue Manager
스포티파이(Spotify)는 아티스트에게 그들의 플렛폼에서 그들의 카탈로그 컨트롤을 제공하도록 결정해왔다. 제일 처음 아티스트들은 자신의 엘범을 관리하고, 자신의 아트워크를 올리고, 특정 제품을 판매하며, 그들의 음악에 가사를 넣는등, 그들이 필요한 조건에 달렸다.

맥-기반 에디터와 아티스트 관리 시스템을 만들어서 아티스트들이 Spoty에서 그들의 presence를 관리할 수 있도록 한다. 솔루션은 Spoty에 현존하는 모든 아티스트 컨텐트를 대상으로 하지만, 자유롭게 창의적으로 넣고 아티스트가 유용해할 수 있는 추가 기능을 넣을 수 있다.

제약사항: 당신은 맥 데스크톱 앱을 디자인하고있다. OS의 기능에 들어가있어야 할 것이지만, 그들이 여기에 적용하지 않으므로 어떤 웹과 관련된 기술 제약은 무시해도된다.

6. E-ink
지금 e-ink의 가격은 0원이다. 어떤 인터페이스가 집에서 매일매일 삶을 더 흥미롭게 만드는데 혁신적일 수 있을까? 포괄적으로 그리고 잘 생각해낸 리스트를 찾아보자. 비주얼없이 설명하기 힘든 몇가지 인터페이스 예시를 만들어야한다고 생각되면 먼저 리스트를 만들어라.

제약사항: 없음

7. Crisis News Network
"Crisis News Network" 혹은 CNN은 속보와 세계적인 다른 뉴스들의 가장 큰 기업합동(syndicate)이다. 그들은 millennial 청중에 포커스를 맞추고있다. 그들은 자신의 사이트(데스크톱)에서 뉴스 경험을 다시 생각하기위해 당신을 고용하였다.

오늘 세대의 뉴스 소비자를 위해 주목할만한 뉴스 사이트를 디자인하라. millennial들이 컨텐트를 소비하고 공유하는 방법을 직접 찾아보자. CNN은 "그들이 어떤것을 항상 해내는 것"에대해 독단적이고 싶어하지 않는다. 그들은 장벽을 깨고싶고, 그들은 몇가지 위험을 안고서도 새로운 곳으로 가고싶어하고, 당신이 업계에 변화를 만들기를 기대하고 있다.

홈페이지와 스토리페이지를 디자인하라.

제약사항: 현존하는 웹 기능을 사용하라.

8. 오디오북을 개인화하기
오디오북과 팟케스팅은 모바일에서 오디오 부분을 가장 빠르게 성장했다. 오디오북을 듣는 사용자들은 페이지 한쪽 모서리를 접거나, 원하는 곳에 밑줄 긋거나, 좋아하는 페이지를 메모하는 일을 즐기지 않는다... 그들은 책을 소유하고 오랫동안 보아서 향수를 불러 일으키는 면을 잃는다. 오디오 경험으로 모바일에서 너무 많이 있게된다.

매우 개인적이고, 인터렉티브한 오디오북 혹은 팟케스트 모바일 앱을 디자인하라. 그리고 책이 할 수 있는 것보다 더 유용한 기능을 가져다 주어야한다.

제약사항: 제안된 모든 기능은 현존해야하거나, 다음 6개월안에 실현가능해야 한다.

9. 오디오북에서 특정 오디오 섹션과 인터렉트하기
주머니에는 iPhone을 가지고있고, 손목에는 Apple Watch, 헤드폰을 끼고있으며, 삶을 바꾸는 오디오북이 그 안에서 실행하고있다. 사용자가 아래중 하나 혹은 그 이상이 되는 인터렉션 플로우를 디자인하라.
- "하이라이트" 오디오, 책에서 텍스트에 하이라이트하는 것과 비슷하다. 사용자가 컨텐트에 하이라이트하면 이제 어떤 일을 할 수 있을까?
- 세계에있는 다른 청취자의 book을 듣기. 다른 청취자의 컨텐트에 당신의 이모션을 공유하자.
- 당신이 찾은 흥미로운 오디오북 일부분에 메모를 하기.

제약사항: 당신이 가진 기기의 기술적 한계내에서 작업하라.

10. 여행하는 영업사원을 위한 캘린더
발렌티나(사람이름)는 행운의 500개 회사를위해 영업과 비지니스 개발을 선도한다. 그녀는 한달 4주중에 3주를 여행하며, 여행은 거의 대부분 국외로간다. 다른 타임존 여행과 다른 도시에서 바쁜 회의 스케줄 사이에서, 그녀는 올바른 시간에 올바른 장소를 보여주는 과제를 찾아냈다. 회의시간을 제안하고, 타임존 변경을 책임지고, 그녀가 항상 회의에 제시간에 가도록 선처할만큼 스마트한 캘린더 플로우와 인터페이스를 디자인하라.

제약사항: 솔루션은 모바일친화적으로 만들고 오늘날의 실용적인 기술을 사용해야한다.

11. 매일 음식 섭취
게리(사람이름)는 Gen-Xer이다. 그는 아직 30대 초반의 독신자이다. 전문대 교육을 받고 기술 분야에서 뛰어나다. 최근 그는 의사에게서 비만 초기 증상을 진단받았다. 게리는 어떤 기기를 이용하여 그의 일일 음식 섭취량을 추적하고 과식하는 신호를 그에게 보여줄때 중재하도록 만들어 유입 흐름에 가장 낮은 장벽을 디자인하라. 그의 삶은 이것에 달렸다.

제약사항: 모든 기술과 제안들은 반드시 오늘날 사용할 수 있는 것이여야한다.

12. Garbage
평균 중산층의 미국인 가족은 그들의 라이브스타일을 유지하기위해 4천파운드 이상 버린다. 하루기준 대부분은 버려지거나 재활용된다. 미국인들이 버리는 것을 어떻게 스스로 더 인지하게 만들 수 있을까?

기술은 여게서 돕는 역할을 맡았다고 가정하자. 사용자 인터페이스가 쓰레기 처분을 관리하는데 도움을 주게 만들자. 하드웨어와 소프트웨어가 함께 이 문제를 해결하는 가능성으로 자유롭게 재치있게 해보자.

제약사항: 제안된 기술은 오늘날 존재하거나 6개월내에 시장에서 사용할 수 있어야한다.

13. NYC 메트로카드
NYC 메트로카드 시스템은 몇년동안 바뀌지않고 남아있다. 메트로카드 기계의 인프라 비용, 메트로카드를 사기위해 오랫동안 줄을 서서 기다리고, 더러운 기계를 만져야하고, 메트로카드를 잃어버릴 수 있는 잠재성과, 당신 카드를 넣어 쉽게 게임할 수 있는 체제로 도시에 100만달러의 비용이 나가고 사용자 경험에서 필요한 것이 많이 남아있다.

메트로를 매일 사용하는 사용자와 한번만 메트로를 이용하는 멀리서온 방문자에게 물리적인 NYC 메트로카드 없이 이용할 수 있는 새로운 시스템을 디자인하라.

제약사항: 제안된 모든 기술은 오늘날 시장에서 사용할 수 있는 기술이야한다.

다른 과제들
14. 당신이 많이 좋아하고 많이 사용하는 앱을 골라서, 어떻게 디자인할지 설명하고 왜 했는지 설명하라.

15. 오늘날 전세계 인구의 54%는 도시에 살며, 2050년에는 66%까지 증가할것으로 전망하고있다. 전반적인 세계인구 증가와 결합된 도시화는 2050년까지 도시 인구에 또다른 25억명이 증가할 수 있는 전방이다. 정부를 도울 수 있고 이 과제를 다룰 수 있는 디지털 제품을 생각해보라.

16. 애완동물 관리는 600억달러 규모의 시장이다. 이런 종류의 서비스 수요를 활용할 수 있는 제품을 생각해보라.

17. 당신이 잘 몰랐지만 Amazon.com이 서비스 하고 있는 타겟 유저를 하나 골라라. 이 유저 타입을 끌기위해 Amazon.com을 어떻게 리디자인할 수 있을까?


우리는 구인중이다
WeWork는 뉴욕에있는 디지털 팀에 조인하기위해 재능있는 제품 디자이너항상 찾아보고 있다. 사람들이 일하는 것과 삶을 어떻게 바꿀지에대해 이야기를 더 들어보고 싶거나, 이 일에 동참하고 싶으면 나에게 한줄 남겨달라.

Ariel Verber, Shem Magnezi, Andrew Couldwell에게 감사하다.


이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: Red, White, and Blue

모두가 알아야하는 칼라 팔렛트의 8가지 규칙

사람과 컴퓨터간의 인터렉션은 그래픽적인 UI 요소를 기반으로하며, 여기서 칼라는 중요한 역할을 한다. Pierre Bonnard가 이렇게 말했다.
칼라는 디자인에 기쁨의 퀄리티를 더해주는게 아니라 그것을 강조하는 것이다.
새로운 제품을 디자인할때 무한개 종류의 칼라 조합이 나올 수 있으므로,  칼라 스킴의 칼라를 정하는 일은 보통 어렵다. 이 글에선 올바른 칼라 팔렛트를 선택할 수 있도록 8가지 기본 규칙을 다룰 것이다.

1. 칼라의 수를 제한하기
디자인 제품에 칼라를 적용하는 것은 균형과함께 많이 해보아야한다. 많은 칼라를 사용할수록 균형을 맞추기 힘들어진다. 여러분의 칼라 스킴에 최대 3개의 주요 칼라를 담아둔다면, 더 나은 결과물이 나올 것이다. 사람들이 어떻게 Adobe Color CC를 사용하는지 연구한 Toronto대학의 연구에 따르면, 많은 사람들이 두세개의 칼라로 조합한 간단한 칼라 조합을 선호한다고 말했다.

여러분의 팔렛트에 정해놓은 것들을 너머 추가적인 칼라가 필요하게되면, 셰이드(shade)와 틴트(tint)를 이용할 수 있다.

스킴은 어떻게 만들까
그래서 이 두세가지의 칼라는 어떻게 정할까? 칼라 휠(color wheel)이 도와줄 것이다.

이 12가지 칼라 휠은 칼라 스킴을 만드는데 중요한 도구이다이 12가지 칼라 휠은 칼라 스킴을 만드는데 중요한 도구이다


새로운 칼라 스킴을 만들기 쉽게, 미리 정의해둔 칼라 스킴 기준들이 있다(특히 초보자를 위한).
  • Monochromatic: Monochromatic 스킴은 같은 칼라에서 나오지만, 틴트, 셰이드, 톤으로 조정하기 때문에 스킴을 만들기 가장 쉬운 기준이다. Monochromatic 칼라들은 함께 잘 어울려 부드러운 효과를 만든다.

Monochromatic 스킴은 눈에 굉장히 들어오기 쉽다(특히 blue나 green hues). 페이스북 예시에서도 볼 수 있듯, 이 스킴은 깔끔하고 우아해 보인다Monochromatic 스킴은 눈에 굉장히 들어오기 쉽다(특히 blue나 green hues). 페이스북 예시에서도 볼 수 있듯, 이 스킴은 깔끔하고 우아해 보인다

  • Analogous: Analogous 칼라 스킴은 연관된 칼라들로부터 만들어진다. 한 칼라는 주요 칼라로 사용되고, 다른 칼라들은 스킴을 풍성하게 하는데 사용된다. 이것은 상대적으로 뽑아내기 쉽지만, 전체적인 스킴이 이것에의해 과장될 수 있으므로, 여러분이 사용하는 칼라의 vibrancy를 잘 정하는것이 요령이다. 예를들어 제스처-주도 Todo앱인 Clear는 현재 작업들의 우선순위를 시각화하기위해 강한 인상(striking)의 analogous 칼라를 사용한다. 반면 명상 앱인 Calm는 사용자에게 편안함과 평화로움을 느끼게 하기위해 blue와 green의 analogous 칼라를 사용한다.

    12색 칼라 휠에 서로 인접한 세가지 칼라를 사용하여 analogous 스킴을 만들었다. 제스처기반 to-do 앱인 Clear는 현재 테스크들의 우선순위를 표현하기위해 강렬하고 눈에띄는 analogous 칼라를 사용한다12색 칼라 휠에 서로 인접한 세가지 칼라를 사용하여 analogous 스킴을 만들었다. 제스처기반 to-do 앱인 Clear는 현재 테스크들의 우선순위를 표현하기위해 강렬하고 눈에띄는 analogous 칼라를 사용한다


    Calm은 전반적인 분위기를 만들기위해 analogous 칼라들을 사용한다Calm은 전반적인 분위기를 만들기위해 analogous 칼라들을 사용한다

  • Complementary: 그것들의 기본 양식에서 이 스킴들은 두가지 강하게 반대되는 칼라로만 이루어진다. 이 스킴은 보는이의 시선을 끄는데 사용된다. complementary 스킴을 사용할때는, 주 칼라를 정하는 것이 중요하고, 강조를 위한 보색을 사용한다. 예를들어, 인간의 눈이 다른 종류의 green으로 가득찬 물체를 보고 있을때, 약간의 red는 굉장히 눈에 띌 것이다.

보색은 어떤것을 눈에 띄게 하기 가장 쉬운 방법이다보색은 어떤것을 눈에 띄게 하기 가장 쉬운 방법이다

  • Custom: 커스텀 칼라 스킴을 만드는 것은 많이들 생각하는것 만큼 복잡하지 않다. 훌륭한 칼라 팔렛트를 만들기위해 적용시킬 수 있는 간단한 요령이 있다. 중립적인 팔렛트(전통적인 monochromatic 스킴)에 밝은 강조의 칼라를 넣으면 된다. 새로 만들어진 스킴은 시각적으로 굉장히 강한 인상이 있을 것이다.

회색톤의 디자인에 한 칼라를 넣으면 간단하고 효과적으로 눈을 끈다. 드롭박스의 칼라 스킴에서, white와 grey의 조합으로 만든 레이아웃은 blue로 강조되어 튀어보인다회색톤의 디자인에 한 칼라를 넣으면 간단하고 효과적으로 눈을 끈다. 드롭박스의 칼라 스킴에서, white와 grey의 조합으로 만든 레이아웃은 blue로 강조되어 튀어보인다


2. 자연에서 영감을 받기
최고의 색 조합은 자연에서 온다. 왜냐? 이 스킴들이 눈에 자연스럽게 보이기 때문이다. 영감을 받기 위해, 우리는 주변만 둘러보면 된다. 여러분의 하루 삶에서 특히 아름답거나 강한 인상의 칼라를 본다면 그것으로 스킴을 만들려고 해보아라. 간단하게 아름다운 순간을 사진으로 찍고 이것으로 칼라 스킴을 만들어보자.

최고의 칼라 조합은 자연에서 온다. 사진 한장에서 칼라 스킴을 만들 수 있다최고의 칼라 조합은 자연에서 온다. 사진 한장에서 칼라 스킴을 만들 수 있다


3. 603010 규칙을 따르려 하자
이 규칙은 오랫동안 사용해온 데코레이팅 규칙이다. 이것은 칼라스킴을 함께하기 쉽게 도와준다. 60% + 30% + 10% 비율은 어떤 공간에서 사용되는 칼라의 벨런스를 말한다.

이 개념은 사용하기 아주 쉽다. 60%는 주 색조, 30%는 두번째 칼라, 10%는 강조하는 칼라로 이루어진다. 이 생각은 두번째 칼라가 메인 칼라를 지지하지만, 서로 충분히 다른 부분에 놓는다. 10%는 여러분의 강조하고자하는 칼라이다. CTA나 다른 주목하고 싶은 요소에 이 칼라를 놓을 수 있다.

60%는 주 색조, 30%는 두번째 칼라, 10%는 강조하는 칼라로 이루어진다. 이 기술은 눈을 하나의 초점에서 다른 곳으로 편안하게 이동시킬 수 있게 한다60%는 주 색조, 30%는 두번째 칼라, 10%는 강조하는 칼라로 이루어진다. 이 기술은 눈을 하나의 초점에서 다른 곳으로 편안하게 이동시킬 수 있게 한다


4. 그레이스케일 먼저 디자인하기
칼라를 가지고 노는것은 즐겁다. 이것이 왜 새로운 제품의 작업을 할 때 칼라 스킴 고르기를 가장 먼저 하는 이유이기도 하다. 이것은 매우 칼라 스킴으로 유혹되는데, 나는 여러분이 그레이스케일 디자인을 먼저 해보도록 하기를 추천한다. 그레이스케일 그라디언트로 여러분의 앱 프로토타입을 먼저 만들고 이것을 기본선으로 사용하자. 칼라를 넣기 전에 그레이스케일로 디자인 하면 여러분을 요소들의 공간과 레이아웃에 집중시킬 수 있다.

칼라를 나중에 넣고, 그 목적으로만 작업하자.

그레이스케일 레이아웃에 한 칼라를 넣으면 간단하고 효과적으로 이목을 끈다그레이스케일 레이아웃에 한 칼라를 넣으면 간단하고 효과적으로 이목을 끈다


5. 칼라 Black 사용을 피하기
현실 세계에선, 순수한 black은 거의 존재하지 않는다. 우리 주변에 있는 모든 "black" 물체는 대부분 불을 껐을때 그 색이 된다. 이 말은, 그들은 실제 black이 아니고, dark grey이다. 길은 black이 아니다. 그림자도 black이 아니다.

이 개의 칼라는 dark grey이지 black이 아니다이 개의 칼라는 dark grey이지 black이 아니다


조심스럽게 골랐던 칼라들 옆에 순소한 black을 놓으면, black은 다른 모든것들을 압도해버린다. 이것은 자연스럽지 않기때문에, 눈에 띄게 된다. 우리가 매일 사용하는 많은 앱들은 기본으로 black을 가지지만, 이 black은 실제 black이 아니라 dark grey들이다. 예를들어 Asos 상단 바의 가장 어두운 색은 #000000가 아니라 #242424이다. 그러니 여러분의 칼라에 항상 채도를 조금 넣자.

ASOS에서 가장 어두운 칼라는 black이 아니다ASOS에서 가장 어두운 칼라는 black이 아니다


6. 칼라 대비를 이용하여 중요성 만들기
칼라는 눈을 가이드해주는데 도움을 주는 도구이다. 어떤것을 더 두드러지게 만들고 싶으면, 칼라를 더 대비되게 할 수 있다. 일반적으로 높은 대비는 중요한 내용이나 핵심 요소에대한 좋은 선택이다. 사용자가 어떤것을 보거나 클릭하게 하고 싶으면, 눈에띄게 만들어라!

대비는 화면의 남은 부분에비해 다른 영역으로 보이게 만든다. 어떤것을 더 두드러지게 만들고 싶으면, 칼라를 더 대비되게 할 수 있다대비는 화면의 남은 부분에비해 다른 영역으로 보이게 만든다. 어떤것을 더 두드러지게 만들고 싶으면, 칼라를 더 대비되게 할 수 있다


7. 사용자의 감정에 영향을주는 칼라를 사용하기
칼라가 고유의 의미를 가지고 감정을 자극할 수 있다는 사실은 이미 잘 알려진 사실이다. 이 의미는 사용자가 여러분의 제품을 지각하는데 직접적인 방법으로 영향을 줄 것이라는 의미이다.

당신이 앱/사이트를 위해 칼라 팔렛트를 선택할때는, 이것들이 어떻게 생겼는지 그냥 생각하지 말고, 이것들이 어떤식으로 느껴지는지도 생각해야한다. 당신이 고른 칼라는 여러분이 만들고자 했던 브렌드 아이덴티티와 잘 맞을수도있고 맞지 않을 수도 있다. 시작해보기위해, (서양의) 각 칼라와 기본적인 연관에대해 빠른 참조 가이드를 모아놓았다.

Red, Orange, Yellow
  • Red (정렬적인, 강력한, 위험한, 중요한): Red는 극도로 자극적인 칼라이다. 속도나 힘에대한 인상을 남긴다. 에너지의 칼라로 알려져있다. 이것은 혈액순환을 증가시키고 신진대사를 촉진하는 심리적 효과가 증명되어있다. 사람들이 왜 red를 볼 때 강하고 빠른게 읽는지에대한 이유이다. red를 사용하면, 사용자의 주의를 잡거나 주의가 필요한 개별 요소에 강조할 수 있다.
  • Orange (명량한, 에너지있는, 매력적인, 싼): Orange는 따뜻하고 활기찬 칼라이다. 에너지있는 아우라를 가지며, 사용자에게 따듯하고 환영하는 느낌을 만들어 줄 수 있다. 몇 연구자들은 Orange가 싸다는 느낌을 만드 것을 발견했다.
  • Yellow (쾌활한, 친근한, 자극하는, 시선을 끌고 싶어하는): Yellow는 당신이 정한 셰이드에따라 극도로 다재다능해지는 칼라이다. Light Yellow는 해와 관련 있어서 적극성이나 따뜻함과 소통한다. (gold와 같은) Dark Yellow는 고대나 시대의 인상을 준다. 이 darker 셰이드는 종종 영원이나 현명함에 관련되있다.


Green, Blue, Purple
  • Green (자연의, 안전의, 신선한): Green은 환경의 의미를 반경하고 자연과 가까운 의미를 가진다. 또한 성장을 나타내고, 이것이 왜 비지니스와 연관되는지의 이유이다. Green은 옳고 그름의 의미도 나타낸다.
  • Blue (고요한, 책임의, 신뢰할 수 있는, 의존하는): blue 칼라는 고요함과 편안한 감정과 관련되있다. 설득력과 신뢰도에도 관련이 되있고, 믿음과 전문가적인 이해를 준다. Blue는 내부적인 보안의 느낌을 발산한다. 이것이 은행이나 기술 회사가 blue를 사용하는 이유이다. 페이스북, 트위터, 링크드인같은 커다란 소셜 미디어는 모두 그들의 네트워크에 이 칼라를 사용한다.
  • Purple (럭셔리한, 미스테리한, 로멘틱한, 숭고한): 역사적으로 왕족과 연결되있는 purple는 그 제품이 최고급이라는 느낌을 넌시시 비친다.


Pink, Black, White, Gray
  • Pink (여성의, 순결의, 어린): Pink는 여성스러움과 관련되있는 것으로 알고있다.
  • Black (강력한, 세련된, 미스테리의, 뚜렷한): Black은 red를 포함한 다른 칼라들보다 빨리 주의를 끈다. 텍스트나 강조에만 일반적으로 사용되는 이유이다.
  • White (순수한, 건강한, 깨끗한, 순진한): White는 주변에 있는 다른 칼라들을 강조하고, 두번째 칼라로 인기있다.
  • Gray (자연적인, 형식적인, 세련된, 무미건조한): Gray는 중립을 나타내고, black이나 white의 성격을 가져갈 수 있다. 주 칼라로 사용될때, 형식적인 인상을 준다.



문화나 환경에따라 칼라의 의미가 다양해질 수 있다는 것이 중요하다. 이 부분에대해 더 많이 알고 싶다면, Symbolism Of Colors And Color Meanings Around The World 글을 확인해보자.

8. 디자인 접근성을 만들기
접근성(Accessibility)는 칼라로 디자인할때 핵심 고려사항이다. 오늘날의 제품들은 (사람의 능력에 상관없이) 모두를위한 접근성이 필요하다.

지시자로 칼라 혼자 사용되는 것을 피하기
약 8%의 남자들과 0.5%의 여자들은 색맥의 어떤 형태의 영향을 받는다. 12명의 남자들중 1명, 200의 여자들중 1명이다. 여러 형태의 조건이 있지만, red와 green 색맹이 가장 일반적이다. 색맹의 형태로 겪고있는 사람은 일반적으로 red와 green의 변색들을 보기 힘들 것이다.

정산적인 시각으로 보이는 칼라와 red-green 칼라 결핍으로 보이는 동일한 칼라(제2색맹과 적녹색맹)정산적인 시각으로 보이는 칼라와 red-green 칼라 결핍으로 보이는 동일한 칼라(제2색맹과 적녹색맹)



색맹은 (red-green, blue-yellow, moochromatic을 포함하여) 다른 형태를 받아드리므로 여러분의 제품에서 중요한 상태를 소통하기위해 여러 시각적 힌트를 사용하는 것이 중요하다. 칼라를 추가하고, 선, 지시자, 패턴, 텍스쳐, 엑션과 내용을 설명하는 틱스트등을 사용하자.

red 문자를 보지 못하는 사람들에게 극도로 답답한 경험을 줄 수 있으므로, red나 green 칼라만 사용한 정보전달은 피하라red 문자를 보지 못하는 사람들에게 극도로 답답한 경험을 줄 수 있으므로, red나 green 칼라만 사용한 정보전달은 피하라


텍스트에 낮은 대조는 피하라
칼라 대조는 디자인의 사용성에대해 칼라 이론이 중요하게 생각하는 한 분야이다. 텍스트에 칼라를 사용하고 있으면, 두 칼라가 서로 낮은 값 대비(low value contrast)로 옆에 놓이면 여러분의 카피는 굉장히 읽기 힘들어진다는 것을 알고 있어야한다.

낮은 대비의 텍스트는 잠재적으로 많은 앱들의 사용성을 망가뜨릴 수 있다낮은 대비의 텍스트는 잠재적으로 많은 앱들의 사용성을 망가뜨릴 수 있다


백그라운드와 포그라운드의 칼라가 색맹의 사람들과 시력이 낮은 사람들에게 충분히 대조되는지 검증하자. 그렇게 어려운 일이 아니다. 명암비(contrast ratio)를 확인하면 끝이다. 명암비는 한 칼라가 또다른 칼라와 얼마나 다른지 표현한다(일반적으로 1:1 혹은 21:1 이런식으로 쓴다). 비율에서 두 숫자의 차가 높을수록 두 칼라 사이에 상대적 휘도(luminance) 차이가 크다는 것이다. W3C는 바디 텍스트와 이미지 텍스트에대해 아래  명암비를 추천한다.
  • 작은 텍스트는 백그라운드에대해 적어도 4.5:1의  명암비를 가져야한다.
  • 큰 텍스트(14pt 볼드/18pt 기본 보다 큰)는 백그라운드에대해 적어도 3:1의 명암비를 가져져야한다.
좋은 소식은, 이것을 직접 확인하지 않아도 된다는 점이다. Color Contrast Checker 도구를 사용하여 그냥 몇번의 클릭으로 칼라 조합을 확인할 수 있다.

Webaim 칼라 대조 체커Webaim 칼라 대조 체커


보너스: UX 디자이너를 위한 필수 도구들
쉽게 일하기 위해 칼라 팔렛트를 고르는데 최고의 도구들을 알려주겠다.

Adobe Color CC(이전에는 Kuler로 알려졌다)는 칼라 스킴을 찾고, 수정하고, 만드는데 훌륭한 도구이다. 팔렛트에 있는 모든 칼라는 몇번의 클릭으로 개별적으로 수정하거나, 기본 칼라로 정할 수 있다. 팔렛트를 저장하고 라이브러리에 넣을 수도 있고, 이 사이트의 커뮤니티에서 만든 여러 훌륭한 칼라 스킴들이 있다.

Adobe Color CC는 다양한 칼라 스킴 선택을 빠르게 탐험해볼 수 있는 멋진 도구이다Adobe Color CC는 다양한 칼라 스킴 선택을 빠르게 탐험해볼 수 있는 멋진 도구이다


다른 디자이너가 사용한 특정 칼라에대해 비주얼 조사를 하고 싶으면, dribbble.com/colors로 가서 필요한 칼라를 선택하자.

shot에 포함된 칼라의 최소 퍼센트를 지정할 수도 있다(이 shot은 30% blue이다)shot에 포함된 칼라의 최소 퍼센트를 지정할 수도 있다(이 shot은 30% blue이다)


shot에 포함된 칼라의 최소 퍼센트를 지정하기shot에 포함된 칼라의 최소 퍼센트를 지정하기


메트리얼 디자인 가이드라인은 일러스트레이션에 사용되거나 브랜드 칼라를 개발하는데 사용될 수 있는 굉장한 칼라 팔렛트를 제공한다. 이 팔렛트의 모든 칼라들은 서로 조화롭게 동작한다.


Colorzilla는 구글 크롬과 모질라 파이어폭스에서 가능한 익스텐셔이다. 여기에는 color picker, eye-dropper, CSS gradient generator, palette browser을 포함하여 칼라 관련 것들을 담고있다.



Coolors는 다중칼라의 스킴을 만드는데 강력한 도구이다. 선택된 칼라를 잠그고, 새로운 팔렛트를 생성하기위해 스페이스바를 누르면 된다. 이 도구의 멋진 점은 한 결과만 나오도록 제한하지 않았다는 점이다. 참조 포인트를 수정ㅎ여 간단하게 몇개의 칼라 스킴을 얻어낼 수가 있다.


내가 칼라 스킴을 만드는 개인적인 방법으로는 사진을 이용하는 것이다. 이 도구는 이미지를 업로드하여 그것으로부터 칼라 팔렛트를 만들어준다.

Coolors는 이미지를 업로드하여 그것으로부터 칼라 팔렛트를 만들어준다Coolors는 이미지를 업로드하여 그것으로부터 칼라 팔렛트를 만들어준다


Color Blindness Simulation in Adobe Photoshop
포토샵으로 당신의 디자인의 접근성 테스트를 할 수 있다. 그냥 View > Proof Setup으로 가서, 적녹색맹과 제2색맹(Protanopia-type이나 Deuteranopia-type), 두 타입중에 선택할 수 있다.



디자인의 접근성 이슈를 막기위해, 디자인하는동안 스스로 색맹의 경험을 해보는 것도 좋은 방법이다. NoCoffee Vision Simulator는 어느 페이지에서도 칼라-시력 결핍이나 낮은-시력 조건으로 시뮬레이팅할 수 있게 해준다. 예를들어 "Color Deficiency"를 사용하여 "Deuteranopia"를 설정하면 웹페이지가 흑백으로 보인다. 이것이 시각적인 저하의 사용자에게 당신의 디자인 접근성을 만드는데 도움을 줄 것이다.




 칼라는 디자이너의 툴킷 중에 가장 강력한 도구 중 하나이다. 그러나 동시에 통달하기에 까다로운 도구이기도 하다. 위에서 말한 규칙들이 새로운 디자이너들에게 좋은 토대가 되길 바란다. 이제 실전으로 가볼 시간이다. 칼라 스킴에서 훌륭해지는 최고의 방법은 실제로 만들어 보는 것이기 때문이다.



이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: Yeah, redesign(Part 1)

모바일 세상에서 어떻게 리디자인에 접근할 수 있을까

나는 디자인 수석으로서, 항상 내 자신에게 이렇게 질문한다. "우리 팀이 사용자에게 어떻게 최고의 제품 경험을 계속해서 전달할 수 있을까?" 내 대답은 항상 같다. '급격하게 변하는 커뮤니티에서 변화하고 진화하는 사용자의 기호를 항상 고려해야한다.' 그러나 제품 경험을 리디자인하는 것이 방법이라면, 시작된 프로세스를 얻어내기 위한 내부 토론을 어떻게 시작할까? 제품 아이덴티티는 유지한채로 새로운 기능과 디자인의 균형을 맞춰가며 확장가능할 솔루션을 어떻게 달성할 수 있을까?

여러분도 비슷한 디자인 과제를 안고있다면, 아래 질문들의 대답을 찾아가며 이 글이 어느정도 도움이 될 수 있을 것이다.

  1. 그 사용자가 이미 사랑하고 있을때 왜 제품을 리디자인해야할까?
  2. 어떻게 데이터 주도 회사의 패이스에 맞춰가며 리디자인을 시행할까?
  3. 결과물을 어떻게 측정할까?
  4. 다음 단계는 무엇일까?

이 질문에대한 답변을 찾는데 우리 메인 제품인 Sing! Karaoke가 겪은 리디자인을 공유하고, 우리 팀이 이 방법으로 어떻게 난과을 극복했는지 보여주고 싶다.

2년하고도 6개월전에 내가 처음 회사에 들어왔을때, 각 앱(Sing! Karaoke, Magic Piano, Autiharp, Guitar)마다 배치된 팀이 하나씩 있었다. 각 팀은 디자이너 한명, 프로덕트 메니저 한명, 그리고 두명의 엔지니어로 구성된다. 서로다른 성장 속도로인해 Smule 식구중에 Sing!이 선두에있는 앱이 되었다. 회사는 앱 기반 개발 구조에서 기능 기반 구조로 초점을 바꾸기 시작했다. Sing에 기능을 추가하는데 더 많은 노력이 들어가고 디자이너들 사이에 디자인 협업이 더 많이 필요하게 되었다는 의미이다. 사업이 바뀌면서 우리는 기존의 제품 디자인과 프로세스는 팀을 키우고 사용자를 만족시키는데 요구사항이 충족되지 못했다는 것을 알았다.

리디자인을 단지 한 프로젝트에만 적용시키는게 아니라 우리 사용자와 디자이너, 프로덕트 매니저, 인지니어, 이사원들을 끌여 들여야 한다는것을 알았다. 당사자들은 리디자인의 목적을 위해 초기 단계에 얻고 리디자인이 어떻게 진행되어야하는지에대한 피드백을 받음으로써 4가지 범주에서 리디자인이 달성하고자하는 명확한 목표를 설정할 수 있게 도와준다(Have these parties buy into at early stage for the reasons of redesign and provide feedback for “how” the redesign should happen helped us set a clear goal what redesign would achieve in four areas).


  • 사용자 경험 증진하기(Improve user experience)
  • 디자인 팀을 확장가능하게 만들기(Empower design team for scale)
  • 제품 인게이지먼트 증진하기(Increase product engagement)
  • 유지가능한 공학적인 솔루션 만들기(Build a sustainable engineering solution)

1. Sing!의 사용자 경험 증진하기
Sing! 경험에 일관성과 지속성 만들기
수많은 사용자 연구에서 사용성에 가장 강력하게 기여하는 녀석 중 하나가 일관성이라는 것을 알고있다. Sing!은 많은 기능으로 즐거운 제품이다. 이 제품이 2012년도에 출시되었을때는 더 적은 기능과 작은 사용자 기본을 가졌었다. 이런 적은 기능들은 서로 다른 문맥에서 분리된 컨텐트를 표현하기위해 서로다른 칼라를 쓰는 디자인의 결과를 낳았다. 예를들어 이전 버전의 Sing!은 다양한 사용으로 'Call to Actions'를 표시하는데 4가지 이상의 칼라를 사용했다. 예전 디자인이 사용자를 즐겁게하는 목적에 맞춰져있는동안 이런 여러 칼라 CTA(wiki, 역자가 이해한바로는 CTA는 광고버튼 등을 의미함)는 새로운 사용자를 혼란스럽게 만든다는 사실을 알아냈다. 현재 사용자 경험을 증진하기위해서 리디자인은 일관적인 UI 랭귀지를 설립할 필요가 있다는 의미이다.

새로운 사용자 인게이지먼트(engagement, 참고링크) 증진하기
컨덕팅 사용자 연구(Conducting user studies)에서는, 새로운 사용자는 그들의 (다른 앱이나 제품으로부터 UI 인터랙트했던) 예전 경험을 가져와서 처음 Sing!의 인터렉션 기능처럼 동작할거라 생각한다는 것을 인지해야 한다고 말한다. 그리고 아주 중요하게도, Sing! 인터페이스가 사용자 경험에 일치하지 않았을때는 그 인터페이스를 배우고 이해하는데 추가적인 에너지가 소비되고, 이것은 새로운 제품을 관심있게 시도해보게 만들기도 하지만 생소한것을 겪어야하기도 하게 만든다. 리디자인 과정에서 개발해온 패턴을 매칭시키기위해 표준적인 UI가 증가하거나 커스텀 UI를 바꾸는 것이 사용자들에게 더 빨리 더 쉽게 제품에 친숙해지게 돕는다는 생각했다. 이렇게하여 사용자들이 빨리 더 나은 인게이지먼트의 제품을 자연스럽게 이해하는데 도움을 줄 수 있다.

기존에있던 사용자 잔존율을 증가시키기
앱과의 인터렉션에서의 비용은 육체적(physical)으로나 정신적(mental)으로 둘 다 측정가능하다. 육체적 비용은 사용자가 필요로하는 특정 목표를 달성하는데 몇 단계인지 측정한다. 정신적 비용은 사용자가 한 작업을 완료시키거나 어떤 목표 혹은 스트레스(stress)를 달성하기위해 필요한 내제적, 외부적 인식 로드를 측정한다. 예를들어 Sing!의 사용자들이 다른 사용자와 듀엣을 시작하길 원할때, 이 목표를 달성하기위해 다중 UI로 넘어간다. 이것은 컨텐트의 이해를 돕지 못하여 시간적으로나 스트레스적으로 비용이 드는 것이다. 여기에는 명확한 표준적 인터렉션과 UI 디자인의 계획과 신조로 사용자의 육체적, 정신적 비용을 줄일 것이다.




2. 디자인 팀을 확장가능하게 만들기
Sing!을 위한 새로운 폰트 만들기
Sing!은 Gotham 폰트로 시작했었다, 이 폰트는 뉴욕시티의 중세 건축에서 착안되었다. Gotham은 Smule의 제미와 기발함, 환영하는 기분을 알리기위한 훌륭한 폰트이다. 오늘날까지도 Smule의 브렌드 아이덴티티로 표현되고 있다. 그러나 Gotham은 보통 인쇄나 미디어 어플리케이션에 사용되는 폰트이다. 모바일 기기에서 폰트를 사용할때, 많은 이슈를 야기한다. Gotham은 넓은 커닝(kerning, 텍스트가 시각적으로 보기 좋도록 글자간의 간격을 조정한것)을 가지고 있고, 주어진 단어나 문장에대해 너 많은 공간을 차지했다. 모바일 기기는 제한적인 소유지(화면 크기)를 가지므로 디자이너들은 항상 그 텍스트들을 iOS와 안드로이드 둘다에서 잘 보이도록 만들어야하는 추가적인 노력을 해야했다. 그 폰트 크기는 작은 공간에 맞추기위해 여러번 줄여야했고, 이것은 사용자에게 가독성 이슈를 만들었다. Gothan에의한 또다른 이슈로는 낮은 기준선(baseline)이다. 시각적으로 중앙에 놓으려면 이것때문에 수작업을 해야했다. 이런 예시들에서 볼 수 있듯, 결과적으로 개발동안 많은 디자인 이슈를 만났다. 이제는 리니자인을 하면서 해야할 것으로서, 확장가능하고 플랫폼 표준 폰트를 잦는것이 중요한 결정사항이라는 것을 안다.

Sing!은 그 디자인 언어인 표준화가 필요하다.
디자인은 유기적(organic)이기도하고 향수를 불러일으키기(nostalgic)도한 창의적인 과정이다. 표준 UX/UI 디자인 가이드라인이 제자리에 없이는, 프로젝트에서 작업하는 각 디자이너의 미학으로 이 제품은 뒤죽박죽이 될것이다. 이런 디자인으로 계속 작업하다가는 디자인 팀에서 혼란을 만들고, 디자이너 결과물의 한계와 질이 떨어진 제품을 만들었다. 우리의 예전 Sing! 디자인 표준이 명확하게 정의되있지 않았다는걸 알았다. 이런 모호함은 디자인 비평/검토 과정을 더 지연시키고 더 힘들게 하였다. 팀에서 누구도 우리가 목표로 하고있는 디자인 표준을 분명하게 말할 수 없었을때, 모든 피드백이나 리뷰는 개신 선호에따라 판단되었으며, 결국 대부분 정당성을 입증할 수 없었다. 한 팀으로서, 사용자에게 최고의 제품과 경험을 제공하기위해서는 협력적인 노력이 들것이라는 것을 인지했다. 결국 리디자인하고 앞으로 나가기위해서는, 모든 디자인 팀원들간에 소통할 수 있는 명확한 표준이 필요했음을 깨달았다. 우리는 팀에의해 모든 제품 디자인 결정사항에대한 표준을 설정하였다.

디자인팀에서 거대한 성장은 몇가지 규칙들을 설립해야한다는 것을 알게 만들어주었다. 이 가이드라인은 IA, 레이아웃, 폰트, 칼라, 그림요소(imagery), 인터렉션을 다루는 법을 세울 것이다. 이 가이드라인은 디자이너들이 한번에 올바른 디자인 결정을 만들 수 있도록하는데, 디자인 프로세스를 절감해 많은 디자인 이슈에 적용할 수 있는 프레임워크가 될 수 있다. 더욱 중요하게도 디자인 팀은 우리의 스타일, 요소, 패턴을 문서화하여 가지고 있어야하는데, 공유되고, 중앙 저장소이고, 필요한만큼 빈번하게 업데이트되야한다. 한곳에 공유된 중심원(hub)이 있으면 디자인의 일관성을 증진시킬 수 있으며, 뿐만 아니라 디자인의 질과 양도 따라온다. 즉 디자인팀은 Sing! 리디자인으로 가이드라인을 만들어낼 필요가 있었으므로, 분리되고 개인적인 디자인을 줄이고, 외관상으로 일관적이게 남길 것이다. 이것이 우리의 목표이며, 결국 디자이너들은 세세한 아이콘으로 작업할 수 없고 올바른 명세가 무엇인지 생각할 수 없을 것이다. 대신 사용자를위한 더 창의적인 디자인 솔루션에 집중할 수 있다.

디자인팀은 규모가 확장되야할 필요가 있다
제품에 추가되고있는 기능이 많아지고 더 많은 Sing 사용자가 생기면서, 우리 디자인 팀은 협력을 성장하고 증진할 필요가 있다. 협력을위한 기본적인 틀의 작은 블럭을 만드는 공통된 이해 없이는, 팀에게 이런 성장을 유지하기위해 넣는 압력은 복잡해진 의사소통을 만들 수 있다. 우리 팀이 잘하고있다는 확신을 위해서, 우리는 디자인 접근법과 워크플로우를 모듈화시켜야 한다는 점을 알았다. 이 말은,  리디자인팀이 작은 블럭을 만들며 디자인을 만들어야할 필요가 있다는 뜻인데, 이 블럭은 리디자인의 기초가 되고 모든 디자인 노력(effort)이 될것이다. 이렇게 각자가 블럭을 만드는 것은 디자이너들이 쉽게 협력할 수 있게 해주고 필요에따라 작업을 쪼개게 해준다. 게다가 새로운 디자이너가 오면, 기존의 팀원이 프로젝트를 이끌기위해 블럭을 만드는 것을 활용할 수 있고, 새 맴버를 위한 일정을 명확하게 정할 수 있게 된다.




3. 제품 인게이지먼트 증진하기
새 사용자에게 내장된 경험 증진하기
새로운 사용자가 새 앱을 쓰려고 할때, 한번에 두가지를 배우는데, 첫째로 앱의 기능이고, 둘째로 이 기능을 어떻게 쓰는지이다. 명확하고 표준화된 UI/UX 디자인이 없으면 사용자는 앱에서 개별적인 인터페이스 요소를 완전히 소화하지 못할 것이다. 사용자에게 인터페이스 디자인을 소개하는 것보다 제품 기능 사용에대해 초점을 맞추기 때문에, 우리는 새로운 사용자의 기대를 이해하고 그들에게 명확하게 유용한 정보를 전달해야했다. 전반적으로 새 디자인은 앱의 혼란스러운 부분을 간단하게 만들어야했고, 사용자들이 새 기능을 시도하고 인터렉트함에 편안하도록 해주어야 했다.

사용자 잔존율(retention)을 증가시키기
Smule에서는 새 사용자가 앱을 처음 경험하고나서 이후에 얼마만에 다시 돌아오는지(예를들어 2일이나 7일같이) 정의하여 사용자 잔존율을 면밀히 모니터링한다. 만약 사용자의 첫번째 경험이 좋지 않았다면, 이틀연속 다시 돌아오기 힘들 것이다. 사용자 연구를 통해 알아내었는데. 사용자들이 처음하는 시점에서 기능을 찾아내면 많은 기능들을 즐긴다. 혹은 이미 있는 기능들을 요청했다. 이런 발견으로부터 우리 디자인 안내가 사용자의 유지를 잡지 못하고 있음을 의미했다. 만약 디자인이 사용자의 생각속에 있는 기능을 어디서 찾고 어떻게 접근하는지 알려주지 못한다면 사용자들은 혼란에 빠지고 Sing을 계속 사용하고 싶다는 흥미를 잃어버리게 될것이다. 리디자인으로 사용자 잔존율과 제품 사업 목표를 만족시키는 더 나은 안내를 고안해내야한다.

개발과 배포 사이클 증진하기
2014년도에 리디자인을 고려하기 시작할때부터 iOS와 안드로이드에서의 제품 기능을 동일하지 않았다. Sing! iOS는 Sing 안드로이드보다 더 많은 기능이 있었다. iOS와 안드로이드간의 일관성 부재는 디자인 팀에게 일거리를 두배로 주고 개발 사이클을 지연시켰다. Sing!은 우리가 리디자인을 생각하기 시작할때부터 많은 사용자들이 생겼었다. 제품 디자인과 개발 사이클에 추진력과 속도를 높히고 싶었다. 이런 마음을 가지고 우리는 내부 디자인 팀의 워크플로우와 효율을 올리는데 리디자인이 필요하다는 것을 알았다. 리디자인으로 디자인과 개발 시간을 50%나 줄일 수 있었고, 이것은 현재 리소스로 새로운 기능을 테스트하고 배포하는데 더 많은 기회를 줄 것이다.




4. 유지가능한 공학적인 솔루션 만들기
개발 프로세스 증진하기
부조화스러운 UI는 사용성 이슈를 만들 뿐만 아니라 디자이너와 엔지니어들에게 추가적인 작업 과중을 안겨준다. 예를들어, 디자이너들은 한 아이콘일지라도 여러 시나리오에서 사용될 여러 칼라와 사이즈로 아이콘들을 만든다. 엔지니어에게 이 아이콘들을 올바른 화면에 놓게 하기위해 아이콘들을 만들고 명세하는데 디자이너들은 추가적인 40% 시간이 더 든다. 엔지니어도 이 명세를 따르고, 각 아이콘이 올바르게 위치하도록 커스터마이징된 코드를 짜야한다. 말은 쉬워보이지만 다양한 화면 크기나 플랫폼(iOS와 안드로이드)에 부딪혔을때 이 프로세스는 끔찍해진다. 엔지니어와 이야기하고나면 디자이너와 엔지니어 모두 더 나은 방법으로 서로 협력하고 싶어한다. 여기서 리디자인의 필요성에대한 서로다른 관점이 나온다. 디자이너와 엔지니어가 어떻게 효율적으로 제품을 설정하고 만들지에대한 체계적인 방법을 만들자.

제품 개발 품질을 증가시키기
디자인 QA를 하는것과 올바르게 구현되었는지 확인하는 것은 디자이너의 책임이다. 디자이너와 엔지니어에게 가장 비극의 순간은, 디자인 부분을 변경하다가 생긴 디자인 버그를 엔지니어가 수정하는 것인데, 여기서 또다른 버그가 만들어진다. 이때문에 엔지니어는 디자인 버그를 고치는데 더 많은 시간이 들고, 그 구현이 버그없이 디자인과 일치한다고 보장할 수 없었다. 앞단에 나오는 모든 디자인 버그를 해결하기위한 리디자인을 요구하는것은 비현실적이라는 것쯤은 우리도 안다. 그러나 마진을 어떻게 줄것인지, 아이콘 사이즈를 어떻게 만들것인지, 누른 상태는 어떻게 적용시킬지 등에 대한 표준의 중심 디자인 가이드라인을 만들어서 예전과같은 일이 일어나지 않게 할 수 있다.

세계 현지화 준비하기
리디자인에대한 생각을 시작할쯤에 Sing은 US 중심의 앱에서 다국적인 제품으로 옮겨가고 있었다. 세계 사용자에게 소통하기위해, 우리는 12가지 언어에서 20가지 언어로 현지화 시켜야 했다. 영어기반 앱을 외국어로 적용시킬때 UI는 쉽게 망가질 수 있다. 예를들어 영어와 독일어/러시아어를 비교해보면 같은 의미라도 독일어/러시아어가 더 많은 문자로 표현된다. 영어 레이블에 맟춰놓은 제한된 공간에서는 독일어와 러시아어가 제대로 작동하지 않을 수 있었다. 공간을 설정하고 올바른 계층을 적용시는 규칙을 명확하게 하지 않고서는 현지화된 언어가 작은 사이즈로 표시되거나 짤리게 될 것이다. 언어 하나하나 이 이슈를 해결하면서 엔지니어와 QA에 어마어마한 수고가 들어갔다. 리디자인을 통해 미래에는 서로다른 모든 언어를 최적화할 수 있는 유지가능한 솔류션을 찾아야한다.



이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: Design words with data


우리가 작성하는 것을 어떻게 데이터로 알 수 있을까?

쓰는것은 양식의 예술이다. 단어는 우리를 웃게 만들기도 하고, 울게 만들기도 하며, 멋진일을 하는데 영감을 주기도 한다.

그러나 나는 쓰기에도 과학이 있다는 것에 대해 오늘 이야기해보고 싶다. 우리는 데이터로부터 어떻 용어를 쓸지에 대한 정보를 제공받고 그 용어에대해 객관적으로 생각하게 해준다.

무엇이 옳고 무엇이 그른가?
나는 드롭박스의 UX 작성자로서, 우리의 목표는 모든 사람들이 우리가 사용하는 모든 단어를 이해할 수 있게 만드는 것이다. 잘못된 단어 하나라도 사용자 경험을 파괴할 수 있다. 모호한 버튼의 글자 하나나 익숙하지 않은 용어는 사용자를 쉽게 낙담시킨다.

우리가 옳바른 단어를 골랐음을 확신하려면, 쓰기에대해 정보에 근거한 선택을 하기위해서 조금 특별한 기술들을 사용하고 있다.

1. Google Trends
몇몇의 용어들 중에 적절한 것을 선택해야한다고 가정해보자. 예를들어 다음 중에 어느것을 여러분 제품에 사용할 수 있을까?

* Log in
* Log on
* Sign in
* Sign on

첫번째로 소개할 것은 Google Trends이다. 쉼표를 기준으로 비교하고 싶은 단어를 모두 입력해 넣으면 된다. Google Trends는 사람들이 Google에서 이 단어를 얼마나 자주 검색했는지 비교해준다. 그 검색은 자동으로 "페이스북은 log in" 혹은 "Sign in은 안된다" 같은 말도 포함된다.

그래서 Google Trends는 어떤 결과물을 보여줄까?

Google Trends를 사용한 용어비교Google Trends를 사용한 용어비교


짜잔! 여기선 깔끔하게 Sign in이 이겼다. 이 말은 사용자들이 이 동작을 부를때 "Sign in:을 더 많이 쓰는 것으로 보인다. 당신이 사용자 경험에 단어를 맞추려면, 다른 것보다는 "Sign in"을 고르는게 더 안전할 것이다.


드롭박스에서는 "Version history" 기능을 표현할때 각기 다른 용어를 쓴다는 것을 발견했다.


우리는 이런 부조화를 고치고 싶었으나 어떤 용어를 사용해야할지 확신이 서지 않았다. "version history"라 해야하나, 아니면 "file history"? 우리는 여러개 고려대상 중, Google Trends의 결과로 그 한가지를 뽑아냈다.

Google Trends에서는 "version history" 검색이 더 많아보이게 나왔고, 우리가 제품 전반에서 "version history"라 부르는 가장 큰 이유가 이것이다. 

2. Google Ngram Viewer
Ngram Viewer는 Google Trends와 비슷한데, 구글이 스캔한 출판된 책에서 검색한다는 점만 다르다. 여러분은 이 데이터를 이용하여 여러분의 언어에서 어떤 용어가 더 일반적으로 쓰이는지 볼 수 있다.

드롭박스는 최근에 iOS앱에 새로운 서명 툴을 출시했다. 여러분의 서명을 그리는 화면에서, 이것을 검토하기 전에는 "Sign Your Signature"이라 적어놓았었다.

우리도 "Sign Your Signature"가 이상하게 보인다는 점을 인지하고 있었으나, 이상하게 보인다는 이유로 이것을 바꿀 순 없었다. 어떻게 이 변경을 납득시켰을까?

Ngram Viewer를 보여주며 "Sign Your Signature"과 "Sign Your Name"을 비교했을 때이다. 이것은 "Sign Your Signature"이 좋지 않음을 보여주었다. 이 데이터를 팀에게 보여주니 그들은 빠르게 "Sign Your Name"으로 바꾸어주었다.

Ngram Viewer를 사용한 용어 비교Ngram Viewer를 사용한 용어 비교


3. 가독성 테스트
몇년동안 언어 전문가들은 여러분의 단어가 어떻게 쉽게 이해되는지 측정해주는 여러 가독성 테스트를 개발해왔다.

이 테스트의 많은 것이 여려분이 쓴 것의 등급을 매겨줄 것이다. 예를들어 8등급이라는 의미는 US에서 일반적으로 8등급이 여러분이 쓴 거을 이해할 수 있다는 뜻이다.

나는 이 테스트중 하나를 사용해 내 Medium 이야기(How to design words)를 하나 돌려보았다. 아래에 그 결과이다.

Readability-Score.com의 결과Readability-Score.com의 결과


여기서 아주 흥미로운 데이터를 얻을 수 있다. 예를들어
  • 나는 6등급으로 이야기를 썼다.
  • 내 어조가 중립적이지만 약간 긍정적이다.
  • 나는 문장당 평균 10.7 단어를 쓴다(드롭박스에서는 문장을 15단어 이하로 쓰려고 노력하고 있다).

이런 테스트 중 하나를 받아보고 싶다면 아래에 몇 시도해볼 수 있는 링크를 준비해놓았다. 이 중 몇개의 테스트는 더 좋은 가독성으로 작성하기 위한 수정도 제안해줄 것이다.

4. 리서치 조사
새 기능에 어떤 이름을 붙일지 알아보고 있는가? 아니면 어떤 가치관에 집중하는가(Or what value prop to focus on)? 이런 상황에서는 리서치 조사를 세팅하는게 도움이 될 수 있다.

많은 조사 툴이 여러분의 타겟 대중을 선택할 수 있게 해준다. 따라서 잠재적 사용자로부터 쉽게 피드백을 받을 수 있다.

아래에는 여러분이 연구 조사를 설정할 수 있는 몇가지이다.
드롭박스는 우리 제품을 사용하는데 가장 큰 이점이 무엇인지 물어보는 설문조사를 시행했다. 대부분의 사람들이 "접근"이라고 대답했다(어떠한 기기에서도 내 파일을 가져올 수 있는 능력). 결론적으로 우리는 대문 페이지를 '접근'에 맞춰 다시 디자인하게 되었다.


5. 사용자 연구
사용자 연구는 여러분이 작성한 것에 대한 피드백을 받을 수 있게 해준다. 일반적으로 사용자 연구에서는 여러 사람들 초대해 글을 읽게 하거나 제품을 사용하게 한 다음 그것에 대해 질문을 한다. 이런 것은 여러분이 작성한 것이 이해되었는지 아닌지 알아보기에 매우 좋다.

우리의 조사자 중 한명은 최근 새로운 흐름을 테스트했던 연구를 진행했다. 거기서 말한 한 단계이다.
Select "Remove local copy" to save space
사용자가 이 기능을 사용할때 질문해보았다. 대부분 이 기능을 이해나는데 힘들었고, 유용하다고 생각되지 않았다. 그래서 사용자에게 유리한 말을 앞쪽으로 놓음으로서 단어의 순서를 바꾸었다.
Save space by selecting "Remove local copy"
이번에는 참여자들이 이 기능을 사용할때 훨씬 쉬웠다고 말해주었다. 그리고 우리는 모든 단어의 순서를 바꾸었다.

자성자의 직감이 어떻게 경험으로 바뀔수 있는지 보여주고, 여러분은 다른 디자인 선택처럼 테스트할 수 있다.

마음으로 쓰고 머리로 고치자
특정 용어를 선택하려 할때는 데이터가 유용할 수 있다. 그러나 이 말뜻이 기계처럼 작성하라는 의미는 아니다.

내가 본 바로는, 먼저 마음으로 초안을 그린다. 당신의 결단력을 믿자. 그러고나서 당신의 생각을 써내고 이제 단어를 다듬기위해 조사나 데이터를 찾아보면 된다.

글쓰기는 예술이자 과학이다. 마음으로 쓰고 머리로 고침으로써 근거있고 유악한 것을 만들어낼 수 있다.

데이터는 작성자에게 편리함을 제공한다. 데이터는 여러분이 쓴 것이 "옳도록" 만든다.



이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: UI Animation: Please Use Responsibly



지난 몇년간 프로토타입 툴이 터져나왔는데, 이것은 디자이너들에게 세부적인 인터렉션을 만들 수 있는 기회를 주게 되었다. 디자이너는 이 틀울 배우는데 몇시간이나 몇일을 쓰고 있다. 그러나 많은 디자이너들이 프로토타이핑 툴의 선택의 기술적 세부사항에서 놓히고있는게 있다. 디자이너들은 몇걸음 뒤로 물러서서 애니메이션의 목적과 목표가 무엇인지 질문을 던저여한다. 어떤 의도로 애니메이션을하면 모션은 의사소통을위한 도구로서 사용된다. 디자이너들은 사용자에게 방해가되는 경박한 애니메이션 사용을 피해야한다.

디자이너들은 디자인 문제를 해결하기위한 이점으로서 애니메이션을 사용해야한다. 예를들어 계속성을 보여준다던지 들어가고 나오는 애니메이션을 통한 오브젝트 사이에 관계를 보여준다던지 하는 것들이 있다. 선택에대한 개선을 위해 인식 로드(cognitive load)를 줄임으로서 의미있는 애니메이션은 사용자를 기쁘게하고 정보를 제공한다.

인식 로드를 줄이기
인식 로드는 작업을 완료하기위해 필요한 정신적 노력의 양을 말한다. 위키피티아에서 "큰 인식 로드는 작업 완수에 부정적인 영향을 줄 수 있다"고 말하고 있다. 사용자가 사이트에 들어와있을때, 그들은 정보를 넘치도록 받는다. 그 결과 '터널 시야'라고 알고있는 선택적 태도를 가지는데, 화면에서 그들이 작업하고 있는 부분에 직접적으로 집중한다는 의미이다. 따라서 사용자는 화면에 있는 모든것을 보지는 않을 것이다.

디자이너로서, 사용하기 쉬운 인터페이스를 만드는 것은 중요한 일이다. 이것은 사용자가 작업을 완수하는데 드는 정신적인 노력을 가볍게 해준다. 디자이너들은 이런점을 어떻게 애니메이션으로 달성할 수 있을까? 우리가 모션을 잘 사용할때, 이것은 사용자 피드백과 효과적으로 소통하여 사용자 혼란을 줄여준다. 추가적으로 사용자 생각을 없애므로서, 페이지의 "액션을 부른다"던지 그런 더 중요한 것들에 주의를 기울일 수 있게 된다.


사용자의 주의를 끌기
NNgroup은 "애니메이션을 써서 효과적인 방법은 사용자의 시선을 끄는 것이다"고 말했다. 사용자의 시선을 끌게되면 스크린과 화면안의 요소들 사이의 계층과 관계를 보여주는데 집중시켜 가이드를 할 수 있게 해준다는 이점이 있다.

애니메이션은 사용자 화면에 바로 놓이면 안된다. NNgroup 글에서는 주변의 뷰 중에 움직임은 주변의 잠재적 위험을 인식하는 생물학적 특성덕분에 사용자 시선을 빠르게 끌 수 있다. 그러나 사용자가 의된 사이즈의 사이드바나 헤더에 있는 전형적인 베너나 팝업에 주목하지 않으려고 해왔는데, 디자이너들은 UI와 애니메이션이 이 패턴을 밟지 않도록 반드시 확신해야한다. 디자이너들은 한번에 최소한의 모션만하고, 관련된 정보가 있을것이라 사용자가 생각하는 위치에 요소를 애니메이션하여 무분별한 베너를 피할 수 있다.

시각적 계층
화면에서 페이지 요소가 로드되는 순서를 애니메이션하는 것은 페이지의 시각적 계층을 보여줄 수 있다. 미묘한 애니메이션을 이용하여 페이지의 레이아웃을 사용자게게 보여줄것이고 인식 로드를 줄이는 것에 초점을 맞출 수 있다.

추가적으로 다른 요소에대해 같은 애니메이션을 사용하여, 그 요소들이 그룹화되있고 비슷한 동작을 취한다는 이해를 돕는데 도움이될것이다. 사람의 마음은 항상 새로운 패턴을 찾고있다.

더 나은 선택을 만들기
미시 인터렉션(microinteraction, 한 오브젝트의 이동)과 거시 인터렉션(macrointeraction, 오브젝트 사이의 이동)에서의 모션은  사용자 문맥을 제공하고 시스템을통한 지속성을 보여준다. 또한 모션은 새로운 인터렉션이나 제스처를 사용자에게 가르쳐줄 수 있다. 잘 사용된 애니메이션은 정보들이 어떻게 맞아떨어지는지 빠르게 이해할 수 있게 해주며 결과적으로 더 나은 결정을 할 수 있게 해준다.

애니메이션은 발견할 수 있게 해주는 능력을 가지고있다. 상태간의 트랜지션은 한 오브젝트의 기능을 소통할 수있게 한다. 예를들어, 메뉴 아이콘이 닫기 아이콘으로 바뀌어서 사용자에게 같은 버튼이 두 동작을 완료한다는 것을 보여준다.

애니메이션은 사용자가 공간적 정보의 마음의 지도를 만드는데 도움을 준다. 작은 화면에서는 이것이 중요하다. 한 사용자가 화면미로안에서 쉽게 길을 잃어버릴 수 있다. 예를들어 사용자가 오른쪽으로 계속 스와이핑하여 페이지 깊숙히 들어간다. 몇몇 사용자는 왼쪽으로 스와이핑하여 메인페이지로 돌아갈 수 있다는 것을 발견할 것이다. 발견가능성을 보장하기위해, 애니메이션과함께 시각적인 행동유도성(affordances)이 사용되어야 한다.

적응시키기(Onboarding)
애니메이션은 인터렉티브한 적응을 도와준다. 적당한 시점에 적절한 것을 사용자에게 보여줌으로서, 디자이너들은 진행하는 것을 보여준다(Designers are creating progressive disclosure). 진행 모습은 사용자가 봐왔던 잡다한 것을 줄여서 시스템을 이해하기 쉽게 만들어준다. 앱이 어떻게 동작하는지 새로운 컨텐트를 배우는동안 정밀한 애니메이션은 편하게해준다. 결과적으로 이것은 사용자에게 무엇이 중요한지 기억하는데 도움이 된다.

기쁨을 만들기
애니메이션은 사용자가 기쁘고 사용자 경험을 증진시키는데 멋진 방법이다. 그러나 애니메이션으로 사용자를 기쁘게하기전에 디자인너들은 사용자의 기본 기대를 충족시켜줘야하고 깨진것을 번저 제거해야한다. 그렇지않으면 즐거움이 없는 애니메이션을 느낄것이다. 애니메이션의 빈도(frequency), 지속(duration), 속도(speed)는 사용자의 시스템 이해에 영향을 준다. 이것이 왜 디자이너들이 애니메이션을 만들때 심사숙고해야하는지 그 이유다.


기쁨을 위한 애니메이션 추가를위한 적절한 장소는 그들이 원하는 것을 보여주면서 놀라게 해줄때이다. 예를들어 무료 배송같은 것들이다. 애니메이션은 사용자에게 방해가 되지 않아야한다.

빈도
디자이너는 사용자에게 이 애니메이션이 얼마나 자주 나타날지 생각해야한다. 첫번째로 보여지는 애니메이션은 신선하고 사용자를 기쁘게할 수도 있지만, 신선함과 기쁨은 그 후에 성가신것이 될수 있다. NNGroup은 사용자 테스트 세션동안 다음을 찾아냈다. 참가자들이 말한 내용이다: "이 [애니메이션]은 처음 보기엔 멋지지만 지금은 성가신것이 되었다"

지속
디자이너는 사용자들이 애니메이션을 기다리다가 그 작업을 포기하기 전에 얼마나 기다릴 수 있는지 알아야한다. NNGroup 연구는 100ms까지는 사용자에게 나타나야함을 보여준다. 애니메이션이 좀 길게 걸린다는 것을 파악하고, 그 시간 범위는 150ms에서 350이다. Val Head에 따르면 일반적인 애니메이션 가이드라인은 200ms에서 500ms 사이에 실행되는 것이다. 그 목적은 애니메이션이 자연스럽게 보이게 만들기 위함이다. 사용자들은 보기에 친숙한 것으로 식별하기때문에 결국 디자이너의 결정에 달려있다. 애니메이션이 얼만큼의 빠르기로 실행되어야하는지 적당한 선이 있는데, 너무 빨리 빠르면 사용자가 너무 느리게 놓칠 수 있으며, 너무 느리면 사용자는 시스템이 느리다고 인식 할 수 있습니다.

속도
애니메이션의 전반적인 속도는 성능의 인지에 영향을 줄 수도 있다. 느린 애니메이션은 전반적인 시스템이 느리다고 생각하게 만들 것이다. 그러나 지연을 숨기고 사용자가 인지하는 성능 증가를 유지하기위해 애니메이션을 사용할 수도 있다.

로딩 애니메이션은 시각적 피드백과 함께 나타나 사용자를 잡아둔다. 결과적으로 사용자는 기다리는 시간을 더 짧게 느낀다. 애니메이션의 사이클 수는 지각하는 속도를 높힐 수 있다. 페이스북은 스켈래톤 컨텐트 로딩 애니메이션을 가지고 있다. 이것은 전통적인 로딩 스피너로 만든 우아한 솔루션이다. Viget의 연구에서는 사람들이 일반적인 애니메이션보다 브랜드로된 로딩 이미지에대해 더 길게 기다릴 것이라는 점을 발견했다.


접근성
디자이너들은 애니메이션 접근성을 고려해야한다. 무질서하게 개별적인 모션은 현기증나고 지겹고 혼란스럽게 만들 수 있다. iOS7에서 화면 이동(transition)이나 백그라운드로 가는 애니메이션을 선택적으로 끌 수 있게 해놓은 이유이다. 백그라운드에있는 방식은 포그라운드보다 더 천천히 움직이는 시간차 스크롤은 올바르게 사용되지 않는다면 혼란을 만들 수도 있는 모션의 예시이다. 이것을 해결하기 위해서는, 디자이너들이 '큰' 동작의 애니메이션을 자동으로 실행시키지 않도록 해야한다. 사용자들이 애니메이션을 시작한다면 좀 더 준비되있을 것이고 방심한 틈을타 당하지 않을 것이다.


웹 접근성는 애니메이션이 적용된 컨텐트를 확인하는것이 텍스트 형태로 표현되는 것을 추천한다; 시각적으로 감소된 컨텐트와 무질서하게 사용자에게 접근하는 것을 접근하게 해준다. 디자이너들은 영향이 없는 사용자들이 그 작업흐름을 빨리하기위해 애니메이션을 끌 수 있어야한다는 상황도 알고 있어야한다. 제일 좋은 방법은 W3C 가이드라인에 따른 애니메이션 접근성을 만들기 위해서는 Web Accessibility를 확인하라.



디자이너들은 마음속에 아래 습관들을 기억하고 있어야한다.

체크리스트:
목표 : 애니메이션이 사용자에게 전달하고 싶은 것이 무엇인가?
초점 : 사용자의 현재 초점이 어디인가? 사용자가 찾고 있는 것이 무엇인가?

모션의 메카닉:
빈도 : 애니메이션을 얼마나 자주 실행하나?
지속 : 애니메이션을 얼마나 길게 실행하나?
속도 : 애니메이션을 어떤 속도로 실행하나?
발생 : 어떻게해서 애니메이션이 발생하나? 사용자 동작으로부터? 아니면 자동적으로?
접근성 : 사용자가 애니메이션을 껐을때 어떻게 사용자 경험에 영향을 줄 것인가?

디자이너들은 체크리스트의 항목으로 모션 스타일 가이드를 만들고 싶어할 것이다. 컨텐트와 시각적인것은 스타일 가이드가 있으며, 리스트에 애니메이션을 추가함으로서, 디자이너들은 전반적으로 일반적인 경험을 만들고 싶어한다. Google의 Material design and Slaesforce의 Lightning Design 좋은 예시 자료이다.

참조:



이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: How to use colors in UI Design


실질적인 팁과 도구들


색은 모든것과같고(Color is like everything else), 알맞게 사용하는 것이 최고이다. 여러분의 칼라 스킴에서 색을 최대 세가지로 제한하면 더 나은 결과물을 낼 수 있을 것이다. 디자인 프로젝트에 칼라를 적용시키는것은 균형을 맞추는 수많은 작업을 가지며, 더 많은 칼라를 사용할수록 그 균형을 맞추기 더 복잡해진다.


칼라는 디자인에 좋은 품질을 더하지 않는다-더 강력하게 만든다.
Pierre Bonnard

여러분 팔랫트에 정의해놓은 것에서 색을 추가해야 한다면, 쉐이드와 틴트를 사용하자. 이것은 다른 톤으로 작업할 수 있게 해준다.

60-30-10 규칙
이 인테리어 디자인 규칙은 시대에 상관없이 칼라 스킴을 쉽게 서로 놓게해주는 데코레이팅 기술이다. 60% + 30% + 10% 균형은 칼라에 균형을 맞춰준다. 이 공식은 균형에대한 이해를 만들어주고 집중하는 지점에서 다음까지 눈을 편안하게 이동할 수 있게 해주기때문에 잘 먹힌다. 또한 사용하기에도 매우 간단하다.

60%는 주요 색상(dominant hue)이고, 30%는 두번째 칼라, 그리고 10%는 강조하고싶은 칼라이다.



칼라의 의미
과학자들은 몇세기동안 특정 칼라에대한 심리적 영향을 연구해왔다. 미학 외에도 칼라는 감정(emotions)과 연상(associations)의 창조자다. 칼라의 의미는 문화와 환경에따라 다양하다. 이것이 왜 흑&백 패션 매장을 보는지의 이유이다. 그들은 우아하고 숭고해보이고 싶다.


  • 빨강색: 열정의, 사랑의, 위험한
  • 파랑색: 고요한, 책임감있는, 안전한
  • 검정색: 미스터리한, 우아한, 악의
  • 하얀색: 순수한, 고요한, 깨끗한
  • 초록색: 새로운, 신선한, 자연의

더 많은 리스트를 보고싶으면 color culture를 확인해보자.

먼저 그레이스케일부터
디자인에서 처음부터 칼라와 톤으로 작업하고싶어하지만, 이런 행동은 당신이 주요 칼라를 조정한다고 3시간을 쓰고있다는 것을 알아차렸을때 당신은 배신해버릴것이다... 매우 매혹적이긴하나 이런 태도를 피하는 법부터 배워야한다.

대신에 공간을 정하고 요소들의 레이아웃을 잡도록 해야한다. 이렇게하면 여러분의 많은 시간을 단축시킬 것이다. 몇 제약은 매우 생산적이다. 필립(flips)은 지루하지 않게 보여야한다. 좋게 보이려면 다른 톤을 시도해보자.


순수한 그레이스케일과 점정으로부터 떠나기
내가 배웠던 가장 중요한 칼라 기법중 하나는 채도없는 그레이 칼라 사용을 피하는 것이다. 실제 세상에서 순수한 그레이 칼라는 거의 존재하지 않는다. 검정도 마찬가지이다.

여러분의 색에 조금이라도 채도를 항상 넣자. 잠재적으로 사용자에게 더 자연스럽고 친근하게 보일 것이다.




자연을 믿자
최고의 칼라 조합은 자연에서보터 나온다. 그들은 항상 자연스러워보인다. 디자인 솔루션을 위한 환경을 찾는 가장 좋은 방법은 항상 팔레트가 바뀐다는 점이다.
영감을 얻기 위해서는 단지 주변을 둘러보면 된다
대비를 기억하자
몇 칼라들은 서로 잘 맞지만, 다른 것들은 그렇지 않을 수 있다. 칼라 휠에서 가장 잘 관찰되는 인터렉트가 무엇인지에대한 명확한 규칙들이 있다. 이 방법을 알고 있어야하지만 손수 할 필요는 없다.


여러분이 칼라 이론에대해 더 배우고 싶다면 이 글을 확인해보자-Color Theory For Designers: Creating Your Own Color Palettes


영감을 얻자
UI 참조에대해 이야기할때는 dribbble이 최고이다. 칼라로 검색하는 도구도 가지고 있어서, 다른 디자이너들이 사용한 특정 칼라에대한 시각적 조사를 하고싶으면 여기로 가보자 dribbble.com/colors


비디오, 출력 디자인, 인테리어 디자인, 패션... 그 많은것이 한곳에 모여있다. 이 팔랫트에서만 있지말고 관심있는 모든것을 저장하자.

  

종종 나는 KPOP 비디오클립에서 칼라를 따내기도한다. 이것들은 매우 훌륭하다.

도구들
쉽게 작업하기위해, 2017년에 사용할 수 있는 칼라 파랫트의 최고의 툴들을 묶어보았다. 이것들은 여러분의 시간을 많이 단축시켜 줄것이다.

Coolors.co
칼라를 선택하는데 명백하게 내가 제일 좋아하는 툴이다. 선택된 칼라에 락을 걸어놓고 공간을 누르면 팔랫트를 만들어준다. 또한 Coolors는 이미지를 업로드하여 그 이미지로부터 칼라 팔랫트를 만드는 기능도 제공한다. 이렇게 멋진 기능은 한 결과물에대해서만 제한이 없지만 대신에 참조 포인트를 수정할 수 있게 해주는 picker를 가진다.



Kuler
이 툴은 어도비에서 나온 툴이며, 긴 시간동안 우리 곁에있었다. 브라우저에서 데스크탑 버전으로 사용할 수 있다. 데스크탑 버전을 사용하고 있다면 포토샵에 칼라 스킴을 내보낼 수 있다.


Paletton
Kuler와 비슷하지만 다섯개의 톤으로 제한되지 않는다는 점이 다르다. 톤을 추가해가면서 주요 칼라가 필요할때 좋은 툴이다.


Designspiration.net
칼라 팔랫트에대한 아이디어는 있지만 그것을 섞은 예시자료가 필요하다고 생각해봐라. Designispiration는 이런 당신을 위한 좋은 도구이다. 5개의 칼라를 골라서 여러분의 쿼리에 맞는 이미지를 검색할 수 있다. 특정 팔랫트로 이미지를 찾을 수 있을 뿐 아니라 디자인에서 실제로 구현된 것이다.

Shutterstock Lab Spectrum
내가 고른 칼라로 사진을 찾고 싶으면 어떨까? 흠, Shutterstock는 특정 톤으로 사진을 찾는 Spectrum이라는 도구를 가지고있다. 검색에 뭔가 쳐넣을 필요가 없는데, 물방울표시로 작은 미리보기 이미지가 팔랫트를 생성해줄 것이기 때문이다.


Tineye Multicolr
그러나 사진에 있는 여러 칼라를 찾고 싶고, 각각의 양을 고르고 싶으면 Tineye가 도와줄 것이다. 이 웹사이트는 Flickr로부터 1000만개의 창의적인 일반 이미지를 데이터베이스에 쓰고 있다.
<동영상, viemo>

마지막의 생각들
칼라는 마스터하기에 힘든 개념이고, 특히 디지털 영역에서는 더 그렇다. 위에서 말한 팁들은 올바른 칼라를 선택하는 일에 도움이 될 것이다. 멋진 색채 스킴를 만드는 법을 배우는 가장 좋은 방법은 여러분 자신을 위해 열심히 연습하고 색을 가지고 노는 것이다.


이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
제목: Creating Usability with Motion: The UX in Motion Manifesto



역자: 이번 번역글은 늘 번역하던 개발관련 주제가 아닌데다 어려운 용어가 많아서 고민을 많이 했습니다. 제 번역글에서 부자연스러운 부분이나 잘못된 번역이 있다면 편하게 알려주시면 감사하겠습니다.




아래 선언서에는 "UX, UI 디자이너로서, 사용성을 위해 언제 어디서 모션을 구현해야하는지 어떻게 아는가? 질문에 대한 답변이다.

지난 5년동안, 나는 40개국 이상을 다니면서 몇백개의 상위 브렌드와 디자인 컨설던트, UX & UI 디자이너를 코치하고 멘토링하기위해 특별히 기여해왔고 UI 애니메이션에대한 튜토리얼을 했다.

그후 15년동안 사용자 인터페이스에대한 모션을 연구하여, 나는 모션을 사용한 UX 프로젝트에서 사용성에대해 12개의 특정 기회가 있다는 결론에 도달했다.

나는 이 기회를 "모션에서 UX에대한 12가지 원칙"이라 부르며, 이것들은 수많은 창조적인 방법으로 서로 쌓이고 섞일 수 있다.

나는 선언서을 5단계로 나누었다:
  1. UI 애니메이션 주제를 다루기-여러분이 생각하는 그런것은 아니다
  2. 실시간 vs 비실시간 인터렉션
  3. 모션이 사용성을 지원하는 여러방면
  4. 원칙, 기술, 프로퍼티, 값
  5. 모션에서 UX에대한 12가지 원칙

빠른 플러그로, 모션과 사용성에관한 주제에관해 학회나 워크샵에서 야러분의 팀위한 나의 강연을 원한다면, 여기로 가봐라. 여러분의 도시에서 수업에 참석하고 싶으면, classes">여기로 가보아라. 마지막으로 여러분의 프로젝트에대해 컨설팅을 받고 싶으면, 여기로 가면 된다. 내 목록에 추가되려면 여기로 가면 된다.



UI 애니메이션에 관한 것이 아니다
사용자 인터페이스에서 모션에관한 주제는 대부분 디자이너가 'UI 애니메이션'이라고 이해하고 있기 때문에(그렇지 않다), 12가지 원칙에 들어가기 전에 약간의 문맥을 만드는 것을 좋아한다.

디자이너들은 'UI 애니메이션'을 보통 더 즐거운 사용자 경험을 만드는 것이라 생각하지만, 전반적으로 어떤 가치를 더하지 않는다. 그러므로 UI 애니메이션은 종종 UX의 의붓자식처럼 다뤄진다(모든 의붓자식들에게 미안하다). If at all, it usually comes at the end, as a final lipstick pass.

추가로 사용자 인터페이스의 문맥에서의 모션은 디즈니의 12 애니메이션 원칙 문제 아래에 이해할 수 있게 잡혀있는데, 내가 쓴 'UI Animation Principles — Disney is Dead'에서 이야기해놓았다.

나의 선언서에는, 구성을 아키텍트화함으로서, UI 애니메이션은 '모션 원칙에서의 12가지 UX'가 된다는 경우로 만들것이다.

이렇게하여, 내가 말하고자하는 바는, 한 구조는 (요구하는 구성이) 존재하기위해 물리적으로 만들어져야하지만, 무엇이 만들어질지를 결정하는 안내는 원칙의 도메인으로부터 나온다.

애니메이션은 모두 도구에관한 것이다. 원칙들은 도구의 사용이나 그런것을 가이드하는 아이디어들의 실제 응용이다. 원칙들은 디자이너에게 높은 사용 기회를 제공한다.

많은 디자인들이 'UI 애니메이션'를 사실 디자인의 더 높은 형식성의 실행이라 생각한다: 실시간과 비실시간 이벤트동안 인터페이스 오브젝트의 시간적인 동작.



실시간 vs 비실시간 인터렉션
이 접점에서, '상태(state)'와 '동작(act)' 사이의 구별이 중요하다. UX에서 무언가의 상태는 근본적으로 정적이다. 마치 디자인 시안처럼 말이다. UX에서 무언가의 동작은 근본적으로 시간적이고 모션 기반이다. 한 오브젝트가 마스크된 상태에 있을 수 있고 혹은 마스크되고있는 동작에 있을 수 있다. 만약 후자이면, 모션이 포함되있고 때에 따라 사용성을 제공할 수도 있다.

추가로 인터렉션의 모든 시간적 양상은 실시간이나 비실시간으로 일어난다고 생각될 수 있다. 실시간은 사용자 인터페이스에서 사용자가 오브젝트와함께 직접 상호소통한다는 의미이다. 비실시간은 오브젝트 동작이 상호소통 이후에 일어난다는 의미이다: 사용자 동작 후에 일어나고 이동된다.



이 구별은 중요하다.

실시간 인터렉션은 '직접 조작'으로 생각할 수 있는데, 사용자는 인터페이스 오브젝트와 직접적으로 그리고 즉시 소통하고있다. 인터페이스의 이 동작은 사용자가 사용하고 있음으로서 일어난다.

비실시간 인터렉션은 사용자가 입력은 넣은 후에만 발생하고, 그 트랜지션이 완료될때까지 가볍게 사용자 경험으로부터 사용자를 락킹시키는 효과를 가진다.

이런 구별법은 모션에서 UX의 12가지 원칙 세계로 떠나는 여행내내 이용하게 될것이다.


모션은 4가지 방법으로 사용성을 제공한다.
이 네가지 기둥은 사용자 경험의 시간적 동작이 사용성을 지원하는 4가지 방법을 표현한다.

예상(Expectation)
예상은 2가지 영역으로 나뉜다. 사용자가 어떤 오브젝트인지 감지하는것, 그리고 어떻게 동작하는지 감지하는것이다. 디자이너로서 말하자면, 우리는 사용자가 기대하는 것과 그들의 경험 사이의 갭을 최소화시키고 싶다.

연속성(Continuity)
연속성은 사용자 흐름에대해서나 사용자 경험의 '일관성' 둘다에 대한 이야기이다. 연속성은 '내부-연속성'(장면내의 연속성 그리고 '내부 연속성')이라는 용어로 생각될 수 있는데, 일련의 장면에 연속성은 전체 사용자 경험을 만든다.

설명적(Narrative)
설명적은 사용자 경험에서 이벤트의 선형적 과정이다. 이것은 시간적/공간적 프레임워크의 결과가된다. 이것은 처음부터 끝까지 사용자 경험을 연결하는 일련의 인지된 순간들이나 이벤트들로 생각할 수 있다.

관계(Relationship)
관계는 사용자의 이해와 선택을 돕는 인터페이스 오브젝트들 사이에서 공간적인, 시간적인, 계층적인 표현이다.


원칙, 기술, 프로퍼티, 값
Tyler Waye says it as good as any when he writes, "원칙...들은 기술의 어떤 수치를 증가시키는 기능의 약속, 규칙을 근간으로한다. 이런 요소들은 조화롭게 있으며, 무슨일이 일어나도 상관없다." 원칙들은 디자인의 어그노스틱(agnostic)이라는 것을 되풀이한다.

거기서부터, 제일 높은 원칙과 그 아래 기술, 그 아래 프로퍼티, 제일 아래에 있는 값으로서 한 계층을 생각해볼 수 있다.

기술은 원칙의 다양한, 제한이없는 실행들 혹은/그리고 조합들이라 생각할 수 있다. 내 생각에 기술은 '스타일'과 유사한것 같다.

프로퍼티는 기술을 만들기위해 애니메이션하게될 특정 오브젝트 파라미터이다. 이것들은 위치(position), 투명도(opacity), 스케일(scale), 로테이션(rotation), 앵커포인트(anchor point), 색깔(color), 선두께(stroke-width), 모양(shape)등을 포함한다(제한이 없다).

은 우리가 '애니메이션'이라 부르는 그것을 만들기위해 매번 다른 실제 수치의 프로퍼티 값이다.

그래서 여기에 들어가기위해(조금 뛰어들어가기위해), 하나의 가상의 UI 애니메이션 참조는 '블러된 글라스' 기술로 엄폐(Obscuration) 원칙을 사용하고있는데, 이 '블러된 글라스' 기술은 블러(Blur)와 투명도(Opacity) 프로퍼티를 25px, 70% 값으로한다고 말할 수 있다.

이제 해보기위한 몇 도구를 가졌다. 그리고 더 중요한것은, 이런 용어의 도구들은 모든 특정 프로토타이핑 툴의 아그노스틱(agnostic)이다.


모션에서 UX의 12가지 원칙들
이징(Easing)과 오프셋(Offset)&딜레이(Delay)는 타이밍(timing)과 연관된다. 페어렌팅(Parenting)은 오브젝트 관계(object relationship)에 연관된다. 값 변경(Value Change), 마스킹(Masking), 오버레이(Overlay), 클로닝(Cloning)은 모두 오브젝트 연속성(object continuity)에 연관된다. 페럴랙스ㄹ(Parallax)는 시간적 계층에 연관된다. 엄폐(Obscuration), 차원(Dimensionality), 돌리(Dolly)&줌(Zoom)은 모두 공간적 연속성에 연관된다.



원칙1: 이징(Easing)
오브젝트 동작은 시간적 이벤트가 발생할때 사용자 예상을따라 일어난다.



이즈(ease)는 시간적 동작이 나오는 모든 인터페이스 오브젝트이다(실시간이든 비실시간인든). 이징은 부드러운 사용자 경험에서 타고난 '자연주의(naturalism)'을 만들고 그렇게되도록 한다. 그리고 사용자가 기대하는대로 오브젝트가 동작할때 연속성의 이해가 만들어진다. 덧붙이자면 디즈니는 이것을‘Slow_In_and_Slow_Out">Slow In and Slow Out’'라 부른다.

 



왼쪽의 예시는 선형적인 모션이고 '나빠' 보인다. 제일 위에 첫번째 예시는 이징된 모션인데 '좋아' 보인다. 위의 세 예시는 정확한 프레임 수와 정확히 동일한 횟수로 시행된다. 오직 이징에서만 다르다.

디자이너는 사용성을 고민하기 때문에, 미학은 제쳐두고 어떤 예시가 더 사용성을 제공하는지 우리 스스로 엄격하게 요구하고 조사해야한다.

내가 여기서 보여주는 경우는 스큐어모피즘의 특정 수치는 이징에 내제되있다. 사용자 기대를 벗어나는 것이 적은 사용성의 인터렉션이 되는점에서 '이징 그라디언트(easing gradient)'를 생각해볼 수 있다. 사용자 기대치를 벗어나는 동작으로인해 사용가능한 상호작용이 적게되는 '이징 그라디언트(easing gradient)'를 생각해볼 수 있다. 적절히 이징된 모션의 경우에, 사용자는 모션 그자체가 고르고 눈에 걸리지않는 경험을 한다. 주의를 분산시키지 않기 때문에 좋은 일이다. 선형 모션은 명확히 보이고 어찌되었든 완료되지 않은것같고, 거슬리고 눈에 걸린다.

이제 나는 여기서 내 스스로를 완전히 반박하고 옳은 예시에대해 이야기 할 것이다. 모션은 고르지 않다. 사실 그렇게 느끼도록 디자인되었다. 우리는 오브젝트가 어떻게 올라가는지 인지한다.다르게 느껴지지만 여전히 선형의 모션 예시보다 더 '알맞게' 느껴진다.

이징을 적용하지만 여전히 사용성이 없는가(Can you employ easing and still have it not support (or worse case undermine) usability?)? 그 대답은 그렇다. 그리고 여러 방법들이 있다. 한 방법은 타이밍이다. 만약 타이밍이 너무 느리거나(Pasquele에서 빌렸다) 너무 빠르면, 예상을 벗어나고 사용자의 주의를 분산시킬 수 있다. 비슷하게, 이징이 브랜드나 전반적인 경험에 잘못된 선상에 놓이면, 예상과 고름에 부정적인 영향을 줄수도 있을 것이다.

여러분에게 열어주고 싶은 것이 무엇이냐하면, 이징된 모션이 될때의 기회이다. 당신이 디자이너로서 프로젝트에서 만들고 구현할 수 있는 사실상 무한한 숫자의 이징이 있다. 이 모든 이징들은 사용자에서 발생하는 그들의 고유 예상 반응을 가진다.

요약하기: 언제 이징을 사용할까? 항상이다.

원칙2: 오프셋&딜레이(Offset&Delay)
새로운 엘리먼트와 화면이 나올때, 오브젝트 관계와 계층을 정의한다.


오프셋&딜레이는 디즈니의 애니메이션 원칙에 영향을 받은 모션 원칙의 두 UX 중 두번째것이다. 이것은 'Follow_Through_and_Overlapping_Action">Follow Through and Overlapping Action'로부터 온 케이스이다.

실행에서는 비슷하지만 목적과 결과에서는 다른, 그 구현에대해 인지하는것이 중요하다.디즈니의 원칙은 '더 시선을끄는 애니메이션'의 결과가 되는 반면, UI 애니메이션 원칙은 더 사용가능한 경험의 결과가 된다.

이 원칙의 효용은, 인터페이스에서 사용자에게 오브젝트의 자연스러움에대해 뭔가 말함으로서, 성공을위한 사용자를 미리 인지시키는 세팅 작업이다. 위의 참조에서 설명적인것은 위 두 오브젝트가 결합되있고 아래 오브젝트는 분리되있다. 아마도 위 두 오브젝트는 상호소통하지않는 이미지와 텍스트일수 있는 반면 하단의 오브젝트는 버튼일 것이다.

사용자가 이 오브젝트가 무엇인지 인지하기 전이라도, 디자이너는 이미 그에게 오브젝트들이 다소 '분리'되있다고 말해왔다. 이것은 매우 강력하다.


위 예시에서, 플롯팅 액션 버튼(FAB)는 세개의 버튼을 포함한 헤더 네비게이션 엘리먼트로 변형된다. 버튼들이 각기 다른 시간에 '오프셋'되기때문에, 그들의 '분리'를 통해 사용성을 제공하게된다. 다르게 말하면, 디자이너는 시간을 사용하여 (사용자가 오브젝트를 인지하기 전일지라도) 오브젝트들이 분리되있음을 말한다. 이것은 사용자에게 말하는 효과를 가지고, 시각적 디자인으로부터 완전히 독립적이며, 인터페이스에서 오브젝트의 자연스러운 부분이다.

어떻게 하는지 보여주기위해 오프셋&딜레이 원칙을 나눈 예시를 보여주겠다.


위의 예시에서는 정적인 시각적 디자인이 우리에게 백그라운드 넘어에 아이콘들이 있다고 말한다. 아이콘들이 각자 서로 분리되고 서로 다른 일을 한다고 어림짐작할 것이다. 그러나 모션은 이것을 부정한다.

시간적으로는, 아이콘이 줄 단위로 묶여서 마치 한 오브젝트인것처럼 동작한다. 그 타이틀들도 마찬가지로 줄 단위로 묶여있어서 한 오브젝트처럼 동작한다. 이 모션은 사용자이 눈으로 본것과 다른 무언가를 말하고 있다. 이 경우에, 우리는 이 오브젝트의 인터페이스상 시간적 동작은 사용성을 제공하지 ㅇ낳고 있다고 말할 수 있다.

원칙3: 페어렌팅(Parenting)
다수의 오브젝트와 상호소통할때 공간적, 시간적 계층의 관계를 만든다.


페어렌팅은 사용자 인터페이스에서 오브젝트에 '관계'를 부여하는 강력한 원칙이다. 위 예시에서는, 상위 혹은 '자식' 오브젝트의 '스케일'과 '포지션' 프로퍼티는 하위 혹은 '부모' 오브젝트의 '포지션' 프로퍼티에 부모역할을 한다.

페어렌팅은 오브젝트 프로퍼티를 다른 오브젝트 프로퍼티에 연결한다. 이것은 사용성을 제공하는 방법으로 오브젝트 관계와 계층을 만든다.

또한 페어렌팅은 자연스러운 오브젝트 관계를 사용자에게 전달하면서 디자이너가 사용자 인터페이스상의 더 나은 동위의 시간적 이벤트를 만들 수 있게 해준다.

스케일, 투명도, 위치, 로테이션, 모양, 색깔, 값등을 포함한 오브젝트 프로퍼티를 재호출한다. 이런 모든 프로퍼티는 사용자 경험에서 시너지스틱한 순간을 만들기위해 다른 프로프터에 연결될 수 있다.

 



위에서 왼쪽 예시에서, 얼굴 엘리먼트의 'y축' 프로퍼티는 둥근 인디케이터 부모의 'x축' 프로퍼티에 자식역할을 한다. 둥근 인디케이터 엘리먼트는 수평 축을 따라 움직일때, 그 '자식' 엘리먼트는 수평과 수직을 따라 움직인다(마스크(또다른 원칙이다)되고 있지만).

이 결과는 동시에 발생하는 계층적인 시간의 설명적 프레임워크이다. 각각의 숫자에서 '얼굴'이 부분적으로 완전히 보이고 보이지 않는다는 점에서 '얼굴'은 일련의 '잠금 장치(lockup)'로 작동한다는 점을 인지하자. 사용자는 이런 고름을 경험하지만 우리는 이 예시에서 미묘한 '사용성 치트'가 있다고 말할 수 있다.

페어렌팅은 '실시간' 인터렉션으로는 최고의 기능을 한다. 상ㅇ자가 직접 인터페이스 오브젝트를 조작하기 때문에, 디자이너는 모션을통해 사용자에게 소통할 수 있다(어떻게 오브젝트들이 연결되있는지, 그들사이에 어떤 관계가 있는지)

페어렌팅은 3가지 형식으로 나타난다: '직접 페어렌팅(direct parenting)' (위에서 본 두 예시), '지연된 페어렌팅(delayed parenting)'과 '역 페어렌팅(inverse parenting)' (아래에서 보이는 것)

 



원칙 4 : 변형(Transformation)
오브젝트 기능이 바뀔때, 설명적 흐름의 지속적인 상태를 만든다.
 


모션 원칙 '변형'에서 UX에대해 이미 많이 알아보았다. 어떤 면에서는, 가장 명확하고 간파하기 쉬운 애니메이션 원칙이다.

변형은 보면 가장 알기 쉽고, 가장 눈에띄게 보인다. 'submit' 버튼의 모양이 원형의 프로그래스 바로 바뀌고 결국 확인 체크 표시의 모양으로 돌아오는 것은 우리가 인지하는 것이다. 이것은 시선을 잡아주고, 이야기를 말하며, 완료시킨다.


트렌스포메이션이 하는 일은, 다른 UX 상태나 '이다(is)'(이것은 버튼이다, 이것은 원형 프로그래스 바이다, 이것은 체크 표시이다)를 통해 사용자를 균일하게 트렌지션하여 결국 원하는 결과를 만들어낸다(원문: What Transformation does is seamlessly transition the user through the different UX states or ‘is’s’ (as in this is a button, this is a radial progress bar, this is a check mark) which eventually result in a desired outcome). 사용자는 이 기능적인 공간을 통해 최종 목적지로 이끌린다.

변형은 사용자 경험에서 고르게, 연속적인 이벤트로 핵심 순간들을 나누는 효과를 가진다. 이 고름은 더 나은 사용자 인지, 기억, 완수의 결과가 된다.

원칙 5: 값 변경
값 주체가 바뀔때, 동적이고 연속적인 설명적 관계를 만든다.


텍스트 기반 인터페이스 오브젝트(숫자나 글자를 표현하는)는 그 값을 바꿀 수 있다. 이것은 '정의하기 어려운 명확한(elusive obvious)' 개념중 하나이다.

텍스트와 숫자의 변경은 매우 일반적이어서 유용성을 지원할 때 자신의 역할을 평가할 수있는 구별과 엄격함을 제공하지 않으면서도 이를 통과시킨다.

그래서 값이 바뀔대 사용자 경험이 무엇일까? 사용저 경험에서는 모션 원칙에서 12가지 UX가 사용성을 제공하는 기회들이다. 여기 세가지 기회는 데이터 뒤의 현실성에이젠시 개념, 그리고 값 그자체의 동적인 자연스러움을 위해 사용자를 열결시키는 것이다.

아래 사용자 데시보드 예시를 보자.

 


값 기반 인터페이스 오브젝트가 '값 변경' 없이 불러오면 사용자에게 숫자가 정적인 오브젝트라는 것을 전달하게 된다. 이것은 시속 55마일 속도 제한을 표시하는 표지판과 비슷하다.

숫자와 값은 현실에서 일어나는 것들의 표현이다. 현실은 시간, 수입, 게임 스코어, 사업 메트릭스, 건강 추적 등일 수 있다. 모션을 통해 구별해야하는것은 '겂 주체'는 동적이고 값은 동적인 값 설정으로부터 무언가를 반영한다.

이 관계는 시각적인 값으로 구성된 정적 오브젝트로 인해 손실될뿐만 아니라 더 깊은 기회도 잃는다.

모션 기반 값에서 동적 시스템의 표현을 채택했으면, '뉴로피드백'같은 것을 활성화시킨다. 그 데이터의 동적인 자연스러움을 잡고있는 사용자들은 이제 값을 변경할 수 있게 되고 에이전트가 될 수 있게 한다. 값이 정적이면 값 뒤에 현실에 더 적게 연결되고 사용자는 에이전시를 잃는다.

  


값변경 원칙은 실시간 이벤트 비실시간 이벤트 둘 다로 나타날 수 있다. 실시간 이벤트에서는 사용자가 값 변경을 위해 오브젝트와 상호소통한다. 불러올때나 트렌지션같은 비실시간 이벤트에서는 동적인 설명을 반영하기위해 사용자 입력 없이 값을 변경한다.

원칙 6: 마스킹(Masking)
오브젝트나 그룹의 어떤 부분에의해 결정되는 기능이 나타나거나 숨겨질때, 한 인터페이스 오브젝트나 오브젝트 그룹에 연속성을 만든다.


이 마스킹  요청은 오브젝트의 모양간의 관계와 그 기능으로 생각할 수 있다.

디자이너들이 정적 디자인의 문맥에서 '마스킹'에 친숙하기때문에, 시간내 상태로서가 아닌 동작으로서 발생하는 모션 원칙 '마스킹'에서의 UX를 구별하는 것이 필요하다.

오브젝트의 범위를 드러내고 숨기는 시간적 용도를 통해, 기능은 연속적으로 고른 방법으로 트랜지션된다. 또한 설명적 흐름을 보존하는 효과도 가진다.


위 예시는, 헤더 이미지의 바운딩 모양과 포지션을 변경하지만 컨텐트는 변경하지 않은체 앨범이 된다. 마스크로 컨텐트롤 보존하면서, 이것은 그 오브젝트가 무엇인지 변경하는 효과를 가진다(꽤 멋진 기술로). 이것은 트랜지션이라 비실시간으로 일어나고, 사용자 액션을 받고 난 뒤에 활성화된다.

UI 애니메이션 원칙들은 시간적으로 일어나고, 연속성, 설명적, 관계, 예상을통해 사용성을 제공한다는 점을 기억하자. 위 참고자료에서 오브젝트 자체가 바뀌지 않은채로 남아있는 동안, 바운더리와 위치를 가지고 있고, 이 두가지 요인은 이게 어떤 오브젝트인지 결정한다.

원칙 7: 오버레이
층의 오브젝트가 종속된 위치일때, 설명적인 것과 시각적 2차원에서 오브젝트의 공간적 관계를 만든다.


오버레이는 비공간적 계층의 부재를 극복하기위해 사용자에게 2차원의 순서있는 프로퍼티들을 이용하게 함으로서, 사용성을 제공한다.

오버레이는3차원 공간이 아닌 곳에서, 다른 오브젝트보다 뒤나 앞에 있는 위치가 종속된 오브젝트들을 소통하기위해 디자이너들은 모션을 사용할 수 있다.

 


왼쪽의 예시는. 뒷편에 위치한 추가적인 오브젝트를 드러내기위해 앞편의 오브젝트를 오른쪽으로 민다. 오른편의 예시는, 추가적인 컨텐트와 옵션을 드러내기위해 전체 화면을 아래로 민다(각 사진 오브젝트를 소통하기위해 오프셋&딜레이 원칙을 사용하면서).

약간은 디자이너로서 레이어' 방법은 자명할 정도로 매우 명확하다. 우리는 레이어로 디자인하고 레이어 개념은 깊게 내재되있다. 그러나 '만드는것'과 '사용하는것'의 과정은 조심해서 구별해야한다.

계속해서 '만드는' 과정에 끌려가버린 디자이너로서, 우리가 만든 모든 오브젝트 부분들에 충분히 친숙하다. 그러나 사용자로서 눈에 보이지 않는 부분은 시각적으로나 인지적으로 숨겨진 정의와 동작에 의한 것입니다.

오버레이 원칙은 디자이너들에게 'z축' 위치의 레이어 사이에 관계를 통해, 사용자에게 공간적 방향을 개선한다.

원칙 8: 클로닝(Cloning)
새 오브젝트가 시작하고 출발할때, 연속성, 관계, 설명을 만든다.


새 오브젝트가 현재 화면에서 (혹은 현재 오브젝트로부터) 만들어질때, 그 출현에대해 설명적으로 알려주는 것은 중요하다. 이 선언서에서 나는 오브젝트 시작과 출발을위한 설명적 프레임워크를 만드는것이 강력하게 중요하다고 주장한다. 간단하게 투명도 조절은 이런 결과를 달성할 수 없다. 강력한 설명을 만들기위해 마스킹, 클로닝, 차원은 사용성 기반 세가지 접근법이다.

  


위 세가지 예시에서는, 사용자가 이 오브젝트에 집중하고 있는 시간동안 히어로 오브젝트로부터 새 오브젝트를 만든다. 접고 펼치는 위 두가지 예시의 접근법(주의를 잡고, 클론된 새 오브젝트의 생성을 통해 눈을 끈다)은 이벤트를 명확하고 모호하지않게 연결하여 소통하는 강한 효과를 가진다: 액션 'x'는 새 자식 오브젝트의 생성 'y'의 결과를 가진다.


원칙 9: 엄폐(Obscuration)
사용자에게 주요 시각 계층이 아닌 오브젝트나 화면에 관계에서 공간적으로 그 자체를 익숙하게 해준다.


모션 원칙의 마스킹과 비슷한데, 엄폐는 정적 현상과 시간적 현상 둘다에 존재한다.

시간적인 생각을 경험하지 못한 디자이너에게는 혼란스러울 수 있다(이것은 순간 사이의 순간이다). 보통 디자이너들은 화면대 화면을 디자인하거나 작업대 작업을 디자인한다. 엄폐라는것을 엄폐된 상태가 아니라 엄폐되는 동작이라고 생각하자. 정적인 디자인은 엄폐된 상태를 표현한다. 시간을 도입하여 엄폐되고있는 오브젝트의 동작을 만들어준다.

 


위의 두 예시에서, 엄폐를 볼 수 있는데, 투명한 오브젝트나 오버레이처럼 보인다. 또한 시간내 여러 프로퍼티를 포함하는 시간적 인터렉션이다.

여기서의 여러 일반적인 기술에는 블러 효과와 전체 오브젝트 약한 투명성(lessoning of overall object transparency)을 가진다. 사용자는 그가 동작하고있는 곳에 추가적으로 주요하지 않는 문맥을 알게 되었다(그 주요 오브젝트 계층 '뒷편에' 또다른 세계가 있다).

엄폐는 사용자 경험에서 뷰나 '목표 뷰'를 하나로 만들기위해 디자이너들이 보완할 수 있게 해준다.

원칙 10: 페럴랙스(Parallax)
사용자가 스크롤 할때, 시각적 2차원에서 공간적 계층을 만든다.


'페럴랙스'는 모션 원칙에서 한 UX로서 다른 비율로 움직이는 다른 인터페이스 오브젝트를 표현한다.

'페럴랙스'는 디자인 완결을 유지하면서 동시에 사용자를 주요 액션과 컨텐트에 집중하게 해준다. 페럴랙스 이벤트동안 사용자는 뒷편의 엘리먼트들은 뒤로 들어가있는 지각과 인식을 준다. 디자이너는 배경이나 도움을주는 컨텐트로부터 직접적인 컨텐트를 분리해낼 수 있게 페렐랙스를 사용할 수 있다.

 


사용자에게 있는 이 효과는 인터렉션의 지속시간, 다양한 오브젝트 관계를 명확하게 정의하는 것이다, 앞쪽의 오브젝트, 혹은 사용자에게 '가까히' 나타나서 '빠르게' 움직이는 오브젝트이다. 비슷하게, 뒷쪽의 오브젝트, 혹은 '멀리 있다'고 인지되어 '천천히' 움직이는 오브젝트이다.

디자이너는 이런 관계를 만들 수 있는데, 시간 자체를 사용하여 인터페이스에서 어떤 오브젝트가 높은 우선순위를 갖는지 사용자에게 알려준다. 따라서 뒷편에 밀어넣거나 상호소통하지 않는 오브젝트를 더 '뒤로'하여 이해할 수 있다.

시각적 디자인에서 어떤것이 결정되었는지를 넘어, 사용자들이 이제 인터페이스 오브젝트가 계층을 가진다고 인지할 뿐만 아니라, 이 계층은 이제 그 디자인/컨텐트를 의식하기 전에 자연스러운 사용자 경험을 사용자가 가지는데에 이용할 수 있다.

원칙 11: 차원(Diemnsionality)
새 오브젝트가 시작되거나 출발할때, 공간적 설명의 프레임워크를 제공한다.


사용자 경험에 중요한 점은 위치의 이해만큼 연속성의 현상이다.

차원은 2차원의 비논리적 사용자 경험을 극복하는 강력한 방법을 제공한다.

인간은 실제 세상과 디지털 경험 둘다 설명을 위해 공간적 프레임워크 사용에 두드러지게 적응된다. 공간적 시작이나 출발의 레퍼런스를 제공하면 사용자가있는 UX의 정신적 모델을 증진하는데 도움이 된다.

또한 Dimensionality Principle은 깊이가없는 객체가 같은 평면에 존재하지만 다른 객체의 '앞에 또는'뒤에 존재하는 시각적 인 평지의 계층적 역설을 뛰어넘는다.

차원은 세가지 방법으로 표현된다. 오리가미 차원(Origami Dimenstionality), 플롯팅 차원(Floating Dimenstionality), 오브젝트 차원(Object Dimenstionality).

오리가미 차원은 '접는' 혹은 '매딜린' 셈차원 인터페이스 오브젝트의 용어라 생각할 수 있다.

 


여러 오브젝트들이 '오르가미' 구조로 결합되기 때문에, 숨겨진 오브젝트들은 공간적으로 보이지 않더라도 아직 '존재한다'고 말할 수 있다. 이것은 효과적으로 사용자 경험을 랜더링하는데, 인터렉션 모델 자체에서나 인터페이스 오브젝트 그 자체의 시간적 동작에서 둘 다 사용자가 작업의 문맥을 이야기하고 만든다.

플롯팅 차원은 인터페이스 오브젝트에게 공간적 시작/출발을 제공하여, 직관적이고 매우 설명적인 인터렉션 모델을 만든다.


위 예시에서, 차원은 3D '카드' 사용을 통해 달성되었다. 이것은 시각적 디자인을 제공하는 강력한 설명적 프레임워크를 제공한다. 이 설명은 추가적인 컨텐트와 상호활동에 접근하기위해 카드를 '가볍게 튀기면서(flipping)' 연장된다. 차원은 갑작스러움을 최소화하는 방법으로 새 엘리먼트를 소개하는 강력한 방법일 수 있따.

오브젝트 차원은 실제 깊이와 양식으로 차원적인 오브젝트가 된다.

 


여기에는, 실제 공간적인 오브젝트를 형성하기위해 3D 공간에 여러 2D 레이어가 정렬되있다. 그들의 차원은 실시간과 비실시간 트랜지션의 순간에 드러난다. 오브젝트 차원의 이 기능은 사용자가 보이지 않는 공간 위치에 기반한 오브젝트 기능의 예리한 인지를 전개하는 것이다.

원칙 12: 돌리(Dolly)&줌(Zoom)
인터페이스 오브젝트와 공간이 이동할때, 연속성과 공간적 설명을 보존한다.


돌리와 줌은 영화에서의 개념인데, 카메라에 관련된 오브젝트의 이동이나 먼 샷에서 가까운 샷으로(혹은 그 반대도) 부드럽게 변하는 프레임에서 이미지 그자체의 크기와 관련된 오브젝트 이동을 의미한다.

특정 문맥에서, 3D 공간에서 카메라를 향해 이동하거나 3D공간에서 카메라가 오브젝트를 향해 카메라가 이동한다면, 오브젝트가 줌되는지 말하기는 불가능하다(아래 참조를 보자). 아래 세가지 예시는 가능한 시나리오를 설명한다.


'돌리'와 '줌'은 둘 다 연속적인 엘리먼트와 씬상의 변형을 포함함하고 모션 원칙에서 모션을 통해 사용성을 제공한다는 UX의 요구사항을 맞춘다는 점에는 비슷하지만, '돌리'와 '줌'의 인스턴스를 분리해서 다루는것이 적절하다.

  


돌리는 영화 용어인데, 물체를 향해 가거나/멀어지는 카메라 이동에 적용된다(또한 수평적 '추적의' 이동에 적용하는데, 사용성 문맥에는 적게 관련된다).


UX에서 공간적으로, 이 모션은 사용자의 시점에서의 변화이거나 오브젝트가 위치를 변경하면서 남아있는 고정되어있는 시점을 의미한다. 돌리 원칙은 연속성과 설명을 통해 사용성을 제공하고, 인터페이스 오브젝트들과 목적지간의 고른 트랜지션을 한다. 돌리는 차원 원칙과 통합하여 더 공간적인 경험과 더 깊이감의 결과를 만들고, 사용자에게 현재 뷰의 '앞'/'뒤'에 추가적인 영역이나 컨텐트를 알려준다.

줌은 시점이나 오브젝트가 공간적으로 이동하는것이 아닌 곳의 이벤트를 의미하지만, 오브젝트 자체가 스케일되는것이다(혹은 이것의 우리 뷰가 작아져서 확대된 이미지가 된다). 이것은 보는이에게 다른 오브젝트나 화면 안에 추가적인 인터페이스 오브젝트를 알려준다.


 고른 트랜지션(실시간, 비실시간 둘 다)으로 사용성을 제공한다. 돌리&줌 원칙에서 나온 고름은 공간의 정신적 모델을 생성하게될때 꽤 강력하다.



이 긴 것을 완주했다면, 축하한다! 야생의 선언서였다. 모든 gif들이 로딩되서 여러분의 브라우저를 죽이지 않았길 바란다. 또한 여러분 스스로를 위한 어떤 가치와 새로운 도구를 얻었길 바라며 여러분의 인터렉티브 프로젝트에 사용되길 바란다.

사용성을 제공하기위한 디자인 툴로서 어떻게 모션 사용을 시작할 수 있는지에대해 좀 더 배우길 바란다.

다시, 마지막 플러그로, 모션과 사용성에관한 주제에관해 학회나 워크샵에서 야러분의 팀위한 나의 강연을 원한다면, 여기로 가봐라. 여러분의 도시에서 수업에 참석하고 싶으면, 여기로 가보아라. 마지막으로 여러분의 프로젝트에대해 컨설팅을 받고 싶으면, 여기로 가면 된다.내 리스트에 추가되려면 여기로 가면 된다.



이 선언서는 아마존의 Kateryna Sitner의 끊임없는 피드백과 관대하고 인내심있는 기여가 없었다면 가능하지 않았을 것이다. 감사합니다! 브레인스토밍과 I land the plane하는 주장에 Alex Chang, 매의 눈을 가진 마이크로소프트의 Bryan Mamaril, 편집 노트의 Jeremey Hansom, 놀라운 UI 모션 지도자가 된 Eric Braff, 몇년간 나를 믿고 따라온 Artefact의 Rob Girling, 애프터 이펙트 학회에서 UI 모션에대한 영감을 주는 Matt Silverman, 멋진 룸메이트이자 UI에 영감을 주는 Bradley Munkowitz, 모션에서 놀라운 글을 쓰는 Pasquale D’Silva, UI 안무(Choreography)에대한 멋진 글의 Rebecca Ussai Henderson, UI와 모션에관한 주제에 멋진 기여를 하는 Adrian Zumbrunnen, 나의 지능적 형재로 항상 나의 수준을 올려주는 Wayne GreenfieldChristian Brodin, 그리고 영감의 gif들을 만들어내고있는 수천의 UI 애니메이터들에게 특별 감사를 전한다.



이 블로그는 공부하고 공유하는 목적으로 운영되고 있습니다. 번역글에대한 피드백은 언제나 환영이며, 좋은글 추천도 함께 받고 있습니다. 피드백은 

으로 보내주시면 됩니다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

프로그래밍 패러다임 관점에서나 탄생 이유의 관점에서나 리액티브(Reactive)를 이해하기 위해서는 현재 개발자와 회사가 직면한 문제들과 10년전의 문제를 비교하여 생각해보아야한다.

개발자와 회사에 바뀐 두가지는 아래와 같다.
  • 하드웨어의 발전
  • 인터넷

"모닥불 주위에 모여 옛날일을 이야기하는 것"은 일부에의해 대화의 수준이 낮아질 수 있음으로 고려해야하는 반면, 우리는 모든 개발자가 직면한 문제를 고심하기 위해 직종의 역사를 탐구해볼 필요가 있다.

왜 이것들이 이제 달라졌을까
10년간 컴퓨팅 연구 끝에 발견한 의미있는 지식이 하나 있다. 리액티브 프로그래밍은 소프트웨어의 새 세대를 만들기 위한 시도이다.

1999년
1999년, 내가 캐나다 임패리얼 상업은행에 있고 처음 자바를 배우기 시작할 무렵이다.
  • 인터넷은 2.8억 유저에 달성했다.
  • JSEe는 여전히 썬(Sun MicroSystems)사의 꿈으로서 가슴속에 있는 상태였다.
  • 온라인 뱅킹이 5년정도 된 유아기 시점이었다.
1999년으로 돌아가면 나는 동시성에 대한 문제에 직면하고 있었다. 그 해결책은 스레드와 락(lock)에 관련이 있었으며, 유경험자의 개발자까지도 그 문제를 해결하기 힘들어하는 상황이었다. 자바의 특징은 "한번 작성하면, 어디서든 실행할 수 있다"인데, 여기서 "어디서든"은 JVM이 설치되어있는 OS에 한에서 "어디에든"이지, 클라우드나 IoT 세대를 위해 설계한 다른 동시접속의 개념이 아니다.

2005년
2005년이 오래전은 아니지만 컴퓨팅쪽과 인터넷쪽이 크게 바뀌었다. J2EE, SOA, XML이 인기를 끌었고 루비온레일즈가 J2EE의 고통받는 컨테이너 기반 개발 문제를 해결하기 위해 탄생하였다.

이때의 인테넷에는
  • 1억유저가 있었다.
  • 페이스북이 550만 유저를 가지고 있었다.
  • 유튜브가 탄생했다.(2005년 2월)
  • 트위터가 아직 없었다.(2006년)
  • Netflix가 비디오 스트리밍을 소개했다.(2007년)

2014년
이 글을 쓰고 있는 시점인 2014년은 Internet Live Stats에 의하면 약 2,950,000,000(29억 5천만)정도의 인터넷 유저가 있다고 한다. 중국이 혼자서 6억 4천만 인터넷 유저를 보유하고 미국이 2억 8천만을 보유하고 있었다.

오늘날 가장 인기있는 웹사이트이다.
  • 페이스북—13억 유저
  • 트위터—2억 7천 유저

시간이 흐르면서 한 웹사이트의 트래픽이 지난 20년전의 인터넷 전체 트래픽보다 많다.

1999년부터 2015년까지 인터넷, 페이스북, 트위터 유저 수1999년부터 2015년까지 인터넷, 페이스북, 트위터 유저 수



우리는 점점 확장과 예측에 관한 이슈가 중요해지고, 우리의 삶에서의 소프트웨어가 중요해짐을 쉽게 확인할 수 있다. 또한 과거의 패러다임이 현재까지 이어질 수는 없을 것이고, 분명 미래까지도 이어지기 힘들 것이다.

4가지 리액티브 요소
리액티브 앱은 4가지 요소로 구성되있다.

  • 반응성(responsive)있는 앱이 그 목표이다.
  • 반응성있는 앱은 확장가능(scalable)하고 탄력(resilient)있다. 반응성은 확장성과 탄력성 없이 불가능하다.
  • 메시지-주도(message-driven) 구조는 확장가능함과 탄력있음을 근간으로 하고 궁극적으로 반응성있는 시스템을 기반으로 한다.

반응성(Responsive)
"앱이 반응성 있다"는 것이 어떤 의미일까?

반응성있는 시스템은 시종일관으로 분명한 유저 경험을 보장하기위해 좋은 상황이나 나쁜  상황이나 상관없이 모든 유저에게 즉각 반응하도록 하는 것이다.

외부 시스템의 실패나 트래픽 급증과 같은 다양한 상황에서의 재빠른 처리분명한 사용자 경험탄력성확장성이라는 두 성질에 의존한다. 메시지-주도 구조는 반응성 있는 시스템을 위한 전반적인 근간을 제공해준다.

왜 반응성 있는 것이 메시지-주도 구조에 중요할까?

세상은 비동기적이다. 당신이 한 포트의 커피를 끓이는데 크림과 설탕이 없음을 깨닭았을때의 그 예시가 있다.

아래는 그 한가지 방법이다.
  • 한 포트의 커피를 끓이기 시작한다.
  • 커피가 끓는동안 가게에 간다.
  • 크림과 설탕을 산다.
  • 집으로 돌아온다.
  • 즉시 커피를 마신다.
  • 여유를 즐기면 된다.

또 다른 방법이다.
  • 가게에 간다.
  • 크림과 설탕을 산다.
  • 집으로 돌아온다.
  • 커피를 끓을 때까지 시계를 보면서 기다린다.
  • 카페인 금단현상을 겪는다.
  • 젠장

여러분이 볼 수 있듯, 메시지-주도 구조는 당신을 시공간으로부터 분리된 비동기 바운더리를 가능하게한다. 우리는 남은 이 포스트에서 비동기적 바운더리 개념에 대해 이야기해볼 것이다.

왈마트 캐나다(Wlamart Canada)에서의 일관성
Typesafe에 들어가기 전에, 나는 왈바트 캐나다의 플랫폼을 만든 Play and Scala 팀의 기술 리더였다.

우리의 목표는 분명한 사용자 경험의 일관성을 만드는 것이었다. 다음 것들에 관계없이 말이다.
  • 데스크탑, 테블릿, 모바일 기기등 어떤 기기에서도 walmart.ca를 서핑할 수 있다.
  • 현재 피크 트래픽이 튀어오르든 유지되든 관계없어야 한다.
  • 전체 데이터 센터의 손실과 같이 주요 기능이 실패해도 관계없어야 한다.

응답 시관과 전반적인 사용자 경험은 위 시나리오와 관계없이 일관성있다. 일관성은 당신의 웹사이트를 전달하는데 근본적으로 중요하며 오늘날 웹사이트는 당신의 브렌드임을 생각해야한다. 좋지않은 사용자 경험은 실제 상점이 아니라 온라인에서 일어나기 때문에 쉽게 잊어지거나 무시되지 않는다.

Glit에서의 반응성있는 소매(retail)
전자상거래 도매인에서의 일관성은 우연에의해 일어나지 않는다. Glit의 경우, 매일 저녁에 하루 세일을 공지하는데, 그 때 트래픽이 급증하는 플래시 스케일 사이트이다. 플래시 스케일 사이트의 사용자 경험에대해 이야기해보자. 만약 당신이 오전 11:58에 한번 Glit를 접속하고 오후 12:01에 한번 더 접속한다면 Glit는 일관성있게 정해진 응답 경험을 제공하고 이것을 리액티브를 사용하여 시행하였다. 스칼라 기반의 마이크로 서비스 구조로 마이그래이션한 Glit를 더 배우고 싶다면 interview with Eric Bowman of Gilt 여기를 보아라.

탄력있는(Resilient)
많은 앱들이 이상적 환경만을 고려하면서 설계, 개발하지만 사실 이상적이지 않을때도 많다. 이것은 매일 주요앱 기능이 실패하는 다른 보고서를 받거나, 해커에의해 서비스 멈춤, 데이터 손실, 지속적인 손상을 초례하는 다른 co-ordinated breach 시스템이 있을 수 있다.

탄력있는 시스템은 이상적이지 않는 상황에서도 반응성을 보장하기 때문에 바람직한 설계 요소와 구조 요소를 사용한다.

자바와  JVM은 다중 OS에서 한 앱을 문제없이 실행시키는 것에 대한 것이었다면, 201x년대의 상호연결된 앱은 앱단의 구성, 연결성, 보안성에 대한 것이다.

이제 한 앱은 웹사이트나 다른 네트워크 규약을 통해 통홥되어 여러 앱으로 구성되어있다. 오늘날 하나의 앱은 신뢰된 방화벽을 가진 바깥은 외부 서비스들에(10개, 20개, 혹은 더 많이) 의존하며 만든다.

이 복잡한 통합을 고려하면 얼마나 많은 개발자가 필요할까?

  • 모든 외부 의존성을 분석하고 모델링하는 사람
  • 통합된 각 서비스의 이상적인 응답 시간을 문서로 만들고 피크일때나 아닐때 모두 퍼포먼스 테스트가 초창기 기대와 일치하는지 확인하기위해 관리하는 사람
  • 모든 퍼포먼스, 실패, 핵심앱 로직으로 포함되는 다른 비기능적인 요구사항을 문서화하는 사람
  • 각 서비스의 모든 실패 시나리오를 다시 분석하고 테스트하는 사람
  • 외부 의존성의 보안성을 분석하고, 외부 시스템과 통합했을때 새로운 취약점이 있는지 알아내는 사람

탄력성은 가장 정교한 앱의 가장 약한 연결 중 하나이지만, 추가적으로 탄력있어야하는 것은 곧 끝난다.(원문: Resiliency is one of the weakest links of even the most sophisticated application, but resiliency as an afterthought will soon end.) 현대의 앱들은 이상적인 상황 보다는 다양한 현실세계에서 반응성을 유지해야하기 때문에, 앱의 핵심(core)이 반드시 탄력적이어야한다. 퍼포먼스, 내구성, 보안성은 모든 면에서 말이다. 여러분의 앱은 단지 몇 부분이 아닌 모든 부분에 걸쳐 탄력적이어야한다.

메시지-주도 탄력성
메시지-주도 핵심에서 가장 아름다운 제작방법은 여러분이 자연스럽게 작업에 필요한 것들을 한조각 한조각 얻어내는 것이다.

고립(Isolation)은 시스템의 자체 회복을 위해 필요하다. 잘 고립되있을때, 우리는 실패의 위험이나 퍼포먼스 특징, CPU와 메모리 사용 등과 같은 요인에 기반하여 여러 타입으로 나눌 수 있다.

정확한 위치는 마치 같은 VM에서 동작하게 한 것 처럼 서로다른 노드위에서 서로다른 프로세스들이 상호소통할 수 있게 해준다.

특정 목적용 에러 채널은 단지 에러 신호를 호출자에게 던저버리는게 아니라 다른 우리가 원하는 곳으로 보낼 수 있다. 

이러한 사실은 우리 앱에서 확고하게 에러 핸들링을 구체화하고 결함에 내성을 만들어준다. 이것은 아카의 감독 계층(Akka's supervisor hierarchies)처럼 구현함으로서 입증되었다.

조각(block)을 만드는 핵심은 이상적인 환경 뿐만 아니라 좋지않은 환경에서도 메시지-주도 구조가 탄력성에 기여하는 것에의해 제공하고 다음으로 반응성에 기여한다.

44억 달러의 탄력성 실수
2012년에 를 생각해보자. 소프트웨어가 향상되는동안 통합된 앱 방식은 점점 인기있고(fired up) 거래 규모가 점점 커지기 시작했다.

다음은 45분동안 일어나는 악몽같은 시나리오였다.

Knight의 자동교환 시스템이 잘못 거래하여 나스닥(NASDAQ)을 침수시켰고, 10억달러가치를 의도치않은 회사에 놓았다. 이러한 사고는 다시 반환(reverse)하는데 회사에 44억달러의 비용이 들게 되었다. 나스닥이 침수되고 거래의 범람을 고치는 동안 나스닥은 Knight 돕는 것을 중단했다. Knight의 주식은 하루만에 63%나 떨어졌으며 그들은 가까스로 살아남았고, 일부를 회복한 후에 투자자에의해 다음 인계를하고 살아갈 수 있었다. 

그때 Knight의 시스템은 동작했었지만 탄력성이 없었다. 탄력성이 없는 Knight 시스템은 문제를 확장시키는데 한 몫을 하였다. Knight는 최악의 버그가 발생했을때 그들의 시스템을 끌 수 있는 스위치(kill-switch) 매커니즘도 없는 상태였으므로, 나쁜 환경에서 그들의 자동 거래시스템이 45분만에 회사의 모든 주요 자산을 고갈시켜버린 것이다.

이것은 이상적인 환경을 위한 설계 정의이자 개발 정의였다. 이제 소프트웨어는 우리 개인 삶이나 회사에서 핵심 요소이다. 예측되지 못한 나쁜 상황의 시나리오 된다면 굉장히 많은 비용을 감당해야할 수 있다.

확장가능한(Scalable)
일관성있는 반응성 앱을 만들때 탄력성과 확장성을 잘 이용해야한다.

확장 가능한 시스템은 다양한 요구량의 상황(various load conditions)에서도 반응성을 보장하기 때문에 그에 맞춰 쉽게 업그레이드 시킬 수 있다.

온라인에서 물건을 팔아본 사람이라면 물건을 최대로 많이 팔때 가장 큰 트래픽이 생긴다는 사실을 알 것이다. 대부분의 경우(사이버상 공격을 제외하고) 트래픽이 폭발하는 것은 당신이 뭔가 잘하고 있을 때이다. 트래픽이 치솟았을대 사람들은 당신에게 돈을 주고 싶어하고 있는 것이다.

그럼 어떻게 치솟는(혹은 꾸준히 증가하는) 트래픽을 다룰까?

첫째로 당신의 패러다임을 먼저 고른다. 둘째로 그 패러다임을 구현할 수 있는 언어와 툴킷을 정한다. 많은 개발자가 종종 너무 가볍게 언어와 프레임워크를 선택한다. 한번 툴을 선택하면 그것을 다시 바꾸기 쉽지 않으므로 당신은 주요 투자가와 함께 그 결정을 내려야한다. 만약 여러분이 기술적인 선택 결정을 원칙과 분석에 기반하여 하고 있었다면 굉장히 잘하고 있는 것이다.

동시성을 위한 스레드-기반 제한
기술적인 선택에서 가장 중요한 것중 하나는 동시성 모델 프레임워크이다. 고수준에서 두개의 서로다른 동시성 모델이 있을 수 있다.
  • 전통적인 스레드-기반 동시성으로 콜스택과 공유 메모리를 기반으로 한다.
  • 메시지-주도 동시성

레일즈와같은 몇 인기있는 MVC 프레임워크는 스레드 기반이다. 이 프레임워크의 전형적인 특징은 아래와 같다.
  • 공유 가변 상태(Shared mutable state)
  • 요청당 한 스래드(A thread per request)
  • 가변 상태에 동시 접근(Concurrent access to mutable state)—이것(변수나 객체 인스턴스)은 또다른 복잡한 동기화 방법이나 락(lock)으로 관리한다.

루비와 같은 인터프리트 언어로 다이나믹 타입의 특징을 합치면 여러분은 쉽게 퍼포먼스와 확장성의 상한선에 도달할 수 있을 것이다( Combine those traits with a dynamically typed, interpreted language like Ruby and you can quickly reach the upper bounds of performance and scalability). 이것이 어떠한 스크립트 언어라도 그 본질은 같다고 말할 수 있을 것이다.

Out 혹은 Up?
앱 확장을 좀 다른 방법으로 생각해보자.

스케일업(Scale up)은 단일 CPU/서버의 리소스를 최대화 하는 것인데, 파워풀하고 희귀하고 값비싼 그런 컴퓨터를 종종 사야한다.

스케일아웃(Scale out)은 여러 저렴한 하드웨어를 연결하여 컴퓨테이션을 제공하는 것인데, 비용면에서 효과적이다. 그러나 당신의 시스템이 시공간 개념에 기반하였다면 매우 어려울지도 모르겠다. 위에서도 이야기했듯 메시지-주도 구조는 시공간으로부터 분리하기위해 필요한 비동기 바운더리를 제공하며, 필요에따라 스케일아웃 할 수 있는 유연성(elasticity)을 제공한다. 반면 스케일업은 이미 가지고있는 자원의 효율을 높히는 것이고, 유연성은 당신의 시스템이 바뀌기 원하는대로 새 자원을 추가할 수 있음에 관한 것이다. 필요에따라 스케일아웃 할 수 있는 능력은 리액티브 앱의 궁극적인 확장성의 목표이다.

공유 가변 상태, 스레드, 락 기반의 앱을 스케일아웃하는게 어렵기 때문에 리액티브 앱들을 스레드 기반으로 만드는것은 어려운 일이다. 개발자들은 한 머신에서 멀티 코어의 이점을 활용해야 할 뿐만 아니라, 특정 시점의 개발자들은 머신의 클러스터를 활용해야 한다. 그게 불가능할지라도, 공유 가변 상태 또한 스케일업하기 어렵게 만든다. 한번이라도 두개의 스레드에서 공유 가변 상태를 다뤄본 사람이라면, 스레드 세이프를 보장하는 과정이 얼마나 어려운지, 스레드 세이프를 위해 과한 작업을 하게되는 실적 패널티가 얼마나 큰지 이해할 수 있을 것이다.

메시지-주도(Message-driven)
메시지-주도 구조는 리액티브 앱의 근간이다. 메시지 주도 앱은 이벤트 주도 이거나 행위자 기반일 것이고, 혹은 이 둘 모두를 합친 것일 것이다.

이벤트 주도 시스템은 0개 혹은 그 이상의 Observer에의해 관찰된 이벤트 기반이다. 이것은 명령형 프로그래밍과는 좀 다른데, 호출자가 부른 루틴으로부터 응답을 블락된 상태로 기다릴 필요가 없기 때문이다. 이벤트는 바로 특정 장소를 지정하는게 아니라 나중에 일어날 어떤 결과를 지켜보고 있는 것이다.

행위자-기반 동시성은 메시지-전달 아키텍처의 확장이며 메시지는 수신자에게 전달된다. 메시지는 스레드 경계를 넘거나 실제 다른 서버의 다른 행위자의 메일함으로 전달 될 수 있다. 행위자가 네트워크를 통해 배포 될 수 있지만 여전히 동일한 JVM을 공유하는 것처럼 서로 통신 할 수 있으므로 요구에 맞게 스케일-아웃 할 수 있다.

메시지와 이벤트의 차이점은 메시지는 전송되는 것이고 이벤트는 일어나는 것이다. 메시지는 명확한 도착지가 있지만 이벤트는 0혹은 그 이상(0-N)의 Observer에의해 관찰되고 있을 것이다.

이벤트-주도와 행위자-기반 동시성에 대해 좀 더 세부적으로 들어가보자.

이벤트-주도 동시성
일반적인 앱들은 명령형 스타일(오퍼레이션 순서)로 개발되고 콜스택을 기반으로 개발한다. 콜스택의 주 기능은 프로세스에서 호출자가 블럭되고 리턴값과 한께 호출자에게 컨트롤을 돌려주는 동안, 주어진 루틴에서 호출자를 계속 쫓고, 호출된 루틴을 실행하는 것이다.

겉으로 보았을 땐 이벤트 주도 앱이 콜스택에 맞추는게 아니라 이벤트 트리거에 맞춘다. 이벤트는 0개 혹은 그 이상의 Observer에의해 지켜보고 있는 큐에 메시지로 인코딩 되어 있을 것이다. 명령형 스타일과 비교하여 이벤트-주도의 큰 차이점은 응답을 기다리는 동안 호출자가 한 스레드 위에서 블락되거나 멈추지 않는다. 이벤트 루프 자체는 단일 스레드 일 수 있지만, (단일 스레드 이기도 한)스레드 된 이벤트 루프가 들어오는 요청을 처리 할 수 있도록 허용하면서 호출 된 루틴이 업무를 수행하는 동안 (잠재적으로 IO 자체를 차단하면서) 동시성은 여전히 달성된다. 프로세스가 완전히 끝나지 않는한 요청을 블락시키는 대신에 호출자의 id가 요청 메시지의 바디와 함께 전달되므로 깨어있는 루틴이 이것을 선택하면 호출자는 응답과 함께 콜백될 수 있다. 

이벤트 주도 구조를 선택하는 이유는 콜백지옥(링크)이라는 것에 괴로워할 수 있기 때문이다. 콜백지옥은 메시지를 받는 놈이 정해져 있는 것이 아니라 익명의 콜백이기 때문에 발생한다. 콜백지옥을 해결하는 일반적인 방법은 이러한 문제가 생기는 이유를 잊고 코드에 표현된 이벤트 순서대로 디버깅하기 어려운것도 생각하지 않으면서 온전히 구문(aka, the Pyramid of Doom) 형태에만 초점을 맞춘다.

행위자-기반 동시성
행위자-기반 앱은 여러 행위자 사이에서 비동기 메시지를 보낸다.

행위자는 아래 속성들을 갖는다.
  • 메시지를 받기 위한 메일 박스
  • 각 타입별로 메시지를 어떻게 받는지 결정하기 위해 패턴매칭의 행위자 로직
  • 요청 사이에 컨텍스트를 저장하기 위한 고립된 상태
이벤트-주도 동시성처럼 행위자 기반 동시성에서는 콜스택은 피하고 가벼운 메시지 전달을 지향한다. 행위자는 메시지를 밖으로든 자기자신에게든 보낼 수 있다. 한 행위자는 그 큐의 첫번째 요청을 먼저 제공한 뒤에 처리가 긴 요청을 처리하기 위해 메시지를 자기자신에게 보낼 수도 있다. 행위자-기반 동시성의 큰 장점은 이벤트-주도 구조에서 얻은 장점을 얻을 수 있다는 점이다. 네트워크 경계를 통해 컴퓨테이션을 스케일-아웃하기도 쉽고, 행위자에게 직접 메시지를 전해주기 때문에 콜백 지옥을 피할 수도 있다. 이러한 강력한 컨셉은 설계, 구현, 유지보수하기 쉬우면서 확장성이 있는 앱을 만들 수 있게 해준다. 시공간에대해 생각하거나 깊게 감쌓인 콜백들에대해 생각하는것보다, 행위자 사이에 메시지 흐름이 어떻게 되는지만 고민하는게 더 낫다.

또 다른 주요 장점은 요소들끼리 느슨하게 연결된다는 점이다. 호출자는 응답을 기다리기 위해 스레드를 멈추지 않으므로 빨리 다른 일을 할 수 있다. 호출자에의해 켭슐화되있는 현재 루틴은 필요에따라 호출자를 다시 호출하면 된다. 이것은 다양한 가능성을 열어준다. 콜백 스택이 한 메모리 공간에 있기 위해 앱을 묶어버리지 않으며 행위자 모델은 프로그래밍적인 일보다 구성에 관련된 일을 추상화하여 만듦으로 여러 머신을 통해 루틴을 분배할 수 있다.

Akka는 행위자-주도 툴킷이고 타입 세이프 리액티브 플랫폼의 일부로서 JVM에서 높은 동시성, 분배, 실패에 대한 내성을 가진 행위자-기반 앱을 만들기 위한 런타임이다. Akka는 탄력을 위한 관리계층이나 확장성을 위한 일 분배와 같은 리액티브 앱 개발에 필요한 멋진 기능들을 탑재하고 있다. Akka에대해 더 깊게 보고싶으면 Let it Crash blog를 확인해보길 바란다.

또한 이 세션 일부의 자료로 사용된 Benjamin Erb’s Diploma Thesis의 글(Concurrent Programming for Scalable Web Architectures)을 읽어보기를 강력 추천한다.

결론
위의 모든 것들이 오늘날 앱 개발에 흠집을 내고, 왜 리액티브 프로그래밍이 단지 또다른 트렌드가 아닌지 이야기하며, 그러나 왜 현대 소프트웨어 개발자들이 배워야하는 패러다임인지도 이야기했다. 여러분이 선택하는 언어나 툴킷에 관계없이 반응성을 얻기위해 확장성과 탄력성 또한 탑재하는 것이 사용자의 기대를 충족시키는 유일한 방법이다. 이것은 몇년간 더욱 중요하게 떠오를 것이다.

저자에대해
Kevin Webber는 Lightbend에서 Enterprise Advocate이다. 그는 heritage 구조에서 리액티브 프로그래밍 원칙을 포괄하는 실시간 분배 시스템까지 큰 구조의 트랜지션을 돕는 것에 열정적이다. 남는 시간에 ReactiveTOProgramming Book Club Toronto를 운영한다. 그는 가끔 제 3자에서 자기 자신에 대해 글을 쓰기도 하는데, 이 단락이 그러한 순간이다. 


'그 외' 카테고리의 다른 글

(번역)Android Architecture  (0) 2016.10.01

WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

내 이름은 Eugene Obrezkov이고 오늘 나는 NodeJS라는 무시무시한 플랫폼에대해 이야기 해보려고 한다. "NodeJS는 어떻게 동작하는가?"라는 아주 복잡한 질문에 대한 답을 해나갈 것이다.

나는 마치 NodeJS가 존재하지 않는다고 생각하고 글을 써내려 갈 것이다. 이렇게하면 그 내부가 어떻게 동작하는지 이해하기 쉬워진다.

여기서 사용한 코드는 실제 NodeJS에서 발췌한 코드이며 이 글을 읽고나면 NodeJS에대해 더 편안합을 느낄 수 있을 것이다.


이렇게 하려면 무엇이 필요한가?
위 이야기를 보면 막상 "이렇게 하려면 무엇이 필요한가?"라는 질문이 먼저 떠오를 것이다.

Vyacheslav Egorov는 이렇게 말했다: "JS VM은 자바스크립트 소스를 0과 1로 만드는 미지의 블랙박스라 생각하고, 더 많은 사람들이 그것을 그만 들여다본다." 이 발상은 NodeJS에도 적용시켜보았다. "NodeJS는 저수준 API를 돌아가게 해주는 미지의 블랙박스라 생각하고, 더 많은 사람들이 그것을 그만 들여다본다."

그냥 해보자!
2009년으로 돌아가면 NodeJS가 만들어지기 시작하는 시점이다.

우리는 백엔드에서 자바스크립트를 실행시키고 싶었고, 자바스크립트가 저수준 API에 접근하고 싶었다. 또한 우리의 자바스크립트를 CLI와 REPL로부터 실행시키고 싶었다. 사실 자바스크립트로 뭐든 다 하고싶었던 것이다!

이게 어떻게 가능할까? 내 머릿속에 처음 드는 생각은 브라우저였다.

브라우저
브라우저는 자바스크립트를 실행시킬 수 있다. 따라서 브라우저를 우리 앱에 합쳐 자바스크립트를 동작시키게 할까?

설마! 아래에 반드시 답해야할 질문들을 보자.

브라우저가 저수준 API를 자바스크립트로 만들까? — 아니다!
다른 곳에서 자바스크립트를 돌릴 수 있을까? — 반반이다. 좀 더 복잡한 이야기이다.
브라우저가 제공하는 모든 DOM 기능이 필요할까? — 아니다!
브라우저가 조금이라도 필요할까? — 아니다!

브라우저는 필요 없다. 자바스크립트는 브라우저 없이 실행된다.

그럼 브라우저가 자바스크립트를 실행시키는게 아니라면 무엇이 자바스크립트를 실행할까?

가상머신(Virtual Machine-VM)
가상머신(VM)이 자바스크립트를 실행한다!

VM은 고수준 프로그래밍 언어라는 추상화를 제공한다.(시스템의 저수분 ISA 추상화와 비교해보아라)

VM은 추상화이고 플랫폼에 독립적인 프로그램 실행환경을 만들기 위해 단일 컴퓨터에서 동작하도록 설계되었다.

가상머신에는 Google의 V8, 마이크로소프트의 Chakra, 모질라의 SpiderMonkey, Apple의 JavaScriptCore 등 수많은 것들이 있다. 여기서 신중하게 고르지 않으면 남은 인생동안 분명 후회하며 살 것이다.

나는 V8을 선택하려 한다. 왜일까? 그 이유는 다른 VM보다 더 빠르기 때문이다. 당신도 아마 백엔드에서 실행속도는 중요하다는 것에 동의할 것이다.

이제 V8을 살펴보면서 이것이 NodeJS 구성에 어떤 도움을 줄 수 있는지 살펴보자.

V8 VM
V8은 어떤 C++ 프로젝트와도 합칠 수 있다. 단지 간단한 라이브러리처럼 V8 소스를 거기에 인클루드(include)시키면 된다. 이렇게만 하면 이제 자바스크립트 코드를 컴파일하고 실행할 수 있다.

V8은 C++을 자바스크립트에서 사용할 수 있게 해준다. 자바스크립트로 저수준 API를 사용할 수 있게 해주는 중요한 역할을 한다.

위 두가지 포인트가 "어떻게 자바스크립트로 저수준 API에 접근할 수 있는지"에대한 대략적인 구현을 생각해볼 수 있을것이다.

다음 챕터부터는 C++ 코드로 설명을 시작할 것이기 때문에 위의 것들을 한데모아 생각해보자. 가상머신을 선택하고(우리의 경우 V8을 선택했다) -> 우리 C++ 프로젝트에 그것을 통합시킨뒤 -> V8이 C++을 자바스크립트로 사용할 수 있게 한다.

그러나 어떻게 C++코드로 작성하고 그것이 자바스크립트에서 가능할까?

V8 템플릿
V8 템플릿들을 통해 가능하다!

한 템플릿은 자바스크립트에서의 함수와 객체를 위한 청사진이다. C++ 함수와 데이터 구조체를 자바스크립트로 감싸기 위해 템플릿을 사용한다.

예를 들어보자. 구글 크롬은 C++ DOM 노드를 자바스크립트 객체로 감싸고 전역에 함수를 만들어 두기 위해 템플릿을 사용한다.

여러분도 템플릿들을 만들어 그것을 사용할 수 있다. 따라서 당신이 원하는 만큼 템플릿을 만들면 된다.

그리고 V8은 두가지 타입의 템플릿을 가지고 있다: 함수 템플릿(Function Templates)객체 템플릿(Object Templates)이다.

함수 템플릿은 한 함수의 청사진이다. 당신이 자바스크립트 함수로 만들고 싶은 컨텍스트에서 템플릿의 GetFunction 메소드를 호출하여 자바스크립트 인스턴스의 템플릿을 만들어 낼 수 있다. 자바스크립트 함수 인스턴스가 호출될 때 함수 템플릿이 호출되는데, 이 함수 템플릿과 C++ 콜백을 연관시킬 수도 있다.

객체 템플릿은 객체 초기화에서 함수 템플릿과 함께 만들어진 객체를 구성하는데 익숙하다. 객체 템플릿은 두가지 C++콜백 타입과 연관이 가능하다: 접근자 콜백(accessor callback)인터셉터 콜백(intercepter callback). 접근자 콜백은 특정 객체 프로퍼티가 스크립트에의해 접근될 때 호출된다. 인터럽트 콜백은 어떤 객체 프로퍼티라도 스크립트가 접근하면 호출된다. 즉 C++ 객체/구조체를 자바스크립트 객체로 감쌀 수 있다.

간단한 예제를 살펴보자. 이것은 C++ 메소드인 LogCallback을 전역 자바스크립트 컨텍스트에서 사용하는 것이다.

두번째 라인에서 새 ObjectTemplate를 생성한다. 그리고 3번째 라인에 FunctionTemplate를 생성하고 그것을 LogCallback이라는 C++ 메소드와 연관시킨다. 그 다음 이 FunctionTemplateObjectTemplate에 세팅한다. 새 컨텍스트에서 자바스크립트를 실행시킬때 전역에서 log 메소드를 사용하도록 이 새로운 컨텍스트에 ObjectTemplate 인스턴스를 보낸다. 결과적으로 FunctionTemplate 인스턴스와 연관된 LogCallback C++ 메소드가 트리거 될 것이다.(As a result, C++ method, associated with our FunctionTemplate instance, LogCallback, will be triggered.)

여러분도 보았듯 C++에서는 자바스크립트에서 객체를 정의하는 것과 비슷하다.

그러나 이제 C++ 메소드를 어떻게 자바스크립트에 드러낼 것인지 배울 것이다. 방금처럼 수정된 컨텍스트에서 어떻게 자바스크립트 코드를 실행시키는지 살펴볼 것이다. 사실 단순하다. 그냥 요소를 컴파일하고 실행시키자.

V8 컴파일 && 자바스크립트 실행
우리가 만든 컨텍스트에서 자바스크립트를 실행하려면 V8에 컴파일(compile)과 실행(run)의 간단한 API만 호출하면 된다.

새 컨텍스트를 만들면서 자바스크립트를 실행시키는 이 예제를 살펴보자.

2번째줄을 보면 새로운 자바스크립트 컨텍스트를 만들었다(위에서 설명한 템플릿들과 함께 수정할 수 있다). 5번째줄은 자바스크립트 코드를 컴파일하고 실행하기 위해 컨텍스트를 활성화 시킨다. 8번째줄은 자바스크립트 소스로부터 새 문자열을 생성한다. 위처럼 하드코딩 할 수도 있고 파일을 읽거나 다른 방법으로도 가능하다. 11번째줄은 우리의 자바스크립트 소스를 컴파일한다. 14번째줄은 실제 실행시켜보고 결과를 기다린다. 이게 다다.

마침내 위에서 말한 테크닉들을 조합하여 우리는 간단한 NodeJS를 만들 수 있다.

C++ -> V8템플릿 -> 자바스크립트를 실행 -> ?
V8 머신을 만든다 -> 원하는 만큼 C++ 콜백과 연관된 FunctionTemplate를 만든다 -> ObjectTemplate 인스턴스를 만들고 그것에 만들어놓은 FunctionTemplate 인스턴스를 할당한다 -> 우리의 ObjectTemplate 인스턴스를 전역 객체로 한 자바스크립트 컨텍스트를 만든다 -> 이 컨텍스트에서 자바스크립트를 실행한다 -> NodeJS. 여기까지이다!

그러나 챕터 타이틀에 물음표부분의 "자바스크립트를 실행" 이후에는 무엇이 올까? 위 구현에는 약간의 문제가 있다. 굉장히 중요한 점을 하나 지나쳤다.

fs, http, crypto등과 함께 동작하는 수많은 C++ 메소드(약 10K SLOC)를 작성했다고 생각해보자. 우리는 [C++ 콜백들]을 ObjectTemplate에 할당하고 [FunctionTemplate]를 ObjectTemplate에 불러온다. 이 ObjectTemplate 자바스크립트 인스턴스를 쓰면 자바스크립트 전역에서 모든 FunctionTemplate 인스턴스에 접근할 수 있게 된다. 그리고 모든 것이 잘 동작하는 것처럼 보일 것이나..

당장에 fs이 필요없다면? crypto의 모든 기능이 필요 없다면? 전역에 모듈을 죄다 불러오지 않고 그들이 요구하는 것만 불러준다면 어떨까? 모든 C++ 콜백이 한 파일에 긴 C++ 코드를 작성하지 않는 것은 어떨까? 그래서 위 타이틀에서 "?"의 의미는..

모듈화이다!

각 C++ 모듈이 각 fs, http 나 다른 기능에 일치하기 때문에 이 모든 C++ 메소드는 모듈로 쪼개지고 각 다른 파일에 위치한다.(이 점이 개발을 쉽게 만들어준다) 자바스크립트 컨텍스트도 같은 로직이다. 전역에서 반드시 모든 자바스크립트 모듈에 접근할 수 있는게 아니라 요구에 따라 접근이 가능하다.

위의 방법을 기반으로 우리만의 모듈로더(module loader)를 구현해야 한다. C++ 코드에서 요구하는 데로 모듈을 가져오고 자바스크립트 컨텍스트도 마찬가지로 그러기 위해 모듈로더는 C++ 모듈과 자바스크립트 모듈을 불러오는 역할을 한다.

먼저 C++ 모듈부터 시작해보자.

C++ 모듈로더
이제 좀 많은 C++코드가 있을텐데, 마음 단단히 먹고 시작해보자 :)

모든 모듈로더의 기초부터 이야기 해보자면, 각 모듈 로더는 모든 모듈(혹은 그것을 어떻게 얻어내는지에대한 정보)을 담고 있는 변수를 반드시 가지고 있어야한다. C++ 모듈에 대한 정보를 가지고 있는 C++ 구조체를 정의하고 이 이름을 node_module이라 하자.

우리는 이 구조체 안에 현재 존재하는 모듈에 대한 정보를 담았다. 결과적으로 사용가능한 모든 C++ 모듈의 딕셔너리를 가진다.

위 구조체의 각 필드를 다 설명하진 않겠지만, 그중 몇개만 이야기 하고 싶다. nm_file에서는 어디서부터 그 모듈을 불러오는지 파일 이름을 저장하고 있다. nm_register_func와 nm_context_register_func에는 모듈이 필요할 때 호출하는 함수들을 담고있다. 이 함수들은 Template 인스턴스로 만들어질 것이다. 그리고 nm_modulename은 모듈 이름을 저장한다 (파일 이름이 아니다) .

다음으로 이 구조체를 도와주는 helper 메소드들이 필요하다. 우리 node_module 구조체에 정보를 저장할 수 있는 간단한 메소드를 만든 뒤 우리의 모듈 정의에서 이 메소드를 사용할 수 있다. 이것을 node_module_register라 부르자.

위에서 보이듯 여기서 하는 일이라곤 모듈 정보를 node_module 구조체에 저장하는 일 뿐이다.

이제 메크로를 이용해 이 과정을 간단하게 만들 수 있다. 당신의 C++ 모듈 안에 메크로를 정의하자. 이 메크로는 단지 node_module_register 메소드를 감싸는 용도이다.

첫번째 메크로는 node_module_register 메소드를 감싸는 메크로이다. 다른 하나는 첫번째 메크로에 미리 정의된 인자를 박아둔 메크로이다. 결론적으로 modnameregfunc라는 두 인자를 받는 메크로가 완성되었다. 이 메크로를 호출하면 새 모듈 정보를 우리의 node_module 구조체에 저장한다. 그럼 modnameregfunc는 무엇일까? 음.. modnamefs처럼 모듈의 이름을 뜻한다. regfunc는 이전에도 우리가 이야기한 모듈 메소드이다. 이 메소드는 V8 Template 초기화와 ObjectTemplate에 이것을 할당하는 역할을 한다.

앞에서 보았듯 각각의 C++ 모듈은 모듈 이름(modname)과 초기화 함수(regfunc)를 인자로 받는 메크로로 정의할 수 있는데, 이 메크로는 모듈이 필요할 때 호출되는 것이다. 우리에게 필요한 것은 단지 node_module  구조체로부터 정보를 읽고 regfunc 메소드를 호출할 수 있는 C++ 메소드를 만드는 것이다.

node_module 구조체에서 이름으로 모듈을 검색할 수 있는 간단한 메소드를 만들어보자. 이 메소드를 get_builtin_module이라 부를 것이다.

이 메소드는 nm_modnamenode_module 구조체의 이름이 일치하면 앞서 정의된 모듈을 반환한다.

node_module 구조체의 정보를 기반으로 C++ 모듈을 불러오고 우리의 ObjectTemplate에 V8 Template 인스턴스를 할당하는 간단한 메소드를 만들 수 있다. 그러면 이 ObjectTemplate는 자바스크립트 인스턴스에 따라 자바스크립트 컨텍스트에 보내질 것이다.

위 코드에 관해 몇가지 짚고 넘어가자면, Binding은 모듈 이름을 인자로 받는다. 이 인자는 당신이 메크로를 통해 주는 모듈 이름이다. 그리고 우리는 get_builtin_module 메소드에서 나온 이 모듈에 관한 정보를 찾아온다. 만약 찾으면 exports와 같은 유용한 인자들을 보내면서 이 모듈의 초기화 함수를 호출한다. exportsObjectTemplate 인스턴스이므로 exports에서 V8 Template API를 사용할 수 있다. 이 모든 동작이 끝나고 Binding ㅁ[소드의 결과물로 나온 exports 객체를 받는다. 여러분이 기억하는데로 ObjectTemplate 인스턴스는 자바스크립트 인스턴스와 Binding이 한 것을 반환할 수 있다.

마지막으로 해야할 것은 이 메소드를 자바스크립트 컨텍스트에서 사용할 수 있게 하는 것이다. 이것은 마지막 라인이 하는 일인데, FunctionTemplate에서 Binding 메소드를 감싸고 전역변수 process에 할당하는 일을 한다.

이 단계에서 process.binding('fs')를 호출하여 네이티브 바인딩을 할 수 있다.

단순함을 위해 로직을 뺀, 내장된 모듈의 예시이다.


위 코드는 process.binding('V8')를 호출하여 자바스크립트 컨텍스트로부터 이 자바스크립트 객체를 얻어내려고 자바스크립트 객체를 내보내는 "V8"이라는 바인딩을 만든다.

고맙게도 여러분들은 아직 잘 따라오고 있다.

이제 우리는 require('fs')와같이 깔끔하게 되도록 도와주는 자바스크립트 모듈 로더를 만들 것이다.

자바스크립트 모듈로더
좋다. 마지막 개선(improvements)에 감사하다. 우리는 process.binding()을 호출하고 자바스크립트 컨텍스트로부터 C++ 바인딩에 접근할 수 있게 되었다. 그러나 아직 자바스크립트 모듈에 관한 이슈는 해결된 바가 없다. 어떻게 자바스크립트 모듈을 작성하고 필요할 때 그것을 require 할 수 있을까?

먼저 모듈에는 두가지 타입이 있음을 이해해야한다. 그 중 하나는 C++ 콜백과 함께 작성된 자바스크립트 모듈이고 NodeJS에 내장된 fs, http 등과 같은 모듈들이다. 이 모듈을 NativeModule이라 부르자. 다른 모듈은 여러분이 작업하는 디렉토리 안에 있는 모듈이다. 이것을 그냥 Module이라 하자.

우리는 두가지 타입 모두 require 할 수 있어야한다. 이 말은 NodeJS로부터 NativeModule을 부르는 법과 작업 디렉토리에서 Module을 부르는 법을 알아야한다는 뜻이다.

NativeModule부터 먼저 이야기해보자.

자바스크립트에 있는 모든 NativeModule은 C++ 프로젝트로 다른 폴더에 위치한다. 이 말은 모든 자바스크립트 소스가 컴파일 시간을 가진다는 뜻이다. 이렇게하여 우리가 나중에 사용할 자바스크립트 소스를 C++ 헤더파일에 감싸 넣을 수 있게 한다.

이것을 위한 js2c.py(tools/js2c.py에 위치한)이라는 파이썬 툴이 있다. 이것은 자바스크립트 코드로 감싸진 node_natives.h 헤더파일을 생성한다. node_natives.h는 C++에서 자바스크립트 소스를 얻어내는 어떠한 C++ 코드에서도 포함될 수 있다.

이제 C++ 컨텍스트에서 자바스크립트 소스를 사용할 수 있다. — 한번 시도해보자. node_natives.h에서 자바스크립트 소스를 가져오고 그것을 ObjectTemplate 인스턴스에 할당하는 DefineJavaScript 메소드를 구현했다.

위 코드에서, 우리는 각 네이티브 자바스크립트 모듈들을 통해 돌면서 ObjectTemplate 인스턴스에 키로서 모듈이름을, 값으로서 모듈 자체를 넣었다. 마지막으로 우리가 할 일은 타겟으로 ObjectTemplate 인스턴스와 함께 DefineJavaScript를 호출하는 것이다.

이때 Binding 메소드가 유용하다. C++의 Binding 구현(C++ 모듈로더 부분)을 보면 하드코딩된 constantsnatives라는 두 바인딩이 있을 것이다. 그러므로 바인딩 이름이 natives이면 environmentexports 객체가 DefineJavaScript 메소드와 함께 호출될 것이다. 결과적으로 자바스크립트 NativeModuleprocess.binding('natives')가 호출될 때 반환될 것이다.

그래 좋다. 그러나 node.gyp 파일에서 GYP 작업을 정의하고 이것으로부터 js2c.py 툴을 호출하여 또다른 개선을 할 수 있다. 이것은 NodeJS가 컴파일 될 때 자바스크립트  소스가 node_natives.h 헤더파일로 감싸지기 때문에 이 개선을 만들 것이다.

이제부터 우리는 process.binding('natives')로 사용할 수 있는 NativeModule의 자바스크립트 소스들을 가지고 있을 수 있다. 이제 NativeModule을 위한 간단한 자바스크립트 껍데기를 만들어보자.

이제 모듈을 불러오기 위해 NativeModule.require() 안에 모듈 이름을 넣어 호출한다. 먼저 모듈이 이미 캐시에 있는지 확인한다. 있으면 캐시에서 꺼네오고 그렇지 않으면 모듈을 컴파일하고 캐시에 넣은 뒤 exports 객체로 반환한다.

이제 좀 더 아까이서 cachecompile 메소드를 살펴보자.

cache가 하는 일은 NativeModule에 위치한 스태틱 객체 _cacheNativeModule 인스턴스를 세팅한다.

compile 메소드가 더 흥미롭다. 먼저 (process.bind('natives')로 세팅해둔 이 스태틱 프로퍼티)_source에서 필요한 모듈의 소스를 꺼낸다. 그리고 wrap 메소드로 그 소스를 감싼다. 위 소스에서 볼 수 있듯 함수의 결과물은 exports, require, module, __filename, __dirname 인자를 받는다. 그 후 필요한 인자와 함께 이것을 호출한다. 결과적으로 NativeModule.exports를 가리키는 exports, NativeModule.require를 가리키는 requireNativeModule 그 자체를 가리키는 module, 현재 파일 이름의 문자열인 __filename을 가지는 영역에서 우리 자바스크립트 모듈이 감싸진다. 이제 여러분은 module이나 require이 자바스크립트 코드 어디에서부터 오는지 안다. 그것들은 단지 NativeModule 인스턴스를 가리키고 있다. 😃

다른 하나는 Module 로더 구현이다.

Module 로더의 구현은 기본적으로 NativeModule과 같다. 그러나 다른 점은 소스가 node_natives.h 헤더파일로부터 오는 것이 아니라 우리가 fs 네이티브 모듈이라 부르는 파일로부터 온다. 따라서 wrap, cache, compile 하는 일은 같지만 파일로부터 읽는 소스만 다르다.

좋다, 이제 우리는 어떻게 네이티브 모듈이나 여러분의 작업 디렉토리로부터 모듈을 요청하는지 안다.

마지막으로, 우리는 위의 일들을 사용하여 만든 NodeJS 환경을 실행(run)하고 준비(prepare)할 때 마다 실행되는 간단한 자바스크립트 모듈을 작성할 수 있다.

NodeJS 런타임 라이브러리?
런타임 라이브러리가 무엇일까? 이 라이브러리는 전역변수인 process, console, Buffer등을 세팅하여 코딩할 수 있는 환경을 갖추고, NodeJS CLI에 인자로 보내는 메인 스크립트를 실행한다. 이 라이브러리는 NodeJS 런타임시 모든 자바스크립트 코드가 실행되기 전에 실행되는 간단한 자바스크립트 파일로 아키브(achieve)될 수 있다.

첫번째 단계로는 전역에 모든 네이티브 모듈을 프록싱(proxying)하고 다른 전역 변수를 설정하는 것이다. 이 일은 단지 global.Buffer = NativeModule.require('buffer')global.process = process와 같은 일들이다.

두번째 단계는 NodeJS CLI에 인자로 보내는 메인 스크립트를 실행한다. 로직은 간단하다. process.argv[1]를 파싱하여 그 값을 객체 초기화때 값으로 Module 인스턴스를 생성한다. 따라서 Module은 파일로부터 소스를 읽을 수 있고 -> NativeModule이 했던 것처럼 미리 컴파일된 자바스크립트 소스로 캐시와 컴파일 해 둘 수 있다.

여기에 내가 더 추가할 수 있는게 없다. 굉장히 매우 간단하며, 만약 그대로 더 세부적인 것을 원한다면 노드 저장소의 src/node.js 파일을 한번 확인해보아라. 이 파일은 NodeJS 런타임시 실행되고 이 글에서 말한 모든 테크닉을 사용한다.

이것이 바로 NodeJS가 어떻게 당신의 자바스크립트 코드에서 저수분 API에 접근하며 실행하는지에관한 이야기였다. 멋지지 않는가?

하지만 아직 비동기 처리에대한 문제가 남았다. 여기서는 fs.readFile()같은 연산은 완전히 순차적으로 실행된다.

비동기 처리를 위해 어떤 것이 필요할까? 이벤트 루프이다.

이벤트 루프
이벤트 루프는 프로그램 내에서 이벤트나 메시지를 기다리고 디스패치(dispatch)하는 메시지 디스패처이다. 이것은 내부/외부 이벤트 프로바이더(보통 이벤트가 도착하기 전까지 요청을 블락시키는 것)에 요청을 만듦으로서 작업한다. 그리고 적절한 이벤트 핸들러를 호출한다(이벤트를 디스패처 한다). 선택되거나 채택될 수 있는 파일 인터페이스를 따르는 이벤트 프로바이더라면, 이벤트 루프는 리엑터(reactor)와 협력하여 사용할 수 있다. 이벤트 루프는 항상 메시지 제공자와 함께 비동기로 처리한다.

V8 환경을 생성하면 V8은 인자로 이벤트 루프를 받을 수 있다. 그러나 V8에 이벤트 루프를 세팅하기 전에 먼저 그것을 구현해놓아야한다.

이제 libuv라 불리는 그 구현을 이미 가지고 있다치자. libuv는 파일 읽기와 같은 모든 비동기 처리의 책임을 가지고 있다. libuv가 없는 NodeJS는 단지 순차적으로 자바스크립트/C++를 실행할 수 있는 도구일 뿐이다.

따라서 기본적으로 NodeJS에 libuv 소스를 인클루드 할 수 있고, 거기에 있는 libuv 기본 이벤트 루프와 함께 V8 환경을 만들 수 있다. 여기에 그 구현이 있다.

CreateEnviroment 메소드는 루프 인자로 libuv 이벤트 루프를 받는다. 우리는 V8 네임스페이스에서 Enviroment::New를 호출할 수 있고 libuv 이벤트 루프를 보낸 다음 V8 환경으로 구성할 수 있다. 여기까지가 NodeJS를 어떻게 비동기 처리 할 수 있는지에 관한 이야기였다.

libuv에대해 더 이야기하고 어떻게 동작하는지 말해주고 싶지만, 이 이야기는 다음으로 미루도록 하자. :)

Thanks!
이 글을 끝까지 읽어준 모든이에게 감사하다. 여러분이 여기까지 읽으면서 뭔가 즐겁게 배웠기를 바란다. 만약 뭔가 문제를 발견한다면 자유롭게 이 글에 커멘트해주면 된다. 그러면 가능한 빨리 내가 답변해주도록 하겠다.(옮긴이: 자유롭게 이 블로그에 댓글 달아주시면 됩니다!)

Eugene Obrezkov aka ghaiklor, Technical Leader at Onix-Systems, Kirovohrad, Ukraine.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

안드로이드 프로젝트에서 MVC, MVP, MVVM을 위한 간략한 가이드

Model View Controller(MVC)
MVC 디자인 패턴은 세가지 양상으로 앱을 쪼갠다: Model, View, Controller. 일들을 강제로 분리시켜 도메인 model과 controller 로직을 유저 인터페이스(View)로부터 분리시켜준다. 결과적으로 앱을 유지보수하기 간편하고 테스트하기 쉽게 만들어준다.

Model
Model은 비즈니스 로직(즉 비즈니스 Model)과 데이터 접근 기능(Data Model)을 담은 클래스들의 집합으로 표현한다. 또한 데이터가 어떻게 바뀌고 다뤄지는지에대한 비즈니스 규칙을 정의한다.

View
View는 UI 컴포넌트를 표현한다. View는 Controller로부터 받은 결과의 데이터를 화면에 표시하는 역할만을 가지고 있다. 또한 Model을 UI에 넣어 적용하는 일도 한다.

Controller
Controller는 들어온 요청을 처리하는 역할을 한다. Vie를 통해 사용자의 입력을 받으면 Model의 도움으로 사용자의 데이터를 처리하고 다시 그 결과를 View에 보내준다. 보통은 View와 Model 사이에 중재자 역할을 한다.

Model View Presenter(MVP)
이 패턴은 Controller 대신 Presenter가 들어간 MVC와 유사한 형태의 패턴이다. 이 디자인 패턴은 세가지 주 양상으로 앱을 쪼갠다: Model, View, Presenter


Model
Model은 비즈니스 로직(즉 비즈니스 Model)과 데이터 접근 기능(Data Model)을 담은 클래스들의 집합으로 표현한다. 또한 데이터가 어떻게 바뀌고 다뤄지는지에대한 비즈니스 규칙을 정의한다.

View
View는 UI 컴포넌트를 표현한다. View는 Controller로부터 받은 결과의 데이터를 화면에 표시하는 역할만을 가지고 있다. 또한 Model을 UI에 넣어 적용하는 일도 한다.

Presenter
Presenter는 View의 도움으로 모든 UI 이벤트를 다루는 역할이다. view를 통해 사용자로부터  입력을 받고, Model의 도움으로 사용자의 데이터를 처리한 뒤, 다시 View에 결과물을 돌려준다. View와 Controller에서와는 다르게 View와 Presenter는 서로 완전히 분리되있고 인터페이스에의해 서로 소통하는 방식이다.
또한 Presenter는 Controller처럼 들어오는 요청 트래픽을 관리하지 않는다.

MVP 패턴의 요점
  • 사용자는 View에서 상호작용한다.
  • View와 Presenter는 one-to-one 관계를 가진다. 이 의미는 하나의 View는 하나의 Presenter에 맵핑된다.
  • View는 Presenter에 참조하고 있지만, Model에는 참조하지 않는다.
  • View와 Presenter 사이에 두 방향으로 소통할 수 있다.

Model View ViewModel(MVVM)
MVVM은 Model-View-ViewModel로 정의된다. 이 패턴은 View와 ViewModel 사이에서 두방향 데이터 바인딩을 지원한다. 이것은 ViewModel에서 View에게 자동으로 변화를 전달할 수 있다. 일반적으로 ViewModel에서 View로 변화를 알림받는 옵저서 패턴을 사용한다.


Model
Model은 비즈니스 로직(즉 비즈니스 Model)과 데이터 접근 기능(Data Model)을 담은 클래스들의 집합으로 표현한다. 또한 데이터가 어떻게 바뀌고 다뤄지는지에대한 비즈니스 규칙을 정의한다.

View
View는 UI 컴포넌트를 표현한다. View는 Controller로부터 받은 결과의 데이터를 화면에 표시하는 역할만을 가지고 있다. 또한 Model을 UI에 넣어 적용하는 일도 한다.

ViewModel
ViewModel은 View의 상태를 유지, View의 액션 결과로 Model을 다루기, View 자체에서 이벤트를 트리거하는 그런 메소드나 명령, 다른 프로퍼티들을 노출시키는 역할을 한다.

MVVM 패턴의 요점
  • 사용자는 View에서 상호작용한다.
  • View와 ViewModel은 many-to-one 관계를 가진다. 그 의미는 여러 View는 하나의 ViewModel에 맴핑될 수 있다.
  • View는 ViewModel에 참조되지만 ViewModel은 View에대해 모른다.
  • View와 ViewModel의 사이에 두방향 데이터 바인딩을 제공한다.

안드로이드 구현




앞으로 "Controller"라는 용어를 앞에서 말한 Controller, Presenter, ViewModel과 같은 의미로 사용할 것이다.

일반적으로 안드로이드에서는 Activity 클래스가 Controller이고 Fragment 클래스가 View 영역이다. 그러나 이것은 코드의 재사용성을 줄인다. 또한 Fragment와 Activity는 제한적으로 화면 전환 애니메이션이 가능하다.


View 영역(layer)을 위한 UI 클래스(i.e. LinearLayout) 
View 영역은 LinearLayout이나 ViewGroup과 같은 View(UI) 엘리먼트를 상속하여 View를 구현할 수 있다.
  • Activity / 앱 플로우의 독립적인 기능을 재사용할 수 있다.
  • Activity 수를 줄인다.(앱 용량을 덜 잡아 먹는다)
  • Controller와 의존적인 부분을 줄인다.

(독립된) Controller 클래스
Controller 클래스는 어떤 안드로이드의 클래스를 상속받아서도 안된다. Activity와 Fragment로부터 독립적이게 해주어야 재사용이 가능할 것이다.
  • Controller를 가볍게 만들어라, View와 Model을 연결해주는 역할만 하면 된다.(단일 책임 원칙)
  • 이벤트를 다른 Controller에게 넘겨주어라(i.e. analytics)
  • 안드로이드 클래스로부터 분리해라 재사용을 위해

관련된 좋은 습관들
Activity 클래스의 의존성을 줄이기
  • Controller는 추상화에 의존한다(interface)
  • 시스템 구성과 의존성을 컨트롤하기위해 코드 중심에 위치시킨다.
  • 차후에 의존성 주입(dependency injection)을 옮길 수 있게 한다.

Analytics, A/B 테스트 등을 분리하기 위한 파사드(facade)
  • 우리는 여러 기록장치를 사용하기 때문에 파사드를 이용해 이 API들을 한데 모아둘 필요가 있다.
  • A/B 테스트나 다른 임시적인 기능들은 추상화돼있어야하고, 분리된 Controller나 파사드를 통해 접근가능해야한다.

이것들은 어떻게 생겼을까?
테스트에 용이
저렇게 잘 구현하여 Activity로부터 완전히 분리시킨다면, 테스트하기 아주 수훨해 질 것이다. 일반적으로 Activity는 수많은 것(디바이스의 시스템 구성, 네비게이션, 스타일, 액션바..)을 다루며 이것이 테스트의 범위를 너무 크게 만들어버린다.

위와같은 방법으로 Robelectric 테스트는 모든 의존성의 모의 객체(mock)를 만들어주고, 바깥에서 유닛 테스트 할 수 있게 해준다.

사용가능한 라이브러리&프레임워크
아래 안드로이드 프레임워크는 앞서 말한 것들을 구현할 수 있게 해준다. 우리는 지금 시점에서 저것들이 필요하지 않을 수 있으나, 나중에 코드베이스 전반에 걸쳐 적용시켜보려한다면 손쉽게 사용해볼 수 있을 것이다.

  • Square mortar: Activity 라이프 사이클의 행동으로부터 분리시켜, View를 가볍게 만들고 View를 Controller와 한 쌍으로 만들어주는 간편한 라이브러리
  • inloop AndroidViewModel: 엄청난 양의 코드 없이 Fragment나 Activity로부터 데이터와 상태를 분리시켜준다. 벙어리(dumb) View가 되는걸 줄인다.
  • sockeqwe mosby: 현대 안드로이드 앱을 위한 Model-View-Presenter 라이브러리.


'그 외' 카테고리의 다른 글

[번역] 리액티브 프로그래밍이란?  (0) 2017.03.03

WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

옮긴이 : 종종 브라우저로 원문 링크에 들어가지지 않는 현상이 생깁니다. 이럴때는 Medium 앱으로 Architecture of Node.js Internal Codebase를 검색하여 들어가시면 됩니다.


첫째로 JavaScript라는 단어에 대해...

StackOverflow 공동 창시자인 Jeff Atwood가 Coding Horror 프로그래밍 블로그에 글을 올렸다.
"JavaScript로 작성될 수 있는 모든 앱들은 결국 JavaScript로 작성될 것이다."

JavaScript는 지난 몇년간 가장 인기있는 프로그래밍 언어 중 하나로 크게 확장되었다. 실제로 2016년 SO 개발자 조사에 따르면, StackOverflow에서 가장 인기있고 가장 기술력있는 언어로 1등을 달성하고, 다른 결과들도 좋은 기록을 세웠다.

Node.js는 바이너리 데이터 조작, 파일 시스템 I/O 오퍼레이션, 데이터베이스 접근, 컴퓨터 네트워킹 등과 같은 중요한 서버사이드 기능을 담은 기초(foundation)로서 JavaScript 환경의 서버사이드이다. 이것은 Django(Python), Laravel(PHP), RoR(Ruby) 등과 같은 현존하는 시도되고 테스트된 프레임워크 사이에서 특출난 특징을 가진다. Node.js는 PayPal, Tinder, Medium, LinkedIn, Netflix와 같은 기술 리더 회사들이 사용한다는 것이다. 몇몇은 Node.js가 1.0버전이 되기도 전에 이미 사용하고 있었다.

나는 최근에 StackOverflow에서 Node.js 내부 코드베이스의 아키텍처에 관한 질문에 답변을 달았었다. 그것이 이 글을 쓰도록 영감을 불어넣어 주었다.


사실 공식적인 문서에서는 Node.js가 무엇인지 설명하기에 크게 도움이 되지 않는다.


"JavaScript 런타임은 크롬의 V8 JavaScript 엔진으로 만들어졌다. Node.js는 event-driven, non-blocking I/O 모델이고..."

이 말을 이해하고 실제 숨어있는 힘을 이해하기 위해 Node.js 요소들을 쪼개어보고, 몇몇 중요 용어들을 상세히  설명 할 것이다. 다음 어떻게 다른 조각들이 서로 소통하여 Node.js를 강력하게 만들 수 있는지 설명할 것이다.

Node.js 아키텍처 (High-Level to Low-Level)

요소들/종속물(COMPONENTS/DEPENDENCIES)
V8 : 구글에의해 오픈소스화된 높은 퍼포먼스를 자랑하는 JavaScript 엔진이며 C++로 구현되어있다. 크롬에서 사용하는 엔진과 동일한 엔진이다. V8은 당신이 JavaScript로 작성한 코드를 받아서, 기계코드로 컴파일한 뒤(이렇기에 빠르다), 실행시킨다. 어떻게 V8이 그냥 빠를 수 있을까? StackOverflow의 답변을 확인해보아라.

libuv : 비동기적 기능을 제공하는 C 라이브러리이다. 이것은 다른 중요한 기능들 사이에서 이벤트 루프, 스레드 풀, 파일 시스템 I/O, DNS 기능, 네트워크 I/O를 관리한다.

다른 C/C++ 요소들/종속물 : c-ares, crypto(OpenSSL), http-parser, zlib. 이 요소들은 서버에서 네트워킹, 압축, 암호화와같은 중요한 기능을 수행하기 위해 low-level로 소통하는 방식을 제공한다. 

앱/모듈 : 이것은 JavaScript 코드가 존재하는 모든 곳이다. 당신의 앱 코드, Node.js의 코어 모듈, npm으로 설치한 모든 모듈, 당신이 작성한 모든 모듈까지 당신은 대부분의 시간을 여기서 보낼 것이다.

바인딩 : 당신은 아마 이 시간을 통해 Node.js가 JavaScript와 C/C++로 작성되었다는 것을 알게 되었을 것이다. 여기엔 수많은 C/C++ 라이브러리가 있는데 그 이유는 간단하다: 빠르기 때문이다. 그러나 어떻게 당신이 JavaScript로 짠 코드가 C/C++로 짠 코드와 자연스럽게 소통할까? 그것은 세개의 서로 다른 언어이지 않는가? 그렇다. 다른 언어로 짜여진 코드는 보통 서로 서통할 수 없다. 바인딩 없이는 안된다. 이름에서 이야기하듯 바인딩은 한 언어를 다른 언어에 '묶어(bind)' 코드를 접합시킨다. 그러면 서로 의사소통을 할 수 있게 된다. 이 경우(Node.js) 바인딩은 단순히 C/C++로 작성된(c-ares, zlib, OpenSSL, http-parser 등) Node.js 내부 코어 라이브러리들을 JavaScript에 연결한다. 바인딩을 작성하는데 첫번째 이유는 재사용이다: 만약 필요한 기능들이 이미 구현되있다면, 그것을 가져다 사용하면 된다. 단지 언어가 다르다는 이유로 그것을 다시 짤 필요는 없다. 왜 그냥 연결시켜 사용하지 않겠는가? 두번째 이유는 퍼포먼스이다: C/C++ 같은 시스템 프로그래밍 언어들은 일반적으로 고수준언어(Python, JavaScript, Ruby등) 보다 빠르다. 그러므로 CPU-집약 오퍼레이션 코드는 C/C++로 작성하는 것이 현명할 것이다.

C/C++ Addon : 바인딩은 단지 zlib, OpenSSL, c-ares, http-parser와 같은 Node.js 내부 라이브러리를 접합하는 기능만 한다. 만일 당신이 써드파티의 C/C++ 라이브러리(외부 C/C++ 라이브러리)를 넣고 싶으면, 스스로 라이브러리를 접합시켜야한다. 당신의 코드를 접합해주는 코드가 addon이라 불리는 것이다. 바인딩과 addon은 당신의 JavaScript 코드와 Node.js의 C/C++ 코드를 연결하는 다리라고 생각하면 편할 것이다.

용어들(TERMINOLOGIES)
I/O : Input/Output의 약자이다. 이것은 기본적으로 시스템 I/O의 하위 시스템에의해 주로 다뤄지는 모든 컴퓨터 오퍼레이션을 나타낸다. I/O 바운드( https://en.wikipedia.org/wiki/I/O_bound)오퍼레이션은 디스크/드라이브와의 상호작용을 포함한다. 예를들어 데이터베이스 접근과 파일 시스템 오퍼레이션을 포함한다. 연관된 다른 개념에는 CPU 바운드, 메모리 바운드 등이 있다. 오퍼레이션이 I/O 바운드에 속하는지 CPU 바운드에 속하는지 아니면 다른데 속하는지 구별하는 좋은 방법은, 특정 오퍼레이션이 더 많은 퍼포먼스를 내고 리소스를 많이 잡아먹는지 체크하면 된다. 예를들어 한 오퍼레이션이 눈에 띄게 빨라지고 CPU 파워가 증가했다면 그것은 CPU 바운드 이다. 

Non-blocking/비동기적 : 보통 리퀘스트가 들어오면 앱은 그 리퀘스트를 다루고, 그 리퀘스트의 작업이 끝날때까지 다른 모든 오퍼레이션을 멈춘다. 다음은 실제 일어날 수 있는 문제이다: 만일 한꺼번에 수많은 리퀘스트가 들어오면, 각 리퀘스트는 이전 리퀘스트의 작업이 끝날때까지 기다려야한다. 다른 말로는, 이전 오퍼레이션이 다음 것을 블럭(block)시킬 것이다. 최악의 상황은,  이전 리퀘스트가 긴 응답시간(eg. 먼저 1000개의 계산 후, DB로부터 3GB 데이터를 읽는 경우) 이라면, 다른 리퀘스트들은 긴 시간동안 멈춤/블럭이 되 있을 것이다. 이 문제를 해결하기 위한 방법에는 각 리퀘스트에 대해 멀티 프로세싱 혹은/그리고 멀티 스레딩이 있을 수 있다. Node.js는 이것을 좀 다르게 다룬다. 모든 새 요청에 대해 새 스레드를 만드는 것 대신, 요청들은 한 메인스레드에서 다뤄지며, 그것이하는 일의 대부분이다.

리퀘스트들을 다루기 : 리퀘스트에 포함된 모든 오퍼레이션(eg. 파일 시스템 접근, 데이터베이스 읽기/쓰기)은 백그라운드에서 (위에서 언급한)libuv에의해 관리되는 일꾼 스레드로 보내진다. 즉, 리퀘스트 안에 있는 I/O 오퍼레이션들은 메이스레드가 아닌 곳에서 비동기적으로 다뤄진다. 이 방법으로 무거운 것을 다른곳으로 보냄으로써, 메인스레드가 블럭되지 않게 해준다. 당신의 앱 코드는 한 순간에 한가지 일만 하고 있고, 그것은 메인스레드 안에 있을 것이다.  libuv의 스레드풀에 있는 모든 일꾼 스레드는 당신이 접근할 수 없게 만들어 놓았다. 여러분은 그들에게 직접 접근할 수 없으므로 그것에대해 걱정할 필요도 없다. Node.js가 당신을 위해 관리해주기 때문이다. 이러한 아키텍처는 I/O오퍼레이션을 특히 효율적이게 만들어준다. 그러나 이것에 단점이 없는 것은 아니다. 오퍼레이션에는 I/O 바운드 하나만 있는게 아니라 CPU바운드, 메모리 바운드 등이 더 있다. 조금만 더 이야기해보자면 Node.js는 I/O 작업을 위한 비동기 기능만을 제공한다. CPU 집약 오퍼레이션을 수행하는 방법이 있지만, 이 글의 논지가 아니니 넘어가도록 하자.

이벤트기반(Event-Driven) : 일반적으로 현대의 대부분 시스템은 메인 앱이 꺼져야 들어오는 리퀘스트에의해 프로세스가 초기화된다. 그러나 그들이 다르게 흘러간다면? 전형적인 구현은 리퀘스트를 다음 순서처럼 다룬다: 리퀘스트를 위한 스레드를 하나 만들고, 다른 오퍼레이션이 끝난뒤 그 오퍼레이션을 수행하며, 오퍼레이션이 느려지면 그 스레드에 있는 모든 오퍼레이션이 멈추거나 느려진다. 모든 오퍼레이션이 완료되면 리스폰을 돌려준다. 그러나 Node.js에서는 메인 앱에의한 것이든 리퀘스트에의한 것이든 모든 오퍼레이션이 트리거(trigger)를 기다리는 Node.js 이벤트로 등록된다.

런타임(시스템) : Node.js 런타임은 고수준, 저수준 둘 다 Node.js 앱 실행을 같이 도와주는 전체 코드베이스(위에서 언급한 요소들)이다.

모든것을 섞어보자. (PUTTING EVERYTHING TOGETHER)
이제 Node.js 요소의 고수준 관점에서 보자. 우리는 그것의 아키텍처를 더 잘 알기위해 그것의 워크플로우(workflow)를 알아보고, 어떻게 다른 요소들이 서로 소통하는지도 알아볼 것이다.

Node.js 앱이 실행되면, V8엔진이 당신의 앱 코드를 실행시킨다. 당신 앱의 객체들은 옵저버(이벤트로 등록할 수 있는 기능)의 목록에 넣어둔다. 이 옵저버는 각 이벤트들이 발생할 때 알림을 받는다.

한 이벤트가 발생되면, 그것의 콜백 함수가 이벤트 큐(event-queue)에 들어간다. 큐에 이벤트가 한개라도 남아있으면 이벤트 루프(event loop)는 큐에서 이벤트를 빼어 콜스택(call stack)에 집어넣는다. 이전 이벤트가 처리가 되면 이벤트 루프는 다음 이벤트를 콜스택에 넣는다는 점만 유의하면 된다.

콜스텍에서 우연히 I/O 오퍼레이션을 만나면, 처리하기위해 libuv에게 넘어간다. 기본적으로, libuv는 4개의 일꾼 스레드를 유지하고 있다. 물론 더 많은 스레드를 만들 수도 있다. 만약 요청이 파일 시스템 I/O나 DNS 관련이면, 처리를 위해 스레드 풀에 할당될 것이다; 다른경우, 네트워킹과 같은 다른 리퀘스트들에서는 특정 플랫폼의 매커니즘이 그 리퀘스트들을 알아서 배치할 것이다.

스레드 풀을 사용하게 만드는 I/O 오퍼레이션들(파일 I/O, DNS 등)은 데이터베이스 트렌젝션이나 파일 시스템 접근과 같은 오퍼레이션을 수행하기 위해 Node.js의 저수준 라이브러리로 일꾼 스레드가 작용할 것이다. 처리가 끝나고 libuv는 이벤트가 다시 메인스레드에서 처리될 수 있게 이벤트 큐에 다시 집어넣는다. 이 동안에는 libuv가 비동기의 I/O 오퍼레이션을 다루고 있고, 메인스레드는 마냥 앉아서 처리 결과를 기다리는 것이 아니라 자신의 할 일을 하고 있는다. libuv에의해 돌려받는 이벤트는 이벤트 루프에의해 콜스택으로 돌아왔을때, 다시 메인스레드에서 처리될 수 있다. 이것이 Node.js에서 이벤트 생명주기이다.

mbg는 기가막히게 Node.js와 레스토랑을 비유해 놓았다. 나는 Node.js 사이클을 더 쉽게 설명하기 위해 그의 이야기를 빌려 설명하겠다.

Node.js 앱을 스타벅스 카페라 생각해보자. 높은 효율과 숙련이 잘 된 웨이터(한 명이고 메인스레드라 할 수 있다)가 주문을 받는다. 만약 같은 시간대에 많은 고객이 들이닥치면 웨이터의 서비스를 받기위해 줄을 서게 된다(이벤트 큐에 넣는다). 한 고객이 웨이터로부터 서비스를 받으면 웨이터는 메니저(libuv)에게 주문을 넘겨준다. 각 주문을 어떤 바리스타(일꾼 스레드 혹은 플랫폼-특정 매커니즘)에게 주문을 할당할지 정한다. 바리스타는 다른 다른 재료들과 기계를 써서(저수준 C/C++ 요소들) 고객이 요청한 것들의 음료를 만든다. 보통 4명의 바리스타가 특정 라떼(파일 I/O, DNS 등)를 돌아가면서 만든다. 그러나 주문이 피크치에 달할 때는 더 많은 바리스타를 일시적으로 고용할 수 있다(개업한 날의 이야기이지, 점심시간대의 이야기는 아니다). 한 번 웨이터가 메니저에게 주문을 넘기면, 웨이터는 다른 고객을 서브하기 위해 커피 만드는 것을 기다리지 않는다. 대신에 다음 고객을 부른다(이벤트 루프에의해 다음 이벤트를 큐에서 꺼네어 콜스택에 넣는다). 이벤트가 콜스택 안에 있는 것은, 고객이 카운터에서 서브를 받으며 있는 것과 비슷하다. 커피가 다 만들어지면, 커피는 고객 줄의 끝으로 보내진다. 커피가 카운터로 나오면 웨이터는 고객의 이름을 부를 것이고, 고객은 주문한 커피를 받게된다. (비유가 다소 현실세계에서는 이상할 수 있지만, 프로그램 관점에서 프로세스를 고려할 때는 딱 들어 맞을 것이다)


고수준 관점의 전반적인 Node.js 내부 코드 베이스와 그것의 일반적인 이벤트 생명주기에대해 설명이 끝났다. 그러나 이 총람은 굉장히 일반적인 상황의 이야기이고 많은 이슈와 세부적인 요소에는 들어맞지 않을 수 있다는 점을 유의하길 바란다. 예를들어 CPU 바운드 핸들링이나 Node.js 디자인 패턴 등등이 있다. 더 많은 다른 글들의 토픽들이 그 부분을 채워줄 것이다. 



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

Node.js 쓰다보면 메모리를 점점 잡아먹는 현상을 발견할 있다. 이것은 굉장히 일반적인 현상이고, Node.js에서 쓰는 V8엔진은 기본으로 1.4GB 메모리를 한계로 잡아놓고(기본적으로 64비트는 1.4GB, 32비트는 512MB 한계로 잡는다.) 안에서 메모리를 점점 사용하게된다. 나의 경우는 아마존 프리티어를 사용하기때문에 메모리가 1GB 밖에 되지않아서 메모리 제한을 낮추어야했다.


--max-old-space-size=512

메모리 사용을 512MB 제한하라는 옵션이다. 아래와같이 사용할 있다.

혹은 forever 모듈을 사용하고있다면 아래와같이 사용하면 된다.


--expose-gc

가비지 컬랙터를 수동으로 전환한다. 내가 자바스크립트 코드에서 gc(); 호출하면된다. 적어도 30초에 한번씩은 가비지 컬랙팅을 하기를 추천 한다고 한다.


--max-new-space-size=2048

만약 서버 멈춤이 짧은것이 중요하다면 --max-new-space-size=2048 플래그를 사용하면 된다. 이것은 피크 퍼포먼스를 줄여버리기도하지만, 100ms정도로 서버 멈춤이 짧아질 것이다


--noincremental-marking

반면 피크 퍼포먼스가 중요하고 서버 멈춤이 오래 걸려도 괜찮다면 --noincremental-marking 플래그를 사용하면 된다. 플래그를 사용하면 1GB 1 정도의 서버 멈춤을 예상할 있다. 따라서 주로 작은 (heaps)이나 일괄 처리 테스크(순차 처리 테스크) 유용하게 사용된다.



참고

  • StackOverFlow : NodeJS / ExpressJS Memory Leak
    http://stackoverflow.com/questions/22507667/nodejs-expressjs-memory-leak
  • StackOverFlow : Is anybody making a Node-optimized V8?
    http://stackoverflow.com/questions/8263210/is-anybody-making-a-node-optimized-v8
  • 600k concurrent websocket connections on AWS using Node.js
    http://www.jayway.com/2015/04/13/600k-concurrent-websocket-connections-on-aws-using-node-js/
  • How does Node.js do memory allocation?
    https://www.quora.com/How-does-Node-js-do-memory-allocation



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

포트폴리오 페이지를 제작하고있다. 보통 포트폴리오 제일 하단에 footer를 만들어서 자신의 소셜 링크를 달아놓는다. 그 부분을 쉽고 깔끔하게 구현하는 코드를 기록해놓았다.

결과는 아래와 같다.

참고 :  http://fortawesome.github.io/Font-Awesome/examples/#
더 많은 아이콘 : 
http://bootstrapheroes.com/semantriademo/downloader/light-blue/ui_icons.html


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

목표

- http://{username}.github.io에 Hello World 웹페이지가 나타나도록 만들것이다.
 +) 추가로 http://{username}.github.io가 아닌 http://profile.canapio.com 나만의 도메인을 적용시켜 볼것이다. 물론 도메인을 미리 구매하여 준비해둬야한다.

들어가며

Github는 깃을 사용하는 프로젝트를 지원하는 웹 기반의 호스팅 서비스이다. 여기서 홈페이지를 만들 수 있는 기능을 제공한다. 다르게 말하면 홈페이지를 구성하는 파일들을 Github에 올려놓고 홈페이지를 돌릴 수 있다는 것이다. 원래는 홈페이지를 만들기위해서는 서버까지 구축했었어야했는데, 요즘은 다양한 서비스에서 서버를 무료(또는 무료)로 제공해주고있다. 그중 하나가 Github인것이다.

"http://{username}.github.io"에 Hello World 페이지 띄우기

STEP 1 : 저장소를 판다.
저장소 이름은 {유저이름}.github.io로 한다. 저장소 이름이 나중에 웹페이지 도메인 네임이 될것이다.

STEP 2 : index.html 파일을 만든다.

STEP 3 : 확인한다.

나만의 도메인으로 바꾸기

STEP 1 : CNAME 파일을 생성하여 바꾸고자 하는 도메인을 넣어둔다.


이때 http://나 https://는 빼고 입력해야한다.

STEP 2 : 도메인 등록 사이트에 가서 A 레코드 설정을 한다.
Github의 DNS Provider IP주소는 아래 두가지이다. 둘중 하나 선택하여 등록해주면 된다.

  • 192.30.252.153
  • 192.30.252.154
위 사진은 닷넷코리아라는 도메인 사이트에서 등록할때의 모습이다.

이렇게 등록을 해주면 시간이 좀 걸릴수도 있다는데(10분정도?), 곧 확인해보면 원하는 주소에 나의 github 사이트가 연결되었음을 알 수 있을것이다.



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : https://blog.risingstack.com/fundamental-node-js-design-patterns/

Translated by canapio
Help by soojin

디자인패턴에 대해 이야기할 때 당신은 singleton, observer, factory들을 생각할 것이다. 이 글은 단지 그것들에 대해서만 이야기하는것은 아니고 dependency injection이나 middleware와 같은 다른 일반적인 패턴과 함께 다룰것이다.

디자인 패턴이란?

디자인 패턴은 흔히 발생하는 문제를 재사용가능하게 일반화하여 해결한다.

Singleton

singleton 패턴들은 해당 "클래스"의 인스턴스 갯수를 한개로 한정한다. Node.js에서는 require을 사용함으로써 꽤 쉽게 싱글톤을 만들 수 있다.

//area.js
var PI = Math.PI;

function circle (radius) { 
  return radius * radius * PI;
}

module.exports.circle = circle; 

당신의 응용프로그램에서 싱글턴 객체를 얼마나 사용하든 상관없이; 오직 하나의 객체로 존재하게 될 것이다.

var areaCalc = require('./area');

console.log(areaCalc.circle(5));

require의 동작 덕분에, 싱글톤들은 NPM모듈들 사이에서 가장 일반적인 Node.ja 디자인 패턴들일 것이다

Observer

한 객체는 상태가 바뀔때 dependents나 observer의 리스트를 자동으로 유지하고 그것들을 알린다. Observer 패턴을 구현하기 위해서는 EventEmitter를 끌어 사용해야한다.

// MyFancyObservable.js
var util = require('util');  
var EventEmitter = require('events').EventEmitter;

function MyFancyObservable() {  
  EventEmitter.call(this);
}

util.inherits(MyFancyObservable, EventEmitter);  

이것이 그 방법이다; 우리는 단지 옵저버가 가능한 객체를 만들었다! 이것을 유용하게 만들기 위해서는 몇가지 기능을 추가하면 된다.

MyFancyObservable.prototype.hello = function (name) { 
  this.emit('hello', name);
};

잘 했다. 이제 우리의 observable은 이벤트를 발생시킬 수 있다. 이제 사용해보자!

MyFancyObservable.prototype.hello = function (name) { 
  this.emit('hello', name);
};

Factory

팩토리 패턴은 생성자 대신 제네릭한 인터페이스를 만들어야 하는 creational pattern이다.
이 패턴은 만들려는 프로세스가 복잡할 때 굉장히 유용하게 쓰인다.

function MyClass (options) {  
  this.options = options;
}

function create(options) {  
  // modify the options here if you want
  return new MyClass(options);
}

module.exports.create = create;  

펙토리는 테스팅 또한 쉽게 만든다. 가령 이 패턴을 이용해 모듈에 dependency를 넣을 수 있다.

Dependency Injection

Dependency injection은 의존객체에 하나 이상의 dependency를 주입하거나 참조로 전달하는 소프트웨어 디지인 패턴이다.     

예를들어 데이터베이스에 의존적인 UserModel을 생성해보자.

function userModel (options) { 
  var db;

  if (!options.db) {
    throw new Error('Options.db is required');
  }

  db = options.db;

  return {
    create: function (done) {
      db.query('INSERT ...', done);
    }
  }
}

module.exports = userModel;

이제 이걸 이용해서 인스턴스를 만들 수 있다.

var db = require('./db');

var userModel = require('User')({  
  db: db
});

왜 이게 유용한가? 이것은 테스팅을 엄청나게 쉽게 만들어준다 -당신이 유닛테스트를 만들 때, 이 모델에 가짜 db 인스턴스를 쉽게 넣어줄 수 있다.

Middleware / pipeline

Middleware는 강력하지만 아주 심플한 컨셉이다: 한 유닛이나 한 함수의 결과값은 다음을 위한 인풋이다. 만약 당신이 이미 ExpressKoa를 사용했다면 이 컨셉을 이미 사용해보았다.

Koa가 어떻게 그것을 하는지 확인해보자:

app.use = function(fn){  
  this.middleware.push(fn);
  return this;
};

기본적으로 이 코드는 middleware를 추가하면 단순히 middleware 배열에 추가한다. 지금까지는 잘 되고 있다. 그러나 서버에 요청을 하면 어떨까?

var i = middleware.length; 
while (i--) { 
  next = middleware[i].call(this, next);
}

마법이 아니다 - 당신의 middleware는 줄줄이 호출된다. 

Streams

stream은 특별한 pipeline으로 생각할 수 있다. 이것은 객체가 아닌 bytes이지만 많은 양의 데이터 흐름을 처리하는 데 좋다.

process.stdin.on('readable', function () {  
    var buf = process.stdin.read(3);
    console.dir(buf);
    process.stdin.read(0);
});

$ (echo abc; sleep 1; echo def; sleep 1; echo ghi) | node consume2.js 
<Buffer 61 62 63>  
<Buffer 0a 64 65>  
<Buffer 66 0a 67>  
<Buffer 68 69 0a>  

Example by substack

stream에 대해 더 공부하고 싶으면 substack의 Stream Handbook을 확인해보자.

Further reading



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,


먼저 이클립스에 cocos2d-x 환경을 세팅한다. 그리고 cocos2d-x 프로젝트를 하나 만든 다음, 그것을 안드로이드 스튜디오에서 열어볼 것이다. 

아래와 같이 13기가의 용량을 비워두고 환경 세팅을 시작했다. cocos2d-x프로젝트를 만들어 기기에 돌려보기까지 13기가를 꼬박 다 쓰고도 5기가를 추가로 다시 마련했다.

그리하여 환경세팅은 겨우겨우 끝냈지만 아직 빌드라던지 새 프로젝트를 만든다던지 하기 전이었다.

400메가가 남은 상태에서 도저히 진행이 불가능하여서 iMoive와 가비지벤드, iPhoto를 지우고 다시 진행했다. 

내가 새벽에 내내 작업을 해서 정신이 혼미했지만.. 안드로이드 스튜디오가 깔려 있는 상태에서 나머지 환경세팅을 하는데 약 20기가 정도가 들었다. 빌어먹을 NDK..
그리고 여분의 15기가를 준비하여 프로젝트를 생성, 빌드하는데 무리없도록 만들었고 가슴이 아픈 메모리 정리였다ㅠ

결론적으로 나는 총 35기가 정도의 용량으로 환경세팅을 완료했다. (확실하게 측정한 값은 아닙니다. 참고만 해주세요...)

아래는 간단하게나마 환경세팅을 하는 순서를 나열하겠다.
혹시 이미 설치된게 있다면 알아서 넘어가면 된다.

글쓴이가 기본 환경 경로로 잡은 곳은 /Users/사용자이름/Document 이다.
여기에 eclipse와 Cocos2d-x, ant, ndk를 다운 받았고, android-sdk는 eclipse폴더 안에 넣어두었다.


맥에서 Cocos2d-x 환경 세팅하기

1. 맥에 이클립스 설치 (http://toplogic.tistory.com/40)


2. 맥에 이클립스에 안드로이드(android-sdk) 설치 (http://toplogic.tistory.com/41)
$ sudo find / -name "*ndk*"
"*ndk*"의 뜻은 ndk를 포함한 모든것을 찾아달라는 뜻이다.


3. 대망의 NDK 다운 (https://developer.android.com/ndk/downloads/index.html#download)

- 글쓴이는 r10e 버전을 다운받았다.
- 다운 받고 나면 아래와 같이 압축을 풀어준다. (압축 푸는데 시간 좀 걸린다. 용량도 엄청 잡아먹는다.)
ndk$ chmod a+x android-ndk-r10c-darwin-x86_64.bin
ndk$ ./android-ndk-r10c-darwin-x86_64.bin


4. ANT를 다운 (http://ant.apache.org/bindownload.cgi)


5. ./bash_profile을 설정한다.
- $ vi /Users/사용자이름/.bash_profile 을 쳐서 ./bash_profile 파일에 들어간다.
- vi 에디터 사용법을 모른다면 대강 익히고 돌아오자..

- 위 스크린샷과 같이 경로를 지정해주면 되는데, 앞에서 다운 받았던 것들의 경로를 넣어주면 된다. (tip : 폴더를 드래그해서 터미널에 드롭하면 절대 경로를 알아낼 수 있다!)
- android-sdk, ndk, ant의 경로를 오타 없이 잘 넣자.


6. 이제 cocos2d-x를 다운받자! (http://www.cocos2d-x.org/download/version#Cocos2d-x)
- 글쓴이의 경우 v3.0을 다운받았다. (http://cdn.cocos2d-x.org/cocos2d-x-3.0.zip)


7. 다운받은 Cocos2d-x의 압축을 풀고, 터미널로 압축을 풀었던 폴더에 들어간다.


8. .bash_profile파일에 지정해놨던 경로들을 Cocos2d-x에 적용시킨다. 아래 명령어를 치면 된다.
$ ./setup.py
- 만약 뭐 경로가 하나라도 없다면 없는 경로가 있다고 알려줄 것이다.
- 경로가 잘 세팅 되있다면 아래 명령어를 치면 된다고 뜰 것이다. 아래 명령어를 치면 이제 경로 적용이 완료된 것이다.

$ source ~/.bash_profile


여기까지 잘 따라왔다면 mac에서 cocos2d-x 환경 세팅이 완료된 것이다.
아흑.. 너무 힘들었다.. 하지만 아직 프로젝트를 생성해보기 전까지 방심해서는 안된다. 젠장 첩첩산중이지만 슬슬 끝이 보인다. 


맥에서 Cocos2d-x 프로젝트 생성하기

1. 프로젝트를 생성하고 싶은 경로에 들어가서 아래 명령을 입력한다.

$ cocos new MyGameTest -p com.your_company.mygametest -l cpp -d ./mygametest
- 프로젝트 이름은 MyGameTest이고 페키지 이름은 com.your_company.mygametest이다 그리고 mygametest폴더를 만들어서 그 안에 프로젝트를 생성한다.


2. finder에서 프로젝트 폴더 안에 들어가보면 아래와 같이 나온다. 프로젝트 생성이 된거다.


아이폰 프로젝트를 Xcode로 열고 실행시켜보기

0. Xcode가 설치되있어야합니다.

1. 위 경로에서 proj.ios_mac 폴더에 들어가서 Xcode 프로젝트를 실행시킨다.

2. Xcode가 켜지면 빌드&런을 해서 시뮬레이터(혹은 단말기)에 앱이 올라가는지 보면 된다.
- 빌드하는데 시간이 생각보다 많이 걸린다.. ㅠ

이렇게 실행이 되면 성공이다.


안드로이드 프로젝트를 Android Studio에서 실행시켜보기

0. 안드로이드 스튜디오를 설치해놓아야한다.

1. 유튜브 링크에 들어가서 그대로 따라한다. 이미 프로젝트 생성까지는 했으므로 안드로이드 스튜디오에 프로젝트를 import하는 부분부터 하면 된다. (https://youtu.be/VLeGy1foMQA?t=7m51s)

2.  쭉 따라서 하면 된다. 아래와 같이 된다면 성공이다.





추가로) 이 포스팅에서는 안드로이드 빌드를 터미널에서 해보진 않았지만, 터미널에서 안드로이드 빌드를 해보는 과정에서 아래와 같은 에러가 뜨는 경우가 있다. 


$ cocos run -p android
...
...
building apk Android platform not specified, searching a default one...
Can't find right android-platform for project :"/Users/nownabe/projects/HelloCocos/proj.android".
The android-platform should be equal/larger than 10


이 문제는 이 링크(http://qiita.com/nownabe/items/496285423c74b47dcd42)를 통해서 해결할 수 있다. 비록 일본어로 되어있지만 크롬으로 켜서 번역기 돌리고 보면 나름 이해가 된다. 중간부분에 해결 방법을 설명해놓았다. 안드로이드의 버전 문제인듯 하다.







WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
사실 5분은 오버고..
암튼 엄청 빠르게 서버 푸시 시스템을 구축할 수 있다는 뜻입니다. 아래 링크에 들어가서 따라하시면 됩니다.


위 링크에서 필요한 내용이나, 추가할만한 내용을 뽑아봤습니다. 



nodejs 서버사이드 iOS 푸시

iOS용부터 설명하겠다. 링크 여기 강좌에 들어가면 정말 쉽게 푸시 구현하는 방법을 설명해 놓았다. 3분안에 푸시를 쏘아볼 수 있다! 내가 위 링크의 포스팅보다는 잘 쓸 자신이 없으므로 나는 배포하는 부분을 좀 이야기하겠다. 테스트만 해볼 분들은 링크만 참고하면 되지만 배포할때는 아래 코드로 수정해야한다.

1) 푸시 개발용, 푸시 배포용 
// Developer 
var options = { 
    gateway : "gateway.sandbox.push.apple.com", 
    cert: './keys2/cert_production.pem',
    key: './keys2/key_production.pem',
    production: false
};

// AppStore 배포, Adhoc 배포
var options = { 
    gateway : "gateway.push.apple.com",//"gateway.sandbox.push.apple.com", 
    cert: './keys2/cert_production.pem',
    key: './keys2/key_production.pem',
    production: true
};

바뀐 부분은 두 라인인데, gateway부분과 production부분이다. gateway 값을 바꿔주고 productiontrue로 수정해야한다. 이렇게하면 AppStore배포나 Adhoc배포에서 푸시가 날아간다. 그러니 저렇게 바꿔서 테스트를 해보고 싶으면 Adhoc으로 배포하여 푸시테스트를 해보면 된다. (필자는 Developer, Adhoc, AppStore Distribute 상황에서 모두 테스트해보았고 그 결과를 말하는 것이다.) 

2) 푸시 여러개 한번에 보내기
위에서 소개한 강좌에 들어가면 푸시를 한번에 하나밖에 보내지 못한다. 아래 소스는 푸시 날리는 부분에 푸시아이디값을 Array로 만들어 한꺼번에 여러개 날릴 수 있게 해준다. 

var myDeviceArray = [ ]
for (var i=0; i<results.length; i++) {
     var token = results[i]._id;//'앞에서 Xcode로 build 하면서 획득한 아이폰 디바이스 토큰을 입력한다.'
     var myDevice = new apn.Device(token);
     myDeviceArray.push(myDevice);
}
try {
     apnConnection.pushNotification(note, myDeviceArray);
} catch (e) {
     console.log("apn exception : " + e);
}


apnConnection.pushNotification(note, myDeviceArray);
이 부분이 푸시를 실제 날리는 부분이고, 애플에게 푸시를 쏘아달라고 요청하게된다.

여기서 원래 myDeviceArray가 아닌 myDevice라는 객체를 넣었었는데, 필자는 여기에 myDevice의 배열을 넣었다. 이렇게하면 한번에 20개, 30개씩 푸시를 날릴 수 있다. 




nodejs 서버사이드 android 푸시

안드로이드는 iOS보다 휠씬 간단하게 구현이 가능하다. 안드로이드는 인증서 이런게 없기때문에 그냥 코드 구현을 하고 키값만 넣어주면 된다. 
그런데 자료를 찾다보니 앞서 소개한 iOS푸시구현 블로그와 동일한 저자가 안드로이드푸시 저자가 동일하고, 정리가 정말 잘되있다.. 링크를 따라가면  구현할 수 있을 것이다. 

여기서는 링크에서 서버쪽 코드만 빼내서 설명하겠다.

우리가 사용할 nodejs모듈은 https://github.com/ToothlessGear/node-gcm이다. node파일이 위치한 디렉토리에 들어가서 npm install node-gcm 명령을 치면 된다.

상단에 node-gcm를 불러오고

var gcm = require('node-gcm');


// or with object values
var message = new gcm.Message({
     collapseKey: 'demo',
     delayWhileIdle: true,
     timeToLive: 3,
     data: {
          lecture_id:"notice",
          title:"제목입니다",
          desc: "설명입니다",
          param1: '첫번째파람',
          param2: '두번째파람'
     }
});

var server_access_key = '/*안드로이드 개발자가 넘겨준 서버키*/';
var sender = new gcm.Sender(server_access_key);
var registrationIds = [ ];     // 여기에 pushid 문자열을 넣는다.

registrationIds = ['/*안드로이드 단말기에서 나온 푸시 아이디*/'];

/*
for (var i=0; i<push_ids.length; i++) {
     registrationIds.push(push_ids[i]);
}
*/

// 푸시를 날린다!
sender.send(message, registrationIds, 4, function (err, result) {
     // 여기서 푸시 성공 및 실패한 결과를 준다. 재귀로 다시 푸시를 날려볼 수도 있다.
     console.log(result); 
});
이상 서버사이드 아이폰, 안드로이드 푸시 알림이였습니다. 


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

공지알림서비스 for PNU CSE


가격
무료

첫 버전 출시
2015년 6월

설명
부산대학교 정보컴퓨터공학부를 위해 만들어진 공지 알림 서비스입니다. 이 프로젝트는 부산대에 소속되지 않고 오로지 부산대 정컴인의 편의를 위해 개발된 무료 서비스입니다.

특징
- 약 15명 정도의 서로 다른 교수님 홈페이지가 지원됨
- 약 50여개의 서로 다른 URL을 모아서 보여줌
- 약 300개의 글을 모아 잘 정리되어 이 앱에서 보여줌
- 학사의 공지 또한 지원
- 푸시 알림 지원
- 안드로이드, 아이폰, 아이패드 지원

할말
본 서비스는 학과에서 만난 학생들과 함께 한 강의에서 만들어진 팀 프로젝트로써 2015년 1학기에 강의가 끝남과 동시에 서비스를 오픈하였습니다. 그리고 팀원들 모두 큰 흥미를 느끼고 프로젝트를 없애지 않고 이어서 개발하기로 결정하였고, 힘이 닫는대까지는 서비스가 운영, 유자, 보수 될 것입니다. 안드로이드 개발자 , 웹 개발자 팀원에게는 항상 감사한 마음입니다. 앞으로 꾸준히 서비스가 유지될 수 있도록 많은 유저들의 서비스 이용이 있으면 좋겠습니다.


스크린샷






다운로드 링크
Play Store : https://play.google.com/store/apps/details?id=com.pnucse.csenotice.Hugang
App Store : https://itunes.apple.com/app/id1000141391

소개페이지 : http://14.49.37.33:8003/DSTWebManager

피드백 : canapio.dst@gmail.com




WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
path없이 바로 /opt/nosql/mongodb/bin에 있는 명령을 실행하기위해 준비
# export PATH=/opt/nosql/mongodb/bin:$PATH

mongod 명령은 MongoDB 시스템을 위한 기본 데몬 프로세스이다. 데이터 요청, 데이터 접근, 백그라운드에서 동작할 수 있게하는 등의 기능을 수행한다.

1) 테스트를 위한 mongod 돌리기
1. mongod 명령 수행
# mongod

2. 새로운 터미널을 열어서 mongo 명령 수행
# mongo
>

3. 종료
mongo 종료 : 
> exit
mongod 종료 :
# cmd+c (혹은 # ctrl+c)


2) 서비스를 돌리기 위한 mongod를 데몬으로 돌리기(백그라운드에서 돌리기)
1. mongod 명령을 데몬으로 수행. 데몬으로 수행하면 fork를 하여 백그라운드에서 돌고 있다.
# mongod --fork --logpath /var/log/mongodb.log

2. mongo 명령 수행
# mongo
>

3. 종료
mongo 종료는 위와 동일
mongod 종료 :
# mongod --shutdown




MongoDB 클라이언트에 들어온 모습



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
OS : centos 32bit
mongodb : 3.0.2


1. 아래 링크에 들어가서 해당 OS의 MongoDB 다운로드 URL 준비한다.

2. 리눅스에 curl 명령을 실행하여 MongoDB 압축파일을 다운받는다.
# curl -O [1번에서가져온URL]
예) # curl -O https://fastdl.mongodb.org/linux/mongodb-linux-i686-3.0.2.tgz

3. 압축을 푼다 (# ls를 해보면 해당 디렉토리에 들어있는 파일을 볼 수 있다)
# tar -zxvf 압축파일이름
예) # tar -zxvf mongodb-linux-i686-3.0.2.tgz

4. 압축을 푼 폴더를 /opt/nosql 으로 옮긴다.
# mkdir /opt/nosql
# mv mongodb-linux-i686-3.0.2 /opt/nosql/mongodb

5. db가 저장될 폴더를 만든다.
# mkdir -p /data/db

6. mongodb 디렉터리로 들어가서 mongod를 실행시킨다.
# cd /opt/nosql/mongodb

(7. mongodb 클라이언트를 실행시켜본다.)
# export PATH=/opt/nosql/mongodb/bin:$PATH  // monodb 클라이언트를 바로 실행할 수 있게 해줌
# mongdb
>


빠르게 훑어보는 nodejs, mongodb 연동 : http://bcho.tistory.com/889


참고 



WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
1. 아래 링크에 들어가서 해당 OS의 nodejs 다운로드 URL 준비한다.

2. nodejs 압축파일을 다운받고 압축을 푼다.
# wget http://nodejs.org/dist/v0.12.2/node-v0.12.2-linux-x86.tar.gz
# tar xfz node-v0.12.2-linux-x86.tar.gz

3. node 폴더를 옮긴다.
# mv ./node-v0.12.2-linux-x86 /usr/local/node

4. /etc/profile 파일에 들어가서 수정(:a)모드로 바꾸어 export를 두개 만들고 저장(:wq)한다. vi편집기 사용. (vi 편집기 사용법)

# vi /etc/profile

5. 방금 수정한 profile을 적용시킨다.
# source /etc/profile

6. node 명령을 실행해본다.

# node -v


연관 글

> [Node.js, MongoDB] Node.js 설치 및 실행

[Node.js, MongoDB] MongoDB 리눅스에 설치 및 실행

[Node.js, MongoDB] MongoDB 돌리기 (+백그라운드에서 돌리기)


(번역) Express.js 4, Node.js and MongoDB REST API 강좌


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,


종종 좋은 것들은 한곳에 머무르지 않고, 그래서 모카(Mocha)와 Superagent를 이용한 테스트와 Mongoskin과 Express.js를 사용하여 Node.js와 MongoDB를 이용한 JSON REST API 서버를 만드는 튜토리얼을 Express.js 4버전이 출시됨과 함께 만들게 되었다. 최신의 Express.js 4, Node.js, MongoDB를 다루는 튜토리얼을 만나보자.
새 튜토리얼을 위한 소스코드는 github.com/azat-co/rest-api-express (master branch)에서 확인할 수 있다. 이전의 Express 3.x버전을 위한 튜토리얼 코드는  아직 작동하고 express3 branch에 있다.



Express.js4와 MongoDB REST API Tutorial은 아래 파트로 나뉘어 구성되어있다.
1. Node.js와 MongoDB REST API 개요
2. 모카와 Superagent를 이용한 REST API 테스트
3. NPM-ing Node.js Server Dependencies
4. Express.js 4.x Middleware Caveat
5. Express.js와 MongoDB (Mongoskin) 구현
6. Express.js 4 랩을 실행하고 모카를 이용한 MongoDB 테스팅
7. Express.js와 Node.js의 결론 및 확장성

만약 당신이 자장소와 그것이 무엇을 동작하는지로부터 코드의 동작에 관심이 있다면, 여기 REST API server가 어떻게 다운로드되고 동작하는지 간단한 설명이 여기있다.
$ git clone git@github.com:azat-co/rest-api-express.git
$ npm install
$ node express.js


$ mongod 와 함께 MongoDB를 시작한다. 그다음, 새 터미널창을 띄워서 모카 테스트를 실행한다. :

$ mocha express.test.js


아니면, 모카를 전역으로 설치하지 않은 경우. :

$ ./node_modules/mocha/bin/mocha express.test.js



1. Node.js와 MongoDB REST API 개요
Node.js, Express.js, MongoDB(Mongoskin) 튜토리얼은 모카와 SuperAgent를 사용해 테스트를 해나갈것이다. 이것은 Node.js의 JSON REST API 서버를 만들면서 테스트 주도 개발(Test-Driven Development)을 필요로 한다. 
서버 응용프로그램은 Express.js 4버전대 프레임워크와 MongoDB를 위한 Mongoskin 라이브러리를 필요로한다. 이 REST API 서버에서 우리는 CRUD(create, read, update and delete)기능을 실행하고 app.param( ), app.use( )와 같은 Express.js middleware 방식의 메소드를 실행할 것이다.

가장 처음에 할 것은, MongoDB를 설치하는 것이다. 이 링크를 따라가면 할 수 있을 것이다.
우리는 아래의 버전의 라이브러리를 사용하게 될 것이다.
  • express: ~4.1.1
  • body-parser: ~1.0.2
  • mongoskin: ~1.4.1
  • expect.js: ~0.3.1
  • mocha: ~1.18.2
  • superagent: ~0.17.0

만약 버전이 맞지 않다면 코드가 동작하지 않을 수도 있다 :-(



2. 모카와 Superagent를 이용한 REST API 테스트
시작하기 전에, 우리가 만들게될 REST API 서버에 HTTP 요청을 만드는 기능 테스트를 한번 적어보자. 만약 모카를 사용할 줄 알거나, 바로 Express.js 앱 구현을 해보고 싶은 사람들은 마음대로 해도 된다. 당신은 물론 터미널에서 CRUL테스트를 할 수도 있다.
우리는 이미 Node.js, npm, MongoDB를 설치했다고 가정하고, 새 폴더를 만들어보자.
$ mkdir rest-api
$ cd rest-api


우리는 모카, Expect.js, SuperAgent 라이브러리를 사용하게 될 것이다. 그것들을 설치하고, 프로젝트폴더에 들어가서 이 명령을 실행해라.

$ npm install mocha@1.18.2 --save-dev
$ npm install expect.js@0.3.1 --save-dev 
$ npm install superagent@0.17.0 --save-dev


Note: 당신은 물론 (명령에 -g를 넣고) 모카를 전역으로 설치할 수도 있다. 
이제 아까 그 폴더에 express.test.js파일을 만들자. 아래 6가지를 진행할 것이다.
  • 새 객체를 생성한다.
  • 객체의 ID를 가져온다.
  • 객체의 모든 정보를 가져온다.
  • ID를 이용해 객체를 업데이트한다.
  • ID를 이용해 객체를 제거한다.
HTTP 요청은 Super Agent’s와 연관된 (단지 테스트케이스를 넣기만 하면되는) 함수들을 사용하면 굉장히 식은죽먹기이다. 
이 강좌는 Express.js 4, MongoDB, Mocha를 사용하여 REST API를 만드는것이 목적이기 때문에 테스트케이스(test suits)에 대해 깊게 들어가지는 않겠다. 코드를 복붙하시오!

아래 코드는 express.test.js파일이다.
var superagent = require('superagent')
var expect = require('expect.js')

describe('express rest api server', function(){
  var id

  it('post object', function(done){
    superagent.post('http://localhost:3000/collections/test')
      .send({ name: 'John'
        , email: 'john@rpjs.co'
      })
      .end(function(e,res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(res.body.length).to.eql(1)
        expect(res.body[0]._id.length).to.eql(24)
        id = res.body[0]._id
        done()
      })    
  })

  it('retrieves an object', function(done){
    superagent.get('http://localhost:3000/collections/test/'+id)
      .end(function(e, res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(typeof res.body).to.eql('object')
        expect(res.body._id.length).to.eql(24)        
        expect(res.body._id).to.eql(id)        
        done()
      })
  })

  it('retrieves a collection', function(done){
    superagent.get('http://localhost:3000/collections/test')
      .end(function(e, res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(res.body.length).to.be.above(0)
        expect(res.body.map(function (item){return item._id})).to.contain(id)        
        done()
      })
  })

  it('updates an object', function(done){
    superagent.put('http://localhost:3000/collections/test/'+id)
      .send({name: 'Peter'
        , email: 'peter@yahoo.com'})
      .end(function(e, res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(typeof res.body).to.eql('object')
        expect(res.body.msg).to.eql('success')        
        done()
      })
  })
  it('checks an updated object', function(done){
    superagent.get('http://localhost:3000/collections/test/'+id)
      .end(function(e, res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(typeof res.body).to.eql('object')
        expect(res.body._id.length).to.eql(24)        
        expect(res.body._id).to.eql(id)        
        expect(res.body.name).to.eql('Peter')        
        done()
      })
  })    
  
  it('removes an object', function(done){
    superagent.del('http://localhost:3000/collections/test/'+id)
      .end(function(e, res){
        // console.log(res.body)
        expect(e).to.eql(null)
        expect(typeof res.body).to.eql('object')
        expect(res.body.msg).to.eql('success')    
        done()
      })
  })      
})

테스트를 하기위해, $ mocha express.test.js 커맨드를 날릴 것이다. (모카를 전역으로 설치하지 않은 경우 $ ./node_modules/mocha/bin/mocha espress.test.js)


3. NPM-ing Node.js Server Dependencies
이 튜토리얼에서 우리는 Mongoskin을 사용할 것이다. 또한, Mongoskin은 Mongoose나 shema-less보다 훨씬 가볍다. 자세한 내용은 Mongoskin comparison blurb를 확인해보기 바란다.
Express.js는 Node.js HTTP module 핵심 객체로 감싸져있다. Express.js 프레임워크는 Connect middleware의 상위층을 기반으로 만들어져있고, 어마어마하게 많은 편리함을 제공한다. 몇몇 사람들은 ...

만약 당신이 이전 섹션(Text Converage)에서 rest-api 폴더를 만들었다면, 어플리케이션 모듈을 설치하기 위해 아래 명령만 입력하면 된다. :
$ npm install express@4.1.1 --save
$ npm install mongoskin@1.4.1 --save


4. Express.js 4.x Middleware Caveat

슬프게도 NPM express만 하는 것으로는 Express.js와 함께 최소한의 REST API 서버를 구축하는게 불가능하다. 왜냐하면 4.버전대의 middlewares은 번들이 아니기 때문이다!(the middlewares are not bundled) 개발자들은 Express.js 4.x.왼쪽에 있는 express.static를 제외한 분리된 모듈들을 설치해야한다. 그리고 들어오는 정보를 파싱하기위해 body-parser를 추가해야한다:
$ npm install body-parser@1.0.2 --save


5. Express.js와 MongoDB (Mongoskin) 구현

제일 처음에 우리의 express.js 안에 우리의 dependencies를 정의해야한다. :
var express = require('express'),
  mongoskin = require('mongoskin'),
  bodyParser = require('body-parser')


3.x대 이후 버전(물론 v4도 마찬가지), Express.js은 앱 인스턴스의 객체를 간소화해서 가져온다, 아래 라인은 서버객체를 우리에게 제공할 것이다.(번역자:그냥 import정도로 생각하면 될듯):

var app = express()


요청의 바디로부터 파람들을 추출하기위해, 우리는 아래와같은 모양의 bodyParser() middleware를 사용할 것이다.:

app.use(bodyParser())


Middleware(여기, 다른 포럼)는 Express.js에서 강력하고 편리한 패턴이고 구성요소를 연결하며 코드의 재사용을 증진시킨다.

HTTP 요청의 바디객체 파싱의 넘사벽으로부터 구해주는 bodyParser()메소드와 같이, Mongoskin은 딱 한줄의 코드로 MongoDB 데이터베이스에 접속하는게 가능하다.:
var db = mongoskin.db('mongodb://@localhost:27017/test', {safe:true})


Note: 만약 당신이 원격으로 데이터베이스에 접속하고 싶다면(MongoHQ와 같은 것들..), 당신의 username, password, host and port의 값들을 스트링으로 치환하라. 여기 URI 스트링의 포맷이 있다:
mongodb://[username:password@]host1[:port1][, host2[:port2], …[, hostN[:portN]]][/[database][?options]].

app.param() 메소드는 또다른 Express.js middleware이다. 이것은 기본적으로 “요청 핸들러의 URL페턴에 어떤 값이 있으니 매 시간마다 뭔갈 처리해라”는 것을 말하고 있다. 우리의 경우 요청 패턴이 collectionName 스트링에 콜론이 점두사로 있을 때, 우리는 특정 콜랙션을 선택한다. 그러면 다음 요청 핸들러에서 사용할 수 있는 요청 객체(widespreadreq)의 프로퍼티(콜랙션이나 다른것일 수도 있다.)로써 콜랙션을 저장한다. (번역자:뭔소린지 모르겠다)
app.param('collectionName', function(req, res, next, collectionName){
  req.collection = db.collection(collectionName)
  return next()
})


단지 유저지향적으로, 메시지와 함께 루트 라우트를 넣자.:

app.get('/', function(req, res) {
  res.send('please select a collection, e.g., /collections/messages')
})


이제 진짜 할 일을 시작한다. 다수의 요소들중에 리스트를 어떻게 가져오는지 있다 (첫번째 파라메터는 빈 오브젝트{}이고 임의의 라는 뜻이다). 이 결과는 _id에(두번째 파라메터) 의해 정렬된 10개 제한으로 낼 것이다. find()메소드는 커서를 반환하고 우리는 toArray()를 불러 JavaScript/Node.js용 배렬로 만든다. :

app.get('/collections/:collectionName', function(req, res, next) {
  req.collection.find({} ,{limit:10, sort: [['_id',-1]]}).toArray(function(e, results){
    if (e) return next(e)
    res.send(results)
  })
})


URL 패턴 파라메너에서 :collectionName 스트링에대해 언급한적이 있나? 이것과 이전 app.param() middleware는  req.collection 객체를 우리에게 준다. 이 객체는 우리의 데이터베이스에서 특정 콜랙션을 가르키고 있다.

우리는 단지 MongoDB에서 전체적인 페이로드를 지나온 이후로 마지막 시점에 만들어진 이 객체는 조금 이해하기 쉽게 해준다. 이 메소드는 서버나 다른 것들의 데이터베스가 어떠한 데이터 스트럭쳐도 받아드릴수 있기 때문에 종종 free JSON REST API라 불린다. Parse.com과 다른 백엔드 서버 제공자는 free JSON 접근을 만들어낸다. 우리 Express.js 앱에서는 이것을 위해 req.body를 사용할 것이다.
app.get('/collections/:collectionName', function(req, res, next) {
  req.collection.find({} ,{limit:10, sort: [['_id',-1]]}).toArray(function(e, results){
    if (e) return next(e)
    res.send(results)
  })
})


함수들을 구하는 findByIdfindOne과같이 생긴 단일 객체는 find()보다 빠르다. 그러나 그것들은 조금 다른 인터페이스를 사용한다 (그것들은 커서 대신에 진짜 오브젝트를 반환한다). 그러므로 그것을 기억하고 있어라. 추가적으로, 우리는 Express.js 마법에 의해 req.params.id 경로의 :id 부분으로부터 ID를 가져올 것이다.

app.get('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.findById(req.params.id, function(e, result){
    if (e) return next(e)
    res.send(result)
  })
})


PUT 요청 핸들러는 update()가 증가된 객체를 반환하기때문에  더 흥미로운 것을 가져온다.
또한 {$set:req.body}는 값을 저장하는 기능을 가진 특별한 MongoDB 기능이 (보통 달러표시로 시작한다).

두번째 {safe:true, multi:false} 파라메터는 MongoDB에 callback 함수가 실행되기 전까지 동작을 멈추고 오직 한가지(첫번째) 아이탬만 처리하라고 알리는 옵션을 가진 객체이다.
app.put('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.updateById(req.params.id, {$set:req.body}, {safe:true, multi:false}, function(e, result){
    if (e) return next(e)
    res.send((result===1)?{msg:'success'}:{msg:'error'})
  })
})


마지막으로 DELETE HTTP 함수는 app.del()에 의해 실행된다. 요청 핸들러에서, 우리는 그것이 그 동작을 하는 것처럼 보이는 removeById()를 사용한다. 그리고 커스텀 JSON success 메시지를 제거과정에서 내보낼것이다.:

app.del('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.remove({_id: req.collection.id(req.params.id)}, function(e, result){
    if (e) return next(e)
    res.send((result===1)?{msg:'success'}:{msg:'error'})
  })
})


Note: delete는 JavaScript의 연산자이고 대신에 Express.js는 app.del을 사용한다.

아래의 경우 서버 3000포트를 시작하는 마지막라인이다.
app.listen(3000)


단지 이 경우 뭔가 잘 실행되지 않을 수 있다. 여기 express.js 파일의 풀 소스가 있다.

var express = require('express') , mongoskin = require('mongoskin') , bodyParser = require('body-parser') var app = express() app.use(bodyParser()) var db = mongoskin.db('mongodb://@localhost:27017/test', {safe:true}) app.param('collectionName', function(req, res, next, collectionName){ req.collection = db.collection(collectionName) return next() }) app.get('/', function(req, res, next) { res.send('please select a collection, e.g., /collections/messages') }) app.get('/collections/:collectionName', function(req, res, next) { req.collection.find({} ,{limit:10, sort: [['_id',-1]]}).toArray(function(e, results){ if (e) return next(e) res.send(results) }) }) app.post('/collections/:collectionName', function(req, res, next) { req.collection.insert(req.body, {}, function(e, results){ if (e) return next(e) res.send(results) }) }) app.get('/collections/:collectionName/:id', function(req, res, next) { req.collection.findById(req.params.id, function(e, result){ if (e) return next(e) res.send(result) }) }) app.put('/collections/:collectionName/:id', function(req, res, next) { req.collection.updateById(req.params.id, {$set:req.body}, {safe:true, multi:false}, function(e, result){ if (e) return next(e) res.send((result===1)?{msg:'success'}:{msg:'error'}) }) }) app.del('/collections/:collectionName/:id', function(req, res, next) { req.collection.removeById(req.params.id, function(e, result){ if (e) return next(e) res.send((result===1)?{msg:'success'}:{msg:'error'}) }) }) app.listen(3000)

코드를 저장하고 당신의 에디터를 닫아라, 우리의 소박한 Express.js REST API 서버가 완성되었다.


6. Express.js 4 랩을 실행하고 모카를 이용한 MongoDB 테스팅

이제 MongoDB가 설치되고 실행됬다는 가정($ mongod)하에 터미널에서 실행시켜볼 수 있다(modgod와 다른 창을 띄워라).
$ node express.js


그리고 다른 창에서 아래 명령을 쳐라(처음 창은 닫으면 안된다):

$ mocha express.test.js

혹은 모카를 전역으로 설치 하지 않은 경우.:

$ ./node_modules/mocha/bin/mocha express.test.js


만약 모카나 BDD 사용을 원치 않다면, CURL는 언제나 당신을 위해 있다. :-)

예를들어 POST 요청을 만들기 위해 CURL데이터이다. :
$ curl -X POST -d "name=azat" http://localhost:3000/collections/test13


그리고 결과는 아래처럼 나오게 될 것이다.:

{"name":"azat","_id":"535e180dad6d2d2e797830a5"}]


우리는 REST API 서버를 사용하기때문에 쉽게 이 객체를 확인할 수 있다.:

$ curl http://localhost:3000/collections/test13
Using CURL with Express 4 and MongoDB REST API


GET요청 또한 브라우저에서 동작할 수 있다. 예를들어, http://localhost:3000/collections/test13 링크를 당신의 로컬 서버가 포트 3000에서 돌아가고 있을때 열 수 있다.
혹은 서버의 결과를 신뢰하지 못한다면, MongoDB($ mongo)를 이용하여 데이터베이스를 확인할 수도 있다.:
> db.test13.find()


Note: 만약 데이터베이스의 이름을 test라는 이름 대신에 다른 이름으로 바꾸고 싶으면, 명령 앞에 > use your_database_name 을 써라.

이 튜토리얼에서, 우리 테스트들은 실제 동작하는 어플리케이션 코드보다 길다. 몇몇에게는 테스트-기반-개발(Test-Driven Development)을 포기하고싶게 만들지도 모르겠지만, 당신이 어떠한 크고 복잡한 응용프로그램을 개발할 때에도 좋은 TDD 습관이 당신의 개발 시간을 줄여줄것이라 믿는다. 



7. Express.js와 Node.js의 결론 및 확장성
Express.js 4와 MongoDB/Mongoskin 라이브러리는 간단하게 몇 줄 만에 REST API 서버를 구축하기에 정말 좋다. 후에, 당신이 라이브러리를 확장하고자 한다면, 그것들은 또한 당신의 코드를 구성하는 방법을 제공할 것이다.
NoSQL 데이터베이스는 MongoDB와같이 스키마를 정의할 필요 없고 어떠한 다양한 형태의 데이터를 넘기거나 저장할 수 있는 좋은 free-REST APIs이다.
express.test.js, express.js and package.json의 풀소스코드는 github.com/azat-co/rest-api-exrpess에 있다.
Express.js나 다른 자바스크립트 라이브러리에대해 더 공부하고 싶다면, 아래 Azat의 책들을 보라.
  • Practical Node.js: Building Real-world Scalable Web Apps
  • Express.js Guide: The Comprehensive Book On Express.js
..
..
..

연관 글

[Node.js, MongoDB] Node.js 설치 및 실행

[Node.js, MongoDB] MongoDB 리눅스에 설치 및 실행

[Node.js, MongoDB] MongoDB 돌리기 (+백그라운드에서 돌리기)


> (번역) Express.js 4, Node.js and MongoDB REST API 강좌


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : http://www.dspdimension.com/admin/dft-a-pied/
Posted by Bernsee on September 21, 1999


Step 6 : DFT(Discrete Fourier Transform)

사인 변환에서 푸리에 변환까지 과정을 더 '일반화' 시킴으로써 간단하다. 사인 변환에 측정된 각 진동수를 위한 사인 파형을 사용하는 반면, 푸리에 변환에서는 사인 코사인 파형을 둘다 사용했다. That is, for any frequency we are looking at we ‘compare’ (or ‘resonate’) our measured signal with both a cosine and a sine wave of the same frequency. 만약 우리 신호가 사인 파형과 굉장히 닮았다면, 우리 변환의 사인 부분은 큰 진폭을 가질것이다. 만약 코사인 파형과 닮았다면, 코사인 부분이 커지게 될 것이다. 사인 파형과 정반대라면, 이것은 영에서 시작하여 1로 올라가는게 아니라 -1로 떨어지르것이다, 사인 부분은 음수의 값이 큰 진폭을 가질 것이다. 사인 코사인 위상은 받은 진동수에서 임의의 사인 형태로 보여질 수 있는것과 같이 +와 - 둘이 함께 보여질 수 있다.

//
// Listing 1.2: The direct realization of the Discrete Fourier Transform***:
//

#define M_PI 3.14159265358979323846

long bin, k;
double arg, sign = -1.; /* sign = -1 -> FFT, 1 -> iFFT */

for (bin = 0; bin <= transformLength/2; bin++) {
    cosPart[bin] = (sinPart[bin] = 0.);
    for (k = 0; k < transformLength; k++) {

        arg = 2.*(float)bin*M_PI*(float)k / (float)transformLength;
        sinPart[bin] += inputData[k] * sign * sin(arg);
        cosPart[bin] += inputData[k] * cos(arg);   

     }
}

우리는 여전히 푸리에 변환에 의해 뭔가 유용한 것을 얻어내야하는 과제를 남겨놓고 있다. I have claimed that the benefit of the Fourier transform over the Sine and Cosine transform is that we are working with sinusoids. 그러나 우리는 어떠한 정령 파도 보지 않았다, 오로지 싸인과 코싸인만 있다. 으음 이것은 추가적인 처리를 요구한다.

//
// Listing 1.3: Getting sinusoid frequency, magnitude and phase from 
// the Discrete Fourier Transform:
//

#define M_PI 3.14159265358979323846

long bin;
for (bin = 0; bin <= transformLength/2; bin++) {

    /* frequency */
    frequency[bin] = (float)bin * sampleRate / (float)transformLength;
    /* magnitude */
    magnitude[bin] = 20. * log10( 2. * sqrt( sinPart[bin]*sinPart[bin] + cosPart[bin]*cosPart[bin]) / (float)transformLength);
    
    /* phase */
    phase[bin] = 180.*atan2(sinPart[bin], cosPart[bin]) / M_PI - 90.;

}

DFT 아웃풋의 위 코드를 실행한 한 뒤에, 우리는 정형파의 합으로써 인풋 신호의 계산을 끝날 것이다. k-th 정형파는 frequency[k], magnitude[k] 그리고 phase[k]에 의해 설명된다. 단위는 Hz (Hertz, periods per seconds), dB (Decibel) 그리고 ° (Degree)이다. 이전에 계산한 1.3 Listing의 싱글 정형파의 사인 코사인 부분을 변환한뒤, 이제 항상 양수를 가지는 k-th 정형파의 DFT bin "magnitude" 진폭이라 부를것이고 이것을 기억하고 있어라. 우리는 진폭이 -1.0이든 1.0이든 위상이 +혹은 -180도 다른 magnitude가 1.0이라고 말 할 수 있다. 관련 문헌에서는, magnitude[ ] 배열을 측정된 신호의 Magnitude Spectrum라 부르고, phase[ ] 배열을 프리에 변환에 의해 계산된 측정된 신호의 Phase Spectrum이라 부른다.

데시벨에 bin magnitude를 측정하기 위해 참조함으로써, 우리의 인풋 파형은 DFS(digital full scale)의 0dB 크기를 갖는 [-1.0, 1.0] 범위의 값을 가질 것으로 예상 할 수 있다. DFT의 어플리케이션에 흥미를 보임으로써, 예를 들어 listing 1.3은 DFT를 기반으로한 스펙트럼 분석을 도출하는데 사용될 수 있다.





WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : http://www.dspdimension.com/admin/dft-a-pied/
Posted by Bernsee on September 21, 1999


Step 5 : Apple과 Oranges에 대해

만약 아직 당신이 따라오고 있다면, 푸리에 변환에 대한 여행이 거의 끝나간다. 우리는 얼마나 많은 사인 파형이 필요로 하는지에 대해 배웠고, 필요로 하는 수는 우리가 보고있는 샘플 수와 밀접한 관게가 있다는것, 낮은 주파수와 높은 진동수의 경계에 있는 것과 어쨋든 우리의 레시피를 완성시키기 위해서는 각 부분의 파형의 진폭을 결정할 필요가 있다는 것을 배웠다. 아직 완벽하게 해결한 것은 아니지만 샘플들을 어떻게 조리할지 결정할 수는 있을 것이다. 쉽게말하면, 우리가 측정한 샘플들과 우리가 알고 있는 진동수의 사인파형을 비교함으로써 사인파형의 진폭을 알아내고, 그것들이 어떻게 '같은지'에 대해 알아내보았다. 만약 그것들이 완벽히 같다면 그 사인파형은 반드시 같은 진폭이고 만약 참고하고있는 사인파형과 우리의 신호가 맞지 않다면 아닐 같은 진폭이 아닐 것이다. 그런데 어떻게 우리가 알고 있는 사인파형과 샘플 신호를 효과적으로 비교할 것인가? 다행히도 DSPer은 이 부분을 미리 만들어 놓았다. 사실 숫자를 곱하거나 더하는 아주 쉬운 부분이다. - 우리는 알고있는 진동수와 유닛진폭(이것은 계산기나 우리 컴퓨터의 sin( )함수로부터 나온 오직 한개의 진폭을 의미한다.)의 '참조하는' 사인파형을 계산하고, 우리의 신호 샘플들을 곱한다. 곱해진 결과값을 더하고나서, 우리가 다루고있는 진동수로부터 사인파형의 진폭을 얻어낸다.

이것을 C로 나타내면 아래와 같이 된다.

#define M_PI 3.14159265358979323846

long bin, k;
double arg;
for (bin = 0; bin < transformLength; bin++) {
    transformData[bin] = 0.;
    for (k = 0; k<transformLength; k++) {

        arg = (float)bin * M_PI * (float)k / (float)transformLength;
        transformData[bin] += inputData[k] * sin(arg);
    }
}

이 코드는 inputData[0...transformLength-1] 에 저장된 샘플 포인트를 transformData[0...transformLength-1]에 사인 파형의 진폭들의 배열 형태로 변환한다. According to common terminology, we call the frequency steps of our reference sine wave bins, which means that they can be thought of as being ‘containers’ in which we put the amplitude of any of the partial waves we evaluate. 일반적으로 쓰이는 용어를 빌리지면, 우리가 계산한 부분 파형의 어떤 진폭을 담은 'containers' 로써 생각될 수 있음을 의미하며, 참조하는 사인 파형 bin들의 진동수 단계라고 부른다
DST(Discrete Sine Transform)는 사인파형 부분들의 진폭을 구하기 위해 우리의 신호가 어떻게 생겼는지 모르거나 아니면 우리가 효과적인 방법을 사용할 수 있다고 가정하는 그러한 일반적인 흐름을 따른다. (예를들어 우리가 미리 우리의 신호가 알고있던 진동수의 한 ㅏ인 파형이라고 안다면, 우리는 즉시 사인파형의 큰 범위를 계산함 없이 진폭을 구할 수 있을 것이다. 푸리에이론에 기반한 이 효과적인 접근은 “Goertzel” 알고리즘을 찾을 수 있게 해주었다.)




WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : http://www.dspdimension.com/admin/dft-a-pied/
Posted by Bernsee on September 21, 1999


Step 4 : 요리법(cooking recipes)에 대해

이전 단락에서는 컴퓨터의 어떤 신호가 혼합된 사인파형으로부터 만들어 질 수 있다는 것을 확인했다. 우리는 진동수에 대해 생각해보았고 어떤 최대, 최소 진동수의 사인파형이 우리가 분석하는 신호를 완벽하게 복원하기 위해 필요로하는지도 생각해보았다. 우리가 봐온 샘플의 수가 가장 낮은 사인 파형이 필요로하는 가장 최하 부분을 결정하는데 얼마나 중요한지 봐왔지만, 우리는 아직 실제 사인파형이 최대 몇개의 결과물을 만들어내는지 논의되지 않았다. 사인 파형에의해 만들어진 신호를 구성하기 위해, 우리는 그 중 한 부분을 확인해볼 필요가 있다. 사실은, 주파수는 우리가 알아야할 유일한 것이 아니다. 우리는 또한 사인 파형들의 진폭을 알 필요가 있다. 즉. 인풋 신호를 다시 만들기위한 각 사인 파형의 갯수. 진폭은 사인파횽의 최대 높이이다. 그러니까 0으로부터 최댓값 사이의 거리를 맗나다. 높은 진폭은 음량이 클것이고, 우리도 그렇게 들을 것이다. 그러므로 신호에 저음이 많다면 높은 주파수의 사인파형 보다 낮은 사인파형들이 많이 합쳐져 있을 것으로 예상할 수 있다. 일반적으로 저음의 낮은 주파수의 사인파형은 높은 사인 파형들보다 큰 진폭을 가지고 있다. 우리의 분석에서, 우리는 레시피(recipe)를 완성하기위해 각 사인파형의 진폭을 정해야 할 것이다.


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

한글 시계


가격
$0.99

첫 버전 출시
2014년 10월

다운로드 수
약 2,000건 다운 (무료+유료 2014.11 기준)

설명
한글날 출시된 “한글 시계” 앱은 텍스트를 한글만을 이용하여 만들었습니다. 어색하지 않는 UI 배치를 하려고 많이 고심했습니다. 

특징
- 앱스토어 최초 한글 시계
- 거부감이 들지 않는 UI 배치
- 편안한 애니메이션 효과
- 여러 설정 기능들


스크린샷










다운로드 링크 : https://itunes.apple.com/us/id923856886
피드백 : yapprj@gmail.com






WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

Guitar Kit+


가격
$1.99

첫 버전 출시
2014년 1월

다운로드 수
약 60,000건 다운 (무료+유료 2014.11 기준)

설명
기본에 충실한 iOS용 계산기 어플입니다. 아이폰 아이패드 둘다 지원을 하며, 기본 계산기 기능 + 여러 추가 기능을 합쳐서 만들었습니다. 

특징
- 전문적인 앱임에도 불구하고 아름다운 UI를 지원
- 약 4000개의 코드 디비
- 타이핑을 이용한 코드 검색
- 자판을 터치하여 코드 검색
- 자주 쓰는 코드 저장
- 메트로놈 기능
- 초보를 위한 28개 기본 코드 연습 기능



소개 영상


스크린샷






다운로드 링크 : https://itunes.apple.com/app/id791551793
피드백 : guitar.chord.plus@gmail.com





WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,


쉬운 계산기


가격
무료

첫 버전 출시
2013년 4월

다운로드 수
약 40,000건 다운 (2014.11 기준)

유저 활성 현황
하루 약 4,000명이 앱을 사용하고 있으며 아무 홍보 없이 매일 50건이상씩 다운로드가 일어나고 있음

설명
기본에 충실한 iOS용 계산기 어플입니다. 아이폰 아이패드 둘다 지원을 하며, 기본 계산기 기능 + 여러 추가 기능을 합쳐서 만들었습니다. 

특징
- 쉬운 화면 인터페이스
- 직관적인 터치 애니메이션
- 다항 연산
- 00버튼
- %(백분율) 연산
- 딜리트(한글자씩 지우기) 기능
- 내보내기, 불러오기 기능
- 앱이 꺼져도 계산 기록 보족
- 아이폰, 아이패드 지원


스크린샷






다운로드 링크 : https://itunes.apple.com/app/id626808258
피드백 : easi.calculator@gmail.com




WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,
원문 : Mastering The Fourier Transform in One Day
Posted by Bernsee on September 21, 1999

Step 3 : “많다”는게 얼만큼인가?

위에서 확인했듯이, 복잡한 모양의 파형은 사인 파형들의 조합으로 만들어 질 수 있다. 우리는 이렇게 질문을 던질 수 있다. “컴퓨터가 신호를 만드는데 얼마나 많이 필요로 하나?” 흠.. 물론 이것은 하나의 사인파형일 수도 있다. 그 주어진 사인파형으로 우리가 다룰 그 시그널이 어떻게 만들어지는지 알고있다. 대부분 우리는 복잡한 구조의 현실세계 신호를 다룬다. 따라서 우리는 현재 파형의 얼만큼 나누어져있는지 미리 알지 못한다. 이 경우, 원본 신호를 구성하는 사인파형이 얼마나 많은 상한선을 필요로하는지 모르는 것은 얼마나 다행스런 일인지 모른다. 그치만 여전히 "얼마나 많이”에 대한 질문은 해결되지 않았다. 그럼 좀 직관적으로 접근해보자: 신호 중 1000개의 샘플이 있다고 가정해보자. 이 짧은 주기(신호 안에 대부분 최댓값과 최솟값이 있는)에 있을 수 있는 사인 파형은 모든 샘플마다 최댓값과 최솟값을 왓다갓다 했다. 그러므로 모든 샘플이 피크가 있다고 가정할 때, 가장 높은 주파수의 사인파형은 1000개의 샘플에서 500개의 최댓값과 500개의 최솟값을 가진다. 아래 그래프의 검정색 점을 말하는 것이다. 따라서 가장 진동수가 높은 사인 파형은 아래와 같이 생겼다. 


이제 가장 낮은 진동수의 사인 파형이 어떻게 생겼는지 확인해 보자. 만약 우리가 오직 하나의 샘플 점을 얻었다면, 이 점 하나가지고 어떻게 사인파형의 최댓값과 최솟값을 구하겠는가? 할 수 없다, 그러므로 이 한 점으로부터 나올 수 있는 파형의 주기는 무수히 많다.


그러므로 한개의 데이터 점은 전동수를 표현하기에는 충분하지 않다는 것이다. 이제 우리는 두개의 샘플이 지정되있을 경우, 이 두개의 점을 가지고 가장 낮은 진동수의 사인파형을 만들 수 있을까? 이 경우는 굉장히 단순하다. 여기서 두 점으로 부터 얻은 가장 낮은 진동수의 파형은 오직 하나밖에 없다. 아래 그림을 보자.



한뼘 정도 되는 두 못 사이에 줄이 연결되어 있는 상황을 상상해 보아라 (위 그래프는 사인 파형이 주기를 갖는다는 것을 세개의 점으로 표현한 것이다. 그러나 우리는 진동 수를 알아내기 위해 단지 제일 왼쪽 두 점만 있으면 된다). 사인 파형이 두 점 사이에서 왼쪽으로 가는 것과 같이, 우리가 볼 수 있는 가장 낮은 진동수는 두 못 사이에서 앞 뒤로 흔들리는 줄이다. 1000개의 샘플을 가지고 있다면, 두 ‘못’은 첫번째 샘플과 마지막 샘플이 될 수 있을 것이다, 예를들어 샘플 1번과 샘플 1000번. 우리는 우리의 경험으로 악기의 현 길이가 길어질수록 진동수가 낮아진다는 것을 안다. 그래서 우리는 못을 멀리 떨어뜨릴수록 사인파형의 주파수가 낮아짐을 예상할 수 있다. If we choose 2000 samples, for instance, the lowest sine wave will be much lower since our ‘nails’ are now sample number 1 and sample number 2000. 사실 1000 샘플에서 못을 두배 멀리 떨어뜨리면, 두배로 낮아질 것이다. 그러므로 우리가 더 많은 샘플을 가지고 있으면 0을 교차하는 점('못')을 멀리 떨어뜨려 더 낮은 주파수를 구할 수 있다. 이것은 설명을 이해하는데 굉장히 중요한 부분이다. 

또한 두 ‘못’과 함께 파형은 오르막 경사와 함께 반복된 후에 확인 할 수 있을 것이다(처음과 세번째 못은 동일하다). This means that any two adjacent nails embrace exactly one half of the complete sine wave, 다른말로는 한 최대점 혹은 한 최솟점 혹은 1/2 주기이다.


방금 무엇을 배웠는지 요약하자면, we see that the upper frequency of a sampled sine wave is every other sample being a peak and a valley and the lower frequency bound is half a period of the sine wave which is just fitting in the number of samples we are looking at. But wait – wouldn’t this mean that while the upper frequency remains fixed, the lowest frequency would drop when we have more samples? 정확하다! 우리는 낮은 주파수에서 시작하기 때문에, 이 결과는 알 수 없는 컨텐트의 더 긴 신호를 합치길 원할 때 더 많은 사인 파형을 필요로 하게 될 것이다.

모든것이 순조롭다. 그러나 여전히 결과적으로 얼마만큼의 사인 파형이 필요한지는 알 지 못했다. 이제 낮은 주파수나 높은 주파수의 사인 파형의 일부분을 알 수 있음으로써, 우리는 이 두 한계치 사이에서 얼만큼이 맞는지 계산할 수 있다. 우리는 극좌에서 극우까지 사이에서 가장 낮은 사인파형을 넣었어야 하기 때문에, 다른 모든 사인 파형 뿐만 아니라 nails까지 필요로 한다(왜 저렇게 다르게 다루고 있는가? 모든 사인파형은 같게 만들어지기 때문!). 단지 기타에서 두 고정된 점이 연결되 있는 현을 사인파형이라고 상상해보아라. 현은 두 고정된 점 사이에서만 진동할 것이다(부서지지 않는한), 우리의 사인 파형과 닮았다. 우리가 다루고 있는 1000 샘플에서 가장 낮은 1/2 주기를 가진 부분, 1주기를 가진 두번째 부분, 1과 1/2(1.5)주기를 가진 세번째 부분의 관계를 도출해낸다.

그림으로 그려보면 아래와 같다.


이제 1000샘플에서 얼마나 많은 사인파형이 적당한가를 물어본다면, 정확히 1000개의 사인 파형이 필요하다고 답해주면 된다. 사실 우리는 항상 가지고 있는 샘플의 수에 따라 사인파형이 필요하다는 것을 발견할 것이다.




WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,

원문 : Mastering The Fourier Transform in One Day
Posted by Bernsee on September 21, 1999


Step 2 : 푸리에 변환에 대해 이해하기
Jean-Baptiste Joseph Fourier(푸리에씨)는 부모가 그를 자랑스러워하거나 부끄러워하거나 하는 둘중 하나의 아이였다, 그는 14살때 굉장히 어려운 수학 용어를 막 말하기 시작했다. 비록 그는 일생동안 어마어마하게 많은 중요한 일을 했지만, 가장 중요한 일은 물질에 관한 열 전도를 알아냈다는 것일 것이다. 그는 열이 중간 온도를 맞추기위해 어떻게 움직이는지에대한 방정식을 만들어내고, 삼각함수의 무한급수에 관한 이 방정식을 풀었다(우리가 논쟁하고 있는 사인 코사인). 우리의 주제와 연관지어서 생각해보면, 기본적으로 신호는 복잡하지만 푸리에는 신호가 사인 함수의 합으로 이루어져있고 그것을 합치면 신호가 된다는 것을 알아냈다.


저기 보이는 그래프는 원본 신호이며, 이것은 어떻게 특정 관계로 합쳐진 사인들로인해 비슷한 모양이 되는지 보여준다. 이제 잠시 레시피(recipe)에 대해 이야기 해보자. 당신도 볼 수 있드시 사인함수가 많을 수록 원본 파형에 가깝데 결과가 나타난다. '현실 세계'에서는 당신의 측정장비로는 한계가 있는 극한의 작은 텀으로 측정이 가능할 것이고, 당신은 얻은 신호로부터 무한히 많은 사인 함수를 뽑아내고 싶을 것이다. 불행히도, DSPers로써 우리는 그 세계에 살고 있지 않는다(이상 세계에 살고 있지 않다는 뜻인듯). 오히려, 우리는 일정 간격과 무한하지 않는 정밀도로 측정된 "현실세계"의 셈플을 다루고 있다. 그러므로 우리는 무한히 많은 사인함수는 필요 없고, 그냥 '많다' 싶을 정도만 있으면 된다. 또 우리는 '많다는게 얼만큼이냐'고 되물을 수 있는데 다음 단락에서 알려주겠다. 한 순간동안, 모든 신호는 당신의 컴퓨터가 단순한 사인 파형으로 합쳐서 형상화할 수 있다는 것이 중요하다.(For the moment, it is important that you can imagine that every signal you have on your computer can be put together from simple sine waves, after some cooking recipe.)


WRITTEN BY
tucan.dev
개인 iOS 개발, tucan9389

,