스토리 홈

인터뷰

피드

뉴스

조회수 1611

스마트 컨트랙트 개발과정에서의 실수 — TransferFrom

Hexlant는 Blockchain 전문 개발 팀으로, 다양한 기관들의 스마트 컨트랙트 코드를 검수하는 업무도 진행하고 있습니다.지금까지 다양한 컨트랙트 코드들을 리뷰하면서 나왔던 문제점들을 공유하고, 더 나은 방법으로 개발 할 수 있는 방법들에 대해 이야기 해보고자 합니다.transferFrom에 대한 이해ERC-20 표준에 보면, transferFrom 이라는 함수가 있습니다. 일반적으로 많이 쓰이는 기능이 아니다 보니 잘 모르고 넘어가는 경우가 많습니다.function transferFrom(address _from, address _to, uint256 _value) public returns(bool)transferFrom은 남이 가지고 있는 토큰을 누군가에게 보내는 기능입니다.그 누군가는 내가 될 수도 있습니다.이 설명만 보면, 아래와 같은 의문이 생기실 겁니다.어? 남의 토큰을 내 마음대로 옮길 수 있다고??당연히 마음대로 옮기면 안되겠죠.그래서 approve 함수를 통해, 내 토큰을 사용할 수 있는 사람을 지정할 수 있습니다function approve(address spender, uint256 _value) public returns(bool)토큰의 holder는 approve함수를 호출하여 spender에게 일정량 만큼을 사용할 수 있게 허용을 해 줍니다. 그럼 spender는 허용된 범위 안에서 토큰을 마음대로 옮길 수 있습니다.허가되지 않은 토큰의 이동많이 쓰지 않는 기능이다 보니, 이 부분에 대해 고려하지 않고 개발 하는 경우가 있을 수 있습니다.아래는 저희가 리뷰했던 코드 중 일부입니다function approve(address _spender, uint256 _value) public returns (bool success) { require(_spender > address(0)); allowed[msg.sender][_spender] = _value; Approval(msg.sender, _spender, _value); return true; }function transferFrom(address _from, address _to, uint256 _value) public { require(_from > address(0)); require(_to > address(0)); require(balances[_from] >= _value); require(balances[_to] + _value > balances[_to]); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); Transfer(_from, _to, _value); }approve 함수를 우선적으로 보면, allowed 테이블에, msg.sender가 _spender에게 얼마만큼 토큰사용을 허용해 주었는지 저장하는것 말고는 특별한 기능은 없습니다.allowed[msg.sender][_spender] = _value;이제 transferFrom 함수를 확인해 보겠습니다.transferFrom은 실제 토큰이 전송되는 부분이니 예가 필요할 것같습니다.Alice에게 10000개의 토큰이 있을 때, Bob이 transferFrom을 다음과 같이 호출했다고 합시다.transferFrom(Alice, Bob, 10000)자 이제 transferFrom코드를 따라가며 토큰이 어떻게 전송이 되는지 확인해 봅시다.require는 안에 들어간 조건이 만족해야만 다음 라인을 실행 할 수 있다는 명령어 입니다. require를 만족하지 못하면, 해당 트랙잭션은 수행되지 않고 실패로 처리됩니다.require(_from > address(0)); require(_to > address(0));위의 두 줄의 조건은 입력된 주소_from, _to는 각각 Alice와 Bob의 지갑 주소이기 때문에 0x*****형태로 0x0000…0000이 아니기에 해당 조건들을 모두 만족합니다.require(balances[_from] >= _value); require(balances[_to] + _value > balances[_to]);Alice의 지갑에는 10000개의 토큰이 있고 _value는 10000개이니까 저 require를 실제 숫자로 대입하면require(10000 >= 100000); require(0+10000 > 0);조건을 충분히 만족합니다.그 다음부분들을 실제로 Alice의 주소에서 Bob의주소로 10000개의 토큰을 옮기는 작업입니다.balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); Transfer(_from, _to, _value);Alice의 잔액에서 10000개만큼이 빠지고,Bob의 잔액에 10000개가 추가됩니다.balances[Alice] = balances[Alice].sub(10000); balances[Bob] = balances[Bob].add(10000); Transfer(Alice, Bob, 10000);이로서 Bob은 Alice의 토큰 10000개를 자신의 지갑으로 이동시켰습니다.일련의 과정을 요약하면1. 주소 오류 검증 2. 보내려는 토큰이 Alice가 가진 잔액보다 작은지 검증 3. 받았을때 Overflow가 발생하는지 체크 4. Alice의 잔액에서 보내는 만큼의 토큰 수량을 뺀다 5. Bob의 잔액에 보내는 만큼의 토큰 수량을 더한다과정을 보면 Bob이 Alice로 부터 토큰 사용을 허락받았는지 체크하는 부분이 없습니다.따라서 누군가가 보유한 토큰을 다른 사람이 제멋대로 쓸수 있게됩니다.오류수정transferFrom이 정상적으로 동작하려면 어떻게 수정되어야 할까요?function transferFrom(address _from, address _to, uint256 _value) public { require(_from > address(0)); require(_to > address(0)); require(balances[_from] >= _value); require(balances[_to] + _value > balances[_to]); require(allowed[_from][msg.sender] >= _value); balances[_from] = balances[_from].sub(_value); balances[_to] = balances[_to].add(_value); allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value) Transfer(_from, _to, _value); }첫 번째로는 당연히 transferFrom을 호출한 사람이 권한이 있는지 확인해야 합니다.require(allowed[_from][msg.sender] >= _value);이 조건을 통해 허용된 수량안에서만 토큰을 옮길 수 있게 만들 수 있습니다.두번째는, 토큰을 옮긴 후 허용량을 줄여주어야 합니다.allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value)만일 Alice가 Bob에게 10000개의 토큰을 허용해 주고, Bob이 그중 100개를 사용했다면, 그 다음번에 Bob은 9900개 안에서만 사용할 수 있어야 합니다.#헥슬란트 #HEXLANT #블록체인 #개발자 #개발팀 #기술기업 #기술중심 #실수담
조회수 1368

스켈티인터뷰 / 스켈터랩스의 금손 이주현 님을 만나보세요:)

Editor. 스켈터랩스에서는 배경이 모두 다른 다양한 멤버들이 함께 모여 최고의 머신 인텔리전스 개발을 향해 힘껏 나아가고 있습니다. 스켈터랩스의 식구들, Skeltie를 소개하는 시간을 통해 우리의 일상과 혁신을 만들어가는 과정을 들어보세요! 스켈터랩스의 하드웨어팀 금손 이주현 님을 만나보세요:)사진1. 스켈터랩스의 하드웨어 엔지니어 이주현 님Q. 자기소개를 부탁한다.A. 스켈터랩스의 하드웨어 엔지니어로 일하고있는 이주현이다.Q. 스켈터랩스에서 구체적으로 어떤 일을 맡고 있는가.A. 현재는 스켈터랩스의 레고(L.ego)팀에서 곧 출시 예정인 스마트 미러, 샘(Samm)을 만들고 있다. 레고 팀은 스켈터랩스가 가진 원천 기술을 소비자가 쉽고 편하게 접할 수 있도록 디바이스(Device) 형태로 구현하는 팀이다. 우리의 원천 기술이 다양하다 보니, 이 기술을 어떻게 활용하여 어떤 제품을 만들어야 할지부터 고민한다.Q. 매번 새로운 기획을 하고 아이디어를 내는 것이 쉬운 일은 아닐 것 같다.A. 그래서 다양한 소스를 참고하고 많은 사람에게 의견을 구하려고 한다. 킥스타터(Kickstarter)나 와디즈(Wadiz)와 같은 크라우드펀딩 플랫폼을 들여다보거나 DIY 상품을 여러가지 찾아보며 영감을 얻는다. 최근에는 레고팀 PM(Product Manger)이신 아영님의 소개로 산업디자인과 수업을 청강했다. 산업디자인이 내가 일하는 분야와 아주 밀접한 것은 아니지만 학생들이 아이디어를 개진하여 그것을 발전시켜나가는 것을 보며 나 또한 아이디어를 얻을 수 있었다. 이런 과정을 통해 제품이 구체화되면 성공 가능성에 연연하지 않고 일단 개발을 시도하려 한다.Q. 실제로 제작하는 과정에서도 예기치 못한 문제에 많이 부딪히지 않나.A. 맞다. 참신해보였던 아이디어도 기능을 구체화하는 단계에 접어들면 자잘한 이슈가 생기기 마련이다. 사람마다 생각이 다르기 때문에, 고객에게 제품의 어떤 기능이 유용할 지 예상하기도 쉽지 않다. 때문에 소프트웨어 엔지니어와 디자이너, 마케터와 같은 다른 포지션의 동료들과 자주 미팅을 갖는다.제품의 구체화가 성공적으로 완료되더라도, 실제 구현이 녹록치 않다. 가령 곧 출시를 앞두고 있는 스마트 미러 제품, 샘(Samm)의 경우 사용자의 제스처(Gesture)를 인식하여 작동하는데 생각보다 카메라의 한계가 있더라. 그래서 요즘은 카메라 뿐만 아니라 다양한 센서를 활용하는 방법을 찾고있다.Q. 내가 상상했던 ‘일반적인 하드웨어 엔지니어'의 업무와는 조금 달라보인다. 기획자 역할까지 겸비하는 것으로 보이는데, 맞나.A. ‘일반적인 하드웨어 엔지니어'의 역할을 무엇이라고 정의하는지에 따라 다른 것 같다. 나는 오히려 스켈터랩스에서 하는 업무가 내가 생상했던 ‘하드웨어 엔지니어'의 업무다. 보통 엔지니어들은 직접 만들어보는 것을 좋아한다. 그렇지만 만들고 싶은 디바이스가 늘 회사의 방향성과 일치하는 것은 아니기 때문에, 집에서 홀로 개발하기에는 시간과 돈이 늘 부족하다는 하소연을 많이 듣곤 한다. 또한 회사의 규모가 커질수록 하드웨어 엔지니어는 하나의 제품을 깊게 들여다보기 때문에 전문가로 성장하는 반면, 내가 하고싶은 개발을 할 수 있는 기회는 줄어들기 마련이다. 하지만 스켈터랩스에서는 내가 상상한 디바이스를 구현하기 위해 각종 부품을 조립하여 테스트하고, 응용하여 새로운 디바이스를 만들고 있다. 그래서인지 이곳이 내게는 딱딱한 회사의 느낌이 아니다. 정확히 내가 꿈꾸고 하고싶었던 일을 할 수 있게 도와주는 곳이라고 느낀다.Q. 최근에는 어떤 디바이스를 만들고 있는가.A. 흔히 인공지능이라고 하면 일종의 어시스턴트를 많이 떠올리는 것 같다. 개인적으로는 이 ‘어시스턴트'라는 것이 너무 범위가 넓고 거대한 느낌이다. 나는 조금 더 작고 가벼운 기술, 그리고 특정한 범위 내에서 나의 일상에 정말 도움을 주는 제품을 개발하고 싶었다. 처음에는 방에 무드 조명이 있는데 ‘이 조명이 좀더 스마트하다면’이라는 생각을 가지고 확장시켜나갔다. 피터팬에 등장하는 “팅커벨”이라는 캐릭터가 생각이 났고 원하는 분위기에 따라서 혹은 알람을 제공하기 위해 예쁘게 불빛을 밝혀주는 것이 초기 모델이었다. 가정에서 인공지능 스피커를 사용하는 사용자들은 스피커를 실상 똑똑하게 쓰지 못하는 경우가 많다. 심지어 꺼놓는 경우도 많이 보았다. 나 또한 구매 초기에는 열심히 사용하다가 요즘은 알람 기능 만을 사용하고 있다. 개인적으로 인공지능 스피커를 잘 사용하지 않는 이유가 현재의 사용성과 음성으로 정보를 전달한다는 한계 때문이라고 생각했다. 스피커는 음성 명령을 잘 알아듣지도 못할 뿐더러, 내게는 스피커의 부자연스러운 음성이 시끄럽게 느껴지기조차 했다. 이런 불편함을 개선하기 위해 무드 조명의 색 조합을 통한 정보 전달을 구상했다. 조명의 색깔로 전달한다면, 스피커처럼 음성이 다 끝날 때 까지 기다리지 않아도 되고, 더욱 빠르고 덜 성가신 방법으로도 정보를 전달할 수 있다고 생각한다. 프로젝트를 구체화하며 조명과 사물인터넷(IoT)에 대해 공부하고, 컨셉을 발전시키다 보니 사물인터넷을 통한 조명 컨트롤이라는 새로운 방향성이 생겼다.사진2. 이주현 님은 다양한 실험을 통해 최적의 디바이스를 개발하고 있다.Q. 스켈터랩스에 어떻게 입사하게 되었는지.A. 어릴 때 부터 아이디어를 내고, 그것을 실제로 구현해보는 다양한 활동을 좋아했다. 학부 시절에는 아이디어를 발제하고 이를 직접 만들어보는 소모임에도 참여하였다. 학부 전공이 전자공학이지만 인공지능 기술에 대한 관심도 컸다. 사실 인공지능은 소프트웨어 분야 아닌가. 그래서 졸업작품을 인공 지능 관련 디바이스로 정했을 때도 소프트웨어 관련 강의를 찾아 들어야했다. 그러다 현재 우리회사 하드웨어 엔지니어 파트의 리더를 맡고 있는 재경님을 만나게 되었다. 처음에는 아이디어를 실현하기 위한 기술 자문을 구하기 위해 뵈었는데, 재경님이 근무하고 계신 회사 얘기를 들으면서 입사에 대한 꿈을 키우게 되었다. 그렇게 우연히 스켈터랩스에 대해 알게된 것 같다.Q. 자발적으로 인공지능 관련 공부를 했다지만, 스켈터랩스에서 일하며 인공지능 기술 회사에 하드웨어 엔지니어로 근무하기가 녹록치않을 것 같다.A. 인공지능 기술을 비롯한 소프트웨어 전반의 공부를 계속 해야하는 것은 맞다. 그렇지만 스켈터랩스는 자발적으로 공부하기 좋은 문화를 갖추고 있고, 자연스럽게 최신 기술을 접할 수 있는 기회도 많다. 너와 나의 일을 규정짓고 나누기보다는, 무엇이든 스스럼 없이 질문하고, 함께 답변을 찾아 가는 분위기가 조성되어있다. 그래서 기술 하나를 물어보면 열을 가르쳐주려고 한다. A를 물어볼 때, 시간이 된다면 A부터 Z까지는 알아서 답변해주는 분위기 같다. Tech-Talk와 같은 사내 세미나를 통해서 강의 형태로 인공지능 기술에 대해 접하기도 한다. 또한 하드웨어 팀 내부적으로도 공부에 대한 필요를 느끼고  자체 세미나를 진행한다. 거창한 것은 아니지만, 우리가 스켈터랩스 기술에 대해 알아야 할 부분을 각자 공부하고 공유하는 자리였다. 이러한 과정이 버겁기 보다는 좋아하는 분야를 더욱 심층적으로 접할 수 있어 좋다.Q. 스켈터랩스에서 일하며 느끼는 좋은 점을 자랑한다면.A. 스켈터랩스는 ‘일단 해보자'라는 분위기가 있다. 아이디어를 내면, 시간과 재화를 제공해주고 시도해볼 것을 권장한다. 작은 실패에 연연해 할 필요도 없다. 해보고 아니다 싶을 때, 그 때 가서 접어도 늦지 않다, 라는 쿨한 문화가 있다. 나와 같이 새로운 것을 생각하고 만드는 것을 좋아하는 이들이라면, 이곳이 정말 이상적이다. 집에서 혼자 하던 것을 ‘일'로서 지원받으며 할 수 있으니까 말이다. 그리고 정말 눈치보지 않는 문화라는 점을 강조하고 싶다. 일하다 지칠 때면 블루룸(스켈터랩스에서 가장 큰 룸인데, 게임방으로 활용되고 있다)에서 게임을 할 수도 있고, 쇼파로 편하게 자리를 옮겨 일하기도 한다. 입사 초창기에 휴가에 대해서 미리 양해를 구하곤 했는데, 그럴 때마다 들은 말은 ‘알아서 할테니 걱정하지 말아라. 휴가썼다고 말도 하지 말고 떠나라' 였다. 이처럼 자율적인 문화에서도 각자 알아서 제 몫을 톡톡히 해내고 있다는 것이 스켈터랩스의 가장 멋진 점이라고 생각한다.Q. 반대로 가장 힘든 점은.A. 아무리 하드웨어 엔지니어 파트에 대한 지원이 있더라도, 우리는 어디까지나 ‘인공지능 기술’ 회사다. 그렇기 때문에 소프트웨어 엔지니어가 훨씬 많고, 프로그램 개발이 회사의 메인 테스크(Main Task)로 인식될 때가 많다. 전자공학을 전공했는데 인공지능 회사에 다닌다고 하면 의아해 하는 엔지니어들도 많다. 하지만 최근 하드웨어 단에서 인공지능을 작은 저전력 디바이스에 옮기려는 연구는 계속해서 진행되고 있다. 소프트웨어팀이 멋지게 구현한 어플리케이션 등의 서비스를 100퍼센트 전달할 수 있는 디바이스를 만드는 것을 목표로 하고 있다.사진 3. 스켈터랩스의 블루룸에는 각종 게임이 구비되어있고 밴드부 연습실로 활용된다.Q. 스켈터랩스에서 업무 외에 어떤 활동을 하고 있나.A. 밴드, 축구, 헬스동아리까지 하고 있다. 취미가 음악이라 대학교 때부터 밴드부로 활동했는데, 그때마다 공간의 필요성을 절감했었다. 악기 대여비도 만만치않게 들지 않나. 스켈터랩스 밴드인 Terkels는 공간과 악기를 모두 갖추고 있다. 심지어 PA(Public Address) 앰프와 공연용 스피커까지 구비되어 있다. 축구 동아리에서 매주 1회 풋살 대결을 펼치고, 점심 시간마다 헬스 동아리원들과 함께 헬스장에 간다. 이렇다보니 부모님한테 ‘놀려고 회사가냐'라는 핀잔을 들을 정도다.Q. 많은 동아리와 업무를 병행하는 것이 힘들지는 않은가.A. 전혀. 오히려 동아리 활동으로 더욱 친해진 팀원과 함께 머리를 맞대고 하는 업무이다보니 ‘일'이 아니라 일종의 ‘놀이'처럼 인식될 때가 있다. 그리고 스켈터랩스 특유의 문화가 겉으로는 느릿느릿 여유롭더라도 내부적으로는 치열한 부분이 있다. 축구동아리에 처음 참여했을 때 동아리원들이 ‘살살 뜁시다' 하더니 막상 경기 시작되자마자 엄청나게 공격적이더라. 살살 뛰는 사람은 한 명도 없었다. 무섭게 뛰고 공격하면서 골이 계속 터졌다. 헬스동아리는 최근에 생긴 동아리다. 여름맞이 몸을 만들기 위해서 여럿이 뭉쳐서 헬스장을 함께 간다. 헬스 자체가 함께 할 수 있는 운동은 아니지만, 그래도 시간을 정해서 함께 이동하다 보니 ‘오늘은 좀 운동하지말고 먹을까' 싶다가도 다른 분들이 가면 자극을 받게 되고, 더 열심히 운동하게 되더라. 일도 마찬가지다. 처음에는 ‘회사가 이렇게 놀게 해줘도 되나'했지만, 내부적으로 탄탄하게 서로 함께 놀고 일하며 자극과 영감을 받는 문화다.회사는 딱히 데드라인을 촉박하게 주지도 않고, 압박을 하는 경우도 없다. 그런데 다들 게임방에서 신나게 게임을 하다가도 다음 날이면 개발을 마친 결과물을 들고 온다. 자율적이지만 확실하게 자신의 업무에 대해 책임을 지는 문화가 형성되어 있다. 그렇다보니 나 또한 자연스럽게 동아리 활동을 하다가도 오늘 하루 내가 끝내야할 일로 정해놓은 것들은 마치고 퇴근하려 한다.Q. 회사에 게임방이라니, 게임방 얘기를 듣고싶다.A. 게임을 좋아하는 사람들이 많다 보니 닌텐도를 비롯해서 엑스박스(Xbox), 플레이스테이션(Playstation)을 비롯한 각종 게임기가 마련되어 있다. 다트와 탁구대, 당구대까지 준비되어 있다. 사무실을 성수로 이사하면서 테드님(Ted Cho, 스켈터랩스의 대표인 조원규 님은 사내에서 테드님으로 불린다)이 ‘모두가 놀 수 있는 공간을 만들겠다'라고 했었는데, 정말 놀이터를 만들어주시더라. 덕분에 점심시간마다 삼삼오오 모여서 각종 게임과 탁구, 당구를 즐기고 있다.Q. 하드웨어 엔지니어로서 최종 목표가 있다면.A. 테드님이 우리에게 자주 하는 말 중 하나가 ‘Don’t be evil’이다. 이 말은 사실 구글의 모토인데, 스켈터랩스의 모두가 공감하는 얘기다. 기업이 이윤을 추구할수록 소수에 대한 외면이 발생하기도 하고, 기술 기업으로서 수익 창출 만을 목표로 하면 정작 일상을 어떻게 더욱 편리하고 윤택하게 만들어줄 수 있는지를 쉽게 망각하는 것 같다. 사악해지지 않으면서, 정말 우리의 삶을 나아지게 하는 방법을 계속해서 고민하고 싶다.#스켈터랩스 #사무실풍경 #업무환경 #사내복지 #기업문화 #팀원인터뷰 #팀원소개 #팀원자랑
조회수 1405

