스토리 홈

인터뷰

피드

뉴스

조회수 13646

슬랙봇, 어디까지 만들어봤니?

스포카에서 다년간 일하면서 나에게는 몇 가지 별명이 생겼다. 그 중 하나는 봇맘(Bot mom)이다. 다른 스타트업에서처럼 으레 스포카에서도 주어지는 일만 하는게 아니라 작고 큰 문제를 스스로 발견하고 고민할 기회가 왕왕 생긴다. 나 또한 그런 기회가 있었고 그러던 중 (귀차니즘을 극복하기 위해라고 쓰고) 일을 더 효율적으로 하기 위해(라고 읽는다) 봇(Bot)에 재미를 느끼게 되었다. 그리고 하나 둘 봇으로 문제를 해결하게 되었고 어느새 사람들이 그 별명을 붙여주었다.봇(Bot)2014년 즈음부터 스포카는 슬랙(Slack)을 사내 메신저로 사용하기 시작했다. 슬랙 도입 초창기에는 기본적인 업무 커뮤니케이션과 아틀라시안 제품군(JIRA, Confluence 등), Github 등 사내 업무 툴의 슬랙 라우팅 기능으로만 슬랙을 사용하였다. 하지만 기본 기능 만으로는 실제 업무 환경에서 불편한 부분들이 더러 있어 슬랙봇 기능을 점차 활발히 사용하게 되었다. 팀마다 사용빈도는 다르지만 현재 많은 직원이 슬랙봇을 활용하고 있는데 지속적으로 업무 환경을 개선하는데 봇 기능이 상당한 기여를 하고 있다.인터넷 상에서 자동화된 작업(스크립트)를 실행하는 응용 소프트웨어봇(Bot)은 위와 같이 설명되고 있다. 예를 들어, 슬랙에서 사용자가 설정한 단어가 입력되거나 시간대가 되었을 때, 설정했던 이미지나 텍스트가 자동으로 나오는 기능이라고 생각하면 된다.슬랙에서 기본적으로 제공하는 슬랙 봇과 Reminder 기능만 잘 활용해도 누구나 업무환경 개선을 시도해볼 수 있다. 개인적으로 스포카의 봇 활용(hacking)1은 어떠한 다른 팀과 비교해도 뒤지지 않는다 생각한다. 실제 업무에 적용한 사례를 보면 봇이 무엇인지, 무엇을 할 수 있는지 아는데 도움이 될 것이다. 큰 도움이 되고 있었던 사례를 모아 소개하겠다.2Case1. 자연스럽게 직원들에게 세뇌시키기상황 및 의도서비스 내 용어가 팀별로 다르게 쓰이거나 여러가지로 불리고 있는 것들이 있었다. 혹은 서비스가 런칭/업데이트되면서 개편된 제품/기능이름들이 있었다. 이는 아는 사람끼리는 문제가 없지만 신규입사자나 아직 전달이 덜된 타팀과 소통할 때에는 오해가 생길 수 있었다. 이런 상황에서 UXD팀에서는 추가적으로 새로운 이름을 알리고 즉각 교정 효과를 볼 수도 있는 효율적인 방법을 고안하고자 했다.1-1. 도도 매틱이 도도 메시지로 서비스명이 변경되었음을 알리는 봇이다1-2. 개편된 제품/기능이름을 알릴 때 쓰였던 슬랙봇들. 시간이 지나면서 제 임무를 다하고 사라졌다.효과잘못된 단어를 사용할 때마다 봇이 알려주니 즉각 교정 효과가 나타났다. 사람마다 교육되는 기간을 달랐지만 점차 잘못된 단어를 사용하는 사람들이 사라졌고, 몇 개월 후에는 옛날의 잘못된 단어가 무엇인지 까먹은 사람도 있었다. 그리고 시간이 지나고 제 목표를 달성한 슬랙봇들을 삭제하기까지 이르렀다.Case2. 개발자님 도와주세요ㅠㅠ상황 및 의도디자이너가 코드를 다루다가 가끔 알 수 없는 함정에 빠질 때가 있다. 서버가 왜인지 켜지지 않는다거나 원인을 명확히 알 수 없는 에러가 뜬다거나 하는 경우다. 그런 때면 개발자에게 도움을 요청하는데, 개발자의 입장에서는 진행하고 있던 업무를 잠시 중단하고 해결할 수 있는 커맨드를 알려주거나 알아보는데 시간이 걸릴 수 있다. 이럴 때 봇이 취해야하는 커맨드를 알려준다.봇으로 개발자가 도와줘야 하는 단계가 하나 줄었다!효과개발자가 도움요청 메시지를 보기 전, 디자이너가 먼저 바로 응급처치를 해볼 수 있어 덜 답답했고 개발자도 하나의 예상원인을 제거할 수 있어 빠르게 상황을 파악할 수 있었다.Case3. 항상 똑같은 질문과 답변은 그만!상황 및 의도기억력의 한계와 투명한 업무 진행상황 공유를 위해 이슈 기록 등 문서 작성에 기를 가하는 문화가 있다보니 사내위키문서가 자연스레 방대해졌다. 찾고자 하는 문서가 어딨는지 못 찾아 메일함과 위키사이트를 헤매고 못 찾으면 항상 팀원들에게 물어보게 되어 괜히 미안한 상황이 있었다. 그냥 누군가 물어볼 때 딱!하고 찾아주었으면 했다.다른 경우로는, 매번 특정 팀에게 물어보는 것이 있다. 사이트 내 친절히 설명을 작성하고 공지해도 정보 접근이 귀찮거나 어려운 곳에 있으면 바로 담당자에게 물어서 바로 올바른 답변을 얻고자 하게 된다. 이런 경우, 같은 질문을 하는 사람은 수십 명인데 답변하는 사람은 한 두명여서 답변하는 담당자는 피로해질 수 있다.3-1. 우리팀 주간미팅 회의록이 어딨더라...?3-2. 디자인팀에게 요청할 때 뭘 알려드려야 하지?3-3. 이 지역 담당자가 누구더라?효과원하는 문서의 바로가기 링크를 바로 얻거나 정보를 얻을 수 있어 위키 메뉴를 헤매지 않고 시간을 절약할 수 있었다. 반복적으로 물어보게 되는 사항을 물어보고 싶을 때 불편한 마음을 전혀 가지지 않아도 되었다.Case4. 이번엔 누구에게 의견을 물어볼까?상황 및 의도현재 스포카 Visual design팀(이하 VD팀)은 5명이며 디자인이라면 모두 관심을 가지고 의견을 주는데 주저함이 없다. 어떤 이슈를 진행할 때 중간 점검의 느낌으로 가볍게 1~2명에게 리뷰를 받고 싶을 때가 있다. 항상 같은 사람에게만 리뷰를 부탁하는건 아닌지, 다양한 의견을 받아보고는 싶은데 누구에게 돌리는게 좋을까, 리뷰어 선정에 고민을 하게 될 때가 있다. 혹은 이슈진행자가 정해지지 않았을 때 마음의 짐을 덜고 책임자를 정하는 잔인한 방법이 되기도 한다.(ㅋㅋ) 5명인데 1명 혹은 2명을 고르고 싶으므로 or/and를 병기하여 모든 경우의 수를 정리하여 봇을 만들었다.VD리뷰랜덤효과누구에게 리뷰를 맡길지 고민하는 시간이 줄었다. 타팀에서도 VD팀 누군가에게 리뷰를 부탁하고 싶을 때 활용되기도 한다. 하지만 휴가 중이라던지 가끔 리뷰를 볼 수 없는 사람이 계속 무작위로 나올 때가 있어 두세번 봇을 불러야 하는 일이 있다.Case5. 다나와 대화형 봇 (심화)앞서 소개한 유형들이 너무 단순하다고 느껴진다면 키워드 봇을 연속적으로 활용해보는 방법도 있다. 채팅형 봇을 만든 듯한 착각을 느끼게 할 수 있다.사이즈 다나와 (혹자는 이 사례를 보고 슬랙해킹의 정점을 달려가는 것 아니냐 감탄하였다.)Case6. 잊는 법이 없는 나만의 비서!봇이 일상화되니 왠만한 정기적인 업무일정은 무조건 봇으로 만드는게 습관이 되었다. 예전에는 다른 봇제작 서비스를 통해 만들던 기능이었는데, 슬랙에 리마인드(Remind) 기능이 업데이트 되면서 더 편해졌다. 리마인드 기능 설명은 이쪽을 참고 바란다.6-1. 스프린트 시작 알림 봇6-2. 데일리미팅 알림 봇6-3. 주말의 시작을 알리는 봇6-4. 파트타이머 급여 처리를 잊지 않도록 도와주는 비서봇Case7. 슬랙 API를 활용한 데이터드리븐 봇 (고급)상황 및 의도지금까지 소개한 것들은 회사 내부에서 업무를 진행할 때 도움을 받거나 내부 커뮤니케이션을 위한 것들이었다. 이번에 소개할 것은 회사 서비스와 관련된 개발자 친화적인 방법이다. 서비스 내 DB와 슬랙에서 제공하는 API를 접목하여 별도의 트래킹(tracking)툴 없이 실제 사용자의 행동 중 주요하게 알아야 하는 것을 슬랙봇으로 만든 것들이다.7-1. 부정적립으로 의심되는 이벤트를 알려주는 봇7-2. 매장 잔여코인 알림과 코인결제완료를 알려주는 봇효과별도의 트래킹툴이나 웹사이트에 접속할 필요 없이 실시간 데이터를 파악할 수 있었다. 또한 서비스에 주요한 영향을 끼치는 사용자의 실제 행동을 팀원들과 함께 빠르게 공유할 수 있었다.봇을 만들 수 있는 다른 방법슬랙의 리마인드 기능을 쓰지 않더라도 봇을 부릴(?) 수 있는 방법이 있다. 슬랙봇은 슬랙을 사용해야하고 관리자 권한이 있어야 설정 가능하다. 그러므로 개인적으로 쓴다면 아래 2가지 서비스들을 추천한다. 조합할 수 있는 서비스가 다양하니 자동화할 수 있는 아이디어가 있다면 시너지가 엄청날 것이다. 업무 뿐만 아니라 일상생활에도 활용할 수 있다.Zapier글쓴이가 슬랙에 리마인드 기능이 없을 때 애용하던 서비스이다. 무료 플랜으로 사용하면 설정할 수 있는 봇 개수와 작동하는 횟수가 제한적이지만 소소하게 가끔 필요한 것을 쓰기에는 괜찮다. 업데이트가 계속 되고 있으니 시도해보시라.IFTTTIf this, then that. 컨셉별 봇 레시피가 잘 정리되어 있어 바로 일상생활에 적용해볼 아이디어를 제공한다. 슬랙 외에도 다양한 앱과 연동하여 사용할 수 있는 장점이 있다.슬랙봇과 스포칸업무에 유용한 봇을 위주로 소개했으나 스포카의 슬랙봇은 업무의 즐거움을 향상시키는 스포칸의 드립 아카이브 역할을 하기도 한다. 업무에 활용하는 것만큼 다양한 방식으로 소구되고 있는데, 드립의 특성상 시간이 지나면 그 재미가 무뎌지는 것들이 있어 굳이 소개하지는 않겠다. 또한, 그외 개발자분께서 직접 창의적인 봇용 앱을 만든 사례도 여러 개 있었는데 나중에 기회가 되어 소개를 해볼 수 있으면 좋겠다.계속 슬랙이 업데이트되면서 나 외에도 비IT직군도 슬랙봇을 잘 활용해나가고 있고, 다른 팀원들도 번뜩이는 위트를 겸하며 슬랙봇을 활용하고 계시다. 여러가지로 활용되고 있는 슬랙봇은 하나의 값진 유산이라고 생각되기까지 한다. 간단한 기능임에도 더 집중해야 할 곳에 집중할 수 있도록 도와주기도 하고, 동료 간의 유대감을 깊게 만들기도 하기 때문이다. 스포카 외에 슬랙을 사용하는 다른 회사/팀들도 각자 사용하고 계시는 툴을 재밌고 유용한 방식으로 활용하며 팀 커뮤니케이션에 보탬이 되었으면 좋겠다.시스템 혹은 프로그램의 문제를 고치기 위한 행위 ↩이 포스팅의 예시 중에는 1~2년 전 스포카의 슬랙에서 활발히 쓰였다가 현재는 잘 사용되지 않는 경우도 있다. ↩#스포카 #개발 #개발자 #사내문화 #조직문화 #인사이트 #꿀팁
조회수 1331

'구루급' 개발자란...

'구루'라는 단어는 이제 '수준급'을 넘어선 분들에게 부여되는 의미 있는 호칭이다. 특히, 개발자 사회에서는 비공식적으로 '구루급'이라고 불리는 개발자들이 있다. 이 정의에 대해서 누가 명확하게 옳다고 이야기할 수 있는 것은 아니다.다만, 30년 동안 소프트웨어 개발자로 살아오면서 만난 수많은 개발자들과 해외 유수의 개발자들과 만나고 소통하면서 느낀 개인적인 경험을 바탕으로 '구루급'에 대해서 정의를 해보겠다.매우 당연하게 이 정의는 전적으로 객관화된 것이 아닌, 매우 주관적인 기준이다.보통, '구루'급 개발자라고 불리는 분들을 보면, 오픈소스로 한 획을 그었거나, 그의 뜻을 따르는 후배들이 많거나, 특정 분야의 경험이 매우 풍부한 분들을 대상으로 이야기한다.다만, 이 기준에 '돈'을 많이 벌었거나, 특정 제품이나 게임, 서비스를 잘 만들었다는 식의 기준은 들어가는 것은 일부 논외로 하겠다. 이것은 전적으로 개인적인 기준이다. 이런 분들은 '구루급'개발자가 되기보다는, 산업적이거나 경제적으로 크게 성공한 기준이 더 높기 때문이며, 금전적으로 성공한 분들이 '후배'들에게 개발자로서의 영향력을 주는 것이 사실상 어렵기도 하거니와, 이미 비즈니스의 단계로 넘어간 분들이기 때문에 '구루급'개발자라고 이야기하기에는 모호하다고 개인적으로 이야기한다.그렇다면, 내가 생각하는 구루급 개발자의 최소한의 필요조건을 나열해 보자. 전적으로 개인적인 기준이니 너무 주관적이라고 비판하지 마시기를... 그 이유는 정말 주관적이기 때문이다.하나. 하나의 소프트웨어나 도메인을 10년 이상 장기간 개발 및 연구하고 있는가?둘. 자신만의 개발 문화에 대한 철학과 그 기준을 가지고 실행하고 있는가?셋. 자신이 소유하거나 만들어낸 개발 도구나 방법, 기술에 대해서 후배 개발자들에게 전파하고 있는가?넷. 후배 개발자들에게 존경받는 개발자로서의 기본적인 성품을 가지고 있는가?다섯. 후배 개발자들에게 자신의 롤을 양보하거나, 팀과 조직을 위해서 자신의 자리를 포기할 줄 아는가?여섯. 자신의 먹을거리를 위해서 비용을 싸게 부르지 않고, 후배들도 대우를 받을 수 있도록 너무 싸게 일하지 않아야 한다는 것을 실천하는가?제가 생각하는 '구루급'개발자의 조건입니다.분명, 이렇게 활동하는 '구루급'개발자들이 주변에 존재하고 있으며, 이를 위해서 개발자의 처우에 대해서 노력하기도 하고, 불합리한 경영자들과 논쟁을 벌이기도 합니다. 자신의 개인적인 이익만을 위해서 움직이지도 않는 그들이야말로 '구루급'개발자 아닐까요?그리고.대부분의 구루급개발자들은 충분한 대우와 보수를 받고 일하고 있습니다.그것이, 후배 개발자들의 처우와 미래를 위해서 매우 필요하다고 생각하고 있기 때문이죠.저는 '구루급'개발자를 그렇게 생각합니다.ps.최고의 개발자, 슈퍼개발자 등에 대한 호칭도 있을 수 있습니다. 제가 생각하는 '구루'급 개발자는 후배들에게 존경을 받고, 후배들의 처우나 개발자들의 미래에 대해서도 고민하고 실천하는 분들에 대해서 정의해 본것입니다.
조회수 4543

개발자 직군 파헤치기 4 | 빅 데이터 엔지니어

