스토리 홈

인터뷰

피드

뉴스

조회수 1212

레진 기술 블로그 - Kotlin의 빛과 그림자

핀터레스트의 안드로이드 개발팀이 코틀린을 도입하면서 겪은 어려움과 해결책을 소개한 The Case Against Kotlin을 foot번역하고 자의적으로 해석하고 요약했습니다. 저자 라이언 쿡(Ryan Cooke)은 현재 코틀린이 가트너의 하이프 사이클에서 “뻥튀기된 기대감의 산(Peak of Inflated Expectations)” 쯤에 있다고 말합니다. 레진시 개발동에서는 이미 코틀린을 부분적으로 도입했고, 현재는 범위를 넓혀가는 중인데요… 정말 괜찮은 걸까요?문제: 학습 곡선자바 개발자로서 문법에 익숙해지는 데 1주일 정도 걸립니다.코틀린을 이미 잘하는 사람이 없으면 베스트 프랙티스들을 찾아보면서 해야하는 데 시간이 듭니다.코틀린 사용을 가속화 시키는 데 팀 트레이닝을 계속 해야합니다. -> 기회비용 많이 듭니다.하기 싫어 하는 사람도 있고…혼자서 알아서 잘 배우는 사람도 있고…해결책: 학습 곡선코틀린은 아직 말년병장성숙한 언어가 아닙니다! 지금도 자라나고 있습니다! 그게 제일 무서워..책도 있고 인터넷 리소스도 있지만, 코틀린 신봉자가 하나 있어서 다 가르쳐주는 게 짱입니다.필자가 코틀린을 하고 싶었던 이유는 생산성인데요, 동료들 중에는 그렇게 느꼈던 사람들이 많지 않은 것 같습니다. 정착이 되면 보이겠죠.문제: 빌드 속도Gradle 빌드 속도는 보통 30초, 클린 빌드는 75초 까지 걸립니다.코틀린은 보통 빌드 속도의 25%, 클린 빌드의 40% 밖에 안나옵니다.해결책: 빌드 속도알아서 하셈 ㅋ코틀린 파일 하나 변환 -> 클린 빌드 시 조금 시간이 더 걸립니다. 파일을 많이 변환할수록 느려지긴 하지만 체감하긴 어렵습니다.보통 빌드할 때는 코틀린 파일 많아도 상관 없습니다.결론: 클린 빌드할 때 느려진다는 걸 체감할 겁니다.문제: 개발 안정성코틀린의 문법이나 특성이 문제가 아니라, 코드를 생산성 있게 작성하는 자신을 막는 새로운 문제들 때문이라고 생각합니다.사실 그냥 코틀린 배우기 싫은 거 같아요.예를 들면, 코틀린 애노테이션 프로세서 툴(kapt) 때문에 빌드가 안 되고, 무조건 클린 빌드로만 개발을 했던 적이 있습니다.이거… 코틀린 때문 아니야?!?!?! 하는 의심들 많았죠.고치느라 시간이 많이 흘렀습니다.또 어떤 문제가 튀어나올지에 대한 두려움이 커지네요.해결책: 개발 안정성그냥 IDE 나 언어의 stable 버전만 업데이트 하세요.안정된 버전들만 사용하면 그나마 힘든 일 없을거예요.정말?문제: 정적 분석FindBugs, PMD, Error Prone, Checkstyles and LintJava 는 이와 같은 툴들로 인해 Code Review에 쓸데없는 걸 줄이거나 룰을 적용할 수 있는데,코틀린에는… 이런 게 없… 분석을 위한 게 아직… 없습니다… 사람들이 알아서 다 찾아야 합니다.해결책: 정적 분석그냥 손가락빨고 기다려야 합니다. 아니면, 직접 만드세요!문제: 나 돌아갈래~돌아가기 쉽지 않습니다. 자바를 코틀린으로 옮기기에는 쉬운데, 반대는… 어렵습니다!코드가 깨지고, 변수명부터, 이런 저런 부분들을 다시 구현해야합니다.코틀린스럽거나, 코틀린의 고유한 기능들을 사용했다면, 여기서부터 헬이죠.해결책: 나 돌아갈래~되돌아오는 건 쉽지 않기 때문에 잘 생각해야 합니다.유닛 테스트가 정말 잘 된 파일들부터 바꾸세요.간단하고 재사용 가능한 잘 모듈화된 파일들을 먼저 바꾸세요.결론이 글은 고려해야 할 리스크에 대해서 나열했습니다.단점들은 구글과 젯브레인과 스택오버플로우가 차차 해결해 줄 겁니다.TL;DR 코틀린으로 작성하는 건 쉽지만, 되돌리기는 어렵습니다.그래서 말인데… 레진코믹스에서 코틀린 삽질을 함께 할 개발자를 모십니다!
조회수 411

iOS 개발자를 구합니다!

“세상 모든 광고영상을 누구나 쉽게 만들 수 있게 한다.”영상광고는 사업의 규모와 업종을 막론하고 모든 분야에서 필수적인 요소로 자리잡고 있습니다. 잘 만든 영상광고가 매출로 이어진다는 사실은 검증되었고, 그 중요성은 나날이 증가하고 있습니다.하지만, 영상제작 전문기술 없이 광고영상을 제작한다는 것은 시간과 비용적인 측면에서 매우 어려운 일입니다. 광고영상을 SNS에 업로드 하고 싶은 마케터나 창업가들은 영상 전문가나 디자이너가 되는 것을 꿈꾸지 않습니다. 단지 자신의 서비스와 제품이 멋지게 홍보될 영상을 원하고 있습니다.더브이플래닛은 전문기술 없이도 누구나 쉽고 빠르게 광고영상을 제작할 수 있는 브이플레이트를 통해 많은 마케터들과 창업가들이 겪는 시간과 비용에 대한 어려움을 해소할 것입니다.“더브이플래닛”에서 영상광고 생태계의 흐름을 바꿀 iOS개발자를 모집합니다.광고영상을 누구나 쉽게 만들 수 있도록 함께 고민하고 시장을 주도해나갈 분을 애타게 찾고 있어요.우리는 한사람 한사람의 소중한 능력들이 맘껏 발휘될 수 있도록 존중과 배려로 서로를 응원하고 있어요. 우리와 함께 소중한 능력을 맘껏 발휘하실 분들의 많은 지원 부탁드려요.
조회수 5883

개발자 채용 시 기술검증 어떻게 할 것인가

