스토리 홈

인터뷰

피드

뉴스

조회수 1707

잔디 팀에서 가장 자유로운 영혼을 가진 그녀! 고객 경험(CX)팀의 Soo를 만나다

맛있는 인터뷰: 고객 경험(Customer Experience) 매니저 Soo ▲ 점심엔 역시 맥주 한 잔이죠? 알코올과 함께 하는 맛있는 인터뷰 먼저 인터뷰를 제안해 온 사람은 처음이다. 본인 소개를 부탁한다Soo(이하 ‘S’): 반갑다! 잔디 팀에서 고객 경험: CX(Customer Experience) 업무를 담당하고 있는 Soo라고 한다. 고객 응대뿐 만 아니라 서비스 번역이나 비즈니스 팀에서 사용되는 제품 메뉴얼 작성, 영상 작업 등 고객 경험에 연관된 다양한 업무를 수행하고 있다. 하는 일이 꽤 많은 것 같은데?S: 잔디 팀원이라면 당연히 이 정도는! 타이 음식은 오랜만이다. 이 곳을 오게 된 이유가 있다면?S: 우리가 온 곳은 망고플레이트에서도 평이 좋은 태국 음식점 ‘알로이 타이(Aloy Thai)‘다. 개인적으로 동남아 음식을 너무 좋아한다. 미국에 있을 때 먹었던 쌀국수 맛이 늘 그리웠는데.. 수소문 끝에 알아낸 인생 맛집이다. 선릉역 2번 출구에서 도보 5분 거리에 있다. 정확한 주소는 서울시 강남구 대치동 8… 잠깐! 광고비를 받은 건가? 맛있는 인터뷰는 원칙적으로 협찬을 금지하고 있다S: 무슨 소리. 인생 맛집이라 이렇게라도 알리고 싶었다. 아님 말고..S: ..^^ 음식과 함께 술을 주문한 인터뷰이는 Soo가 처음이다S: 평소 술을 즐기는 편이다. 하지만 오해하지 않았으면 좋겠다. 술을 좋아하는 거지 잘 마시는 건 아니다. 가끔 집에서 혼술하는 것도 좋아한다. 술 말고 좋아하는 건?S: 게임을 좋아한다. 미국에 있을 때는 집에서 혼자 농구게임을 엄청 많이 했고, 친구들과 철권을 즐겼다. 한국에서는 롤을 무척이나 많이 했다. 아침부터 새벽까지 랭겜을 돌리곤 했다. 티어가…?S: 그것은 비밀이다. (웃음) 술, 게임, 쌀국수까지. Soo의 미국 생활이 진심 궁금하다S: 남들과 크게 다르지 않다. 중학교를 제외한 학창 시절을 모두 미국에서 보냈다. 한국에서 이렇게 오래 지내보는 건 처음이다. 잔디 팀에 조인하면서 한국 생활을 시작한 격인데 처음엔 무척 낯설었다. 2년 지난 지금은 꽤 괜찮아졌다. ▲ 미국에 있을 당시의 Soo 모습. 왼쪽에서 화사하게 웃고 있는 사람이 Soo다.어떻게 잔디 팀을 알고 지원했는지 궁금하다S: 대기업에서 인턴을 해보니 수직적인 기업 문화가 맞지 않았다. 때마침 지인에게 잔디 팀을 추천 받게 되어 입사하게 되었다. 스타트업은 뭔가 열정이 넘치다 못해 폭발하는 사람만 가는 곳이라 생각했는데, 지금은 그 ‘스타트업’ 중 한 곳에서 일하고 있다. 묘한 감정이 든다. (웃음) 잔디 팀의 업무 문화는 마음에 드는가?S: 잔디 팀에서 일하면서 가장 좋은 점은 내 직무에서 풀어야 할 숙제를 스스로 한다는 점이다. 개인적으로 가장 재미있고 신나는 경험이다. 너무 교과서적인 대답이다. 신박한 답변을 원한다S: 역으로 질문하고 싶다. 잔디 팀의 업무 문화가 마음에 드는가? 소중한 말씀 감사합니다..S: ^^ 주말에는 무엇을 하고 지내는가?S: 보통 술을 마신다. (웃음) 아니면 집에서 영화를 본다. 뭔가 #술 #알코올 #혼술 #집스타그램 해시태그를 붙여야 할 것 같은 인터뷰다. 다른 이야기를 해보자!S: 언제든지! 잔디 표지모델은 어떻게 하게 되었는지?S: Product 팀의 DL이 부탁해서 촬영하게 되었다. 사진을 본 내 친구들이 이게 뭐냐며 비웃었던 게 가장 기억에 남는다. DL이 보정을 해준다고 했는데 실제로는 목주름만 보정해줬다. 뭔가 슬펐다. ▲ 잔디 홍보 자료에 자주 등장한 Soo 일하는 자리를 보면 아기자기한 물건들이 많다. 애착이 가는 물건이 있다면?S: 내가 기르고 있는 식물이다. 귀엽기도 하고, 물만 줘도 조용히 잘 자라는 녀석들이 기특하다. 펫을 기른다는 기분으로 정성스레 기르고 있다. 이름도 지어주었다. 이름이?S: 밝힐 수 없다. 맛있는 인터뷰를 통해 공개하기엔 부적절한 이름이다. (웃음) 대학교에서 신문방송학을 전공했다고 들었다. 전공과 무관한 고객 경험 업무를 하게 된 계기가?S: 고객 응대만을 하는 CS(Customer Service)가 아니라 총체적인 ‘고객 경험’에 참여하는 CX 라는 점이 끌렸다. 제품과 고객을 잇는 브릿지 역할을 한다는 점이 매력적이었고, 잔디를 이용할 때 퍼널(Funnel) 최전방에서 가장 먼저 접하는 사람이 나라는 점도 흥미로웠다. 그리고 주 전공인 영상 제작 업무도 CX 일을 하며 할 수 있어 좋았다. 업무를 하다 보면 재미있는 에피소드가 있을 것 같다S: 연령대가 높은 사용자 중 생각보다 컴퓨터 사용법을 잘 모르는 경우를 종종 볼 수 있다. 그럼에도 불구하고 최근 많은 이슈가 되고 있는 협업 트렌드를 배우고자 열심히 노력하는 모습이 너무 인상적이었다. 더욱 더 도와주고 싶다는 생각이 자연스레 들 정도다. 협업툴에 대한 요구가 많아졌음을 직감하는지?S: 협업툴에 대한 요구도 많아졌지만 그보다 더 피부에 와닿는 변화는 고객의 인식이 확연히 바뀌었다는 점이다. 처음 CX 업무를 시작했을 때 접한 잔디 사용자들은 돈을 주고 서비스를 사용한다는 개념을 생소하게 여겼다. 반면 지금은 다르다. 최근 잔디 도입을 문의하는 고객 대다수는 서비스 요금부터 문의한다. 잔디 도입 문의 어디에 하는 게 효과적인가?S: 잔디 웹사이트 우측 하단에 있는 파란색 버튼을 클릭하거나 도입 문의 폼을 남기면 CX팀과 세일즈 팀이 바로 도움을 드린다. ▲ 인형과 식물이 가득한 Soo의 업무 공간잔디 팀에서 배운 점이 있다면?S: 사람과 소통하는 방법을 가장 많이 배웠다. 아무래도 한국 문화에 익숙하지 않아 ‘한국식 소통 방법’이 낯설었는데 사회 생활을 통해 자연스레 학습할 수 있어 좋았다. 잔디 팀에서의 경험 덕분에 자신감이 생겼다. 다른 곳에 간다고 해도 잘 할 수 있을 것 같다. 첫 직장으로서 잔디 팀의 생활이 만족스럽다는 걸로 들린다S: 물론이다. (웃음) 정말인가?S: 물론이다. 건배나 하자. 태국 음식엔 역시 맥주가 짱이다. (웃음) 어떤 꿈을 가졌는지 궁금하다S: 사실 무엇을 해야할 지 정한 건 없다. 막연하지만 나만의 것을 해보고 싶다. 사무실에 앉아서 일하는 것보단 무언가 발로 뛰며 성취하는 경험을 해보고 싶다. 이전 인터뷰이였던 잔디 HR 담당자 Amy의 질문이다. 자신의 인생에서 가장 행복했던 순간은?S: 행복했던 순간이 너무 많아 한 가지만 고르기 힘들다. 뭔가 성취감을 느꼈을 때 행복을 느끼는 것 같다. 그 외에는 맥주 한잔하면서 집에서 뒹굴뒹굴할 때가 행복하다. 일상의 소소한 것에서 느끼는 즐거움이 진짜 행복은 아닐지 생각해본다. 다음 인터뷰이를 위한 질문을 부탁한다S: 올해 꼭 이루고 싶은 목표는? ▲ 술과 음식으로 점철된 맛있는 인터뷰가 열린 선릉역 맛집 ‘알로이 타이’마지막 질문이다. 왜 맛있는 인터뷰가 하고 싶었는지?S: 잔디 팀과 함께 한 시간이 어언 2년이다. 팀의 일원으로서 잔디 이름을 가진 어딘가에 내 흔적을 남기고 싶었다. 맛있는 인터뷰가 그 흔적으로 적합하다고 생각하는가?S: 물론이다. 맛있는 인터뷰를 보면 그간 잔디 팀과 함께 했던, 그리고 함께 한 멤버들의 모습을 꺼내볼 수 있다. 일종의 추억 보관함이라고 해야할까? 내 이야기도 잔디 팀의 누군가에게 추억이 될 거라 생각해 내 이름을 꼭 남기고 싶었다. 인터뷰 해줘서 너무 고맙다. (웃음) #토스랩 #잔디 #JANDI #팀원소개 #인터뷰 #기업문화 #조직문화 #팀원자랑
조회수 1757

아키텍트, 개발 리더십의 변화...