빅 데이터 엔지니어는 무엇을 하나요?빅 데이터가 부상하면서 그와 관련된 직업군도 함께 주목받기 시작했습니다. 빅 데이터 엔지니어, 빅 데이터 애널리스트, 빅 데이터 사이언티스트 등 다양한 직업군이 생겼습니다. 오늘은 개발자 직군 중 데이터와 관련된 빅 데이터 엔지니어에 관해 이야기해 볼 것입니다. 빅 데이터 엔지니어는 무엇을 할까요? 빅 데이터 엔지니어가 무엇을 하는지 알기 위해서는 먼저 빅 데이터가 뭔지 알필요가 있겠습니다.빅 데이터는 기존 데이터베이스 관리도구의 능력을 넘어서는 대량의 정형 또는 심지어 데이터베이스 형태가 아닌 비정형의 데이터 집합조차 포함한 데이터로부터 가치를 추출하고 결과를 분석하는 기술입니다(위키 참조).빅 데이터의 특징은 방대한 데이터와 더불어 비정형 데이터까지 포함한다는 것입니다. 많은 양의 데이터와 정형화 되지 않은 데이터를 수집하는 일은 보통 일이 아닙니다. 빅 데이터를 통한 새로운 알고리즘를 만들거나 인사이트를 발견하기 위해서는 빅 데이터가 존재해야 합니다. 빅 데이터 엔지니어는 이러한 빅 데이터를 수집하고 관리하는 프로그래머입니다. 일반적인 데이터 수집과 달리 수십테라 정도의 정보를 수집 하게 됩니다. 또 그런 데이터를 어떻게 효율적으로 관리할지 고민해야합니다.데이터는 미래의 석유라고 합니다. 빅 데이터 엔지니어는 빅 데이터 분석가나 과학자들에게 이러한 석유를 가져다 주는 송유관을 설치하고 관리하는 역할을 한다고 볼 수 있습니다. 빅 데이터 활용을 위해서라면 빅 데이터 엔지니어의 역량이 반드시 필요합니다.데이터 과학자와 데이터 엔지니어는 다르다.위에서 빅 데이터 엔지니어는 데이터를 수집하고 관리하는 업무를 한다고 했습니다. 하지만 구체적으로 빅 데이터 과학자(Big Data Scientist)와 빅 데이터 엔지니어(Big Data Engineer)는 무엇이 다를까요?어떤 직업의 업무라는 것이 무 자르듯 쉽게 나눌 수 있는 것은 아니지만 확실히 그 직업만의 특징은 존재합니다. 각 직업 별로의 특징을 통해 빅 데이터 엔지니어가 빅 데이터 과학자와 어떻게 다른지 알아보도록 하겠습니다.1. 빅 데이터 엔지니어(Big Data Engineer)빅 데이터 엔지니어는 위에서도 언급 했지만, 데이터를 수집하고 관리하는 일을 합니다. 빅 데이터 엔지니어를 통해 '빅 데이터'가 만들어진다고 해도 무방하죠. 숫자나 규칙이 있는 정형 데이터는 물론이고 글자나 불규칙적인 비정형 데이터까지 수집하고 관리합니다. "그냥 데이터를 수집하고 관리하는 일인데 별거 있나?"라고 생각하실 수도 있습니다. 빅 데이터라는 개념 이전에도 데이터는 수집되었고 분석을 통해 비즈니스 문제를 해결해 왔으니까요. 그렇지만, 빅 데이터라는 개념이 부상하고 실현 가능할 수 있었던 이유는 방대한 데이터를 수집할 수 있는 퍼널(funnel) 설계과 그 데이터를 관리하고 알맞게 사용할 수 있는 시스템을 구축할 수 있었기 때문입니다.그렇기 때문에 빅 데이터 엔지니어는 프로그래밍에 아주 능숙해야합니다. 빅 데이터를 수집하고 관리할 수 있는 방법을 짜야하니까요. 또한, 개별적인 정보가 아닌 큰 틀에서의 정보를 다루고 통합하고 나누어 볼 수 있는 설계 능력이 따라주어야 합니다.정교하게 짜여진 빅 데이터가 아니라면 빅 데이터 과학자가 그것을 분석하고 사용하는데 상당한 자원이 들거나 최악의 경우 아예 이용하지 못하게 될 것입니다.2. 빅 데이터 과학자(Big Data Scientist)빅 데이터 엔지니어가 빅 데이터를 수집하고 관리한다면 빅 데이터 과학자는 그것을 요리하는 역할을 합니다. 데이터보고 직면한 비즈니스 문제를 해결할 새로운 인사이트를 도출해 내는 것입니다. 혹은 현재 가지고 있는 프로세스를 개선할 알고리즘을 만들어 낼 수도 있습니다.빅 데이터 과학자는 데이터를 분석할 수 있는 통계학적 지식뿐만 아니라 그 데이터를 다룰 수 있는 프로그래밍적 지식도 요구됩니다. 일반적인 데이터가 아닌 '빅' 데이터다 보니 그것을 쉽게 운용하고 자유자재로 이용하게 해줄 툴을 익혀야합니다. 또한, 빅 데이터 과학자에게 요구되는 핵심 역량 중 하나는 바로 머신러닝에 대한 지식입니다. 이 또한 프로그래밍 지식과 알고리즘 지식이 필요합니다. 빅 데이터 엔지니어가 되기 위한 Key Skills그렇다면 빅 데이터 엔지니어가 되기 위해서는 어떤 기술 스택들을 익혀야할까요? 빅 데이터 엔지니어는 데이터와 관련된 직군인만큼 데이터베이스와 관련된 기술스택들이 중요합니다.1. SQL데이터 관리를 하시는 분들이면 다들 알고 계시는 SQL입니다.  SQL은 관계형 데이터베이스 관리 시스템의 데이터를 관리하기 위해 설계된 특수 목적의 프로그래밍 언어입니다(위키참조).2. MapReduce(맵리듀스)맵리듀스는 구글에서 대용량 데이터 처리를 분산 병렬 컴퓨팅에서 처리하기 위한 목적으로 제작하여 2004년에 발표한 프레임워크입니다.(위키참조).3. Apache Hadoop(아파치 하둡)Apache Hadoop은 대규모 데이터 세트를 효율적으로 처리하는 데 사용할 수 있는 오픈 소스 소프트웨어 프로젝트입니다. 하나의 대형 컴퓨터를 사용하여 데이터를 처리 및 저장하는 대신, 하둡을 사용하면 상용 하드웨어를 함께 클러스터링하여 대량의 데이터 세트를 병렬로 분석할 수 있습니다.4. Apache Cassandra(아파치 카산드라)Apache Cassandra 자유-오픈 소스 분산형 NoSQL 데이터베이스 관리 시스템의 하나로, 단일 장애점 없이 고성능을 제공하면서 수많은 서버 간의 대용량의 데이터를 관리하기 위해 설계되었습니다. 카산드라는 여러 데이터센터에 걸쳐 클러스터를 지원하며 마스터리스(masterless) 비동기 레플리케이션을 통해 모든 클라이언트에 대한 낮은 레이턴시 운영을 허용합니다(위키참조).5. Java(자바)빅 데이터 엔지니어는 기본적으로 프로그래머이기 때문에 프로그래밍 지식있어야 합니다. 빅 데이터 엔지니어를 목표로 처음 프로그래밍을 시작한다면 자바를 추천합니다. 물론, 다른 언어를 통해 프로그래밍 실력을 쌓아도 됩니다. 그렇지만, 아파치 하둡과 아파치 카산드라가 자바를 베이스로 만들어졌기 때문에 자바를 배운다면 이 기술스택들을 습득하는데 훨씬 효율적일 것입니다.다른 포스팅에서도 항상 말씀드려왔지만 기술스택만 익힌다고 해서 그 직업을 가질 수 있는 것은 아닙니다. 기술스택은 기본이고 개발자로써의 역량이 뒷받침 되어야 시장에서 환영받는 빅 데이터 엔지니어가 될 수 있습니다.Photo by Ehud Neuhaus on Unsplash빅 데이터 엔지니어가 되기 위한 학습 콘텐츠시중에서는 완성된 단계로써 빅 데이터 엔지니어를 양성하는 프로그램은 많지 않습니다. 따라서 개인이 빅 데이터 엔지니어에게 필요한 기술 스택들을 하나씩 익혀 나가야 합니다.무료 온라인 콘텐츠도 많겠지만, 비싸지 않으면서도 잘 정제된 콘텐츠를 소개하려고 합니다. 유튜브 강좌보다는 보기 편하고 학습 환경이 잘 갖춰져 있어서 공부하기에 좋은 콘텐츠를 추천합니다.1. SQL - SQL 프로그래밍 : SQL을 무료로 학습할 수 있는 사이트(한글)2. Hadoop - 유데미 The Ultimate Hands-On Hadoop - Tame your Big Data! (영어)3. Cassandra - 유데미 From 0 to 1: The Cassandra Distributed Database (영어)데이터 엔지니어는 예전부터 있었다.오늘은 빅 데이터 엔지니어에 대해 알아보았습니다. 사실, 빅 데이터 엔지니어는 어느 날 갑자기 생겨난 직업이 아닙니다. 데이터베이스를 관리하는 프로그래머가 더 나은 기술 스택을 익히고 더 좋은 방법으로 데이터를 수집하고 관리하면서 생겨난 것입니다.세상은 빠르게 변한다고 하지만 그 안을 들여보면 서서히 발전한 것들이 다르게 네이밍(Naming) 되면서 새롭게 다가오는 것이라 생각합니다. 그렇다고 해서 그것이 변하지 않는 것이 아닙니다. 새롭게 변하는 기술들을 익히고 자신의 역량을 갈고 닦아야만 새롭게 다가오는 변화에 휩쓸리지 않고 주도할 수 있는 것 같습니다.
조회수 1551

도도 파이터 제작기

안녕하세요. 도도 파이터의 개발과 시각 디자인을 각각 담당한 스포카 크리에이터 박준규, 박지선입니다.우선, 도도 파이터에 관심 가져주시고 참여해 주신 분들께 감사의 말씀을 드립니다. 도도 파이터는 저희의 당초 예상을 훨씬 뛰어넘는 71명의 제출로 마무리되었습니다. 많은 분의 참여 덕분에 이벤트를 무사히 마칠 수 있었다고 생각합니다.이 글에서는 도도 파이터의 기획 의도와 제작과정, 기술적인 디테일에 대해서 다루어 보려고 합니다.기획 의도저희는 파이콘 한국에 2015, 2016년에 이어 이번 2018년까지 총 세 차례 후원사로 참여하였습니다. 저희는 매번 코딩 컨테스트를 열고 있는데 2015년에는 코드 골프1, 2016년에 코드 난독화2이벤트를 개최했습니다. 저희는 지난 이벤트들을 통해 파이콘 참가자들에게 오락거리를 제공하면서 재능을 발굴할 수 있었습니다그동안 다른 후원사들도 여러 가지 훌륭한 코딩 컨테스트를 열었습니다. 저희들은 이에 고무되어 2018년 파이콘 한국 참가를 결정하면서 새로운 코딩 컨테스트 이벤트를 만들어 보기로 했습니다.저희는 이번 코딩 컨테스트의 목표를 아래 세 가지로 잡았습니다.바이럴 효과가 있을 것사람의 눈을 사로잡을 수 있어야 할 것접근성 있고 직관적인 규칙을 제공할 것위의 점들을 고려해 봤을 때 인공지능 대전 격투게임의 아이디어는 비교적 자연스럽게 도출되었다고 생각합니다.유저 대 유저가 직접 경쟁하는 방식은 코드 골프나 난독화처럼 주최 측이 취합해서 평가하는 방식보다 훨씬 버즈를 만들기 쉽습니다.대전 격투 게임이라는 틀은 30년 넘는 세월 동안 거의 그대로 유지되어 왔기 때문에 수많은 사람들에게 익숙합니다. 그리고 두 사람의 대결을 가장 직관적으로 표현할 수 있는 포맷입니다.게다가 저희는 귀여운 마스코트 캐릭터도 가지고 있습니다. 귀여운 마스코트 캐릭터들이 투닥투닥 싸우는 모습을 누가 그냥 지나칠 수 있을까요.익숙한 장르이기 때문에 게임의 규칙 역시 큰 틀을 잡는 데 어려움이 없습니다.이런저런 다른 후보들도 있었지만 이러한 이유로 격투 게임을 만들자는 합의에 다다랐습니다.게임 디자인하지만 격투 게임은 직관적으로 보이는 외양에 비해 파고들기 굉장히 복잡합니다. 현존하는 대전격투 게임들은 수많은 캐릭터가 등장하고 캐릭터별 성능 차이와 상성 관계가 존재하며 대응 전략도 전부 제각각이기 때문입니다. 저희는 이러한 요소를 전부 배제하기로 했습니다. 그런 것들이 대전격투 게임의 본질을 관통하는 특성은 아니기 때문입니다. 그것들을 전부 벗겨내면 남는 본질은 심리전입니다. 상대방의 플레이 전략을 파악한 뒤에 정보를 취합하여 액션을 취하는 것이 대전격투 게임의 알파이자 오메가입니다. 저희는 이 게임을 턴제로 설계했는데, 보통 실시간으로 이루어지는 대전격투 게임을 턴제로 설계해도 말이 되는 이유가 여기에 있다고 생각합니다. 턴제로 만들어도 대전격투 게임의 본질이 심리전이라는 대전제가 깨지지 않기 때문입니다. 저희는 인공지능 대전으로 심리전의 특징을 살릴 수 있을 거라 보았습니다.여러 가지 시스템을 고려했으나 게임 디자인은 최소화된 형태로 수렴했습니다.플레이어는 뒤 또는 앞으로 한 칸씩 움직일 수 있다.공격 방식은 펀치와 킥이 있는데, 펀치는 숙여서 피할 수 있고 킥은 점프해서 피할 수 있다.심리전이 성립하기 위해서는 최소한의 상성 관계가 만족되어야 합니다.상대방의 공격을 무조건 맞는 대신 받는 데미지를 절반으로 줄이는 방어 액션이 있다.때로는 리스크를 지지 않는 안전한 선택지도 제공하면 좋을 것입니다.그 외에 게임 디자인 과정에서 여러 가지 시행착오가 있었습니다.처음에는 캐릭터를 움직인다는 개념이 없었습니다. 두 캐릭터들이 같은 위치에 서서 싸운다기보다는 가위바위보를 하는 모양에 가까웠습니다. 그래서 캐릭터 이동 액션을 추가했습니다.그런데 스테이지 크기에 제한이 없었습니다. 플레이어가 무한히 뒤로 갈 수 있었는데 한 대 때린 뒤에 끝날 때까지 뒤로 도망가는 파훼가 불가능한 전략을 쓸 수 있었습니다. 스테이지 크기에 제한을 두는 방식으로 해결했습니다.원거리 공격, 대쉬, 필살기 등등 여러 가지 세부적인 시스템을 고려했으나 시스템이 지나치게 복잡해질 것 같았고 무엇보다 제때 밸런스를 조정할 자신이 없어서 포기했습니다.시스템을 이렇게 만들어 보니 상대가 근접하면 가만히 서서 공격만 하는 에이전트가 승리할 확률이 가장 높았습니다. 이를 방지하기 위해 최근 다섯 턴 간 취한 액션이 한 종류라면 데미지가 1/3, 두 종류라면 2/3만 들어가도록 페널티를 주었습니다.이 조치만으로는 방어/회피 없이 공격만 해도 이기는 문제를 해결하지는 못합니다. 따라서 방어/회피에 성공할수록 다음 번의 공격력이 강해지는 시스템을 추가하여 적극적으로 방어/회피를 하도록 유도하였습니다.저희는 데미지 계산 공식을 공개하는 것을 주저했는데, 구체적인 공식을 공개하면 제출물의 성향이 한쪽으로 쏠릴 것을 염려했기 때문입니다. 저희는 최대한 창의적인 솔루션이 많이 나오길 바랐습니다. 하지만 지금 돌이켜보면 구체적인 수치를 공개한다고 크게 바뀔 것이 있었나 싶기도 합니다.시각 디자인처음엔 격투 게임이라는 설정만 있었지만, 시각적으로 풍부하게 표현하기 위해 더 디테일한 기획이 필요했습니다. 그리하여 도도 파이터 만의 세계관을 만들어 풀어보기로 했습니다. 설정을 초반에 정하고 나니 캐릭터부터 모든 디자인이 술술 풀려갔습니다. 왜 게임을 만들 때 초반에 세계관과 시놉시스를 세세히 기획하는지 알겠더군요.원래 실제 도도새는 마다가스카르 동쪽에 있는 모리셔스 섬 해안가에 주로 서식한 것으로 추정된다고 합니다. 모리셔스 섬에 도도새가 모여 마을을 이루고 있는 모습을 상상했고, 그곳을 배경으로 도도 파이터가 펼쳐집니다.야자수, 뜨거운 햇빛, 맑은 바다. 그리고 자영업자가 많은 평화로운 도도 포인트 마을. 손님을 위해 더 좋은 매장을 운영하려면 체력은 필수. 각자의 방식으로 체력을 기르던 매장 사장님들이 최고의 체력왕을 고르기 위해 도도 파이터라는 대회를 개최하게 됩니다. 과연 체력왕 사장님은 누가 될까요?노을이 아름다운 모리셔스 섬에 숨겨진 도도 포인트 마을Lean하게 캐릭터 디자인하기짧은 시간 내 게임을 완성하기 위해서 그래픽 리소스 제작 비용을 줄여야 했습니다. (인력 서포트도 있었습니다3) 기존에 잘 정리되어 있는 디자인 리소스들은 이런 상황에서 특히나 빛을 발합니다. 파이터는 포포(도도새 캐릭터)로 한정하고 동작 디자인은 거의 통일하기로 했습니다. 또한, 게임 특성을 고려해 기존에 디자인되어 있던 반측면 조형만을 활용했습니다.다만 사용자간 구분이 필요하기에 각 캐릭터별 특색을 넣었습니다. 게임에 등장할 포포들은 매장 사장님이므로 격투게임에 등장하면 흥미로울 만한 업종에 계신(?) 포포만을 모셨습니다. 그리고 각 업종에 어울리는 패션 아이템과 구별되는 성격을 배합해서 총 3종의 캐릭터를 완성했습니다.도도 파이터 대회에 참가한 포포 사장님들스시 장인 포포: 철두철미한 성격으로 묵직하고 독특한 풍미의 시그니처 스시를 주 무기로 사용합니다.학원 원장 포포: 성실히 학생들을 지도하며 평소에 칠판 지우개로 팔근육을 단련해왔습니다.볼링장 사장 포포: 걱정이 많지만 볼링을 사랑하며 즐깁니다.도도 파이터에서 캐릭터는 총 9가지의 액션을 취할 수 있습니다. 기본 틀은 동일하지만 캐릭터별 특색을 넣는 것만으로도 단조로움을 없앨 수 있었습니다. 공격하는 무기는 잔인하기 보다는 귀엽고 웃긴 방향으로 해 산뜻한 분위기가 되도록 했습니다. 만약 스시 장인 포포가 칼을 들고 있었다면 게임 분위기가 살벌했을 것입니다.캐릭터들의 다양한 모습구현 상세서버서버는 아래의 소프트웨어 스택을 사용하여 구현하였습니다.파이썬 3.6Flask 웹 프레임워크PostgreSQL 데이터베이스SQLAlchemy 데이터베이스 라이브러리그 외에 설정 관리에는 settei, 데이터베이스 마이그레이션은 alembic 등 여러 오픈 소스 프로젝트를 사용하고 있습니다.이상은 스포카에서 사실상 표준으로 사용하고 있는 소프트웨어 스택이기 때문에 스포카 개발팀이 비교적 능숙하게 사용할 수 있습니다. 덕분에 3~4주 남짓한 짧은 기간 안에 완료할 수 있었습니다. 개발 당시의 급박한 상태가 그대로 드러나는 퀄리티긴 하지만, 소스 코드는 여기에서 받으실 수 있습니다. PR이나 버그 보고는 두손 두발 다 들고 환영합니다.프론트엔드게임의 프론트엔드는 Unity 엔진을 사용하여 개발하였습니다. Unity는 WebGL 타겟 빌드를 지원하는데, 이를 통해 웹 브라우저 위에서 실행가능한 WebAssembly 바이너리로 빌드할 수 있습니다.매칭 기록을 재생해주기만 하면 되는 간단한 부분이기 때문에 처음에는 런타임 바이너리 용량만 수 메가바이트에 달하는 거대한 게임 엔진을 쓰는 것이 내키지 않았습니다. HTML5 Canvas를 직접 써서 만들까 했지만, 생각보다 손이 많이 가고 제때 끝낼 자신이 없었습니다. 다행히 Unity로는 빠른 작업이 가능했고 절약한 시간만큼 애니메이션 효과와 시각적 완성도에 조금 더 시간을 투자할 수 있었습니다. 빌드 용량이 크긴 했지만, 결과적으로는 좋은 결정이었다고 생각합니다.배포 인프라도도 파이터는 Docker로 빌드되며, 스포카의 프로덕션 서비스에 사용되고 있는 AWS ECS 클러스터 위에 배포됩니다. 기존 인프라를 활용하여 추가적인 지출을 최소화할 수 있었습니다.지금에서야 말할 수 있는 사실이지만 도도 파이터는 파이콘 행사 중에도 미완성 상태였습니다. 여러분들이 도도 파이터에 참가하고 계신 와중에도 개발자는 부스 한구석에서 부리나케 작업을 하고 있었습니다. 급박한 과정에서 Docker와 ECS가 있었기에 빠른 배포가 가능했습니다.샌드박싱웹 앱 위에서 임의의 파이썬 코드를 실행을 허용하면 필연적으로 공격의 위협에 노출됩니다. 따라서 저희는 악의적인 코드가 실행되지 않도록 하는데 많은 노력을 했습니다.에이전트 스크립트는 메인 서버 프로세스와 격리되어 실행됩니다. 이때subprocess모듈을 사용합니다.스크립트는 바로 실행되지 않고 러너 안에서 실행됩니다.이때 러너에서는 스크립트가 다른 파일을 열지 못하도록__builtins__.open()함수를 지웁니다.러너 프로세스는 제한된 유저 권한으로 실행됩니다. 혹여나 다른 파일을 불러올 수 있는 가능성을 OS 레벨에서 차단합니다.보안상의 이유로 에이전트는 허용된 모듈만 불러올 수 있습니다. 러너에서는 스크립트의추상 구문 트리를 분석하여 허용되지 않은 모듈을 불러오는지를 검사합니다. 이때ast모듈을 사용합니다.러너가 참조하는 모듈을 에이전트 안에서 참조하지 못하도록sys.modules를 비웁니다.실수 또는 DoS로 스크립트가 무한 루프를 도는 상황을 방지하기 위하여 3초가 지나도 스크립트가 완료되지 않으면 프로세스를 강제로 종료하는 역할도 합니다.서버는 Docker 컨테이너 안에서 격리되어 실행됩니다. 만약 잘못된 코드로 인해서 서버가 죽는 상황이 생기면 ECS 클러스터가 자동으로 복원해 줍니다.가장 마지막으로, 모든 실행되는 코드는 기록을 남깁니다. 만에 하나 이 모든 보호 조치들을 우회한다고 하더라도 어떤 GitHub 아이디로 로그인해서 무슨 코드를 실행시켰는지 기록을 남겨서 사후에 추적할 수 있도록 하였습니다.느낀 점들무엇보다 대회 진행에 아쉬움이 진하게 남습니다. 참가자들을 여러 조로 나눈 것은 수시로 조를 배정하고 결승전 이전에 조별 우승자를 미리 선정하기 위함이었는데, 결과적으로 최종 제출 기한이 끝난 뒤에 조가 배정되고 결승 중계 현장에서 조별 우승자가 정해졌습니다. 이로 인해 결승 중계 진행이 많이 늘어졌던 것 같아서 아쉽습니다.참가자와의 소통을 위한 피드백 창구가 없었던 점 또한 아쉽습니다. 몇몇 참가자 분들께서는 직접 부스로 찾아오셔서 문의하시기도 했습니다. 생각하지 않은 것은 아니었는데 다른 시급한 작업이 우선이라 엄두를 내지 못했습니다.예상보다 참가자들이 많아서 결승전 중계 때는 시간이 많이 밀렸습니다. 플레이백 속도를 조절할 수 있는 기능을 넣었어야 했다는 아쉬움도 남네요.처음에 우려했던 밸런스가 붕괴하는 상황은 다행히 발견되지 않았습니다. 승리에 유리한 전략은 어느 정도 경향성이 있는 것으로 보이나 게임의 밸런스가 망가진 수준까진 아니라고 판단하고 있습니다.마치며여기까지가 장장 4주에 달하는 도도 파이터의 제작 후기였습니다. 후속 포스팅에서 이번 파이콘 한국 2018 세션에서 제출된 출품작들을 분석하고 어떤 참신한 코드가 있었는지를 알아보도록 하겠습니다. 읽어주셔서 감사합니다.특정 목적을 달성하는 프로그램을 가장 짧은 길이로 작성하여 겨루는 경쟁 게임입니다. ↩창의력을 동원하여 어떤 목적을 달성하는 코드를 가장 알아보기 어렵게 작성하는 경쟁 게임입니다. ↩디자인 서포트를 해주신 안정빈 디자이너에게도 감사를 표합니다. ↩#스포카 #기업문화 #조직문화 #개발자 #개발팀 #프로젝트 #후기 #일지
조회수 1058