eBrain에서 진행하는 "개발자 채용 시 기술검증 어떻게 할 것인가"라는 미니 워크숍을 다녀왔다. 항상 고민하고 있는 주제이기도 하고 개인적으로 팬심(?)을 가지고 있는 김창준님의 강의라 한시간 거리를 극복했다.  이미 창천향로님이 강의 내용을 잘 정리해 주셨다. 하지만 내 자신의 학습을 위해 강의 내용을 재해석 해서 적어 본다. 빠져든다! 1. 현재 기술력 검증의 문제점최근의 개발자 채용에 사용되는 기술력 검증 방식은 다음과 같은 것들이 있다.  온라인 코딩 테스트 (최근에 여러 가지 플랫폼도 있다)손 코딩 테스트기술 인터뷰과제 제출이 중 최근에는 주로 알고리즘에 대한 코딩 테스트가 주가 되는 것 같다. 생각보다 난이도가 있어서 재직자들이 “이런 문제면 저는 못 들어왔을 것 같아요”라고 하는 경우도 있다. 코딩 테스트에 대해 두 가지 사례를 들어 질문을 던져 본다.  삼각형 판별 문제삼각형 판별 문제는 세 좌표가 주어졌을 때 이 삼각형이 어떤 삼각형인지 (정삼각형, 이등변 삼각형, 둔각 삼각형 등)를 맞추는 것이다. 이 프로그램이 잘 동작하는지를 검증하는 것이 QA 동네의 ‘Hello World’ 문제다. 이 문제가 주어지면 초보자들은 그냥 문제를 푼다. 하지만 전문가는 문제를 풀지 않고 “이 프로그램을 누가 쓸 것인가요?”를 물어본다. 콘텍스트에 따라서 완전히 다른 테스트의 설계가 필요하기 때문이다.  코딩 테스트도 이와 비슷하다. 코딩 테스트는 단순화된 문제를 푼다. 즉 맥락이 제거된 상태에서의 문제를 푼다. 실무는 종합적인 환경에서 이뤄진다. 따라서 이 문제를 잘 푼다는 것이 실무를 잘할 수 있는 것을 의미하지 않을 수 있다.  질문) 우리의 코딩 테스트는 과연 실무에서의 실력과 높은 상관관계가 있는가?  전문성 연구개발자는 종종 전문성의 연구 대상이 되곤 한다. 이때 연구비를 이유로 주로 혼자서 빠르게 풀 수 있는 문제로 실험이 이뤄진다. 하지만 이런 식의 실험들에서 “토이 문제”가 아닌 “복잡하고 확장된 문제"를 전달했을 때 전혀 다른 결과가 도출된다는것을 알게 되었다.  복잡한 문제, 즉 실제 문제를 풀 때는 인지적 전략이 많이 바뀐다. 또한 사회적 요소도 필요하다. 이런것들을 “토이 문제”로 검증하기는 쉽지 않다. X를 테스트하면 X를 잘하는 사람을 뽑게 된다.  즉, 알고리즘 코딩 테스트를 하면 알고리즘 코딩 테스트에 능한 사람을 뽑게 된다. 질문) 실무에 최대한 가까운 상황을 제한된 면접 시간 내에 만들어 내려면 어떻게 해야 할까? 2. 개발자 채용은 어떻게 해야 할까?채용이 더 크리티컬 한 곳이 있다. 델타포스, 네이비씰과 같은 특수부대이다. 이곳에서는 사람을 어떻게 뽑을까?  작전 지역을 설정 해 두고, 보급품과 군사장비를 실제 작전 수행 환경과 같이 조성해 놓는다. 그곳에서 직접 작전을 수행하는 것을 시뮬레이션 한다.이를  교관이 직접 따라가며 기록과 채점을 한다.  개발자의 면접 시에도 최대한 실제와 비슷한 환경을 구축하는 것이 좋다. 코딩 문제처럼 맞고 틀림만 보는 것이 아니라 과정에 대한 채점이 이뤄져야 한다. 3. 효과적인 기술력 검증을 위해서는 어떻게 준비해야 하는가?1) 우리가 하는 일을 분석한다.  우리가 하는 일에 코딩만 있는 것이 아니다. 설계도 하고, 버그도 찾고, 장애 해결도 하고, 커뮤니케이션도 한다.  2) 대표 케이스들을 뽑거나 만들어 내야 한다.  예를 들어 새롭게 코드를 작성하는 것보다 기존의 기능을 파악해서 코드를 수정하는 일을 더 많이 한다면 이런 상황을 문제로 만드는 것이 좋다.  3) 대표 케이스들로 파일럿 테스트를 해본다.  우리 회사의 뛰어난 개발자 3명과 평범한 개발자 3명에게 이 문제를 풀게 해보고 이를 기준으로 채점표를 만들어야 한다. 어느 누가 평가해도 비슷하게 나오도록 해야 한다. 뛰어난 개발자의 문제 풀이 방식을 기준으로 채점 기준을 만들 수 있다. 예를 들면 다음과 채점 기준이 나올 수 있다.  질문을 5개 이상 한다.코딩하는 과정에서 반복적인 실행을 한다. 4) 면접 후에는 결과에 대한 논의가 필요하다.  특정 항목에 대해 채점 기준이 다른 경우 이에 대한 논의 과정이 필요하다. 이는 면접관의 훈련에 도움이 된다.   4. 실습실제로 면접 문제 만드는 것을 실습해 보자.1) 수강생의 제안다음과 같은 면접 문제는 어떨까요?첫날 출근을 했는데 회사 웹서비스가 죽었습니다. 어떻게 하면 좋을까요? 2) 코칭좀 더 게임스럽게 만들어 본다. 실제 토이 서버를 죽여 놓고, 쉘을 주면서 실제로 어떻게 해결 하는지 살펴본다.옆에 조언을 줄 수 있는 가상의 3년 차 팀원(NPC처럼)을 제공한다. 제한된 답변을 하도록 한다.면접자가 다음과 같은 경우면 더 높은 점수를 줄 수 있다. 실제 업무를 할 때에는 이런 상황까지 이어진다는 것을 유념하자.  문제의 원인을 밝힌 이후에 이 문제를 근본적으로 해결하기 위한 후속조치를 말한다. 개발팀 내에 이 원인과 해결에 대한 공유를 한다.  5. 질문 답변1) 필터링의 목적으로 코딩 테스트는 의미가 있나요? 간단한 문제를 던져서 못 푸는 사람을 필터링하는 것으로는 의미가 있다. 하지만 그 이상의 목적으로 사용하는 것은 조심해야 한다고 생각한다.코딩 테스트라는 과정은 특히 지원자에게 많은 비용이 드는 과정이기 때문에 조금 더 경제적인 방법들이 있다. 예를 들면 “행동 기반 인터뷰”가 있다. 과거에 있었던 행동에 대한 구체적인 질문을 던지는 것이다.또한 코딩 테스트는 지원자에게 상당히 스트레스를 주는 방법이고, 지능이 높은 사람은 오히려 스트레스에 취약하다는 연구가 있다. 따라서 코딩 테스트를 진행하더라도 스트레스를 덜 주는 방향을 고민해야 한다.  2) 블라인드 테스트(이력서를 보지 않고 면접)의 장단점? 결국 코딩 테스트에 적합한 사람을 뽑게 될 것 같다. 코딩 테스트라는 것이 훈련 과정이 필요하기 때문에 입사에 대한 갈망을 볼 수는 있겠다. 질문 시에는 실무와 관련이 깊은 질문을 하면 좋겠다. 역시나 과거의 행동에 기반한 질문이 편향이 적고 많은 정보를 얻을 수 있다. 예를 들면 “팀장이 한 달 걸릴 일을 일주일 만에 끝내라고 한 적이 있나요? 그때 어떻게 하셨나요?”와 같은 질문이다. 3) 끈기, 성실 여부를 판단할 수 있을까요? 주위에서 끈기, 성실이라는 키워드를 생각하면 떠오르는 사람이 있을 것이다. 그 사람의 구체적인 행동을 기반으로 면접 문제를 만들어내는 것이 좋다. 행동에 대한 질문을 할 때에는 과거에 대한 질문을 하는 것이 좋다. 사람은 미래에 대해서는 거짓을 이야기 하가 쉽지만 과거의 이야기를 할 때에는 과거의 상황을 조작하는 동시에 거짓말을 하기가 쉽지 않다.  4) 채용 여부는 실력에 기반하게 되는데, 결국 연봉은 연차에 따라 주게 된다. 좀 더 세밀하게 측정할 수 있는 방법이 있을까? 임시 월급을 주고, 1달 혹은 3달 뒤에 급여를 적용하는 방법이 있다. 실제 환경에서는 보다 정확하게 퍼포먼스를 측정할 수 있다.  하지만 입사할 때 연봉이 중요한 요소가 되지 않게 하는 것이 더 주요한 방법이다. 내재적 동기를 갖게 하는 것이 더 중요하다. 연봉 인상에 따른 동기는 최대 3 달이면 없어진다. 외재적 동기는 점점 내재적 동기를 감소시킨다. 그 일을 즐기지 않게 되고, 하기 싫어지고, 성과가 없어진다. 연봉 말고 다른 협상 거리를 많이 가지고 있어야 한다. 연봉이 여러 가지 조건 중 하나가 되어야 한다.  5) 현재 잘하는 사람을 기준으로 채점 기준을 만들었다면, 다른 장점이 있는 사람이 탈락되지 않을까? 만일 현재 채점기준에는 적합하지 않지만, 다른 측면에서 장점이 있는 사람이 있다면 그 측면을 반영한 채점 기준을 만들어야 한다.  채용에 대해서 틀린 선입견을 가지고 있는 경우가 많이 있다. 예를 들면 술을 잘 먹는 사람이 협력을 잘한다.라고 생각하는 것이다. 그 반례가 있는지를 생각해 보면 그런 선입견을 깨는데 도움이 된다.  6) 비개발자와 함께 면접을 할 때 합의가 힘든 경우가 있다.  회사 안에서 어떤 사람을 뽑고 싶은지 합의가 필요하다. 우리 회사에서 핵심 인재를 추린 다음에 이 사람들의 공통점을 찾아서 인재상을 만들어야 한다.  7) 전화면접 괜찮을까요? 화상면접이 더 효과적인진 않을까요? 억양이 포함되어 있는 대화는 90%의 정보를 전달할 수 있다고 본다. 그 사람의 생각을 충분히 전달받을 수 있기 때문에 화상면접이 크게 더 효과적이라고 생각하지는 않는다.  우리나라에서는 많이 하지 않지만 면접에 대한 비용이 저렴하기 때문에 전화면접이 효과적인 수단이라고 생각한다. 단, 전화면접을 하기 전에 기준이 명확해야 한다. 느낌만으로 판단을 내리는 것은 의미가 없다. 8) 사내 전문가가 없는 영역에 대한 채용을 해야 한다면? 회사 외부의 전문가 몇 분을 찾아가서 그분들의 경험을 듣는다. 그 경험들에 기반해서 면접 문제를 만든다. 도메인에 관계없는 전문성이 있는지는 검증할 수 있는 방법이 있다. 즉, 전문가의 특징이 있다. 전문가는 공부를 한다. 실력을 향상하기 위한 꾸준한 노력을 한다.전문가는 확정적이지 않고 유연하다. 9) 러닝 커브가 좋은 사람을 찾는 방법은? 소규모 회사일수록 현재는 저평가되어 있지만 성장 가능성이 있는 사람을 채용해야 한다. 사실 능력 좋은 사람이 노력도 많이 한다. 뛰어난 사람은 “의도적 수련”의 양이 많고 질이 좋다.  학습에 관련된 테스트를 할 수도 있다. 예를 들어 “새로운 언어로 작은 프로그램을 작성해 보세요. 그리고 그 과정을 타임 로그로 남겨보세요” 와 같은 문제를 보면 학습 자체에 대한 능력을 테스트할 수 있다.  10) 개발을 잘하는 친구는 리드를 안 하려고 하고, 상대적으로 부족한 친구는 리드를 하려고 합니다.  개발을 잘하는 것에 대해서 생각해 볼 필요가 있다. 보통 개발을 잘한다고 하면 코딩을 잘하는 것만 생각하지만 협력에 대한 것이 포함되어야 한다. 흔히 하는 실수가 코딩 실력만 보고 리더를 삼으려고 하는 것이다.  내가 좋아했던 상사를 생각해 보고 그 사람의 특징을 생각해 보는 것부터 시작해 보는 것이 좋겠다. 개발 트랙, 매니저 트랙으로 나눠서 이야기하는 것은 좋지 않다.   6. 후기좋은 시간이었다. 워크숍에 참여하고 나서 어떻게 실력을 검증할것인가에 대해 구체적인 방향이 잡혔다. 우리가 현재 하고 있는 것들 중에 도움이 되는것과 그렇지 않은것이 구분 되었다. 8퍼센트에 좋은 분을 모실 수 있게 하나씩 시도해 봐야겠다.#8퍼센트 #에잇퍼센트 #개발자 #워크숍 #워크샵 #채용워크숍 #채용워크샵 #후기 #참여후기
조회수 876

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

