Browse Category

번역글

Psychological Safety – 1편 Unsafety Signals

마틴 파울러의 한 마디 : 심리적 안전감이 없는 팀은 성과를 내지못한다.

그리고 위험 신호와 개선 방법에 대한 글을 하나 소개해주네요.
Psychological-Safety

이 글은 위의 링크를 나름대로 정리한 글입니다.

성공적인 팀의 가장 중요한 지표는 Psychological Safety!

당신의 팀은 아래의 다섯 질문에 얼마나 동의하시나요?
많이 동의할수록 Unsafety한 것입니다.
1. 만약 기회를 얻은 사람이 실패했다면 비난 받을 것이다.
2. 우리팀은 새로운 멤버가 합류하기 어려운 강한 문화를 가지고 있다.
3. 우리팀은 곤란을 겪고 있는 사람을 돕는데 소극적이다.
4. 나의 기술과 재능을 활용하는 것은 팀의 목표보다 후순위이다.
5. 팀의 민감한 이슈에 대한 공개된 솔직한 대화(open honest conversations)는 불편하다.

Unsafe team의 영향력을 가상의 신입사원 카렌의 사례로 설명해줍니다.
카렌은 분산 데이터베이스의 low-level locking 줄여줄 방법을 찾았고 테스트 결과 15%의 CPU를 절감할 수 있었기에, 제품(production) 환경에도 적용하기로 마음 먹었스비다. 데이터베이스 설정 파일을 수정하면 끝이었기 때문에 코드리뷰를 받을 필요도 없었습니다. 하지만 안타깝게도 서비스 전면 장애가 짧게나마 발생했고, 동료가 문제를 발견해서 10분 이내로 원복할 수 있었습니다.

안전하지 못한 팀은 변화를 받아들이지 못하기에 망하거나 급격히 저성과를 낼것이다.

“If I take a chance, and screw up, it’ll be held against me”
주간 포스트 모텀에서 이 사고는 다루어지게 되고 엔지니어링 디렉터는 약간의 성능을 향상시키기 위해 전면 장애를 내는 것은 받아들일 수 있는 일이 아니며 그녀를 무책임한 사람으로 몰아갔습니다. 그리고 그녀는 절대로 이 일을 잊지못할 것이고 다시는 시스템을 개선하기 위해 노력하지 않을 것입니다.

“Our team has a strong sense of culture, and it’s hard for new people to join”
카렌이 받은 충격은 아무도 그녀를 옹호해주지 않았기 때문에 더욱 커졌습니다. 아무도 데이터베이스 설정 파일의 변경에 대한 코드리뷰가 없는 것을 언급하지 않았으며, 무책임한 행동과 무책임한 사람의 차이에 대해서 언급하지 않았습니다. 그 팀은 그들이 만든 시스템의 신뢰성(reliability)에 대한 자부심을 느끼고 있었으며, 그들의 명성을 지키는 것이 신입 사원보다 훨씬 더 중요했습니다.
카렌이 배운 것은 그녀의 팀과 매니저가 그녀를 돌봐주지 않는다는 것이었습니다.

“My team is slow to offer help to people who are struggling”
카렌은 제품(production)에는 처음이기에, 사고 대응이나 제품 안정성(production hygiene)에 대한 공식적인 교육을 받지 않았으습니다. 분산 시스템에 대한 문제해결은 고사하고. 그녀의 팀은 경력자로 구성되었기 때문에 트레이닝이나 신규입사자 문서가 필요가 없었습니다. 또한 카렌과 같은 신규입사자가 이러한 기술을 배우는데 시간을 보내도 된다는 지침(signal)도 없었습니다.

카렌은 가면 증후군(Imposter Syndrome: 자신의 성공이 노력이 아니라 순전히 운으로 얻어졌다 생각하고 지금껏 주변 사람들을 속여 왔다고 생각하면서 불안해하는 심리이다.)에 시달렸고, 어떻게 그녀가 입사할 수 있었는지 이해할 수 없었으며 왜 자신이 아직까지 해고되지 않는지 종종 생각하게 되었습니다.

“Using my unique skills and talents come second to the goals of the team”
카렌은 알고리즘, 자료구조, 그리고 분산 컴퓨팅을 전공했으며, 시스템이 전체적인 관점에서는 최적화되지 않았으며 부하 급증을 결코 처리하지 못할 것이라는 것을 깨달았습니다. 팀은 항상 고객이 계약보다 더 많이 사용한다며 비난했으며 이것은 마치 바베큐를 할려는데 왜 비가 오냐고 기상예보를 비난 하는 것과 같습니다.

카렌은 새로운 설계를 제안했지만, 동료들은 친숙하지 않는 새 기술을 리스크로 간주했으며 토론도 해보지 못하고 포기해야 했습니다. 카렌은 코드를 작성하고 시스템을 만들기를 원했지만 무의미한 논쟁은 원치 않았습니다.

“It’s uncomfortable to have open, honest conversations about our team’s sensitive issues”
대규모 고객 트레픽 증가가 몇 시간의 장애를 일으켰을 때, 카렌은 지금의 설계로는 절대로 문제를 해결할 수 없고 자신의 설계에 대해 말했지만 엔지니어링 디렉터는 카렌의 설계는 이미 엔지니어링 리뷰에서 기각되었다고 말했습니다.
이후에 카렌은 팀 동료에게 그 디렉터의 설계가 문제라는 것을 이해하지 못한다고 말했지만, 그 팀동료는 어깨를 으쓱이며 지금까지 잘해왔다고만 말할 뿐이었습니다.

카렌은 칼퇴하고 새로운 일자리를 찾아 떠났고, 회사는 그녀를 그리워하지 않았고 그녀를 무모하고, 불평하고 그리고 권위에 대항하는 사람으로 남게 되었습니다. 그리고 그들은 그녀의 설계가 반복되는 장애에 의한 고객 탈출을 막을 수 있는 설계라는 것을 결코 깨닫지 못했습니다.

어떻게 Psychological Safety를 만들 것인가는 2부에서 계속됩니다.
How to build psychological safety into your own team
We need to balance respect for our culture, with an openness to change it as needed.

[hotjar] Questions-love-to-ask-users 일부번역

https://www.hotjar.com/blog/2016/03/05/questions-love-to-ask-users/#E-commerce

  • 리딩 포인트 : 드라이버, 배리어, 훅 중 무엇을 얻고자 하는 질문인지 생각해보자.

E-commerce
구매전
– 어떤 정보가 누락되었는가? 혹은 어떤 정보가 구입 결심을 쉽게 만드는가?
– 이 아이템을 구입할 때 무엇이 가장 큰 불안(fear)과 우려(concern)인가?
– 오늘의 방문 목적을 달성(complete)할 수 있었는가?
– 만약 오늘 구입을 하지 않았다면, 무엇이 당신을 포기(stop)하게 만들었는가?

구매후
– 결제(checkout) 프로세스에서 개선해야 할 곳은 어디인가?
– 우리 사이트에서 상품을 구입하는데 가장 큰 불안과 우려는 무엇인가?
– 아이템을 구입하도록 유혹한(persuade) 요소는 무엇인것 같은가?
– 만약 더 이상 서비스를 사용할 수 없게 된다면, 가장 아쉬울 것 같은 기능 하나는 무엇인가?