DevOps 문화 안에서의 APM의 역할 [1] (DevOps+JENNIFER)

 DevOps의 시작언제나 그랬듯이 소프트웨어 개발 트렌드는 계속 변화하고 있다. A부터 Z까지 모든 것을 새롭게 개발했던 것과 달리 아키텍처나 사용하는 용도에 따라 개방형 플랫폼이나 오픈소스 등을 활용하여 원하는 소프트웨어를 쉽게 개발할 수 있게 되었다. 또한 클라우드로 인해 애플리케이션과 서비스 개발에 대한 새로운 패러다임이 나타나고 있다. 기존의 온-프레미스 환경에서는 물리적 서버 준비, 운영체제 설치, 서비스 배포 등에 수많은 시간이 걸렸지만, 클라우드를 활용하면서 단시간에 원하는 자원을 준비하고 배포할 수 있게 되었다.이러한 변화로 개발자의 영역이 좀 더 넓어지는 계기가 되었다. 이는 전통적인 비즈니스 환경에서 개발, 빌드, 테스트, 배포, 운영에 이르는 프로세스를 효율적으로 운용할 수 있게 되어 고객의 요구사항을 빠르게 반영할 수 있게 되었다. 이것이 바로 DevOps의 시작이다. 하지만 다양한 오픈소스의 탄생과 클라우드 환경의 확산 등으로 인해 정말로 새로운 기능에 대한 개발이 빨라졌을까? 그렇다면 이에 따른 문제는 없을까? 개발 프로세스의 병목 구간DevOps의 필수 조건인 테스트 및 배포의 자동화가 이뤄지면 운영 단계에서는 반영된 사항들에 대해 주기적으로 모니터링을 해야 한다. 만약에 반영된 소스코드에 장애를 발생시킬 수 있는 잠재적 버그가 존재한다면 이를 어떻게 운영 단계에서 찾을 수 있을까? 예를 들어 특정 서비스의 피크타임에 부하가 급증한다면 앞서 말한 상황에 대한 버그가 발생할 확률이 상대적으로 높아진다. 하지만 장애의 원인이 될 수 있는 요소는 매우 다양하기 때문에 단순히 트래픽 문제로 속단할 수는 없다.직접 개발한 소프트웨어만의 문제가 아닐 수도 있으며, 제품 개발시 생산성 향상을 위해 도입된 다른 종류의 오픈소스에서 문제가 될 수도 있다. 실은 이런 류의 프로젝트들은 상용 제품이 아니므로 문제가 발생하면 상당히 곤란한 경우가 생기곤 한다. DevOps를 위한 환경이 구성되고, 고객의 요구사항을 빠르게 반영할 수 있는 시스템이 갖춰졌더라도 결국에는 앞서 말한 다양한 종류의 잠재적, 환경적인 문제들로 인해 병목이 발생할 수 있다.  모니터링 단계에서 APM의 역할개발 프로세스의 마지막 관문인 모니터링 단계는 DevOps에서 매우 중요한 역할을 한다. 하지만 안타깝게도 이미 반영된 실제 서비스에서 모니터링을 성공적으로 마치고 피드백 수집 단계로 넘어가기 위해서는 앞서 말했던 장애의 원인을 빠르게 진단해야 한다. 경우에 따라 많은 시간이 소모되기도 하기도 하며, 이는 바로 생산성 저하로 이어진다. 또한 새로운 프로세스 진행을 더욱더 보수적으로 만드는 원인이 된다.DevOps를 완벽하게 실현하기 위해서는 모니터링 단계에서 서비스 배포 이후의 서버에 들어오는 트랜잭션에 대한 상태를 배포 전과 비교할 수 있어야 하며, 응답을 지연시킬만한 요소들을 빠르게 인지할 수 있어야 한다. 그리고 배포된 소스코드로 인해 서비스 장애가 발생하는 상황이 온다면 이를 처리하기 전까지 어떻게든 서비스 장애를 지연시켜야만 한다. 이러한 이유로 DevOps 진영에서는 APM의 역할은 매우 중요한 이슈이다. 우리는 제니퍼를 통해 앞서 말한 기능들을 활용하는 방법에 대해 알아볼 것이다. 모니터링 프로세스모니터링 단계는 아래 그림과 같이 문제의 발견 및 조치, 문제해결시 재배포 단계로 나눌 수 있다.  제니퍼 대시보드를 통해 액티브서비스 상태와 트랜잭션 변화 추이를 모니터링 할 수 있는데, 만약에 새로 배포된 소스코드에 문제가 있다면 처리 중인 액티브서비스가 쌓이게 되고 , 트랜잭션 분포도 차트는 기존에 그려졌던 패턴과 다르게 보여지게 된다.이런 시점에 운영에서는 설정 여부에 따라 이벤트를 발생 시킬 수 있다. E-Mail이나 SMS, Slack과 같은 메신저 등으로 각각의 담당자들에게 서비스 상태를 알려줄 수 있으며, 담당자에게 이벤트 메시지가 전달되었다면 제니퍼를 통해 두가지 조치를 할 수 있게 된다. 먼저 개발자는 스마트 프로파일링 기능을 통해 원인분석을 하고, 운영에서는 서비스가 최악의 상태가 되기 전에 트랜잭션 유입을 차단하여 다른 화면으로 리다이렉트 시켜주는 PLC 기능을 사용할 수 있다.제니퍼에서는 서버에서 하나의 요청에 대한 처리가 끝나면 곧바로 수집되는 데이터를 트랜잭션이라하며, 현재 수행 중인 상태에 대한 실시간 데이터를 액티브서비스라고 정의한다.   모니터링 기준 값 설정서비스를 배포하기 전에 모니터링 단계를 원활하게 수행하기 위해서는 제니퍼 관리 화면에서 몇가지 설정을 해야한다. 먼저 서비스 장애 발생시 이벤트 알림 및 서비스 부하량 제어 설정의 기준이 되는 값인 전체 에이전트의 평균 액티브서비스 개수를 알아야 한다. 하지만 서비스가 운영되는 환경에 따라 기준 값이 너무 다르기 때문에 어느 정도 안정적으로 서비스가 운영되고 있다고 생각하는 시점에 대략적으로 기준 값을 정하면 된다.에이전트란 모니터링 대상 애플리케이션에 기생하여 성능 데이터를 수집하고, 이를 서버로 전송하는 역할을 하는 모듈을 말한다. 참고로 모니터링 대상 애플리케이션은 플랫폼 환경에 따라 차이가 있을 수 있는데, 일반적으로 WAS(Web Application Server)나 웹 서버를 말한다.  액티브서비스는 처리가 완료되지 않은 상태이므로 서비스 장애의 원인분석을 위한 데이터로는 적합하지 않다. 그렇기 때문에 액티브서비스 개수는 기준 값이 될 수 없으며, 개발자는 처리가 완료된 트랜잭션 데이터의 응답시간을 기준 값으로 제니퍼의 프로파일링 관련 설정을 해야 한다. 설정된 값을 기준으로 트랜잭션 분포도 차트에서 가상의 선을 긋고, 그 선 위에 있는 트랜잭션을 대상으로 스마트 프로파일링 기능을 수행할 수 있다.  본문에서는 모니터링 단계에서 직면하게 되는 문제점과 이를 해결하기 위한 APM의 역할과 필요성 대한 이야기를 했다. 다음 편에서는 본격적으로 제니퍼를 활용하여 모니터링 프로세스를 어떻게 수행하는지에 대해 알아볼 것이다.2편에서 계속...
조회수 1104

앱 공모전 기획자에서 비전공 개발자가 되기까지

스푼을 만드는 사람들 다섯 번째 이야기클라이언트팀의 유일한 여성 개발자 Julia를 소개하고자 한다.바나나 최대 몇 개까지 드세요?"마케팅팀 썸머에겐 아귀찜이 있다면, 저에겐 '바나나'입니다. 저는 바나나 우유도 좋아하고, 바나나 한 송이를 그 자리에서 혼자 다 먹을 만큼 좋아해요. 카카오톡 이모티콘도 바나나 이모티콘을 가장 많이 사용할 정도로요. 바나나는 맛도 있지만, 먹으면 기분이 좋아지는 과일이에요"(인터뷰 후, 줄리아에게 바나나 한 다발 선물해드렸습니다. 맛있게 드셨길 바라요)Q. 할머니 감성을 가지셨다고 들었는데, 사실인가요? "네, 모르시는 분들이 많으시겠지만 저는 친구들이 '할머니'라고 불러줘요. 이유인즉슨, 건강에 관심이 워낙 많아서 영양제도 잘 챙겨 먹고 꽃무늬 옷이 많거든요. 정확히 말하면 꽃무늬 치마! 그리고 사석에서는 고향(전라도) 사투리를 많이 써서 그런 것 같아요"줄리아 닮은꼴: 닥터 슬럼프 아리 '줄리아'를 더 알아가고 싶어요본인은 어떤 사람이라고 생각하세요?독한 사람 - 저는 웬만한 것에 있어서 타의적으로 절대 포기를 하지 않아요. 제 스스로가 싫증이 날 때까지는 꼭 끝까지 해내고 말거든요.그래서 전 제 스스로를 독한 사람이라고 말하고 싶어요. 이전부터 개발자로서 커리어를 쌓아오셨나요?"저는 원래 문과생이에요. 비전공자죠. 대학 때 독어를 전공했고, 개발과는 사실 거리가 먼 사람이었어요. 저는 이 전에 많은 경험들을 해왔어요. 세계일주를 하고 싶어서 해상 승무원 준비도 했었고, 중국에서 무역회사에서 근무도 했었고요. 통역도 잠시 했었고, 이 전에는 앱 공모전 기획자로서의 삶도 있었어요. 앱 공모전 기획자라는 건, 회사 및 대회를 홍보하기 위해 직원 대상 또는 시민을 대상으로 행사 및 공모전을 기획해서 행사업체를 고용하거나 직접 운영하는 업무랍니다. 그리고 현재는 안드로이드 개발자로 커리어를 쌓고 있습니다."많은 커리어를 거쳐 개발자가 되신 계기가 있다면?"저는 인생 계획을 짧으면 5년, 길게는 10년씩 잡고 살아가요. 20대 때는 해보고 싶은 게 너무 많았고, 지금도 여전히 많아요. 그래서 20대는 정말 하고 싶은 모든 걸 해보자라는 마음으로 살아왔어요. 30대가 되면서 조금 더 안정적으로 살고픈 마음이 생기기 시작했고 무엇보다 하나의 전문적인 직업을 가지고 싶단 욕구가 커졌어요. 그래서 개발을 선택하게 되었습니다."책상에 약이 굉장히 많네요?"제가 아까 할머니 감성이 있다고 했는데.. 저는 건강을 엄청 챙기거든요.. 그래서 탕비실에도 돼지감자 차 및 영양제 등 굉장히 뭘 많이 챙겨 먹습니다. 그래서 제 책상엔 비타민 등 영양제가 가득하답니다!"집에서 가져온다는 돼지감자 차 당신의 회사생활이 궁금합니다Q. 여성 개발자로 일하는 삶은 어떤가요?"사실 저는 '개발'을 하는 일을 성별로 나누고 싶지는 않아요. 남자 개발자가 많은 이유는 아무래도 공대에 남성 비율이 더 많기 때문이라고 생각이 들기도 하고, '여자' 이기에 특별히 다르다거나 불편한 점은 없어요. 아직은 신입 개발자이다 보니, 배우고 있는 시점이기도 하고요. 그저 열심히 배우는 단계라고 봐주시면 좋을 것 같습니다 :) 무엇보다 제 위로 8년 차, 14년 차 선배분들과 함께 일하면서 정말 많이 배우고 있습니다."Q. 일하면서 언제가 가장 뿌듯하세요?"개발을 하시는 분들은 공감하실 텐데.. 안되던 문제가 갑자기 될 때(?)에요. 분명히 어제는 안됐는데, 오늘은 되는 날이 있거든요. 반대인 경우도 있고요. 그때 정말 뿌듯(?)하고 행복해요. 또 다른 하나는, 보통 다른 곳은 신입 개발자는 보조만 하는 경우가 많거든요. 하지만 팀원들이 저를 믿어주셔서 제가 새로운 기능을 맡아서 짠 추가 코드가 프로덕트에 적용이 될 때가 정말 뿌듯해요."Q. 회사 다니면서 가장 기억에 남는 일이 있다면?"제가 입사 후 함께 처음으로 새로운 국가에 출시했을 때요. 저는 새로운 국가에 서비스를 출시할 때마다 너무 기대되고 업무가 더 즐거워져요. 조금 더 다양한 업무가 주어지고, 생각도 더 많이 하게 되거든요. 그리고 저는 건강에 정말 신경 많이 쓰는데, 저번에 Jun 이 막내 특집(?)으로 홍삼 음료를 주셨는데.. 너무 취향 저격인 거예요. 딱 제가 정말 좋아하는 건강한 맛! 그래서 그날도 너무 행복했어요."Q. 어떤 사람과 일하고 싶으세요?배울 점이 있는 사람이요. 저 또한 누군가에게 배울 점이 있는 사람이고 싶어요.줄리아 업무 공간 당신의 사생활이 궁금합니다Q. 안드로이드 개발자는 안드로이드만 사용하나요?"모두가 그런 건 아니겠지만, 저는 사실 여태 살면서 안드로이드 폰만 사용했었어요. 무엇보다 저는 안드로이드 캐릭터가 너무 귀엽다고 생각하기에.."Q. 주말에는 무엇을 하며 시간을 보내세요?"저는 지난 1년간은 매주 주말마다 코딩 스터디를 해왔어요. 아무래도 비전공자에 늦게 시작한 개발자다 보니 엄청난 노력이 필요하거든요. 지금도 스터디를 하고 있어요. 그리고 2019년부터 목표는 한 달에 한 번쯤은 리프레쉬하기 위해 가까운 곳이라도 여행을 가려고 노력하고 있어요."Q. 개발자가 된 후 삶에 있어 변한 점이 있다면?"예전에는 어떤 것을 설명하거나 표현할 때, 굉장히 문과적(?) 이게 표현을 했었던 것 같아요. 지금도 완전히 바뀌진 않았어요. 하지만, 무언가 문제가 있을 때 원인과 결과를 먼저 파악하는 성향이 생겼달까요? 그리고 편견일 수도 있지만 조금 더 프로페셔녈 해 보이고 싶어서 백팩이나 후디를 자주 입습니다!" 비전공자로서 개발자를 꿈꾸는 사람들에게 "먼저, 비전공자라 하여 못할 거라는 생각을 하지 않으셨으면 좋겠어요. 저도 여전히 배우고 있는 입장이지만 생각보다 비전공자 중에 개발자로서 훌륭하신 분이 굉장히 많거든요. 늦더라도 정말 하고 싶은 마음이 있다면 꼭 도전하라고 말하고 싶어요. 그리고 꼭 영어 공부하세요. 아무래도 문서들이 영어로 되어있으니, 영어를 배워두면 번역기의 도움이 없이도 되기에 큰 도움이 되고 시간이 절약되거든요! 아, 그리고 개발을 배우고자 만약 학원에 가서 수업을 들을 예정이시라면, 수업을 듣기 전에 혼자라도 미리 예습을 하고 가셨으면 좋겠어요. 학원을 다닌다고 해서 정말 모든 걸 알려주진 않거든요. 얼마나 열심히 하고 노력하느냐에 따라 성패가 달린다고 생각합니다."안드로이드 팀원들이 줄리아를 한마디로 표현한다면?Derek 曰:  “줄리아는 강한 사람이라고 생각합니다. 외부의 환경에 흔들리지 않고 자신의 꿈을 향해 계속 전진하는 강한 사람이라고 생각합니다.”Yong 曰:  "낯선 길에서 의지를 잃지 않고 가고자 하는 길을 걷는 사람, 그리고 미소가 예뻐서 꽃 같은 사람입니다" 
조회수 1071