전편에서는 개발 프로세스 내에서 모니터링 단계의 문제점과 이를 해결하기 위한 방법으로 APM의 역할이 DevOps 진영에서는 매우 중요한 이슈가 되고 있다고 정리했었다. 또한 모니터링 프로세스의 세부 단계와 모니터링 기준 값 설정에 대한 내용을 다뤘는데, 이를 기반으로 제니퍼를 활용하여 모니터링하는 방법에 대해 알아보려고 한다.장애 발견 및 알림제니퍼에서 이벤트 발생 조건은 컴파일 에러나 응답 시간 초과, OOM과 같은 애플리케이션 에러 유형이나 액티브서비스 개수, 응답 시간, CPU 사용률, 힙 메모리 사용률 등 서비스나 시스템의 상태 값으로 설정될 수 있다. 그리고 이벤트 설정시 외부연동 활성화 기능을 사용할 수 있으며, SMTP(Simple Mail Transfer Protocol) 모듈을 기본으로 제공한다. 또한 고객이 직접 이벤트 모듈을 구현할 수 있도록 인터페이스와 유틸리티를 제공한다. 참고로 제니퍼를 사용하는 고객사 중에서 자체적으로 구축한 관제 시스템에 제니퍼 이벤트를 연동하여, 별도의 WAS 경고 시스템을 만든 사례도 있다.   서비스 부하량 제어 (운영)제니퍼는 PLC(Peak Load Control)라는 서비스 부하량을 제어할 수 있는 기능을 제공한다. 트랜잭션 유입 차단의 기준이 되는 최소/최대 액티브서비스 개수를 설정하고, 해당 임계치 값 초과시 사용자에게 가이드해줄 수 있는 메시지나  리다이렉트 페이지를 설정할 수 있다.   만약에 대상 애플리케이션(서버 또는 WAS)이 처리 중인 액티브서비스 개수가 설정한 임계치 값을 초과하면 들어오는 사용자 요청은 거절되며 액티브서비스 이퀄라이저 차트의 요청 효과가 반사되고, 색상 또한 붉은색 계통으로 변하게 된다.사용자의 요청(Request)이 거절되면 PLC 관리 화면에서 설정한 메시지가 보이거나 아래와 같은 화면으로 리다이렉트 되며, 모니터링 대상 애플리케이션의 액티브서비스가 임계치보다 낮아지면 원래의 화면으로 돌아올 수 있다.  장애 원인 분석 (개발)개별 트랜잭션에 대한 프로파일 데이터를 분석하기 위해서는 대상이 되는 패키지나 클래스를 알아야 하는데, 적용 범위에 따라 프로파일 데이터 크기가 매우 커질 수 있으므로 실제로 운영되는 서비스에는 큰 부담이 될 수 있다. 하지만 제니퍼의 자동 프로파일링과 스택트레이스 기능은 설정한 응답시간을 초과한 트랜잭션에만 적용되기 때문에 실제 운영 단계에서 사용하기에 적합하다. 프로파일이란 트랜잭션의 시작점이 되는 메소드의 호출 구조를 상세하게 분석하는 기능을 말하며, 스택트레이스는 앞에서 설정한 기준 값을 초과하는 순간에 호출된 메소드 구조에 대한 로그를 남기는 것을 말한다. 만약에 설정한 응답시간을 초과하여 의심이 될만한 트랜잭션을 분포도 차트에서 찾았다면, 트랜잭션 분석 화면을 통해 문제 시점의 스택트레이스 정보를 참고하거나 응답이 지연되는 프로파일 데이터를 구간 별로 검색하여 콜-트리를 통해 문제가 되는 메소드 위치를 정확히 알아낼 수 있다.소스코드가 배포되었다면 트랜잭션 분포도 차트에서 배포 시점에 세로 축이 하나 그려진다. 해당 축을 선택하면 새로 추가되거나 수정된 리소스 목록을 조회할 수 있으며, 리소스의 배포 전/후의 내용을 분석하는 코드리뷰 기능은 개발 환경에서 반영된 소스코드를 분석해야하는 번거로움을 덜어준다.배포 이후에 액티브서비스가 빠르게 처리되지 못하고, 트랜잭션 분포도 차트가 기존의 패턴과 다르게 형성이 된다면 새로 반영된 소스코드에 문제가 있을 가능성이 매우 높다.결론인류 사회에서 자신이 속해 있는 환경과 전혀 다른 이질적인 문화나 새로운 생활 양식을 접할 때 받는 충격과 공포를 문화 충격(Culture Shock)라고 하는데, 이는 IT 분야에서도 크게 다르지 않다. 사실 DevOps는 몇년 전부터 계속 주목받고 있으며, 많은 소프트웨어 개발 조직에서 시도하고 있는 개발 방법론이다. 하지만 새로운 문화에 대한 거부감으로 인해 제대로 적용되지 못하고 있는 것이 현실이다.DevOps가 추구하는 가치인 존중과 신뢰를 바탕으로 개발과 운영의 원활한 의사소통과 협업 관계 형성은 말처럼 쉽지 않다. 어떻게 보면 이상적일 수 밖에 없는 추상적인 개념이지만 본문에서 다뤘듯이 APM을 상호 간의 의사소통 도구로써 잘 활용한다면 이상이 아닌 보다 현실에 가까워질 수 있다고 필자는 확신한다. APM은 소프트웨어 제품과 서비스를 빠른 시간에 개발 및 배포하는 것을 목표로 하는 DevOps를 개발 문화로 성공적으로 정착시키는데 가장 중요한 역할을 하는 도구라고 생각한다.
조회수 1095

클라우드와 운영자의 불안함.

2018년은 정말 클라우드가 일반화되는 해가 될듯 합니다. 클라우드 이전 사업 소식이 이곳저곳에서 들리는 요즘입니다. 스타트업 생태계는 이미 클라우드로 넘어갔지만 올해에는 엔터프라이즈 기업에서 대규모 IT 기업들까지 모두 클라우드로 넘어가고 있습니다. 와탭이 클라우드 최적화를 목표로 하는 모니터링 서비스이다보니 클라우드로 전환하는 시점에 있는 많은 기업들을 만나는데요. 클라우드를 적용하려고 준비중이거나 최근 클라우드로 이전한 기업의 운영팀들은 현업에서 사용하는 과정에서 클라우드 안정성에 대한 불안을 토로하기도 합니다. IT 운영자들이 느끼는 클라우드에 대한 불안감IT 운영의 핵심은 안정화입니다. 클라우드 이전까지 IT 인프라는 변화를 관리하는 대상이 아니였습니다. IT 인프라는 운영중에 변화하지 않으며 초기 설계에서도 최대 부하를 견디기에 충분한 여지를 남겨서 구성하였습니다. 하지만 클라우드에서는 IT 인프라가 운영중에도 변화 가능한 요소가 되면서 IT 인프라 규모 산정에서 부터 커다란 변화가 발생합니다. 최대 부하가 아닌 최소 부하가 규모 산정 기준이 되다. 여지껏 IT 인프라의 구성 기준은 언제나 최대 부하를 견딜수 있도록 설계되어왔습니다. 하지만 IT 인프라를 클라우드로 시작한 스타트업들이 IT 인프라를 구성하는 방법은 기존의 규칙을 무시하기 시작합니다. IT 인프라를 규모를 최소 부하에 맞춰서 구성하는 것입니다. 단지 실시간으로 확장 가능한 서비스 구조와 Auto Scailing을 통해 규모를 맞춰갑니다.IT 인프라 평균 부하의 기준이 높아지다. 클라우드 이전까지 우리는 IT 인프라의 CPU 부하율을 평소 20% 아래로 유지해 왔습니다. 하지만 이 또한 변화가 생깁니다. 제가 만나는 많은 클라우드 기반 서비스 기업들이 CPU 부하율을 50%에서 70%까지 유지하고 있었습니다. 일반적은 운영관점에서 IT 서비스 운영에 익숙하지 않은 기업의 운영 미숙이라 생각할 수 있습니다. 하지만 클라우드에 익숙한 운영팀은 서비스 성능에 문제가 발생하지 않는 범위에서 인프라의 규모를 실시간으로 조절합니다. 기존의 상식으로는 매우 위험해 보이지만 클라우드를 정말 잘 쓰는 기업들은 성능과 안정성을 해치지 않으면서 인프라 자원의 여유를 최대한 줄이는 방법들을 내재화하고 있습니다. IT 인프라 장애를 해결하지 않는다.  모든 IT 인프라는 장애가 발생합니다. 인프라의 장애는 이벤트성으로 발생하지만 운영팀은 장애를 반복 해결해 나가는 과정에서 패턴을 인지하고 대처해 나갑니다. 클라우드에서도 장애는 어쩔수 없이 발생하지만 운영팀은 장애를 인지할 뿐 장애를 물리적으로 해결하지는 않습니다. 대신 클라우드를 사용하는 IT 운영팀은 빠르게 서비스 구성과 환경을 전환하여 서비스를 원활하게 동작시킵니다. 운영자들이 갖는 불안감이 현실이 되다.다시 운영자들의 불안감에 대해서 이야기 해보죠. IT 인프라의 규모를 줄이고 자원 사용률이 평소에서 50%를 넘기는 급박한 사용 환경에서 클라우드 인프라에 장애가 발생해도 할 수 있는 일이 없다는 것은 정말 큰 스트레스를 주는 일입니다. 물론 위에서 설명한 것처럼 클라우드 네이티브한 서비스라면 문제없이 돌아갈 수 있겠지만 기존 레거시를 운영하면서 클라우드로 전환한다면 IT 운영자 입장에서는 앞에 이슈들이 불안감이 아닌 현실이 됩니다. 넷플릭스 7년만에 클라우드 이전을 완료하다.넷플릭스가 클라우드 이전을 결정한것은 2007년이지만 이전을 완료한것은 2016년이였습니다. 이렇게 긴 시간은 투자한 이유에 대해 넷플릭스는 "기존 IDC 기반의 인프라가 가진 문제들을 클라우드로 가져가지 않기 위해서"라고 했지만 다른 한편으로는 클라우드에서 발생하는 문제들을 해결할 수 있는 시스템 구조를 만들기 위해서였습니다. 그렇기 때문에 넷플릭스에서는 클라우드 네이티브 방식을 택하여 사실상 모든 기술을 재구축하고 운영 방식을 근본적으로 바꿨다. 아키텍처 면에서 넷플릭스는 거대한 앱을 수백 개의 마이크로 서비스로 마이그레이션하고 NoSQL 데이터베이스를 사용하여 데이터 모델을 반정규화했다. 예산 승인, 중앙화된 릴리스 관리, 몇 주에 걸친 하드웨어 프로비저닝 주기를 도입해 지속적인 콘텐츠 전달이 가능해졌으며, 느슨하게 결합된 개발운영(DevOps) 환경에서 엔지니어링 팀이 셀프서비스 툴로 독립적인 결정을 내릴 수 있게 되면서 혁신이 가속화되었다. 이 과정에서 새로운 시스템을 여럿 구축해야 했으며, 새로운 기술도 배워야 했다. 넷플릭스가 클라우드 네이티브 기업으로 변신하는 데는 많은 시간과 노력이 필요했지만, 클라우드 마이그레이션을 통해 글로벌 TV 네트워크로서 지속적인 성장을 이뤄나갈 밑거름을 마련할 수 있었다.https://media.netflix.com/ko/company-blog/completing-the-netflix-cloud-migration결론기존의 레거시를 바탕으로 클라우드 마이그레이션을 진행하는 기업들은 클라우드에서 발생하는 다양한 운영 이슈들을 겪을 수 밖에 없습니다. 대부분 클라우드 이전 사업을 진행하는 데 있어서 이전 서비스 성능을 맞추는 데만 집중하다보니 이전 후 운영과정에서 발생하는 많은 문제들은 운영팀이 짊어지게 됩니다. 하지만 이 문제들은 개발팀과 운영팀이 함께 지속적으로 개선해 나가야 합니다. 최종적으로 클라우드 네이티브 구조가 완성되기 위해서는 시스템과 조직 문화 모두가 변화해야 합니다. 클라우드 마이그레이션은 엄청 고난한 일입니다. 만일 클라우드를 도입했는데, 아직 불안함이 있다면 아직 클라우드 마이그레이션이 끝나지 않은것입니다. #와탭랩스 #개발자 #개발팀 #인사이트 #경험공유 #일지
조회수 6503