웹 서비스 개발자가 APM을 사용해야 하는 이유

백엔드 서비스를 만들고 운영하는 개발자라면, 지금 바로 APM 서비스를 사용해 보세요. 와탭의 APM은 국내 수많은 Enterprise 기업에서 자사의 서비스를 분석하기 위해 사용되고 있으며 많은 효과를 보고 있습니다. 북미에서는 이미 수많은 스타트업이 DevOps의 기본 도구로 APM을 선택하고 있습니다. APM은 원래 대규모 서비스를 운영하는 분들이 전문적으로 사용하고 있었지만 최근 트렌드는 운영자에서 개발자로 이동하고 있는 서비스 이기도 합니다. 특히 와탭의 APM은 개발자 분들을 위한 스택 분석 기능이 있습니다. 개발자라면 와탭 APM 서비스가 제공하는 아래의 3가지 스택 분석 기능을 꼭 사용해 보세요. 유니크 스택탑 스택액티브 스택많은 개발자들이 자신이 만든 서비스가 어떻게 동작하는지 또는 웹 서비스에 어떤 영향을 주고 있는지 알지 못합니다. 하지만 와탭 애플리케이션 성능 모니터링(APM) 서비스를 사용하면 메소드가 애플리케이션에서 어떻게 사용되는지 얼마나 사용되는지 알수 있습니다. 와탭은 다른 APM 서비스와 다르게 10초에 한번씩 활동중인 트랜잭션을 검사하여 트랜잭션에 콜스택정보를 저장하고 있습니다. 그리고 이렇게 저장된 스택정보를 가지고 3가지 형태로 가공하여 보여주는데, 이 것이 유니크 스택 / 탑 스택 / 액티브 스택입니다. 먼저 유니크 스택은 가장 많이 사용된 스택 정보를 보여주는 방식입니다. 트랜잭션에서 실행되고 있는 메소드가 A 이고 이를 호출한 메소드가 모두 일치하는 스택을 유니크 스택이라고 합니다.1. A() ← C()2. A() ← C()3. B() ← D()4. B() ← E()5. B() ← F()위와 같은 경유 유니크 스택은 아래와 같이 통계를 내어 보여 줍니다. 40% A()    A()    C()20% B()    B()    D()20% B()    B()    E()20% B()    B()    F()이렇게 콜스택 정보 전체를 기준으로 분석을 하는 경우에는 성능에 영향을 주는 기능 단위의 분석이 가능합니다. 하지만 성능에 영향을 많이 주는 메소드를 알고 싶을 때가 있습니다. 이런 경우에 사용하는 것이 탑 스택 분석입니다. 아까와 같은 상황을 예를 들겠습니다.1. A() ← C()2. A() ← C()3. B() ← D()4. B() ← E()5. B() ← F()이런 상황에서 탑 스택 분석은 아래와 같이 가장 많이 사용되느 메소드를 알려줍니다. 60% B()    33% D()    33% E()    33% F()40% A()    100% C()유니크 스택에서는 A() ← C() 가 가장 많이 사용된 스택이라는 것을 알려주지만 탑 스택에서는 B() 메소드가 가장 많이 사용된 메소드라는 것을 알려줍니다. 이 두가지 내용을 통해 가장 많이 사용되는 메소드의 집합가 가장 많이 호출되는 메소드를 알아 낼 수 있습니다. 만일 서비스를 메소드 단위에서 개선하고 싶다면 이 정보를 기반으로 개선 작업을 진행하면 많은 도움을 받을 수 있습니다. 위에 화면에서 메소드를 선택하면 메소드를 호출한 스택들의 정보를 확인 할 수 있습니다. 마지막으로 액티브 스택입니다. 액티브 스택은 WAS 서버와 URL 그리고 발생 시간을 기준으로 저장된 콜스택의 정보를 보여줍니다. 서비스 성능이 떨어진 시간대의 콜스택 정보를 확인 함으로써 메소드 구간에서의 튜닝 정보를 제공합니다. 액티브 스택은 핵심 기능이 하나더 있습니다. 바로 서비스가 동작하는 스탭정보에 통합됨으로써 문제를 바로 확인할 수 있는 기능입니다. 와탭의 APM에서만 분석가능한 기능이며 특허로 등록되어 있습니다. 액티브 스택은 통계 관점이 아니라 실행 관점에서 문제를 바라보고 있습니다. 우리가 만든 웹 어플리케이션을 고객에 입장에서 보면 아래와 같이 동작합니다. 고객 → 웹 서비스 요청 → 서버 접속 → 서비스 접속 → 애플리케이션1 → 메소드 1 → DB 1접근 → Query 1 → Query 2 → 메소드 2 → 파일 접근 → 메소드 3 → 결과 취합 → WAS 통과 → 웹 서비스 결과 반환 일반적으로 애플리케이션 모니터링은 이런 상항을 아래와 같이 보여줍니다. 서비스 접속 → Query 1 → Query 2 → 파일 접근 → 트랜잭션 종료와탭의 애플리케이션 모니터링은 수집된 콜 스택 정보를 기반으로 아래와 같이 보여줍니다.  서비스 접속 → Query 1 → 메소드 2 → Query 2 → 파일 접근 →메소드 3 → 트랜잭션 종료위에 상황은 트랜잭션에서 메소드 2와 메소드 3이 수집된 경우에 트랜잭션의 스탭의 실행시간에 맞쳐서 정보를 재구성하는 것을 보여주고 있습니다. 이렇게 확인하게 된다면 메소드에서 발생하는 성능 문제를 확인 할 수 있습니다. APM 서비스는 와탭 / 뉴렐렉 / 데이터 독과 같은 서비스들을 통해서 2주에서 한달간 언제든 무료로 사용가능합니다. 다만 메소드에 대한 분석 기능은 와탭의 APM에서만 제공하는 기능들이 많습니다. 개발자라면 한번쯤 와탭의 APM 서비스를 통해 자신이 만들고 운영하고 있는 서비스에서 가장 많이 사용되는 메소드가 무엇인지 확인 해 보시기 바랍니다. Tip!! APM은 개발시에 사용하는 디버깅 도구라기 보다는 막대한 량의 트랜잭션이 발생하는 운영과정에서 사용되는 도구입니다. 트랜잭션 자체가 적다면 원하는 데이타가 안 나올 수 도 있습니다. 와탭으로 모니터링 하기 - 목차 바로가기#와탭랩스 #개발자 #개발팀 #인사이트 #경험공유 #일지 #서비스소개
조회수 2403

Tabnabbing 피싱 공격의 동작 원리와 대응책