보통, 하나의 서비스를 개발하는데 얼마나 걸리며, 그 시간 동안 어떤 일을 '구체적'으로 진행시켜야 하느냐에 따라서 아키텍팅의 관점이 변화된다.자주 쓰는 장표 중의 하나이다. 간단하게 설명하면 과거의 비즈니스와 현재의 비즈니스의 차이를 디지털 서비스로 만들어 내는 기간으로 표시한 것이다.과거에는 하나의 디지털 비즈니스가 동작하기 위해서 데이터를 수집하고 분석, 기획, 구현, 실행하기까지 대부분 8.5개월에서 10개월 정도의 시간이 소요되었고, 이렇게 만들어진 서비스들은 실제 고객과 단절되어 있는, 내부 시스템에 가까웠다는 것을 표현한다.그리고, 디지털 비즈니스의 세계에서는 모바일로 실 고객과 커넥티드 되어 있으며, 각 비즈니스가 실제 수집부터 실행까지 1주에 동작되는 세계를 표현한다.이 차이는 정말 개발 조직과 개발 리더십에 많은 차이를 주게 된다.Classic Business에서는 8개월 이상의 방향성이 흔들리지 않도록, 전체적인 방향성이 흐트러지지 않도록 개발 리더십을 발휘하는 것이 중요했다. 특히, 초기의 개발 조직을 세팅하고 예산과 비즈니스의 완성과 실 서비스 후의 이익과 같은 경영적인 판단이 더 중요하던 시기였기 때문에, 실제 소프트웨어를 만들어내는 관점은 디테일하고, 기능적인 것에 집중화된 상태로 개발 조직이 구성되고, 리더십도 그것을 최대한 끌어내는 것에 집중했다.또한, 내부적 조직의 문제로 일이 더디게 진행되거나, 품질이나 세부적인 문제를 쥐어짜거나, 어떻게든 일정을 맞추기 위해서 조정하는 조정자의 역할도 매우 큰 상태였다. 개발 리더십도 그런 관점에서 구성되었고, 기술적인 변화도 거의 없이 초기에 결정된 상태로 대부분 진행되었다.그런데, Digital Business의 세계로 넘어오면 이것은 완전 다른 구도를 가지게 된다.1주 단위의 개발 및 배포까지 매우 유연한 상태로 가동되고, 이 단위는 기술적 선택과 실패가 매우 빠르게 반복되는 것을 의미하게 되며, 개발 조직은 말 그대로 작게 세분화되고, 전체적인 방향성은 계속 유동적으로 변화하게 된다.24시간 내에 하나의 개념이 수립되고, 이를 배포까지 진행시키기 위한 매우 다양한 시도들을 선택할 수 있게 하며, 기획 조직과 개발 조직이 하나의 '지표'나 '시각화'된 장표를 보고 빠르게 판단하게 할 수 있다.매우 빠른 순간 판단이 중요하며, '몇 분'간격으로 회사의 운명을 결정할 수 있는 서비스의 론칭도 가능하게 한다.관리적인 방법은 DevOps의 자동화된 환경과, 세분화된 배포 권한, 기획자들과의 유기적인 환경들을 보다 효율적으로 운용할 수 있는 방법들에 대해서 개발 리더십은 고민하게 된다.어떻게 빠르게 일을 효과적으로 움직일 것이며, 빠른 판단을 할 수밖에 없다. 빠르게 변화하는 기술 스택을 더 잘 알고 있는 것은 개발 조직이기 때문에, 아키텍트나 개발 리더의 권한은 계속 실무자에 가깝게 내려가게 되는 것이 순리에 가깝다.현재 DevOps를 지향하고 있는 개발 조직에서 아키텍트가 지향하는 것은 크게 개념적으로 변화한 것은 없다. '고객과 비즈니스를 이해하는 개발'임에는 틀림없으나, 기존의 아키텍팅과 많이 달라진 것은 실시간 서비스에 대한 분석과 기획의 변화, 데이터 중심의 개발 구조의 시각화를 통해서 개발 조직을 통제한다기보다는, 개발 조직을 숨 쉬게 만드는 '심장'과 같은 역할을 하게 된다.마치, 비즈니스가 빨라지면, 심장도 빨리 뛰고, 비즈니스가 좀 수월해지면 호흡을 고를 수 있는 형태...현재의 아키텍트는 개발 조직의 '심장'과도 같아.속도와 박자, 전체적인 흐름을 중시하는 것이 현재의 아키텍트의 역할이다.건축가인 아키텍트들에게는 엄청난 규칙과 법칙, 책임의 범위가 상당하다. 하지만, 소프트웨어 아키텍트들에게는 그런 책임이 법적으로 제시되고 있지 못하고 있다. 보통 소프트웨어 아키텍트라고 한다면, 부정적인 환경에서 제대로된 소프트웨어를 만들 수 없기 때문에 부당한 개발환경을 담당할 가능성이 없다는...그래서, SI현장에서 아키텍트는 거의 나오지 않는다고 봐야 한다. 슬프지만. 그리고, 마지막으로... 아키텍트는 '직위'나 '권위'가 아니다. '롤'일뿐이다. 그뿐...
조회수 2851

채널 iOS에 Redux를 적용하게 된 7가지 이유.