Elastalert로 로그 알람 구축하기

Elasticsearch로 로그를 수집하고 추세를 분석하기는 좋지만 실시간 알람을 받으려면 X-Pack Alerting 등을 이용해야 한다. 하지만 사용자 편의성 측면에서 개선할 점이 많다. 로깅 알람 전용이 아닌 다양한 용도로 커스터마이징해서 쓸 수 있게 설계한 탓일 수도 있다. 아무튼 대안을 살펴볼 필요가 있겠다 싶어서 Yelp가 공개한 Elastalert로 알람을(도) 적용해보았다.X-Pack Alerting과 비교했을 때 Yelp/elastalert의 장점은 명확하다. 무엇보다 시나리오별로 정해놓은 패턴에 따라 알람을 작성하면 일이 쉽게 끝난다. 여덟 가지 정도의 알람 타입이 있어서 상황에 맞는 템플릿을 가져다 쿼리만 살짝 고치면 된다.“Match where there are X events in Y time” (frequency type)“Match when the rate of events increases or decreases” (spike type)“Match when there are less than X events in Y time” (flatline type)“Match when a certain field matches a blacklist/whitelist” (blacklist and whitelist type)“Match on any event matching a given filter” (any type)“Match when a field has two different values within some time” (changetype)“Match when a never before seen term appears in a field” (new_term type)“Match when the number of unique values for a field is above or below a threshold (cardinality type)예를 들어 OutOfMemoryError라는 단어가 로그에 찍혔을 때 알람을 받고 싶다면 다음과 같이 Rule 파일을 준비한다.# Alert when the rate of events exceeds a threshold # (Required) # Rule name, must be unique name: OutOfMemoryError # (Required) # Type of alert. # the frequency rule type alerts when num_events events occur with timeframe time type: frequency # (Required) # Index to search, wildcard supported index: logstash-%Y.%m.%d* use_strftime_index: true # (Required, frequency specific) # Alert when this many documents matching the query occur within a timeframe num_events: 1 # (Required, frequency specific) # num_events must occur within this amount of time to trigger an alert timeframe: hours: 1 # (Required) # A list of Elasticsearch filters used for find events # These filters are joined with AND and nested in a filtered query # For more info: http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/query-dsl.html filter: - query_string: query: "message: OutOfMemoryError OR log: OutOfMemoryError" # (Required) # The alert is use when a match is found alert: - "slack"기본 템플릿을 가져다가 filter에 들어갈 쿼리만 다시 작성하면 일이 끝난다. 파이썬으로 작성한 간단한 소프트웨어라 사용하기도 쉽고 Docker로 만들기도 쉽다. pip install elastalert 그 외에 경험한 특이사항만 정리하고 이 글을 끝내려 한다.Elasticsearch의 플러그인으로 작동하는 X-Pack과 달리 ElastAlert는 독립 실행 애플리케이션이다. Kubernetes 같은 환경에서는 독립 실행 애플리케이션이 더 관리하기 쉽다.알람을 추가/삭제할 때마다 도커 빌드를 하기 힘든 환경이라면 RESTful API를 지원하는 X-Pack이 편할 것이다. back-end / elastalert 같이 RESTful API를 지원하는 ElastAlert 환경이 있긴 하지만 도커 배포환경에서는 여러 모로 한계가 있다. 도커를 올렸다 내렸다 하더라도 설정이 날아가지 않게 하려면 고민이 많아진다. node 애플리케이션과 Python 애플리케이션 둘을 하나의 도커 이미지로 제공하다 보니 다른 문제도 많다. 이런 식의 구성을 구현해봤다면 무슨 이야기인지 알 것이다.ElastAlerts는 Index Aliases를 지원하지 않는다. 물론 오픈소스이니 소스코드를 고쳐서 Pull Request를 보내면 될 일이다.X-Pack Alerting과 달리 알람 메시지를 정형화했다. 알람의 메시지 포맷을 조금 고칠 수는 있지만 기본적으로는 주어진 그대로 써야 한다. 간단하게 쓰기에는 낫고 그렇지 않다면 소스코드까지 손을 대야 한다.ElastAlert는 중복 알람 처리 등의 정책을 지정할 수 있다. 알람을 하루에 수백통 넘게 받아보면 이 기능이 왜 중요한지 알게 된다.문서에서 언급하듯 Elasticsearch 5.x와 함께 쓰려면 다음과 같이 버전을 명시하는 편이 좋다. pip install elasticsearch>=5.0.0 && pip install elastalert==0.1.8테스트 환경은 elastalert-test-rule 명령어를 제공하는 ElastAlert쪽이 더 낫다. 검색 쿼리를 제대로 작성했는지 알람 설정은 맞는지 확인하기가 쉬웠다.더 읽기ElastAlert: Alerting At Scale With Elasticsearch, Part 1ElastAlert: Alerting At Scale With Elasticsearch, Part 2Originally published at Andromeda Rabbit.#데일리 #데일리호텔 #개발 #개발자 #개발팀 #일지 #후기 #도입후기 #Elastalert #인사이트
조회수 444

컴공생의 AI 스쿨 필기 노트 ⑦합성곱 신경망