그 외 좋은(great) 질문들
– 가자고를 지인들에게 추천할 확률은 얼마나 되는가? (NPS 질문, 상세내용 => http://book.naver.com/bookdb/book_detail.nhn?bid=7851521)
– 가자고는 몇점(1 – 10)?

‘핫자르’로 웹사이트 최적화하기 – 액션 플랜 가이드

Translated by Dongho Kang@LeisureQ

이 문서는 (주)레저큐의 웹서비스 가자고핫자르를 도입하고자, 영문으로 되어있는 hotjar action-plan 문서를 한국어로 번역한 것입니다. 번역은 2016년 8월 22일자 문서를 기준으로 하며 의역, 오역이 있을 수 있습니다. 어색한 부분이나 변경된 부분을 발견하시면 피드백 부탁드립니다.


‘핫자르’로 웹사이트 최적화하기

웹사이트 방문자들이 실제로는 어떻게 웹사이트를 이용하고 있는지 확인해보세요 – 당신의 비지니스가 성장할 수 있는 가장 ‘핫한 기회’ 하태핫태!를 발견할 수 있을 것입니다.

이 문서에서는 다음의 내용을 다룹니다.

A: 어떻게 드라이버(Driver – 몰이꾼)와 배리어(Barrier – 장벽)와 훅(Hook – 갈고리)을 이용해서 웹사이트의 ‘큰 그림(Big Picutre)’을 볼 수 있는지
B: 오늘 당장! 당신의 웹사이트를 개선할 수 있는 아홉 단계의 쉽고 간단한 핫자르(Hotjar) 액션 플랜.

시중에는 많은 데이터 분석 툴들이 있지만 대부분의 툴들이 쓸데없이 데이터들을 무수히 늘어놓기만 할 뿐 효과적인 의사결정을 오히려 방해하고는 합니다. 오로지 핫자르 만이 당신에게 ‘핫한 기회’를 선사합니다. 저희가 주의깊게 골라 만든 핫자르 도구세트는 웹사이트 방문자들이 무얼 하고 있는지 (관련도구: 힛맵 (Heatmaps), 방문자 인터랙션 다시보기 (Visitor Playback), 퍼넬 (Funnel)) 그리고 왜 그 일을 하고 있는지 (관련도구: 피드백 투표(Feedback Polls), 서베이 (Surveys), 사용자 테스터 채용하기 (Recruit User Testers))보여줄 것입니다.

핫자르 액션플랜은 단기간에 큰 임팩트를 줄 수 있는 테스트나 변화를 만들 수 있도록 도와줌으로써 당신에게 멋진 기회들을 가져다 줄 것입니다. 하지만 액션플랜을 살펴보기 이전에 당신은 먼저 웹사이트의 진정한 ‘큰 그림’을 볼 수 있어야 합니다.

A. ‘큰 그림’ 보기

체스를 두고 있는 상황을 상상해봅시다. 말을 이동시키기 전에 당신은 우선 전체 판의 흐름을 볼 수 있어야 합니다. 웹사이트를 운영하는 것도 크게 다르지 않습니다. 당신이 진정으로 웹사이트의 ‘큰 그림’을 보지 못한다면 페이지를 바꾸거나 새로운 테스트를 만드는 것은 아무런 의미가 없습니다.

당신이 이 ‘큰 그림’을 보기 위해선 세가지를 알고 있어야 합니다.

a_1_hotjar_way.png
드라이버, 배리어, 훅은 ‘큰 그림’을 볼 수 있게 해줍니다.

1. 드라이버 – 방문자들의 의도를 알아내기

드라이버: 몰이꾼 정도로 번역 가능합니다. 방문자들을 움직이게 하는 동인, 그들의 의도에 대한 비유적 표현이라고 생각할 수 있습니다. 역주.

당신의 방문자들에게 그들이 무엇을 찾고 있는지, 그들이 왜 그것을 원하는지를 ‘그들만의 언어’로 표현하도록 부탁해보세요. 그들의 대답은 강력한 인사이트를 가져다 줄 것입니다. 그리고 그들이 이용하고 있는 언어와 정확하게 같은 언어를 이용하도록 노력하세요. (사용자들이 웹사이트에 대해 사용하는 용어, 단어와 웹사이트를 운영하는 이들이 사용하는 용어, 단어가 완전히 같아야 한다는 것을 의미합니다. 역주) 그렇게 되면 방문자들은 웹사이트의 컨텐츠와 인터페이스, 그리고 웹사이트가 제공하는 사용자 경험(UX: User Experience)에 친근함을 느끼게 될 것입니다. 뿐만 아니라 사용자들의 의도를 이해하게 되면 중요한 셀링 포인트에 더 높은 우선순위를 둘 수 있게 됩니다.

이상의 과정을 다 끝냈다면, 마지막으로 방문자들에게 어디에서 당신의 웹사이트에 대해서 알게 되었는지 물어보세요. 이 것은 당신이 새로운, 혹은 생각치도 못했던 채널을 발견하고 이를 통해 성장할 수 있도록 해줄 것입니다.

드라이버 사용의 예:

  • 어느 한 소프트웨어 리뷰 사이트에서는 대다수 방문자들이 자신이 스타트업에 속해있고, 그 이전까지 자신들이 찾고 있던 소프트웨어를 한번도 사용해보지 못했다는 것을 고백했습니다. 이런 정보를 토대로 웹 사이트의 주인은 소프트웨어의 인트로 가이드를 서비스하고 스타트업을 타게팅하는 새로운 전략으로 잠재 고객들을 발굴해낼 수 있었습니다. (원문에서는 리드(Lead) 제너레이션을 증가시킨다는 표현을 썼습니다. 리드 제너레이션이란 지금 구매하지 않더라도 이후에 상품을 구매할 가능성이 높은 잠재 고객들을 발굴해내는 마케팅 기법을 의미합니다. 역주.)

  • 헤드폰은 판매하던 한 이커머스(e-commerce) 사이트는 한 음악 포럼(게시판)에 그들의 제품에 대한 내용이 올라와 있는 것을 발견했습니다. 이들은 이 포럼이 매우 효과적인 광고 채널이 될 수 있다는 것을 깨닫게 되었습니다.

드라이버를 보여주는 핫자르 도구들:
투표하기(Polls), 서베이(Surveys), 사용자 테스터 채용하기(Recruit User Testers)

2. 배리어(장벽) – 장벽이 높은 단계를 찾아내세요.

방문자들이 자꾸 웹사이트를 떠나는데 어디서 방문자들이 떠나는지, 그리고 왜 그들이 떠나는지 이해하지 못 한다면 웹사이트의 경험성과 핵심 요소들을 절대 개선할 수 없습니다. 이젠 더 이상 생각나는대로 버튼을 바꾸거나 페이지 레이아웃을 바꾸지 마세요. 그 대신, 웹사이트의 경험성을 가로막고 있는 장벽이 어디에 있는지 먼저 주의깊게 살펴보세요.

항상 가장 큰 장벽에 제일 먼저 초점을 맞추세요. 당신의 가장 ‘핫한 기회’는 언제나 가장 트래픽이 많이 발생하는, 그리고, 가장 이탈이 많이 발생하는 페이지(혹은 단계)에서 생겨납니다. 바로 그 지점에서부터 시작해보세요 🙂

배리어 이용의 예:

  • 클라우드 호스팅 서비스는 떠나는 고객들이 대부분 월 이용요금이 너무 비싸다고 느낀다는 것을 알게되었습니다. 이런 깨달음을 엊고 나서 그들은 왜 이용 요금이 경쟁 서비스보다 높은지 합리적으로 설명하는데 많은 리소스를 투자했고, 경쟁서비스들이 사실은 ‘눈에 보이지 않는 숨겨진 비용’을 추가로 만들어 낸다는 사실을 알렸습니다. 이를 통해 이들은 더 많은 사용자들을 모을 수 있었습니다.

  • 꽃을 파는 한 이커머스 사이트는 고객들이 체크아웃 페이지에서 브랜드에 대해 신뢰하지 못해 계속 이탈한다는 것을 발견했습니다. 그들은 고객의 신뢰를 얻기 위해서 사용자 리뷰의 중요성을 높이고 자신들의 웹 서비스가 신뢰할 만한 사이트로 선정되었다는 것을 알리는 로고(‘featured in’ logos)를 페이지 상단에 높이 배치했습니다.

  • 어떤 SaaS 툴 (Software as a Service: 고객들이 인터넷을 통해서 접근할 수 있는 소프트웨어 어플리케이션을 의미. 클라우드 서비스 종류의 하나. 역주)을 이용하는 고객들은 오랫동안 회원가입과 로그인 화면을 자주 혼동해왔습니다. 이 사실을 안 운영자들은 제목과 레이블을 바꾸었고, 사용자들의 이탈률을 현격하게 줄일 수 있었습니다.

배리어를 보여주는 핫자르 도구들:
힛맵(Heatmaps), 사용자 인터랙션 다시보기(Visitor Playback), 전환 퍼넬(Conversion Funnels), 피드백 투표(Feedback Polls), 서베이(Surveys), 사용자 테스터 채용하기(Recruit User Testers).

3. 훅 – 설득력있는 요소들을 찾아내기

훅: 갈고리를 의미합니다. 여기선 사용자들을 갈고리에 걸어서 끌어당길 수 있는 요소들을 비유적으로 표현했습니다. 역주.

당신의 웹사이트를 방문하는 고객들이 진정으로 구매하는 것은 무엇입니까? 그들이 정말 제품이나 서비스를 구매하고 있습니까? 그들이 당신이 제공하는 새로운 라이프 스타일에 돈을 내고 있습니까?

당신의 고객들, 그리고 잠재적인 고객들을 진정으로 설득하고 있는 것이 무엇인지 이해하는 것이 바로 더 많은 고객들을 끌어들일 수 있는 가장 빠른 방법입니다. 이런 이해가 그들을 어떻게 지속적으로 방문하게 할 수 있을지, 어떻게 더 많이 방문하게 할 수 있을지 깨닫게 해줄 것입니다.

훅을 보여주는 핫자르 도구들:
투표하기(Polls), 서베이(Surveys), 사용자 테스터 채용하기(Recruit User Testers).

B. 핫자르 액션 플랜의 9가지 스텝

  1. 트래픽이 높거나, 반송률 (웹사이트에 접속한 뒤 첫 페이지에서 다른 페이지로 이동하지 않고 바로 나가는 비율. 역주.)이 높은 페이지에 힛맵(Heatmap)을 세팅하세요.
  2. 트래픽이 높은 랜딩 페이지에 피드백 투표하기(Feedback Polls) 기능을 이용해서 ‘드라이버(Driver)’들을 발견하세요.
  3. 이메일을 통해서 고객 서베이(Survey)를 하세요.
  4. 퍼넬(Funnel)로 웹사이트의 가장 큰 배리어가(Barrier) 뭔지 확인하기.
  5. 배리어 페이지들에 피드백 투표(Feedback Polls) 세팅하기.
  6. 힛맵을 베리어 페이지에 세팅하기.
  7. 방문자 인터랙션 다시보기(Visitor Playback)로 배리어 페이지의 어느 지점에서 방문자가 떠나는지 확인하기.
  8. 사용자 테스터 채용하기(Recruit User Testers)로 드라이버와 배리어 발견하기.

1. 트래픽이 높거나, 반송률이 높은 페이지에 힛맵(Heatmap)을 세팅하세요.

  • 왜 하나요?: 트래픽이 높거나 반송률(bounce rate)이 높은 페이지들은 더 많은 사용자들을 끌어들일 수 있는 가장 큰 기회들을 가지고 있습니다. 이런 페이지들에 힛맵을 세팅하면, 방문자들이 웹페이지에 어떻게 묶이게 되는지, 어떻게 하면 계속 더 많은 방문자들을 끌여들여야 할지 깨달을 수 있습니다.
  • 어떻게 하나요?: 트래픽이 높은 페이지에 힛맵을 설정하고 ‘quick 8 Hotjar Heatmap tests’ 를 실행하세요. 당신의 웹페이지에서 가장 흔하게 발생하는 문제가 무엇인지, 해결책은 무엇인지 알려줄 것입니다.

b_1_hotjar_move_heatmap.png
핫자르의 힛맵은 방문자들의 행동을 보여주고, 반송률을 낮출 수 있는 힌트를 줄 것입니다.

2. 트래픽이 높은 랜딩 페이지에 피드백 투표하기(Feedback Polls) 기능을 이용해서 ‘드라이버(Driver)’들을 발견하세요.

  • 왜 하나요?: 당신의 가장 큰 방문자 풀을 인터뷰함으로써, 방문자들이 당신의 웹사이트를 방문하는 이유가 뭔지 알 수 있게 될 것입니다. 방문자들이 당신의 사이트를 방문하는 이유를 점점 더 깊이 파보세요. 만약 당신이 게임 사이트를 운영한다면, 게이머들이 게임을 하는 동기가 무엇인지 물어보는 것이 여기에 해당할 것입니다. (돈을 위해서? 재미를 위해서? 아니면 친목도모를 위해서?) 이런 과정은 당신의 사이트 디자인과 텍스트를 좀 더 연관성있게, 또한 좀 더 설득력 있게 만들 수 있도록 도와줄 것입니다.
  • 어떻게 하나요?:
    1. “[서비스 혹은 상품]을 찾는 이유가 무엇인가요?”
    2. “이 페이지에서 빠져있는게 있을까요?”
    3. “처음에 우리에 대해서 알게 되었을때 어떤 얘기들을 들으셨나요?”
  • 방문자들이 정해져있는 답들을 고르도록 강제하지 마세요. 그 대신에 자유롭게 답을 서술 할 수 있도록 해주세요. 그리고 답변들을 이용해서 ‘드라이버’ 워드 맵을 만들어보세요. 아래에는 핫자르 팀이 Hotjar.com 을 방문하는 방문자들을 대상으로 “간단한 질문 – 핫자르가 어떻게 당신의 삶을 더 쉽고, 더 낫게 만들어주고 있나요?” 라는 질문을 던지고 그 응답으로 만든 워드 맵입니다. This should not replace reading carefully through all responses you receive.

b_2_hotjar_feedback_cloud.png
‘드라이버’ 워드 맵은 방문자들이 당신의 웹사이트를 방문하도록 만드는 것이 무엇인지 보여주는 가장 좋은 방법입니다.

3. 이메일을 통해서 고객 서베이(Survey)를 하세요.

  • 왜 하나요?: 어쩌면 드라이버, 배리어, 훅을 한번에 찾는 가장 좋은 방법은 당신의 고객들에게 직접 답을 얻는 것일지도 모릅니다.
  • 어떻게 하나요?: 다음 4개의 open ended 질문을 포함한 서베이를 만드세요.
    1. “당신이 [서비스 혹은 상품]을 찾게 된 동기는 무엇입니까? 이 것이 당신의 삶을 어떻게 개선할 수 있을지 가능한 자세히 설명해주세요.”
    2. “당신이 [액션 e.g. 구매 / 가입]을 하게 만든 것은 무엇이었습니까? 생각나는대로 적어주세요.”
    3. “당신의 결정을 돕기 위해 저희가 할 수 있는 일이 무엇이 있을까요?”
  • 가치있다고 생각되는 질문들을 좀 더 추가하세요. 하지만 7, 8개를 넘지는 마세요. 아래가 좋은 예가 될 수 있습니다.
    1. “당신이 어떤 사람인지 알려주실 수 있으신가요? e.g. 저는 30살의 차와 포커 도박? 를 사랑하는 남성 디자이너입니다”
    2. “친구분들에게 저희 서비스를 소개해주신다면 어떻게 소개할 수 있을까요?” (이런 질문은 당신의 웹사이트를 위한 훌륭한 추천사가 될 수 있습니다!)
  • 답변을 해주시는 사용자들에게 추첨을 해서 선물을 주는 것이 많은 답변을 이끌어내는 인센티브가 될수 있습니다. (짧은 데드라인을 만들면 빠른 답변을 얻는데 도움이 됩니다.)

b_3_hotjar_survey.png
고객 서베이는 드라이버와 배리어와 훅을 한번에 알려주는 좋은 수단입니다. 이것은 핫자르에서 사용할 수 있는 가장 가치있는 툴중 하나입니다.

4. 퍼넬(Funnel)로 웹사이트의 가장 큰 배리어가(Barrier) 뭔지 확인하기.

퍼넬: 직역하면 깔때기라는 뜻입니다. 왜 깔때기라고 하는걸까요? 여기에서는 가장 트래픽이 높은 페이지에서부터 방문자들이 어떤 페이지로 흘러가는지 추적하는 통로의 역할을 하기 때문에 깔때기라는 단어를 사용하는 것 같습니다. 역주.

  • 왜 쓰나요?: 우리는 한번에 바꾸기엔 지나치게 많은 부분을, 과도하게 많이 바꾸려고 하곤 합니다. 이런 실수를 막기 위해서 핫자르에서는 퍼넬(Funnel)이라는 툴을 이용합니다. 퍼넬을 만들면 가장 방문자들을 많이 잃어버리게 되는 곳이 어디인지, 그리고 어떻 작업을 가장 먼저 해야하는지 쉽게 인지할 수 있게 됩니다.
  • 어떻게 쓰나요?: 퍼넬 사용에서 가장 중요한 것 중 하나는 퍼넬을 ‘뒷쪽으로 쭉 이어서’ (원문엔 ‘backward’라고 써놨습니다. 역주) 만들어 놓는 것입니다. 먼저 당신에게 가장 중요한 목표가 무엇인지 스스로에게 한번 물어보세요. 회원가입입니까, 아니면 주문입니까? 이 질문에 대한 나름의 답을 얻었다면 가장 트래픽이 많이 몰리는 페이지에서부터 뒷쪽으로 쭉 퍼넬을 심어두세요. 일반적인 규칙은 당신이 웹사이트에 세운 각각의 목표 지점마다 퍼넬을 세팅해놓는 것입니다.
  • 각 퍼넬은 당신이 만들어놓은 퍼넬에 ‘첫 발자국’을 남긴 방문자들의 데이터만 보여주게 될 것입니다. 따라서, 만약 당신의 웹사이트에서 주로 트래픽을 발생시키는 소스가 2개라면 (이를테면 홈페이지와 랜딩 페이지) 각 소스를 분리하여 퍼넬을 만들어 놓는 것이 좋을 것입니다.
  • 아래가 퍼넬의 용례입니다.
    • 이커머스: 홈페이지 > 상품 페이지 > 카트 > 결제 > 결제완료 페이지
    • 뉴스나 블로그: 홈페이지 > 기사 페이지 > 구독 페이지 > 구독완료 페이지
    • 웹앱: 홈페이지 > 체험판 등록하기 페이지 > 인터페이스(웹앱) > 업그레이드 페이지 > 업그레이드 완료 페이지
    • 리드 제네레이션: 카테고리 페이지 > 양식을 포함한 랜딩 페이지 > 완료 페이지 (리드 제너레이션이란 지금 구매하지 않더라도 이후에 상품을 구매할 가능성이 높은 잠재 고객들을 발굴해내는 마케팅 기법을 의미합니다. 역주.)

b_4_hotjar_funnel.png
가장 배리어가 높은 지점에서 부터 조사해보세요. 위의 이미지에서는 ‘랜딩 페이지’ 단계가 이에 해당합니다.

5. 배리어 페이지들에 피드백 투표(Feedback Polls) 세팅하기.

  • 왜 하나요?: 이쯤이면, 지금 당신의 웹사이트에서 가장 많은 방문자들을 잃고 있는 곳이 어딘지 알게 되셨을 겁니다. 이젠 그들이 떠난 이유에 대해서 들어볼 시간입니다.
  • 어떻게 하나요?: 방문자들을 잃고 있는 페이지들을 타겟으로 피드백 투표를 만드세요. 이 투표는 방문자가 페이지를 나가려고 할때, 혹은 방문자가 페이지의 절반 정도를 스크롤해서 내려봤을 때 뜨도록 설정됩니다. 만약 응답률이 충분하지 않다면 웹 페이지를 들어오고 10초 후에 투표가 뜨도록 설정을 변경하세요.
  • 질문 템플릿은 3가지입니다.
    1. “간단한 질문 – 만약 당신이 [액션 e.g. 가입 / 구매]을 하지 않기로 결정했다면, 무엇이 당신을 멈추게 한 요소였나요?”
    2. “간단한 질문 – 우리 웹사이트에 대해서 걱정하고 있거나 신뢰하지 못하고 계신 부분이 있나요?”
    3. “간단한 질문 – 우리 페이지에 어떤 것이 빠져있다고 느끼시나요?”
  • 효과적인 결과를 얻기 위해서 위의 질문 타입들을 번갈아 가면서 내보내도록 설정하는 것을 고려해보세요.

b_5_hotjar_feedback_poll.png
가장 배리어가 높은 페이지에 피드백 투표를 만들어 놓으면 해당 페이지에 있어서 당신이 그동안 간과했었던 이슈가 무엇인지, 고객들이 가장 우려하고 있는 것이 무엇인지 알 수 있게 됩니다.

6. 힛맵을 베리어 페이지에 세팅하기.

  • 왜 하나요?: 이탈율이 높은 페이지에 힛맵을 생성하면 굉장한 인사이트를 얻을 수 있습니다. 힛맵은 방문자들이 어떻게 페이지와 인터렉션(상호작용: 클릭, 탭, 마우스 움직임, 스크롤…)하고 있는지 빠르게 가시화해줍니다. 이는 곧 방문자들이 진정 보고 있는 것이 무엇인지, 그들이 무시하고 있는 것은 무엇인지 알 수 있게 해줄 것입니다. 이런 정보들은 테스트를 만들거나, 페이지를 개편하는데 큰 도움이 됩니다.
  • 어떻게 하나요?: 힛맵이 세팅되고 나면, ‘quick 8 Hotjar Heatmap tests’를 사용해 가장 흔하게 발생하는 문제는 무엇인지, 해결책은 무엇인지 찾아보세요.

b_6_hotjar_scroll_heatmap.png
당신의 방문자들이 무엇을 보고 있는지, 핫자르 힛맵을 이용해 확인하세요.

7. 방문자 인터랙션 다시보기(Visitor Playback)로 배리어 페이지의 어느 지점에서 방문자가 떠나는지 확인하기.

  • 왜 하나요?: 방문자 인터랙션 다시보기는(Visitor Playback) 방문자의 신발에 작은 카메라를 달아 놓는 것이라고 이해하면 됩니다. 웹사이트를 떠난 고객의 녹화된 화면을 되돌려보면 당신의 페이지에 방문자가 어떻게 반응했는지 확인할 수 있게 됩니다. 혹시 방문자들이 어떤 단계에 정체되어 있지는 않은가요? 혹시 그들이 페이지를 너무 빨리 떠나고 있지는 않은가요?
  • 액션플랜 5와 액션플랜 6을 통해서 우리는 투표하기와 힛맵을 사용한 결과를 얻게 되었습니다. 이제는 ‘방문자의 관점에서 보기’에 대해서 잘 이해하게 되셨을 겁니다. 방문자의 관점에서 그들에게 ‘공감(empathizing)’함으로써 더 나은 의사결정을 내리고, 배리어가 높은 페이지를 어떻게 바꾸어야 할지, 어떤 테스트를 만들어야할지 깨닫게 될 것입니다.
  • 어떻게 하나요?: 올바른 녹화 비디오를 찾기 위해선 검색 필터의 ‘EXIT PAGE’ 항목에 배리어가 높은 웹페이지의 URL을 입력하면 됩니다. 그리고 나서는 준비해놨던 팝콘을 뜯으시면 됩니다 🙂

b_7_hotjar_visitor_playback.png
방문자 인터랙션 다시보기는 방문자의 신발에 카메라를 달아놓고 웹사이트에서 그들의 관점으로 경험성을 파악할 수 있게 해줍니다.

8. 사용자 테스터 채용하기(Recruit User Testers)로 드라이버와 배리어 발견하기.

  • 왜 하나요?: 사용자 테스팅은 사용자들이 당신의 웹사이트를 이용하는 동안 그들을 관찰하고 그들의 행동을 코멘트하는 과정입니다. 이 단계에서 당신은 이미 대강의 ‘큰 그림’을 그리게 되었을 것입니다. 하지만 사실, 그 어떤 작업도 사용자 한명, 한명을 인터뷰하고 상대하는 것만 못할 것입니다. 이런 작업은 꽤나 공수가 많이 들고 지루할 것 처럼 보이지만 생각보다 꽤나 즐겁고 또 굉장한 인사이트를 줄 수 있는 작업입니다.
  • 어떻게 하나요?: 가장 트래픽이 많이 발생하는 랜딩 페이지에 리크루팅 양식(recruit form)을 세팅하세요. 이 프로그램에 참여하는 방문자들에게는 약간의 인센티브를 제공할 수 있어야 합니다. (e.g. 무료 컨텐츠, 현금 혹은 아직 출시하지 않은 특정 기능에 대한 우선권 등)
  • 채용할 사용자를 선택하세요 – 5명 정도의 사용자 테스터를 채용하는 것으로도 충분합니다. 그들에게 이메일을 통해서 연락하고 ‘화면 공유’를 할 날짜와 시간 약속을 잡으세요. 화면 공유를 하기 위해서 스카이프(Skype)나 고투미팅(GoToMeeting), 구글 행아웃(Google Hangout) 같은 미팅 툴을 이용할 수도 있을 것입니다.
  • 목표를 준비하고, 완료하고자 하는 단계들을 나열해보세요. 숨겨진 장벽들을 확인하기 위한 몇개 질문들을 준비하는 것도 좋을 것입니다.

b_8_hotjar_recruit_user_testers.png
화면 공유를 통한 사용성 테스트를 위해 방문자와 사용자들을 채용하세요.

b_8_usability_graph.png
5명의 유저 테스트 만으로도 80%의 문제들을 잡아낼 수 있을 것입니다. (출처: Jakob Nielsen)

9. 가장 성공적인 페이지에서 피드백 투표로 ‘훅(Hook)’을 발견하기

  • 왜 하나요?: 좀 더 방문자들을 많이 끌어들이고 싶다면, 사용자들에게 그들을 설득했던, 그들에게 모티베이션이 된 요소들이 무엇이었는지 물어볼 필요가 있습니다. 이런 과정은 당신의 웹사이트에서 방문자들을 잡아당길 ‘훅’이 무엇인지 이해할 수 있게 해줄 것입니다. 뿐만 아니라, 이런 요소들을 강조하고 더 자세히 설명할 수 있도록 사이트를 개선할 수 있게 해줄 것입니다.
  • 어떻게 하나요?: 아래의 워드 클라우드는 핫자르의 ‘훅’에 대한 피드백 투표 결과를 보여주는 것입니다. 이 결과로부터 친구들의 추천과, 통합된 툴 세트, 그리고 핫자르의 가격 정책이 굉장히 설득력 있는 요소였음을 한눈에 알 수 있습니다. 저희는 이 요소들을 앞으로 핫자르가 만들 캠페인들에 포함시킬 뿐만 아니라, 이를 이용할 수 있는 제품들을 개발시킬 것입니다. (e.g. 대시보드(dashboard)에 추천인 정리해서 보여주기)

b_9_hotjar_feedback_cloud.png
핫자르의 ‘훅’을 보여주는 워드 클라우드(Word Cloud).


9 단계를 모두 마쳤습니다. 이제 뭘 해야하나요?

이제 당신의 사이트를 개편할 시간입니다. 참고로, 가능하다면 개편한 웹사이트와 이전 웹사이트의 트래픽을 나누어 변화의 영향에 대해서 테스트해보고 분석하는 것이 좋습니다.

개편된 웹사이트에서 방문자들의 드라이버, 배리어, 훅에 대해서 알고 싶다면, 다시 액션플랜 1으로 돌아가 아직 숨어있는 새로운 기회들을 찾아보세요!

제가 9 단계를 잘 마쳤는지 어떻게 알 수 있을까요?

  • 당신의 웹사이트가 방문자들의 드라이버와 잘 맞는지 확인해보세요. 방문자들이 이용하는 언어, 용어와 당신이 이용하는 언어나 용어가 일치해야 합니다. 또 사용자가 사이트에 도달하고나서 그들이 찾고 있는 것이 어디있는지 바로 발견할 수 있어야 합니다.
  • 방문자들을 우려하게 하고, 주저하게 하고, 그들의 사용성에 문제를 만드는 배리어들을 최소화했는지 살펴보세요. 웹사이트의 컨텐츠를 좀 더 명확하고 분명하게 만들었다면, 그리고 당신이 웹사이트를 어떻게 더 쉽게 이용하도록 할지 고민하고 있다면, 퍼넬을 통과하는 방문자들의 수가 늘어났다는 것을 확인할 수 있을 것입니다.
  • 방문자들을 끌어당기고, 그들을 효과적으로 설득할 수 있는 요소들을 지속적으로 사용함으로써, 훅의 효과를 극대화시키고 있는지 살펴보세요. 다시 한번 강조하지만, 당신은 고객들이 서베이에서 이용하는 언어나 단어들을 그대로 웹사이트에서 사용하고 있어야 합니다.
  • 위의 세 항목을 모두 달성했다면, 당신은 성공적으로 사용자 경험을 개선한 것입니다. 곧 사용자들이 예전보다 당신의 사이트에서 더 많은 시간을 보내고, 더 자주 방문하고 있다는 것을 확인할 수 있게 될 것입니다. 운이 좋다면 방문자들이 자신의 친구들에게 웹사이트를 추천할 수도 있겠죠 🙂

왜 자바에서 static의 사용을 지양해야 하는가?

자바에서 데이터를 가공하거나 특정 메서드를 수행할 때 새로운 클래스를 만들어서 이를 인스턴스화 해서 쓸건지 아니면 static 으로 쓸건지 고민하게 될 때가 있다. 사실 후자는 객체지향적 관점에서 그리 좋은 선택은 아니다. Vamsi Emani라는 프로그래머가 stack overflow에 남긴 질문 Why are static variables considered evil? 과 가장 많은 지지를 받은 두개의 답변을 번역했다.


Q by V. Emani

I am a Java programmer who is new to the corporate world. Recently I’ve developed an application using Groovy and Java. All through the code I’ve used quite a good number of statics. I was asked by the senior technical lot to cut down on the number of statics used. I’ve googled about the same, and I find that many programmers are fairly against using static variables.

저는 현업에 갓 뛰어든 자바 프로그래머입니다. 근래에 Groovy와 Java를 이용하는 어플리케이션을 개발하고 있습니다. 그동안 자바로 개발할 때 “static” 변수(그리고 static 메소드)를 꽤나 많이 이용하는 습관을 가지고 있었습니다. 근데 제 시니어는 static 의 개수를 줄이라고 말합니다. 그 이유가 궁금해서 구글에 검색을 해봤는데 많은 자바 프로그래머가 static 을 사용하는 것을 꺼린다는 것을 발견했습니다.

I find static variables more convenient to use. And I presume that they are efficient too (please correct me if I am wrong), because if I had to make 10,000 calls to a function within a class, I would be glad to make the method static and use a straightforward class.methodCall() on it instead of cluttering the memory with 10,000 instances of the class, right?

사실 저는 static 을 이용하는 것이 보다 편하고 효율적이라고 생각합니다. (제가 틀린 부분이 있으면 지적해주세요!) 어떤 클래스 내에서 만번의 함수 호출을 하게 된다면 그 함수를 static으로 만들어서 class.methodCall()의 형태로 사용하는 것이 만개의 인스턴스를 생성해서 메모리를 어지럽히는 것보다 훨씬 낫지 않을까요?

Moreover statics reduce the inter-dependencies on the other parts of the code. They can act as perfect state holders. Adding to this I find that statics are widely implemented in some languages like Smalltalk and Scala. So why is this oppression for statics prevalent among programmers (especially in the world of Java)?

PS: please do correct me if my assumptions about statics are wrong.

게다가 static 변수는 코드의 상호의존성(inter-dependency)을 줄여준다고 생각합니다. 상태를 저장하는데 있어서 static 변수들은 아주 유용하게 사용될 수 있습니다. 사실 static은 자바 뿐만 아니라 Smalltalk나 Scala 와 같은 프로그래밍 언어에서도 널리 이용되고 있습니다. 근데 왜 유독 자바 프로그래밍 세계에선 개발자들이 static의 사용을 꺼리는 걸까요?

PS: static 변수에 대한 제 생각에 틀린 부분을 지적해주시면 감사하겠습니다.


A by J. Skeet

Static variables represent global state. That’s hard to reason about and hard to test: if I create a new instance of an object, I can reason about its new state within tests. If I use code which is using static variables, it could be in any state – and anything could be modifying it.

Static 변수는 global state(역주: 전역 상태. 프로그램 혹은 한 모듈 전체의 상태)를 상징합니다. Global state는 추론과 테스트가 매우 까다롭습니다. 가령 코드에서 static 변수를 사용한다고 하면, 이 변수의 상태는 코드 여러 부분에서 영향을 받을 수 있게 되고 따라서 변화를 추적하기가 어려워집니다. 반면에 이를 객체화하여 인스턴스로 생성하면 테스트 중에 그 변수가 어떤 상태를 가지고 있는지 추론하는 것이 보다 간단해집니다.

I could go on for quite a while, but the bigger concept to think about is that the tighter the scope of something, the easier it is to reason about. We’re good at thinking about small things, but it’s hard to reason about the state of a million line system if there’s no modularity. This applies to all sorts of things, by the way – not just static variables.

프로그래머로서 제가 그동안 경험해온 바에 따르면 큰 개념에 대해서 그리기 위해선 일단 이해하고자 하는 범위를 좁혀 쉽게 추론할 수 있어야 합니다. 일반적으로 우리는 작으면 작을수록 그 대상을 쉽게 이해합니다. 다시 말해, 모듈화를 제대로 하지 않는다면 백만 줄 짜리 시스템의 상태에 대해서 추론하는 것은 굉장히 어려운 일입니다. 이것은 단순히 static 변수 뿐만 아니라 모든 프로그래밍 이슈에 대해서 적용할 수 있는 중요한 사실입니다.


A by A. Lockwood & J. Brown

Its not very object oriented: One reason statics might be considered “evil” by some people is they are contrary the object-oriented paradigm. In particular, it violates the principle that data is encapsulated in objects (that can be extended, information hiding, etc). Statics, in the way you are describing using them, are essentially to use them as a global variable to avoid dealing with issues like scope. However, global variables is one of the defining characteristics of procedural or imperative programming paradigm, not a characteristic of “good” object oriented code. This is not to say the procedural paradigm is bad, but I get the impression your supervisor expects you to be writing “good object oriented code” and you’re really wanting to write “good procedural code”.

첫째로, static은 객체 지향적이지 않습니다: 개발자들이 static 변수를 ‘악’으로 규정하는 이유는 static 변수가 객체 지향의 패러다임과 상반되기 때문입니다. 특히나 static 변수는, 각 객체의 데이터들이 캡슐화되어야 한다는 객체지향 프로그래밍의 원칙(역주: 한 객체가 가지고 있는 데이터들은 외부에서 함부로 접근하여 수정할 수 없도록 해야 한다는 원칙)에 위반됩니다. 질문자께서 스스로 설명했듯이 static은 스코프(역주: 한 변수가 유효한 범위)를 고려할 필요가 없는 경우, 즉 전역 변수를 사용할 때에 유용합니다. 이는 절차지향적 프로그래밍 혹은 명령형 프로그래밍(역주: C가 대표적인 절차지향적, 명령형 프로그래밍 언어이며 Java 역시 큰 범위에서 절차지향적, 명령형 프로그래밍 언어라고 할 수 있다.)에서 매우 중요한 개념입니다. 하지만 이 것이 객체지향의 관점에서 좋은 코드라고 얘기하기는 힘듭니다. 절차지향 패러다임이 나쁘다는 것이 아닙니다. 다만, 당신의 시니어는 당신이 “객체지향적으로 좋은 코드”를 짜기를 바라는 것입니다. 반대로 당신은 “절차지향적으로 좋은 코드”를 짜기를 원하는 것이라고 말할 수 있을 것입니다.

There are many gotchyas in Java when you start using statics that are not always immediately obvious. For example, if you have two copies of your program running in the same VM, will they shre the static variable’s value and mess with the state of each other? Or what happens when you extend the class, can you override the static member? Is your VM running out of memory because you have insane numbers of statics and that memory cannot be reclaimed for other needed instance objects?

사실 자바에서 static을 사용하기 시작하면 예측이 어려운 문제가 많아지게 됩니다. 예를 들어서 하나의 가상머신에서 어떤 프로그램 두 카피가 돌고 있다고 가정해봅시다. 만약 이 두 카피가 동일한 static 변수를 공유하게 된다면, 서로의 상태에 영향을 주게 되지 않을까요? 더불어서 오버라이딩을 할 수 없는 static 멤버들 때문에 클래스를 확장하는게 어려워질 것입니다. 뿐만 아니라 지나치게 많은 static 변수를 사용하게 되면 이들로부터 메모리 회수를 할 수 없어서 가상머신이 메모리 부족을 겪게 될 것입니다.

Object Lifetime: Additionally, statics have a lifetime that matches the entire runtime of the program. This means, even once you’re done using your class, the memory from all those static variables cannot be garbage collected. If, for example, instead, you made your variables non-static, and in your main() function you made a single instance of your class, and then asked your class to execute a particular function 10,000 times, once those 10,000 calls were done, and you delete your references to the single instance, all your static variables could be garbage collected and reused.

객체의 라이프타임: 추가로, static 변수는 프로그램이 실행되고 있는 내내 살아있게 됩니다. 즉, 그 클래스를 이용한 작업을 끝내더라도 static 변수가 점유하고 있는 메모리는 garbage collector(역주: 사용하지 않는 메모리를 회수하는 기능)에 의해서 회수되지 않게 됩니다. 반대로, 프로그래머가 그 변수를 인스턴스화 해서 main() 함수 내에서 하나의 인스턴스로 생성하게 되면, 그리고 그 인스턴스에게 만번의 함수 호출을 시키게 되면 그 만번의 함수 호출이 끝난 후 인스턴스는 소멸됩니다. 따라서 메모리를 훨씬 절약할 수 있게 됩니다.

Prevents certain re-use: Also, static methods cannot be used to implement an interface, so static methods can prevent certain object oriented features from being usable.

static은 재사용성이 떨어집니다: 또한, static 메서드는 interface를 구현하는데 사용될 수 없습니다. 즉 static 메서드는 프로그래머가 (재사용성을 높여주는)이러한 자바의 유용한 객체지향적 기능들을 사용하는 것을 방해합니다.

Other Options: If efficiency is your primary concern, there might be other better ways to solve the speed problem than considering only the advantage of invocation being usually faster than creation. Consider whether the transient or volatile modifiers are needed anywhere. To preserve the ability to be inlined, a method could be marked as final instead of static. Method parameters and other variables can be marked final to permit certain compiler optimizations based on assumptions about what can change those variables. An instance object could be reused multiple times rather than creating a new instance each time. There may be complier optimization switches that should be turned on for the app in general. Perhaps, the design should be set up so that the 10,000 runs can be multi-threaded and take advantage of multi-processor cores. If portability isn’t a concern, maybe a native method would get you better speed than your statics do.

static의 대안들: 프로그래머에게 효율(여기서는 속도)이 가장 중요한 문제여서 객체를 생성할 때 마다 생기는 사소한 불이익에도 민감한 상황일 수 있습니다. 이 경우에도 여전히 static 대신에 다른 방법들을 사용하는 것이 가능합니다. 먼저 “transient”나 “volatile”과 같은 제어자(modifier)를 쓸 수 있는지 먼저 고려해봅니다. 실행 속도를 빠르게 해주는 메소드 인라이닝(역주: 실제 메소드를 호출하지 않고 바로 결과값을 돌려주는 방식)을 위해 “final” 메서드를 사용하는 것도 생각해볼 수 있습니다. 또한 메서드 파라미터들과 변수들이 final로 선언되면 컴파일러 단에서의 최적화 작업이 가능해집니다. 인스턴스를 사용할 때마다 새로 생성하는 대신에 여러번 재사용할 수도 있습니다. 아마도 컴파일러 단의 최적화 작업이 switches that should be turned on for the app in general. 어쩌면 멀티스레드를 이용해서 멀티코어 프로세스의 장점을 극대화하기 위해선 이런 디자인이 필수적일 수도 있습니다. 이식성(역주: 다른 플랫폼으로 쉽게 옮길 수 있는 특성)이 중요한 것이 아니라면, native 메서드를 사용해서 static을 사용하는 것보다 더 빠르게 만들 수도 있을 것입니다.

If for some reason you do not want multiple copies of an object, the singleton design pattern, has advantages over static objects, such as thread-safety (presuming your singleton is coded well), permitting lazy-initialization, guaranteeing the object has been properly initialized when it is used, sub-classing, advantages in testing and refactoring your code, not to mention, if at some point you change your mind about only wanting one instance of an object it is MUCH easier to remove the code to prevent duplicate instances than it is to refactor all your static variable code to use instance variables. I’ve had to do that before, its not fun, and you end up having to edit a lot more classes, which increases your risk of introducing new bugs…so much better to set things up “right” the first time, even if it seems like it has its disadvantages. For me, the re-work required should you decide down the road you need multiple copies of something is probably one of most compelling reasons to use statics as infrequently as possible. And thus I would also disagree with your statement that statics reduce inter-dependencies, I think you will end up with code that is more coupled if you have lots of statics that can be directly accessed, rather than an object that “knows how to do something” on itself.

만약 여러개의 인스턴스를 만드는 것을 피하고 싶다면 싱글톤 디자인 패턴을 이용하는 것이 훌륭한 대안이 될 수 있습니다. 싱글톤 디자인은 (싱글톤을 제대로 구현했다는 전제하에) 스레드 안정성을 가지고, lazy-initialization(역주: 객체가 필요할 때마다 만들어 쓰는 기법)을 허용하며, 객체가 사용될 때마다 제대로 초기화 된다는 것을 보장합니다. 뿐만 아니라 서브 클래싱(sub-classing) 기법을 가능하게 하고, 테스트와 리팩토링이 매우 용이합니다. 다음의 상황을 가정해봅시다. 프로그래밍을 하다가 어느 시점에서 지금까지의 설계를 바꿔야겠다는 생각이 들게 되면 두말할 것도 없이 하나의 인스턴스를 수정하는 것이 모든 static 변수들을 리팩토링 하는 것보다 훨씬 편할 것입니다. 사실 static을 사용하다가 refactoring을 해야하는 상황은 매우 흔한 일입니다. 그것은 유쾌하지 않은 일일 뿐 아니라 훨씬 많은 클래스를 수정하게 만들기도 합니다. 이렇게 또다시 클래스들을 수정하다보면 새로운 버그를 만들어낼 소지가 매우 커집니다. 이런 상황을 피하기 위해서 처음에 “제대로”(위에서 언급한 방식들대로) 디자인하여 코딩하는 것이, 그 방식이 몇가지 단점을 가지고 있는 것 처럼 보여도 훨씬 나은 선택입니다. 사실 이런 끔찍한 재수정 작업이 요구될지도 모른다는 소지가 제가 static을 되도록 쓰지 않으려는 가장 큰 이유 중 하나입니다. 정리하자면, 저는 질문자께서 static이 코드의 상호의존성(inter-dependency)을 줄여준다고 말하신 것에 동의할 수 없습니다. 인스턴스화 되어 있는 객체들을 쓰지 않고 static 변수에 직접 접근하는 방식으로 코드를 짜다보면, 결국 작성한 모듈들이 서로 더 많이 엮이는 (바람직하지 않은) 상황에 처하게 될 것입니다.


가자고팀은 백엔드 어플리케이션을 Java로 개발하고 있다. Java로 개발을 하다보면 자주 쓰는 메서드들을 static (클래스 메서드)으로 선언하고자 하는 유혹이 생겨난다. 객체화를 할 필요도 없고 접근이 훨씬 용이하기 때문이다. 하지만 위의 두 개발자의 답변대로 static의 남용은 프로그램의 상태를 추정하기 어렵게 만들고 결과적으로 객체지향적이지 않은 코드를 작성하게 만든다.

물론 static을 ‘evil’이라고 규정하고 있는 이들의 의견에 전적으로 동의하는 것은 아니다. 그러나 필자도 개발 중에 static 을 빈번하게 사용하면 겪게 되는 문제들을 경험해본 적이 있다. ‘좋은 코드’라는 것에 결코 절대적인 기준이 있는 것은 아니지만, 객체지향적 프로그래밍의 원칙들을 되새겨볼때 분명 static의 사용에 심사숙고할 필요가 있어보인다.

By Eastsky Kang

Paul Graham의 Programming Bottom-Up

Viaweb(야후에 인수됨)과 Y Combinator의 창업자이자 Lisp의 선구자인 Paul Graham은 자신의 웹사이트 paulgraham.com에 프로그래밍과 스타트업에 대해 훌륭한 에세이들을 기고해왔다. Programming Bottom-Up은 그가 bottom-up 프로그래밍 방식의 장점에 대해서 강조하기 위해 쓴 에세이이다. 아래에 에세이의 전문 번역을 포스팅한다.


This essay is from the introduction to On Lisp. The red text explains the origins of Arc’s name.

이 에세이는 Paul Graham의 저서 On Lisp: : Advanced Techniques for Common Lisp (1993) 의 서문에 실린 글입니다. Paul Graham은 On Lisp 에서 프로그래밍 언어 Lisp 을 이용한 프로그래밍 기법과 bottom-up 프로그래밍에 대해 저술하였습니다.

It’s a long-standing principle of programming style that the functional elements of a program should not be too large. If some component of a program grows beyond the stage where it’s readily comprehensible, it becomes a mass of complexity which conceals errors as easily as a big city conceals fugitives. Such software will be hard to read, hard to test, and hard to debug.

프로그래밍의 세계에서, 기능별로 분리된 하나의 프로그램 컴포넌트를 지나치게 크게 설계하면 안된다는 것은 아주 오래된 불문율입니다. 어떤 프로그램 컴포넌트가 지나치게 커져 한번에 이해할 수 있는 규모를 넘어가게 되면 에러들을 찾는 것이 매우 어려워집니다. 마치 영화 속 악당들이나 범죄자들이 거대한 도시에 숨어 감시와 추적을 피하는 것과 같은 원리인 것입니다. 하나의 컴포넌트가 너무 커지면, 소프트웨어의 가독성이 떨어질 뿐만 아니라 테스트와 디버깅을 하기가 매우 어려워집니다.

In accordance with this principle, a large program must be divided into pieces, and the larger the program, the more it must be divided. How do you divide a program? The traditional approach is called top-down design: you say “the purpose of the program is to do these seven things, so I divide it into seven major subroutines. The first subroutine has to do these four things, so it in turn will have four of its own subroutines,” and so on. This process continues until the whole program has the right level of granularity– each part large enough to do something substantial, but small enough to be understood as a single unit.

이런 사실에 입각하여 프로그래머들은 일반적으로 하나의 큰 프로그램을 여러개의 조각들로 나눕니다. 큰 프로그램일 수록 당연히 더 많은 조각들로 나뉘어집니다. 이런 전통적인 프로그램 설계 방식은 흔히 top-down 디자인 이라고 불립니다. 예를 들자면 “만약 전체 프로그램이 일곱개의 기능을 가져야 한다고 하면, 프로그램을 일곱개의 서브루틴으로 나눌 수 있고, 첫번째 서브루틴은 다시 4개의 하위 기능을 가져야 하므로 네개의 하위 서브루틴으로 나눌 수 있고…” 이런 과정이 반복되는 방식 입니다. 이렇게 프로그램을 쪼개는 과정은 전체 프로그램이 충분히 잘게 쪼게질때까지 반복되는데 나뉘어진 각 부분은 충분히 구현되어야 하는 기능을 충실히 수행하면서도 하나의 단위로서 충분히 쉽게 이해될 수 있어야 합니다.

Experienced Lisp programmers divide up their programs differently. As well as top-down design, they follow a principle which could be called bottom-up design– changing the language to suit the problem. In Lisp, you don’t just write your program down toward the language, you also build the language up toward your program. As you’re writing a program you may think “I wish Lisp had such-and-such an operator.” So you go and write it. Afterward you realize that using the new operator would simplify the design of another part of the program, and so on. Language and program evolve together. Like the border between two warring states, the boundary between language and program is drawn and redrawn, until eventually it comes to rest along the mountains and rivers, the natural frontiers of your problem. In the end your program will look as if the language had been designed for it. And when language and program fit one another well, you end up with code which is clear, small, and efficient.

하지만 숙련된 Lisp 프로그래머들은 top-down 디자인 만큼이나 bottom-up 디자인 이라고 불리는 방식을 자주 이용합니다. 이 디자인 원칙의 핵심은, 한마디로 요약하면 이용하는 프로그래밍 언어를 개발하려는 프로그램에 최적화되도록 만들어 나간다는 것에 있습니다. 즉, Lisp을 이용해서 프로그램을 작성할 때 프로그램을 쪼개어 나가면서 (위에서 아래로 내려간다는 표현을 씁시다.) 가장 하위의 언어의 단계로까지 내려가게 하는 것이 아니라, 동시에 언어 자체를 확장해나가며 프로그램의 단계로 올라가게 한다는 것입니다. 만약 프로그램의 어떤 부분을 작성하면서 “나는 Lisp이 이런 연산자를 가지고 있으면 좋을 것 같다.”라고 생각하면 그 기능을 바로 구현하기 시작하는 것입니다. 후에 개발을 진행하면서 그 새로운 연산자가 다른 부분에서도 유용하게 쓰여 프로그램의 설계를 훨씬 단순화시킬 수 있다는 것을 발견할 수 있을 것입니다. 좀 더 쉽게 말해서, bottom-up 방식에서는 프로그램과 프로그래밍 언어가 동시에 진화합니다. 마치 전쟁 중인 두 국가의 국경선이 끊임없이 다시 그려지다가 마침내 산과 강을 따라서 수렴하게 되는 것처럼, 언어와 프로그램 사이의 경계선도 끊임없이 다시 그어지다가 프로그램에 최적화되어 있는 경계선으로 확정되게 됩니다. 이렇게 완성된 프로그램에선 마치 프로그램 언어가 처음부터 이 프로그램을 위해서 디자인되어 있었던 것처럼 보이게 됩니다. 프로그램과 프로그래밍 언어가 서로에게 가장 알맞는 모습이 되면, 프로그래머가 짠 코드는 굉장히 명료하고, 간단하며 효율적인 형태가 되어 있을 것입니다.

It’s worth emphasizing that bottom-up design doesn’t mean just writing the same program in a different order. When you work bottom-up, you usually end up with a different program. Instead of a single, monolithic program, you will get a larger language with more abstract operators, and a smaller program written in it. Instead of a lintel, you’ll get an arch.

여기서 중요한 것은 bottom-up 디자인이 단지 프로그램을 작성할때 top-down 방식으로 프로그램을 작성할때의 반대 순서로 작성하는 것만을 의미하는 것은 아니라는 점입니다. 프로그래머가 bottom-up 방식으로 프로그램을 작성하면, 완성된 프로그램은 top-down 방식으로 작성한 프로그램과는 전혀 다른 모습이 됩니다. 하나의 통일된 프로그램 대신에 좀 더 추상화된 연산자들을 가지게 되며, 훨씬 더 간결한 프로그램으로 재탄생하게 됩니다. 건축에 비유하자면 천장을 지탱하기 위해서 두개의 기둥을 쌓아올리고 그 위에 대들보(lintel)를 올려놓는 대신에 처음부터 아치(arch)를 쌓아올리는 것으로 표현 할 수 있을 것입니다. (역주: 참고로 이러한 Paul Graham의 아치 비유 는 Paul Graham과 Robert Morris가 개발한 Lisp의 방언인 Arc 의 이름의 기원이 되었습니다.)

In typical code, once you abstract out the parts which are merely bookkeeping, what’s left is much shorter; the higher you build up the language, the less distance you will have to travel from the top down to it. This brings several advantages:

일단 프로그래머가 필요하다고 생각하는 부품들을 추상화하여 쌓아올리고 나면, 남은 작업은 매우 간단합니다. 프로그래밍 언어를 더 높이 쌓아올릴 수록, top-down을 해야 하는 거리가 줄어들게 되므로 따라서 작업이 훨씬 간단해지는 것입니다. 이는 다음의 몇가지 장점들을 불러옵니다.

  1. By making the language do more of the work, bottom-up design yields programs which are smaller and more agile. A shorter program doesn’t have to be divided into so many components, and fewer components means programs which are easier to read or modify. Fewer components also means fewer connections between components, and thus less chance for errors there. As industrial designers strive to reduce the number of moving parts in a machine, experienced Lisp programmers use bottom-up design to reduce the size and complexity of their programs.
  2. Bottom-up design promotes code re-use. When you write two or more programs, many of the utilities you wrote for the first program will also be useful in the succeeding ones. Once you’ve acquired a large substrate of utilities, writing a new program can take only a fraction of the effort it would require if you had to start with raw Lisp.
  3. Bottom-up design makes programs easier to read. An instance of this type of abstraction asks the reader to understand a general-purpose operator; an instance of functional abstraction asks the reader to understand a special-purpose subroutine.
  4. Because it causes you always to be on the lookout for patterns in your code, working bottom-up helps to clarify your ideas about the design of your program. If two distant components of a program are similar in form, you’ll be led to notice the similarity and perhaps to redesign the program in a simpler way.
  1. 프로그래밍 언어의 기능이 확장됨으로써, 프로그램의 구현은 훨씬 간결하고(짧고) 또 훨씬 유연해집니다. 간결하고 짧은 프로그램은 여러개의 컴포넌트로 나뉘어질 필요가 없습니다. 이는 코드를 읽고 고치기가 훨씬 더 자유로워진다는 것을 의미합니다. 또한 컴포넌트의 개수가 줄어든다는 것은 컴포넌트 간의 연결이 훨씬 줄어든다는 것을 의미하기도 합니다. 따라서 에러에 가장 취약할 수 있는 이 연결 고리들 사이에서 에러가 발생할 가능성을 줄이게 됩니다. 기계를 설계하는 산업 디자이너나 엔지니어들이 움직이는 부속의 수를 줄이기 위해서 고군분투하는 것과 마찬가지로, 숙련된 Lisp 프로그래머들은 bottom-up 디자인을 이용해서 프로그램의 크기와 복잡도를 줄이는데 몰두합니다.
  2. Bottom-up 디자인은 코드의 재활용성(reusability)을 증대시킵니다. 흔히, 여러개의 프로그램을 작성할때 처음 프로그래머가 작성했던 유틸리티(역주: 앞에서 프로그래머가 언어 레벨에서 필요하다고 생각했던 기능을 Bottom-up 방식으로 구현한 구현체들)들은 그 다음 프로그램들을 작성할 때 요긴하게 사용됩니다. 경험 많은 프로그래머가 이전의 프로그램들을 위해서 충분히 이런 유틸리티들을 많이 구현해놓고 있다면 raw Lisp (이런 유틸리티들이 전혀 구현되어 있지 않은 순수한 Lisp)으로 처음부터 프로그램을 작성하는 것보다 훨씬 적은 노력으로 프로그램을 작성할 수 있게 됩니다.
  3. (프로그래머가 프로그래밍 언어를 확장하기 위해서 짠 유틸리티에 대해 이해하고 있다는 전제 하에) Bottom-up 디자인은 프로그램의 가독성을 높여줍니다. Bottom-up 디자인과 같은 추상화 방식에서는 연산자들을 좀 더 일반적으로 사용하는 것이 가능합니다. 반면에 함수를 이용한 추상화 방식에서는 프로그램을 읽는 사람이, 프로그래머가 정의한 이 새로운 함수를 이해할 것을 요구합니다. (역주: 예를 들어 "Hello"라는 문자열과 "World"라는 문자열을 잇는 작업을 한다고 했을 때 Bottom-up 디자인에서는 "Hello" + "World" 와 같이 일반적인 + 연산자를 사용할 수 있게 언어를 확장하는 것이 가능합니다. Bottom-up 방식을 사용하지 않고 함수로 이를 구현하는 경우에는 이 작업을 해주는 함수, 가령 concat("Hello", "World") 와 같은 함수를 만들고 호출하는 식으로 구현이 됩니다. 전자가 후자보다 가독성이 낫다는 것은 다소 자명한 것입니다.)
  4. 마지막으로, Bottom-up으로 프로그램을 작성하기 위해선 전체 코드의 패턴을 살피고 이해하고 있어야 하므로, 프로그래머가 작성하는 프로그램의 디자인에 대한 아이디어를 명확히 이해하는데 도움을 줍니다. 동일한 패턴을 가지고 있는 두개의 컴포넌트가 꼭 코드 상에서 붙어있으리라는 보장은 없습니다. 만약 멀리 떨어져있는 두개의 컴포넌트가 유사성을 가지고 있다면 프로그래머는 그 유사성을 파악하고, 전체 프로그램을 다시 좀 더 간단한 형태로 설계할 수 있도록 유도될 것입니다.

Bottom-up design is possible to a certain degree in languages other than Lisp. Whenever you see library functions, bottom-up design is happening. However, Lisp gives you much broader powers in this department, and augmenting the language plays a proportionately larger role in Lisp style– so much so that Lisp is not just a different language, but a whole different way of programming.

Bottom-up 디자인은 Lisp 말고도 다른 언어들에도 어느정도 적용될 수 있습니다. 라이브러리 함수들은 bottom-up 디자인의 대표적인 예라고 볼 수 있을 것입니다. 물론 Lisp에서 bottom-up 디자인은 훨씬 더 빛을 발합니다. 이 것은 Lisp의 스타일이 단지 C와 Java와 같은 프로그램과 다른 문법을 가진 프로그래밍 언어라서가 아니라, 완전히 다른 방식의 프로그래밍 패러다임이기 때문입니다. (Lisp의 함수형 프로그래밍으로서의 특성에서 기인합니다.)

It’s true that this style of development is better suited to programs which can be written by small groups. However, at the same time, it extends the limits of what can be done by a small group. In The Mythical Man-Month, Frederick Brooks proposed that the productivity of a group of programmers does not grow linearly with its size. As the size of the group increases, the productivity of individual programmers goes down. The experience of Lisp programming suggests a more cheerful way to phrase this law: as the size of the group decreases, the productivity of individual programmers goes up. A small group wins, relatively speaking, simply because it’s smaller. When a small group also takes advantage of the techniques that Lisp makes possible, it can win outright.

사실 이런 소프트웨어 개발 스타일은 큰 규모의 팀보다는 작은 규모의 팀에서 작업할 때 더 적합합니다. 대신 이런 방식은 작은 규모의 팀이 할 수 있는 일의 한계를 놀라울 정도로 증대시킵니다. Frederick Brooks는 그의 저서 Mythical Man-Month 에서 프로그래머 그룹의 생산성은 팀의 규모와 정비례하지 않는다는 유명한 이론을 제안한 바 있습니다. 실제로 많은 경우에, 팀의 규모가 커질수록 프로그래머 개개인의 생산성은 떨어지게 됩니다. 반대로 팀의 규모가 줄어들수록 프로그래머 개개인의 생산성은 향상됩니다. 작은 팀이 큰 팀에 승리하는 이유는 단지 규모가 작기 때문입니다. 그러나 만약에 작은 규모의 팀이 Lisp 프로그래밍이 가능하게 만든 bottom-up 프로그래밍의 장점을 취할 수 있게 된다면 어떤 일이 일어날까요? 그 팀은 천하무적의 팀이 될 것입니다.


Paul Graham은 늘 전서계의 개발자들에게 자신이 믿고 있는 프로그래밍 방법론들과 패러다임의 장점에 대해 설파하는데 열심이다. 이 글에서도 새로운 신도들을 만드려는 듯한 그의 의지가 여전하다.

이 글을 온전히 이해하기 위해서는 함수형 프로그래밍 패러다임에 대한 깊이 있는 이해가 필요한 것처럼 보이지만 일단 그 방대한 내용들을 공부하기 위해서는 많은 시간이 걸릴 것이므로 일단 논외로 치려고 한다. 그러나 bottom-up 이라는 용어를 처음들어본 사람들에게도 익숙할 사용자 정의 라이브러리나 API와 같은 개념을 ‘언어의 확장’이라는 측면에서 접근했다는 점에서 매우 신선하다는 생각이 들었다. ‘마치 그 프로그램을 위해서 존재하는 언어를 만들 듯이’ 프로그래밍 한다는 그의 표현은, 분명 이런 설계 기법이 생소한 사람들에게도 단박에 와닿는 설명이다. 더불어서 왜 이 기법이 top-down 방식에 비해서 이점을 가지는지에 대한 설명도 너무나 논리적이고 탁월하다.

마치 기계를 설계할 때 표준화된 부품들을 사용함으로서 그 종류의 개수를 줄이려는 시도를 하려는 것처럼 프로그래밍에서도 처음부터 이런 ‘표준화된 부품(본문의 컴포넌트 혹은 유틸리티)’들을 미리 만들어 놓음으로서 효율적인 구현을 하겠다는 것은, 비록 이를 염두에 두고 작업을 해보지는 않았지만 분명 고개를 끄덕일 수 있을만한 합당한 시도처럼 보인다.

다만 그가 지적하는 것처럼, 그 ‘표준화된 부품’을 만들기 위해선, 어떤 부품을 표준화 해야 할 것인가에 대한 프로그래머의 통찰력이 분명 필요할 것이며 그 것은 경험이 많은 프로그래머들 만이 익숙하게 해낼 수 있는 작업일 것이다. 그러나 그의 주장을 염두에 두고 프로그래밍 하면 분명 효율 면에서 큰 개선을 이룰 수 있을 것 같다.

저자의 주장의 유효성에 대해서 논하는 것을 떠나서, 늘 테크 구루들이나 뛰어난 엔지니어들의 글에선, 사소하게 지나갈 수 있는, 너무나도 당연해 보이는 접근이나 방식들을, 그들은 얼마나 잘 체계화하고 이론으로 만들어 방법론화하는지 실감하게 된다. 이런 패러다임화를 통해서 탄탄한 시스템을 구축하고 좀 더 효율적인 작업을 꾀하는 이들의 노력이, 수준 높은 차원의 엔지니어링에는 필수적인 요소라는 것을 다시 한번 느끼게 된다.

By Eastsky Kang