브라우저에서 사용자의 개인 정보를 가로채는 여러가지 피싱 공격 기법이 있습니다. 이 글에서는 그 중에서도 상대적으로 단순해서 과소평가된 Tabnabbing 공격의 동작 원리와 대응책을 함께 알아보겠습니다.Tabnabbing 의 동작 원리Tabnabbing은 HTML 문서 내에서 링크(target이 _blank인 Anchor 태그)를 클릭 했을 때, 새롭게 열린 탭(또는 페이지)에서 기존의 문서의 location을 피싱 사이트로 변경해 정보를 탈취하는 공격 기술을 뜻한다. 이 공격은 메일이나 오픈 커뮤니티에서 쉽게 사용될 수 있습니다.(출처: blog.jxck.io 영어 스펠링이 이상해 보이는 것은 기분 탓입니다)공격 절차는 다음과 같습니다:사용자가 cg**m**.example.com에 접속합니다.해당 사이트에서 happy.example.com으로 갈 수 있는 외부 링크를 클릭합니다.새 탭에 happy.example.com가 열립니다.happy.example.com에는 window.opener 속성이 존재합니다.자바스크립트를 사용해 opener의 location을 피싱 목적의 cg**n**.example.com/login 으로 변경합니다.사용자는 다시 본래의 탭으로 돌아옵니다.로그인이 풀렸다고 착각하고 아이디와 비밀번호를 입력한다.cg**n**.example.com은 사용자가 입력한 계정 정보를 탈취한 후 다시 본래의 사이트로 리다이렉트합니다.예제: 네이버 메일 vs. Gmail시나리오를 하나 그려볼까요?공격자가 네이버 계정을 탈취할 목적으로 여러분에게 세일 정보를 담은 메일을 보냅니다. 그 메일에는 [자세히 보기]라는 외부 링크가 포함되어 있습니다. 물론 이 세일 정보는 가짜지만 공격자에겐 중요하지 않습니다. 메일을 읽는 사람이 유혹에 빠져 링크를 클릭하면 그만이죠.(상단의 주소를 주목하세요)하지만 Gmail은 이 공격이 통하지 않습니다. Gmail은 이러한 공격을 막기 위해 Anchor 태그에 data-saferedirecturl 속성을 부여해 안전하게 리다이렉트 합니다.rel=noopener 속성이러한 공격의 취약점을 극복하고자 noopener 속성이 추가됐습니다. rel=noopener 속성이 부여된 링크를 통해 열린 페이지는 opener의 location변경과 같은 자바스크립트 요청을 거부합니다. 정확히 말해서 Uncaught TypeError 에러를 발생시킵니다(크롬 기준).이 속성은 Window Opener Demo 페이지를 통해 테스트해볼 수 있습니다. 크롬은 버전 49, 파이어폭스 52부터 지원합니다. 파이어폭스 52가 2017년 3월에 릴리즈 된 것을 감안하면 이 속성 만으로 안심하긴 힘들겠네요. 자세한 지원 여부는 Link types를 참고하세요.따라서, 이러한 공격이 우려스러운 서비스라면 blankshield 등의 라이브러리를 사용해야 합니다:blankshield(document.querySelectorAll('a[target=_blank]')); 참고로, noopener 속성은 이 외에도 성능 상의 이점도 있습니다. _blank 속성으로 열린 탭(페이지)는 언제든지 opener를 참조할 수 있습니다. 그래서 부모 탭과 같은 스레드에서 페이지가 동작합니다. 이때 새 탭의 페이지가 리소스를 많이 사용한다면 덩달아 부모 탭도 함께 느려집니다. noopener 속성을 사용해 열린 탭은 부모를 호출할 일이 없죠. 따라서 같은 스레드일 필요가 없으며 새로운 페이지가 느리다고 부모 탭까지 느려질 일도 없습니다.성능 상의 이점에 대한 자세한 내용은 The performance benefits of rel=noopener을 참고하세요.참고자료Tabnabbing: A New Type of Phishing AttackTarget=”_blank” - the most underestimated vulnerability ever링크에 rel=noopener를 부여해 Tabnabbing을 대비(일어)The performance benefits of rel=noopener
조회수 1191

안드로이드 클라이언트 Reflection 극복기