안녕하세요! 이번 주 수업에서는 합성곱 신경망에 대해서 배웠어요. 제가 읽은 한 기사에 의하면 대장 내시경 검사에도 딥러닝을 이용하면 종양 식별 능력을 더 높일 수 있다고 해요. 딥러닝을 이용한 검사는 전문가 분석을 통한 대장 내시경 검사보다 종양을 9개 더 많이 발견했고 진단 정확도는 96%인 것으로 나타났어요. (원문 링크) 이 대장 내시경에 우리가 배운 CNN(Convolutional Neural Network), 이미지 기반 딥러닝 모델을 사용했다고 하는데요. 이 대장 내시경에 사용된 CNN에 대해 알아볼까요? (Cover image : Photo by Paul Carmona on Unsplash)CNN(Convolutional Neural Network, 합성곱 신경망) CNN(합성곱 신경망)은 Convolution(합성곱)연산을 사용하는 인공신경망의 한 종류에요. 합성곱 신경망은 주로 이미지 데이터를 다루는 문제에서 사용돼요. 쉽게 말해 합성곱 신경망은 이미지의 특징을 추출하고 잘 조합하여 문제를 해결하는데요.  예를 들어 왼쪽 이미지가 고양이인지 컴퓨터가 알아맞히기 위해서 합성곱 신경망은 고양이가 가져야 할 특징을 한 번에 파악하는 것이 아니라 부분부분 판단하여 종합적으로 결론을 내요. 합성곱 신경망은 사진에 고양이의 특징이 기묘하게 분포되어 있어도 정확하게 고양이의 특징을 찾아내는 높은 적응도를 갖고 있어요.이제 합성곱 신경망의 구조에 대해 알아볼까요?CNN의 네트워크 구조1. 합성곱 층 (Convolutional Layer)합성곱은 두 함수 중 하나를 반전하고 이동시켜가며 다른 하나의 함수와 곱한 결과를 적분해나간다는 아주 어려운 뜻을 가지고 있어요. 다음 예시를 보도록 할게요.여기에 2차원 배열 픽셀을 넣으면 X 인지 O 인지 알아내는 합성곱 신경망이 있다고 해봐요.이 합성곱 신경망은 똑바로 된 X와 O를 넣으면 X 인지 O 인지 정확하게 구분하는데,이렇게 크기가 바뀌고 회전되어 모양이 변형된 이미지를 보고도 X 인지 O 인지 정확히 구분할 수 있을까요?합성곱 신경망은 합성곱 신경을 이용하여 이미지의 특징을 매칭 시킨 결과가 같으면 같은 이미지라고 인식해요.‘X’ 이미지의 특징을 추출하면 위와 같은 매트릭스, 합성곱 필터(Convolution filter(=커널))가 나와요. (세 특징을 잘 조합하면 X 형태가 나오죠?)이제 제일 왼쪽의 합성곱 필터를 가지고서 이미지가 X 인지 알아볼게요. 합성곱 필터와 원본 이미지를 비교할 때는 곱셈을 이용해요. 합성곱 필터의 크기만큼 원본 이미지와 차례차례 곱해서 값을 채워나가요.위의 합성곱 정의에서 두 함수를 하나는 이미지, 또 하나는 필터라고 생각하면, 필터를 이동시켜가며 이미지와 곱한 결과를 적분 즉, 덧셈해 나간다는 뜻이 돼요.합성곱 필터의 크기만큼 값을 다 계산한 후, 계산한 원소를 다 더해서 합성곱 필터의 크기만큼 나눈 평균값을 또 다른 새 매트릭스에 채우게 되는데 이를 특징 맵(Feature map)이라고 불러요. 즉, 특징 맵은 기존의 이미지에 필터를 곱한 결과로 각 픽셀에 쓰여있는 값이 클수록 그 특징을 가지고 있다는 뜻이에요.이렇게 원본 이미지와 합성곱 필터의 곱한 결과로 특징 맵이 나왔어요.나머지 두 개의 합성곱 필터와 곱한 결과로 두 개의 특징 맵을 가질 수 있어요.한 개의 합성곱 층(Convolutional layer)에는 여러 개의 합성곱 필터가 있어요. 합성곱 층에서 기존의 이미지와 필터들을 합성곱한 결과, 처음 이미지는 필터 된 이미지(특징 맵)로 쌓이게 돼요.2. 풀링 층(Pooling Layer)풀링은 가로/세로 방향의 공간을 줄이는 연산으로 합성곱 층의 특징을 압축한 특징 맵을 형성해요. 풀링에는 최대 풀링(Max pooling)과 평균 풀링(Average pooling)이 있는데 이미지 인식 분야에서 주로 사용하는 것은 최대 풀링이에요. 그래서 보통 풀링이라고 하면 최대 풀링이라는 의미로 사용한다고 보시면 돼요.위의 예시는 2x2 최대 풀링을 적용한 예시에요. 아까 구한 특징 맵에서 2x2 픽셀에서 가장 큰 원소 값을 새로운 맵을 채워나가는데 이를 활성화 맵(Activation map)이라고 불러요. 최대 풀링을 사용하면 노이즈가 감소하고 속도도 빨라지며 영상의 분별력이 좋아진다고 해요. 마지막 출력 층은 최대 풀링의 모든 뉴런과 연결되어 출력값이 어떤 클래스에 해당하는지 파악되는데 사용돼요.이렇게 CNN을 이용하면 변형된 이미지라고 하더라도 원래 이미지의 특징을 가지고 있다면 정확히 구분할 수 있어요.코드로 연습해보기아래는 간단한 인공신경망 코드예요.Layer 1 - input:1x28x28 , output : 64x28x28 + Activation function - reluLayer 2 - input: 64x28x28 output:1x28x28Layer 3 - input: 1x28x28=784 output:10class MNIST_Net(nn.Module):    def __init__(self):        super(MNIST_Net, self).__init__() # nn.Module 생성자 호출         # an affine operation: y = Wx + b        layers = []        layers.append(nn.Conv2d(1,64,3,1,1))         layers.append(nn.ReLU())         layers.append(nn.Conv2d(64,1,3,1,1))         layers.append(nn.ReLU())         self.main = nn.Sequential(*layers)        self.fc = nn.Linear(28*28, 10)    def forward(self, x):        # x.view함수는 주어진 인자의 크기로 해당 데이터의 크기를 반환합니다. 즉, (Batch_size,1,28,28) --> (Batch_size,28*28)로 변환합니다.        x = self.main(x)        x = x.squeeze().view(-1, 28*28)        x = self.fc(x)  # 10 으로 10개의 Class에 대한 logit 값을 호출합니다.         return x합성곱 인공 신경망의 내용은 정말 배울 것이 많아서 수업 시간 내에 다 배우기가 조금 벅찼지만 다른 인공 신경망에 비해 재밌어서 집중할 수 있었어요. 이제 앞으로 1번의 이론수업만을 남겨두고 있어서 아쉽기도 하고 또 뿌듯하기도 해요. 앞으로 조원들과 함께 프로젝트를 진행하면서 지금까지 배운 이론을 적용해보게 되는데요. 프로젝트 주제를 정하는 것부터 벌써 쉽지가 않아요. 하지만 열심히 프로젝트를 해서 리쿠르팅 데이 때 실력을 뽐낼 수 있다면 좋겠네요!* 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 7회차 수업에 대해 수강생 최유진님이 작성하신 수업 후기입니다.
조회수 2211

[MOIN] 05. MOIN 인턴 개발자를 떠나보내며...

어느덧 9월이 됐습니다. 정말 가을이 성큼 다가오는 것 같습니다.저희 MOIN에서도 큰 변화가 있었습니다. 두 달동안 안드로이드 개발에 여름방학을 불태워 준 오소연님이 학교로 돌아가게 됐습니다. 이번에는 7-8월 가장 뜨거웠던 여름을 함께한 오소연 안드로이드 개발자에 대해 소개해드리겠습니다.무뚝뚝한 매력이 철철 넘쳤던 오소연 안드로이드 개발자- Education -한양대학교 컴퓨터공학부 학사 (재학중)▶     업무에서 어떤 부분을 담당하고 계신가요?안드로이드 네이티브 어플리케이션 개발을 담당하고 있습니다. ▶     아직 학생이시죠? 왜 컴퓨터 공학을 전공하고 싶으셨나요? 어렸을 때부터 컴퓨터로 이것저것 해보는 걸 좋아했어요. 포토샵이나 나모웹에디터, html 같은 걸로 뭘 만들어 보는 게 재밌었거든요. 그 때는 코딩에 대해 전혀 아는 게 없었어요. 그러다가 중학교 때 어떤 선생님 한 분이 C언어를 가르쳐주셨는데 재밌더라구요. 나중에 이런 걸 해보면 좋겠다고 생각했어요. 대학교 전공을 선택할 때도 컴퓨터 코딩을 전문적으로 배운 적이 없으니까 해보자라는 마음으로 온거구요.  ▶     수많은 개발 영역 중에서 안드로이드를 선택한 이유도 있나요?학교 내 학술동아리 중 안드로이드를 다루는 동아리가 있었어요. 그게 재밌어 보이더라구요. 그래서 2학년 때 안드로이드 동아리에 들어갔어요. 안드로이드 앱은 직접 만든게 결과로 보이고 만든 결과물을 제가 직접 사용해볼 수도 있어서 뿌듯하기도 하고 만족스러웠어요. 웃는게 매력적인 오소연 안드로이드 개발자 ▶     모인에 합류하게 된 계기는 무엇이었나요?학교에 방학 때 하는 현장실습 프로그램이 있었어요. 저도 한 번 지원해보려고 기업리스트를 봤죠. 저는 컴퓨터 공학 전공이니까 그 전공을 필요로 하는 기업들 리스트를 살펴봤어요. 그 중에 모인이 있었어요. 모인 기업 설명을 보니까 호기심이 생기더라구요. 솔직히 학생으로서 핀테크, 해외송금 같은 분야는 쉽게 접해볼 수 있는 분야는 아닌 거 같거든요? 해보고 싶었어요. 그래서 지원했습니다.  ▶     그렇군요. 아직 학생이신 분에게 이런 질문을 하는 건 좀 그렇지만 개발 영역 중에 자신있는 부분이 있나요?아니면 재밌다고 생각하는 부분도 좋아요.오히려 배울수록 모르는 게 더 많아지는 거 같아서 자신 있는 파트는 잘 모르겠어요. 근데 앞으로 웹이나 앱 개발 하는 일을 더 전문적으로 공부하고 싶어요. 제가 생각했을 때 저는 제가 한 작업들이 결과물로 딱 보이는 걸 좋아해서요. 웹이나 앱은 제가 직접 써볼 수 있잖아요. 그래서 이 부분을 더 전문적으로 공부하고 싶습니다.  오소연 개발자에게 '함께 일하고 싶은 사람'이란?#매너 #겸손 #긍정(대책 없는 거 제외)▶     모인에서 두 달 정도 일해보니 어땠어요?진짜 재밌었어요. 여기 계신 분들은 제가 좀 무뚝뚝한데도 잘해주셨거든요. 학생이라고 무시하는 것도 없었고, 잘 챙겨주시고 진짜 좋았어요. 특히 디자이너와 하는 협업은 처음이었어요. 디자이너인 보람님은 초보인 제가 답답하셨을 거 같은데 매번 친절하게 대해주셨어요. 사소한 것 까지도 세세하게 잘 알려주시고, 덕분에 큰 어려움 없이 일할 수 있었어요.  그리고 대학생으로서 모인이 입주해있는 구글캠퍼스에서 일할 수 있었던 것도 정말 신기해요.▶     구글캠퍼스의 어떤 점이 신기했어요?구글캠퍼스 분위기가 진짜 멋졌어요. MOIN뿐만 아니라 여기 계신 분들이 다들 좋아하는 일을 자발적으로 하고 있다는 느낌을 받았어요. 각자 자기가 하시는 일이나 소속 스타트업에 대해 애정과 자부심이 있어 보였다고 해야 되나? 그냥 돈 벌려고 회사 나오는 느낌이 아니었어요. 저도 여기 오면서 “아, 나도 열심히 살아야겠다”고 반성 많이 했어요 (^^) 또 이곳에서 스타트업 세계를 새로 접했어요. 졸업하면 이름있는 기업에 들어가야겠다고만 생각했었는데 생각이 달라졌어요. 그녀는 라이언 노트북 파우치 함께 학교로 돌아갔다고 한다!!!!!!! (글쓴이는 절대 부럽지 않다)▶     오, 그러면 모인이라는 스타트업은 어떤 곳이라는 생각이 들던가요?처음 면접 때, 대표님이 저한테 “저희 회사는 출퇴근도 그렇고 유연한 곳이라서 너무 큰 부담은 안가져도 된다”고 하셨거든요. 솔직히 그때 ‘설마 그러겠어?’ 라고 생각했어요. 근데 진짜 그러더라구요. 뭔가 출퇴근이 자유로우면 풀어질 거 같은데, 여기 분들은 다들 자율적으로 알아서 하시더라구요. 다들 알아서 하면서도 체계가 생긴다는 게 신기했어요. 엄청 능력자로 보였어요.   ▶     너무 좋은 얘기만 해줬는데, 아쉬운 점은 없어요?진짜 별로 없는데… 그냥 스타트업에 대한 대중 인지도가 전반적으로 낮다는 거에 대한 아쉬움은 있어요. 제 주변 어른들도 그렇고 이름이 알려지지 않았다는 이유로 불신하는 분들도 많았고, 아예 관심도 안가지시는 분들이 많았거든요. 그게 조금 그랬어요. 그거 외에는 딱히…?▶     앞으로 어떤 개발자가 되고 싶으신가요?음. 제 머릿속에 있는 걸 그대로 구현 해낼 줄 아는 개발자가 되고 싶어요. 일단 앞에서도 말했지만 저는 제가 직접 만들어 낸 걸 눈으로 확인하고 싶고, 써보고 싶거든요. 근데 머릿속에 있는 대로 안되면 좀 그렇죠. 거기에 덤으로 세련되고 깔끔한 코딩을 할 줄 아는 개발자라면 훨씬 좋겠어요. - 오소연이 꼽은 인생 명언 -아직 안 일어난 일을 미리 걱정하지 좀 마라!by. 우리 엄마 (소연님 어머니)#모인 #MOIN #개발자 #개발 #개발팀 #인턴 #인턴소개 #팀원 #팀원소개 #팀원인터뷰 #인터뷰 #기업문화
조회수 1620