주니어 개발자가 외칩니다, "Hello, System Architecture!"

Overview주니어 개발자는 시스템 아키텍처(System Architecture) 또는 시스템 디자인(System Design)이라는 단어에 덜컥 겁부터 먹습니다. 지금 진행하고 있는 개발에만 집중하다 보니 큰 그림을 놓치고 있는 게 아닐까 란 생각이 들었죠. 조금 더 큰 그림을 보고자 공부를 시작했습니다. 문득 같은 생각을 하는 주니어 개발자 분들도 많을 것 같다고 생각했어요. 그래서 이번 글은 시스템 아키텍처에 ㅇ_ㅇ? 뀨? 하는 표정을 짓는 주니어 개발자들을 위해 썼습니다.상상의 나래: 가상의 패션 e커머스상상의 나래를 펼쳐봅시다. 패션 e커머스 서비스를 이용하는 김유저 씨가 구매한 옷이 마음에 들어 상품 리뷰를 남기고 싶어한다고요.김유저 씨는 본인의 착용 사진과 텍스트 리뷰를 작성하고 ‘리뷰 등록하기’ 버튼에 엔터를 탁! 누를 겁니다. 그런데 말이죠. 김유저 씨는 요청하고 싶은 웹서버의 IP 주소를 모르기 때문에 요청을 보낼 수가 없습니다.내 정체를 알려줘: DNS (Domain Name System)그래서, DNS(Domain Name System)에게 물어봅니다. 서버의 도메인 이름으로부터 해당 서버의 IP 주소를 알려주는 것이 바로 DNS입니다. 도메인 이름에 대한 질의를 하고, 만일 해당 도메인 이름이 DNS에 ‘A Record’ 형태로 등록이 되어 있다면 도메인 이름에 해당하는 IP 주소를 응답으로 돌려줍니다.서비스에서 자체 DNS 시스템을 가지고 있을 수 있습니다. 예를 들어 Route 53, Cloud Flare같은 서비스가 있습니다. 그렇다면 또 한 가지 의문이 생깁니다. 왜 서비스는 시스템적 부담을 안고서 자체 DNS 서버를 구축하고 있는 걸까요? 그 이유로 두 가지를 꼽을 수 있습니다.첫 번째로는 신뢰도가 높습니다. 직접 DNS Record를 관리 및 운영하기 때문입니다. 두 번째로는 보안이 우수합니다. 만약 공개하고 싶지 않은 IP 주소, 예를 들어 Database IP 주소 같은 건 공개하지 않습니다. 1)작업장소: Web Server이제 웹서버의 IP 주소를 알았으니 통신을 시도합니다. 웹서버는 웹서비스에서 필요로 하는 다양한 요청과 그에 대한 응답을 제공합니다. 클라이언트가 리뷰에 대한 사진과 텍스트를 등록하고 싶다면 웹서버에게 등록하라는 요청을 보내야 합니다.웹서버에서 요청을 받으면 사용자가 요구한 대로 사진과 텍스트를 등록하고, 그에 대한 결과 정보를 응답으로 보내줄 것입니다. 웹서버 내부에서는 그 과정에 필요한 연산을 수행합니다. 서버 개발자는 이 연산에 대한 코드를 작성하고요.센스가 없는 서버:API (Application Programing Interface)서버는 사람이 아닙니다. 센스나 재치가 없죠. 미리 정의되지 않은 요청은 대응하지 못합니다. (어버버버버 퉤! Error 404!) 그래서 약속한 요청을 보내면 약속한 방식으로 응답해줄게라고 명세를 제공합니다.약속한 요청으로 데이터를 보내면 원하는 요청에서 데이터를 정제해 잘 처리했는지, 또는 처리된 데이터를 약속한 방식(예를 들어, JSON 방식)으로 내보내죠. 웹서버는 정의된 API에 맞춰 요청과 응답을 합니다.그런데 웹서버가 수많은 요청을 받고 응답하면 과부하가 일어날 수도 있습니다. 사용자 수가 어마어마한 규모로 늘어나서 서버가 펑! 하고 터진다면, 김유저 씨는 서비스를 더 이상 이용할 수 없을 겁니다. 이용하고 싶지도 않을 겁니다!따라서, 서버가 감당하는 요청을 나누기 위해 같은 역할을 하는 서버 장비 수를 늘릴 수도 있습니다. 그러면 요청이 각기 다른 웹서버 장비에 분산되어 한 번에 감당할 수 있는 요청 수가 더욱 많아집니다.이 구역의 매니저는 나야: Load Balancer그림처럼 서버가 4대 존재하는 상황이라면, 서버 4대에 일을 적절히 분배해주는 역할이 필요합니다. 그것이 로드 밸런서(Load Balancer)입니다. 로드 밸런서가 서버에게 일을 나누는 방법론은 여러 가지가 있습니다.Random: 랜덤으로 분배하기Least loaded: 가장 적은 양의 작업을 처리하고 있는 서버에게 요청을 할당하기Round Robin: 순서를 정하여 돌아가며 작업 분배하기많이 쓰는 로드 밸런서의 종류는 Layer 4, Layer 7을 꼽을 수 있습니다.Layer 4 Load Balancer: 데이터의 내용을 보지 않고 IP주소 및 TCP/UDP 정보에 따라 단순히 분배를 해줍니다.Layer 7 Load Balancer: 서버가 하는 역할이 분리되어 있는 환경에서 데이터의 내용을 보고 각기 맞는 역할을 하는 서버에게 분배를 해줍니다.로드 밸런서는 클라이언트가 요청을 보내야 할 서버를 골라야 하는 부담을 덜어주며, 로드 밸런서에게 할당된 vIP (가상 IP)로 요청을 보내기만 하면 로드 밸런서에서 알아서 작업을 나눠줍니다. 서버에서는 적절한 로드 밸런서를 사용하면 들어오는 요청이 여러 장비에 분산되어 처리량이 늘어나고 응답 시간이 줄어드는 효과를 기대할 수 있습니다. 컨텐츠 저장소: CDN(Content Delivery Network)이제 웹서버가 클라이언트의 요청에 의해 웹페이지에 대한 응답 결과를 돌려줬습니다. 이때 클라이언트의 화면에 렌더링해야 하는 수많은 이미지가 필요합니다. 이 이미지들을 웹서버가 전부 주려면 데이터의 용량이 너무 크고, 무거워서 서버가 헥헥거리죠. (서버가 죽으면 어떻게 될까요? 클라이언트님이 경쟁사로 환승하겠죠.. 안 돼요..) 따라서 웹서버는 직접 이미지를 주는 대신 CDN(Content Delivery Network)에게 요청하라고 이야기합니다. CDN은 일반적으로 용량이 큰 컨텐츠 데이터(이미지, 비디오, 자바스크립트 라이브러리 등)를 빠른 속도로 제공하기 위해 사용자와 가까운 곳에 분산되어 있는 데이터 저장 서버입니다. 클라이언트는 용량이 큰 컨텐츠 데이터를 가까운 CDN에 요청해 멀리 있는 웹서버에서 직접 받는 것보다 빠르게 받을 수 있습니다. CDN이 동작하는 방식에는 크게 Push CDN, Pull CDN이 있습니다. Push CDN: 서버에서 컨텐츠가 업로드되거나, 변경되었을 때 모두 반영하는 방식 Pull CDN: 클라이언트가 요청할 때마다 컨텐츠가 CDN에 새로 저장되는 방식 두 방식 모두 장단점이 있습니다. Push CDN은 모든 컨텐츠를 갖고 있기에 웹서버에 요청할 일이 없지만 유지하는데 필요한 용량과 비용이 많이 필요하겠죠? Pull CDN은 클라이언트가 요청한 컨텐츠가 있으면 바로 응답하지만 그렇지 않을 땐 데이터를 웹서버로부터 가져와야 하기 때문에 서버에 요청하는 부담이 존재합니다. 컨텐츠명은 그대로인데 내용만 변경되었다면 인지하지 못하고 옛버전의 컨텐츠를 제공하죠. 그래서 Pull CDN에 들어가는 컨텐츠는 TTL(Time To Live)이 적용됩니다. TTL이란 유통기한이라고 생각하면 쉽습니다. 일정시간이 지나면 해당 데이터가 삭제되는 것이죠. 이런 방식이 적용된다면 Pull CDN의 최대 단점을 보완할 수 있습니다. 이렇게 보완이 되면 수정된 데이터에 대해서도 대응이 가능하며 서버의 용량 즉, 비용적 부담이 해소될 겁니다.소중한 내 데이터: Database서비스를 제공하다 보면 클라이언트의 소중한 정보, 이력, 상품 가격, 상품 정보 등 다양한 데이터를 저장하고, 또 제공합니다. 하지만 수많은 데이터를 웹서버에 전부 저장하고 사용하기엔 데이터의 양이 너무 많아 저장 공간도 부족하고, 데이터를 원하는 모양에 맞게 정제하기가 어렵습니다. 그래서 데이터를 저장하는 데이터베이스 서버가 따로 존재합니다.민감한 정보를 다루는 데이터베이스는 ACID라는 성질을 만족해야 하는데요.Atomicity(원자성): 데이터베이스에 적용되는 명령이 중간만 실행되지 않고 완전히 성공하거나 완전히 실패해야 한다는 것을 의미합니다. 반만 적용된 명령이 있다면 헷갈리겠죠.Consistency(일관성): 데이터베이스가 수행한 명령이 일관적으로 반영되어 있어야 한다는 의미입니다. 예를 들어 계좌에 돈을 입금했는데 잔고에 반영되지 않는다면 당황스러울 겁니다.Isolation(고립성): 데이터베이스가 수행하는 명령 도중 다른 명령이 끼어들지 못한다는 것을 의미합니다.Durability(지속성): 성공적으로 수행한 명령은 영원히 그 이후 상태로 남아있어야 한다는 걸 의미합니다. 갑자기 하루 뒤에 명령이 취소되거나 이전 상태로 롤백되면 안 됩니다. Replication (복제 / 이중화)큰 시스템에서는 똑같은 데이터베이스가 여럿 존재한다고 하는데요. 그렇다면 왜 비용적인 부담을 안으면서까지 복제 데이터베이스를 구축해놓는 걸까요? 만약에 데이터베이스가 정상적으로 동작하지 않는다면 클라이언트의 데이터를 변경하지 못하며, 클라이언트가 원하는 정보를 제공하지 못하는 불상사가 일어나게 됩니다. 글로만 써도 벌써 땀이 납니다. 그러므로 복제해놓은 데이터베이스를 얼른 마스터로 등업해 데이터 흐름에 차질이 없도록 대비해야 합니다.만약 하나의 데이터베이스가 어떤 일을 수행할 때 다른 요청들은 계속 기다려야 합니다. 그렇다면 데이터를 변경하는 데이터베이스는 하나, 읽기만 하는 데이터베이스는 여러 대가 존재해도 되지 않을까요? 바로 여기서 Master-Slave의 개념이 탄생합니다.master-slave-replicaMaster-Slave Replica (a.k.a 주인-노예)요청을 분산하기 위해서 데이터베이스를 늘리다 보면 master-slave 토픽이 등장합니다.Mater: CRUD(Create, Read, Update, Delete)가 모두 가능Slave: R(Read)만 가능Master가 데이터를 변경할 동안 읽기에 대한 요청은 Slave에게 보내집니다. 그렇게 하면 읽기 요청은 분산되어 훨씬 더 수월하고 빠른 속도로 데이터 처리가 가능할 것입니다. 만약 Master가 변경된다면 아래 계급인 Slave, Replica 데이터베이스에게도 이 정보를 전해야 합니다. 다시 말해, 자신에게 들어온 요청(Query)을 동일하게 보내 빠른 시간 안에 동기화를 시켜주죠. 하지만 동기화도 시간이 걸리는 작업이므로 무한대로 Slave Replica를 늘려 확장하기는 어렵습니다.Master-Master Replica의문이 하나 생길 겁니다. “여러 대의 Master를 두어서 변경도 가능하고, 읽기도 가능하게 하면 되지 않을까?”앞서 언급했듯이 같은 데이터의 변경 가능한 데이터베이스는 하나여야 할 것입니다. 동시에 같은 데이터를 변경했을 때 갈등을 해소하기 위한 방법론은 존재하지만, 그 방식이 복잡하고 오래 걸립니다. 안정성도 낮아지고, 효율도 떨어집니다. 그래서 Master-Slave 아키텍처를 선호하는 것이죠.Sharding그러면 같은 데이터베이스 테이블을 동시에 변경하는 건 불가능한 걸까요? 그것을 해소하기 위해 샤딩(Sharding)이라는 방법론을 사용합니다. 샤딩된 테이블은 개념적으론 하나의 테이블처럼 보이지만 사실 그 내용물이 쪼개져 있습니다. 쪼개는 방법은 여러 가지 선택할 수 있습니다만, 분명한 건 겹치는 데이터 없이 쪼갠다는 것입니다. 그래서 같은 테이블이어도 쪼개져 있다면 그 테이블에 동시에 접근해 데이터를 변경할 수 있는 것이죠.이외에 서비스별, 기능별로 쪼개어 데이터베이스를 관리하는 Federation 등 많은 데이터베이스 디자인 방법론이 존재합니다.시스템 아키텍처가 가지고 있어야 할 최소본 아키텍처요점: 시스템 아키텍쳐에서 고려해야 할 성질이렇게 간단한 시스템 아키텍처의 면면을 살펴봤습니다. 시스템 개발자라면 시스템을 디자인하면서 반드시 고려해야 할 성질들을 만날 텐데요. 위에서 소개한 내용들 역시 아래의 성질들을 충족하기 위해 탄생했다고 볼 수 있습니다.Scalability (확장성): 10만 명의 요청을 처리할 수 있는 시스템과 1000만 명의 요청을 처리할 수 있는 시스템은 다릅니다. 확장성을 고려한 시스템은 앞으로 클라이언트 수가 늘어났을 때 무리 없이 모든 요청을 처리할 수 있을 겁니다.Performance (성능): 속도와 정확성을 말합니다. 요청한 내용을 정확하고 빠르게 돌려주어야 합니다.Latency (응답 시간): 모든 요청은 클라이언트가 불편해하지 않을 정도로 빠른 시간 안에 돌려주어야 합니다.Throughput (처리량): 같은 시간 안에 더욱 많은 요청을 처리한다면 좋은 시스템입니다.Availability (접근성): 사용자가 언제든지 시스템에 요청을 보내서 응답을 받을 수 있어야 합니다. 비록 서버 장비 한두 대가 문제가 생겨 제 기능을 하지 못하더라도 사용자는 그 사실을 몰라야 합니다.Consistency (일관성): 사용자가 서버에 보낸 요청이 올바르게 반영되어야 하고, 일정한 결과를 돌려주어야 합니다. 요청을 보낼 때마다 불규칙한 결과를 돌려준다면 믿을 수 없는 서비스가 될 것입니다.결론발로 그렸나 싶을 정도의 그림과 기나긴 글을 마무리 지으며주니어 개발자로서 시스템 아키텍처를 공부하면서 느낀 점이 있다면 시스템에 대한 완벽한 대응은 없으며, 모두 장단점이 존재한다는 것입니다. (이것을 보통 trade-off라고 표현합니다.)하지만 설계하는 서비스를 잘 알고 서비스에서 무게를 둬야 할 부분을 파악한다면, 그에 맞는 시스템을 설계하고 디자인할 수 있을 겁니다. 김유저 씨도 만족시킬 수 있을 거고요. 꼬박 이틀을 밤새워서 쓴 글이 아직 시스템 아키텍처를 두려워하는 다른 주니어 개발자분들에게 도움이 되었으면 합니다. 이번에는 시스템에서 아주 기초적인 부분을 공부했으니 다음 글에선 MSA(MicroService Architecture)를 씹어봅시다! 겁이 나고 무서워도 외쳐보세요. “Hello, System Architecture!”이 세상 모든 주니어 개발자분들, 퐈잇팅입니다.참고1) 추가적인 이점에 대하여: 웹서버에서 요청을 보낼 때 database 도메인 네임으로 보낼 경우, 멀리 있는 공인 DNS 서버 (예를 들면 google public DNS server: 8.8.8.8)에 물어오는 것보다 자체 DNS 서버에 물어오는 것이 훨씬 더 빠른 속도로 응답을 받아올 수 있습니다.출처GitHub - donnemartin/system-design-primer: Learn how to design large-scale systems. Prep for the system design interview. Includes Anki flashcards.글오연주 사원 | R&D 개발2팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발자 #개발팀 #인사이트 #경험공유 #주니어개발자
조회수 972

[Tech Blog] Software architecture: The important stuff