비트윈 팀은 비트윈 안드로이드 클라이언트(이하 안드로이드 클라이언트)를 가볍고 반응성 좋은 애플리케이션으로 만들기 위해 노력하고 있습니다. 이 글에서는 간결하고 유지보수하기 쉬운 코드를 작성하기 위해 Reflection을 사용했었고 그로 인해 성능 이슈가 발생했던 것을 소개합니다. 또한 그 과정에서 발생한 Reflection 성능저하를 해결하기 위해 시도했던 여러 방법을 공유하도록 하겠습니다.다양한 형태의 데이터¶Java를 이용해 서비스를 개발하는 경우 POJO로 서비스에 필요한 다양한 모델 클래스들을 만들어 사용하곤 합니다. 안드로이드 클라이언트 역시 모델을 클래스 정의해 사용하고 있습니다. 하지만 서비스 내에서 데이터는 정의된 클래스 이외에도 다양한 형태로 존재합니다. 안드로이드 클라이언트에서 하나의 데이터는 아래와 같은 형태로 존재합니다.JSON: 비트윈 서비스에서 HTTP API는 JSON 형태로 요청과 응답을 주고 받고 있습니다.Thrift: TCP를 이용한 채팅 API는 Thrift를 이용하여 프로토콜을 정의해 서버와 통신을 합니다.ContentValues: 안드로이드에서는 Database 에 데이터를 저장할 때, 해당 정보는 ContentValues 형태로 변환돼야 합니다.Cursor: Database에 저장된 정보는 Cursor 형태로 접근가능 합니다.POJO: 변수와 Getter/Setter로 구성된 클래스 입니다. 비지니스 로직에서 사용됩니다.코드 전반에서 다양한 형태의 데이터가 주는 혼란을 줄이기 위해 항상 POJO로 변환한 뒤 코드를 작성하기로 했습니다.다양한 데이터를 어떻게 상호 변환할 것 인가?¶JSON 같은 경우는 Parsing 후 Object로 변환해 주는 라이브러리(Gson, Jackson JSON)가 존재하지만 다른 형태(Thrift, Cursor..)들은 만족스러운 라이브러리가 존재하지 않았습니다. 그렇다고 모든 형태에 대해 변환하는 코드를 직접 작성하면 필요한 경우 아래와 같은 코드를 매번 작성해줘야 합니다. 이와 같이 작성하는 경우 Cursor에서 원하는 데이터를 일일이 가져와야 합니다.@Overridepublic void bindView(View view, Context context, Cursor cursor) { final ViewHolder holder = getViewHolder(view); final String author = cursor.getString("author"); final String content = cursor.getString("content"); final Long timeMills = cursor.getLong("time"); final ReadStatus readStatus = ReadStatus.fromValue(cursor.getString("readStatus")); final CAttachment attachment = JSONUtils.parseAttachment(cursor.getLong("createdTime")); holder.authorTextView.setText(author); holder.contentTextView.setText(content); holder.readStatusView.setReadStatus(readStatus); ...}하지만 각 형태의 필드명(Key)이 서로 같도록 맞춰주면 각각의 Getter와 Setter를 호출해 형태를 변환해주는 Utility Class를 제작할 수 있습니다.@Overridepublic void bindView(View view, Context context, Cursor cursor) { final ViewHolder holder = getViewHolder(view); Message message = ReflectionUtils.fromCursor(cursor, Message.class); holder.authorTextView.setText(message.getAuthor()); holder.contentTextView.setText(message.getContent()); holder.readStatusView.setReadStatus(message.getReadStatus()); ...}이런 식으로 코드를 작성하면 이해하기 쉽고, 모델이 변경되는 경우에도 유지보수가 비교적 편하다는 장점이 있습니다. 따라서 필요한 데이터를 POJO로 작성하고 다양한 형태의 데이터를 POJO로 변환하기로 했습니다. 서버로부터 받은 JSON 혹은 Thrift객체는 자동으로 POJO로 변환되고 POJO는 다시 ContentValues 형태로 DB에 저장됩니다. DB에 있는 데이터를 화면에 보여줄때는 Cursor로부터 데이터를 가져와서 POJO로 변환 후 적절한 가공을 하여 View에 보여주게 됩니다.POJO 형태로 여러 데이터 변환필요Reflection 사용과 성능저하¶처음에는 Reflection을 이용해 여러 데이터를 POJO로 만들거나 POJO를 다른 형태로 변환하도록 구현했습니다. 대상 Class의 newInstance/getMethod/invoke 함수를 이용해 객체 인스턴스를 생성하고 Getter/Setter를 호출하여 값을 세팅하거나 가져오도록 했습니다. 앞서 설명한 ReflectionUtils.fromCursor(cursor, Message.class)를 예를 들면 아래와 같습니다.public T fromCursor(Cursor cursor, Class clazz) { T instance = (T) clazz.newInstance(); for (int i=0; i final String columnName = cursor.getColumnName(i); final Class<?> type = clazz.getField(columnName).getType(); final Object value = getValueFromCursor(cursor, type); final Class<?>[] parameterType = { type }; final Object[] parameter = { value }; Method m = clazz.getMethod(toSetterName(columnName), parameterType); m.invoke(instance, value); } return instance;}Reflection을 이용하면 동적으로 Class의 정보(필드, 메서드)를 조회하고 호출할 수 있기 때문에 코드를 손쉽게 작성할 수 있습니다. 하지만 Reflection은 튜토리얼 문서에서 설명된 것처럼 성능저하 문제가 있습니다. 한두 번의 Relfection 호출로 인한 성능저하는 무시할 수 있다고 해도, 필드가 많거나 필드로 Collection을 가진 클래스의 경우에는 수십 번이 넘는 Reflection이 호출될 수 있습니다. 실제로 이 때문에 안드로이드 클라이언트에서 종종 반응성이 떨어지는 경우가 발생했습니다. 특히 CursorAdapter에서 Cursor를 POJO로 변환하는 코드 때문에 ListView에서의 스크롤이 버벅이기도 했습니다.Bytecode 생성¶Reflection 성능저하를 해결하려고 처음으로 선택한 방식은 Bytecode 생성입니다. Google Guice 등의 다양한 자바 프로젝트에서도 Bytecode를 생성하는 방식으로 성능 문제를 해결합니다. 다만 안드로이드의 Dalvik VM의 경우 일반적인 JVM의 Bytecode와는 스펙이 다릅니다. 이 때문에 기존의 자바 프로젝트에서 Bytecode 생성에 사용되는 CGLib 같은 라이브러리 대신 Dexmaker를 이용하여야 했습니다.CGLib¶CGLib는 Bytecode를 직접 생성하는 대신 FastClass, FastMethod 등 펀리한 클래스를 이용할 수 있습니다. FastClass나 FastMethod를 이용하면 내부적으로 알맞게 Bytecode를 만들거나 이미 생성된 Bytecode를 이용해 비교적 빠른 속도로 객체를 만들거나 함수를 호출 할 수 있습니다.public T create() { return (T) fastClazz.newInstance();} public Object get(Object target) { result = fastMethod.invoke(target, (Object[]) null);} public void set(Object target, Object value) { Object[] params = { value }; fastMethod.invoke(target, params);}Dexmaker¶하지만 Dexmaker는 Bytecode 생성 자체에 초점이 맞춰진 라이브러리라서 FastClass나 FastMethod 같은 편리한 클래스가 존재하지 않습니다. 결국, 다음과 같이 Bytecode 생성하는 코드를 직접 한땀 한땀 작성해야 합니다.public DexMethod generateClasses(Class<?> clazz, String clazzName){ dexMaker.declare(declaringType, ..., Modifier.PUBLIC, TypeId.OBJECT, ...); TypeId<?> targetClassTypeId = TypeId.get(clazz); MethodId invokeId = declaringType.getMethod(TypeId.OBJECT, "invoke", TypeId.OBJECT, TypeId.OBJECT); Code code = dexMaker.declare(invokeId, Modifier.PUBLIC); if (isGetter == true) { Local<Object> insertedInstance = code.getParameter(0, TypeId.OBJECT); Local instance = code.newLocal(targetClassTypeId); Local returnValue = code.newLocal(TypeId.get(method.getReturnType())); Local value = code.newLocal(TypeId.OBJECT); code.cast(instance, insertedInstance); MethodId executeId = ... code.invokeVirtual(executeId, returnValue, instance); code.cast(value, returnValue); code.returnValue(value); } else { ... } // constructor Code constructor = dexMaker.declare(declaringType.getConstructor(), Modifier.PUBLIC); Local<?> thisRef = constructor.getThis(declaringType); constructor.invokeDirect(TypeId.OBJECT.getConstructor(), null, thisRef); constructor.returnVoid();}Dexmaker를 이용한 방식을 구현하여 동작까지 확인했으나, 다음과 같은 이유로 실제 적용은 하지 못했습니다.Bytecode를 메모리에 저장하는 경우, 프로세스가 종료된 이후 실행 시 Bytecode를 다시 생성해 애플리케이션의 처음 실행성능이 떨어진다.Bytecode를 스토리지에 저장하는 경우, 원본 클래스가 변경됐는지를 매번 검사하거나 업데이트마다 해당 스토리지를 지워야 한다.더 좋은 방법이 생각났다.Annotation Processor¶최종적으로 저희가 선택한 방식은 컴파일 시점에 형태변환 코드를 자동으로 생성하는 것입니다. Reflection으로 접근하지 않아 속도도 빠르고, Java코드가 미리 작성돼 관리하기도 편하기 때문입니다. POJO 클래스에 알맞은 Annotation을 달아두고, APT를 이용해 Annotation이 달린 모델 클래스에 대해 형태변환 코드를 자동으로 생성했습니다.형태 변환이 필요한 클래스에 Annotation(@GenerateAccessor)을 표시합니다.@GenerateAccessorpublic class Message { private Integer id; private String content; public Integer getId() { return id; } ...}javac에서 APT 사용 옵션과 Processor를 지정합니다. 그러면 Annotation이 표시된 클래스에 대해 Processor의 작업이 수행됩니다. Processor에서 코드를 생성할 때에는 StringBuilder 등으로 실제 코드를 일일이 작성하는 것이 아니라 Velocity라는 template 라이브러리를 이용합니다. Processor는 아래와 같은 소스코드를 생성합니다.public class Message$$Accessor implements Accessor { public kr.co.vcnc.binding.performance.Message create() { return new kr.co.vcnc.binding.performance.Message(); } public Object get(Object target, String fieldName) throws IllegalArgumentException { kr.co.vcnc.binding.performance.Message source = (kr.co.vcnc.binding.performance.Message) target; switch(fieldName.hashCode()) { case 3355: { return source.getId(); } case -1724546052: { return source.getContent(); } ... default: throw new IllegalArgumentException(...); } } public void set(Object target, String fieldName, Object value) throws IllegalArgumentException { kr.co.vcnc.binding.performance.Message source = (kr.co.vcnc.binding.performance.Message) target; switch(fieldName.hashCode()) { case 3355: { source.setId( (java.lang.Integer) value); return; } case -1724546052: { source.setContent( (java.lang.String) value); return; } ... default: throw new IllegalArgumentException(...); } }}여기서 저희가 정의한 Accessor는 객체를 만들거나 특정 필드의 값을 가져오거나 세팅하는 인터페이스로, 객체의 형태를 변환할 때 이용됩니다. get,set 메서드는 필드 이름의 hashCode 값을 이용해 해당하는 getter,setter를 호출합니다. hashCode를 이용해 switch-case문을 사용한 이유는 Map을 이용하는 것보다 성능상 이득이 있기 때문입니다. 단순 메모리 접근이 Java에서 제공하는 HashMap과 같은 자료구조 사용보다 훨씬 빠릅니다. APT를 이용해 변환코드를 자동으로 생성하면 여러 장점이 있습니다.Reflection을 사용하지 않고 Method를 직접 수행해서 빠르다.Bytecode 생성과 달리 애플리케이션 처음 실행될 때 코드 생성이 필요 없고 만들어진 코드가 APK에 포함된다.Compile 시점에 코드가 생성돼서 Model 변화가 바로 반영된다.APT를 이용한 Code생성으로 Reflection 속도저하를 해결할 수 있습니다. 이 방식은 애플리케이션 반응성이 중요하고 상대적으로 Reflection 속도저하가 큰 안드로이드 라이브러리에서 최근 많이 사용하고 있습니다. (AndroidAnnotations, ButterKnife, Dagger)성능 비교¶다음은 Reflection, Dexmaker, Code Generating(APT)를 이용해 JSONObject를 Object로 변환하는 작업을 50번 수행한 결과입니다.성능 비교 결과이처럼 최신 OS 버전일수록 Reflection의 성능저하가 다른 방법에 비해 상대적으로 더 큽니다. 반대로 Dexmaker의 생성 속도는 빨라져 APT 방식과의 성능격차는 점점 작아집니다. 하지만 역시 APT를 통한 Code 생성이 모든 환경에서 가장 좋은 성능을 보입니다.마치며¶서비스 모델을 반복적으로 정의하지 않으면서 변환하는 방법을 알아봤습니다. 그 과정에서 Reflection 의 속도저하, Dexmaker 의 단점도 설명해 드렸고 결국 APT가 좋은 해결책이라고 판단했습니다. 저희는 이 글에서 설명해 드린 방식을 추상화해 Binding이라는 라이브러리를 만들어 사용하고 있습니다. Binding은 POJO를 다양한 JSON, Cursor, ContentValues등 다양한 형태로 변환해주는 라이브러리입니다. 뛰어난 확장성으로 다양한 형태의 데이터로 변경하는 플러그인을 만들어서 사용할 수 있습니다.Message message = Bindings.for(Message.class).bind().from(AndroidSources.cursor(cursor));Message message = Bindings.for(Message.class).bind().from(JSONSources.jsonString(jsonString));String jsonString = Bindings.for(Message.class).bind(message).to(JSONTargets.jsonString());위와 같이 Java상에 존재할 수 있는 다양한 타입의 객체에 대해 일종의 데이터 Binding 기능을 수행합니다. Binding 라이브러리도 기회가 되면 소개해드리겠습니다. 윗글에서 궁금하신 점이 있으시거나 잘못된 부분이 있으면 답글을 달아주시기 바랍니다. 감사합니다.저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 1863

파이썬의 개발 “환경”(env) 도구들

안녕하세요. 스포카 프로그래머 홍민희입니다.파이썬 패키징 생태계에서 개발 환경을 구성하기 위해 널리 쓰이는 virtualenv나 pyvenv, virtualenvwrapper 같은 각종 도구가 왜 필요한지 (또는 자신에게는 큰 도움이 안 되는지) 알려면 그 이전의 파이썬 라이브러리 배포 방식에 대한 이해가 많은 도움이 됩니다. 여기서는 필요한 몇 가지 역사적 사실과 파이썬 패키징 개념 중 현재의 생태계 이해에 필요한 것들을 위주로 정리하고, 최종적으로 각자의 필요에 따라 어떤 도구를 활용하면 될지 지침을 제안합니다.sys.path패키징이고 뭐고 아무것도 없던 90년대 말에는 라이브러리 소스 코드 파일들을 타르볼(tarball)로 압축해서 배포했습니다. 쓰는 사람은 그걸 자신의 애플리케이션 소스 트리 안에 풀어서 사용했습니다.파이썬에는 지금도 sys.path라는 인터프리터 전역적인 상태가 존재합니다. PATH 환경 변수가 실행 바이너리를 찾을 디렉터리 경로들의 목록인 것과 비슷하게, sys.path도 import foo를 하면 foo.py (또는 foo/__init__.py) 파일을 찾을 디렉터리 경로들의 목록을 담습니다. 그리고 기본 동작으로 그 목록의 맨 처음에는 현재 디렉터리(./)가 들어갑니다. 따라서 라이브러리 타르볼을 애플리케이션 소스 트리에 풀어두면 import해서 쓸 수 있습니다.하지만 자신이 작성한 애플리케이션 코드와 남이 작성한 라이브러리 코드를 같은 소스 트리에서 관리하는 것은 여러모로 불편합니다. 따라서 라이브러리는 애플리케이션 소스 트리와는 별도의 디렉터리(예: ../libs/)에 풀어서 관리하고, 애플리케이션 소스 코드 맨 위에 아래와 같이 써두는 패턴이 많았습니다.import sys sys.path.append('../libs') 또는 sys.path를 소스 코드를 건드리지 않고 조작하기 위해 PYTHONPATH 환경 변수를 활용하는 경우가 많았습니다.세기말, 파이썬 1.5를 쓰던 때의 이야기입니다.site-packages새 천 년이 밝았고 파이썬 2.0이 나왔습니다. 표준적인 라이브러리 배포 방식 및 설치 방식이 제안되었고, 표준 라이브러리에 distutils도 들어왔습니다. (지금도 setuptools는 distutils에 의존하고, pip는 setuptools에 의존합니다.) 제안된 방식은 이랬습니다.애플리케이션 코드가 아닌 라이브러리 소스 코드는 모두 /usr/local/lib/pythonX.Y/site-packages/ 디렉터리 안에 둡니다. X.Y는 파이썬 인터프리터 버전이고, 경로는 인터프리터를 빌드할 때 (./configure) 정합니다. 데비안 계열은 site-packages 대신 dist-packages라는 이름으로 바꿔서 빌드하는 등, 파이썬 인터프리터의 설치 방식에 따라 달라집니다. 어떻게 정하든 이를 site-packages 디렉터리라고 부릅니다. 파이썬 인터프리터를 빌드할 때 경로가 결정되므로, 파이썬 인터프리터 별로 각자의 site-packages 디렉터리를 갖게 됩니다. (한 시스템에서 여러 파이썬 버전을 설치했을 때 pip 역시 pip2.7, pip3.6 등과 같이 버전 별로 명령어가 생기는 것도 같은 이유입니다.)기본적으로 sys.path 목록에는 맨 앞에 현재 위치(./), 뒤쪽에는 site-packages 경로가 들어있습니다. import를 하면 현재 위치에서 찾고, 없으면 site-packages를 찾아본다는 뜻입니다.표준 라이브러리의 distutils.core.setup() 함수는 라이브러리 파일들을 시스템의 site-packages 디렉터리에 복사해주는 함수입니다. 라이브러리 타르볼 파일 맨 바깥에는 이 함수를 이용해 라이브러리를 시스템 site-packages에 설치해주는 스크립트를 setup.py라는 파일명으로 포함하는 관례가 있었습니다. pip 같은 게 없던 때에는 라이브러리 타르볼을 받아서 푼 다음 python setup.py install 명령을 실행하는 것이 일반적인 라이브러리 설치법이었습니다. 지금도 pip는 *.whl 파일이 아닌 *.tar.gz/*.zip 파일인 패키지를 설치할 때 내부적으로 python setup.py install 스크립트를 실행합니다.참고로 이때 정립된 파이썬 패키징 표준은 리눅스에서 쓰이는 dpkg나 RPM 같은 일반적인 패키징 방식을 의식하며 만들어졌습니다.1 당시는 도커는 커녕 가상화 자체가 보편적이지 않던 때로, 한 시스템에 여러 애플리케이션을 함께 설치해서 쓰는 멀티테넌시 환경이 일반적이었기 때문입니다.workingenv파이썬으로 작성한 애플리케이션 여럿이 한 시스템에 설치되면 공통으로 의존하는 라이브러리의 버전을 결정하는 게 문제가 됩니다. A 애플리케이션은 foo >= 1.0.0, < 2>에 의존하고 B 애플리케이션은 foo >= 1.5.0에 의존하면 시스템에 설치할 수 있는 foo의 버전은 >= 1.5.0, < 2>으로 한정됩니다. 만약 C 애플리케이션을 설치하려는데 foo > 2.0.0에 의존한다면, A나 C 중 하나는 포기해야 합니다.시스템에 파이썬 애플리케이션을 단 하나만 설치한다 해도, 설치하는데 시스템 관리자 권한이 필요하다는 것도 문제였습니다. 일반적으로 site-packages 디렉터리는 시스템 관리자만 수정할 수 있고 나머지는 읽기만 가능한 /usr 아래 어딘가로 정해졌기 때문입니다. 이를 우회하려고 사용자가 시스템에 설치된 파이썬 인터프리터를 쓰지 않고 직접 파이썬 인터프리터를 빌드해서 사용하는 편법도 쓰였습니다.이런 문제를 해결하기 위해, 애플리케이션·프로젝트마다 별도의 site-packages 디렉터리를 두는 방식이 제안됐습니다. 나중에 virtualenv을 만들게 되는 이안 비킹이 그 전신인 workingenv를 만들어 이 아이디어를 실현했습니다. 현재의 virtualenv 사용 방식은 workingenv에서 만들어진 것입니다.애플리케이션마다 별도의 “환경”(env)을 만듭니다.애플리케이션을 실행하기 전에 우선 그 “환경”을 “활성화”(. bin/activate 또는 Scripts\activate.bat)합니다.workingenv가 만들어주는 활성화 스크립트는 PATH와 PYTHONPATH 환경 변수를 재정의하여 시스템에 설치된 파이썬 인터프리터의 실행 바이너리 디렉터리 및 site-packages 디렉터리를 가리키는 대신, “환경” 내의 bin/ 및 site-packages 디렉터리를 바라보도록 해줍니다. 이안 비킹은 이렇게 분리된 실행 파일들(bin/)과 site-packages 등을 묶어서 “환경”이라고 명명했는데, workingenv 이후로 파이썬 패키징 및 배포 분야에서 이 용어가 정착됩니다.최근에 만들어진 신생 언어의 패키지 관리자는 대부분 파이썬과 달리 애플리케이션·프로젝트마다 별도의 환경을 두고 설치되는 경우가 많습니다. 예를 들어 npm은 -g 옵션을 일부러 켜지 않는 한 현재 디렉터리를 기준으로 ./node_modules 디렉터리에 라이브러리를 설치하게 되어 있고, 별도의 “활성화” 없이도 노드 인터프리터가 해당 경로에서 라이브러리를 찾습니다. 하지만 파이썬의 패키징 표준은 앞서 언급한 것처럼 멀티테넌시 환경이 일반적이었던 시대에 만들어졌고, 또 많은 라이브러리가 실행 파일도 함께 제공하기 때문에2 PYTHONPATH 뿐만 아니라 PATH 환경 변수도 재정의해야 해서 activate 과정이 필요합니다.workingenv는 파이썬 웹 프로그래머 사이에서 빠르게 퍼지기 시작했습니다. 웹 애플리케이션은 정통적인 CLI 및 GUI 애플리케이션과 달리 FHS 표준 같은 것에 크게 구애될 필요가 없었고, 웹 애플리케이션의 배포도 점차 가상화 기술을 통해 완전히 격리된 시스템에 설치되는 식으로 보안 문제에서 많이 자유로워졌기 때문입니다.무엇보다 workingenv는 프로그래머가 여러 프로젝트를 동시에 작업하는 경우 골치 아팠던 라이브러리 버전 충돌 문제를 우회했기 때문에, 배포 도구보다는 개발 도구로 정착되는 면이 컸습니다.virtualenv이안 비킹은 PYTHONPATH를 조작하여 별도의 site-packages 공간을 두는 workingenv의 방식이 복잡하게 패키징된 기존 라이브러리 및 프로젝트에서 호환되지 않는 문제로 골머리를 썩이다, 아예 PYTHONPATH를 이용하지 않는 방식으로 새 도구를 만듭니다.새로운 방식은 아예 파이썬 인터프리터 실행 바이너리를 복사한 뒤, sys.path 기본값에 박힌 시스템 site-packages 경로를 환경 내 site-packages 경로로 바꿔버리는 것이었습니다. 이러한 동작 원리의 차이는 이용자 입장에서 크게 중요한 것은 아닙니다.하여튼 이안 비킹은 virtualenv라는 이름으로 새 도구를 만들었고, workingenv를 빠르게 대체했습니다.virtualenvwrapper앞서 언급한 것처럼, workingenv와 그 후계자인 virtualenv는 저자의 의도와 무관하게 애플리케이션 배포보다는 개발 용도로 더 널리 쓰입니다. 파이썬 프로그래머가 새로운 프로젝트를 시작할 때는 항상 “환경”도 생성합니다. 또 개발을 시작할 때마다 “활성화” 과정도 거칩니다. 너무나 반복적이기 때문에 당연히 이를 자동화하는 도구도 만들어졌습니다. virtualenvwrapper는 바로 그런 목적으로 만들어진 bash/zsh/fish 스크립트 모음입니다.여러 단축 명령을 제공하지만, 핵심 기능은 다음의 두 가지입니다.A라는 프로젝트 작업을 시작할 때마다 cd ~/projects/a; . .venv/bin/activate라고 쳐줘야 했던 것을 workon a 명령으로 줄여줍니다.프로젝트 디렉터리마다 .venv/ 또는 .env/ 등의 이름으로 환경 디렉터리를 생성해두고 버전 관리 시스템에서는 제외되도록 .gitignore 목록에 해당 디렉터리를 넣었어야 했습니다. 예를 들어 ~/projects/a/.venv/, ~/projects/b/.venv/ 같은 식이었습니다.virtualenvwrapper를 쓰면 환경 디렉터리들을 일정한 위치로 모아줍니다. 위치는 기본값이 없으며 virtualenvwrapper 설치할 때 WORKON_HOME 환경 변수를 통해 입맛대로 정할 수 있습니다. 예를 들어 WORKON_HOME을 ~/.virtualenvs/ 디렉터리로 정했다면, 프로젝트별 환경은 ~/.virtualenvs/a/, ~/.virtualenvs/b/ 같은 식으로 저장됩니다.pyvenv파이썬 3.3부터는 virtualenv가 아예 파이썬에 내장됐습니다. 환경을 만드는 명령어는 virtualenv가 아닌 pyvenv로 좀 다르지만, 그 이후의 과정은 같습니다. 파이썬 3만 사용한다면 이제 virtualenv를 따로 설치할 필요가 없어진 것입니다.참고로 아래에서 설명할 pyenv와는 다른 도구입니다. 철자의 “v”에 주의해주세요.pyenv애플리케이션을 개발할 때는 하나의 파이썬 버전을 정하면 되지만, 라이브러리는 여러 파이썬 버전과 호환되어야 합니다. 그러다 보니 라이브러리 개발자는 여러 버전의 파이썬을 시스템에 동시에 설치할 필요가 있습니다. 데드스네이크스 PPA나 데드스네이크스 홈브루 탭 같은 것을 이용해서 설치할 수도 있지만, 보통은 pyenv를 많이 씁니다.pyenv는 동시에 여러 버전의 파이썬을 시스템에 설치해주며, 이렇게 설치된 파이썬은 시스템의 패키지 시스템(데비안·우분투의 APT나 맥OS의 홈브루 등)을 통해 설치되는 것이 아니라, pyenv가 다운로드와 빌드 및 설치를 직접 하여 별도로 관리합니다. 설치된 파이썬들은 PEP 394에 따라 일정한 형식으로 이름지어진 명령어(예: python2.7, python3.6)로 실행할 수 있게 됩니다.또한, 여러 파이썬 버전 중에 하나의 시스템 기본 파이썬 버전도 선택 가능하며, 특정 프로젝트 디렉터리 안에서만 기본 파이썬의 버전이 달라지게 할 수도 있습니다.pyenv-virtualenvpyenv가 여러 파이썬 버전을 동시에 설치해주기는 하지만, 그렇다고 자동으로 site-packages가 프로젝트마다 격리되는 것은 아닙니다. 예를 들어 pyenv로 파이썬 3.6을 설치한 뒤, 파이썬 3.6으로 두 프로젝트를 한 시스템에서 개발할 경우 두 프로젝트는 시스템 site-packages를 함께 쓰게 됩니다.따라서 pyenv를 쓰더라도 virtualenv는 따로 써야 하는데, 따로 사용할 수도 있지만 pyenv-virtualenv를 쓰면 pyenv virtualenv 명령으로 프로젝트에 쓸 파이썬 버전 지정과 가상 환경 생성을 한 번에 할 수 있게 됩니다.비슷하게 pyenv와 virtualenvwrapper를 통합해주는 pyenv-virtualenvwrapper 같은 도구도 있습니다.마치며여러 파이썬 개발 환경 관리 도구를 소개했지만, 여기 있는 모든 도구를 꼭 써야 하는 것도 아니고, 가장 최근에 나온 도구로 하루빨리 갈아타야 하는 것도 아닙니다. 글을 쓴 저 자신도 pyenv 같은 도구가 나온 지 몇 년이나 지났고 주변에서 쓰는 사람이 많음에도 쓰지 않고 있습니다. virtualenvwrapper를 대체하는 Pipenv 같은 실험적인 방식3도 생겨나고 있지만, 어느 쪽이든 동시에 여러 파이썬 프로젝트를 작업하는 사람이 아니라면 굳이 쓸 필요가 없는 도구입니다. 각자의 용도에 따라 필요한 수준의 도구를 이용하면 됩니다. 2017년 10월 현재, 아래의 지침으로 정리할 수 있겠습니다.파이썬 프로그래머가 아니지만, 파이썬 애플리케이션을 설치해서 이용합니다.시스템에서 제공하는 패키지 관리자(APT나 홈브루 등)를 통해 애플리케이션을 설치하세요.파이썬 프로그래머가 아니지만, 파이썬 애플리케이션을 유난히 많이 이용합니다.pipsi를 이용해 파이썬 애플리케이션을 설치하는 것을 권합니다.파이썬 프로그래머이고, 하나의 애플리케이션을 개발합니다.파이썬 3.3 이상을 이용할 경우 pyvenv로 개발 환경을 만들어서 개발하세요. 그 이전의 파이썬 버전을 이용할 경우 virtualenv를 활용하세요.파이썬 프로그래머이고, 여러 애플리케이션을 개발합니다.virtualenvwrapper를 활용하세요.파이썬 프로그래머이고, 여러 애플리케이션을 다양한 파이썬 버전으로 개발합니다.pyenv-virtualenvwrapper를 활용하세요.파이썬 프로그래머이고, 라이브러리를 개발합니다.pyenv와 tox를 활용하세요.파이썬으로 만든 애플리케이션을 distutils를 통해 패키징한 뒤, RPM 기반의 리눅스 배포본 용으로 python setup.py bdist_rpm 명령을 통해 *.rpm 파일을 제공하기도 했습니다. 이를 통해 애플리케이션을 설치할 경우, 각 파일들은 리눅스 FHS 표준과 해당 시스템 설정에 따라 흩어지게 됩니다. ↩예를 들어 파이썬에서 가장 많이 쓰이는 국제화 라이브러리인 바벨은 pybabel 명령어를, 구문 강조 라이브러리인 파이그먼츠는 pygmentize 명령어를, 장고는 django-admin 명령어를 제공합니다. ↩저는 2017년 4월에 한 번 써보았으나, 아직은 실무에서 쓰기에는 이르다는 결론을 내렸습니다. 이에 관한 그때의 제 감상은 별도의 글로 다루었습니다. ↩#스포카 #파이썬 #개발팀 #개발자 #인사이트 #후기 #일지
조회수 1179

OLTP에 대하여

Overview우리는 대부분의 활동을 스마트폰 하나로 해결할 수 있습니다. 은행에 가지 않아도 앱만 있으면 은행 업무를 할 수 있고, 몇 번의 터치만으로 다양한 물건을 구매할 수 있습니다. 모든 것을 온라인에서 해결합니다. 이 말을 바꿔 말하면, ‘온라인에 연결되지 않았다는 건 대부분의 경제활동에서 벗어났다’는 의미이기도 합니다. 우리가 온라인에서 무언가를 클릭(또는 터치)한다는 건 서버에 호출하는 행위이기도 합니다. 서버가 실시간으로 원하는 결과를 우리에게 다시 보내주는 것이죠. 이렇듯 많은 사람들에게 실시간으로 서버가 자료를 처리하는 과정을 OLPT(Online transaction processing)라고 합니다. Table의 구조OLTP 처리를 하려면 DB를 어떻게 설계해야 할까요. 예를 들어봅시다. 모든 웹사이트는 서비스를 이용하려면 우선 회원가입을 해야 합니다. 가입을 할 때는 ID 와 비밀번호를 꼭 만들어야 하고요. 이것을 DB Table로 가정하면 회원 Table은 ID와 암호 컬럼으로 구성될 겁니다. 회원ID암호위의 Table은 가입자 수가 많아지면 운영을 하고 건수가 많아지면 두 가지 문제가 발생합니다. 첫 번째는 ID가 중복된다는 것, 그리고 두 번째는 자료가 많아질수록 가입된 회원의 ID를 가져오는 게 느려진다는 것이죠. 전자의 문제는 Application 단에서 어느 정도 확인할 수는 있지만 다중 사용자 구조에서 중복되지 않는다는 보장을 할 수 없습니다. 후자의 문제는 Table만으로는 해결되지 않습니다. 이를 해결하려면 Index(Primary Key)를 생성해 해결할 수 있습니다. Index 생성으로 문제를 해결할 수 있다는 게 생소할지도 모릅니다. 우선 Index의 기본적인 구조를 알아야 합니다. 보통 Table에 자료를 Insert하면 입력한 순서대로 자료가 쌓입니다. 회원입력순서ID암호1홍길동12342강감찬56783이순신abcd4김좌진efgh하지만 Oracle Cluster Table과 MySQL InnoDB Table은 Table에는 입력한 순서대로 쌓이지 않고, 특정 KEY에 따라 쌓입니다. 그러므로 모든 테이블이 꼭 위의 예시처럼 순서대로 쌓이진 않습니다. Oracle Cluster Table과 MySQL InnoDB Table은 아래 예시처럼 보여집니다.회원입력순서ID암호2강감찬56784김좌진efgh3이순신abcd1홍길동1234이번에는 Index에서 가장 많이 사용하는 BTree Index를 살펴보겠습니다. Index는 보통 테이블의 자료를 빠르게 검색하기 위해 생성합니다. 1개의 Table 위에 N개의 Index를 생성할 수 있습니다.1) 회원 테이블의 ID를 KEY로 하는 Index를 생성한다고 가정하면 아래와 같은 Index 구조를 가집니다.회원_ID_IndexID(KEY)Table 위치 값강감찬XXX김좌진XXX이순신XXX홍길동XXXIndex는 KEY의 순서(오름차순 or 내림자순)로 정렬되어 있습니다. 그러므로 N개의 KEY를 지정해 Inedx를 생성하면 N개의 KEY 순서대로 정렬됩니다. 그렇다면 BTree Index는 왜 정렬되어 있을까요? 자료를 찾는 속도가 빠른 것과는 어떤 관계가 있을까요?자료 구조를 조금이라도 공부했다면 이미 BTree라는 이름에서 눈치채셨을 겁니다. Btree Index는 이진검색(Binary Search)에 기반을 두고 있습니다. Binary Search는 자료가 정렬되어 있는 상태에서 자료의 절반 위치를 찾아가는 구조입니다. (처음 전체의 절반, 절반의 절반 , 그 절반의 절반) 전체를 읽을 때보다 빠르게 원하는 값을 찾을 수 있고, 자료를 읽어내는 속도도 빨라집니다. 이렇게 해서 Index가 생성되어 있다면 Index에서 값을 빠르게 찾을 수 있고, 이 값이 위치한 Table의 레코드를 바로 접근해 원하는 값을 가져올 수 있게 됩니다. Index에서 원하는 값을 빠르게 찾을 수 있기 때문에 Index를 생성할 때 속성(UNIQUE or NON UNIQUE)을 설정해 중복 허용 여부를 지정할 수 있습니다. Index와 Table관계를 표시하면 아래와 같습니다.회원_ID_IndexID(KEY)Table 위치 값강감찬2김좌진4이순신3홍길동1▼회원입력순서ID암호1홍길동12342강감찬56783이순신abcd4김좌진efghPrimary Key만약 ID의 컬럼 속성을 NOT NULL로 설정하면 중복이 되지 않고 값을 항상 입력합니다. ID의 무결정을 보장하고, 자료도 빠르게 찾을 수 있게 되는데요. 방법은 크게 두 가지로 설정할 수 있습니다. 하나는 Unique Index 와 NOT NULL을 사용하는 것이고, 다른 하나는 Primary Key를 지정하는 것입니다.2) 그렇다면 우리는 어떤 것을 지정하는 것이 좋을까요? 사실 DB 특성과 Table특성, 용도에 따라 달라지기 때문에 정답은 없지만 일반적으로 Primary Key를 지정합니다. Primary Key를 지정하는 건 몇 가지 이유가 있습니다. 첫째, 논리적으로 Primary Key를 지정해 Table의 기준을 알 수 있습니다. 둘째, 거의 모든 DB가 같은 조건(Index가 여러 개 있을 경우)이라면 Primary Key를 우선적으로 사용합니다. 마지막으로, 특정 DB는 Table(MySQL InnoDB Table)이 Primary Key로 정렬되고, 이것이 위치 값으로 사용되면 다른 Index를 쓰는 것보다 속도가 빠릅니다. 그러므로 가능한 Primary Key를 사용하는 것이 좋고, 그 외의 경우엔 Index를 사용하면 됩니다. Conclusion지금까지 OLTP 처리를 할 때의 기본적인 회원 Table 구조와 문제점 및 해결 방안 , 간단한 Index 및 Primary Key를 알아봤습니다. 다음 글에서는 조금 더 확장된 개념인 단일 Table을 Select하는 법을 다뤄보겠습니다. 뭐든 기초가 중요하니까요. 하하.. 참고 1) Oracle Bitmap Index의 경우 2개 테이블을 연결하여 1개의 Index를 생성할 수도 있습니다. 2) Primary Key는 NOT NULL컬럼만 지정 가능합니다. 글한석종 부장 | R&D 데이터팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 3089

국내 스타트업 개발자들도 저녁이 있는 삶을 산다.

[대화 1]친구 A: 남편은 무슨일 해?아내: 어, IT회사 다녀.친구 A: 거기서 무슨일 하는데?아내: 개발자에요.친구 A: 아 그래? 그럼 퇴근 제때 못할텐데, 애들 키우기 힘들겠네.…[대화2]아내: 아니 그렇게(반바지) 입고 회사 가려고?필자: 음... 요즘 판교 쪽에서는 패피들은 반바지에 샌들 정도 신어줘야 인정받아..아내: 우리(금융회사)는 반바지 입는 사람은 생수 배달하는 사람 뿐인데. 갈아입고 가.금융기관에서 일하는 필자 아내와의 일상 대화 중 일부입니다. 대화는 짧지만 많은 의미가 함축되어있습니다. 우리 사회에서 금융권 직원이라 하면 말끔한 수트를 차려입고 아침부터 아메리카노 한잔 하면서 뭔가 중요한 딜을 성사시킬 것 같은 느낌이라면, IT개발자라 하면 그 금융권에서 사용하는 시스템 개발을 하위 위해 파견온 협력회사 직원과 그 회사에서 고용한, 소위 을, 병, 정 프리랜서들로 반바지에 좀 헝크러진 머리를 하고 밤늦게까지 그리고 주말에도 코딩하느라 제대로 씻지도 못하고 다니는 사람을 먼저 떠올립니다. 최근에 국내 유수의 게임 회사 한 곳에서만 세 명이 과로사하거나 업무 부담으로 회사에서 자살했다고 하니 그런 인식이 전혀 틀리지만은 않은 듯 합니다.미국에서는 개발자들이 대접은 잘 받지만 업무 난이도와 강도는 정말 높다고 합니다. 미국에서는 소프트웨어 개발자라고 하면 엄지손가락을 치켜 세우며 ‘6 digits’이냐고 물어보고들 합니다. 연봉이 $100,000 즉  1억 1,200만원 이상이냐고 묻는 것입니다. 연봉 10만 달러는 미국에서도 높은 편이지만, 소프트웨어 개발자들은 일반적으로 이를 상회합니다. 실리콘밸리에서는 개발자 대졸 초임이 10만 달러 정도 된다고 합니다.시가총액 상위 기업 대부분이 ICT 기업들이고 미국에서도 소프트웨어 개발 인력은 공급이 상당히 부족하니 그럴 수 밖에 없습니다. 공대중에서 최고라 하는 스탠포드와 MIT에서 최고 인기 전공은 단연 컴퓨터 사이언스라고 하는데, 대한민국에서는 인재들이 소프트웨어 분야를 기피하고, 이 분야가 더 열악해지는 악순환이 계속되고 있습니다. 자율주행 시스템, 암진단을 인간 의사보다 잘한다는 IBM 왓슨, 자산관리 로봇까지 가지 않더라도 뱅킹, 콜센터, 주차 정산, 음식 주문, 모바일 게임 등 우리 일상 생활을 소프트웨어 개발자들이 책임지고 있는데, 만성적인 개발 인력 부족으로 우리 ICT 산업의 경쟁력이 갈수록 떨어지지 않을까 걱정입니다.어제 오늘의 이야기도 아니고, 해결책이 과연 있는가?고무적인 것은 과거보다는 소프트웨어 개발자의 근무 환경에 더 관심을 가지고 야근 문화를 없애나가려고 노력하는 기업들이 많아지고 있다는 점입니다.핀테크 기업 핀다도 접근 방법은 다소 다르지만 이런 긍정적인 문화를 확산시키는 데 노력하고 있습니다. 그로 인해 우수한 인력이 한명이라도 더 핀다를 선택하고, 대한민국 젊은이 몇명이라도 더 공시생이 되기보다는 소프트웨어 개발자로 진로를 선택하기를 기대합니다.업무 환경이 중요하다.핀다의 개발자는 공유오피스 위워크(Wework) 을지로점 내의 사무실 및 라운지 등에서 자유롭게 근무합니다. 근무중에 사무실 내의 탁구장에서 함께 탁구를 치기도 하고 다트 게임을 하기도 합니다. 위워크 다른 층 라운지 쇼파에서 탁트인 전망을 보며 일하기도 합니다.물론 업무가 몰리고 데드라인에 쫓기면 야근을 하기도 하고 주말에 집에서 일하기도 하지만 이를 권장하기 보다는 지양하고 더 줄여나가려고 합니다. 저녁이 있는 삶을 보장하기 위해 지속적으로 노력할 것입니다.Wework 16층 회의실 겸 탁구장에서 열심히 탁구치는 우리 개발자. Le Viet Hoang‘월화수목금금금’ 일해도 일정 맞추기 어려운데 무슨 배부른 소리인가?소프트웨어 개발은 집중력을 요하는데, 사람이 하루 8시간도 집중해서 일하기는 쉽지 않습니다. 집중하지 못한 상황에서 작성한 낮은 품질의 코드로 더 많은 오류를 일으키고 이를 해결하기 위해 더 많은 시간을 일해야 하는 악순환이 발생합니다. 해당 직원의 행복지수도, 건강도, 로열티도 떨어지고 퇴사할 가능성이 높아집니다. 결국 회사는 잃는 것이 더 많아지게 됩니다. 하지만, 단지 초과 근무로 인해 생산성이 떨어지므로 이를 지양해야 한다고 하기에는 현실은 일반적으로 너무 열악하고 다급합니다. 초과 근무를 대신할 다른 혁신적인 방안이 있어야 기업의 관리자를 설득할 수 있을 것입니다.핀다 개발팀은 다릅니다. 개발 환경을 소개합니다.1. 이슈관리 시스템 Jira를 이용하여 태스크, 오류 등 모든 이슈를 관리합니다.      위키 시스템 Confluence를 통해 회사 및 프로젝트의 날리지를 관리합니다.  위키에 프로젝트별로 이와 같이 스페이스를 만들고 트리 구조로 페이지를 생성합니다.그림 상의 페이지에는 Jira에서 생성한 이슈들을 나열한 것을 볼 수 있습니다. 이런 방식으로 회사의 모든 지식은 체계적으로 정리되고 공유됩니다.2.  Git을 이용하여 소스코드 뿐 아니라 디자인 프로젝트까지 관리합니다.동시에 여러 버전의 소스를 유지하고, 여러 사람이 협업하기 위해 위와 같은 Git flow를 준수합니다.소스 변경(커밋) 시에는 그림과 같이 관련 이슈 번호를 넣어서 커밋과 이슈를 연동합니다.상용 배포 버전에는 그림과 같이 버전을 태그로 달아두고 버전별로 릴리즈 노트를 작성합니다.3. Jenkins를 이용하여 시스템 빌드 및 배포를 자동화하고 있습니다. 각 빌드에도 버전을 태그로 붙이고 있습니다.4. 객체지향 프로그래밍 방식을 철저히 준수합니다.시스템을 모듈로 나누고 각 모듈 간의 의존도는 최소화합니다. 논리적으로 관련된 코드는 한 패키지, 클래스 등에 모아서 응집도를 최대화합니다. 데이터와 데이터 처리 코드는 한 클래스에 모읍니다. 중복된 코드는 피할 수 있다면 한 줄이라도 허용하지 않고, 상속, 함수화, 오버로딩 등을 최대한 활용하여 코드 사이즈를 줄입니다.5. 이해하기 쉬운, 설명이 필요 없는 코드와 문서를 작성합니다.소프트웨어는 본질적으로 복잡합니다. 복잡한 문제를 최대한 쉽게 풀어내는 것이 소프트웨어 개발자의 능력의 핵심 중 하나입니다. 문제를 더 복잡하게 만들어서 다른 사람이 이해하기 어려워 하는 것을 본인의 능력이 뛰어나서라고 자만하거나, 주석을 달거나 문서화를 하지 않고서 다른 사람이 코드를 보고 이해하면 된다는 식의 생각은 아마추어리즘일 뿐입니다.핀다의 소프트웨어 프로젝트는 경험이 부족한 신입 개발자라도 30분 내에 구조와 흐름을 파악할 수 있도록 하고 있습니다.6.  웹, 안드로이드, 아이폰 앱은 철저히 통일된 MVC 구조로 구현합니다.모델(M) 부분은 서버로부터 데이터를 받아오는 모듈, 데이터의 세부사항을  처리하는 모듈, 데이터의 보존과 공급을 담당하는 모듈로 철저히 분리하여 구현합니다.화면의 부분을 담당하는 뷰(V)는 주어진 데이터로 화면을 그리는 것만 담당합니다.화면을 구성하기 위해서는 뷰를 배치하고 모델로부터 데이터를 받아서, 뷰에 전달해야 합니다. 이는 컨트롤러(C)가 담당하는데 컨트롤러는 철저히 컨트롤만 하고 세부적인 사항을 처리하지 않습니다.핀다의 웹, 안드로이드, 아이폰 앱은 모두 동일한 폴더, 클래스 구조를 가지도록 설계하고 있습니다. 이로 인해 다른 분야를 접해보지 못한 개발자라도 하루 내에 파악하여 코드 수정까지 할 수 있어서 누구나 쉽게 풀스택 개발자가 될 수 있습니다.종합해보면, 핀다 개발팀은 나만의 스타일로 코드를 작성할 자유가 없고, 프로그래밍 컨벤션을 따라 최적의 간결한 코드를 작성해야 합니다. 타이트한 프로세스를 따라야 합니다. 구글이나 마이크로소프트 보다 더 높은 수준의 클린 코드를 작성해야 합니다. 다소 타이트해보일 수 있지만, 유능한 핀다의 개발자들은 적극적으로 이를 준수하고 오히려 더 나은 개선 방안을 내놓고 있습니다. 결국 핀다의 개발자는 저녁이 있는 삶 뿐 아니라 신나고 발전적인 직장생활까지 누리게 될 것입니다.핀다의 미래가 밝아 보이나요? 아니면 너무 타이트해 보이나요?핀다는 핀다의 미래가 밝아 보인다고 느끼는 개발자에게 문을 활짝 열어놓고 있습니다.많은 기업이 핀다 방식 혹은 더 나은 방식을 도입하여 행복하게 일하는 개발자들이 더 많아지기를 기대해봅니다.#핀다 #개발 #개발팀 #개발자 #저녁이있는삶 #기업문화 #조직문화 #사내복지
조회수 3020

GitHub 계정으로 Kubernetes 인증하기

초기에는 kube-aws가 만들어준 관리자 인증서를 통해 Kubernetes를 관리했는데 역시나 대내외적으로 여건이 바뀌니 변화가 필요했다. 내부적으로는 개발 인력이 늘고 여러 프로젝트가 동시 진행되니 Staging 환경이 급격히 바뀌는데 계정이 하나이니 누가 무슨 작업을 했는지 확인하기 어렵고 외부적으로는 경쟁사의 보안사고 등에 영향을 받아 보안을 강화할 필요가 생겼다. 하여 보안 관련 작업을 여럿했고 그 중 하나가 바로 GitHub와 Kubernetes를 OAuth로 엮는 일이다.기본적으로는 개발자 각자가 자신의 GitHub 계정으로 인증 토큰을 받고 이를 이용해 Kubernetes API에 접근하는 것이다. 전체적인 흐름은 How I built a Kubernetes cluster so my coworkers could deploy apps faster 등을 참고하면 이해하기 그리 어렵지 않다.1. Admin time should be saved (since they are also our developers)2. New users can generate their own credentials without needing the admin3. User credential is always private for security reasons4. Developers have their own space to experiment5. Project spaces can be accessed and changed by multiple users6. In the future, we may want to enable auditing to track changes다만 저들과 달리 Webhook 토큰 인증 플러그인을 직접 짜지 않고 coreos/dex를 이용했다. Dex를 이용하면 GitHub를 비롯해 다양한 OpenID, OAuth 2.0 인증 서비스와 Kubernetes 클러스터를 엮기 쉽다. 더욱이 kube-aws에 Dex가 통합되어서 설치하기도 쉽다.설치하기구구절절 어떻게 설정하는지 설명할 생각은 없는데 회사와 프로젝트에 따라 세부적인 차이가 꽤나 클 수 있기 때문이다. 그러니 대략적인 작업 순서를 간략히 기술하고 끝내려 한다.우선 kube-aws의 cluster.yaml를 보자.# # Enable dex integration - https://github.com/coreos/dex # # Configure OpenID Connect token authenticator plugin in Kubernetes API server. # # Notice: always use "https" for the "url", otherwise the Kubernetes API server will not start correctly. # # Please set selfSignedCa to false if you plan to expose dex service using a LoadBalancer or Ingress with certificates signed by a trusted CA. # dex: # enabled: true # url: "https://dex.example.com" # clientId: "example-app" # username: "email" # groups: "groups" # selfSignedCa: true # # # Dex connectors configuration. You can add configuration for the desired connectors suported by dex or # # skip this part if you don't plan to use any of them. Here is an example of GitHub connector. # connectors: # - type: github # id: github # name: GitHub # config: # clientId: "your_client_id" # clientSecret: "your_client_secret" # redirectURI: https://dex.example.com/callback # org: your_organization # # Configure static clients and users # staticClients: # - id: 'example-app' # redirectURIs: 'https://127.0.0.1:5555/callback' # name: 'Example App' # secret: 'ZXhhbXBsZS1hcHAtc2VjcmV0' # # staticPasswords: # - email: "[email protected]" # # bcrypt hash of the string "password". You can use bcrypt-tool from CoreOS to generate the passwords. # hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" # username: "admin" # userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"우선 GitHub의 Organization Settings 메뉴로 가서 OAuth Apps에 Dex를 추가한다. 이때 Authorization calllback URL은 https://dex.example.com/callback가 된다.GitHub가 준 Client ID와 Client Secret를 cluster.yaml에 적어넣는다.dex: enabled: true url: "https://dex.example.com" clientId: "example-app" username: "email" groups: "groups" selfSignedCa: false # # # Dex connectors configuration. You can add configuration for the desired connectors suported by dex or # # skip this part if you don't plan to use any of them. Here is an example of GitHub connector. connectors: - type: github id: github name: GitHub config: clientId: "GITHUB_OAUTH_APP_CLIENT_ID" clientSecret: "GITHUB_OAUTH_APP_CLIENT_SECRET" redirectURI: https://dex.example.com/callback org: DailyHotel # # Configure static clients and users staticClients: - id: 'example-app' redirectURIs: 'https://kid.example.com/callback' name: 'Example App' secret: 'ZXhhbXBsZS1hcHAtc2VjcmV0'staticPasswords: - email: "[email protected]" # # bcrypt hash of the string "password". You can use bcrypt-tool from CoreOS to generate the passwords. hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" username: "admin" userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"여기서 dex.example.com은 kube-aws가 띄울 dex Deployment와 연결되는 서비스(ELB)의 도메인주소가 되어야 한다. 그런데 kube-aws는 Dex의 External service를 생성해주지 않으므로 아래와 같이 직접 서비스를 생성해야 한다. GitHub가 이쪽으로 콜백을 보내야 하므로 방화벽을 열어야 하고 회사 도메인 인증서를 붙일 것이므로 `selfSignedCa`값은 `false`로 한다.apiVersion: v1 kind: Service metadata: name: dex namespace: kube-system labels: app: dex component: identity dns: route53 annotations: domainName: dex.example.com service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:blahblah service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https spec: ports: # the ports that this service should serve on - name: https port: 443 targetPort: 5556 protocol: TCP selector: app: dex component: identity type: LoadBalancer loadBalancerSourceRanges: - 0.0.0.0/0staticClients / example-app는 Dex에 포함된 예제 프로그램이다. 이를 이용하면 웹 브라우저를 통해 GitHub에 인증하고 토큰을 내려받을 수 있다. DailyHotel/kid 등의 도커 이미지를 사용하면 쉽게 띄울 수 있다. kube-aws는 이 예제 프로그램을 띄우지 않기 때문에 직접 올려야 한다.apiVersion: v1 kind: Service metadata: name: kid namespace: kube-system labels: app: kid dns: route53 annotations: domainName: "kid.example.com" service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:blahblah service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https spec: ports: - name: https port: 443 targetPort: 5555 protocol: TCP selector: app: kid type: LoadBalancer loadBalancerSourceRanges: - 사무실IP/32 --- apiVersion: extensions/v1beta1 kind: Deployment metadata: name: kid namespace: kube-system spec: replicas: 1 template: metadata: labels: app: kid spec: containers: - name: kid image: dailyhotel/kid:latest livenessProbe: tcpSocket: port: 5555 timeoutSeconds: 120 ports: - containerPort: 5555 env: - name: CLIENT_ID value: example-app - name: CLIENT_SECRET value: ZXhhbXBsZS1hcHAtc2VjcmV0 - name: ISSUER value: https://dex.example.com - name: LISTEN value: http://0.0.0.0:5555 - name: REDIRECT_URI value: https://kid.example.com/callback이때 example-app의 REDIRECT_URI는 Dex의 REDIRECT_URI와는 다르다는 점에 주목하자. 옵션의 이름이 비슷하기 때문에 헷갈릴 수 있다. 또한 CLIENT_ID와 CLIENT_SECRET은 cluster.yaml 중 GitHub connector 설정이 아닌 staticClients 설정에서 쓴 값이라는 점도 눈여겨볼 필요가 있다.이 정도만 주의하면 dex를 설치하고 설정하는 것은 어렵지 않다. 이제 인증하는 방법을 알아보자.인증하기웹브라우저로 kid에 방문해서 토큰을 받는다. 첫 화면에서 Login 버튼을 누른 후 GitHub 로그인을 하면 토큰이 나온다.GitHub Public profile 메뉴로 가서 Public email 설정을 확인한다. 공개 이메일이 없다면 하나 추가한다. 로그인시 사용자 아이디로 쓰기 위함이다.kubeconfig 파일을 열고 kubeconfig 파일을 열고 MY_PUBLIC_GITHUB_EMAIL에는 GitHub 공개 이메일 주소를 적고 VISIT_KID_EXAMPLE_COM_AND_GET_TOKEN에는 앞서 받은 토큰을 적는다.apiVersion: v1 kind: Config clusters: - cluster: certificate-authority: credentials/ca.pem server: https://MY_KUBE_CLUSTER name: kube-aws-cluster contexts: - context: cluster: kube-aws-cluster namespace: default user: MY_PUBLIC_GITHUB_EMAIL name: kube-aws-context users: - name: MY_PUBLIC_GITHUB_EMAIL user: token: VISIT_KID_EXAMPLE_COM_AND_GET_TOKEN current-context: kube-aws-context인증 파일의 설정이 정확한지 확인하려면 kubectl --kubeconfig=./kubeconfig version을 실행해보자. 아래와 같이 Client/Server의 버전이 둘다 나오면 정상이다.$ kubectl --kubeconfig=./kubeconfig version Client Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.6.1", GitCommit:"b0b7a323cc5a4a2019b2e9520c21c7830b7f708e", GitTreeState:"clean", BuildDate:"2017-04-03T20:44:38Z", GoVersion:"go1.7.5", Compiler:"gc", Platform:"darwin/amd64"} Server Version: version.Info{Major:"1", Minor:"6", GitVersion:"v1.6.2+coreos.0", GitCommit:"79fee581ce4a35b7791fdd92e0fc97e02ef1d5c0", GitTreeState:"clean", BuildDate:"2017-04-19T23:13:34Z", GoVersion:"go1.7.5", Compiler:"gc", Platform:"linux/amd64"}참고 자료johnw188/dex-exampleKubernetes / Authenticating#데일리 #데일리호텔 #개발 #개발자 #개발팀 #기술스택 #도입후기 #일지 #경험공유 #Kubernetes #Github
조회수 5118

100일 간의 챗봇 디자인 실패기-1편

디자인 학도로서 4년 넘게 학교에서 UI/UX를 공부했다. 또래에 비해 학교를 오래 다녔으며 해당 분야에 대한 관심도 남달랐거니와, 심지어는 UI 디자인 소프트웨어를 만드는 회사에 다닌 경험이 있는 만큼 실무적으로는 아직 많이 부족할 지라도 이론만큼은 이제 어느 정도 자신이 있다고 생각했다.그런데 대체 이 녀석은 또 뭐지. 챗봇이라니.   지난 1월, 새로운 사업을 결심한 팀원들과 사업구상을 하며 챗봇이라는 아이템을 마주하게 되었다. 우리가 챗봇에 대한 무한 신뢰를 했던 이유는 한 가지였다. '일상적 편리함에 있어 메신저만 한 것은 없다'는 것.한때 SNS에 화제가 되었던 '엄마의 메모장'챗봇은 이미 한 차례 미국 본토를 강타하고 조금씩 국내 시장에 진입하고 있던 상황이었고, 새로운 기술에 호기심을 가진 우리 팀은 챗봇에 희망을 품고 해당 분야에 대한 학습을 진행하기 시작했다.  자연어 처리, 형태소 분석 등 기술적인 부분들을 개발팀원들이 검토하고 있는 동안 디자이너로서 챗봇에 대한 리서치를 시작하려는 찰나, 아무리 검색을 해도 평소에 비해 아무것도 나오지 않는 매우 당황스러운 시추에이션이 발생했다.  일반적인 웹이나 어플리케이션 기획의 경우 이미 레퍼런스 삼을 만한 사례가 충분히 있었고, 설령 국내 자료 중에 없다고 한들 영어로 조금만 검색해보면 해외 자료들을 금세 찾을 수 있었다. 그러나 챗봇은 상황이 달랐다. 영어권 챗봇 또한 이제 막 성장하는 단계인 만큼 해외 챗봇 사례 중에서도 이렇다 할 벤치마킹 대상을 찾는 것이 쉽지 않았다.우선 우리가 만들고자 한 챗봇은 '일정' 관련 봇이었다. '자연스러운 대화를 이해하여 사용자의 일정 입력을 돕는 챗봇이 있다면 어떨까'라는 것이 우리의 가설이었다.괜찮지 않을까?지난 4년 간 학교에서 배운 과정대로라면 브레인스토밍, AEIOU, 컨셉맵핑, 유저 인터뷰, 포커스그룹 인터뷰 등에 걸친 여러 기법들을 통해 디자인을 시작해야 했다. 하지만 현 상황은 우리가 대체 정확히 무엇을 만드는 것인지에 대한 정의조차 내려지지 않은 상태였다.이 챗봇의 기능은 무엇이며, 타겟은 누구이고, 어떻게 구현될 수 있는 걸까. 너무나 생소한 분야였던 만큼 우선 첫 한 달 동안은 챗봇 관련 국내외 글을 꾸준히 읽기 시작했다. 4차 산업혁명, 완전자동화 등 챗봇에 대한 여러 이론적인(쓸데없는) 내용들이 있었지만 그중에서도 유독 눈에 띄는 글이 하나 있었다.https://chatbotsmagazine.com/bots-hype-or-glory-656f4d614efb#.g6s68jvkgI was an undercover-bot for 2 months. Here is what I learned.Bots: hype or glory?chatbotsmagazine.com 해당 글의 주요 내용을 번역 및 요약하자면 이러하다.- UX 매니아로서, 그 수많은 챗봇 중에 쓸만한 게 없더라.- 그래서 챗봇을 개발하기 전 직접 실험을 해보기로 했다.- 약 2달간 직접 서비스 내에 사용자를 돕는 봇인'척' 했다(틈틈이 사람이라고 힌트는 줬다).- 우리 서비스를 사용하는 사용자들은 컴퓨터나 기술을 좋아하는 사람들이 아닌, 일반인이었다.- 봇이 아닌 사람이 실시간으로 응대한다고 인지는 시켜주었지만 사실 신경 쓰는 사람은 없었다.본문은 '아직 챗봇은 기술적으로도, 시대적으로도 준비가 되지 않았다'로 최종 결론을 지으며 마무리되는데, 이미 챗봇에 콩깍지가 씌여 있던 나에게는 그저 앞부분의 내용이 중요할 뿐이었다."사람이 챗봇인 척 테스트를 한다고?"서비스 기획 및 디자인에 갈피를 못 잡고 있었던 우리 팀은 긴말할 것 없이 곧바로 실행에 들어갔다. 대학교 게시판에 피실험자 알바 구인 글을 올리고 약 30명의 캘린더 유저를 확보했다. 실험에 대한 대략적인 안내사항은 이러했다.1. 우리는 현재 일정 관련 챗봇을 만들기 위해 수동으로 실험 중이며, 주 기능은 '일정등록' 이다.2. 구글 또는 네이버 캘린더 작성 권한을 사용자로부터 공유받아 일정을 입력한다(캘린더 공유 기능 활용).3. 사용자는 최소 주 1회 이상 카톡을 통해 캘린더에 일정을 입력하여야 한다(페이 지급 조건).4. 사용자는 챗봇에게 일정 등록뿐만이 아닌 일정 관련 어떠한 요청도 할 수 있다.5. 이에 대한 예시로 문자/메일 분석, 공개 캘린더 추가, 키워드 일정 추천 등을 제시한다.6. 대화의 형태는 정해져 있지 않으며 원하는 어떠한 형태(말투, 축약어, 신조어)로든 가능하다.응대에 사용한 옐로아이디 관리자 툴지금은 플러스친구로 업데이트된 카카오톡 옐로아이디 관리자 툴을 활용하여 사용자들과 대화(채팅)를 진행했다. 데스크탑용 웹 인터페이스를 통해 대화를 입력할 수 있었기에 입력 속도는 빨랐지만 사용자가 언제 무슨 말을 걸어올지 도저히 예측이 불가능했다. 팀 내 개발자들이 자연어 처리에 대한 공부를 지속하는 동안 운영을 맡은 팀원과 함께 2명이서 상시 대기하며 사용자들의 요청에 응대했다.운영 초기 우리가 기대했던 이상적인 요청들은 이러했다.하지만 현실은 아래와 같았다.목적어 및 각각의 형태소가 매우 명료하고 명확한, 챗봇 개발 시 자동화가 가능한 텍스트들을 기대하고 있었지만 실상 대부분의 요청은 실제 사람이 개입하지 않는 이상 과연 처리가 가능할까 싶은 내용들이 태반이었다.텍스트 입력 시간도 사용자마다 다 제각각이었다. 아침 일과를 시작할 때 일정을 입력하는 사용자들이 있는 반면 하루를 정리하며 다음날 일정을 계획하는 사용자들도 있었다. 밥을 먹다가도, 샤워를 하다가도 옐로아이디 알람이 울리면 컴퓨터로 달려가 응답을 했다. 아무리 상시 대기를 한다 해도 잠은 자야 했기에 결국 자정부터 다음날 아침 8시까지는 옐로 아이디의 자동 응답기능을 활용하여 '잠시만 기다려주세요'를 출력하였다.(물론 잠시는 아니었지만)여러 시행착오를 거쳐 약 한 달 간의 기나긴 응대 끝에 실험이 종료되었고, 우리는 사용자들을 대상으로 설문 및 인터뷰를 진행하였다.우선 가장 중요하게 생각한 전체 캘린더 일정 입력률(데스크탑/모바일 캘린더를 포함한 모든 입력) 대비 카톡을 통한 일정 입력률은 약 절반 정도로 확인되었다.카톡을 통한 일정 입력률 / 전체 일정 입력률  = 51%이와 더불어 '카톡을 통해 캘린더에 일정을 등록하는 방식에 대해 불편한 점'을 질문한 결과1. 즉각적이지 않은, 늦은 응답 - 40%2. 개인 일정 정보 유출에 대한 불안 - 20%3. 익숙하지 않은 카톡 입력의 불편함 - 13.3%순으로 응답함을 확인하였다.생각보다 나쁘지 않은 결과였다.비록 입력 된 내용들을 정형화 하기가 쉽지는 않았지만, 기대했던 것에 비해 카톡을 통한 입력률이 높은 편이었고 가장 큰 문제점으로 지적된 '늦은 응답'과 '개인 정보 유출'은 챗봇 개발을 통해 개선할 수 있을 것으로 기대했다. 자동화를 통해 즉각적으로 응답할 수 있을뿐더러 사람의 개입을 없애 개인 일정 정보 유출을 방지할 수 있을 것이라는 판단 하에 챗봇 개발을 진행하였다.그렇게 한달 간 입력받은 텍스트 데이터를 활용, 약 2주 간의 개발 끝에 간단한 일정 등록 기능을 갖춘 일정 관리 챗봇, 린더봇이 탄생하게 되었다.https://www.youtube.com/watch?v=zSRYRYfzTFo2편에서 계속...#히든트랙 #챗봇 #기술기업 #개발자 #개발팀 #인사이트 #경험공유
조회수 2948

개발자 직군 파헤치기 2 | 게임 개발자

게임 개발자국내 게임 산업에서 모바일 게임의 매출액은 2011년 4235억원에서 2013년 2조3276억원으로 2년 만에 6배 가까이로 늘어났습니다.(출처:한국콘텐츠진흥원) 한국 모바일 게임은 해외에서도 인기를 끌고 있는 추세입니다. 뿐만 아니라 최근 엄청난 인기를 끌고있는 배틀그라운드는 한국 게임 산업의 가능성을 증명합니다. 배틀그라운드는 작년 한 해 7621억원의 수익을 거두면서 2017년 가장 큰 수익을 거둔 PC 게임 패키지 1위를 차지했습니다.배틀그라운드의 일러스트게임을 좋아하는 사람이라면 한번쯤은 게임 개발에 관심을 가져보았을 것입니다. 특히 프로그래밍을 하는 사람이라면 자신의 게임을 만들어보고 싶다는 생각을 해보거나, 게임 회사에서 일 하는 것을 고려해보았을 것입니다. 그러나 한편으로는 압도적인 근무 시간에 대한 부담으로 게임 개발자가 되겠다는 생각을 접게 되신 분들도 많습니다.이번 포스팅은 게임 개발자에게 필요한 역량이 무엇인지 알아보고, 게임 개발자의 두 가지 커리어 종류에 대해 설명하려고 합니다. 또한 지금 당장, 코딩을 전혀 할 줄 모르는 상태에서 게임 개발에 도전해볼 수 있는 방법 또한 소개해드리겠습니다.게임 개발자에게 필요한 역량게임을 만들기 위해서는 그래픽을 다루는 능력, 스토리와 레벨을 기획하는 능력, 3D 모델링, 그래픽 엔진을 다루는 능력 등 많은 영역들에서 전문성을 필요로 합니다. 물론 이 모든 것을 전문적으로 다루는 사람이 되기란 불가능에 가깝습니다. 그렇기 때문에 스토리라인과 컨셉 구성은 기획자가 담당하고, 기획자의 아이디어는 개발자와 그래픽 디자이너의 손을 거쳐 게임의 모습을 갖춥니다. 그래픽 디자이너가 시각적 구현을 맡는다면, 개발자는 PC나 모바일에서 게임이 실행될 수 있도록 만드는 작업을 하게되는 것입니다. 게임 개발자도 결국 개발자 직군의 일환이기 때문에 일반적으로 개발자들이 많이 다루는 언어에 대한 숙련도나 프로그래밍 능력이 필요합니다. 그러나 게임 개발자의 경우 다른 직군의 개발자에게는 필수적이지 않은 지식을 필요로 할 때가 있습니다. 아래에는 특히 게임 개발자들에게 중요한 세 가지 요소입니다. 1. 프로그래밍 언어대부분의 대규모 게임 회사들은 C++을 가장 많이 사용합니다. 모바일 게임이 대세로 더오르면서 C#을사용하는 경우가 많아진 것은 사실입니다. 그러나 PC, 모바일, 비행기 제어 프로그램까지 폭넓게 지원하는 고성능의 3D 게임을 개발하기 위해서는 여전히 C++이 최적이라는 평가를 받습니다. 주의할 점은 C/C++은 계속해서 발전하고 있는 언어라는 점입니다. 언어를 배우기 위한 서적, 인터넷 강의 등은 무궁무진하지만 중요한 것은 최신의 것을 배워야 한다는 점입니다.2. 게임 엔진게임 엔진은 간단하게 말해 게임을 개발하는 과정을 쉽게 만드는 ‘도구’입니다. 중력 같은 기본적인 물리 효과나 오브젝트 사이의 충돌 여부를 판정하는 ‘컬라이더’ 등, 개발에 필요한 기본적인 기능이 탑재되어있기 때문에 게임 엔진은 개발 과정을 획기적으로 단축시켜줍니다. 가장 많이 쓰이는 게임 엔진은 유니티와 언리얼입니다.이 글을 읽고 있을 대부분의 분들이 개발을 배우는 과정에 있다는 가정하에 학습의 용이함을 기준으로 비교해보면, 유니티의 경우 공식적으로 지원하는 교육 프로젝트의 수는 9개입니다. 그러나 공식적인 자료 외에도 한글 서적이나 온라인 강좌들은 매우 풍부합니다. 반면에 언리얼이 제공하는 공식 교육 프로젝트는 수십개입니다. 대부분이 한글 자막을 지원해줄 뿐만 아니라 다양한 주제를 경험할 수 있습니다. 언리얼의 한계라면 공식 채널 외에서 학습할 수 있는 자료나 커뮤니티가 아직까지는 많지 않다는 점입니다. 3. 수학게임 개발자에게 수학은 매우 중요하고도 기본적인 것입니다. 특히 3D 게임을 다루고 싶다면 수학적 지식과 역량은 매우 중요한 부분을 차지할 것입니다. 물론 위에서 말한 게임 엔진이 수학적인 계산이나 물리와 관련된 문제들을 해결해 줄 수는 있습니다. 그러나 게임 엔진을 활용한다 하더라도 기본적으로 그것이 어떻게 작동하는지는 이해해야 합니다. 그렇기 때문에 이산 수학, 즉 벡터, 행렬, 집합, 논리 연산 등에는 능숙할 필요가 있습니다. 게임 개발자의 커리어게임 개발자가 되기 위한 길이 게임 회사에 취직하는 것만 있는 것은 아닙니다. 최근에는 크게 성공하는 인디 게임, 즉 대규모 회사가 아닌 저예산의 1인기업 혹은 작은 팀단위로 만들어 내는 게임들의 사례가 늘어나고 있습니다. 게임 회사에 취직하는 것만큼 확실한 방법이 없다는 생각을 갖고 계신 분들, 혹은 자신만의 게임을 만드는 것에 강한 매력을 느끼시는 분들을 위해 두 가지 커리어 옵션을 비교해 보았습니다.1. 대규모 게임 회사대부분의 게임 개발자가 특정 회사에 소속되어 일을 합니다. 회사에 소속되어 있기에 안정적인 수입이 보장된다는 것이 첫번째 장점이라면, 두번째 장점은 혼자서는 절대 만들 수 없는 규모의 게임을 개발하는 데에 기여할 수 있다는 점입니다. 한 마디로 말해 완성도 있고 유명한 게임에 일조 했다는 자부심을 가질 수 있게 되는 것입니다. 또한 주니어 개발자로서 풍부한 경험을 가진 시니어 개발자를 포함해 배울 점이 많은 사람들로 구성된 팀에 소속될 수 있다는 것 또한 큰 장점입니다.한편 회사의 크기가 큰 경우에는 각 사람이 맡는 개발의 영역이 매우 세분화 되어있기 마련입니다. 자신이 느끼기에는 조금 지루하고 단순한 일이라고 생각되는 일을 맡게 될 수도 있습니다. 그러나 반대로 말하면 디자인, 기획, 마케팅 등 개발 외의 업무 등에 신경을 쓰지 않고 오직 자신의 일에 집중할 수 있는 환경이 제공되는 것이기도 합니다.2. 인디게임 개발규모가 있는 회사에 취직하는 것이 아니더라도 게임을 만들 수 있는 방법은 많습니다. 또한 안정적인 수입이 보장된 것은 아니지만, 성공하는 경우 생각는 것보다 그 수익이 큽니다. 예를 들어 트리오브라이프를 개발한 오드윈게임즈는 1년 간 20억의 매출에 도달했습니다. 단지 한 사람이 2주 동안 만든 게임, 숨바꼭질은 한 달만에 5000만원의 수익을 냈습니다. 물론, 이를 성공 신화에 불과하다고 말할 수도 있기 때문에 분명히 감수해야 하는 위험이 있는 커리어인 것이 사실입니다. 인디 게임 간에도 경쟁이 매우 치열하기 때문입니다.그럼에도 불구하고 소규모로, 혹은 혼자서 게임을 개발하는 사람들은 게임에 대한 애착을 가지고 개발 과정 전체를 아우르며 작업할 수 있다는 점에서 만족감을 느낍니다. 특히 투자 규모나 시기에 구애를 받지 않고 개성적인 게임, 만들고 싶은 게임을 만들 수 있다는 것이 장점이라고 할 수 있습니다. 지금 시작하기게임 개발을 하고 싶은데 어디서 시작해야 하는지를 막막해하고 있다면, 무조건 일단 만들어보기 시작하는 것이 중요합니다. 자신의 아이디어, 혹은 이미 있는 게임들을 가지고 점점 난이도를 높여가며 여러 프로젝트를 실행해 보는 것이 좋습니다. 이는 실력을 쌓는 데에도 도움이 되지만, 이후에 훌륭한 포트폴리오가 되기도 합니다.일단 만들어보라는 조언도 막막하신 분들을 위해 준비한 것은 무료로 사용할 수 있는 게임 개발 프로그램들입니다. 코딩을 전혀 할 줄 모르는 사람부터 완성도 있는 게임을 만들고 싶어하는 사람들까지 다양한 수준에서 접근할 수 있는 도구들을 소개해드리겠습니다.1.Flow CreatorFlow Creator는 코딩을 해본 적이 없어도 간단한 드래그앤드롭으로 게임을 만들 수 있는 웹사이트입니다. 시각적으로 논리적 구조를 짤 수 있기 때문에 어떤 언어도 배워본 적이 없어도 됩니다. 무료 버전의 경우 5개의 레벨, 50개의 개체로 제한이 되어있지만 유료 버전의 경우 앱으로 만들어 스토어에 올릴 수도 있습니다.2. StencylStencyl도 Flow Creator와 마찬가지로 프로그래밍 언어가 아니라 Stencyl의 사용법만 잘 익히면 훌륭한 게임을 만들 수 있습니다. 사용법이 Flow Creator에 비해 좀더 까다로운 것은 사실이지만 결과물의 완성도가 더 높습니다. 또한 이미 만들어져있는 코드블록 외에도 직접 코드를 작성하고 라이브러리를 불러오는 등 확장할 수 있는 가능성도 있습니다.3. Game Maker StudioGame Maker는 위의 두 가지 프로그램처럼 드랙 앤 드롭으로 만들 수 있지만, Game Maker Language(GML)이라는 자체 언어를 활용하여 만들 수도 있습니다. GML을 사용해서 게임을 만드는 것은 프로그래밍을 학습하는 데에도 도움이 될 것입니다.게임 개발자의 종류는 정말 많다.오늘 포스팅에서 언급한 게임 개발자는 일부입니다. 게임 개발자의 종류에는 온라인 게임, 모바일 게임, 콘솔 게임 등 정말 다양하고 무궁무진합니다. 여러분들이 어떤 게임 개발자가 되고 싶든 중요한 것은 게임에 대한 열정인 것 같습니다. 자신이 정말 하고 싶고 좋아하는 게임을 만든다는 것은 세상에 의미있는 프로그램을 만드는 개발자만큼이나 행복한 개발자겠지요. 다음 편에는 더 재밌는 개발자 직군으로 찾아오겠습니다.
조회수 2272

당신이 고민해야 할 성능 분석 요소

IT 서비스는 더욱 복잡해지고 어플리케이션과 인프라의 경계도 클라우드 환경과 함께 허물어지고 있습니다. 많은 기업들이 가상화를 넘어 컨테이너로 가고 있으며 서버리스도 더이상 낮설지 않습니다. 인프라의 변화와 함께 아키텍처의 변화도 다양하게 만들어져 가고 있습니다. 복잡성이 아무리 높아져도 우리는 서비스의 성능을 보장해야 합니다. 서비스의 성능을 보장하기 위해 우리가 체크해야 할 중요 요소들을 알아보려고 합니다. 1. 인프라스트럭처와 클라우드서비스의 성능은 코드 밖에서도 만들어집니다. 그중에서도 인프라스트럭처는 매우 중요한 요소입니다. 국내에서 인프라스트럭쳐 분야는 클라우드로 전환하는 과도기적인 상황에 있습니다. SMB 시장에서 클라우드는 익숙한 환경이지만 국내 엔터프라이즈 기업의 클라우드 도입 비율은 20%가 되지 않습니다. 특히 클라우드를 도입하려는 엔터프라이즈 기업들은 데이터 센터, 퍼블릭 클라우드, 프라이빗 클라우드를 모두 사용하는 상황으로 넘어가면서 클라우드에 대한 모니터링 체계를 구성하는데 많은 어려움을 겪고 있습니다. 특히 기존의 자원 사용량을 설계하고 운영하던 방식에서 스케일의 변화를 통해 서비스의 성능을 실시간으로 조절하는 클라우드 서비스 운영 방법은 조직의 구조 변화를 동반하기 때문에 더욱 어려운 작업이기도 합니다. 이렇듯 클라우드의 전환은 최근 웹 서비스의 성능에 많은 영향을 미치고 있으며 데이터독이나 뉴렐릭 그리고 와탭 같은 성능 분석 서비스들은 클라우드 기반의 인프라 모니터링 기능들을 강화하고 있습니다. 2. 데이터베이스어플리케이션 성능 이슈의 80% 이상이 데이터베이스 레이어에서 발생합니다. 대부분의 엔터프라이즈 기업들은 자사의 어플리케이션을 성능 분석을 위해 DBA 포지션을 마련하거나 필요에 의해 컨설팅을 받고 있지만 아쉽게도 스타트업은 DBA포지션을 마련하는 경우가 거의 없습니다. 웹 서비스의 규모가 커지기 시작하면 데이터베이스로 인한 지연 장애가 매우 심각해 지기 시작합니다. 레거시로 인한 이슈까지 추가되면 서비스의 성능은 지속적으로 낮아지게 되므로 데이터베이스는 꾸준히 관리해야 하는 요소입니다.데이터베이스의 비중이 높다보니 어플리케이션 분석 서비스 중에서도 데이터베이스만 집중적으로 분석하는 도구들이 있습니다. 국내에서는 엑셈과 티맥스에서 데이터베이스 분석 솔루션을 제공하고 있습니다.  3. 오픈 소스와 써드파티 소프트웨어최근 두가지 형태의 트렌드가 서비스 성능에 영향을 주고 있습니다. 하나는 오픈 소스이고 다른 하나는 써드 파티 소프트웨어 입니다. 안정화 된 오픈 소스를 사용하더라도 설정 이슈 또는 사용 환경 이슈로 성능에 영향을 주는 상황이 많이 발생합니다. 위젯, 광고플랫폼, 플러그인등의 써드파티 또한 웹 서비스의 성능에 영향을 주는 요소입니다. 최근 써드 파티의 사용은 점점 늘어나는 추세로 인해 장애 발생에 대한 위험도는 더욱 높아가고 있습니다. 특히 써드 파티는 시간이 흐르면서 성능에 조금씩 부하를 누적시키기도 하므로 충분히 주의를 기울여야 합니다. 이런 환경에서도 서비스의 성능을 유지하기 위한 방법으로 통계 기반의 메소드 분석 기법 모니터링의 중요한 요소가 되어 가고 있습니다. 와탭의 Java 모니터링이 메소드 분석 서비스를 제공하고 있습니다. 4. 모바일구글 이 운영하는 더블클릭(https://www.doubleclickbygoogle.com/articles/mobile-speed-matters/)에 따르면 북미에서 3G에서의 모바일 페이지 로딩까지 소요되는 시간은 평균 19초입니다. 한국은 이미 4G를 넘어가고 있기도 하고 모바일 기기의 성능도 매우 높아서 북미와 상황이 다르지만 모바일 기반의 웹 서비스 성능을 분석할 수 있는 방안의 필요성은 높아져 가고 있습니다. 이와 함께 다양한 환경을 지원하는 end-to-end 모니터링의 중요성이 점점 대두되고 있는 상황입니다.  5. 컨테이너최근 인프라스트럭처의 새로운 흐름은 컨테이너 입니다. 한국은 리눅스 기반의 서비스 구축 시스템이 잘 발달한 덕분에 클라우드 도입이 다른 나라보다 늦은 편입니다. 하지만 최근 국내에 컨테이너 기반의 인프라스트럭처 도입 기업들이 많아지고 있습니다. 우리나라는 가상화를 건너뛰고 컨테이너부터 활성화 될수도 있을 거라 생각됩니다. 컨테이너 환경은 가상화보다 더 많은 인프라를 더 유동적으로 사용하게 되므로 기존의 규모를 뛰어 넘는 관리 체계를 만들어 나가야 합니다. 데이터독과 뉴렐릭 같은 SaaS 기반의 모니터링 서비스들은 이미 컨테이너의 대한 지원을 하고 있으며 와탭 또한 단순 지원을 넘어 컨테이너 전용 서비스를 준비중에 있습니다. 6. 마이크로 서비스많은 기업들이 클라우드와 함께 Micro Service Arichtecture를 도입하고 있기 때문에 독립적인 어플리케이션을 기반으로 하는 서비스 구조는 계속 발전해 나갈 것입니다. 마이크로 서비스와 클라우드의 조합은 커져가는 서비스의 규모를 독립적인 작은 단위로 나눌 수 있어서 매력적이긴 하지만 과거와 다른 운영 조직과 프로세스를 만들어야 하는 숙제를 만들었습니다. 예를 들면 기존에는 하나의 임계치를 사용하여 서비스의 위험도를 관리했다면 이젠 독립적으로 동작하는 서비스들의 임계치를 각각 어떻게 설정하고 관리할 것인지 고민해야 합니다. 독립된 마이크로 서비스의 성능 이슈가 전체 서비스 성능 이슈로 확대되지 않더라도 작게 발생하는 이슈들을 관리하지 못한다면 지속적으로 발전해야 하는 서비스의 미래도 흔들리게 될 것입니다. 7. 서버사이드 코드정상적인 상황이라면 서버사이드 코드에서 발생되는 지연시간은 찰나에 가깝지만 장애 상황에서의 지연은 서버사이드에서 발생하는 경우가 많습니다. 특히 방어가 되어 있지 않은 코드들은 물리적 요소의 작은 변화에 대처하지 못하고 웹 서비스 전체에 영향을 미치게 됩니다. 스타트업의 경우 개발팀이 운영을 함께 맡고 있는 경우가 많기 때문에 서버사이드의 코드를 직접 분석하곤 합니다. 하지만 서비스의 성능이 느려지는 상황 자체를 파악하지 못하는 경우가 많습니다. 서버 사이드에서 평균 응답시간을 체크하는 경우 10초 평균 응답시간이 0.5초를 넘는 경우는 거의 없습니다. 하지만 0.5초의 평균 응답시간을 같는 서비스라 할지라도 하루 동안 10초이상 걸린 고객의 숫자는 규모에 따라 1,000명이 넘을 수도 있습니다. 서비스에 규모가 있다면 꼭 APM을 사용해야 합니다.8. 네트워크 지연네트워크의 지연으로 인한 고객 불만은 예상외로 많이 발생합니다. 인프라스트럭처 이슈로 볼 수도 있겠지만 서비스를 운영한다면 항상 체크하고 있어야 하는 요소입니다. 해당 이슈를 확인 하려면 웹서비스 모니터링을 사용하시면 됩니다. 웹서비스 모니터링을 통해 네트웍상태를 포함한 서비스의 응답시간을 체크해 볼수 있습니다. 와탭의 경우 내부적으로 웹서비스 모니터링을 개발하여 사용하고 있지만 아직 서비스 하고 있지는 않습니다.  9. 자원 사용률자원 사용률은 최근 새로 떠오르는 이슈입니다. 이전에는 인프라스트럭쳐가 고정값이였기 때문에 자원 사용률이 모자라는 경우 서비스 성능을 포기하고 초과되는 고객의 요청을 앞단에서 버리거나 대기시키는 기법들을 사용해왔습니다. 클라우드 환경에서는 자원 사용량의 임계치가 넘어가면 자동으로 스케일을 조정하는 환경이 마련되면서 성능을 유지하는 것이 가능합니다.  클라우드 환경에서 과부하 상태에 접근하면 자동으로 인프라의 규모가 확장되고 과부하 상태는 정상으로 돌아갑니다. 이렇게 환경이 바뀌면서 자원 사용률의 중요 이슈가 성능에서 비용으로 전환되고 있습니다. 부하에 따른 스케일링 정책을 어떻게 정하는지에 따라서 성능과 비용 모두가 영향을 받기 때문에 Auto Scale에 대한 모니터닝이 관심을 받고 있습니다.  마무리웹 서비스의 성능에 영향을 주는 요소는 정말 많습니다. 와탭랩스 IT 기업의 어플리케이션을 모니터링 하기 때문에 기업의 IT 어플리케이션 성능 문제에 대해 항상 고민하고 있습니다. 해당 내용은 매달 또는 분기별로 트렌드를 반영하여 업데이트하고 할 생각입니다. 많은 분들에게 도움이 되었으면 좋겠습니다. #와탭랩스 #개발자 #개발팀 #인사이트 #경험공유 #일지

기업문화 엿볼 때, 더팀스

로그인

/