Docker Hub 이벤트를 Slack으로 받기

Docker Hub은 Docker Registry 중에 가장 돋보이지 않나 생각하는데는 다음과 같은 이유가 있다.써드파티 도구와 서비스 대부분이 Docker Hub를 우선적으로 지원한다.이미지 이름이 매우 짧다.AWS ECR: 319270577709.dkr.ecr.us-east-1.amazonaws.com/dailyhotel/myweb:1.0.1Docker Hub: dailyhotel/myweb:1.0.1단순하지만 강력한 도커 빌드 서비스를 제공한다.이 외에도 도커 허브는 장점이 많은데 도커 이미지를 도커 허브에서 빌드하거나 외부에서 docker push를 해서 도커 이미지를 레지스트리에 밀어넣으면 해당 이벤트를 Webhook로 외부에 전달해주는 기능도 그 중 하나이다. 이론적으로는 새 도커 이미지가 나올 때마다 Slack을 통해 알람을 받을 수 있다. 하지만 놀랍게도! 도커 허브는 Slack 등의 대중적인 써드 파티 서비스와의 통합 기능을 직접 지원하지 않는다. 기본적으로 도커 허브가 보내는 Webhook를 파싱해서 슬랙 등으로 보내는 서비스는 직접 구현하거나 누군가 만든 도구를 직접 설치해 사용해야 한다.구글링하면 구현체가 몇 개 나오는데 그 중 일부는 matsengrp/relay를 커스터마이징한 것이다. 다른 구현체도 있지만 matsengrp/relay가 제일 구성이 깔끔하고 커스터마이징하기 쉬웠기 때문에 이를 기반으로 더 쓸모있는 구현체를 만들기로 했다. 새로운 구현체는기존 프로젝트를 Dockerize하고소스 코드를 직접 수정하는 대신 환경변수로 설정을 제어하게 하고도커 이미지의 태그 등 중요 정보를 추가로 표시하며위트 넘치는 이미지를 추가하여 지나치게 사무적이지 않게 메시지를 구성하는데초점을 맞추었다. 그래서 나온 결과물은 다음과 같다.개인적으로는 매우 마음에 든다. Docker 이미지로 빌드했기 때문에 서비스를 띄우기도 매우 쉽다. README 문서에도 기술했듯docker run — env SLACK_URL=’https://hooks.slack.com/services/PUT/YOURS/HERE' — env RELAY_PORT=8080 — env=DEFAULT_CHANNEL=’#dev’ — env=IMAGE_URL=’https://i.giphy.com/LYDNZAzOqrez6.gif' -p 8080:8080 dailyhotel/relay이게 전부이다. IMAGE_URL 등 환경변수 대부분은 필수값도 아니어서 실제 설정은 더 간단명료하다. 도커 이미지가 간단한만큼 Kubernetes로 띄우기도 쉽다.apiVersion: v1 kind: Service metadata: name: slackrelay labels: app: slackrelay spec: ports: — name: http port: 80 targetPort: 8080 protocol: TCP selector: app: slackrelay type: LoadBalancer — - apiVersion: extensions/v1beta1 kind: Deployment metadata: name: slackrelay spec: replicas: 1 template: metadata: labels: app: slackrelay spec: containers: — name: slackrelay image: dailyhotel/relay:latest env: — name: SLACK_URL value: "https://hooks.slack.com/services/PUT/YOURS/HERE" — name: RELAY_PORT value: "8080" — name: DEFAULT_CHANNEL value: "#dev" ports: — name: slackrelay-port containerPort: 8080그래도 여전히 몇 가지 개선점이 있긴 하다. 예를 들어 슬랙의 Webhook URL 대신 API 토큰값을 설정으로 받으면 좀더 많은 기능에 접근할 수가 있다. 이러한 점은 향후 정말 필요할 때 개선해볼 생각이다.참고 자료Webhooks for automated builds는 Docker Hub가 보내는 Webhook 메시지를 기술한다. 제목만 읽으면 자동화된 빌드에만 해당하는 이야기 같지만 확인해보니 docker push로 이미지를 푸시했을 때도 동일한 메시지 포맷을 사용한다.RequestBin는 Webhooks for automated builds에서 언급한 웹 서비스인데 Webhook 개발 등에 매우 유용하다. 외부 서비스가 발송하는 HTTP 요청 메시지를 받아서 임시로 보관해준다. Webhooks for automated builds에서 기술한 메시지 포맷대로 실제로 발송되는지 확인하기에 매우 요긴했다.#데일리 #데일리호텔 #Docker #Slack #슬랙 #협업툴 #개발 #개발자 #인사이트 #꿀팁
조회수 396

프로그래밍 수업의 모든 것 — 엘리스 코스 매니저 인터뷰.