마틴 파울러는 Software architecture 를 “무엇이건 간에 중요한 것들(The important stuff whatever it is)” 이라고 정의합니다. 조금은 재미있는 정의지만, 그 정의를 도출하기 위해 제시한 다른 정의를 들어보면 고개를 끄덕이게 합니다.  Software architecture 는 전문 개발자들이 같은 생각을 가지고 이해하는 시스템 디자인입니다. Software architecture 는 이른 시기에 정해져야 하는 디자인 결정들입니다. 혹은 여러분이 “아, 처음부터 좀 더 잘 생각하고 할 껄”이라고 후회하는 바로 그 결정들입니다. Software architecture 는 또한 바꾸기 어려운 결정들의 집합입니다.  결국 무엇을 중요하게 생각할 것인가, 그것이 Software Architecture 라는 의미입니다. Why is it important? 왜 중요한지 설득하지 못한다면 사실 중요하지 않은 것일지도 모르죠. 그래서 왜 Software Architecture 이 중요한지 짚어보고자 합니다. 쿠팡은 Microservice architecture 로 전환하는 여정을 글로 남겼는데요. 블로그 글의 제목을 “행복을 찾기 위한 우리의 여정” 이라고 지었습니다. (좋은 글이니 읽어보시길!) 다시 말해서, Software Architecture는 개발가자 더 좋은 제품을 만들 수 있는 길이기 때문에 중요하다고 말합니다. 그러나 좋은 Software Architecture를 만드는 일은 쉽지 않습니다. 블로그 글을 인용 해보겠습니다: “여기 저렴한 제품과 비싼 제품이 있습니다. 비싼 제품은 software architecture 가 잘 고려되어 있고, 저렴한 제품은 시스템 디자인에 대한 고민 없이 구현되어 있습니다. 하지만 두 제품은 겉으로 보기에 차이가 없습니다. 소비자가 보기에 똑같이 보이고, 똑같은 기능이 있으며, 성능 또한 같습니다. 어떤 제품을 사야할까요?” 소비자는 제품을 만든 개발자의 행복을 위해 더 비싼 제품을 선택하지는 않습니다. 개발자 역시 동료들에게 “내가 행복하려면 시간과 돈이 좀 더 들더라도 좋은 software architecture 를 구성해야 해.” 라고 주장하기엔 설득력이 부족하죠. Software architecture 가 왜 중요한지 모두가 공감하려면 경제적인 입장에서 그 중요성을 설득해야 합니다. “내부 품질을 좀 포기하더라도 이번 릴리즈에 더 많은 기능들이 들어가야 해.” 라는 의견에 “안돼 우리(개발자)는 더 전문적으로 구성해야 해.”라는 의견으로 대응하면 항상 질 수 밖에 없습니다. 장인 정신과 경제 논리 사이의 싸움에서는 경제 논리가 항상 이겨왔거든요.   Cumulative functionality over Time Software architecture 를 고려하지 않으면서 제품을 개발하면 초기에는 기능 추가 속도가 빠를 수 있지만, 시간이 흐름에 따라 제품의 기능 증가 속도는 점차 느려집니다. 이미 구현된 기능들과 코드가 새로운 기능을 추가하는데 걸림돌이 되기 때문입니다. 한편, 좋은 설계를 지속적으로 건강하게 유지하고, 주기적으로 리팩토링을 하고, 코드를 깨끗하게 유지한다면 시간이 흘러도 기능 추가가 느려지지 않을 수 있습니다. 오히려 기능을 추가하기 위해 수정해야 할 곳들이 명확하고 모듈화 또한 잘 되어있기 때문에 시간이 갈 수록 기능 추가가 더욱 빠르게 진행될 수 있습니다. 새로운 개발자가 참여하는 시점에도 시스템을 더욱 빠르게 이해하고, 더 빠르고 안전하게 기능을 추가할 수 있게 됩니다. 결국 장기적으로 더 많은 기능을 생산하고 빠르게 고객에게 전달하기 위해서 개발팀은 좋은 디자인과 설계에 대해 깊게 고민해야 합니다. What is the best software architecture? 옳은 software architecture 는 없습니다. 상황에 따라 해답은 다를 수 있습니다. Microservice architecture 가 좋다고 해서 모든 것에 대한 답이 microservice architecture 인 것은 아니고, 마찬가지로 어떤 시스템이 monolithic architecture 로 구현되어 있다고 해서 뒤쳐져 있는 것도 아닙니다. 모든 선택에는 Tradeoff 가 있기 마련이니까요. 유선 통신 시스템을 구성한다고 생각해 볼까요? 우리 나라처럼 인터넷이 잘 구성된 상황에서 Skype 로 할 수 있는 통화는 무료이고, 품질도 좋고, 영상 통화까지 됩니다. “Skype 만세! 인터넷을 통한 통신이 항상 옳습니다!” 라고 외치려던 시점에 정전이 되었습니다. 방금 외친 외침은 멀리 가봐야 옆집 정도 닿겠죠. 한편 기존 유선 전화 시스템은 느리고 화상 통화도 안되지만, 전화선 자체에 전원이 공급되고 있기 때문에 정전 시에도 통화가 가능합니다. 전쟁 상황이나 기타 재난 등에도 반드시 통신이 가능해야 하는 곳은 유선 전화 시스템이 꼭 필요할 것 같습니다. 은행 시스템도 적절한 예시가 될 수 있습니다. 비밀번호 입력, 전화 인증, OTP 확인하는 등 은행 업무는 왜이리도 복잡할까요? 그냥 비밀번호 기억해주고 로그인 유지해주면 참 편할텐데 말이죠. 안전하기 위해서겠죠. 여러분의 자산은 소중하니까요. 사용성(Usability)과 안전성(Security)은 종종 둘 사이를 조절해야 하는 Tradeoff 입니다. 만들려는 제품과 시스템, 환경, 시기와 조건 등에 따라서 적절한 architecture 는 달라집니다. 좋은 architecture 를 선택할때 개발자는 선택한 것의 대척점에 있는 무언가를 포기 해야합니다. 그렇기에 software architecture 는 기술적인 범주 안에서만 고려되면 안되고, 구현하고자 하는 비지니스를 매우 잘 이해하고 고려해서 적용해야 합니다. What are you going to do? 이미 구성된 software architecture 를 변경하는 것은 굉장히 어렵습니다. 이미 구성되어 있는 것들을 상세하게 알고 있어야 하고, 비지니스의 요구 사항을 수용해야 하며, 이미 존재하는 기능이 변경 도중 문제 없이 동작해야 합니다. 또한 기존 시스템에 기여한 개발자들과 변경 사항에 대한 공감대를 이뤄야 하며, 겉으로 보기에 당장 변화가 없는 것에 대한 비용에 대해 많은 사람들을 설득해야 합니다. 최근 Buzzvil 에서는 Architecture Task Force 팀을 구성하였습니다. 이를 통해 전체적인 설계를 정비하고 모든 개발팀이 구조적으로 같은 이해를 할 수 있도록 분석, 조사, 계획 수립, 실행에 옮길 예정입니다. 지속적인 공유를 통해 전사적인 공감대를 유지하고 체계적인 문서화와 가이드라인을 통해 모든 팀원이 함께 실행하며 성장할 수 있는 기반을 준비하게 될 것입니다. 궁극적으로 전사 프로젝트와 모든 팀이 더욱 빨리 움직일 수 있는 software architecture 를 구성하고, 이를 통해 더 많은 기능을 더 빠르게 전달할 수 있게 할 것입니다. 아직 해야할 일들이 많이 남아있지만 제대로 계획하고 빠르게 움직인다면 충분히 좋은 결과를 만들 수 있을 것 같습니다. 당장은 눈에 보이는 변화가 없을지라도, 좋은 디자인에 대한 고민과 실행이 우리가 궁극적으로 바라는 비전과 목표에 한 걸음 더 빠르게 다가가는 올바른 길이라고 믿습니다.   *버즈빌에서 개발자를 채용 중입니다. (전문연구요원 포함)작가소개 Whale, Chief Architect “Keep calm and dream on.”
조회수 592

오픈서베이 이건노 CTO가 ‘공동성장 가능해야 좋은 개발팀’이라 말하는 이유

오픈서베이 이건노 CTO(이하 폴)는 훌륭한 개발팀의 첫 단추로 ‘일단 매출이 나는 서비스 만들기’를 꼽는 현실주의 개발자입니다. 돈을 벌어야 생존 가능한 환경이 갖춰지고 이때부터 좋은 팀에 대해 고민을 할 수 있다면서요.  동시에 모두가 즐겁게 일하며 공동성장할 수 있는 팀이라는 이상을 꿈꿉니다. 지속가능한 서비스는 지속가능한 개발팀에서 비롯되는데, 즐겁지 않은 업무 환경에서는 그런 개발팀이 나올 수 없다고 믿기 때문입니다.  이런 현실주의적 몽상가는 주니어로 입사해 개발 조직 리더까지 지낸 이스트소프트에서의 경험으로 오픈서베이 개발팀을 리빌딩합니다. 구성원 모두가 즐겁게 일할 수 있는 환경을 위해 폴은 어떤 고민과 노력을 했을까요?   오픈서베이 이건노(폴) CTO   폴, 안녕하세요!  안녕하세요. 스타트업은 처음이라 직원 간 출퇴근 시간도 다르고 영어 이름으로 불리고 하는 게 익숙하지 않았는데, 17년 4월에 조인해서 벌써 만으로 2년째 다니고 있네요(웃음). 오픈서베이 개발팀을 총괄하고 있는 폴입니다.    현실주의적 몽상가의 오픈서베이 합류 계기가 궁금합니다(웃음).  경영진 미팅이었어요. 저는 주변 후배들이 이직 고민할 때도 그 회사의 경영진을 꼭 보라고 이야기하는 편인데, 제가 오픈서베이에 조인한 결정적인 계기도 하이(황희영 대표)와의 미팅이었어요. 하이를 만나보니 제품에 대한 애정이 정말 크다는 걸 느꼈어요. 대표가 제품에 애정이 많다는 뜻은 정말 하고 싶은 일을 한다는 의미잖아요. 사실 제품에는 관심 없고 주식, 엑싯 이런 거만 고민하는 대표도 있거든요. 그런데 하이처럼 제품에 애정이 정말 많은 대표가 있는 회사라면 저도 정말 믿고 다닐 수 있겠다고 생각했어요.  “대표가 제품에 애정이 많다는 뜻은  정말 하고 싶은 일을 한다는 의미라고 생각해요”   현재 개발팀 구성은 어떻게 되나요?  오픈서베이 개발팀은 현재 프로젝트 매니저 3명, 프론트엔드 개발자 2명, 백엔드 개발자 4명, 그리고 앱 개발자 2명까지 총 11명으로 구성돼 있어요. 최근 회사가 빠르게 성장하면서, 올해는 개발팀도 여러모로 성장하는 한 해가 될 것 같아서 기대됩니다.   팀이 성장하면 어떤 변화가 생기나요? 기업의 규모는 천차만별이지만 업무의 범위는 크게 다르지 않아요. 그러다 보니 인원이 적은 스타트업은 한 명이 얕고 넓게 일하는 구조인데, 회사가 성장하면서 직원이 늘면 각 구성원의 역할을 좀 더 세분화하고 전문화할 수 있게 돼요.  오픈서베이 개발팀도 기존에는 프로젝트 매니저가 기획·QA 등 다양한 역할을 모두 소화했다면 최근에는 좀 더 한 분야에 집중해서 깊게 일하는 식으로 역할의 변화를 주고 있어요. 그래서 서비스 기획자·백엔드 개발자·QA 엔지니어 등 다양한 직군을 채용하고 있고요.   오픈서베이 개발팀의 채용 정보를 알고 싶다면? (링크)   조셉(김경만 오베이 PM) 인터뷰를 보면, 개발팀 세미나 제도를 통해 긍정적인 영향을 많이 받은 것 같아요.  사실 세미나 자체가 주니어 개발자의 발언 기회를 위한 제도예요. 개발자는 스스로 제품이나 기술에 대해 주도적으로 고민할 때 역량이 극대화된다고 생각해요. 그런데 주니어 시절에는 아무래도 고민의 결과를 제품이나 기술에 반영하기 힘들죠. 세미나는 이런 갈증을 느끼는 주니어가 좀 더 의욕적으로 일할 수 있는 창구를 제공하기 위해 도입했어요. 구성원분들 덕에 우리 개발팀에는 잘 적용됐지만, 무작정 도입만 한다고 알아서 잘 작동하진 않는 것 같아요. 세미나가 주니어에게는 동등하게 업무 커뮤니케이션을 할 기회지만, 시니어에게는 사실 귀찮고 번거로운 일이 될 수 있거든요. 해왔던 대로 하는 게 편하다는 생각도 들 수 있고 새로운 기술을 팀에 적용하는 과정에서 드는 리소스도 크고요.    주니어 관점일 때는 생각지도 못했는데 이야기를 들어보니 그렇네요.  사실 저도 마찬가지예요. 저도 CTO이기 전에 개발자니까 주니어 개발자의 신선한 아이디어나 최신 기술을 업무에 적용해보고 싶은 마음도 있어요. 주니어분들의 세미나를 통해 저도 새롭게 배우는 점이 많아요. 그런데 CTO 입장에서는 이를 도입했을 때 우리 제품이나 업무 환경에 어떤 영향이 미칠지를 계산하지 않을 수 없어요. 좋아 보인다고 무작정 도입하면 문제가 터졌을 때 대처할 준비가 안 된 거니까 부담이 너무 크거든요.  그래서 이런 제도는 신중하게 도입하고 모든 구성원이 꾸준히 노력해야 잘 유지되는 것 같아요. 저도 간혹 이런 데서 내적 갈등이 생길 때마다 세미나 제도의 긍정적인 영향을 생각하며 이겨내는 편이에요(웃음). 실제로도 팀 업무 환경 개선이나 기술 수준 향상에 많은 도움이 되고 있고요.   “주니어에게도 고민 내용을 공유할 기회를 주려고 해요. 개발자는 주도적으로 제품을 고민할 때 역량이 극대화되거든요”    ‘코드리뷰’도 비슷한 제도라고 들었어요.  맞아요. 코드리뷰는 제품이나 소프트웨어의 변경사항을 체계적으로 관리하는 형상 관리의 일환이기도 해요. 오픈서베이 개발팀은 각 개발 담당자가 코드를 업데이트하면 슬랙에 자동으로 알림이 와요. 그럼 구성원들은 자유롭게 코드를 열어보고 의견을 내는 거죠. 여기서 담당자가 놓친 오류나 실수를 점검해 주거나, 더 효율적이고 경제적인 코드에 대한 의견을 주고받기도 해요.    그럼 코드리뷰는 보통 어떤 식으로 진행되나요?  마이너한 코드는 비대면 방식으로 온라인에서 수시로 리뷰를 진행하는데, 메이저한 코드 업데이트가 있을 때는 따로 회의를 열어서도 해요. 경우에 따라 방식은 다르지만 적극적으로 진행하려는 편이에요.  코드리뷰 제도를 도입하고 장려하는 이유는 명확해요. 개발자는 여럿이 함께 일할수록 시너지가 난다고 생각하거든요. 개발자 개인의 실력이 아무리 좋아도 본인이 작성한 코드의 오류나 실수를 다 잡아내기는 힘드니까요.  코드리뷰 자체가 구성원들이 의견을 주고받으면서 시스템 전반을 두루 이해하고 배우는 과정이기도 해요. 탄탄한 개발팀은 한명의 개발자가 하나의 시스템을 맡는 게 아니라 여러 구성원이 여러 시스템을 보조하는 구조거든요. 그래야 특정 담당자가 공백일 때 다른 구성원이 대신 문제를 처리해줄 수 있고, 개인의 부담도 줄어드니까요.  개발팀의 조셉과 로빈이 코드리뷰 중인 화면   그러다 자칫 잘못하면 서로의 감정을 상하게 하거나, 주니어를 향한 시니어의 훈육 공간으로 전락할 수도 있을 것 같아요.  그래서 어떤 제도가 좋다고 해도 무턱대고 받아들이면 안 된다는 생각을 해요. 도입에 앞서 서로 인신공격을 하면 안 된다거나 리뷰 내용은 공개된 채널에서만 주고받아야 한다는 등의 세세한 규칙을 정할 필요가 있어요. 코드에 대한 의견이 상대방을 헐뜯으려는 게 아니라 제품 개선과 모두의 성장을 위해서라는 상호 신뢰도 충분히 형성돼 있어야 하고요.    구성원들이 서로 자극을 주거나 보고 배우면서 함께 성장하는 팀을 지향하는군요. 정확히 맞아요. 개발자는 연차나 경력과 무관하게 개인별로 역량의 편차가 좀 있는 편이에요. 하나의 팀에 똑같은 수준의 역량을 갖춘 개발자만 모여 있는 게 오히려 부자연스러울 정도로요. 그래서 서로 다른 역량을 가진 팀원들이 함께 일할 때 시너지가 날 수 있는 방법이 필요해요.  저도 예전에는 이렇게 생각하지 않았어요. 일 잘하는 개발자에게 일을 몰아 주고 그 친구가 일을 다 하게 했죠. 거기에 따라 보상도 많이 주고요. 처음에는 일이 되는 것 처럼 보였는데 그런 식으로 한두 명이 일을 많이 하니까 금방 지치더라고요. 결국 서로 도와 가면서 팀으로 일하는 게 필요하더라고요.   그렇게 생각한 특별한 계기가 있나요? 개발팀장 시절에 새로 합류한 구성원 한명이 기억나네요. 좀 독특했어요. 에러·버그 등 문제가 생기면 원인을 파악하고 해결하는 개발업무를 ‘트러블슛(Trouble Shoot)’이라고 하는데, 그 친구는 다른 구성원이 담당하는 시스템의 트러블슛도 함께 고민하는데 시간을 많이 쓰더라고요.  사실 전 그때까지만 해도 팀원은 자신에게 주어진 일을 잘하면 되고 팀장은 역량에 맞춰 일을 잘 분배해주면 된다고 생각했어요. 그래서 이 친구 모습을 보면서 왜 자기 일은 안 하고 다른 사람 일을 야근까지 하면서 보고 있을까 생각했었죠.  그런데 시간이 지날수록 팀원들의 역량과 그 친구의 역량이 동반 성장하더라고요. 그것도 눈에 바로 보일 정도로 빠르게요. 서로 자극을 주고 함께 고민하면서 결국은 팀 전체가 성장한 거예요. 서로 시너지가 났던 거죠. 그러면서 자연스럽게 성과도 잘 나왔어요.   하지만 의지만으로는 자신의 업무를 넘어서 다른 구성원의 업무를 함께 고민하기는 힘들 것 같아요. 팀에서 함께 일할 수 있는 환경을 잘 만들어 주는 게 중요했던 것 같아요. 이슈 관리, 형상 관리, 버전 관리, 테스트, 릴리즈 등 개발과 운영을 위해서 필요한 기본적인 이해가 서로 있어야 해요. 그리고 개발 업무에만 집중할 수 있게 빌드, 배포와 같은 반복적인 업무의 자동화나 운영 툴 개발과 같은 것도 중요합니다.  그리고 가장 중요한 건 서로에 대한 배려심이라고 생각해요. 이번에 도와주고 다음에 도움을 받고 하는 서로에 대한 배려가 없다면 함께 일하는 문화는 자리 잡을 수 없어요. 일이 나뉘어 있기도 하지만 결국 같은 목적으로 일하고 있는 동료와 팀이라는 것을 알고 서로 배려해 주는 거죠. “좋은 제품은 좋은 개발 환경에서 나온다고 생각해요.  그래서 좋은 환경을 만들어주고 싶어요”   레드(김승엽 개발자) 인터뷰만 봐도, 로빈(권장호 개발자)를 통해 자극을 받아 공동성장하는 모습이 인상적이더라고요. 폴은 이런 레드에게 팀장을 넘어 멘토로서도 다양한 조언을 해주려는 것 같아요. 개발팀 구성원들이 회사 안에서의 성장에 갇히길 바라지 않아요. 좋은 인연으로 만났는데 회사라는 틀 안에서 팀장과 팀원 관계로 한정할 필요는 없다고 생각해요. 틀을 벗어나면 제가 할 수 있는 조언의 범위도 넓어지고 깊이도 훨씬 풍부해지기도 하고요. 인생 관점에서 조언해줄 수 있잖아요. 그럼 반대로 저도 레드를 비롯한 다른 구성원들을 통해 많이 보고 배울 수 있게 돼요.    쉽게 가지기 힘든 생각 같은데, 폴의 주니어 때 팀장님을 통해 배우신 건가요? 아니요. 사실 저는 팀장님과의 기억이 많지 않아요. 주니어로 입사한 지 2년 만에 엉겁결에 팀장이 됐거든요. 처음에는 기존 팀장님이 갑작스럽게 자리를 비우면서 팀장 업무를 임시로 맡았어요. 이때는 인사권 같은 건 전혀 없고 그냥 팀 업무를 할당받아서 각 구성원에게 배분하는 역할만 잠깐 한다고 생각했죠. 그런데 회사에서 “이왕 한 거 너가 계속해라”라며 아예 팀장을 시켜버리더라고요. 그때는 많이 당황했어요. 저도 완전 주니어일 때라 좋은 팀장님 밑에서 이것저것 배우고 싶었거든요. 그런데 이렇게 일찍 팀장이 되면서 이젠 내게 가르쳐줄 사람이 없는 걸까 싶어서 앞이 깜깜했어요 “나도 개발 잘할 수 있는데 왜 매니저 역할을 주는 거지? 내가 개발을 잘 못 한다는 건가?”라는 삐뚤어진 생각도 했고요. 얼마나 막막했으면 구글에 ‘팀장이 하는 일’ 같은 걸 검색한 적도 있어요(웃음).   위기를 어떻게 극복했을지 궁금해요. 그 과정이 지금의 폴 인사 철학에 많은 영향을 줬을 것 같아요.  그래도 어쨌든 팀장 일을 해내야 하니까 시선을 좀 넓혀봤어요. 제게는 이제 직속 팀장은 없지만 저보다 경력 많고 실력 좋은 선배 개발자가 팀원으로 있었고, 다른 팀에 훌륭한 시니어 개발자나 선배 팀장님도 계셨죠. 시선을 넓히니 오히려 제가 보고 배울 사람이 더 많더라고요. 그분들에게 궁금한 걸 적극적으로 묻거나 보고 배우면서 중요한 시기를 잘 보낼 수 있었던 것 같아요.  그때 처음으로 깨달은 게 아닐까 싶어요. 제가 엉겁결에 팀장이 되면서 다른 많은 분들을 보면서 보고 배운 것처럼, 팀원들도 꼭 팀장이 아니더라도 다른 팀원들을 서로 보고 배우면서 긍정적인 자극을 받으며 성장할 수 있다는 걸요. ‘팀장은 팀원에게 가르쳐주는 사람이야’란 생각에 갇혀 있었으면 절대 깨닫지 못했을 것 같아요. 얘기를 해보니 정말로 저 난관을 통해서 지금과 같은 생각을 할 수 있게 된 것 같네요(웃음).  “팀장과 팀원이라는 틀을 벗어나면 훨씬 풍부하게 긍정적인 자극을 주고받을 수 있어요”   폴의 경험과 고민이 결국은 팀 업무 환경이나 문화를 통해 드러나는 것 같네요. 그렇게 봐주시면 정말 고맙죠. 사실 어떻게 하면 더 일하기 좋은 회사와 팀을 만들 수 있을지는 계속 고민되는 부분이에요. 돈 많이 주는 회사가 일하기 좋은 회사라고 간단히 생각해버릴 수도 있는데, 저는 일하기 좋은 회사를 이루는 요건은 좀 더 다양한 것 같거든요. 일단 하는 일이 어떤 가치를 가지고 있고 이것을 쓰는 사람들에게 어떤 가치를 제공해 주는지 알고 있어야 해요. 그래야 내가 하는 일에서 보람을 찾을 수 있으니까요. 물론, 회사에서도 보람을 가질 수 있는 방법을 함께 고민해 줘야겠죠.  보람만으로 회사에 다닐 수 없으니 역세권 사무실, 맛있는 커피, 좋은 경영진, 좋은 팀원 등 중요한 요건들이 엄청 많은데요. 오픈서베이는 서로에게 자극을 주거나 보고 배우며 스스로 성장할 수 있는 좋은 구성원들이 많은 것 같아요. 저도 요즘  구성원들에게 많이 배우고 있습니다.    마지막 질문입니다. 좋은 팀을 위한 폴의 역할은 무엇인가요?  장점을 찾아 주는 게 저의 중요한 일이죠. 잘하는 일을 해야 역량도 극대화되거든요. 장점이 없는 사람은 없다고 생각해요. 장점을 잘 모르는 친구들이 있는데 이런 친구들의 장점을 찾아주고 또 그 장점이 회사에서 잘 발현되도록 도와주는 조력자 역할을 잘 해내는 게 제가 할 일이라고 생각해요.  좋은 장점이 잘 발현되면 개발자는 한 단계 더 성장할 기회가 생겨요. 예를 들어 초기 제품 기능을 빠르게 잘 만드는 게 장점인 친구는 신사업 중심의 일을 할 수 있게 해주면 그 역량이 잘 발현되거든요. 거기서 가치를 인정받고 탄력이 붙으면 지속적으로 좋은 성과를 낼 수 있게 되고요. 이 과정을 저는 “알을 깨고 나온다”라고 표현하는데, 이렇게 알을 깨고 나오면 좀 더 제품이 주는 본질적인 가치를 알게 된다고 생각해요. 개발자로서 일하는 가치와 방법을 알게 되는 거죠. 그런 만큼 오픈서베이의 예비 구성원분들도 좋은 자극을 받으며 성장할 수 있는 계기가 되셨으면 좋겠어요. 회사를 그저 출근해서 일만 해주고 돈을 받아가는 공간이라고 생각하면 회사 다니기가 우울하잖아요. 사람마다 얻어갈 수 있는 건 다 다르겠지만, 긍정적인 영향을 받아 성장하는 계기가 오픈서베이가 될 수 있을 것같아요.    “폴과 함께 즐겁게 일하고 싶으시다면 지금 바로 오픈서베이 입사지원을 해보세요”  
조회수 3307