친숙한 MVC 패턴개발자라면 누구에게나 친숙한 MVC (모델 - 뷰 - 컨트롤러) 패턴은 꽤 오랜 시간 동안 사용됐고 아직까지 많은 개발자들에게 사랑받고 있는 패턴이다. 그 이유로는 이 패턴이 일단 진입장벽이 낮기도 하지만 코드 재사용성, 동시 개발의 용이성 때문이다. 만약 당신이 초보 iOS 개발자라면 높은 확률로 MVC 패턴을 쓰게될 것인데 그 이유는대부분의 예제 및 튜토리얼이 MVC 패턴을 쓰고 있고iOS의 IDE인 Xcode에서 (Swift 는 예외지만) 클래스를 생성할때 기본으로 이름에 ViewController라고 들어간다.위와 같은 이유로 많은 iOS 개발자에 영향을 주리라 생각된다. (2011년도부터 iOS 세계에 빠진 저자도 사실 iOS에서는 software architectural design pattern으로는 MVC가 넘사벽이라고 생가하고 있었기에) 문제는 상대적으로 복잡도가 높아지거나 코드의 양이 많은 제품의 개발에서는 생산성이나 가독성에 그다지 도움을 주지 못하는 데 있다고 생각한다. 예를 들어, 한 페이지의 복잡도가 높아지면 ViewController 파일 한 개의 코드 라인이 기하급수적으로 증가한다. 또 (코드 관리에 매우 신경을 쓰지 않는 이상) 객체 간의 통신 및 데이터의 통일성이 없어져서 가독성이 떨어지기 쉽고, 기능을 추가할 때 생산성이 점점 떨어지게 된다.왜 MVC 패턴은 이렇게 문제가 생기는걸까라는 질문에서부터 시작해보자.MVC 패턴, 도대체 뭐가 문제인가?!그림 1. 보편적인 MVC 패턴의 구조보편적으로, MVC 패턴의 구조는 위의 그림과 같다. 그림을 간단히 설명하자면:뷰에서 이벤트가 발생하면 컨트롤러에 알린다컨트롤러는 그것을 처리하고 모델에 업데이트를 하라고 전달한다.모델은 업데이트를 하고 컨트롤러에 다시 알린다컨트롤러는 모델이 업데이트되었다는 것을 뷰에 알린다뷰는 모델의 업데이트된 값에 따라 다시 뷰를 그린다그림 1과 위의 설명만 놓고 보면 각각의 역할이 명확하다고 생각한다. 구조가 복잡하지 않기 때문에 초보자들도 쉽게 이해하고 적용 가능하다는 것이 장점이다. 하지만 MVC 패턴은 객체 간에 어떤 방향으로 커뮤니케이션 해야 하는지에 대해서는 강제하지 않기 때문에 파생된 패턴들이 많이 있다. 실제로 구글에서 “MVC pattern”이라고 검색을 하면 위 그림과 다른 MVC 패턴 이미지들을 볼 수 있다. 그 한 가지 예가 밑에 그림 2이다.그림 2. 또 다른 MVC 패턴의 구조그림 2를 보면 그림 1과는 다른 커뮤니케이션 방향을 나타내고 있다. 바꿔 말하면 개발자가 원하면 언제든지 세 가지 구조 안에서 방향을 유동적으로 바꿔 써도 무방하다는 것이 된다 (그것이 원하는 MVC 패턴이든 아니든지 간에). MVC의 변형으로써는 여러 가지가 있지만, 대표적인 것들은 아래의 그림과 같이 MVP, MVVM 같은 것들이 있다.그림 3. MVC, MVP, MVVM 패턴의 비교실제 저자도 MVC 패턴이 커뮤니케이션 방향을 강제하지 않는 것과 관련해 문제를 겪은 경험이 여러 번 있었던 것을 기억한다. 한가지 예를 들어보자.ViewA.swift (뷰)protocol ViewADelegate {       func updateA() }   class ViewA : UIView {        var delegate: ViewADelegate?       //update through protocol      func didClickOnA() {          self.delegate?.updateA()     }      //update through notification     //maybe same kind of update can happen in other views      func didClickOnAA() {         NotificationCenter.default.post(             name: NSNotification.Name(rawValue: “updateFromA”),              object: nil         )     }      func render(_ model: product) {         //update based on model      }  } ViewController.swift (컨트롤러)class ViewController : UIViewController, ViewADelegate {       Var viewA: ViewA?     Var product = Product()     func viewDidLoad() {         self.viewA = ViewA()         self.viewA.delegate = self         // ...         self.view.addSubview(self.viewA)     }      func updateA() {         self.product.update(name: “aa”, version: “123”)         self.viewA.update(self.product)         //re-render viewA     }  } Product.swift (모델)class Product {       var name = “”     var version = “”     init() {         NotificationCenter.default.addObserver(             self,             selector: #selector(self.doSomething),             name: “updateFromA”, object: nil)     }      deinit {         NotificationCenter.default.removeObserver(self)     }      func update(name: String, version: String) {         self.name = name         self.version = version     }      func doSomething() {          //do something…          //notify viewA or any objects through notification     }  } 조금 극단적인 예처럼 보이긴 하지만 실제 개발을 하다 보면 충분히 일어날 수 있는 상황이다. 코드에 대해 간략하게 설명하자면:ViewA에서는 delegate와 notification으로 각각 ViewController와 Product에 이벤트를 날리고 있고ViewController에서는 delegate method를 구현해서 Product를 업데이트 후, 다시 ViewA를 그리라는 로직을 가지고 있다.Product 에서는 객체를 업데이트 할 수 있는 메소드가 있고 notification을 통한 업데이트를 하고 있다.이건 아주 간단한 예이지만 프로젝트가 커진다면 특정 이벤트에 대해 데이터가 업데이트되는 경로가 달라질 수 있다. ViewA -> Product -> SubProduct -> Product -> ViewA 의 경로라던가, ViewA -> Controller -> Product -> SubProduct -> Controller -> ViewA 의 경로 등이 가능하다. 이처럼 특정 이벤트에 대해 여러 가지 체인형식으로 업데이트가 이루어질 경우 그 경로를 일일이 추적하는데 시간이 걸릴 수밖에 없는 구조를 가지고 있는 것을 볼 수 있다.(프로젝트의 크기가 어느정도 커지게 된다면 이렇게 될지도 ㅎㅎ)이런 케이스가 발생하는 근본적인 이유는 결국 MVC 패턴의 장점이라고도 말할 수 있는 유연성과 양방향 커뮤니케이션 때문이다. 이 패턴 자체가 문제가 있는 것은 아니지만 결국 코드는 사람이 작성하는 것이기에 생산성과 가독성을 떨어뜨리는 결과를 초래할 가능성이 높다. 여기에서 우리는 기존 웹 개발에서 쓰이고 있던 Redux 도입을 생각하게 된 것이다.Redux는 무엇인가?Redux 로고Redux는 Facebook의 Flux 를 모태로 삼고 있고 예측 가능한 상태를 자바스크립트 프로그램에서 구현하기 위한 애플리케이션 아키텍쳐이다. Redux는 본래 자바스크립트에서 시작한 오픈소스 프로젝트이지만 다른 개발자들에게 영감을 주었고 2015년 말쯤 iOS 플랫폼에서는 ReSwift(Redux + Swift)가 생겨났다. ReSwift는 결국 Redux랑 크게 다르지 않고 Redux의 세 가지 법칙을 따른다.Single source of truth — 애플리케이션의 전체 상태(State, 또는 데이터)는 트리 형태의 하나의 저장소(Store)로 저장된다.Changes with pure functions — 상태 트리를 변경하는 리듀서(Reducer)는 순수 함수(pure function)이어야한다.Read-only states — 상태는 오직 액션(Action, 어떤 일이 일어날 것인지 설명할 수 있는 객체)으로만 변화가 가능하다.쉽게 말하자면 “Redux는 한 개의 상태 저장소를 가지고 있고 그 안에 있는 데이터만이 신뢰할 수 있으며 저장소의 상태는 오직 순수 함수인 리듀서를 통해서만 변화가 가능하다” 라고 축약 할 수 있다.그림 4 Redux 패턴의 구조위의 그림 4을 보면 충분히 프로그램의 흐름이 어떤 식으로 흐르는지 감이 왔으리라 생각한다.이벤트가 뷰에서 생성되면 그에 해당이 되는 액션을 통해 알린다.액션은 특정 리듀서에서 처리한다.리듀서는 액션에 따라 저장소를 업데이트한다.저장소에 변화가 오면 구독(Subscribe)을 하고 있는 모든 객체에 알린다.이것이 Redux의 커뮤니케이션 사이클이다. Redux만으로도 충분히 여러가지 블로그 주제가 나올 정도로 할 이야기가 많지만 여기까지만 하고, 좀 더 자세한 디테일을 알기 원한다면 옆의 링크를 클릭하시면 된다. :) -> 리덕스 공식 링크Redux vs. MVCMVC와 Redux에 대해 소개를 했으니 간단히 비교해 보자.The Flow — Redux는 데이터 및 애플리케이션의 흐름을 강제한다. 저장소의 변화는 오직 액션을 통해서만 가능하기 때문이다. 이와 다르게 MVC는 강제성이 없기 때문에 여러가지 파생 패턴이 생길 수 있다.Unidirectional flow — Redux에서 흐름은 액션으로만 변화가 일어나기 때문에 오직 한쪽으로만 흐른다. MVC에서는 양방향이 될 수도 있고 한 방향이 될 수도 있지만 보통 양방향이다.Stores — Redux에서는 상태 및 데이터가 하나의 저장소에 있기 때문에 관리하기가 쉬운 반면, MVC에서는 여러 군데에 상태가 분리되어 있기 때문에 동기화에 신경을 써야 한다. (로컬 데이터 스토리지를 쓴다면 문제가 해결되기는 하지만 패턴 이외에 추가적인 노력이 필요함)그 이외에 여러가지 다른 점이 있겠지만, 위의 3가지가 가장 다른 점이라고 저자는 생각한다.채널 데스크 iOS에 Redux를 적용하게 된 이유이제 MVC와 Redux의 차이점을 알게 되셨으리라 생각한다. 우리 팀이 채널 데스크 iOS에 Redux를 적용한 이유를 소개하려고 한다. 아직 모든 부분에 완벽히 적용한 상태는 아니지만 (부분적으로 Notification, Delegate 그리고 Reactive를 쓰고 있다) 그럼에도 Redux를 적용함으로써 얻는 이점이 많다고 느끼고 있다.Explicit data flow — 새로운 개발자가 왔을 때나 여러 명이 작업을 할때 애플리케이션의 전체 흐름을 파악하고 이해하기 쉽다.Unidirectional flow — 데이터 관련 부분을 전부 Redux로 대체하니 모든 데이터 흐름이 한 방향으로 강제되었다. 덕분에 데이터가 어디에서 왔고 어디로 가는지를 파악하기 매우 쉽다.Single storage — 한 곳에서만 데이터를 관리하기 때문에 데이터에 관한 부분은 리듀서만 잘 짜 놓으면 관리하기 쉬워진 점이 있다. Redux를 적용하기 전에 CoreData를 데이터 저장소로 쓰고 있었는데, 어느 시점에 어떻게 저장되는지 눈에 들어오지 않아 불편한 점을 Redux를 사용함으로써 해결할 수 있었다.Immutability and data consistency — 변경 가능한(Mutable) 객체는 보통 iOS 개발에서나 다른 플랫폼 개발에서 장점일수도 있다. 하지만 데이터의 일관성이 깨지기 쉽다. 만약 A에서의 데이터와 B에서의 데이터가 다르면 어떤 것을 신뢰해야 하는지의 문제도 생길 수 있다. 우리는 Redux의 저장소에 있는 데이터를 모두 변경 불가능한 객체(Immutable, Swift에서는 Struct을 쓴다)로 구현하여 이 문제를 해결하였다. 이 부분은 코딩할 때 불편한 점이 조금 있지만, 그 불편함을 감수할만한 가치가 있다고 생각한다.Predictability — 저장소는 오직 액션을 통해서만 변경할 수 있다는 점이 무엇보다 장점인 것 같다. MVC와 같이 데이터를 어디서든 변경할 수 있다면 데이터와 관련된 버그를 찾는 데 소비하는 시간이 길어지곤 한다. Redux는 어떤 액션이 어디에서 불리는지 아는 것만으로도 그 시간을 비약적으로 단축할 수 있다.Maintainability — 저장소, 상태, 액션 그리고 리듀서로 역할과 레이어를 분리하게 되니 보통 코드 라인이 100줄을 넘지 않는다. 그만큼 유지보수 비용이 적어졌다.Organized Code — MVC 패턴에서는 비지니스 로직이 뷰에 들어가는 경우가 있기도 했었는데 Redux의 가이드라인을 따름으로써 자연스럽게 대부분의 뷰는 그저 데이터를 받고 시각화하는 dummy 뷰의 형태가 되었다. 비즈니스 로직이 완전히 뷰와 분리됨으로써 뷰의 복잡도와 코드를 관리하기가 쉬웠다.ReSwift 도입 시 주의할 점ReSwift 도입을 고려하는 분들을 위해 몇 가지 주의할 점을 소개하겠다.Performance — ReSwift에서는 저장소가 변경될 때마다 newState: 메소드가 호출이 되어 화면을 업데이트할 수 있게 되어있다. 채널 데스크 같은 경우는 실시간 애플리케이션(Real-time application)이라서 API 이벤트와 Socket 이벤트가 자주 발생해서 저장소가 변경되는데, 도입 초기 단계에 이 부분을 간과해서 화면이 거의 멈출 정도로 퍼포먼스가 나오지 않았었다. 만약 ReSwift를 적용했는데 퍼포먼스가 나오지 않는다면 newState: 함수 부분을 최적화하거나 미들웨어(middleware)를 만들어서 batch 형식으로 액션을 처리하는 방식을 고려해봐야 한다.Not thread safe — ReSwift는 thread-safe 하지 않아서 초반에 알 수 없는 crash들이 자주 발생했었다. 저자 같은 경우는 ActionWrapper를 만들어서 액션은 항상 메인스레드에서 처리되도록 강제했다.글을 마무리하며..Redux는 이미 자바스크립트 개발에서는 React와 함께 많이 쓰이고 있지만 iOS에서는 아직도 생소한 아키텍쳐이다. ReSwift는 아직 2년도 되지 않은 프로젝트이고 자바스크립트에서 처럼 유용한 Redux 미들웨어도 많지 않다. 또한 인지도도 MVC, MVVM, MVP에 아직 미비한 편이다. 프로덕션에 참고할 만한 예제도 찾기 어려웠기에 초기 러닝 커브는 조금 있었던 것으로 회상한다. 그럼에도 불구하고 우리 팀은 ReSwift를 적용해 보다 깨끗하고 유지보수하기 쉬운 프로그램을 만들 수 있었고 만족하며 사용하고 있다. 기존 MVC의 불편함을 아시는 분들은 충분히 도입할 가치가 있다고 생각한다.#조이코퍼레이션 #개발자 #개발팀 #인사이트 #경험공유 #일지 #Redux
조회수 1043

안드로이드 개발자의 고민: Fragment

Activity는 화면의 기본 구성단위 입니다. 예전엔 하나의 Activity를 SubActivity 단위로 사용하려고 ActivityGroup으로 여러 Activity를 하나의 Activity로 묶어 사용했습니다. 이 방법은 장점보다 유지 관리 및 Lifecycle 관리 등의 이슈가 더 많았죠. 이제는 사용하지 않습니다.관리 이슈를 보완하기 위해 나온 것이 바로 Fragment입니다. View에는 없는 Lifecycle이 존재합니다. 이것을 이용해 Activity에서 할 수 있는 작업을 Fragment에서도 처리할 수 있습니다.더 이상 ActivityGroup을 이용해서 화면을 재활용하거나 Activity를 관리하지 않아도 됩니다. 대신 FragmentActivity를 이용해 여러 Fragment를 한 화면에서 보여주고 관리할 수 있게 되었습니다.브랜디에서 운영하는 하이버 앱은 위와 비슷하게 설계되어 있습니다. 화면의 기본이 되는 Activity에 실질적인 View를 담당하는 Fragment를 사용합니다. 여기에는 fragment layout이 있죠. 이런 설계 방식은 Activity 영역에선 보통 Toolbar 기능과 Bottom Menu Button을 만들 때 사용합니다. 실질적인 뷰는 Fragment 영역에서 보여주죠.하이버 앱은 Endless 기능을 포함한 RecyclerView가 80% 이상의 화면 비율을 차지합니다. 상품을 나열해서 보여주거나 스토어 목록을 보여주는 리스트 화면이 대부분이어서 RecyclerView에서는 다양한 api를 요청하고, 응답받은 데이터를 Adapter에서 View로 나누는 것이 주된 작업이었습니다.생각한 것과는 다르게 설계되고 말았습니다. 다양한 화면을 재활용하려고 사용한 Fragment들은 API 요청 URL만 바뀌었을 뿐, 화면의 재활용은 Lifecycle 기능이 없는 Adapter에서 관리했기 때문입니다.대부분의 Activity layout의 fragment는 fragment_default_f_adapter.xml 을 이용했습니다.더불어 Fragment를 사용하면서 제일 많이 접한 Fragmentmanager Transaction 버그 때문에 다양한 트릭을 써야 했습니다. 특히 비동기로 생기는 결함이 가장 큰 문제였습니다.문제점이 있어도 View에서는 가질 수 없는 Lifecycle 때문에 결국 Fragment를 사용해야 했습니다.이것은 모든 안드로이드 개발자가 가지고 있는 고민입니다. 하이버 앱은 리펙토링은 끝난 상태이기 때문에 더 이상 리펙토링에 시간을 쓸 수 없었습니다. 그래서 이번에 진행할 브랜디 리펙토링에서는 이 문제점을 고치려고 합니다. 저는 여기에서 도움을 많이 받았습니다.이전에도 이러한 라이브러리가 있다고 알고 있었지만 하이버를 리펙토링하면서 문제를 직접 마주하니 라이브러리가 왜 나왔는지 새삼 느꼈습니다. (역시 사람은 위기를 맞이할 때 큰 깨달음을 얻나 봅니다.)다음 화에서는 이러한 Fragment 문제를 극복하는 방법을 알아보겠습니다.글고재성 과장 | R&D 개발1팀gojs@brandi.co.kr브랜디, 오직 예쁜 옷만#브랜디 #개발자 #개발팀 #인사이트 #경험공유 #안드로이드
조회수 1140

MySQL에서 RDS(Aurora) 로 이관하기

안녕하세요. 스티비팀 서버 개발자 이학진 입니다. 저희는 최근 서비스에서 사용 중이던 MySQL DB를 RDS로 이관하는 작업을 진행하였습니다. 무엇 때문에 이관을 결정하게 되었는지와 어떻게 이관을 진행하였는지에 대해 글을 써보도록 하겠습니다.배경stibee.com은 작년 11월에 정식 오픈한 새내기 이메일 마케팅 서비스 입니다. 사실 오픈 초기부터 얼마전까지만 해도 AWS EC2의 m4.large 인스턴스 하나로 운영되던 서비스였습니다.(사실 웹+API 서버 1대, 메일발송서버 1대)그리고 이 싱글 인스턴스에 무려 6개의 서버, mysql 1개, kafka 1개, redis 1개가 돌고 있었습니다. 그럼에도 불구하고 cpu사용률은 20%를 넘지 않았습니다.하지만 최근 사용자도 점점 늘어났고, 네이버에서 메일 수신정책을 변경하면서 메일발송서버에 대한 요청이 급증했습니다.스티비에서 네이버로 대량메일을 발송했을 때 해당 메일의 본문 링크를 자동검사하는 것을 발견했는데요, 따라서 네이버로부터 비정상적으로 많은 요청이 들어오고 있었습니다. (어떤 기준으로 이런 검사를 하는 것인지 정확한 정책은 아직 모릅니다. 담당자분 이 글을 보신다면 연락주세요. 친하게 지냈으면 합니다#슬로워크 #스티비 #개발 #서버개발 #개발환경 #MySQL #인사이트
조회수 1551

PyCon2017 첫번째날 후기

아침에 느지막이 일어났다. 어제 회사일로 피곤하기도 했지만 왠지 컨디션이 좋은 상태로 발표를 하러 가야지!라는 생각 때문에 깼던 잠을 다시 청했던것 같다. 일어나 아침식사를 하고 아이 둘과 와이프를 두고 집을 나섰다. 작년 파이콘에는 참가해서 티셔츠만 받고 아이들과 함께 그 옆에 있는 유아교육전을 갔었기에 이번에는 한참 전부터 와이프에게 양해를 구해둔 터였다.코엑스에 도착해서 파이콘 행사장으로 가까이 가면 갈수록 백팩을 메고, 면바지를 입고, 영어 글자가 쓰인 티셔츠를 입은 사람의 비율이 높아지는 것으로 보아 내가 제대로 찾아가고 있구나 라는 생각이 들었다.늦게 왔더니 한산하다.지난번에는 입구에서 에코백과 가방을 나눠줬던 것 같은데 이번에는 2층에서 나눠준다고 한다. 1층이 아무래도 복잡해지니 그런 것 같기도 하고, 2층에서 열리는 이벤트들에도 좀 더 관심을 가져줬으면 하는 것 같기도 하다. 우선 스피커 옷을 받고 싶어서 (솔직히 입고 다니고 싶어서) 2층에 있는 스피커방에 들어갔다.허락 받지 않고 사진찍기가 좀 그래서 옆방을 찍었다첫 번째 키노트는 놓쳤지만 두 번째 키노트는 꼭 듣고 싶었기에 간단히 인사만 하고 티셔츠를 들고 나왔다. (외국에서 오신 연사분과 영어로 대화를 나누고 있어서 자리를 피한것은 아니다.) 나가는 길에 보니 영코더(초등학교 5학년 부터 고등학생 까지 파이썬 교육을 하는 프로그램)을 진행하고 있었다. 의미있는 시도를 하고 있다는 생각이 들었다.이 친구들 2년 뒤에 나보다 잘할지도 모른다.키노트 발표장에 갔더니 아웃사이더님이 뒤에 서 게셨다. 지난 파이콘 때 뵙고 이번에 다시 뵈었으니 파이콘이 사람들을 이어주는 역할을 하는구나 싶었다.키노트에서는 현우 님의 노잼, 빅잼 발표 분석 이야기를 들을 수 있었다. 그리고 발표를 통해 괜히 이것저것 알려줘야만 할 것 같아 발표가 부담스러워지는 것 같다는 이야기를 들었다. 나 또한 뭔가 하나라도 지식을 전달해야 한다는 압박감을 느끼고 있었던 터라 현우 님의 키노트 발표를 듣고 나니 좀 더 오늘을 즐겨야겠다는 생각이 들었다.오늘은 재미있었습니다!현우님 키노트를 듣고 같은 시간(1시)에 발표를 하시는 경업님과 이한님 그리고 내일 발표이신 대명님, 파이콘 준비위원회를 하고 계신 연태님과 함께 식사를 하러 갔다. 가는 길에 두숟갈 스터디를 함께 하고 계신 현주님과 희진 님도 함께했다. 사실 이번에는 발표자도 티켓을 사야 한다고 해서 조금 삐져 있었는데 양일 점심 쿠폰을 주신다고 해서 삐진 마음이 눈 녹듯이 사라졌다.부담 부담식사를 하고 발표를 할 101방으로 들어가 봤다. 아직 아무도 없는 방이라 그런지 괜히 긴장감이 더 생기는 느낌이다. 발표 자료를 열어 처음부터 끝까지를 한번 넘겨 보고 다시 닫았다. 처음에는 가장 첫 발표라 불만이었는데 생각해보니 발표를 빨리 마치고 즐기는 게 훨씬 좋겠다는 생각이 들었다. 발표 자료를 다듬을까 하다가 집중이 되지 않아 밖으로 나갔다. “열린 공간” 현황판에 충동적으로 포스트잇을 하나 붙이고 왔다. 어차피 발표는 나중에 온라인으로도 볼 수 있으니까 사람들과 이야기를 나눠 봐야 겠다 싶었다. (내 발표에는 사람이 많이 왔으면 하면서도, 다른 사람의 발표는 온라인으로 보겠다는 이기적인 생각이라니..)진짜 궁금하긴 합니다다시 발표장으로 돌아왔다. 왠지 모르는 분들은 괜찮은데 아는 분들이 발표장에 와 계시니 괜히 더 불안하다. 다른 분들은 발표자료에 짤방도 많이 넣으셨던데.. 나는 짤방도 없는 노잼 발표인데.. 어찌해야 하나. 하지만 시간은 다가오고 발표를 시작했다.얼굴이 반짝 반짝리허설을 할 때 22분 정도 시간이 걸렸던 터라 조금 당겨서 진행을 했더니 발표를 거의 20분에 맞춰서 끝냈다. 그 뒤에 몇몇 분이 오셔서 질문을 해주셨다. 어리버리 대답을 한 것 같다. 여하튼 내 발표를 찾아오신 분들께 도움이 되었기를. 그리고 앞으로 좀 더 정확한 계산을 하시기를.대단히 발표 준비를 많이 하지도 못하면서 마음에 부담만 쌓아두고 있는 상황이었는데, 발표가 끝나니 아주 홀가분한 마음이 되었다. 발표장을 나가서 이제 부스를 돌아보기 시작했다. 매해 참여해 주고 계신 스마트스터디도 보이고 (정말 안 받고 싶은 ‘기술부채’도 받고 말았다.) 쿠팡, 레진 등 친숙한 회사들이 많이 보였다. 내년에는 우리 회사도 돈을 많이 벌어 여기에 부스를 내고 재미있는 이벤트를 하면 좋겠다는 생각이 들었다.부스를 돌아다니다가 이제 파이콘의 명물이 된 내 이름 찾기를 시작했다. 이름을 찾기가 쉽지가 않다. 매년 참여자가 늘어나서 올해는 거의 2000명에 다다른다고 하니 파이썬 커뮤니티의 성장이 놀랍다. 10년 전에 파이썬을 쓸 때에는 그리고 첫 번째 한국 파이콘이 열릴 때만 해도 꽤 마이너 한 느낌이었는데, 이제 주류가 된 것 같아 내 마음이 다 뿌듯하다. (그리고 내 밥줄이 이어질 수 있는 것 같아 역시 기쁘다)어디 한번 찾아보시라다음으로는 박영우님의 "Django admin site를 커스텀하여 적극적으로 활용하기” 발표를 들으러 갔다. (짧은 발표를 좋아한다.) 알고 있었던 것도 있었지만 커스텀이 가능한지 몰랐던 것들도 있어서 몇 개의 기능들을 킵해 두었다. 역시 컨퍼런스에 오면 내게 필요한 ‘새로운 것’에 대한 실마리를 주워가는 재미가 있다.익숙하다고 생각했지만 모르는것이 많다4시가 되어 OST(Open Space Talk)를 하기로 한 208B 방으로 조금 일찍 갔다. 주제가 뭐였는지는 잘 모르겠는데 주식 투자, Tensor Flow, 비트코인, 머신러닝 등등의 이야기들이 오가고 있었다. 4시가 되어 내가 정한 주제에 대해 관심 있는 사람들이 모였다. 괜히 모일 사람도 없는데 큰방을 잡은 것이 아닐까 하고 생각하고 있었는데, 생각보다 많은 분들이 오셨다.각 회사들이 어떤 도구를 사용하는지 설문조사도 해보고, 또 어떤 개발 방법론을 사용하는지, 코드 리뷰, QA는 어떻게 하고 있는지에 대한 이야기를 나눴다. 다양한 회사에서 다양한 일을 하는 사람들이 모여 있다 보니 생각보다 꽤 재미있게 논의가 진행되었다. 사실 내가 뭔가 말을 많이 해야 할 줄 알았는데, 이야기하고 싶은 분들이 많이 있어서 진행을 하는 역할만 하면 되었다. 마지막으로는 “우리 회사에서 잘 사용하고 있어서 다른 회사에도 추천해 주고 싶은 것”을 주제로 몇 가지 추천을 받은 것도 재미가 있었다.열심히 오간 대화를 적어두긴 했다5시에 OST를 마치고는 바로 집으로 돌아왔다. 오늘 저녁에 아이들을 잘 돌보고 집 청소도 열심히 해두어야 내일 파이콘에 참여할 수 있기 때문이다. 기대된다. 내일의 파이콘도.그리고 정말 감사드린다. 파이콘을 준비해주시고 운영해주고 계신 많은 분들께.#8퍼센트 #에잇퍼센트 #개발자 #개발 #파이썬 #Python #파이콘 #Pycon #이벤트참여 #참여후기 #후기
조회수 1363

도도 파이터 제작기

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

[인공지능 in IT] 인공지능과 저널리즘

얼마 전, 재미있는 기사를 읽었다. 일본의 한 SF 공모전에 응모한 작품 1,400편 중 인공지능이 작성한 소설 두 편이 예선 심사를 통과했다는 내용이었다. 이 중 소설 한편의 제목은 '컴퓨터가 소설을 쓴 날'이다. 소설을 작성하는 인공지능 기술을 개발한 연구팀은 육하원칙 등의 제시어를 준 뒤, 연관어에 따라 소설을 쓰는 알고리즘을 활용했다.미디어 혹은 인공지능 분야에 생소한 독자들에게 다소 신기할 수 있겠지만, 사실 인공지능을 활용한 저널리즘은 수 년 전부터 진행 중이다. 국내에서는 2014년 서울대학교 언론정보학과의 'hci+d Lab' 이준환 교수팀이 개발한 알고리즘을 시초라고 할 수 있다. '프로야구 뉴스 로봇'이라고 불리는 소프트웨어는 KBL의 모든 경기를 자동으로 요약해 정리한다. 연구팀이 처음부터 이 같은 기능을 염두에 둔 것은 아니었고, 데이터를 시각화하는 과정에서 시각화 방식을 텍스트로 바꿔본 것이 연구의 시작이라고 한다. 위 사례는 사람이 아닌 기계가 직접 '글'을 작성했다는 점에 있어 의미가 크다. 미디어 업계에서도 디지털화는 불가항력 같은 존재가 되고 있다.얼마 전, 옥스퍼드-로이터 저널리즘 연구소에서 미디어 업계를 대상으로 조사를 시행했다. "2018년 실행해야 할 가장 중요한 과제는 어떤 것이라고 생각하는지"에 대한 물음에 "데이터 수용량을 증가시키는 것"을 가장 많이 답변했다. 모바일 알림, 웹사이트나 애플리케이션에 사용자를 등록시키는 일 등 여러 과제들이 있었지만, IT 솔루션 업계도 아닌 미디어 업계가 데이터 수용량 증가를 최우선 과제로 생각하고 있다는 사실은 개인적으로 매우 충격적이었다. 또한, "현재 귀사에서는 기사 보도에 있어 어떠한 용도로 적극적인 인공지능 기술을 도입할 예정입니까?"라는 질문에 '컨텐츠 추천', '업무 자동화', '기삿거리 탐색' 등 다양한 분야에서 인공지능 기술 도입을 계획하고 있었다. 그만큼 이미 언론에서도 인공지능 기술은 먼 세상 이야기가 아닌, 당장 피부로 느껴질 정도로 가까워졌다.세계 최대 통신사 중 하나인 'Associated Press(AP)'는 2017년 'The Future of Augmented Journalism: A guide for newsrooms in the age of smart machines'이라는 인공지능 활용 기술 가이드를 발간했다. 해당 가이드에 따르면, 인공지능은 언론에서 크게 다섯가지 영역으로 활용된다. 이에 대한 예시를 하나씩 살펴보도록 하자.첫번째로 'Machine Learning', 즉 기계학습이다. 기계학습을 이용하면, 방대한 데이터로부터 결론을 도출하는 과정을 쉽게 처리할 수 있다. 그리고 기계학습 알고리즘을 통해 기자들은 이미지를 포함한 막대한 양의 자료를 한 번에 처리할 수도 있다. 미국의 매체 'Quartz' 소속 'Sarah Slobin' 기자가 트럼프 미국 대통령의 취임 연설에 대한 기사에 기계학습을 이용한 분석 자료를 쓴 일례가 있다. 트럼프의 얼굴 표정과 연설에서 표현된 감정을 판단하는 데에 기계학습 알고리즘을 사용한 것.< 출처: Quartz, 제공: 스켈터랩스 >두번째 활용 영역은 'Language'다. 인공지능 분야에서 언어에 대한 연구는 꾸준히 이어지고 있는데, 언어 처리 분야 중에서도 저널리즘과 관련 있는 기술은 '자연어 생성'과 '자연어 처리'다. 당연하겠지만, 자동으로 문장을 생성하는 것은 언론에서 매우 유용하게 사용할 수 있는 기술 중 하나다. 'LA Times'는 'LA Quakebot'이라는 서비스를 개발했다. 'LA Quakebot'은 자연어 생성 기술을 활용해 지역에서 지진이 일어난 순간, 이미 작성된 프레임에 맞춰 기사를 작성하며, 완성된 기사는 트위터를 통해 송출한다.< 출처: LA QuakeBot 트위터, 제공: 스켈터랩스 >세번째는 'Speech'로, 저널리즘에서 대화형 인터페이스가 뉴스 소비 및 유통에 어떠한 영향을 미칠 지 관심을 가지고 있다. 이미 'AP', 'Wall Street Journal', 'BBC', 'Economist' 등 여러 미디어가 오디오 인터페이스 기술을 시도하는 것으로 알려졌다. Speech 역시 크게 두 가지로 나뉘는데, 'TTS'라고 불리는 'Text-To-Speech'를 활용하면 뉴스룸에서 제공하는 문자 기사를 음성으로 변환시키고, 합성된 음성을 콘텐츠로 송출할 수 있다. 반대로 'STT', 즉 'Speech-To-Text'를 활용하면 음성으로부터 의미를 잡아내고, 모든 의도와 목적에 맞춰 음성을 문자로 변환시키며, 이를 통해 기자들이 인터뷰 내용을 녹취하는데 소요하는 시간을 줄일 수 있다.< 출처: BBC NEWS LABS, 제공: 스켈터랩스 >네번째, 듣는 것과 녹취하는 것을 넘어 눈으로 본 것을 기록할 수 있는 'Vision' 기술이다. 컴퓨터 비전을 활용하면 빠르고 쉽게 이미지 및 영상을 분류하고 정리할 수 있다. 용이한 검색을 통해 궁극적으로 편집 속도까지 높일 수 있는 셈이다. 'AP'는 인공위성으로 수집한 영상 데이터를 공급하는 'Digital Globe'라는 기업을 통해 동남아 선박의 고해상도 위성사진을 확보했다. 이를 통해 노예선에 관한 탐사보도에 필요한 결정적인 증거를 찾으며, 2016년 공공서비스 부문 퓰리처상을 수상했다.< 출처: AP, 제공: 스켈터랩스 >마지막으로 'Robotics'를 꼽을 수 있다. 로봇 센서를 활용해 사건 사고에 대한 사람들의 반응을 실시간으로 측정할 수 있으며, 앞서 언급한 'Quakebot'의 예처럼 자연재해가 발생하는 것에 대해 다룰 수 있다. 'AP'는 2016년 하계올림픽 당시, 로봇과 원격 카메라를 이용해 기자들이 물리적으로 직접 접근할 수 없는 지역에 카메라를 설치하고, 원격 조종해 촬영했다. 또한, 드론을 이용해 이라크 모술 남동쪽 다이바가 근처에 추방된 이라크인들을 촬영해 중독 지역 난민 위기에 대해서도 보도한 바 있다.< 출처: AP, 제공: 스켈터랩스 >이렇듯 인공지능이 미디어 업계 전체에 긍정적인 영향을 주고 있으며, 이를 활용한 사례는 앞으로도 더욱 늘어날 것으로 전망한다. 다만, 지속적으로 발전하는 인공지능을 무조건 도입하는 것만이 능사는 아니다. 인공지능 기술의 확산으로 보도 속도, 보도 규모 및 범위 등에 도움될지라도, 데이터의 질에 따라 좋지 않은 기사가 나올 수 있기 때문이다. 'AP'의 스마트머신 시대 뉴스룸을 위한 가이드에도 언급된 포인트로 마무리를 해보자.1. 인공지능은 저널리즘의 도구이지, 저널리즘을 대체하지 않을 것이다.2. 인공지능은 인간과 마찬가지로 편향적이고, 실수를 할 수도 있다. 이는 데이터가 모든 것을 결정하기 때문이다.3. 인공지능이 만병통치약은 아니다. 최근 자율주행 자동차 사고 이슈처럼 기술이 극복하지 못하는 문제는 여전히 존재한다.4. 인공지능에 대해 더 많이 알아야 인공지능 활용 가능성의 문이 크게 열린다.5. 저널리즘의 도구가 변한다고 해서 저널리즘의 법칙이 변하지 않는다. 언제나 윤리와 기준은 매우 중요하다.이호진, 스켈터랩스 마케팅 매니저조원규 전 구글코리아 R&D총괄 사장을 주축으로 구글, 삼성, 카이스트 AI 랩 출신들로 구성된 인공지능 기술 기업 스켈터랩스에서 마케팅을 담당하고 있다 #스켈터랩스 #기업문화 #인사이트 #경험공유 #조직문화 #인공지능기업 #기술기업
조회수 2367

SQLAlchemy의 연결 풀링 이해하기

안녕하세요. 스포카 프로그래머 김재석입니다.SQLAlchemy는 파이썬 데이터베이스 툴킷으로는 가장 독보적인 수준으로 우아한 기능을 제공하고 있어 많은 사람이 애용하고 있습니다. 스포카에서도 파이썬 프로젝트인데 데이터베이스에 접근해야 한다면 필수로 이용하고 있죠.오늘은 SQLAlchemy의 연결 풀에 대한 기본 개념과 실전에서 연결 풀링과 관하여 알면 좋을 여러 이슈에 대해 다뤄보고자 합니다.연결 풀링 개념연결 풀링은 차후에 발생할 데이터베이스 요청에 대비하여 데이터베이스 연결을 캐싱하는 기법입니다. 빈번한 데이터베이스 요청이 여러 사용자에 의해 발생할 때, 매번 연결을 생성하고 닫는 과정을 반복하면 이에 대한 비용이 크기 때문에 이 기법을 사용하여 연결 생성 과정을 줄일 수 있습니다. 짧은 요청이 빈번하게 발생하는 웹 서비스와 같은 형태가 연결 풀과 궁합이 잘 맞습니다.SQLAlchemy의 기본 풀: 큐 풀(QueuePool)SQLAlchemy 역시 연결 풀을 기본적으로 채택하고 있는데, 그중 기본으로 제공하는 것은 큐 풀(QueuePool)입니다. 큐 풀은 설정된 pool_size와 max_overflow를 바탕으로 복수의 연결 풀을 구성해서 운용합니다. SQLite를 제외한1 모든 데이터베이스에서 기본값으로 이용하므로, 이 글에서는 큐 풀의 관리 방법을 주로 다루도록 하겠습니다.큐 풀의 생애주기큐 풀이 처음부터 연결을 미리 만드는 것은 아닙니다. 일단 0개로 시작합니다.요청이 들어올 때, 큐 풀에 유효 연결이 없으면 하나 생성합니다.설정된 pool_size까지는 더 연결이 필요하지 않은 상황이라도 연결을 종료하지 않습니다.요청이 들어올 때, pool_size까지 다 찼다 할지라도 유효 연결이 없으면 초과하여 하나 생성합니다.4번 이후부터는 오버플로 상황이기 때문에, 큐 풀은 적극적으로 오버플로를 방지하기 위해 새로 들어오는 연결을 종료하여 pool_size에 총연결 수를 맞춥니다.QueuePool이 관리하는 연결이 pool_size + max_overflow까지 다 찬 상황에서 요청이 들어오면, 일단 기다리게 합니다. 기본값으로는 30초를 기다립니다.30초를 기다려도 반환되는 연결이 없다면 TimeoutError 예외를 발생시킵니다.적절한 큐 풀 설정값서비스가 작을 때는 기본값이면 충분하지만, 서비스 사용량이 많아지고 규모 문제가 발생하게 된다면 설정을 현재 상황에 맞춰 바꿔주는 게 좋습니다. 보통 QueuePool 관련 위 언급한 2가지 값(pool_size, max_overflow)을 바꿔주는 게 좋은데 기본값은 5, 10입니다.pool_size: 현재 구성에서 연결 생성 부담을 최소화할 수 있는 가장 작은 값이 되어야 합니다.max_overflow: 현재 구성에서 데이터베이스, 웹 인스턴스가 물리적으로 버틸 수 있는 최댓값이 되어야 합니다.pool_size가 과하게 설정되어있으면 데이터베이스 입장에서 너무 많은 연결을 점유하고 있으니 비효율적입니다. 그렇다고, 너무 적게 설정한다면 오버플로가 자주 발생하여 풀링으로 얻을 수 있는 효율을 누리지 못합니다. 즉, 파이썬 측에서 비효율적입니다.max_overflow가 데이터베이스나 웹 인스턴스의 한계치보다 너무 빡빡하게 잡혀있으면 조금만 사용자 유입이 늘어도 TimeoutError를 쉽게 만나거나 서비스 속도 저하를 자주 경험하게 됩니다. 그렇다고 무한으로 두면 사용량 폭증시 이해할 수 없는 에러 파티를 경험하게 될 것입니다. (데이터베이스나 파이썬 앱, 혹은 둘 다 드러눕습니다.)결국 서비스마다 그만의 퍼포먼스와 장비 한계치가 있으니만큼 내부에서 스트레스 테스트를 통한 벤치마킹으로 적정 값을 뽑아내는 것을 추천합니다.큐 풀 관하여 자주 밟는 문제개발할 때는 문제가 없었는데, 상용 서버를 띄우면 수분 이내로 서버가 TimeoutError 예외를 발생하며 응답을 안 합니다.SQLAlchemy 쓰는 서비스를 만들어서, 개발 잘 하고 배포했는데 프로덕션에서 잠깐 잘 돌더니 TimeoutError를 내뱉으며 픽픽 죽어버리는 경험을 많이 하는 것 같습니다. 이 에러 자체는 Session이 큐 풀에 연결을 받기 위해 기다리다가 못 참고 TimeoutError를 내는 것인데요. 위의 생애주기 기준, 7번에 해당하는 상황이죠. 큐 풀의 timeout 기본값은 30이니까 30초 동안 풀의 모든 연결이 점유된 상태에서 아무것도 받지 못한 상태가 된 것이라고 보시면 됩니다.위와 같은 경험이라면 서비스 사용량이 폭증하는 쪽보다는 십중팔구 기존에 점유한 Session에서 제대로 연결을 반환해주지 않아서 발생하는 문제입니다. 특히 웹서비스라면 Flask 등에서 요청 시마다 Session이 연결을 불러다 써놓고 Pool에 돌려주는 일을 빼먹는 실수가 잦은데, Flask를 쓰고 계신다면 Flask-SQLAlchemy 등을 쓰셔서 생애주기 관리 자체를 타 라이브러리에 위임하시거나, 현재 구조상에서 요청이 끝나는 시점에 맞춰 session.close()를 적절히 호출해주시면 됩니다. (사실 Flask-SQLAlchemy가 해주는 것도 딱 이 수준입니다.)어느 날 갑자기 연결이 왕창 늘어버렸어요.역시 웹서비스 개발하다보면 발생하는 이슈입니다. SQLAlchemy를 쓰면 Session 활용을 암시적으로 하게 될 때가 많습니다. Session이 실제로 요청을 보내는 시점에서야 연결을 시도하기 때문에, 예상치 못한 기능 변경으로 연결 폭증을 겪는 것인데요. 제가 자주 본 것은 Flask의 생애주기중 before_request 구현에서 데이터베이스에 접근하는 것입니다.본래 데이터베이스 연결이 필요한 엔드포인트에서만 접속이 발생하던 것이, before_request에 붙으면서 모든 엔드포인트가 데이터베이스 연결을 하게 되면 사용량이 폭증하기 쉽게 되는데요. 이처럼 전역적인 영역에서 DB 접근을 하는 시나리오를 최소화하는 정책으로 실수를 완화할 수 있습니다.마치며SQLAlchemy의 연결 풀의 동작 방식을 이해하면 상용 서비스를 운영할 때 발생하는 데이터베이스 부하 문제를 진단하고 해결하는 데 많은 도움이 됩니다. pool_size와 max_overflow의 적정값은 서비스에 따라, 인프라의 사양에 따라 다르므로 이를 잘 파악하여 효율적으로 연결 풀이 운영될 수 있도록 세팅하는 것을 추천합니다.연결 풀을 관리하는 방법으로는 SQLAlchemy내의 기본 큐 풀을 쓰는 것 외에 Pgpool-II과 같은 미들웨어를 연결하는 안도 있습니다. 추후 이에 대해서도 다루어보도록 하겠습니다.SQLAlchemy 0.7부터 SQLite 같은 파일 기반 데이터베이스에서는 기본적으로 NullPool을 채택합니다. 파일 기반 데이터베이스에는 네트워크 연결이 일어나지 않기 때문에, 연결 비용이 적기 때문입니다. NullPool은 이름에서 알 수 있듯이 연결 풀을 유지하지 않고2 풀에 연결이 들어오는 즉시 폐기합니다. ↩큐 풀의 pool_size를 0으로 하는 것과 같다고 착각할 수 있으나, 큐 풀은 pool_size가 0일 때 pool_size가 무한대인 것으로 인식합니다. 따라서 풀을 만들지 않으려면 NullPool을 쓰는 것이 적절합니다. ↩#스포카 #개발팀 #개발자 #인사이트 #업무일지 #후기
조회수 2452

React + Decorator + HOC = Fantastic!!

React + Decorator + HOC = Fantastic!!지난 포스팅에서는 ES7의 Decorator 문법을 이용해 선언된 클래스와 그 프로퍼티들을 디자인 시간에 변경하는 법을 알아보았습니다. 그렇다면 리액트 컴포넌트와 Decorator가 만나면 어떤 시너지가 발생할까요?만약 ES7의 Decorator에 대해 모르신다면 지난 포스팅을 읽고 오시는 걸 권장합니다. 이 포스팅은 독자들이 Decorator에 대해 이미 알고 있다고 가정하고 작성됐습니다.Higher Order Component리액트 공식 문서를 보면 Higher Order Component(이하 HOC)를 다음과 같이 설명하고 있습니다.리액트 컴포넌트 로직을 재활용할 수 있는 고급 기법리액트에서 공식적으로 제공하는 API가 아니라 단순히 아키텍쳐이 설명으로는 HOC가 어떤 역할을 하는지 이해하기는 역부족이기 때문에 간단한 예제를 통해 HOC를 어떻게 작성하는지 알아보겠습니다.function withSay(WrappedComponent) {     return class extends React.Component {     say() {       return 'hello'     } render() {       return (                   {...this.props}           say={this.say} />       )     }   } } withSay 함수는 WrappedComponent를 인자로 받아 원하는 속성들을 결합해 새로운 컴포넌트를 반환합니다. 이렇게 만들어진 withSay 함수는 아래와 같이 사용 가능합니다.@withSay class withOutSay extends React.Component {     render() {     return (               {this.props.say()}           )   } } withOutSay 컴포넌트는 say 메소드를 가지고 있지 않습니다. 하지만 withSay 함수를 사용하니 say 메소드를 사용할 수 있게 됐습니다. 이처럼 컴포넌트를 인자로 받아 입맛에 맞게 바꾼 뒤 새로운 컴포넌트로 반환하는 기법을 HOC라고 부릅니다.그렇다면 HOC는 리액트에서 어떻게 사용을 해야 효율적일까요?Cross Cutting Concerns개발을 하다 보면 다음과 같은 상황에 직면하는 경우가 종종 있습니다.개발 전반에 걸쳐 반복해서 등장하는 로직그럼에도 불구하고 모듈화가 쉽지 않은 로직예를 들어 방명록 작성, 게시글 작성, 게시글 스크랩을 하는 컴포넌트들에서 유저 인증과 에러 처리의 과정이 필요하다고 했을 때 어떻게 코드를 디자인해야 할까요? 컴포넌트와 직접적으로 연관이 없는 기능들이 컴포넌트와의 결합이 너무 강해 쉽게 모듈화를 시키지 못합니다.그림 1. Cross Cutting Concerns의 예시이렇듯 코드 디자인적인 측면에서 공통적으로 발생하지만 쉽게 분리를 시키지 못하는 문제를 Cross Cutting Concerns라고 합니다. 이 문제를 끌어안고 가면 프로젝트의 코드는 쉽게 스파게티가 되고 나중에는 유지 보수를 하기 힘들어집니다.하지만 우리게에는 HOC와 Decorator가 있고 이를 이용해 이 문제를 쉽게 해결할 수 있습니다.유저 인증 문제를 HOC로 해결아래는 인증이 안된 유저에게 다른 페이지를 보여주는 코드입니다.class TeamChat extends React.Component {     constructor() {     super()     this.state = {       unAuthenticated: false     }   } componentWillMount() {     if (!this.props.user) {       this.setState({ unAuthenticated: true })     }   } render() {     if (this.state.unAuthenticated) {       return     }     return I'm TeamChat   } } 유저 인증을 전통적인 if-else 구문으로 구현했습니다. 당장 이 컴포넌트를 본다면 문제가 없어 보입니다. 어떻게 보면 정답처럼 보이기도 합니다. 하지만 유저 인증이 필요한 컴포넌트가 많아지면 상황이 달라집니다.100개의 컴포넌트에서 위와 같은 방식으로 유저 인증을 하고 있는데 유저 인증을 하는 로직이 변경된 상황을 생각해 봅시다. 100개의 컴포넌트 모두 유저 인증 코드를 바꿔야 하는 상황에 직면하게 됩니다. 전부 다 바꾸는 것도 일이지만 실수로 몇 개의 컴포넌트를 수정하지 않을 확률이 농후합니다. 당장에는 간단하지만 잠재적 위험을 안고 있는 위 코드는 아래와 같이 수정되어야 합니다.function mustToAuthenticated(WrappedComponent) {     return class extends React.Component {     constructor() {       super()       this.state = {         unAuthenticated: false       }      } componentWillMount() {       if (!this.props.user) {         this.setState({ unAuthenticated: true })       }     } render() {       if (this.state.unAuthenticated) {         return       }       return     }    } } HOC를 이용해 확장이 용이한 유저 인증 로직이 탄생했습니다!! 이렇게 만들어진 HOC는 아래와 같이 적용이 가능합니다.@mustToAuthenticated class TeamChat extends React.Component {     render() {     return I'm TeamChat   } } @mustToAuthenticated class UserChat extends React.Component {     render() {     return I'm UserChat   } } 기존의 코드와 비교했을 때 코드가 훨씬 간단해진 것을 확인할 수 있습니다. 비단 코드만 간단해진 것뿐만 아니라 아래와 같은 추가 효과를 기대할 수 있습니다.유저 인증 로직이 컴포넌트와 분리가 되어 자신이 맡은 역할에만 집중할 수 있습니다.유저 인증 로직이 바뀌어도 코드를 수정해야 할 곳은 하나의 컴포넌트뿐입니다.예시로 작성한 HOC는 최소한의 코드로만 작성된 예시입니다. 실제 제품에서 사용되기 위해서는 몇 가지 고려해야 할 사항이 있는데 이는 리액트 공식 문서를 참고해주세요.i18n 컴포넌트를 HOC로 작성채널 서비스는 한국어, 영어, 일본어를 지원하기 때문에 번역 기능이 필요했습니다. 초기에는 번역 서비스를 아래와 같이 구현했습니다.@connect(state => ({   locale: getLocale(state) }) class Channel extends React.Component {     render() {     const local = this.props.locale     const translate = TranslateService.get(locale)     return (               {translate.title}         {translate.description}           )   } } 처음에는 위와 같은 방식으로 번역 서비스를 구현하는 것이 괜찮았습니다. 하지만 번역을 제공해야 하는 컴포넌트가 많아지면 많아질수록 중복되는 코드가 많아지는 것을 보고 아래과 같이 HOC를 이용해 코드의 중복을 제거했습니다.function withTranslate(WrappedComponent) { @connect(state => ({     locale: getLocale(state)   }))   class DecoratedComponent extends React.Component {     render() {       const locale = this.props.locale       const translate = TranslateService.get(locale) return (                   {...this.props}           translate={translate} />       )    }   } } 이렇게 작성된 HOC는 아래와 같이 사용이 가능합니다.@withTranslate class Channel extends React.Component {     render() {     const translate = this.props.translate     return (               {translate.title}         {translate.description}           )   } } HOC의 작성 방법은 예시로 작성한 두 개의 HOC에서 크게 벗어나지 않습니다. 이를 응용해 자신의 프로젝트에 맞는 코드를 작성해보세요.중첩 가능한 HOCHOC는 여러 개를 중첩해서 사용할 수 있습니다.. 예를 들어 유저 인증과 i18n 서비스를 동시에 제공하고 싶을 때 두 HOC를 중첩해서 사용하면 됩니다.@mustToAuthenticated @withTranslate class Channel extends React.Component {     render() {     return (               {`Hello!! ${this.props.user.name}`         {translate.title}         {translate.description}           )   } } 마무리이상으로 리액트에서 HOC를 사용할 수 있는 상황과 작성 방법을 알아보았습니다. 본 포스팅에서 다루지는 않았지만 만능처럼 소개한 HOC에도 몇 가지 단점은 존재합니다.Component Unit Test를 할 때 문제가 있을 수 있습니다.HOC를 몇 개 중첩하면 디버깅이 힘들 수 있습니다.WrappedComponent에 직접적으로 ref를 달 수 없어 우회 방법을 사용해야 합니다.비동기 작업과 같이 사용하다 보면 예상치 못한 결과를 만날 수 있습니다.하지만 이러한 단점에도 불구하고 상속을 제공하지 않은 리액트에서 HOC는 많은 문제를 효율적으로 해결해주는 단비와 같은 존재입니다. 유명한 리액트 라이브러리들(react-redux, redux-form 등)은 이미 예전부터 HOC를 사용해 사용자들에게 편의를 제공해 왔습니다. 이러한 라이브러리들과 자신의 프로젝트가 직면하고 있는 문제에 맞는 HOC를 작성해 같이 사용한다면 우아하고 아름다운 설계에 한층 더 다가간 프로젝트를 발견할 수 있습니다.마지막으로 한 문장을 남기고 본 포스팅을 마치도록 하겠습니다.React + Decorator + HOC = Fantastic!!본 포스팅은 2017 리액트 서울에서 발표한 내용입니다. 발표 자료와 발표 영상을 확인해보세요.#조이코퍼레이션 #개발자 #개발팀 #인사이트 #경험공유 #일지
조회수 4032

크몽 검색 기능 개선기

안녕하세요? 크몽의 백엔드 개발자로 활동하고 있는 에이든입니다. :)오늘은 크몽에 입사하고 한 달 동안 UX팀에서 진행한 검색 기능 개선에 대한 이야기를 해보려고 합니다.배경크몽에는 재능을 판매하는 프리랜서의 서비스 정보가 많이 저장되어있습니다. 판매하는 서비스 정보가 많을수록 검색 기능이 잘 되어있다면 사용자는 원하는 서비스를 빨리 찾을 수 있고, 프리랜서는 다양한 서비스를 의뢰인에게 판매할 수 있습니다.크몽에서는 사용자에게 정확한 검색으로 다양한 서비스를 제공하기 위해 노력하고 있습니다. 이번 글에서는 크몽 UX팀에서 보다 나은 검색 기능을 위해 어떠한 노력을 했는지 공유하고자 합니다.기존의 검색 기능기존의 검색 기능은 기본적인 키워드 검색 외에 별다른 기능을 제공하지 않았습니다. 그리고 스핑크스 검색엔진으로 구성되었습니다. 스핑크스는 전문 텍스트 검색 기능을 제공하며 데이터베이스와 잘 통합될 뿐만 아니라 스크립트 언어에 쉽게 접근할 수 있도록 설계되었습니다. 스핑크스의 동작 구조는 다음과 같습니다.스핑크스의 동작 구조Searchd는 클라이언트로부터 요청을 받고 스핑크스 인덱스에 대해 검색을 실행하는 역할을 합니다. 그리고 스핑크스 인덱서는 스핑크스 인덱스로 데이터를 가져오는 역할을 합니다.크몽은 이를 통해 사용자에게 검색 기능을 제공했습니다. 하지만 기존의 검색 기능은 불편한 점이 있었습니다.기존의 검색 기능의 불편한 점기존의 검색 기능은 의뢰인이 어떤 서비스를 필요로 하는지 본인이 정확하게 정의할 수 있어야 했습니다. 그게 아니라면 여러 키워드를 검색해보거나 원하는 서비스를 찾기 위해 해당 카테고리에서 서비스 전체를 둘러봐야 했습니다. 또한 많은 유료광고로 인해 사용자는 일반 서비스를 찾기가 힘든 문제가 있었습니다.기능상의 불편한 점뿐만 아니라 구현상에도 불편한 점이 있었습니다. 스핑크스에서 한글 검색을 구현하기 위해서는 복잡한 설정을 거쳐야 했으며 ngram analyzer를 통해서만 한글 형태소 분석이 가능했습니다. ngram analyzer는 음절 단위의 한국어 형태소 분석을 하므로 인덱스의 양이 많아질 뿐만 아니라 불필요한 정보까지 검색에 노출이 됩니다. 불필요한 정보가 노출되면서 종료율은 높아지고 서비스 상세페이지의 전환율이 낮아졌습니다. 또한 스핑크스는 데이터의 저장이 되지 않기 때문에 분석을 위해서는 별도의 과정이 필요했습니다.이에 크몽 개발팀은 사용자를 위한 검색 기능 보강뿐만 아니라 검색 엔진 변경이라는 결론을 내립니다.새로운 검색 기능새로운 검색 기능을 개발하기에 앞서 요구사항을 파악하고 새로운 검색 엔진에 대한 기술 탐색을 선행했습니다.프로젝트 진행 목적 및 요구사항정확한 검색 결과 제공광고 상품 제거를 통한 서비스 상세페이지로의 전환율 증대서비스 검색에 최적화된 검색 플로우무엇을 검색해야 할지 모르는 사용자를 위한 검색 가이드검색 엔진 및 한글 형태소 분석기 변경을 통해 사용자에게 정확한 검색 결과를 제공하는 게 우선순위였습니다. 그리고 광고 상품을 제거하고 사용자가 다양한 서비스를 찾을 수 있게 도와주는 기능을(자동완성검색, 연관검색어, 인기검색어) 추가했습니다. 그뿐만 아니라 서비스 검색에 최적화된 검색 플로우를 위해 UI 개선도 진행했습니다.새로운 검색 엔진새로운 검색엔진을 찾던 중 은전한닢 한글 형태소 분석기를 공식으로 지원하는 엘라스틱서치를 찾았습니다.17개 검색 엔진 순위 (출처: DB-ENGINES)17개 검색 엔진의 순위를 살펴보면 아파치 루씬 기반의 엘라스틱서치가 다른 검색 엔진보다 100점 넘게 차이 나는 압도적인 점수를 기록하고 있습니다. 위의 점수는 구글이나 빙에서 언급 횟수, 구글 트렌드, 기술적 논의 횟수, 채용 공고, 소셜 네트워크에서 언급 횟수 등으로 측정한 점수입니다. 점수 산정 방법이 객관적이지 못하지만 엘라스틱서치가 핫하다는 것에는 이견이 없었습니다. 이에 본격적으로 엘라스틱서치에 대해서 기술 탐색을 시작했으며 스핑크스와 비교도 해봤습니다.엘라스틱서치엘라스틱서치는 확장성이 뛰어난 RESTful 검색 및 분석 엔진입니다. 대용량 데이터를 빠르고 실시간으로 저장, 검색 및 분석할 수 있습니다. 기술 탐색 결과 엘라스틱서치에 저장한 데이터를 키바나를 통해서 분석하고 시각화할 수 있다는 점이 매력적이었고, 공식으로 한글 형태소 분석기를 지원하기 때문에 검색 정확도를 높일 수 있다고 생각했습니다. 한글 형태소 분석기를 이용한 엘라스틱서치의 분석 과정은 다음과 같습니다.한글 형태소 분석기를 이용한 엘라스틱서치의 분석 과정필드의 title에 블로그 검색에 엘라스틱서치를 적용해보려고 합니다. 라는 문장이 있다면 지정한 analyzer를 통해서 분석을 진행합니다. 먼저 문자 필터를 거치고 은전한닢으로 한글 형태소 분석을 수행합니다. 형태소 분석이 완료되면 [블로그, 검색, 엘라스틱, 서치, 적용, 보, 하]로 나누어집니다. 그리고 토큰 필터를 통해 [블로그, 검색, 엘라스틱, 일래스틱, elasticsearch, es, 서치, 적용, 보, 하]로 term이 만들어집니다. 이 term은 elasticsearch index에 문서 id와 함께 저장됩니다.다음은 엘라스틱서치와 스핑크스를 비교해봤습니다.엘라스틱서치 vs 스핑크스엘라스틱서치 vs 스핑크스엘라스틱서치와 스핑크스를 비교해보면 스핑크스도 충분히 좋은 검색엔진이지만 한글형태소 분석기와 키바나의 시각화, 데이터 분석 같은 장점을 활용하기 위해 엘라스틱서치를 도입하기로 했습니다.도입을 결정하고 엘라스틱서치를 구축하는 방법을 알아봤습니다.  1. 엘라스틱 클라우드를 사용하는 방법  2. AWS Elasticsearch Service를 이용해서 구축하는 방법3. EC2 인스턴스에 오픈소스 엘라스틱서치를 직접 설치해서 구축하는 방법   엘라스틱서치를 구축하는 방법에는 보통 3가지 방법이 있고 아래의 특징을 가지고 있습니다.1번은 엘라스틱에서 관리 및 교육, 컨설팅을 지원해줍니다. 그리고 한글 형태소 분석기 은전한닢을 지원합니다. 최신 버전의 엘라스틱 스택을 바로 사용할 수 있으며 모니터링 기능도 지원합니다. 라이선스 별 지원은 링크를 통해서 확인할 수 있습니다.2번은 AWS에서 제공하는 Elasticsearch Service이며, 관리형 서비스입니다. 같은 VPC에 묶여있는 인스턴스를 통해서만 접근할 수 있게 되어있으며 외부에서는 접근할 수 없습니다.(퍼블릭 액세스도 있으나 AWS에서 권장하지 않습니다.) 키바나를 사용하기 위해서는 같은 VPC의 인스턴스 웹 서버 프록시나 AWS 코그니토로 접근해야 합니다. 한글 형태소 분석기 은전한닢을 지원하지만 다른 플러그인은 지원하지 않는 경우가 많이 있습니다. AWS Elasticsearch Service에서 지원하는 플러그인 리스트는 여기에서 확인할 수 있습니다.3번은 EC2 인스턴스에 오픈소스 엘라스틱서치를 설치해서 사용하는 방법입니다. 직접 서버를 구축하는 방법이기 때문에 사용자가 어떻게 사용하느냐에 따라 달라집니다.크몽 개발팀은 가격, 관리적 측면을 고려한 결과 2번 AWS Elasticsearch Service로 구축을 진행했습니다.구현구현은 엘라스틱에서 라라벨 프레임워크에서 사용할 수 있는 엘라스틱서치 관련 라이브러리를 정리해둔 링크를 참고했습니다. 3개의 라이브러리 중 스타가 제일 많은 Plastic 라이브러리를 사용해서 구현을 시도한 적이 있었는데 몇 가지 장점이 있었지만 엘라스틱서치 5까지만 지원을 하므로 field type에 text, keyword가 존재하지 않아 매핑하는데 문제가 있었습니다. 그리고 아직 지원하지 않는 쿼리도 존재하기 때문에 결국에는 PHP 공식 엘라스틱서치 클라이언트 라이브러리인 Elasticsearch-PHP를 사용해야 되는 상황도 발생했습니다. 위에서 말한 점 때문에 Plastic 라이브러리를 걷어내고 Elasticsearch-PHP만 이용해서 개발을 진행했습니다. 엘라스틱에서 제공하는 Elasticsearch-PHP 가이드도 잘 정리되어있습니다. 더욱 자세한 구축, 구현 방법을 알고 싶으신 분들은 아래의 글에서 확인하실 수 있습니다.라라벨 프레임워크 - 엘라스틱서치 사용 경험기 : 초기 작업 수행라라벨 프레임워크 - 엘라스틱서치 사용 경험기 : 문서 관리 작업 수행결과검색 기능 개선 결과는 아래와 같습니다,1.자동완성검색자동완성검색 기능2. 연관검색어 + 검색 결과 광고 제거연관검색어 및 검색결과 광고 제거3. 키워드와 관련된 카테고리 추천키워드와 관련된 카테고리 추천4. 검색 결과가 없는 키워드에는 인기검색어 추천검색 결과가 없는 키워드에는 인기검색어 추천무엇을 검색해야 할지 모르는 사용자를 위한 검색 가이드를 만들기 위해 노력했으며, 기능 추가로 사용자의 검색 만족도와 정확도를 높이려고 노력했습니다.또한 엘라스틱서치와 한글 형태소 분석기 은전한닢을 이용해 검색 기능 개선을 통한 결과 평균 체류 시간은 20초 정도 증가했으며 종료율은 최대 22.4%, 평균 1% 정도 떨어졌습니다. 또한 서비스 상세페이지 전환율은 최대 78.3%, 평균 3% 이상 증가했습니다. 서비스 상세페이지 전환율의 상승은 사용자의 검색 만족과 검색 정확도가 상승했다고 볼 수 있습니다.정리이번 글에서는 엘라스틱서치와 한글 형태소 분석기 은전한닢을 이용해 검색 기능을 개선한 이야기를 정리해봤습니다. 검색 기능 개선 이후 서비스 상세페이지 전환율이 조금씩 상승 중입니다. 릴리즈한지 두 달 정도밖에 되지 않아 조금 더 지켜봐야 하겠지만 전환율이 조금씩 상승하고 있다는 건 좋은 신호인 거 같습니다. 다만 짧은 글을 통해서 경험을 전달하려고 하니 많은 내용을 담지 못한 것 같아 아쉽습니다. 다음에는 더욱더 깊이 있는 글을 전달할 수 있는 에이든이 되겠습니다. 감사합니다.#크몽 #개발팀 #개발자 #개발문화 #경험공유 #인사이트
조회수 913

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

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

기업문화 엿볼 때, 더팀스

로그인

/