안녕하세요 엘리스입니다:)엘리스의 프로그래밍 수업은 누구에 의해서, 어떻게, 어떤 생각을 바탕으로 만들어질까요? 미래를 이끌어나갈 컴퓨터 사이언스 기술과 그 근간이 되는 교육 사이에서 좋은 프로그래밍 수업을 만들기 위해 치열하게 고민하는 엘리스의 코스 매니저가 직접 이야기합니다! 마침 엘리스는 코스 매니저 채용 중에 있으니 관심이 있다면 눈여겨 봐주세요.코스 매니저가 관여한 프로덕트로 인하여 사용자가 성장을 하고 있다면 그것은 충분히 의미 있는 일.# 안녕하세요 저는,“트라우마를 극복한 프로그래밍 수업 크리에이터.”Q. 자기소개 부탁드려요.A. 엘리스의 프로그래밍 과목을 만드는 코스 매니저 이용희입니다.Q. 엘리스에서 일하게 된 이유는 무엇인가요?A. 원래는 프로그래밍에 대한 트라우마가 있었어요. 하지만 기술 창업에 대한 꿈이 있었기 때문에 프로그래밍은 극복해야 할 산이었죠. 엘리스는 가장 뛰어난 기술자들이 모여 창업한 스타트업이에요. 당연히 기술 창업을 가장 가까이에서 경험할 수 있는 매력적인 곳으로 느껴졌죠. 그리고 프로그래밍 교육을 제공한다는 것 역시 기회로 느껴졌어요. 저와 같이 프로그래밍을 미워하고 두려워하는 사람들에게 보다 쉽게 배울 수 있는 환경을 마련해주고 싶다는 기대로 일을 시작하게 되었습니다.Q. 두려운 대상을 향해 몸을 던지셨군요! 그런데 코스 매니저가 프로그래밍을 몰라도 되나요?A. 많이 알면 알수록 당연히 좋아요. 많이 알고 있을수록 시도할 수 있는 것도 많고 학생에게 전달해줄 수 있는 것은 더욱더 많기 때문에요. 하지만 최소한으로는 Class가 뭔지 알고 있으면 OK. 예를 들어서 코드를 보고 이 코드가 어떤 목적을 갖는지 알 수 있으면 직접 코딩을 하지는 못한다고 해도 괜찮아요.Q. 코스 매니징 외에도 라이브 수업 참여, 조교, 챌린지 사회자 등 많은 역할을 하셨는데 이유가 있나요?A. 좋은 수업을 만들기 위한 첫 번째 방법은 코스를 만드는 모든 과정에 참여하는 사람들의 역할을 직접 체험해 보는 것이라고 생각했어요. 학생으로서, 조교로서, 사회자나 라이브 어시스턴트로서. 이렇게 하니까 학생으로서 수업을 접할 때의 감상은 무엇인지, 조교로서 가르쳤을 때는 어떤 어려움이 있는지를 알 수 있었어요. 라이브 수업 어시스턴트로 참여했을 때는 방송하시는 선생님들의 애로사항을 알 수 있겠더라고요.# 코스 매니징의 정수.“프로그래밍적 성장을 도움으로써 가치를 만들어 냅니다.”Q. 코스 매니징의 A to Z는? 구체적인 업무 프로세스가 궁금해요.A. 크게 기획 — 모집 — 제작 — 분석의 네 단계로 이루어져 있어요.수업 기획 — 어떤 과목을 만들 것인가? 주차별로 무엇을 다룰 것인가? 흥미로운 콘텐츠는?선생님, 조교 모집 — 엘리스가 구상한 수업을 가장 잘 전달할 수 있는 선생님과 조교를 모집.수업 제작 및 운영 — 실습 문제, 강의 자료 등을 엘리스의 색깔로 제작하여 수업을 운영.데이터 분석 — 학생들의 피드백과 데이터를 다음 수업의 발전 및 교육자와의 관계 개선에 반영.Q. 업무 방식은? 어떤 메리트가 있나요?A. 처음부터 끝까지 모든 과정을 주도해나가는 방식이에요. 어떤 회사를 가도 프로덕트의 end to end 프로세스를 전부 경험하기는 어려운데 엘리스에서는 그 전 과정을 경험할 수 있어요. 저는 이러한 경험이 교육 업계나 특정 프로덕트에만 적용할 수 있는게 아니라 다른 업계에 간다고 하더라도 충분히 전환될 수 있는 좋은 경험이라고 생각해요.Q. 미래 산업의 근간이 될 교육을 직접 만든다는 중책을 맡고 계신다고 생각하는데요, 좋은 프로그래밍 수업을 만들기 위해 어떤 노력들을 하시나요?A. 그런 영향을 미칠 수 있다는 게 무서운 일인 것도 같아요. 어떤 사람들은 엘리스를 통해서 프로그래밍을 처음 접하는 것일 수도 있는데 그 경험이 불쾌했다면 앞으로 프로그래밍을 배울 생각이 전혀 들지 않을 수도 있는 거잖아요. 그래서 최대한 다양한 피드백을 받아서 수렴하려고 해요. 외적으로는 대학강의, 수많은 수업들을 참고해요. 여러 강의를 보다보면 좋은 예도 많지만 모든 수업이 재미있지는 않아요. 중간에 듣다 마는 경우도 있고요. 그럴 때마다 내가 왜 중단했고 어떤 요소를 바꾸면 엘리스에서는 학생들이 끝까지 들을 수 있을까 고민해서 반영하려고 하죠.Q. 언제 보람을 느끼나요?A. 내가 관여한 프로덕트가 누군가에게 임팩트를 만들어내고 나뿐만 아니라 프로덕트를 사용하는 사람들이 성장을 하고 있다면 그것은 충분히 가치 있는 일인 것 같아요. 저희 플랫폼에서는 대시보드를 통해서, 그리고 학생이 코드를 어떻게 짜고 있는지 보면서 그 결과를 가시적으로 확인할 수 있어요. 누군가 제가 만든 코스를 수강함으로써 실질적으로 성장하는 게 눈에 보일 때 가장 큰 보람을 느끼는 것 같아요.한 번은 한 선생님께서 학생으로부터 ‘선생님 덕분에 취업할 수 있었어요’라는 메시지를 받은 것을 엘리스와 공유해주셨는데 그때 정말 행복하더라고요. 이게 엘리스가 추구하는 거다,라는 생각을 했어요. 엘리스도 하나의 커뮤니티이고 싶거든요. 이 경우에는 학생-선생님-엘리스가 서로의 영향으로 좋은 결과를 만들어 낸 거죠. 이런 접점을 앞으로 더 많이 만들려고 생각하고 있어요.대시보드에 나타나는 학생들의 학습 현황 및 성취도.# 엘리스는 이런 팀.“가치, 성장, 사람. 포기할 수 없는 세 가지가 있는 곳.”Q. 함께 일하는 동료들은 어떤 사람들인가요? 총평을 하자면?A. 항상 내가 최고의 사람들과 함께하고 있다라는 확신이 있어요. 각자 자기 분야에서 최고의 실력을 가진 사람들과 함께 일한다는 것만으로도 큰 자극이 되죠. 프로그래밍이든 스타트업 생존 노하우든 항상 뭔가를 새롭게 배우고 성장하게끔 동기부여를 해주는 사람들이에요. 저는 트라우마가 있었을 정도로 프로그래밍을 두려워했지만 이들과 함께 일하며 작은 피드백을 하나 듣는 것만으로도 제 실력이 빠르게 성장한다는 것을 몸소 느낄 수 있었어요. Q. 엘리스의 분위기, 팀 문화는 어떤가요?A. 새로운 것에 도전하는 것을 환영하는 수평적이고 자유로운 팀. 인턴도 아이디어를 제시할 수 있어요. 이 다음이 더 중요한데, 아이디어에서 그치는 게 아니라 활발한 피드백이 오가요. 아이디어를 실행하기 어렵다고 판단하더라도 왜 그렇고 어떻게 발전시킬 수 있는지 이야기하죠. 실행하게 되었을 때는 아이디어를 제시한 사람에게 일에 대한 권한이 전적으로 주어지고요. 저도 처음엔 파트타임 인턴이었지만, 이런 팀문화 덕분에 계속해서 업무 범위를 확장하고 제 역량을 키울 수 있었어요.# 코스 매니저 채용.“Generalist & Infinite Learner”Q. 현재 코스 매니저를 구인 중인데요. 코스 매니저에 적합한 성향이 있나요?A. Generalist, 그리고 Infinite Learner. 깊게 한 분야를 아는 사람보다는 얕고 넓게 아는 사람이 더 적합하다고 생각해요. 다르게 말하면 새로운 것을 시도하는 것을 좋아하고 새로운 것을 접할 때 포용력이 높은 사람이요. 두 번째로는 배움에 재미를 느끼는 사람. 엘리스는 교육 스타트업이고 코스 매니저는 직접 교육의 경험을 만드는 사람이니 스스로가 배움에서 행복을 느끼는 사람이라면 훨씬 더 재미있게 일할 수 있겠죠. 한 가지 덧붙이면, 데이터 분석을 배우고 싶은 분께 엘리스는 최고의 장소입니다.Q. 코스 매니저로서 갖추고 있으면 좋은 역량이나 자질이 있다면?A. 소통 능력과 균형 감각. 코스 매니저는 수업을 만드는 모든 단계에서 다양한 이해당사자들과 일하게 돼요. 이들과 원활하게 소통하고 의견을 공유하는 게 중요하죠. 그리고 다양한 사람들 사이에서 최고의 균형을 찾아내는 것도 중요해요. 예를 들어서 선생님의 경우 개발만 해왔고 교육이라는 것을 접해본 적이 없는 분들이 대부분이고, 학생은 프로그래밍을 처음 접하면 그 수업이 좋은 건지 아닌지 평가하기 어려워요. 때문에 코스 매니저가 이 둘 사이에 다리를 놓는 중재자의 역할을 하기 위해서는 다양한 시각에서 볼 수 있는 균형 감각이 필요하다고 생각해요.최고의 실력자들과 함께 일하며 프로덕트의 처음부터 끝까지를 만드는 경험을 통해서 사람들의 성장을 돕는 가치를 창출하고 싶으신 분이라면,>> 코스 매니저에 도전해 보세요! <<#엘리스 #코딩교육 #교육기업 #기업문화 #조직문화 #서비스소개 #팀원인터뷰 #팀원소개
조회수 3080

ReactorKit 시작하기