경험 부족한 스타트업의 devops 도입기 1편

개발과 운영을 함께 devops - 출처당분간의 일기 내용앞으로 몇 개월 간 신생 스타트업 I/O가 어떻게 devops를 자기네만의 스타일로 조직에 안착시켜 나가는지 그 시행착오를 생생하게 공유하는 일기를 쓰려고 합니다.첫 번 째 편인 오늘의 이야기는 두 가지 내용을 다룹니다.devops 도입배경: 어떻게 하다가 devops를 도입하기로 했는지 그 배경에 대에서 이야기 합니다.devops 필요성 인지: 가장 먼저 소프트웨어팀이 devops 필요성을 느끼도록 시도한 스터디 세미나에 관한 이야기를 합니다.devops 도입 도중에 실패할 수 있습니다. 그래서 1편이 마지막 연재일 수 있습니다. 혹은 온갖 개고생을 해가면서 결국 devops를 성공적으로 조직에 안착시켜 tech기업다운 모습을 갖출 수 도 있습니다. 정답은 시간이 얼마간 흐른 뒤에야 알 수 있겠죠? 무언가를 조직에 도입하는 스토리를 사후적으로 그러니까 프로젝트가 끝난 후에 쓰게된다면 프로젝트 과정의 생생함이 퇴색됩니다. 힘들었던 추억도 되돌아보면 미화되듯이 그 당시에 골치아팠던 일들을 그 당시에 써놓지 않으면 까먹을 때가 꽤나 많습니다. 한 편으로는 이렇게 칼자루를 뽑아놔야 반드시 devops를 성공시키기 위해 제가 더 처절해질 수 있을 것 같습니다. 제 나약한 마음이 바뀌지 않기 위해 devops 시작과 동시에 연재물도 함께 시작하겠습니다.devops 도입배경스위처 M 앱이 출시된지 약 한 달 정도 되었습니다.경영을 해오면서 항상 위기의식을 느끼고 있지만 이번에는 조금 심상치 않았습니다.“아.. 라이브서비스를 하기엔 현재 I/O의 소프트웨어 역량이 심각하게 부족하구나! 하드웨어 역량이 Critical Path일 줄 알았는데 되려 소프트웨어가 우리의 발목을 잡고 있구나..”그동안 하드웨어 멤버들은 초심자의 마음과 책임감을 동시에 갖고 무서운 속도로 성장해왔습니다. 새로운 버전의 스위처(M)에 적용된 기구설계 수준, Supply chain 관리 능력, 블루투스 모듈 성능은 이전 버전(W) 비할바가 안됩니다. 놀랄만큼 일취월장 했습니다. 단적인 예로 현재 스위처M의 블루투스 연결 거리는 오픈필드에서 70m이상 나옵니다. 이전 세대인 스위처W의 연결거리가 약 20m 미만임을 감안하면 연결성이 300%이상 좋아졌다고 볼 수 있습니다.반면 소프트웨어팀은 여전히 초보적인 수준을 벗어나지 못하고 있습니다. 전공분야라는 자만심에 소프트웨어를 밑도 끝도 없는 구렁텅이에 밀쳐 넣고있는 제 자신을 발견 했습니다. 창피했습니다. 가장 중요하다고 볼 수 있는 초기고객으로부터 어처구니없는 버그 리포팅을 받을때면 쥐구멍으로라도 숨고 싶었습니다. Customer Service역할까지 도맡아하는 마케터가 수 많은 컴플레인을 대응하느라 정말 고생이 많았습니다.심각한 문제는 소프트웨어팀이 문제의 원인이 무엇인지 조차 잘 모르고 있다는 사실이었습니다. 그저 열심히 다음 피쳐를 개발하기 위해 코드를 짜내는 데에만 자신을 몰아붙이고 있었습니다.그 모습은 한 편의 코메디 영화를 보는 것 같았습니다.<디버깅루프>(1) 배포한 기능에 버그가 처음으로 발견됩니다.(2) “엇 이상한데? 그럴리가 없는데?” 일단 현실을 부정하고 지켜봅니다.(3) 한 두 명의 문제가 아니라는 버그리포팅이 들어옵니다.(4) 부랴부랴 원인을 추측하고 핫픽스 코드를 짜기 시작합니다.(5) 개발을 마치고 일단 배포해 봅니다.(6) 그런데 해결될 줄알 았던 버그가 다시 보고됩니다.그렇게 상황은 2번으로 돌아가 이 디버깅루프를 몇 바퀴 돌고난 후에야 잠잠해집니다.하하… 개판이구나 — 출처:구글 이미지 검색허나 이미 많은 고객들이 불쾌한 UX를 겪고 난 뒤… 이대로는 도저히 구상하는 I/O의 큰 그림에 도달할 수 있을 것 같지 않아, 당분간 제가 CTO역할을 도맡아서 하려고 합니다. 벤 호로위츠가 쓴 Hardthing에서 C-level의 포지션이 비어있을 경우 진짜 적임자가 나타나기 전까지는 그 역할을 CEO가 직접 수행하기를 권장합니다. 이제까지 바쁘다는 핑계로 조직 부채, 기술 부채를 안고왔었는데 최근 Event3 사고를 겪으면서 이젠 이 부채들을 털어내고 나아가야 겠구나 결심하게 되었습니다. 직접 현장으로 다이빙해서 소프트웨어 엔지니어들과 함께 악전고투하기로 했습니다.린스타트업에서 말하는 5-why기법을 적용해보니. 근본적인 원인은 이것이였습니다.주먹구구식으로 Product Live service가 운영(operation)된다.엔지니어들의 코드 퀄리티가 낮아서가 아니었습니다. 알고리즘을 몰라서가 아니었습니다. 디자인 패턴을 몰라서도, 함수형 패러다임을 이해하지 못해서도, 동시성 문제를 몰라서도가 아니었습니다. 되려 I/O의 소프트웨어 엔지니어들의 CS 기본기는 나쁘지 않습니다. 저희는 엉클밥, 켄트백, 마틴파울러를 존경합니다.바보야, 문제는 코딩이 아니야!문제는 경제가 아니야, 바보야!저희 팀의 제일 큰 문제점은 그냥 예전 처럼 새로운 feature 코드를 찍어내는일이 Product Live service operation의 전부라는 사고방식입니다. 배포되는 코드가 얼마나 신뢰할만한지에 대한 고민은 전혀 없고 밀어내기식으로 다음 기능을 추가하는 데만 몰두했습니다. 실상 지금의 스위처에는 새로운 기능을 추가하기위해 코딩을 할때가 아니었는데 말이죠. 쿼리 속도를 높이기 위해 인덱싱을 고민 할 때가 아닌데 말입니다. 정작 Product Live service operation에 필요한 일들(tasks)을 수행하고 있지 않았기 때문에 이 문제가 발생한건데 말이죠.린스타트업의 MVP 관점을 포기하고 완벽한 제품을 내보낸다는 의미가 아닙니다. 그 Minimum Viable Product 조차 제대로 작동이 못시키는 문제를 바로잡기 위해서 입니다. 스크럼으로 조직 tasks를 관리해왔지만 소프트웨어팀은 devops로 거듭나야할 때가 왔음을 느꼈습니다.최소한의 검증 절차도 없이 버그가 담긴 소프트웨어가 고스란히 고객에게 전달되는 악몽을 더 이상 마주해선 안됩니다. 불편함을 겪는 고객을 위해서라도 경쟁력을 잃어가는 조직을 위해서라도 곁에서 힘들어하는 동료들을 위해서라도 소프트웨어팀은 변해야만 했습니다.devops 필요성 인지멤버들에게 제가 방금까지 이야기한 문제점을 전달하고 각자 devops가 무엇인지 공부하기로 했습니다. 일주일간 리서치를 마친 후 한 명씩 돌아가면서 devops가 무엇인지 발표하는 세미나를 진행했습니다. 결론부터 말해 devops 필요성에 대한 공감대 형성은 성공적으로 첫 걸음을 뗀듯 합니다. 모두들 세미나를 준비하면서 그동안 무엇이 문제인지 조차 모르는 상황은 벗어나 보였습니다. 한 명쯤은 “devops는 필요없습니다. 지금처럼 해도돼요!”라는 반응을 예상하기도 했는데, 모두가 겸손의 자세로 지금까지의 문제를 반성하고 변화의 필요성을 절감했습니다. 끊임없이 성장하려는 자세를 가진 I/O 멤버들에게 참 고맙습니다.우린 여기에서 어디쯤..?펌웨어 개발자는 우리의 현재 모습이 위의 그림에서 나오는 원숭이조차 안되는 것 같다고 고백 하기도 했습니다. 그만큼 I/O 소프트웨어팀은 변화를 갈망하는 단계로 무사히 넘어왔습니다. 성공적으로 devops의 필요성 공감대를 형성 시킬 수 있었던 요인은 slow-start 덕분인듯합니다. 초기 고객분들이 실험대상이 된것 처럼 말해 죄송하지만, 작은 규모로라도 Live를 진행하고 거기서 작게나마 사고를 치도록 내버려둔 환경이 devops의 필요성을 받아들이는 데 큰 역할을 했습니다.만약 처음부터 무리해서 스케일업을 시도했다면 그래서 감당할 수 없는 수준의 사고가 동시다발적으로 터졌다면 저희는 자멸하고 말았을 겁니다. 아니, 기다리는 많은 고객들의 기대감에 지레 겁먹고 최대한 소프트웨어 출시 일정을 늦췄겠죠. 그리고 그렇게 절벽에서 등 떠밀리듯이 제품을 출시해서 줄을 잇는 버그 리포팅을 받아보며 평정심을 잃고 말았을 것입니다. 그러나, 감당할 수 있는 수준으로 제품 판매수량을 조절했기 때문에 개발자가 문제를 직시해볼 기회를 가졌고 devops의 필요성은 조직에 쉽게 받아들여질 수 있었습니다.물론 devops 세미나를 진행하면서 안좋은 냄새(징조)를 맡기도 했습니다. 저에게는 행운이죠. 사전에 미리 문제를 파악할 수 있어서. 그 냄새는 도구만능주의 였습니다. devops 도달하기 위해서는 시중에 존재하는 다양한 tool들을 최대한 빠르게 도입해야 할것만 같은 느낌을 말합니다. devops tool들만 제대로 구축한다면 devops도 저절도 실현될것 같은 기대감에 젖습니다. 이 도구만능주의가 만연해지면 devops의 본질은 보지 못한 채 최신 tool 사용에만 집착하게되는 오류를 범하고 맙니다.다행이 I/O의 도구만능주의는 심각한 수준까진 아니고 누구나 초기에 충분히 실수할 수 있는 미약한 수준이었습니다. 사실 제가 예전 스타트업에서 스크럼을 도입할 때도 빠졌던 도구만능주의가 묘하게 겹쳐보여서 낌새를 비교적 빠르게 눈치 챌 수 있었습니다.출처 : 구글 이미지 검색devop는 문화와 운동(movement)입니다. 즉, 무형에 가까운 개념입니다. tool이 아니라 행위(action)와 사상(idea)에 역점을 둬야 합니다. tool은 그저 거들 뿐이죠.간단한 사고실험을 해보겠습니다. 모든 microservices의 설정들을 chef와 puppet으로 관리하고 뱀부나 젠킨스로 빌드-배포-리포팅 파이프라인까지 구축한 devops팀이 있다고 가정해 보겠습니다. 달리 말해, 이 팀은 커맨드 입력 한 번으로 방금 짠 코드를 고객에게 배포할 수 있습니다. 어느날 이 팀에 속한 개발자 A가 지난 일주일간 개발해온 피쳐를 지금 막 마무리 지었습니다. 이어서 A는 devops tool로 구축한 배포 파이프라인 이용해 아주 간단하게 새로운 기능을 업데이트 하기로 했는데요. 과연 괜찮을까요? 최신 devops tool로 중무장 했으니 문제가 없을 것 같습니다. 잠시 후 그렇게 배포된 기능을 써본 고객들이 컴플레인을 걸어옵니다. 잠시 화장실을 다녀온 엔지니어는 허겁지겁 hotfix 코드를 다시 짭니다. 그래도 괜찮습니다. A가 속한 팀은 최신 devops tool이 구축되어 있기 때문에 금방 hotfix를 재배포할 수 있으니까요. 그런데 이장면 어디서 익숙하지 않나요? 앞에서 소개한 디버깅루프와 비슷해 보입니다.출처 : 구글 이미지 검색과연 이게 devops일까요? tool들을 전부 사용하는게 진정 devops의 실현일까요?코드를 리뷰하지도 자동화된 테스트 코드를 실행해보지도 않은 상태에서 지속적 배포는 그저 똥을 더 자주 고객에게 전달하는 것과 다르지 않습니다.높은 품질의 제품은 보장할 수 없습니다. 그렇다면 우리는 무엇부터 해야할까요?Next Iteration저는 장황한 계획을 혐오합니다. 계획을 짜내느라 쏟는 에너지와 시간이 너무 아깝고 무엇보다 계획대로 진행될 확률이 낮기 때문입니다. 대신 저는 스타트업 환경에 맞는 방식으로 일하기를 선호 합니다. 비교적 긴 시간이 필요한 프로젝트 성격의 일을 할 땐 북극성의 위치만을 기억합니다. 쉽게 말해 우리가 산출해야하는 프로젝트 결과물만 생각합니다. 북극성까지 도달하는 정해진 길 따위는 없다고 가정합니다. 혹시 있었다 해도 그냥 잊어버립니다. 스타트업의 리스크는 워낙 변화무쌍하거든요.계획 대신 무던히 아래 두 가지 행동을 반복합니다.(1) 고개를 들어 몸이 북극성 향하도록 합니다.(2) 고개를 숙여 한 발짝 전진합니다.출처 : 구글 이미지 검색프로젝트가 끝날 때 까지 위의 두 가지 과정만을 반복하려고 합니다. 저는 이 과정을 baby step이라고 하는데요. 욕심내지 않고 작게 작게 한 번에 하나씩 차근차근 진행하는 방식입니다. 지금 내 딛은 한 걸음이 틀릴 수도 있습니다. 그러나 괜찮습니다. 한 걸음 나아간 다음에는 반드시 고개를 들어 내가 북극성과 가까워졌나 멀어졌나 확인하면 되거든요. 방향이 맞다는 판단이 서면 한 걸음 더 나아가고 틀린 예감이들면 방향을 조절하면됩니다. 만약 판단이 애매하면 더 끌리는 쪽을 택하면 됩니다. 단, 절대 바닥만을 주시한채 두 걸음 이상 걷지 않습니다.devops까지 도달하는 데 지름길은 전혀모릅니다. 하지만, devops라는 북극성은 저에게 명료하고 분명한 목표입니다. devops에 조금이라도 가까워지기 위해 지금 당장 해야하는 가장 중요한 일이 무엇인지 세미나를 진행하면서 그리고 세미나를 돌아보면서 치열하게 고민했습니다. 그렇게 집중하고나니 당장해야 하는 일 3가지는 다음과 같았습니다.(1)코드리뷰(2)테스트코드 작성(3)이슈 관리 프로세스이 세 가지의 일이 정답이 아닐 수 있습니다. 정답인지 아닌지는 얼마간 시간이 흐른 후에야 알 수 있겠죠? 다만, 저희는 늘 저희가 하던 방식대로 용기를 갖고 baby step을 무던히 수행해 나갈 것입니다. 다음화는 위의 세 가지 일을 진행하면서 겪은 시행착오를 공유해 보도록 하겠습니다.긴 글 읽어 주셔서 고맙습니다.#스위쳐 #Switcher #DevOPS #데브옵스 #개발자 #개발 #개발문화 #디버깅 #버그수정 #인사이트
조회수 2154