ReactorKit 시작하기오늘은 StyleShare에서 ReactorKit을 사용한지 딱 1년이 되는 날입니다. ReactorKit은 반응형 단방향 앱을 위한 프레임워크로, StyleShare와 Kakao를 비롯한 여러 기업에서 사용하고 있는 기술입니다.StyleShare의 iOS 프로젝트 첫 커밋은 2011년 8월 23일입니다. 그 뒤로 약 7년간 크고 작은 기능을 추가하며 굉장히 큰 코드베이스를 가지게 되었습니다. 특히 2015년에는 스토어 기능을 런칭하면서 기존 서비스 만큼이나 많은 코드를 작성했습니다. 서비스 복잡도는 점점 높아졌고, 지속 가능한 코드베이스를 위해 많은 개선이 필요했습니다.ReactorKit은 많은 부분에 있어서 StyleShare가 가진 고민을 해결해주었습니다. Flux와 Reactive Programming의 개념을 결합하여 만들어진 ReactorKit에서는 사용자 인터랙션과 뷰 상태가 관찰 가능한 스트림을 통해 단방향으로 전달됩니다. 뷰와 비즈니스 로직을 분리할 수 있게 되면서 모듈간 결합도가 낮아지고 테스트하기 쉬워졌습니다. 또한, 자칫 복잡해질 수 있는 비동기 코드를 일관되게 작성할 수 있게 되었습니다.이 글에서는 ReactorKit의 기본 개념과 테스트를 위한 기법을 소개 합니다.데이터 흐름ReactorKit에는 뷰(View)와 리액터(Reactor)라는 개념이 존재합니다. 뷰는 상태를 표현합니다. 뷰 컨트롤러나 셀도 모두 뷰에 해당합니다. 뷰는 사용자 인터랙션을 추상화하여 리액터에 전달하고, 리액터에서 전달받은 상태를 각각의 뷰 컴포넌트에 바인드합니다. 뷰는 비즈니스 로직을 수행하지 않습니다.반대로, 리액터는 뷰의 상태를 관리합니다. 뷰에서 액션을 전달받으면 비즈니스 로직을 수행한 뒤 상태를 변경하여 다시 뷰에 전달합니다. 리액터는 UI 레이어에서 독립적이기 때문에 비교적 테스트하기 쉽습니다.ViewView 프로토콜을 적용하면 뷰를 정의할 수 있습니다. DisposeBag 속성과 bind(reactor:) 메서드를 필수로 정의해야 합니다.import ReactorKit import RxSwift class UserViewController: UIViewController, View { var disposeBag = DisposeBag() func bind(reactor: UserViewReactor) { } }<iframe width="700" height="250" data-src="/media/78a16e327ba4eb073cc5bdbb703c81f9?postId=c7b52fbb131a" data-media-id="78a16e327ba4eb073cc5bdbb703c81f9" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/78a16e327ba4eb073cc5bdbb703c81f9?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 236.984px;">이 프로토콜을 정의하면 reactor 속성이 자동으로 생성됩니다. 이 속성에 새로운 값이 지정되면 bind(reactor:) 메서드가 자동으로 호출됩니다. 이곳에는 사용자 인터랙션을 리액터에 바인드하거나, 리액터의 상태를 각각의 뷰 컴포넌트에 바인드하는 코드를 작성합니다.func bind(reactor: UserViewReactor) { // Action self.followButton.rx.tap .map { Reactor.Action.follow } .bind(to: reactor.action) .disposed(by: self.disposeBag) // State reactor.state.map { $0.isFollowing } .distinctUntilChanged() .bind(to: self.followButton.rx.isSelected) .disposed(by: self.disposeBag) }<iframe width="700" height="250" data-src="/media/6a6d5aa66b156cae7d4475f6ed13efb0?postId=c7b52fbb131a" data-media-id="6a6d5aa66b156cae7d4475f6ed13efb0" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/6a6d5aa66b156cae7d4475f6ed13efb0?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 325px;">Reactor리액터를 정의하기 위해서는 Reactor 프로토콜을 사용합니다. 사용자 인터랙션을 표현하는 Action과 뷰의 상태를 표현하는 State, 그리고 상태를 변경하는 가장 작은 단위인 Mutation을 클래스 내부에 필수로 정의해야 합니다. 또한 가장 첫 상태를 나타내는 initialState가 필요합니다.import ReactorKit import RxSwift final class UserViewReactor: Reactor { enum Action { case follow } enum Mutation { case setFollowing(Bool) } enum State { var isFollowing: Bool } let initialState: State = State(isFollowing: false) }<iframe width="700" height="250" data-src="/media/572f53fb442c67060d2a69f90a42a07b?postId=c7b52fbb131a" data-media-id="572f53fb442c67060d2a69f90a42a07b" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/572f53fb442c67060d2a69f90a42a07b?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 435px;">Action이나 State와 달리 Mutation은 리액터 클래스 밖으로 노출되지 않습니다. 대신, 클래스 내부에서 Action과 State를 연결하는 역할을 수행합니다. Action이 리액터에 전달되면 두 단계를 거쳐서 뷰의 상태를 변경합니다.mutate() 함수에서는 Action 스트림을 Mutation 스트림으로 변환하는 역할을 합니다. 이곳에서 네트워킹이나 비동기로직 등의 사이드 이펙트를 처리합니다. 그 결과로 Mutation을 방출하면 그 값이 reduce() 함수로 전달됩니다. reduce() 함수는 이전 상태와 Mutation을 받아서 다음 상태를 반환합니다.func mutate(action: Action) -> Observable { switch action { case .follow: return UserService.follow() .map { Mutation.setFollowing(true) } .catchErrorJustReturn(Mutation.setFollowing(false)) case .unfollow: return UserService.unfollow() .map { Mutation.setFollowing(false) } .catchErrorJustReturn(Mutation.setFollowing(true)) } } func reduce(state: State, mutation: Mutation) -> State { var newState = state switch mutation { case let setFollowing(isFollowing): newState.isFollowing = isFollowing } return newState }<iframe width="700" height="250" data-src="/media/dc8fbdce8314a7eba99be944241c5432?postId=c7b52fbb131a" data-media-id="dc8fbdce8314a7eba99be944241c5432" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/dc8fbdce8314a7eba99be944241c5432?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 522.984px;">테스팅테스트를 위해 가장 먼저 고민하게 되는 것은 ‘무엇을 테스트할 것인가’에 대한 것입니다. ReactorKit을 사용하면 뷰와 로직이 분리되어 상대적으로 쉽게 해답을 얻을 수 있습니다.View사용자 인터랙션이 발생했을 때 Action이 리액터로 잘 전달되는지리액터의 상태가 바뀌었을 때 뷰의 컴포넌트 속성이 잘 변경되는지ReactorAction을 받았을 때 원하는 State로 잘 변경되는지뷰 테스팅리액터의 stub 기능을 이용하면 뷰를 쉽게 테스트할 수 있습니다. stub 기능을 활성화하면 리액터가 받은 Action을 모두 기록하고, mutate()와 reduce()를 실행하는 대신 외부에서 상태를 설정할 수 있게 됩니다.func testAction_refresh() { // 1. Stub 리액터를 준비합니다. let reactor = MyReactor() reactor.stub.isEnabled = true // 2. Stub된 리액터를 주입한 뷰를 준비합니다. let view = MyView() view.reactor = reactor // 3. 사용자 인터랙션을 발생시킵니다. view.refreshControl.sendActions(for: .valueChanged) // 4. Reactor에 액션이 잘 전달되었는지를 검증합니다. XCTAssertEqual(reactor.stub.actions.last, .refresh) } func testState_isLoading() { // 1. Stub 리액터를 준비합니다. let reactor = MyReactor() reactor.stub.isEnabled = true // 2. Stub된 리액터를 주입한 뷰를 준비합니다. let view = MyView() view.reactor = reactor // 3. 리액터의 상태를 임의로 설정합니다. reactor.stub.state.value = MyReactor.State(isLoading: true) // 4. 그 때 뷰 컴포넌트의 속성이 잘 변하는지를 검증합니다. XCTAssertEqual(view.activityIndicator.isAnimating, true) }<iframe width="700" height="250" data-src="/media/9e5e0349766c69076a5081cbd680645b?postId=c7b52fbb131a" data-media-id="9e5e0349766c69076a5081cbd680645b" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/9e5e0349766c69076a5081cbd680645b?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 721px;">리액터 테스팅리액터는 뷰에 비해서 상대적으로 테스트하기 쉽습니다. Action이 전달되었을 때 비즈니스 로직을 수행하여 State가 바뀌는지를 확인하면 됩니다.func testBookmark() { // 1. 리액터를 준비합니다. let reactor = MyReactor() // 2. 리액터에 액션을 전달합니다. reactor.action.onNext(.toggleBookmarked) // 3. 리액터의 상태가 변경되는지를 검증합니다. XCTAssertEqual(reactor.currentState.isBookmarked, true) } func testUnbookmark() { // 1. 리액터를 준비합니다. 액션을 미리 한 번 전달해서 테스트 환경을 만들어둡니다. let reactor = MyReactor() reactor.action.onNext(.toggleBookmarked) // 2. 리액터에 액션을 한 번 더 전달합니다. reactor.action.onNext(.toggleBookmarked) // 3. 리액터의 상태가 변경되는지를 검증합니다. XCTAssertEqual(reactor.currentState.isBookmarked, false) }<iframe width="700" height="250" data-src="/media/32af3eac8c1c9646bf95ea1442ad8ff4?postId=c7b52fbb131a" data-media-id="32af3eac8c1c9646bf95ea1442ad8ff4" data-thumbnail="https://i.embed.ly/1/image?url=https://avatars2.githubusercontent.com/u/931655?s=400&v=4&key=a19fcc184b9711e1b4764040d3dc5c07" class="progressiveMedia-iframe js-progressiveMedia-iframe" allowfullscreen="" frameborder="0" src="https://medium.com/media/32af3eac8c1c9646bf95ea1442ad8ff4?postId=c7b52fbb131a" style="display: block; position: absolute; margin: auto; max-width: 100%; box-sizing: border-box; transform: translateZ(0px); top: 0px; left: 0px; width: 700px; height: 522.984px;">마치며ReactorKit은 지금까지 CocoaPods에서 약 3만 7천회 다운로드 되었고, 약 730개 앱에서 사용되고 있습니다. 최근에는 Wantedly에서 사용하며 일본에서도 많은 호응을 얻고 있습니다. 공개된지 1년밖에 되지 않았지만 굉장히 좋은 평을 받으며 성장하고 있는 프레임워크입니다. 만약 새로운 프로젝트를 시작하거나, StyleShare와 비슷한 고민을 하고 계신다면 ReactorKit을 강력하게 추천합니다.ReactorKit GitHublet’Swift 2017 ReactorKit 발표 영상let’Swift 2017 ReactorKit 발표 자료#스타일쉐어 #개발팀 #개발자 #경험공유 #인사이트

기업문화 엿볼 때, 더팀스

로그인

/