레진 기술 블로그 - IntersectionObserver를 이용한 이미지 동적 로딩 기능 개선

구글 크롬 51 버전부터 DOM 엘리먼트의 노출 여부를 비동기로 처리하는 IntersectionObserver API를 사용할 수 있게 되었습니다. 이 기능을 이용하면 이미지의 동적 로딩이나 광고 배너의 노출 측정 등을 효율적으로 사용할 수 있다고 구글 개발자 블로그에서 소개하고 있습니다. 이 글에서는 기존의 이미지 동적 로딩에 대한 문제점을 짚어보고 여러 예제를 통해 IntersectionObserver의 사용 방법을 익혀 기존 기능을 개선할 수 있도록 합니다. 사용한 예제들은 브라우저의 호환성을 고려하지 않고 구글 크롬을 기준으로 작성하였습니다.기존의 이미지 동적 로딩 구현이미지의 개수가 많거나 용량이 큰 페이지를 불러올 경우 쓸데없는 네트워크 비용이 증가하고 이미지를 불러오는 과정에서 서비스 속도에 문제가 발생할 소지가 있어서 이미지가 사용자에게 보일 때만 불러오는 동적 로딩 기능이 필요합니다. IntersectionObserver를 소개하기 전에 먼저 기존 라이브러리들이 이미지 동적 로딩을 어떤 방법으로 구현하고 있는지 간단하게 알아보도록 합니다.엘리먼트 가시성 판단이미지 동적 로딩에서 가장 중요한 코드는 해당 엘리먼트가 현재 화면 내에 보이는지 알아내는 것입니다. 이를 위해 엘리먼트의 크기와 위치 값을 돌려주는 Element.getBoundingClientRect 함수를 사용하는 경우가 많습니다. 아래는 이 함수를 사용한 간단한 구현 예제입니다.function isInViewport(element) { const viewportHeight = document.documentElement.clientHeight; const viewportWidth = document.documentElement.clientWidth; const rect = element.getBoundingClientRect(); if (!rect.width || !rect.height) { return false; } var top = rect.top >= 0 && rect.top < viewportHeight; var bottom = rect.bottom >= 0 && rect.bottom < viewportHeight; var left = rect.left >= 0 && rect.left < viewportWidth; var right = rect.right >= 0 && rect.right < viewportWidth; return (top || bottom) && (left || right); } 이벤트 처리위에서 구현한 isInViewport 함수는 언제 호출해야 할까요? 먼저 문서를 처음 불러왔을 때 호출해야 합니다. 그 후에는 동적 로딩이라는 단어에 맞게 사용자의 동작에 따라 보이지 않던 엘리먼트가 보이게 되는 이벤트를 감지해야 합니다. 마우스나 터치로 스크롤을 통해 문서의 위치가 바뀌거나 브라우저의 크기가 바뀔 수도 있고 모바일 기기의 화면을 돌려서 볼 수도 있습니다. 데스크톱의 경우 scroll, resize 이벤트를, 모바일의 경우 orientationchange 이벤트의 처리를 생각해야 합니다.const images = Array.from(document.querySelectorAll('img')); document.addEventListener('scroll', () => { images.forEach(image => { if (isInViewport(image)) { image.onload = () => images.splice(images.indexOf(image), 1); image.src = 'original_image_path'; } }); }); 간단하게 위 코드와 같이 구현할 수 있습니다. 물론 실제 서비스를 위해서는 수정할 점이 몇 가지 있습니다. 동적 로딩의 대상이 되는 이미지를 구분하기 위해 해당 엘리먼트에만 특정 클래스를 부여하거나 HTML5에서 지원하는 data 속성을 이용하기도 합니다. 스크롤이나 리사이즈 이벤트가 과도하게 발생하는 경우가 많으므로 throttle 또는 debounce 등을 사용해 실행 빈도를 조절할 수도 있습니다. 일부 라이브러리에서는 requestAnimationFrame을 이용해 이벤트 핸들러를 처리하기도 합니다.TADA레진코믹스에서는 이미지 동적 로딩을 위해 서비스 초기에 Unveil 라이브러리를 사용했었습니다. 그러나 적용 후 몇 가지 아쉬움이 있어 따로 TADA 라이브러리를 제작했습니다. 먼저 마크업 구조상 이미지를 태그가 아닌 다른 태그에 배경 이미지로 사용하는 경우를 지원해야 했습니다. 그리고 모바일 웹에 주로 많이 적용하는 수평 스크롤 구역에 대한 처리도 필요했습니다. 문서의 스크롤 이벤트로는 처리가 되지 않기 때문에 특정 엘리먼트를 받아 그 엘리먼트의 스크롤 이벤트 핸들러를 등록할 수 있도록 해야 했습니다. 이를 해결하기 위해 만든 라이브러리를 현재 서비스에 적용 중이지만 이 라이브러리 역시 아래와 같은 문제점들을 가지고 있습니다.</> < id>기존 이미지 동적 로딩의 문제점getBoundingClientRect 함수의 문제점위 코드에서 특정 엘리먼트가 현재 화면 내에 보이는지 검사할 때 사용하던 Element.getBoundingClientRect 함수에는 치명적인 단점이 있습니다. 이 함수를 호출할 때마다 브라우저는 엘리먼트의 크기와 위치값을 최신 정보로 알아오기 위해 문서의 일부 혹은 전체를 다시 그리게 되는 리플로우(reflow) 현상이 발생한다는 점입니다. 호출 횟수가 적을 경우에는 부담이 되지 않지만, 이 함수는 위에서 구현한 것처럼 스크롤이나 리사이즈 이벤트가 발생할 때마다 등록한 모든 엘리먼트를 순환하면서 호출하게 됩니다. 이 코드들이 하나의 메인 스레드에서 실행되기 때문에 스크롤을 할 때마다 실행 속도가 눈에 띄게 느려질 수도 있습니다.외부 도메인 문서를 사용하는 iframe최신 브라우저들은 동일 도메인 정책에 따라 iframe 내의 외부 도메인 문서에서 현재 문서에 접근하지 못 하게 막고 있습니다. 이 제한은 서비스 개발에서 겪게 되는 문제는 아니고 외부 광고 플랫폼 개발자의 입장에서 발생하는 문제입니다. 광고 이미지의 표시나 클릭 이벤트의 처리 등은 iframe 내에서 처리할 수 있지만 광고 이미지를 지연 로딩한다거나 이 광고가 사용자에게 노출이 되었는지 기록하는 등의 기능은 iframe 내에서 불가능합니다. 그래서 광고를 적용하는 서비스 개발자에게 스크립트를 제공하고 서비스 문서 내에 삽입하는 방식으로 처리하고 있습니다. 이러한 외부 광고가 여러 개라면 삽입해야 하는 코드가 늘어날 뿐만 아니라 코드 내에서 스크롤이나 리사이즈 이벤트 등을 각각 사용하기 때문에 위에서 언급한 문제점들이 배가될 수 있습니다.기타 이벤트에 대한 처리대부분의 동적 로딩 라이브러리들은 적용할 엘리먼트에 특정 클래스 또는 data 속성을 부여하면 코드를 추가 작성하지 않더라도 쉽게 사용할 수 있습니다. 하지만 화면에서 보이지 않던 엘리먼트가 갑자기 나타나는 현상은 스크롤이나 리사이즈 이벤트에서만 발생하는 것이 아닙니다. 더보기 버튼을 눌렀을 때 숨겨져 있던 엘리먼트를 노출할 수도 있고 AJAX 호출 후 엘리먼트를 생성한 후 보여줄 수도 있습니다. 이런 경우 일괄적으로 처리하기가 어렵우므로 해당 이벤트가 발생할 때 수동으로 처리하는 수밖에 없습니다.IntersectionObserver위에 나열한 문제들을 효과적으로 처리하기 위해 크롬 51/엣지 15/파이어폭스 55 버전부터 IntersectionObserver를 지원하기 시작합니다. 우리말로 번역하면 교차 감시자 정도가 될 이 기능은 등록한 엘리먼트가 보이는 영역에 나타나거나 사라질 때(용어에 충실하자면 대상 엘리먼트의 영역이 루트 엘리먼트 영역과 교차하기 시작하거나 끝났을 때) 비동기로 이벤트를 발생시켜 줍니다. 기본적인 사용법은 아래와 같습니다.const intersectionObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { // do something observer.unobserve(entry.target); } }); }); intersectionObserver.observe(element); 먼저 IntersectionObserver 생성자에 콜백 함수를 인자로 넘겨주고 생성한 인스턴스의 observe 메소드를 통해 동적으로 처리할 엘리먼트를 등록합니다. 콜백 함수는 IntersectionObserverEntry 객체 목록을 전달받으므로 순환문을 통해 각 엘리먼트에 대한 처리를 완료하고 필요한 경우 unobserve 메소드를 이용해 감시 대상에서 해제할 수 있습니다.IntersectionObserver 예제아래 예제들은 기본적으로 아래 코드를 바탕으로 작성되었습니다. 각 예제들의 최상단에 엘리먼트에 짝을 이룬 표시등을 두었고 콜백 함수가 호출될 때마다 파동 효과를 주었으며 이 때 isIntersecting 속성을 기준으로 표시등을 켜지거나 꺼지게 되어 있습니다.const io = new IntersectionObserver(entries => { entries.forEach(entry => { // isIntersecting 속성으로 해당 엘리먼트가 보이는 지 표시 }); }); Array.from(document.querySelectorAll('.box')).forEach(box => { io.observe(box); }); 스크롤 이벤트를 다루지 않더라도 엘리먼트의 가시성 여부를 isIntersecting 속성을 통해 알 수 있습니다.<iframe class="demo" data-fr-src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-verticalscroll.html" width="600" height="400" frameborder="0">수평 스크롤의 경우에도 overflow 속성이 적용된 컨테이너 엘리먼트의 스크롤 이벤트를 처리하지 않더라도 상관없습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-horizontalscroll.html" width="600" height="200" frameborder="0">더보기 버튼에 대한 클릭 이벤트를 따로 등록하지 않아도 동작합니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/basic-unfold.html" width="600" height="240" frameborder="0">리사이즈 이벤트 역시 따로 처리할 필요가 없습니다. 새 창을 띄운 후 창 크기를 조절하면서 확인할 수 있습니다.위의 모든 예제들은 <iframe> 태그 안에서 실행되고 있습니다. 이처럼 작성한 코드가 외부에서 실행이 되더라도 IntersectionObserver API는 문제없이 동작합니다.IntersectionObserver 생성자 옵션rootroot 옵션에는 가시성의 판단 기준이 될 HTML 엘리먼트를 지정합니다. observe 메소드로 등록하는 엘리먼트들은 반드시 이 루트 엘리먼트의 자식이어야 합니다. 이 옵션을 지정하지 않을 경우 브라우저 화면에서 현재 보이는 영역인 뷰포트가 기본이 됩니다. 아래 예제에서 알 수 있듯이 루트 엘리먼트를 지정하면 현재 화면과는 상관없이 루트 엘리먼트와 등록한 엘리먼트들의 영역이 교차하는 지 판단하게 됩니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-root.html" width="600" height="400" frameborder="0">rootMargin루트 엘리먼트의 마진값을 지정할 수 있습니다. CSS에서 사용하는 형식과 같기 때문에 “10px”, “10px 20px”, “10px 20px 30px 40px” 형태가 모두 가능하며 음수값으로 지정할 수도 있습니다. 기본값은 0이고 루트 엘리먼트를 지정한 상태라면 퍼센트값을 사용할 수도 있습니다. 이 옵션을 이용하면 이미지 동적 로딩에서 해당 엘리먼트가 화면에 나타나기 전에 이미지를 불러오기 시작해 이미지 공백을 줄이는데 유용하게 이용할 수 있겠습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-rootmargin.html" width="600" height="400" frameborder="0">위 예제에서는 root 옵션은 지정하지 않고 rootMargin 옵션을 각각 0, 100px, -100px, 50%로 지정했습니다. 하지만 iframe 내에서 실행을 하게 되면 이 옵션이 정상적으로 동작하지 않습니다. 프로젝트 페이지의 이슈 댓글에는 동일 도메인의 프레임 안에서는 동작하는 것으로 논의되고 있지만 뷰포트에는 해당하지 않거나 버그 또는 아직 크롬에 반영이 되지 않아 보입니다.이 예제는 새 창을 띄워 프레임을 벗어나면 정상적으로 동작합니다. 스크롤을 내리다보면 엘리먼트마다 IntersectionObserver 콜백 함수가 다른 위치에서 호출됨을 알 수 있습니다.thresholdthreshold 옵션은 엘리먼트가 콜백 함수의 호출 시점을 정하는 옵션입니다. 0과 1을 포함한 그 사이의 숫자 또는 숫자 배열을 지정할 수 있는데 이 숫자는 엘리먼트의 전체 영역 중에 현재 보이는 영역의 비율입니다. 이 비율의 경계를 넘나들 때마다 콜백 함수가 호출됩니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-threshold-value.html" width="600" height="400" frameborder="0">위 예제에서는 threshold 옵션을 각각 0, 0.5, 1, [0, 1]로 지정했습니다. rootMargin 예제처럼 엘리먼트마다 콜백 함수가 다른 위치에서 호출됩니다. 두 번째와 세 번째 상자는 콜백 호출 시점에 isIntersecting 값이 항상 참이기 때문에 표시등이 정상적으로 표시되지 않습니다. isIntersecting 속성을 기준으로 처리해야 할 작업이 있다면 반드시 threshold 속성에 0을 포함시켜야 정상적으로 동작합니다. threshold 속성은 아래 예제처럼 콜백 함수의 인자로 받는 IntersectionObserverEntry 객체의 intersectionRatio 속성과 같이 사용하기에 유용합니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/option-threshold-ratio.html" width="600" height="400" frameborder="0">위 예제에서는 threshold 옵션을 각각 [0, 1], [0, 0.5, 1], [0, 0.25, 0.5, 0.75, 1]로 지정하고 콜백이 호출되면 intersectionRatio 값을 기준으로 표시등의 배경 투명도를 바꾸도록 했습니다.IntersectionObserver의 활용이미지 동적 로딩지금껏 알아본 IntersectionObserver를 이용해 이미지 동적 로딩을 간단하게 구현해봅니다. 이미지 엘리먼트를 구성할 데이터가 배열로 존재한다고 가정하고 ES6에서 지원하는 템플릿 문자열을 사용해 배열을 순환하면서 이미지 목록을 생성합니다. 그 후 IntersectionObserver를 초기화하고 만들어진 엘리먼트들을 등록합니다. 콜백 함수에서는 엘리먼트가 보이는 상태일 때 이미지를 로딩하고 해당 엘리먼트를 감시 해제합니다. id="comics"> const comics = [ { alias: 'eunsoo', id: 6080299074584576, title: '은수' }, ... ]; const template = comics => ` ${comics.map(comic => ` ${comic.id}"> ${comic.alias}" class="info">${comic.title} `).join('')} `; document.getElementById('comics').innerHTML = template(comics); const io = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } const target = entry.target; const id = target.dataset.id; target.querySelector('.info').style.backgroundImage = `url(https://cdn.lezhin.com/v2/comics/${id}/images/wide?width=600)`; observer.unobserve(target); }); }); Array.from(document.querySelectorAll('.comic')).forEach(el => { io.observe(el); }); 아래 예제를 실행하면서 브라우저의 개발자 도구를 열고 네트워크 탭을 살펴보면 이미지 엘리먼트가 보이기 시작할 때 불러오기 시작하는 것을 확인할 수 있습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/demo-lazyload.html" width="600" height="400" frameborder="0">무한 스크롤IntersectionObserver 기능을 이용하면 무한 스크롤 역시 쉽게 구현할 수 있습니다. 아래 예제에서는 스크롤의 끝부분에 감시를 할 엘리먼트를 두고 그 엘리먼트가 노출이 될 때마다 콘텐츠를 추가로 불러오도록 작성하였습니다. id="items"> id="sentinel"> const count = 20; let index = 0; function loadItems() { const fragment = document.createDocumentFragment(); for (let i = index + 1; i <= index + count; ++i) { const item = document.createElement('p'); item.classList.add('item'); item.textContent = `#${i}`; fragment.appendChild(item); } document.getElementById('items').appendChild(fragment); index += count; } const io = new IntersectionObserver(entries => { entries.forEach(entry => { if (!entry.isIntersecting) { return; } loadItems(); }); }); io.observe(document.getElementById('sentinel')); loadItems(); 실행 결과를 아래 예제에서 확인할 수 있습니다.<iframe class="demo" src="https://cdn.rawgit.com/fallroot/intersectionobserver-examples/master/demo-infinitescroll.html" width="600" height="400" frameborder="0">마무리IntersectionObserver API는 아직 몇몇 브라우저의 최신 버전에서만 사용할 수 있지만 지원하지 않는 브라우저를 위해 Polyfill을 제공하고 있습니다.IntersectionObserver API는 웹 광고 플랫폼 제공자와 사용자 모두에게도 좋은 소식이라 봅니다. 이 API가 정착된다면 광고 노출 여부를 측정하기가 쉬워지고 서비스에 더해졌던 리소스 낭비를 줄일 수 있을 것이라 생각합니다.레진코믹스는 크롬 브라우저 사용자의 비중이 높은 편이기 때문에 빠른 시일 안에 적용해 볼 예정입니다. 이미지 동적 로딩 기능의 개선과 정주행 기능과 같이 현재 스크롤 이벤트를 과하게 사용하고 있는 코드에 대한 부담을 덜 수 있기를 기대하고 있습니다.참고자료Intersection Observer API SpecificationIntersectionObserver’s Coming into ViewIntersection Observer API
조회수 4417

RESTful API를 설계하기 위한 디자인 팁

올라왔었던 REST 아키텍처를 훌륭하게 적용하기 위한 몇 가지 디자인 팁의 글에서 언급되지 않았던 추가적인 내용에 대해서 좀 더 얘기해보고자 합니다. 혹시 이전 포스팅을 읽지 않으셨다면 이전 포스팅을 먼저 읽으신 후 이 포스팅을 읽어주시기 바랍니다.Document?컬렉션에 관해서는 앞서 소개한 이전 글에서 자세히 설명해놓았으니 읽어보시기 바랍니다. 지금 제가 언급할 것을 도큐먼트인데요. 도큐먼트는 컬렉션과는 달리 단수명사나 명사의 조합으로 표현되어 URI에 나타납니다.http://api.soccer.restapi.org/leagues/seattle/teams/trebuchet/players/claudio 위의 예제에서 leauges라는 컬렉션 리소스가 있는 것을 알 수 있습니다. 그 컬렉션의 자식 리소스 중 하나가 seattle이라는 리소스인데요, 바로 이 리소스가 도큐먼트입니다. 도큐먼트는 하위 계층으로 또 컬렉션을 가질 수 있습니다. 이 예제에서의 teams가 seattle의 자식 컬렉션 리소스가 되겠지요. 즉, 단수 리소스는 도큐먼트라 칭하고 복수 리소스는 컬렉션으로 칭한다고 알아두시면 됩니다.이 URI는 또한 문서의 계층 구조를 표현하고 있습니다. 즉 슬래시 기호(/) 다음으로 나타내는 명사가 그 앞에 나오는 명사의 자식 계층이 되는 것이지요. 이러한 도큐먼트의 응답으로써, 요청에서 명시된 Content-Type 헤더에 1:1대응하는 응답을 주는 것이 의미 있을 때가 있습니다. 가령,URI : dogs/1 1) Content-Type: application/json 2) Content-Type: application/xml 3) Content-Type: application/png 이와 같은 URI에 3개의 요청이 주어졌고, 각각 Content-Type이 다음과 같을 때 어떤 응답이 보내져야 할까요? 물론, 그것은 응답을 설계한 사람의 맘이지만 일반적인 기준을 적용해본다면 1번과 2번 요청에는 각각 json, xml 형식으로 구조화된 데이터가 그리고 3번 요청에 대해서는 해당 강아지의 사진이 담긴 png 파일을 보낼 수 있을 것입니다. 또한, Content-Type에 대해서 명시하여 원하는 리소스를 선택할 수 있으므로 URI 내에는 파일 확장자를 포함하지 않는 것이 좋습니다.dogs/1.xml 위와 같은 URI를 만드는 것보다, dogs/1 위의 URI에 Content-Type: application/xml헤더를 포함하여 요청을 보내는 것이 더 적절한 선택입니다. 어째서 파일에 확장자를 붙이지 않는 것이 더 나은 선택일까요? URI는 고유한 리소스를 나타내는 데 쓰여야 합니다. 그런데 URI에 확장자를 붙이는 순간 마치 다른 리소스인 것처럼 느껴집니다. 확장자를 달리하여 같은 리소스에 대한 다른 표현 양식을 주문하는 것이지 해당 리소스가 달라지는 것은 아닙니다. 또한, URI에 직접 확장자가 붙게 되면 해당 리소스 URI가 응답으로 지원하는 확장자만큼 새로운 URI들이 생기게 되겠지요. 결코, 이것은 좋은 디자인이 아닙니다.Controller?기본으로 GET, PUT, POST, DELETE 요청에 1:1매치 되는 개념인 CRUD가 있습니다. CRUD의 앞글자들을 풀어보면 Create, Read, Update, Delete가 될 텐데, 각각 POST, GET, PUT, DELETE에 대응되는 개념입니다. 그런데 사실 URI를 디자인 하다 보면 이러한 방식으로 나타내기 참 어려운 경우를 많이 만나게 됩니다. 그 중 가장 많은 경우가 어떤 특정한 행위를 요청하는 경우입니다. 많은 분이 이럴 때 동사를 쓰는데, 앞선 포스팅에서 밝혔듯이 동사를 써서 URI를 디자인하는 것은 대체로 옳지 않은 방식으로 여겨집니다.이럴 때 컨트롤러 리소스를 정의하여 이 문제를 해결할 수 있습니다. 컨트롤러 리소스는 URI 경로의 제일 마지막 부분에 동사의 형태로 표시되어 해당 URI를 통해 접근했을 때 일어날 행위를 생성합니다. (개념적으로는 이렇게 받아들이시면 됩니다.) 생성과 관련된 요청이 POST이기 때문에 컨트롤러 리소스에 접근하려면 POST 요청을 보내야 합니다. 예제를 살펴보시면 이해하기 빠르실 겁니다.http://api.college.restapi.org/students/morgan/register 리소스 morgan을 등록 http://api.ognom.restapi.org/dbs/reindex 리소스 dbs를 재색인 http://api.build.restapi.org/qa/nightly/runTestSuite 리소스 nightly에 테스트를 수행 그리고 마치 프로그램의 함수처럼 컨트롤러 리소스에는 입력값을 전달할 수 있습니다. 그것은 POST 요청의 엔티티 바디에 포함되어야 합니다. 그리고 역시 함수에서 반환값을 돌려주듯이 컨트롤러 리소스에서는 해당 입력 값에 대한 응답 값을 돌려주면 되겠습니다.URI 뒤에 붙는 쿼리의 용도흔히 GET 요청을 보낼 때 뒤에 추가로 쿼리 스트링(?,=,& 기호를 이용하여)을 전달하곤 합니다. 여기서는 그 쿼리 스트링을 어떻게 디자인 하는 게 좋은지에 대한 논의와 함께 실제 서비스에서 사용되는 사례를 살펴봅니다.가령 특정 컬렉션 리소스에 대하여 질의를 보낼 때 그 컬렉션의 집합이 너무 거대할 수 있으므로 필요한 정도의 정보만을 요구하기 위해서 페이징 값 혹은 구분 값을 쿼리 스트링에 포함할 수 있습니다. 예를 들어 보면/resources?pageSize=10&pageStartIndex=0 페이징을 위한 정보 전달 /dogs?color=red&state=running&location=park 구체적인 검색 제약사항 전달 이런 식으로 써서 페이징을 한다든가 혹은 다른 파라메터(color=red)따위를 던져서 검색 범위를 제한할 수 있습니다. 흔히 쿼리 스트링을 저런 용도로 많이 사용하기 때문에 아마 관찰력이 좋으신 분들은 저런 종류의 쿼리 파라메터를 네이버, 구글 같은 포털사이트의 검색 서비스를 이용하시면서 본 적이 있으실 것입니다.이와는 약간 다르게 실제 DB에서 사용하는 SQL의 select 문과 같은 결과를 낼 수 있도록 돕는 쿼리 스트링을 URI에 나타내려는 시도도 많은 편인데요. 물론 SQL에서 제공하는 구문의 모든 의미를 다 제공할 필요는 없겠지만, 기본적으로 서비스에서 필요한 정도의 인터페이스를 적절히 제공한다면 사용자가 선택할 수 있는 옵션이 많아진다는 측면에서 좋은 방법이겠죠. 이와 관련된 예제를 몇 개 소개하겠습니다. 이것은 실제 서비스에서 API로 제공되었던 URI들입니다. 구조나 의미가 SQL 문과 상당히 유사합니다.LinkedIn /people:(id,first-name,last-name,industry) 이 경우 people 리소스를 요청하되 마치 SQL 쿼리에서 가져올 필드를 제한하는 것처럼 필요한 필드에 대해서만 괄호로 묶어서 지정한 것을 볼 수 있습니다. Facebook /joe.smith/friends?fields=id,name,picture 이 경우 이름(혹은 계정이름)이 joe.smith인 사람의 정보를 가져오되 LinkedIn의 예와 같이 필드를 제한(id,name,picture)해서 가져오도록 한 예입니다. Google ?fields=title,media:group(media:thumbnail) 구글도 마찬가지네요. 이쯤 오면 대략 저 URI가 무엇을 의미하는지 알아채셨으리라 생각합니다. URI 설계시에 주의해야 할 점URI에는 소문자를 사용해야 합니다. 왜냐하면, RFC 3986은 URI 스키마와 호스트를 제외하고는 대소문자를 구별하도록 규정하기 때문이지요.http://api.example.restapi.org/my-folder/my-doc HTTP://API.EXAMPLE.RESTAPI.ORG/my-folder/my-doc 위의 두 URI는 같은 URI입니다. 호스트에서는 대소문자를 구별하지 않기 때문이지요. http://api.example.restapi.org/my-folder/my-doc http://api.example.restapi.org/My-Folder/my-doc 하지만 위의 두 URI는 다른 URI입니다. 뒤에 붙는 path가 대소문자로 구분되기 때문입니다. 물론 소문자가 아닌, 대소문자를 섞어 쓰거나 혹은 대문자만 쓰는 것도 가능하지 않으냐는 반론이 나올 수 있습니다. 하지만 대소문자를 섞어 쓰면 URI를 기억하기 어려울 뿐만 아니라 실제 사용 시 실수하기 쉽다는 단점이 있습니다. 만약 대문자만 쓴다면 상관은 없겠으나 일반적으로는 URI에 대문자를 잘 쓰지 않기 때문에 소문자로 쓰는 것을 권장합니다.HTTP HEADERHTTP 요청과 응답을 보낼 때 특정 헤더를 포함해 요청, 응답 그리고 리소스에 대한 메타 정보를 전달할 수 있습니다. 요청 헤더와 응답 헤더에 포함되면 좋을 만한 헤더 정보들에 대하여 알아보겠습니다.요청 헤더Accept응답으로 받고 싶은 미디어 타입을 명시하기 위하여 사용됩니다. 예제를 들어 설명하겠습니다.GET /magna-opus HTTP/1.1 Host: example.org Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 이 요청은 mangna-opus 리소스에 대해서 기본적으로는 html이나 xhtml의 형식으로 응답을 받고 싶되, 만약 상황이 여의치 않으면 xml을 만약 그것도 여의치 않다면 모든 응답(*/*)을 받아들이겠다는 것을 말합니다. 옆에 붙은 q가 선호도를 나타내게 되지요. (q 생략 시 1값을 가짐) 만약 앞의 예에서 모든 응답에 대한 표시가 없다고 가정하고 서버에서 앞의 세 가지 미디어 타입을 모두 지원할 수 없는 상황이라면 응답으로 406 상태코드를 내보내야 합니다.Accept-Charset응답으로 받고 싶은 캐릭터셋에 대하여 명시하는 헤더입니다.Accept-Charset: iso-8859-5, unicode-1-1;q=0.8 가령 위의 예제는 일단 iso-8859-5를 선호하지만 unicode-1-1도 괜찮다는 메시지를 전달합니다.User-Agent현재 요청을 보낸 Agent의 정보를 표시하기 위해 사용됩니다.User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/21.0 파이어폭스 버전 21.0의 UA스트링, OS에 대한 정보도 담겨져있다. Referer해당 요청을 보내기 바로 직전에 참조하던 리소스 혹은 주소에 대한 정보를 나타내기 위해 사용합니다.Referer: http://en.wikipedia.org/wiki/Main_Page 응답 헤더Content-Length요청과 응답 메시지의 엔티티 바디가 얼마나 큰지에 대한 정보를 나타내기 위해 사용합니다. 단위는 바이트입니다.Content-Length: 348 Last-Modified해당 리소스가 마지막으로 갱신된 시간을 나타내기 위하여 사용됩니다. 캐싱 정책과 관련되어 중요한 헤더중 하나입니다.Last-Modified: Tue, 15 Nov 1994 12:45:26 GMT 캐시나 쿠키정책과 관련된 헤더 정보는 글의 분량을 고려하여 생략하였지만, 매우 중요한 헤더 중 하나이므로 다른 관련 문서들을 검색하여 일독을 권합니다.HTTP 상태 코드의미에 잘 맞는 URI를 설계하는 것도 중요한 일이지만 그 리소스에 대한 응답을 잘 내어주는 것 또한 중요한 일입니다. 그런데 혹시 HTTP의 상태코드 중 200이나 404코드 정도만 알고 계시지 않으신가요? 그 코드의 정확한 의미를 얘기하실 수 있으신가요? 사실 저도 흔하게 볼 수 있는 상태코드 몇 개 정도만 알고 있고 나머지 상태코드의 정확한 의미라든지 쓰임새에는 관심이 별로 없었던 것이 사실이었습니다. 하지만 전문적으로 웹 개발의 길을 걸어갈 사람이라면 그보다는 좀 더 자세히, 많이 알고 있을 필요가 있겠지요. 사실 우리가 생각하는 것보다 훨씬 많은 상태코드가 존재하고 각각 그 쓰임이 다 다릅니다. 그 중 몇 개를 살펴보겠습니다.200 : OK일반적인 요청 성공을 나타내는 데 사용합니다. 단, 주의해야 할 점이 있다면 200코드를 에러 응답에 사용하면 안 된다는 것입니다. 가령 코드는 200인데 에러메시지를 포함한다든가 하면 의미에 맞지 않은 응답코드를 보낸 것이겠지요. 이런 적절치 못한 상황을 처리하는 경우에는 4XX대 코드를 사용하여야 합니다.201 : Created리소스 생성 성공에 대한 응답 코드입니다. CRUD 요청에서 Create 요청에 대한(즉, 컬렉션에 도큐먼트 추가 같은) 응답으로 내보낼 수 있는 응답코드입니다. 응답 헤더의 Location 필드에 생성된 리소스에 접근할 수 있는 URI를 포함할 수 있다면 브라우저에서 그 값을 참조하여 적절히 대응할 수 있겠습니다.202 : Accepted대체로 처리 시간이 오래 걸리는 비동기 요청에 대한 응답으로 사용됩니다. 즉, 이 요청에 대한 응답이 결과를 포함하지 않을 수 있다는 것이죠. 하지만 최소한 응답 헤더나 응답데이터에 해당 처리를 모니터링할 수 있는 리소스 페이지를 안내하거나 혹은 해당 리소스가 처리되기까지의 예상 경과 시간 따위를 안내하는 것이 더 좋은 설계라고 할 수 있겠습니다.301 : Moved Permanently리소스가 이동되었을 경우의 응답코드입니다. 새로 리소스가 이동된 URI를 응답 Location 헤더에 명시해야 합니다. 이 응답을 받은 클라이언트는 새 URI로 이동하든지 아니면 URI를 갱신하고 캐싱을 한다든지 하는 행위를 해야 되겠지요.400 : Bad Request일반적인 요청실패에 사용합니다. 대체로 서버가 이해할 수 없는 형식의 요청이 왔을 때 응답하기 위해 사용됩니다. 무턱대고 400에러를 응답으로 주지 말고, 다른 4XX대의 코드가 더 의미를 잘 설명할 수 있는지에 대하여 고민해야 합니다.401 : Unauthorized말 그대로 리소스 접근 권한을 가지고 있지 않다는 것을 의미하기 위한 응답코드입니다. 리소스를 획득하기 위하여 요청자는 인증에 필요한 헤더(가령 Authorization 헤더 같은)나 데이터를 첨부해야 할 것입니다. 필요한 헤더나 데이터는 서버 쪽에서 요구하는 스펙을 충실히 따라야겠지요.403 : Forbidden감춰진 리소스에 접근하려 할 때의 응답코드입니다. 401과 달리 인증의 여부와 관계없이 리소스를 보여주지 않습니다. 기본적으로 클라이언트 쪽에 정보를 공개하고 싶지 않은 리소스임을 나타내기 위해 사용합니다.404 : Not Found해당 URI와 매치되는 리소스가 없다는 의미를 전달합니다. 어지간한 사람들은 다 한 번씩(?) 마주치게 되는 응답코드이지요.405 : Method Not Allowed지원하지 않는 요청(예를 들어 POST 요청을 받는 컨트롤러 리소스에 GET 요청을 보낸다든가)을 하였을 때 사용합니다. 가능하다면 응답 메시지에 Allow 헤더를 추가하고 그곳에 지원하는 메서드를 명시하여 클라이언트 측에서 정확한 요청을 보낼 수 있도록 유도합니다.Allow: GET, POST 406 : Not Acceptable해당 미디어 타입(MIME 타입)에 대해서 지원하지 않을 때 사용합니다. 요청 Accept 헤더에 명기된 타입(가령 Application/xml)에 대해서 지원이 불가능할 경우에 돌려주면 되는 코드입니다.409 : Conflict요청의 형식에는 문제가 없지만 리소스 상태에 의하여 해당 요청 자체를 수행할 수 없는 경우의 응답코드입니다. 즉, 이미 삭제된 리소스를 또 삭제한다든가 비어있는 리스트에서 무언가를 요청한다든가 하는 모순된 상황을 생각해보면 되겠습니다. 응답으로는 그 방법을 어떻게 해결할 수 있을지에(혹은 문제가 무엇인지) 대한 힌트가 포함되면 좋을 것입니다.500 : Internal Server Error일반적인 서버 에러에 대한 응답코드입니다. 4XX대의 에러코드가 클라이언트 측 에러를 나타내기 위해 사용된다면, 5XX대의 에러코드는 서버 측 에러를 나타내기 위해 사용됩니다.503 : Service Unavailable가장 두려운(?) 응답코드 중 하나일 503입니다. 현재 서버에 과부하가 걸려있거나 유지보수를 위하여 잠시 접근이 거부될 때 필요한 응답코드입니다.그냥 맨 앞의 숫자별로 퉁쳐서 상태코드를 내보내지 않고, 이렇게 디테일한 의미까지 따져가면서 상태코드를 내보내는 것에 대해서 그 효용성에 의문을 제기하시는 분들이 있을 것 같습니다. 하지만 브라우저에서 혹은 서버 단에서 특정 상태코드에 대해서 내부 구현을 달리하거나 최적화를 통해 더 쾌적한 환경을 제공할 가능성이 있으므로 되도록 의미에 걸맞은 상태코드를 사용하는 것을 생활화하는 것이 중요합니다. 또한, 이렇게 디테일한 상황을 가정하고 만든 URI들이 다음에 서비스를 확장할 때 큰 도움이 될 것임은 의심할 여지가 없겠지요.위에서 소개한 응답 코드 말고 또 다른 응답 코드들에 대해서도 전부 소개해 놓은 링크를 밑에 달아두었으니 참고하시기 바랍니다.정리지금까지 소개한 내용이 조금은 두서없게 느껴졌을 수도 있겠다는 생각이 들어 한 번 전체 내용 정리를 해보려 합니다.컨트롤러의 정확한 쓰임을 알고 적절한 컨트롤러 URI를 구현하자.URI에 추가로 붙게 되는 쿼리 스트링의 형식을 잘 디자인하여 사용자로 하여금 적재적소에 쓸 수 있도록 하자.가능하다면 이용 가능한 HTTP 헤더를 적절하게 첨가하자.HTTP 상태코드의 의미에 대해서 생각해보고 상황에 맞는 적절한 상태 코드를 응답으로 보내줄 수 있도록 하자.이 글을 쓰면서 한빛 미디어의 일관성 있는 웹 서비스 인터페이스 설계를 위한 REST API 디자인 규칙과 apigee사의 web API design eBook을 참고하였습니다. 둘 다 내용이 좋은 서적이고 이 글에서 다루지 않은 심층 내용을 다루니 기회가 되시면 읽어보세요.referencesUniform resource identifierapigee api design best practicesrestful uri designHTTP status codesList of HTTP status codesURI schemeMIME typesMIMEfun and unusual http response headers#스포카 #디자인 #디자이너 #디자인팀 #개발 #개발자 #개발팀 #협업 #코워킹 #Co-working #업무프로세스 #꿀팁 #인사이트

기업문화 엿볼 때, 더팀스

로그인

/