스토리 홈

인터뷰

피드

뉴스

조회수 328

컴공생의 AI 스쿨 필기 노트 ⑤ 베이즈 결정이론

이번 5회차 수업에서는 베이즈 결정이론(Bayes Decision Theory)과 가우시안 혼합모형(Gaussian Mixture model)에 대해 배웠어요.1980년대 이후 세계 금융시장에서 위험관리를 계량화한 것은 확률이론, 그중에서도 ‘베이즈 정리’가 있었기에 가능했어요. 이전의 경험과 현재의 증거를 토대로 사건의 확률을 추론하는 알고리즘 덕분에 온갖 파생상품이 탄생했어요. 그런데 베이즈 정리는 오랫동안 금기시됐는데요. 주관적인 믿음을 측정하기 때문에 합리적이지 않다는 이유에서였다고 해요. 하지만 베이즈 정리의 활용도는 갈수록 커지고 있어요. 암호 해독부터 전쟁 중 의사결정, 실종된 사람이나 선박의 위치 추정, 암 발병률 예측, 스팸메일 걸러내기 등 무한대에 가깝다고 해요. 이번  필기노트에서는 베이즈 결정이론에 대해 알아볼게요.Bayes Decision Theory베이즈 결정이론은 패턴 인식을 위한 통계적 접근 방법이에요. 베이즈가 제시한 통계적 방법을 통해 의사 결정을 하는 방법이죠. 전통적 통계 방식은 통계적 추리를 할 때 표집으로 얻은 정보만 사용해요. 베이지안 확률이 전통적 통계 방식과 다른 점은 학습자가 기존에 가지고 있는 사전 정보를 활용한다는 것인데요. 불확실한 상황에서 통계적으로 얻은 정보를 가지고 의사 결정을 해야 하는 경제학, 경영학 등 여러 분야에서 많이 사용되고 있어요.베이즈 결정이론에 사용되는 베이즈 정리(Bayes rule)에 대해 간단한 예시를 들어볼게요.우리가 은행 지점장이라고 가정해봐요. 고객에게 돈을 빌려줄 수는 있지만 아무에게나 막 빌려줄 수는 없겠죠?그래서 은행 고객을 high-risk, 즉 돈을 빌려줘도 안 갚을 확률이 높은 고객과 low-risk, 즉 돈을 빌려주면 갚을 확률이 높은 고객으로 나눌 거예요.그런데 은행 고객이 돈을 갚을지 안 갚을지를 판단하는 기준이 있어야겠죠? 그래서 고객의 연봉(yearly income)과 현재 은행 계좌 보유금액(savings)을 가지고 판단할 거예요. 이렇듯 변수가 두 개만 있을 때 우리는 이항분포를 사용해서 의사를 결정해요. 위에서는 두 가지 고객이 존재하므로 이항분포를 사용해서 고객에게 돈을 빌려줄지 여부를 결정하죠. 결정을 내릴 때는 확률이 큰 쪽을 선택할 거예요. 확률이 큰 쪽을 선택하는 것은 이성적인 판단이기 때문이에요. 그래서 고객 x가 high risk일 확률(P(C=1|x)이 x가 low-risk일 확률(P(C=0|x)보다 크다면 1이라는 결정을 내리고, 작다면 0이라는 결정을 내려요.하지만 우리가 내리는 결정에도 error(=risk)가 존재하겠죠?확률의 합은 항상 1이고 결정은 항상 P(C=1|x)나 P(C=0|x) 중 확률이 큰 쪽이기 때문에 1에서 그 확률을 빼면 그 결정의 error가 돼요. 베이즈 결정이론은 이처럼 분류하고자 하는 물체들에 대해서 사전 정보가 주어지는 경우에 사용이 될 수 있는 이론이에요.Bayes’ rule베이즈 결정이론에는 베이즈 정리(Bayes’ rule)가 사용되는데요. 자세히 살펴볼게요.- P(C) : prior probability(선행 확률, 특정 사건이 일어날 것에 대한 추가 정보를 획득하지 못한 확률)로 여기서는 x가 어떤 값을 가지든 C가 1일 확률을 말해요.- p(x|C) : likelihood(우도, C가 주어졌을 때 조건부 확률) C가 주어졌을 때 x를 가지고 있을  확률을 말해요. 따라서 x값에 따라 확률이 달라져요. 예를 들어 p(x|C = 1) 은 C가 1인 즉 high risk인 고객이 x를 가지고 있을 확률을 나타내요.- p(x) : evidence(증거)는 C와 상관없이  x가 나타날 확률이에요.- p(C|x) : posterior probability(사후 확률)로 우리는 사후 확률을 기반으로 아래와 같이 decision을 내려요.위의 예시처럼 두 가지 고객만 있는 상황(이항분포)이 아니라 K명의 고객이 있는 경우(다항분포)는 어떻게 계산할까요? 이 경우에도 베이즈 정리가 적용되는데 식이 조금 달라져요.p(x) 구하는 식만 달라지고 나머지는 위에서 봤던 예시와 같아요. 그리고 이항분포의 error는 1에서 둘 중에 큰 확률을 뺐듯이 다항분포의 error도 아래와 같이 구해요.Loss and Risk위의 이항분포에서는 고객에게 돈을 빌려줌으로써 돈을 못 받는 손실(Loss)이 존재하고 돈을 못 받을 것 같은 고객에게 빌려주지 않음으로써 생기는 손실이 존재해요. 이 중 어떤 것이 더 손실이 적을지 생각해봐야겠죠?의사 결정을 하는 행동(action)을 αi라고 했을 때 αi에 대한 손실을 λik라고 정의할게요.위의 식은 예상되는 손실값이에요. 이 손실값은 실제로는 k인 상황이지만 행동 αi를 취해서 생기는 손실이에요.손실을 줄여야 하기 때문에 가장 작은 손실이 생기는 행동을 취해야 해요. 따라서 위의 식을 보면 argmin함수를 이용해서 k개의 행동 중 가장 작은 손실을 취해요.Reject 의사 결정이 어려운 경우에는 의사 결정을 피하는 것이 더 적절한 경우도 있어요. 이때는 어떠한 행동도 하지 않는 행동 αK+1을 추가해요.action αK+1을 추가하면 αK+1에 따른 손실 λik 또한 하나가 더 늘어요.위의 수식은 reject 행동을 포함했을 때 결정을 내리는 식인데 간단하게 참고하시면 될 것 같아요.이번에는 베이즈 결정이론에 대해 자세하게 다뤘는데요. 이번 수업은 교수님께서 많은 것을 가르쳐주셔서 저 같은 초보자가 듣기에 조금 힘든 점이 있었어요. 벌써 8주차 이론수업의 절반 이상이 지났는데요. 5주 동안 배운 많은 이론들을 코드로 능숙하게 표현하는 데에는 많은 노력이 필요하겠지만, 이만큼 왔다는 것만으로도 뿌듯한 기분이 들어요. 8주차부터 시작하게 될 팀 프로젝트에서 실력 발휘를 하기 위해서 더 열심히 수업에 임해야겠어요!* 이 글은 AI스쿨 - 인공지능 R&D 실무자 양성과정 5주차 수업에 대하여 수강생 최유진님이 작성하신 수업 후기입니다.
조회수 1785

연애의 과학의 미션

연애의 과학의 미션"우리는 사람들이 더 나은 연애를 하도록 돕는다"#1 연애: 왜 연애인가?연애는 정말 중요하니까요! 연인은 우리에게 가장 가까운 존재이자 내 행동과 감정을 결정하고, 나의 성장의 기폭제가 되기도 해요. 그래서 우리는 연애에 많은 시간과 관심을 들이고, 그만큼 연애가 우리 삶에서 물리적으로나 심리적으로나 큰 비중을 차지하게 되죠.무엇보다 '사랑하는 사람과의 관계'는 우리의 행복에 큰 영향을 미쳐요. 심지어 우리의 건강과도 관련이 있죠. 하버드 대학에서 75년에 걸쳐 사람들의 일생을 추적한 결과, 행복은 부나 명예, 혹은 열심히 노력하는 것에 달려있지 않았다고 해요. 우리를 건강하고 행복하게 만드는 것은 다름 아닌 '좋은 관계를 맺고 있는지' 여부였죠. 주변 사람들과 건강한 관계를 맺고 있는 사람들은 행복지수가 높았을 뿐 아니라, 노년기에 훨씬 더 건강했다고 합니다.“Good relationships keep us happier and healthier.” - Robert Waldinger#2 돕는다: 왜 도움이 필요한가?연애는 정말 복잡하고 어렵거든요! 하지만 대부분의 사람들은 그렇게 생각하지 않아요. 아래의 세 가지 사례들은, 연애를 너무 쉽고 단순하게 생각해서 발생하는 대표적인 문제들이에요.문제 사례 1: Naive RomanticismNaive Romanticism이란, 괜찮은 사람을 만나 사랑하기만 하면 관계에 아무 문제가 생기지 않을 거라는 믿음이에요. 그래서 관계에 문제가 생기는 원인은 그 사람이 이상해서, 아니면 그 사람은 괜찮지만 그 사람이 날 사랑하지 않아서, 혹은 둘 다라고 생각하곤 하죠. 혹시 연인하고 싸웠을 때 주변에서 이런 말 들어본 적, 많지 않나요?“그 사람 좀 이상한 사람이네!”“그 사람은 너를 별로 안 사랑하는 것 같은데?”그러나 아무리 괜찮은 사람을 만나도, 아무리 서로 사랑해도 연인 관계에서 문제는 생기기 마련이에요. 연애는 생각보다 훨씬 복잡하고 문제의 원인도 그리 단순하지 않은 경우가 많거든요. 한번도 싸우지 않아야만 좋은 관계인 것이 아니라, 싸웠을 때 그 상황을 현명하게 극복할 수 있는 것이 중요한 거죠!문제 사례 2: Naive RationalismNaive Rationalism이란, 친밀한 관계는 늘 합리적으로 작동한다는 믿음이에요. 예를 들어 누군가를 사랑하는 이유는 반드시 명확해야 한다거나, 연인 관계에서 누군가 손해를 보는 건 잘못됐다는 류의 생각들이죠. 즉 연인과 같은 친밀한 사이를 마치 합리적이고 공평한 거래 관계처럼 생각해서 발생하는 잘못된 믿음인 거예요.“내가 연애를 못하는 이유는 외모 때문이야.”“왜 내가 더 희생해야 돼?”하지만 사람과 사람의 관계는 항상 합리적으로 작동하지 않아요! 특히 친밀한 관계일수록 말이죠. 누군가와 사랑에 빠지고 그 관계를 이어나가는 과정은 매우 비합리적이기 쉬워요. 예컨대 외모가 별로거나 내 이상형과 어긋나는 사람인데도, 아주 사소한 순간을 계기로 호감을 느끼기도 하죠. 또 내가 연인에게 좀 져주거나 손해를 봤다고 해서 상대방도 날 위해 똑같이 희생해줘야 하는 것도 아니고요. 그렇게 계산적이고 합리적으로 작동하는 건 연인이 아니라 거래 관계일 뿐이에요.문제 사례 3: Naive Confidence마지막으로 Naive Confidence란 연애는 '하다보면 그냥 저절로 잘 되는 것'이라는 믿음이에요. 굳이 연애를 위해 뭔가를 배우거나 노력하지 않아도, 운명처럼 나와 정말 잘 맞는 사람이 나타난다면, 내가 진심으로 사랑하기만 하면 저절로 행복한 연애를 하게 될 거라고 믿는 거죠. 그래서 내 연애에 도움을 받을 수 있는 글 같은 건 따로 없다고 생각해요.“그냥 진심으로 대하면 되는 거지.”“언젠가 나랑 진짜 잘 맞는 좋은 사람이 나타날 거야!”“연애를 글로 배운다고?”그렇지만, 정말 중요하고 어려운 문제가 저절로 풀리는 걸 본 적 있나요? 끊임없이 고민하고 좋은 해결책을 찾기 위해 노력해야 될까 말까 하죠. 그 과정에서 당연히 조언이나 도움이 필요하구요. 그래서 우리는 연애의 과학을 통해 많은 사람들이 행복한 연애를 오래오래 할 수 있도록 돕고 싶고, 무엇보다 그게 정말 가치 있는 일이라고 생각해요!#3 우리: 왜 우리인가?정리하자면 연애는 정말 중요하고, 또 복잡하고 어렵기 때문에 도움이 필요해요. 그래서 연애의 과학 컨텐츠팀은 어떻게 하면 사람들의 연애를 더 잘 도와줄 수 있을지 고민 또 고민했어요. 그 결과 우리는 다음 세 가지 요소를 모두 갖춰야 한다는 것을 깨달았어요. 우리는 사람들의 행복한 연애를 돕기 위해, 신뢰와 인사이트, 그리고 실용성을 갖춘 컨텐츠를 만들고 그에 대한 탄탄한 지식과 노하우를 가지고 있죠!💪신뢰 : 글의 내용을 믿을 수 있는 컨텐츠아무리 인사이트가 깊고, 아무리 실용적인 내용이라도 신뢰할 수 없다면 결국 쓸모가 없겠죠. 우리의 미션은 사람들의 연애를 돕는 것인데, 만약 우리의 컨텐츠가 아무런 근거가 없는 내용이라면 과연 도움이 된다고 할 수 있을까요? 그러므로 ‘신뢰’는 연애의 과학 컨텐츠의 기본적인 조건이에요. 우리는 컨텐츠의 신뢰성을 확보하기 위해 심리학 논문을 바탕으로 최대한 객관적이고 논리적인, 그리고 충분한 근거가 있는 내용을 전달하려 노력하고 있어요.💡인사이트 : 연애와 관계에 대한 깊은 깨달음을 주며, 근본적인 관점을 변화시키는 컨텐츠생각이나 관점을 바꾼다는 건 단순히 새로운 정보를 하나 전달하는 걸로는 부족해요. 현상의 근본적인 원리와 매커니즘을 건드려야 하죠. 인사이트가 없는 컨텐츠는 그냥 사실을 전달하는 뉴스일 뿐이에요. 당연하고 뻔한 말이라고 느껴질 수 있고, “나는 아닌데?”라는 반응이 나오기 쉽죠. 그래서 우리는 누구나 말할 수 있는 당연한 이야기를 하고 싶지 않아요. 쉽진 않지만 피상적인 현상이 아닌 근본 원인을 알아내서, 사람들이 연애를 새로운 관점으로 바라볼 수 있게끔 하는 컨텐츠를 만들려고 하죠!👍실용성 : 내가 무엇을 해야할 지 명확히 알려주고, 관계에 실질적인 변화를 일으키는 컨텐츠신뢰와 인사이트가 좋은 글을 위한 기본 요소라면, 실용성은 그 좋은 내용을 내 삶에 실제로 적용할 수 있게 만드는 요소에요. 실용성이 없다면 “내용은 좋은데, 그래서 난 이제 어떻게 해야 하지? 뭘 하면 되지?”라는 생각이 들고 마치 딴 세상 얘기처럼 느껴질 수 있거든요. 그래서 우리는 논문에서 발견한 유용한 인사이트를 전달하는 것을 넘어서, 독자들이 직접 실천할 수 있는 구체적인 조언이나 팁도 함께 제시하고자 해요.그래서 연애의 과학 팀의 미션은"우리는 사람들이 더 나은 연애를 하도록 돕는다"에요.사람들이 연애의 과학을 통해 자신의 매력을 잘 발견하고 이해한다면, 두려움을 떨치고 솔직한 마음을 고백할 수 있게 된다면, 연애 초반의 롤러코스터를 잘 극복한다면, 서로가 어떤 사람인지 충분히 이해하고 결혼하게 된다면, 만족스러운 섹스를 오래오래 즐기게 된다면, 자기 자신을 더 깊게 이해할 수 있다면... 정말 의미있고 가치 있는 일 아닐까요?
조회수 2723

Top Ten Things to do in Seoul for Gamers

Whether you live in Korea or you finally planned a backpacking tour through Asia, Seoul is a must-see city for travelers interested in a unique culture, great food, and of course, K-pop. With so much to offer, many nerdy attractions are better known to locals and not often represented on popular tourist sites. Here is a list of 10 experiences Seoul has to offer for nerds, gamers, or anyone exploring the city. Video Game Alley Thousands of games to buy! Source: Kiss My Kimchi Although this sounds pretty self-explanatory, the alley is actually a basement in Yongsan filled to the brim with all types of video games imaginable. Not only can you find new games and old classics, they also have a lot of unique games only sold in Asia. This place is a must visit for any games enthusiast who wants to expand their collection.Location: Within Yongsan Electronics Market off Sinyongsan Station (Line 4)Retro Game Bar Tetris themed bar. Source: Retro Game Bar Want to enjoy games and drinks? This is the place for you. Come alone, with friends, or coworkers to watch livestream eSports games on TVs throughout the joint or challenge each other in video and tabletop games. RGB also hosts a variety of different events like DnD Sunday and FIFA Tournaments throughout the week. Even casual gamers will have fun drinking and enjoying other typical bar games like beer pong and darts.Location: 407-26 Seogyo-dong, Mapo-gu, Seoul, South KoreaLilyCat Cat Café Cute cats hanging out. Source: Facebook Cats, tea, and games, what’s not to like? In addition to adorable furry companions, LilyCat also has board games, making it one of the few board game cafés in Seoul. While sipping your drink and watching the cats jump and play, you can also rent out a variety of different board games to pass the time.Location: Myeongdong 2(i)-ga, Jung-gu, Seoul, South KoreaBANG The entrance to one of Seoul's many PC Bang. Source: Flickr Bang, which means “rooms” in Korean, are exactly what they sound like: rooms. These rooms have a variety of activities depending on the type of bang you visit. Most popular are PC Bang, which have speedy internet, lots of comfy chairs, and big screen TVs to game the day or night away. A few other variations include Cartoon Bang and PlayStation Bang, where you can read comic books or play FIFA with friends.Location: Spread out throughout SeoulVR Park Family enjoying the fun "ride." Source: VR Park Movie Company CGV and VR developers Barunson came together to bring you an amazing VR game experience in Yeongdeungpo Times Square. There you can spend hours on rollercoasters, playing the drums, and shooting a bow and arrow without actually going anywhere. What looks to be a theatre theater lined with seats and controllers, becomes an immersive experience for all ages.Location: 15, Yeongjung-ro, Yeongdeungpo-gu, Seoul, South KoreaCinema World Restaurant The outside of the restaurant and museum. Source: Facebook If you need your nerdy food fix, you may have to travel a couple hours south of Seoul over to Daegu. Here, you can find great food and an enormous collection of memorabilia from Marvel to Star Wars. The youthful collection was amassed by designer Woong Cho, who created the museum and filled it with small figurines, life-sized statues and everything in between. Go to the third floor to see the collection and then enjoy delicious food in the café or on the rooftop terrace.Location: 290 (Daeungpyeong-dong 437-1), Gyeongsan 712-130Seoul Animation Center The Center hosting an animation festival. Source: Wikipedia Cartoon characters are scattered across the path on the way to the entrance of this museum. The center includes a cartoon museum that showcases a themed exhibition hall and a room to build your own cartoon character. The library inside also has an expansive collection of animated films and books for visitors to watch, read and enjoy. The rest of the center shows animators at work and even lets you create your own Claymation video. All around, a great place for anime lovers.Location: 8-145 Yejang-dong, Jung-gu, Seoul 100-250, South KoreaConventions and Festivals Seoul Comic Con 2017. Source: Seoul Comic Con The ever popular “Cons” often come to Seoul to showcase what’s new in tech, games, and the industry as a whole. While they only come once a year, there is a high chance to catch one while in Korea. Boardgame Con hosts contests and other events centering on the best international board games while Pokémon World Festival celebrates everything Pokémon-related, especially Pikachu. Checking for events monthly can help you plan, which experiences you want to attend.Location: VariesSeoul Escape Room A cool poster for one of the escape room themes. Source: Seoul Escape While this isn’t exactly playable on your PS4, the escape room experience is a fun way to think through strategy and teamwork that you would have used playing League. Escape rooms have grown in popularity throughout the world and Seoul is not exempt. The premise is different depending on the escape room theme chosen, but you and a group of friends or strangers are put into a room and must solve riddles and follow clues within the time limit in order to escape. A fun blend of mystery, drama and stress will have you wanting to try all 17 rooms. Because many of the rooms must remain secret, you’ll just have to go Seoul and try one for yourself.Location: 156, Wausan-ro, Mapo-gu 3rd Floor, Seoul 04061, South KoreaLotte World An inside look into the famous Lotte World. Source: Wikipedia No top ten list in Seoul would be complete without mentioning Lotte World. The world’s largest indoor theme park is also home to an enormous arcade. Although there is nothing specifically unusual about this arcade, there are tons of games to play and its location inside Lotte World makes it worth visiting. You can explore rides and do some shopping as well. Another floor of Lotte also has the SBS Theme Studio where you can watch KIGL (Korean Internet Game League) and other internet gaming competitions. Well worth a visit!Location: 240 Olympic-ro, Jamsil 3(sam)-dong, Songpa-gu, Seoul, South Korea  Whether you live in Korea or you finally planned a backpacking tour through Asia, Seoul is a must-see city for travelers interested in a unique culture, great food, and of course, K-pop. With so much to offer, many nerdy attractions are better known to locals and not often represented on popular tourist sites. Here is a list of 10 experiences Seoul has to offer for nerds, gamers, or anyone exploring the city. Video Game Alley Thousands of games to buy! Source: Kiss My Kimchi  Although this sounds pretty self-explanatory, the alley is actually a basement in Yongsan filled to the brim with all types of video games imaginable. Not only can you find new games and old classics, they also have a lot of unique games only sold in Asia. This place is a must visit for any games enthusiast who wants to expand their collection.Location: Within Yongsan Electronics Market off Sinyongsan Station (Line 4) 
조회수 890

마케터를 위한 딥 링크 만들기

더 나은 사용자 경험 딥 링크(Deep Linking)는 사용자를 최종 목적지로 곧장 연결시켜 줍니다. 따라서 즉각적인(On-demand) 해결이 필요한 니즈를 가진 사용자일수록 딥 링크를 통해 복잡한 이동 과정을 생략할 수 있으며, 이는 더 나은 사용자 경험으로 이어집니다.광고에서 매력적인 상품을 발견한 사용자는 광고 클릭, 앱 설치, 앱 실행의 과정을 거치게 됩니다. 해당 상품에 대한 실제 정보는 앱 초기화면에서 검색을 거친 후에나 확인 가능합니다. 하지만 광고에 딥 링크가 적용되어 있으면 사용자는 앱 실행 후 곧바로 광고에서 봤던 상품으로 이동합니다. 따라서 딥 링크는 마케팅 메시지와 랜딩 페이지 사이의 일관성을 유지시키는 역할을 합니다.(딥 링크를 적용하여 마케팅 메시지와 랜딩 페이지의 일관성이 유지되며 최종 페이지로의 이동단계는 축소됩니다. 이를 통해 사용자 경험을 높일 수 있습니다.)딥 링크 찾기이 딥 링크 활용이 쉽지 않은 이유는 딥 링크를 어디에서 찾아야 할 지 알 수 없기 때문입니다. 딥 링크는 웹사이트 URL처럼 쉽게 확인할 수 없으며, 앱을 만들면서 자동으로 생성되지 않습니다. 그렇다면 딥 링크는 어떻게 만드는 것일까요?딥 링크 생성 프로세스를 단순화하면 다음과 같이 표현할 수 있습니다.마케터가 딥 링크 요청 -> 개발자가 딥 링크 생성 -> 마케터가 딥 링크 적용마케터는 앱 빌드를 하지 않기 때문에 딥 링크를 직접 만들기 어렵습니다. 결국 개발자의 도움이 필요합니다. 따라서 이 부분에선 두 번째 단계인 딥 링크 생성을 마케터가 알기 쉽게 설명하려고 합니다. 생성 작업을 알게 되면 개발자와 원활하게 커뮤니케이션 할 수 있고, 이를 통해 작업의 효율성도 높아질 것이라 기대합니다.딥 링크 만들기마케터의 요청을 받은 개발자가 딥 링크를 생성하기 위해 어떤 작업을 하게 되는지 작업 순서대로 설명 하겠습니다. 이해를 돕기 위해 안드로이드 기준으로 말씀 드리겠습니다.(1) 안드로이드 매니페스트와 액티비티“이 화면으로 연결되는 딥 링크를 만들어 주세요”라고 요청이 왔다고 가정하겠습니다. 개발자는 그 화면에 해당하는 액티비티(Activity)를 안드로이드 매니페스트(Android Manifest) 파일에서 찾습니다.안드로이드 매니페스트 파일은 앱의 모든 구성요소가 설명되어 있는 명세서라고 이해하시면 좋습니다. 앱에 어떤 기능을 만들어 놓았더라도, 안드로이드 매니페스트에 그 기능이 기술되어 있지 않다면 그 기능은 존재하지 않는 것과 마찬가지입니다. 따라서 딥 링크로 연결할 화면 역시 안드로이드 매니페스트에 존재하고 있으며, 개발자는 이 액티비티에 딥 링크를 지정하기 위해 안드로이드 매니페스트를 수정하게 됩니다.(2) 인텐트 필터 추가앱 입장에서 생각해 보면 인텐트 필터(Intent-filter)를 쉽게 이해할 수 있습니다. 가만히 있던 앱은 갑작스럽게 딥 링크를 통해서 앱의 특정 액티비티를 열어달라는 호출을 받게 됩니다. 호출 받은 입장에서는 어떤 의도(Intent)로 호출을 했는지 요약된(filter) 설명을 들을 수 있으면 좋겠지요. 인텐트 필터는 위와 같이 액티비티를 호출하기 위한 목적과 방법을 앱에 알려주는 역할을 합니다.개발자는 안드로이드 매니페스트에서 딥 링크로 연결될 액티비티를 찾은 뒤, 특정 딥 링크에서 호출이 오면 이 액티비티를 열면 된다는 명령을 미리 기술하게 됩니다. 위의 설명이 실제로 어떻게 구현되는지 예제를 보면서 확인하겠습니다.123456789101112131415161718192021222324<!-- 딥 링크로 호출할 액티비티 입니다 -->    android:name="com.example.android.GizmosActivity"    android:label="@string/title_gizmos" >    <!-- 인텐트 필터가 추가되었습니다 -->                                    <!-- "http://www.example.com/gizmos”라는 URI를 허용합니다 -->                     android:host="www.example.com"              android:pathPrefix="/gizmos" />        <!-- note that the leading "/" is required for pathPrefix-->                                       <!-- "example://gizmos”라는 URI를 허용합니다 -->                     android:host="gizmos" />   (Source: 구글 개발자 사이트)“com.example.android.GizmosActivity”라는 액티비티를 호출하기 위해 를 추가한 코드입니다.  항목은 화면 조회를,  항목은 브라우저에서 앱을 호출할 수 있도록 하는 역할을 하며, 딥 링크 구현을 위해서 기본적으로 포함되어야 하는 항목입니다.(3) 딥 링크 주소 생성 하위에  항목에서 딥 링크 주소를 ‘지정’할 수 있습니다. 없던 주소를 새로 만드는 것이기 때문에 주소에 어떤 문자열을 사용할지 지정해줘야 합니다. 일반적으로 개발팀 내부 규칙을 따르게 됩니다.딥 링크 주소는 보통 커스텀 URI, 커스텀 스킴 등으로 부릅니다. 예제에서 두번째  항복을 보면 scheme으로 example을, host로 gizmos를 지정하고 있습니다. 스킴과 호스트를 조합한 것이 딥 링크 주소로 사용됩니다. 예제의 경우엔 example://gizmos가 딥 링크 주소가 됩니다. 결과적으로 사용자가 example://gizmos URI가 적용된 광고를 클릭하면 “com.example.android.GizmosActivity” 화면이 호출되며 앱이 실행됩니다.보완책: DEFERRED DEEP LINK딥 링크는 앱의 특정 화면을 호출합니다. 하지만 앱이 없는 사용자가 광고를 클릭한다면 어떻게 될까요? 아무런 동작도 일어나지 않을 것이고 어렵게 확보한 클릭을 잃게 되는 결과로 이어질 것입니다. 이런 경우의 보완책으로 와이즈트래커는 지연된 딥 링크(Deferred Deep Link)를 채택하고 있습니다.위 그림에서 볼 수 있듯이, 앱을 설치한 사용자가 광고를 클릭하면 특정 화면이 호출된 상태로 앱이 실행됩니다. 앱을 설치하지 않은 사용자가 광고를 클릭하면 우선 앱 마켓으로 이동하게 되며, 사용자가 앱을 설치한 후 최초 실행시 딥 링크가 호출하려던 화면이 나타나게 됩니다.만약 지연된 딥 링크가 없다면 사용자 경험을 설계하는데 상당히 많은 경우의 수가 생깁니다. 당연히 캠페인 기획, 실행, 운영 시에 고려할 사항도 크게 늘어나게 됩니다. 따라서 딥 링크를 사용하기로 결정 했다면 와이즈트래커와 같은 3rd Party를 통해 더욱 고도화된 기능의 장점을 충분히 활용하시면 좋겠습니다.
조회수 1232

테이블이냐, 컬렉션이냐, 그것이 문제로다!(KOR)

편집자 주 외래어 표기법에 따르면 ‘원어에서 띄어 쓴 말은 띄어 쓴 대로 한글 표기를 하되, 붙여 쓸 수도 있다.’고 규정하고 있다.(제3장 제1절 영어의 표기, 제10항과, 컴퓨터 전문어, 전기 전문어 등) 즉 ‘원칙’과 ‘허용’이 모두 가능하다는 의미다. 이를 바탕으로 여러 표기 용례를 참고한 결과, TableView는 ‘테이블뷰(원칙)’로 표기해야 하나, 본문에서는 독자의 가독성을 높이기 위해 ‘테이블 뷰(허용)’로 표기한다. 응용하여, CollectionView는 ‘컬렉션 뷰’로, TableViewCell은 ‘테이블 뷰 셀’ 등으로 띄어 쓴다. Overview앱에서 데이터를 사용자에게 보여줄 땐 여러 가지의 모습으로 나타납니다. 설정 앱처럼 목록으로 보여줄 때도 있고, 사진 앱처럼 그리드(grid) 형식으로 보여줄 때도 있습니다. 이처럼 데이터를 보여줄 때 많이 사용되는 뷰는 테이블 뷰(UITableView) 또는 컬렉션 뷰(UICollectionView)입니다. 각자 특징이 있기 때문에 앱의 성격에 따라 적절한 뷰를 사용해야 합니다. 왜냐하면 목록을 보여주는 디자인을 바꿀 때, 다시 개발해야 하는 수고를 덜 수 있기 때문입니다. 이번 글에선 각각의 뷰를 간략하게 알아보겠습니다. 목록 형식의 설정 앱과 그리드 형식의 사진 앱 스크린샷테이블 뷰(UITableView)단일 열에 배열된 행을 사용해 데이터를 표시하는 뷰입니다. 수직 스크롤만 가능하며, 테이블의 개별 항목을 구성하는 셀은 테이블 뷰 셀(UITableViewCell) 객체입니다. 테이블 뷰는 이 객체들을 이용해 테이블에 표시되는 행을 그립니다. 여러 행은 하나의 섹션 안에 구성될 수 있으며, 각 섹션은 헤더(header)와 푸터(footer)를 가질 수 있습니다. 섹션과 행은 인덱스 번호로 구별하는데, 번호는 0부터 시작합니다. 테이블 뷰는 plain과 grouped 스타일 중 한 가지의 스타일을 가질 수 있습니다. Plain 스타일은 보통 목록 스타일입니다. 섹션의 헤더와 푸터는 섹션 분리기(inline separators)로 표시되고 스크롤을 할 때 해당 섹션 안에 있는 콘텐츠 위에 나타납니다. Grouped 스타일은 시각적으로 뚜렷한 행 그룹을 표시하는 섹션이 있습니다. 섹션의 헤더와 푸터는 콘텐츠 위에 나타나지 않습니다. 아래와 같은 사진을 보시면 확연히 차이를 볼 수 있습니다. plain 스타일의 연락처 앱과 grouped 스타일의 설정 앱테이블 뷰의 많은 메소드들은 인덱스패스(NSIndexPath) 객체를 매개변수 또는 리턴 값으로 사용합니다. 테이블 뷰는 해당하는 행의 색인 인덱스와 섹션 인덱스 값을 가져올 수 있게 인덱스패스의 범주를 선언합니다. 또한 색인 인덱스와 섹션 인덱스 값을 가지고 인덱스패스를 만들 수 있습니다. 특히 여러 섹션이 있는 테이블 뷰는 섹션 인덱스 값이 반드시 있어야 행의 인덱스 번호로 구별할 수 있습니다.override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> AttractionTableViewCell {         // Table view cells are reused and should be dequeued using a cell identifier.         let cellIdentifier = "AttractionTableViewCell"              guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? AttractionTableViewCell else {             fatalError("The dequeued cell is not an instance of AttractionTableViewCell.")         }                 let attraction = attractions[indexPath.row]                 cell.attractionLabel.text = "\(indexPath.row). \(attraction.nameWithDescription)"         cell.attractionImage.image = attraction.photo                 cell.attractionImage.tag = indexPath.row                 attraction.indexPath = indexPath                 ...                 return cell     } 위의 코드는 데이터 소스(data source) 메소드로, 테이블 뷰의 특정한 위치에 셀을 추가합니다. 다시 말해, 이 메소드는 테이블 뷰가 ‘표시할 새로운 셀이 필요할 때마다’ 특정 행에 노출할 정보가 있는 셀을 만들고 리턴하는 걸 말합니다. 매개변수로 필요한 셀 객체의 행을 가리키는 indexPath 값을 전달합니다. 그리고 indexPath의 row 값을 이용해서 attraction이라는 배열 인덱스로 활용하고, 셀에 표시할 정보들을 설정합니다. 여기서 attraction 배열은 관광 명소들의 정보들이 담고 있는 배열인데, 1행은 첫 번째로 저장한 관광 명소, 2행은 두 번째로 저장한 관광 명소 등 순서대로 설정하도록 indexPath.row 값을 이용하는 것입니다. indexPath의 row 값과 배열의 인덱스 값은 0부터 시작하기 때문입니다. 해당 예제는 섹션이 1인 경우이기 때문에 섹션 인덱스 값이 없지만, 섹션이 여러 개 있다면 반드시 섹션 인덱스 값을 이용해서 설정해야 합니다.테이블 뷰 객체는 데이터 소스(data source)와 델리게이트(delegate)가 필요합니다. 데이터 소스는 UITableViewDataSource 프로토콜을 구현해야 하고, 델리게이트는 UITableViewDelegate 프로토콜을 구현해야합니다. 데이터 소스는 테이블 뷰가 테이블을 만들 때 필요한 정보를 제공하고 테이블의 행이 추가, 삭제 또는 재정렬할 때 데이터 모델을 관리합니다. 델리게이트는 화면에 보이는 모습과 행동을 담당합니다. 예를 들어 표시할 행의 수, 사용자가 특정 행을 터치했을 때, 행의 재정렬 등과 같은 것입니다.override func numberOfSections(in tableView: UITableView) -> Int {         // #warning Incomplete implementation, return the number of sections         return 1     }      override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {         // #warning Incomplete implementation, return the number of rows         return attractions.count     } 위의 두 소스는 데이터 소스가 필수적으로 구현해야 하는 메소드입니다. 하나는 섹션의 개수를 리턴하고, 또 하나는 한 섹션 안에 있는 행의 개수를 리턴합니다.테이블 뷰는 수정 모드에서 행을 추가, 삭제, 재정렬할 수 있습니다. 각 행은 테이블 뷰 셀에 연관된 editingStyle에 따라서 추가, 삭제, 재정렬을 할 수 있는데, 예를 들어 editingStyle이 insert라면 추가하는 메소드를 실행하고, delete면 삭제하는 메소드를 실행합니다. 행의 showsReorderControl 속성이 true라면, 재정렬하는 메소드를 실행할 수 있습니다.// Override to support editing the table view.     override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {         if editingStyle == .delete {             // Delete the row from the data source             ...                 // delete rows and attractions and reload datas             attractions.remove(at: indexPath.row)             tableView.deleteRows(at: [indexPath], with: .middle)             tableView.reloadData()         } else if editingStyle == .insert {             // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view         }     } 위 소스는 editingStyle이 delete일 때 셀을 삭제하고 테이블 뷰를 다시 로드하는 기능을 구현한 것입니다.테이블 뷰를 만드는 가장 쉽고 권장하는 방법은 바로 스토리보드에서 테이블뷰컨트롤러(UITableViewController)를 이용해서 만드는 겁니다. 런타임에 테이블뷰컨트롤러는 테이블 뷰를 만들고 델리게이트와 데이터 소스를 자기 자신으로 할당합니다.컬렉션 뷰(UICollectionView)컬렉션 뷰는 테이블 뷰에서 할 수 있는 모든 것을 할 수 있습니다. 섹션을 가질 수 있고, 인덱스패스 값을 이용해서 셀을 구별합니다. 이 셀들은 컬렉션 뷰 셀(UICollectionViewCell)의 서브 클래스이며 데이터 소스(UICollectionViewDataSource)와 델리게이트(UICollectionViewDelegate)가 필요합니다. 셀을 추가, 삭제, 재정렬하는 기능도 구현할 수 있습니다. 그렇다면 컬렉션 뷰와 테이블 뷰를 구분하는 특징은 무엇일까요? 바로 레이아웃입니다. 컬렉션 뷰는 여러 개의 열과 행으로 셀을 표현할 수 있습니다. 예를 들어, 그리드(grid) 형태로 아이템의 목록을 보여줄 수 있습니다. 그래서 수직 스크롤뿐만 아니라 수평 스크롤도 할 수 있습니다.스토리보드에서 디자인한 테이블 뷰 셀과 컬렉션 뷰 셀위 스크린샷에서 테이블 뷰와 컬렉션 뷰의 가장 큰 차이는 바로 셀입니다. 테이블 뷰에서는 하나의 열에 여러 행을 표시하는 형식이기 때문에, 셀의 모습을 행에 맞춰서 디자인합니다. 하지만 컬렉션 뷰는 열과 행을 만들 수 있기 때문에, 꼭 행의 모습이 아니더라도 다양한 모습으로 셀을 디자인할 수 있습니다. 컬렉션 뷰 셀의 가장 큰 특징이기도 하죠. 위처럼 셀을 디자인하고 앱을 실행하면 아래의 화면이 나타납니다.테이블 뷰와 컬렉션 뷰의 앱 화면 차이또한 컬렉션 뷰는 레이아웃 객체가 있습니다. 기존에 제공하는 flow layout을 사용해도 괜찮지만, 본인이 원하는 레이아웃 모양을 custom layout을 만들어서 사용합니다. 이를 담당하는 프로토콜은 UICollectionViewDelegateFlowLayout 입니다.func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {         let fullWidth = collectionView.frame.size.width - (self.CGFLOAT_INSET_WIDTH * 3) - (self.CGFLOAT_ITEMSPACING * 3)         let width = fullWidth/3         return CGSize(width: width, height: width + self.CGFLOAT_HEIGHT_ATTRACTIONCELL_DEFAULT)     }         func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {         return UIEdgeInsetsMake(self.CGFLOAT_LINESPACING_VERTICAL, self.CGFLOAT_INSET_WIDTH, self.CGFLOAT_LINESPACING_VERTICAL, self.CGFLOAT_INSET_WIDTH)     } 위 소스에서 collectionView(:layout:sizeForItemAt:) 메소드는 해당하는 셀의 사이즈를 설정하고, collectionView(:layout:insetForSectionAt:) 메소드는 섹션 안에 margin을 설정합니다.여러 모양의 셀을 이루어 하나의 뷰 화면을 구현할 수도 있습니다. 섹션마다 셀을 만들어 각각 다른 모습의 셀을 설정하고, 한 화면에 다양한 모습의 셀을 가진 뷰를 만드는 것입니다. 예를 들어, 헤더, 메뉴, 본문, 푸터 각각 셀을 만들어서 원하는 모양으로 만들고, 하나의 뷰 컨트롤러에 셀을 조합해서 한 화면에 나타나게 할 수 있습니다. 이 방법을 사용하면 자주 사용하는 셀을 재활용할 수 있습니다. 똑같은 헤더와 푸터 셀을 여러 번 만들지 않고 기존의 셀을 재활용하면 시간도 절약하고, 훨씬 깔끔한 소스를 만들 수 있을 겁니다.브랜디 앱 스크린샷 일부위의 스크린샷처럼 여러 화면에서 보여줘야 할 똑같은 뷰가 있을 때, 셀 xib 파일을 만들고 컬렉션 뷰에서 셀을 섹션별로 설정 및 사용하면 재활용하기 좋습니다.Conclusion지금까지 테이블 뷰와 컬렉션 뷰의 특징들을 살펴봤습니다. 한마디로 정리하면 테이블 뷰는 가장 간단한 목록을 만들 수 있습니다. 컬렉션 뷰는 다양한 모습의 목록으로 커스터마이징(Customizing)할 수 있습니다.그렇다면 우리는 어떤 것을 선택해야 할까요? 구현할 목록이 얼마나 복잡한지에 따라 선택은 달라집니다. 테이블 뷰는 간단하고 보편적인 목록을 만듭니다. 반면에 컬렉션 뷰는 특정한 모습의 목록을 만들 수 있습니다. 그래서 테이블 뷰는 목록이 간단하고 디자인 변경이 없을 때만 사용하길 권장합니다. 하지만 나중에 디자인이 바뀔 수도 있다면 컬렉션 뷰를 사용하는게 더 좋겠죠.Simple is the best! 간단하게 구현할 수 있는 건 테이블 뷰를 사용합시다. 테이블 뷰에서 구현하기 힘들다면 컬렉션 뷰를 이용해 개성 있는 목록을 마음껏 만들어봅시다!참고UITableView - UIKit | Apple Developer DocumentationUICollectionView - UIKit | Apple Developer Documentation 글김주희 사원 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발문화 #개발팀 #업무환경 #인사이트 #경험공유
조회수 962

다큐멘터리 제작 조연출에서 마케터로

스푼을 만드는 사람들 2편, 정상인은 한 명도 없다는 한국 마케팅 팀원들 중 한 명인 겉보기엔 굉장히 평범해 보이지만 독특하고 특이한 반전 매력이 넘치는 2년 차 마케터 '썸머 or 써머' 를 소개하고자 한다. (누군가는 그녀를 썸머라고 하고또는 써머라고 부르기에)아귀찜 사진 출처: 해먹남녀별명이 왜 '하아구' 인가요?본명 성이 '하'씨 + 아귀찜을 너무 좋아해서사실 외관상 서머를 보면 (편견이 가득 담겼지만) 곱창, 아귀찜, 축구 그리고 동동주와는 거리가 멀 것만 같아 보였다. 그 누구보다 도시적으로 보이고 세련됐달까? 그런 그녀가 가장 좋아하는 음식은 '아귀찜' 그리고 알고 보니 누구보다 털털한 성격의 소유자였다. 심지어 집에 막걸리 만드는 재료도 있고, 예전에 '막걸리 서포터스'를 했었을 만큼 막걸리를 좋아한다고 한다.Q. "이번 마케팅팀 회식 때 가장 먹고 싶은 음식은 뭔가요?""아, 저 정말 육회 탕탕이가 너무 먹고 싶어요. 아 아귀찜도! 아 아니 간장게장?! 기대된다!"닉네임이 'Summer'인 이유 1. 좋아하는 미드 'THE O.C'에 나오는 주인공 이름2. 발랄하고 활기찬 그 주인공이 마음에 들어서(마케팅팀엔 여름과 관련된 친구가 두 명이나 있다. Summer, Sunny 그것도 바로 옆자리..)마케터가 되기까지Q. 썸머는 다큐멘터리 제작사 조연출에서 교직원까지 다양한 경력이 있으시네요?"저는 사실 마케터가 되는 건 꿈이 아니었어요. 제 꿈은 원래 '영화감독'이었답니다. 하루에 한 편 이상 영화를 볼 정도로 영화를 좋아했고, 대학 졸업과 동시에 제작사에서 조연출로 1년 정도 근무했었어요. 제가 생각했던 진로와는 많이 다르다는 것을 깨달았어요. 그리고 대학교 교직원으로 전환을 했었는데, 생각보다 너무나도 같은 일상이 반복되다 보니 무기력해지는 모습을 발견했어요. 그렇게 저에게 더 원동력을 줄 수 있는, 바쁘고도 빠르게 트렌드를 따라가야 하는 직업인 마케터로 진로를 바꿨어요."Q. 어떤 업무를 하고 계시나요? 그리고 스푼 마케터로서의 삶은 어떤가요?"저의 업무는 주로, 콘텐츠를 기획해서 제작하는 업무를 해왔어요. 최근에는 하나의 큰 프로젝트를 진행하고 있고, 퍼포먼스 마케팅을 주로 했지만 브랜딩 쪽에 관심이 많아서 브랜딩 관련 업무도 차근차근 준비하고 있어요. 마케터로서의 삶은 늘 도전적이라고 생각해요. 마케터로서의 삶은 행복하기도 하고 힘들기도 해요. 제가 스스로 알지 못했던 저의 부족한 모습들을 알게 되고, 저의 괜찮은 모습들도 알게 되는 것 같아요. 제 스스로가 다듬어지는 과정을 함께 하고 있다는 느낌을 받아요, 배우는 것도 정말 많고요."Q. 콘텐츠는 어디서 영감을 받아서 제작하시나요?"저는 보이는 모든 것들이 저에게 영감을 준다고 생각해요. 길을 걷다가, 쇼핑을 하다가 또는 지하철에서도 문득 영감을 받을 때가 있거든요. 또는 유저 콘텐츠를 자주 들으면서 콘텐츠 아이디어가 떠오르기도 하고요."Q. 마케터가 된 후 혹시 변한 점이 있다면?"관련 서적을 참 많이 읽게 되었다는 점이에요. 마케터 전공자가 아니다 보니, 마케팅에 대해 지식도 많이 필요하고 노력도 해야 하다 보니 자연스레 읽게 되는 점과, 'Why'라는 질문을 많이 하게 되었다는 점이에요."Q. 스푼을 어떻게 브랜딩 하고 싶으세요?"우리 어릴 적에 기억나세요? 버디버디라던지.. 세이클럽 등등, 정말 딱 바로 생각나는 추억의 브랜드이잖아요. 물론 앞으로 50년 100년 쭉쭉 스푼이 추억이 아닌 현재의 브랜드가 되리라 믿지만, 한마디로 누군가 어떤 한 시대를 이야기할 때 바로 나올 수 있는 그런 핫하고도 마스코트가 될 수 있는 브랜드로 만들고 싶어요. 그 정도로 인지도가 높은! 그런 서비스요."당신의 회사생활이 궁금합니다Q. 한국 마케팅 팀원들에게 바라는 것이 있다면?"저는 아직도 배우는 중이에요. 제가 몰랐던 것들 그리고 고치고 변해야 할 점들도 스스로도 많이 깨우치려고 하고 배우려고 하는데 아직 다듬어지는 중이라 느리지만 노력 중인 저를 조금만 더 기다려주시고 응원해주셨으면 좋겠어요."(응원할게요 썸머! 열심히 하고 있다는 거 알고 있어요)Q. 입사 후 가장 기억 남는 에피소드는?"작년에 기획 수업을 들은 적이 있어요. 그때 제가 이 수업 끝에 꼭 이루었으면 좋겠다 하는 리스트가 있었는데, 그중에 하나가 제가 만든 콘텐츠로 성과를 내는 거였는데, 정말 그 수업 끝에 좋은 콘텐츠가 제작되었고 광고 성과도 좋았거든요. 그 날이 정말 뿌듯하고 성취감을 느낀 날이에요."Q. 내가 가장 좋아하는 회사 복지제도는?"어버이날, 부모님께 드리는 용돈이 나왔는데 그게 정말 인상 깊었어요. 그날 엄마가 말씀해주신 말이 떠올라요! 정말 좋은 회사에 다니고 있다고..!!!!!"Q. 어떤 사람들과 일하고 싶으세요?타인의 의견을 잘 경청할 줄 알고, 서로에게 인사이트를 줄 수 있는 사람이면 좋겠어요. 서로 신뢰를 가지고 믿고 일할 수 있는 그런 관계요. 꼭 회사에서만 보고 마는 그런 관계가 아닌, 진솔된 관계를 맺을 수 있는 소통이 가능한 사람과 일하고 싶어요. 무엇보다! 스푼이라는 서비스를 좋아하고 관심 있는 사람이면 좋겠어요.이모티콘 수집가 썸머 당신의 사생활이 궁금합니다.Q. 2019년 계획이 어떻게 되세요?"어, 새로 이사를 하게 되었는데요. 무사히 이사를 마치고 새로운 곳에서 새로운 마음으로 시작하고 싶어요! 그리고 개인 Vlog로 시작하고 싶고, 스푼 공식 계정 Vlog도 시작할 예정이에요."Q. 본인을 한 마디로 표현하자면?어린아이 - 저는 의외로 순진하고, 순수하거든요. 늘 궁금한 게 많기도 하고 동심을 잃고 싶지 않아서요.Q. 축구를 왜 그렇게 좋아하시죠?"전에 만난 모든 남자 친구들이 축구를 좋아했답니다... 그러다 보니 자연스럽게"Q. 늘 책상에 먹을 것들이 잔뜩 쌓여있는데 대체.. 왜죠?"저는 모든 친구들도 다 알 정도로, 음식을 습관처럼 쌓아두는 편이에요. 물건도 잘 버리지 못하는 성격이고요. 그렇다 보니 제 책상에 보면, 많은 간식들이 쌓여있어요ㅋㅋㅋ.. 저를 참 잘 아시는 듯.."한국 마케팅 팀원들이 썸머를 한마디로 표현한다면?Sunny 曰: 레드벨벳 아이린 - 내 눈엔 닮았음 Jay 曰: 물놀이하는 아이 - 그냥 느낌이 ㅎ ('ㅎ'자 정말 좋아하시는 분 )Ted 曰: 구름 - 하얗고 맑은 이미지라서Ringo 曰: 하얀 튤립 - 청순하고 여리여리한 한편에..많은 걸 풍성하게 담고 있는 모습 때문에 볼 때마다 그냥 연상됨요..Jakie 曰: 꼬부기 - 물속성 타입 같아서..
조회수 4175

[Tech Blog] Go 서버 개발하기

Go 서버 개발을 시작하며   특정 API만 다른 언어로 구현해서 최대의 성능을 내보자! 저희 서버는 대부분 Django framework 위에서 구현된 광고 할당 / 컨텐츠 할당 / 허니스크린 앱 서비스 이렇게 나눌 수 있는데 Python 이라는 언어 특성상 높은 성능을 기대하기가 어려웠습니다. 하지만 세가지 서비스에서 락스크린에서 어떤 컨텐츠나 광고를 보여줄지 결정하는 Allocation(할당) API 가 가장 많이 호출되고 있었는데 빈도로 보면 80% 정도로 높은 비중을 차지하고 있어서 이 Allocation API 들을 성능이 좋은 다른 언어로 구현하면 어떨까 하는 팀내 의견이 있었습니다. Why Go? 저는 예전부터 Java,  C# 등의 컴파일 언어에 익숙해서 기존 Java 와 C, 그리고 Go 라는 최근에 새로 나온 언어 중에서 아래 블로그글과 같이 여러 reference 들을 통해 성능이 좋다는 Go 로 이 API 들을 포팅하는 작업을 시작하게 되었습니다. Go 에 대한 첫 인상은 Java, C계열 언어보다 덜 verbose 보였고 python 보다는 strongly-typed, encapsulated 하다보니 자유도를 제한해서 코드를 보기 쉽게 하는 것을 선호하는 저의 성격과도 잘 맞는 언어였습니다.     출처: Carles Mateo, Performance of several languages서버 개발 환경   Server design How to import libraries  GVT (https://github.com/FiloSottile/gvt) – Go 는 vendering tool 을 통해 dependency 를 관리할 수 있습니다. GVT 의 경우 처음 도입했을 때 별로 유명하지 않았는데 사용법이 간단해서 도입하게 되었습니다. 아래와 같이 참조하고 있는 revision 을 관리해주며 update 통해서 최신 소스를 받아 올수 있습니다.   { "version": 0, "dependencies": [ { "importpath": "github.com/Buzzvil/go-env", "repository": "https://github.com/Buzzvil/go-env", "vcs": "git", "revision": "2d8489d40184a12c4d09d09ce1ff717e5dbb0745", "branch": "master", "notests": true }, ....  Design pattern  Go 언어에서는 package level cycling dependency 를 허용하지 않아서 좀더 명확한 구조를 만들기 좋았습니다. 예를들어 Service 에서는 Controller 를 참조할수 없고 Model 에서는 Controller / Service / DTO 등을 참조할수 없도록 강제했습니다. 모든 API 요청은 Route 를 통해 Controller 에게 전달되고 이 때 생성된 DTO (Data transfer object) 들을 Controller 가 직접 혹은 Service layer 에서 처리하도록 하였고 DB 에 접근할 때는 모델을 통해 혹은 직접 접근하도록 했지만 추후 구조가 복잡해지면 DB 쿼리 등을 담당하는 DAO (Data access object) 를 도입할 계획입니다   Libraries                  요소이름선택 이유NetworkGinWeb 서버이다 보니 네트워크 성능을 최우선으로 고려, 벤치마크 표를 보고 이 라이브러리를 선택Redis & cachego-redis역시 성능을 가장 중요한 지표로 보고 이 라이브러리 선택MysqlGormORM 없이는 개발하기 힘든 시대이죠. 여러 Database를 지원하고 ORM 중에서도 method chaining 을 사용하는 Gorm 을 선택Dynamoguregu dynamoAWS에서 제공하는 Dynamo 패키지를 그대로 사용하면 코드 양이 너무 많아지고 역시 method chaining 을 지원해서 선택Environment variablescaarlos0 envGo 에서는 tag 를 이용하면 좀더 코드를 간결하고 읽기 쉽게 사용할수 있는데 이 라이브러리가 환경변수를 읽어오기 쉽도록 해줌   Redis cache  func SetCache(key string, obj interface{}, expiration time.Duration) error { err := getCodec().Set(&cache.Item{ Key: key, Object: obj, Expiration: expiration, }) return err } func GetCache(key string, obj interface{}) error { return getCodec().Get(key, obj) }  Mysql  var config model.DeviceContentConfig env.GetDatabase().Where(&model.DeviceContentConfig{DeviceId: deviceId}).FirstOrInit(&config)  Dynamo if err := env.GetDynamoDb().Table(env.Config.DynamoTableProfile).Get(keyId, deviceId).All(&profiles); err == nil && len(profiles) > 0 { ... }  Environment variables  var ( Config = ServerConfigStruct{} onceConfig sync.Once ) type ( ServerConfigStruct struct { ServerEnv string `env:"SERVER_ENV"` LogLevel string .... } ) func LoadServerConfig(configDir string) { onceConfig.Do(func() {//최초 한번반 호출되도록 env.Parse(&Config) } }    Unit test   환경 구성 Test 환경에는 Redis / Mysql / Elastic search 등에 대한 independent / isolated 된 환경이 필요해서 이를 위해 docker 환경을 따로 구성하였습니다. Test case 작성은 아래와 같이 package 를 분리해서 작성했습니다.  package buzzscreen_test var ts *httptest.Server func TestMain(m *testing.M) { ts = tests.GetTestServer(m) // 환경 시작 tearDownElasticSearch := tests.SetupElasticSearch() tearDownDatabase := tests.SetupDatabase() code := m.Run() // 여기서 작성한 TestCase 들 실행 // 환경 종료 tearDownDatabase() tearDownElasticSearch() ts.Close() os.Exit(code) }  Mock server는 은 http.RoundTripper interface 를 구현해서 http.Client 의 Transport 멤버로 설정해서 구현했습니다. 아래는 Test case 작성 예제입니다.  httpClient := network.DefaultHttpClient mockServer := mock.NewTargetServer(network.GetHost(MockServerUrl)) .AddResponseHandler(&mock.ResponseHandler{ WriteToBody: func() []byte { return []byte(mockRes) }, Path: "/path", Method: http.MethodGet, }) clientPatcher := mock.PatchClient(httpClient, mockServer) defer clientPatcher.RemovePatch()  Unit test 관련해서는 내용이 방대해서 추후 다른 포스트를 통해 자세히 소개하도록 하겠습니다.  Infra API 요청 분할 AWS Application load balancer 여러 API 중에서 할당 API 를 제외한 요청은 기존의 Django 서버로 요청을 보내고 할당요청에 대해서만 Go서버로 요청을 보내도록 구현하기 위해 먼저 시도 했던 것은 AWS Application load balancer (이후 ALB) 였습니다. ALB 의 특징이 path 로 요청을 구별해서 처리할수 있었기 때문에 Allocation API 만 Go 서버 로 요청이 가도록 구현했습니다.  출처: Amazon Devops Blog, Introducing Application Load Balancer   하지만 이렇게 오랫동안 서비스 하지 못했는데 그 이유는 서버 구성이 하나 더 늘어나고 앞단에 ALB 까지 추가되다 보니 이를 관리하는데 추가 리소스가 들어가게 되어서 어떻게 하면 이러한 비용을 줄일수 있을까 고민하게 되었습니다.   Using docker & nginx  Go로 작성된 서버가 독립적인 Micro service 냐 아니면 Django 서버에서 특정 API 를 독립시켜 성능을 강화한 모듈이냐 의 정체성을 두고 생각해봤을때 후자가 조금더 적합하다보니 Go / Django 서버는 한 묶음으로 관리하는 것이 명확했습니다. Docker 를 도입하면서 nginx container 가 proxy 역할을 하고 path를 보고 Go container / Django container 로 요청을 보내는 구성을 가지게 되었습니다.  글을 마치며   시작은 미약하였으나 끝은 창대하리라 하나의 API를 이전했음에도 불구하고 Allocation API 에 대해서는 약 1/3, 서버 Instance 비용은 1/2.5 수준으로 감소했습니다.   설명: 기존 4개의 Django 인스턴스의 CPU 사용률이 모두 13% 정도 감소, Go 인스턴스의 CPU 사용율은 17% 정도   17 / (13 * 4)  ≒ 1 / 3  충분히 만족할만한 성과가 나와서 그 뒤로 몇가지 API도 Go 로 옮겼고 새로 작성하는 API 는 Go 환경 안에서 직접 구현하는 중입니다. 처음에는 호출이 많은 하나의 API 를 다른 언어로 포팅하기 위해 시작한 작업이었는데 Container 기술을 도입하는 등 서버 Infra 까지 변경하면서 상당히 큰 작업이 뒤따르게 되었습니다. 하지만 이 작업을 하면서 많은 동료들의 도움과 조언이 있었고 결국 완성할수 있었습니다. 이렇게 실험적인 도전을 성공 할수 있는 환경에 여러분을 초대하고 싶습니다! Go언어에 대한 문의나 좋은 의견도 환영합니다.
조회수 1762

iOS Graphic Interface 살펴보기 (1/2)

1.intro: 애정하는 iOS, 애증의 Xcode프론트엔드 개발자가 가장 기쁠 땐 언제일까요? 여러 가지가 있죠. 직접 만든 스무스한 애니메이션을 볼 때, 고생해서 작업한 하드코어 고난도 레이아웃이 잘 작동할 때, 작업한 화면을 사람들이 ‘예쁘다ʼ고 말해줄 때 등등. 그러므로 iOS는 모든 프론트엔드 개발자가 동경하는 OS라고 말할 수 있습니다. 대부분의 굵직한 Transition들을 알아서 Animate해주고, 프레임레이트가 복잡한 레이아웃 효과도 부드럽게 표현해주기 때문에 ‘예쁘다ʼ, ‘쾌적하다ʼ는 말이 절로 나오는 OS이기 때문이죠. 물론 그만큼 손도 많이 갑니다. 사실 iOS는 신기한 점이 많습니다. Xcode를 사용하다 보면 Interface Builder에서 ctrl+드래그를 사용하여 Code로 Reference를 가져오는 방법부터 String값으로 찾아가는 Xib/StoryBoard 파일까지.. 다른 플랫폼 및 IDE에서는 겪어보지 못한 새로운 경험들을 만나죠. 덕분에 다년차 개발자의 멘탈도 Xcode-iOS를 만나면 탈탈 털립니다. 시간이 지나면 이 독특하고도 불편한 Xcode를 사랑하고, 저주하는 상황까지 생깁니다.그래서 오늘은 많은 iOS 루키들이 겁내고 괴로워하는 iOS의 Graphic Interface를 살펴보고자 합니다. 맨땅에 헤딩할 때 헬멧이라도 쓰고 있으면 그나마 덜 아프니까요.2.Point, PixelAndroid에서는 다양한 기종의 스크린을 지원하기 위해 자체적으로 dp라는 수치 개념을 만들어 사용합니다. 파편화된 디바이스들을 모두 지원하는 레이아웃을 구성하려고 고안한 효율적인 방법이죠. iOS에도 이와 같은 개념이 있습니다. 바로 포인트(Point)인데요. Xcode의 ImageAsset 파일을 열면 이런 것을 찾을 수 있습니다. 1X, 2X, 3X바로 이 화면에서 볼 수 있는 1x,2x,3x라는 문구가 포인트 개념을 설명하고 있습니다. 포인트는 디바이스의 물리적 픽셀을 2배, 3배로 압축해 사용하는 iOS 만의 독특한 단위입니다. 이 개념이 처음 쓰인 건 iPhone 4, 즉 레티나 디스플레이가 등장하면서부터 인데요, 기존의 iPhone 3Gs와 물리적 화면 크기는 동일한데, 4배의 픽셀 수를 가지는 레티나 디스플레이에 기존의 앱들을 그대로 보여주자니 픽셀 단위로 정의된 기존의 모든 이미지/레이아웃이 절반 크기로 줄어드는 문제가 발생했습니다. 따라서 별도의 작업 없이 디스플레이하기 위한 방법으로 고안된 게 바로 포인트입니다.포인트는 픽셀을 2배, 3배로 압축해 1포인트라는 단위로 규정하고, 그 단위를 Nib(Xib) 에디터 및 개발 과정에서 사용합니다. 앞으로 여러분이 iOS 개발을 하면서 접할 기본 단위는 바로 포인트가 될 겁니다. 2X 혹은 3X는 단어는 픽셀을 2배, 3배로 압축했다는 의미입니다. 개발자의 편의를 위해서 만들어진 개념이 오히려 개발자에게 혼동을 주는 아이러니한 상황이 펼쳐졌습니다. 사실 이 픽셀-포인트의 개념이 처음 등장했을 때는 꽤 편리했을 겁입니다. 당시만 해도 iPhone4와 iPhone3Gs의 해상도를 구분하지 않고 작업할 수 있는 획기적인 방법이었으니까요. 하지만 지금은 iPhone5, iPhone7 Plus, iPhone X 등 다양한 장비들이 등장했습니다. 그래서 iOS 개발자는 포인트를 단지, 픽셀의 또 다른 이름처럼 느낄 뿐입니다. 애플도 자신들이 이렇게 다양한 해상도의 iPhone을 출시하게 될 줄은 몰랐을 겁니다.애플의 해상도 춘추전국시대 / 출처: paintcodeapp3.Storyboard, Nib (Xib)iOS UI 디자인의 꽃이 무엇인지 묻는다면 그것은 단연 Storyboard와 Xib일 것입니다. Storyboard는 기획자들이 사용하는 그것과 유사한 개념입니다. 하나의 큰 틀에 화면 단위로 여러 장의 기획안을 놓고, 그것들의 시퀀스를 한 눈에 알아볼 수 있도록 하는 보드입니다.Storyboard는 Segue와 같은 시퀀스 설정을 직접 할 수 있고, 연결된 하나의 Flow를 시각적으로 펼치기 좋습니다. 프로토타이핑을 위한 적절한 툴인 셈이죠.UIStoryboard 예시 - 브랜디 iOS의 Main StoryboardNib(혹은 Xib, 이하 Xib로 지칭)는 조각조각 단위의 화면이나 재활용을 많이 하는 CollectionViewCell 등의 화면 작업에 적합합니다. 이 점이 Storyboard와는 다르죠. (CollectionViewCell에 대한 자세한 포스팅은 여기를 클릭하세요.)물론 Storyboard에서 할 수 있는 작업은 대부분 Xib로도 가능하지만, 각각의 용도를 다르게 해서 사용하는 경우가 많습니다. 예를 들어, 브랜디 iOS 프로젝트는 Storyboard에선 큰 틀의 화면을 다루고, Xib에서는 CollectionView Cell과 ReusableView, Custom Component등을 다루고 있습니다. UICollectionViewCell.xibStoryboard와 Xib로 인터페이스 작업을 할 때는 파일의 컨텐츠가 너무 비대해지지 않도록 조심해야 합니다. Storyboard가 비대해지면 많은 작업자가 동시에 파일을 수정할 수도 있는데, VCS를 사용하면서 Storyboard나 Xib 파일의 충돌이 발생하면 병합하는 과정이 매우 고통스럽습니다. 그러므로 Storyboard는 서로 충돌하지 않도록 더 큰 그림을 그리고, 해당 Storyboard를 Senior 개발자가 관리할 수 있도록 안전장치를 두도록 합시다. 야 이거 소스 건드린 사람 나와 Storyboard와 Xib는 기본적으로 XML 기반의 파일입니다. 혹시라도 충돌이 발생하면 UI로 확인이 불가능하기 때문에, Xcode에서 해당 Storyboard, Xib 파일을 우클릭한 후 Open As > Source Code 메뉴를 클릭하면 XML 형식으로 브라우징할 수 있습니다. 해당 충돌 부분을 찾아가서 수정하고 다시 확인하면 UI로 볼 수 있습니다.소스코드로 스토리보드 보기4.From Storyboard, to CodeStoryboard와 Xib에서 구현한 컴포넌트들을 ViewController의 SourceCode에서 다룰 일이 분명 생길 겁니다(언제나 그렇죠). 그럴 땐 Outlet이라는 개념을 이용해서 Storyboard 와 SourceCode를 연결하는데요.네, 코드가 아닙니다. 포토샵하는 기분으로 ctrl + 마우스 좌클릭 드래그를 해주시면 됩니 다. 이 기능은 다른 IDE에서 보기 힘든 건데요. 나름 쓸만합니다. 익숙해지면 여러 가지 컴포넌트, 유닛들을 Outlet으로 처리할 수 있습니다. 코딩을 자유롭게 할 수도 있고요. 예를 들어, LayoutConstraint를 Outlet으로 처리하면 해당 Constraint를 코드 시퀀스에 따라 자유자재로 변경할 수 있게 되는 것처럼 말이죠.물론 이보다 선행되어야 할 작업은 Storyboard에서 해당 ViewController가 연결될 ViewController를 지정하고, 해당 ViewController의 파일을 미리 만들어야 합니다.5.Extraction of ViewControllerStoryboard에서 ViewController A를 연결했는데, ViewController B 에서 ChildViewController로 ViewController A 를 사용하고 싶다면 어떻게 할 수 있을까요? (간장공장공장장) 당연한 이야기지만 코드를 통해 구현 가능합니다. 필요한 것은 Storyboard 파일명과, Storyboard에서 미리 지정한 ViewController A 의 Identifier, 두 가지입니다. Storybo/rd에서 ViewController A를 연결했는데, ViewController B 에서 ChildViewController로 ViewController A 를 사용하고 싶다면 어떻게 할 수 있을까요? 당연한 이야기지만 코드를 통해 구현 가능합니다. 필요한 것은 Storybo/rd 파일의 이름과, Storybo/rd에서 미리 지정한 ViewController A 의 Identifier, 두 가지입니다. instantiateViewController From Storyboard/**  현재 화면에 디스플레이중인 UIWindow 객체로부터 UITabBarController를 반환받는 메  소드  - parameter window: UIWindow  - returns: UITabBarController */ fileprivate func tabBarControllerFromStoryboard() -> BRTabBarController {  let storyBoard = UIStoryboard(name: "mainStoryboard", bundle: nil let viewController = storyBoard.instantiateViewController(withIdentifier: "mainTabBarController") return viewController as! BRTabBarController  // 잘못된 viewController를 추출한 경우 nil exception } 비슷한 방법으로 Xib에 작성된 View도 추출할 수 있습니다. Xib파일 하나에 여러 View가 정의되어 있다면, 각각의 View를 필요에 따라서 사용할 수도 있습니다.Extraction From Xiblet nib = UINib(nibName: NSStringFromClass(BRDropdownSelector.self) let components = nib.components(separatedBy: ".").last!, bundle: nil) let view = components.instantiate(withOwner: nil, options: nil).last as! BRDropdownSelector  // 잘못된 view를 추출한 경우 nil exception 6.LayoutConstraints For Flexible UI더 유연한 레이아웃 동작을 원한다면, Static하게 선언된 수치보다는 LayoutConstraint로 제한적 범위 안에서 유동적으로 동작할 수 있도록 View를 주물러 주는 게 좋습니다. 예를 들어, 어떤 두 컴포넌트 사이의 최대 너비를 100으로 지정하되, 컨텐츠 사이즈에 따라 더 작아질 수도 있도록 하려면, LayoutConstraints의 Less than or Equal기능을 사용하는 것처럼 말이죠.Less than or equalLess than or Equal뿐만 아니라 Greater than or Equal도 존재합니다. 상황에 맞게 사용하는 지혜가 필요하죠. LayoutConstraint에는 Multiplier라는 개념도 있습니다. 만약 컴포넌트 A 절반 너비의 컴포넌트 B를 작성하고 싶다면, 그리고 이 조건이 화면 크기와 관계없이 동일하게 적용되기를 원한다면, 컴포넌트 B의 너비를 컴포넌트 A와 동일하게 Constraint로 지정하고, Multiplier를 0.5로 지정하면 됩니다. Multiplier는 단어 그대로 ‘배수ʼ라는 의미입니다.이처럼 화면 해상도에 구애받지 않는 유연한 UI를 작성하고 싶다면 LayoutConstraint 의 사용은 필수입니다. 브랜디 iOS 앱이 다양한 해상도의 iOS 디바이스에서 동일한 비율 로 출력되는 것도 이러한 LayoutConstraint를 사용했기 때문이죠.7.View를 핸들링할 그곳앞서 정리한 방식들을 사용해서 Storyboard, Xib 파일을 훌륭하게 작성했다면, 이제는 ViewController의 소스코드로 돌아올 차례입니다. View Size를 이벤트에 따라 변경하거나, 숨겼던 View를 보여주는 등의 작업들을 할 차례입니다.Storyboard나 Xib에서 작업한 View를 코드 상에서 다룰 일은 많습니다. 99.78% 이상 ViewController에서 View를 다루어야만 하죠. 무조건입니다.viewDidLoad() 에서 View는 대부분의 초기화 작업을 합니다. 그것은 소스코드를 다루는 개발자에게도 마찬가지죠. Storyboard에서 연결한 Outlet들도 이 Function에서부터 nil값이 아니게 됩니다. 따라서 뷰에 필요한 초기화 작업 (Button의 Title 지정, ImageView의 이미지 지정 등) 을 viewDidLoad()에서 모두 하면 됩니다. viewDidLoad()는 그 이름처럼 ViewController가 생성되었을 때 단 한 번 호출됩니다. 다시 거치지 않는 코드이기 때문에 ViewController에서 사용할 변수들을 초기화하는 등의 작업도 이 자리에서 할 수 있습니다. viewDidLoadoverride func viewDidLoad() {      super.viewDidLoad()     /* do 초기화 in 여기 */ } 다만 여기서 아무리 해도 안 되는 작업이 있습니다. View 사이즈를 해상도에 맞게 변경하는 작업 같은 것 말이죠. LayoutConstraint를 통해 지정된 사이즈를 가져올 때, 화면을 꽉 채우도록 Constraint를 지정해도 로그를 찍으면 엉뚱하게 더 적은 값 이나 큰 값이 나올 수도 있습니다. 이런 경우에는 아무리 viewDidLoad()에서 열심히 Constraint의 값을 가져와도 결과가 똑같을 겁니다.개미지옥override func viewDidLoad() {      super.viewDidLoad()     // 백년동안 코딩해도 화면 해상도가 다르게 나와요 } viewWillAppear() 에서는 viewDidLoad()에서 작동하지 않던(?) 코드를 적용할 수 있는 자리입니다. Constraint들로 지정된 사이즈들은 viewWillAppear()에서부터 각 디바이스의 해상도에 맞게 적용됩니다. 여기서부터는 화면 크기에 맞춘 SubView들의 사이징이나 Constarint들로부터 추출한 값이 의미가 있습니다.viewWillAppearoverride func viewWillAppear() {     super.viewWillAppear()     // 이제 아마 화면이 나올 차례인가봐요 } viewDidAppear()는 출력된 화면에 실행할 코드를 작성하는 자리입니다. 화면이 등장한 이후 보여줄 팝업창이나, 튜토리얼을 출력하는 건 여기서 해야 합니다. viewWillAppear()는 예상되는 출력 화면에서 호출되기 때문에, 실제로는 화면이 없는 상황에서도 호출될 수 있습니다. 만약 해당 viewController의 출력이 확실히 완료된 후 에 실행되어야 하는 이벤트라면, 이 Function에서 코드를 작성해야 합니다. viewDidAppearoverride func viewDidAppear() {     super.viewDidAppear()     // 화면 출력이 끝났답니다. 마음껏 코딩하세요! } 네, 지금까지 루키들을 위한 GUI 만들기의 기본 과정은 다 알려드렸습니다. 많은 개념과 기능, 방법론이 존재하지만 일단 이 정도면 알아도 첫 번째 iOS 앱 UI를 만들 준비는 어느 정도 마친 겁니다. 그럼 마지막으로 UI를 구성하면서 유용하게 사용할 수 있는 팁을 알려드리겠습니다. 8.Little Tricks1) Clip it, or not Clip it.ImageView를 다루다 보면 자주 발생합니다. 지정된 ImageView의 사이즈보다 이미지가 크면 이미지가 ImageView의 영역을 빠져나가버리는 건데요. 이것은 Label이나 View에서도 동일합니다. 작성한 컨텐츠가 부모 View보다 큰 경우 부모 View의 프레임을 벗어납니다. 이런 경우, 재부팅하세요. clipsToBounds 값을 true로 지정해주면.. view.clipsToBounds = true 매-직! 이 작업은 코드뿐만 아니라 Storyboard상에서도 가능합니다. Xib에서도 동일합니다. Storyboard에서 클리핑2)Circular View요즘 많이 사용하는 동그라미 모양 프로필 이미지 때문에 고생하는 고심하는 개발자들이 많을 겁니다. iOS에서는 이 작업을 view의 Layer를 편집하는 방식으로 아주 간단하게 처리할 수 있습니다.self.layer.cornerRadius = self.frame.size/2.0 self.layer.masksToBounds = true self.clipsToBounds = true 위의 코드를 사용하면 아래와 같은 이미지를 출력할 수 있습니다.둥글게 클립핑된 최신 트렌드의 ImageView를 간단하게 출력했습니다. 물론 위에서 언급한 clipsToBounds 값을 true로 지정해주는 것도 잊지 마시고요. 이 코드를 응용하면 모서리가 둥근 직사각형 뷰도 만들 수 있습니다. 원하는 곡률을 적용할 수 있죠. view의 Layer를 다루는 방법을 공부한다면 다양한 상황에서 유용하게 사용할 수 있을 겁니다.3)NSAtrributedString 클라이언트가 다양한 형태의 Font, Color의 텍스트를 한 문장에 넣어달라고 한다면 어떻게 작업해야 할까요? 스타일마다 Label 묶음을 만들어서 각각의 단어를 지정해주는 방법이 있습니다. 하지만 텍스트 또는 문장 구성이나 스타일이 서로 다른 묶음으로 변경된다면 어떨까요? 또 다시 새로운 기준으로 Label 묶음을 만들어야 할까요? 이럴 때 사용하기 좋은 녀석이 바로 NSAttributedString입니다. 볼드체, 보통체가 혼합된 텍스트에 색상이 다른 텍스트가 혼재되어 있는 Attributed String이렇게 다양한 형태의 텍스트를 한 문장에 담을 수 있고, 변경되는 내용이 있더라도 코드로 간단하게 수정하면 됩니다. 브랜디 앱에서도 NSAttrributedString을 많이 사용하고 있습니다. 브랜디 iOS 앱의 간지나는 UI 속 요소요소를 차지하고 있는 중요한 녀석이죠. 4)Debug Wirelessly 각종 케이블이 난잡하게 널부러진 책상을 보면 한숨이 나옵니까? 걱정하지 마세요. 이제 하나는 줄일 수 있을 겁니다. Xcode로도 무선 디버깅을 할 수 있기 때문이죠. 먼저 디바이스를 맥에 연결하고, Xcode가 활성화된 상태에서 Window > Devices And Simulators 항목을 클릭합니다. Devices and Simulators그런 다음 출력된 화면에서 원하는 디바이스를 선택하고 Connect via Network를 체크 합니다. (디바이스에 암호가 설정되어 있어야 합니다.) 지구본 모양이 디바이스 오른쪽에 있다면 무선 디버깅이 가능한 상태입니다. 무선디버깅체크9.Outro: 긴 글을 마무리하며아장아장 걸음마 시절이던 첫 개발 프로젝트 작업이 생각납니다. 클라이언트는 끝도 없이 요구를 하는데 구현하는 방법을 몰라 막막했던 적이 많았습니다. 여러 실수를 겪고 나서야 많은 것을 알게 되었죠. 그때를 생각하면 이제 막 iOS 개발을 시작하는 분들께 하나라도 더 도와주고 싶답니다. 지금 막 iOS 개발자가 되었나요? 그렇다면 이 포스팅은 분명 당신의 검색 한 번, 실수 한 번을 줄여줄 수 있을 겁니다.글이정환 과장 | R&D 개발1팀[email protected]브랜디, 오직 예쁜 옷만#브랜디 #개발자 #개발팀 #인사이트 #경험공유 #iOS
조회수 735

유통 공룡 아마존의 홀푸드 인수와 아마존고

책 장사로 시작해서 유통 공룡, 그리고 이제 클라우드 서비스로 발전한 아마존의 도약은 놀랍기만 합니다. 지난 2017년 6월에는 아마존이 유기농 식료품 체인 ‘홀푸드’를 인수해서 유통시장에 큰 파장을 가져왔는데요, 언론들은 아마존의 식품시장 진출로 인한 식품유통시장 변화와 막강 라이벌을 맞이할 월마트의 반응에 주목했습니다.아마존이 홀푸드를 인수한 후에 아마존의 주가는 급등했지만 경쟁사인 월마트, 코스트코 등은 일제히 하락을 했습니다. 그만큼 아마존의 식품시장 진출에 시장에서는 많은 기대를 한다는 반증이겠지요?아마존은 오프라인 매장에 ‘아마존 고’라는 무인시스템을 사용해서 인력을 줄이겠다는 전략이었지만 얼마 전 ‘아마존 고’ 매장을 현재로서는 더 늘릴 계획이 없다고 발표를 하였죠. 무인시스템 매장에 대한 고객들의 반응을 관찰해보는 기간이 필요한 것이 아닐까 추측해봅니다. 고객들도 적응하는 데는 시간이 필요하니까요.그동안 아마존이 괄목할만한 성장이 이루면서 핵심가치로 삼은 것은 ‘절약’과 ‘효율성’이기 때문에 직원의 행복과 만족을 중요시하는 홀푸드의 조직문화가 아마존의 문화와 조화를 이루기 위해 어떻게 변화되고 자리를 잡아나갈지 그 또한 관심을 가지고 지켜볼만한 점인 것 같습니다.더욱 재미있는 것은 한 때 아마존의 경쟁자들이었던 백화점 유통업체들이 아마존이 홀마트를 인수하는 것을 보면서 홀마트처럼 자신들도 아마존의 러브콜을 받아 부진을 극복해보기를 바라는 곳들도 생겨났다는 점입니다. 시장은 항상 변하기 마련이지만 '이윤창출' 보다는 '고객 편의와 확보를 통한 시장 확장'에 비중을 두는 아마존의 엄청난 성장은 어쩌면 당연한 것인지도 모르겠습니다.
조회수 3103

KBS 분야별 업무소개 - 방송경영

한때 방송사에서 ′경영′이라는 단어가 생소했던 시절이 있었습니다. 몇 개의 방송사가 방송 시장을 과점하고 있었기 때문에 재원은 여유가 있었고, 방송사간의 경쟁은 큰 의미를 주지 못했습니다. 당시에는 프로그램을 ′제작′하고 뉴스를 ′보도′하는 것만이 방송사의 활동이었습니다. 그러나 방송 환경이 과거와는 비교되지 않을 정도로 변한 지금, ′경영′을 빼놓고는 방송을 말할 수 없습니다. 종합편성채널, CATV, 위성방송, 인터넷 등 지상파방송의 지위를 위협하는 많은 매체들이 방송시장에서 경쟁을 부추기고 있습니다.KBS 역시 이 경쟁에서 자유로울 수 없습니다.우수한 프로그램이라 하더라도 효율성과 경제성을 바탕으로 제작하지 않으면 누구도 방송사의 생존을 보장하지 않습니다. ′방송사를 경영하는 것′,  다시 말해 ′조직의 비전을 제시하고 자원을 효율적으로 집중하고 배분하는 역할을 하는 것′이 '기획행정'의 존재이유입니다. 우리는 가장 가까이에서 방송을 바라보고 있습니다.KBS는 한국을 대표하는 공영 방송이며 영국의 BBC, 일본의 NHK 등 세계 일류 공영 방송과 어깨를 나란히 할 수 있는 방송입니다. 세계 방송의 흐름을 읽고 국내 방송 환경을 개척하며 한국방송을 굳건히 세우는 일. 또 5년 후, 10년 후의 KBS를 조망하고 바람직한 방송 위상을 확립하는 일. 여러분이 정책을 기획하고 조직과 예산을 관리하는 기획예산국과 같은 곳에서 일하게 된다면 여러분은 KBS의 미래로 밤잠을 설칠 수도 있을 것입니다. ′기획행정′은 방송과 함께 합니다.뛰어난 방송 제작을 위해 재원을 마련하고 인력과 물자를 적절히 배분 하는 일이 그것입니다. 대시청자서비스를 담당하며 시청자 제일주의를 실현하는 시청자권익보호국, 공영방송의 소중한 재원인 수신료를 관리하는 수신료정책국, 업무처리의 타당성을 점검하는 감사실, 인력채용·운영과 제도 전반을 다루며 인재를 육성하는 인적자원실, KBS의 주요 정책을 개발하고 예산 및 계열사·지역국을 관리하는 기획예산국, 광고국, 자산을 관리하고 직원 급여 및 후생복지, 제작비, 결산·세무를 담당하는 총무국 등 한정된 자원으로 최적의 최선의 노력을 기울이고 있습니다. ′기획행정′은 방송 제작의 일선에서도 그 역할을 충실히 수행하고 있습니다.방송국은 물론 방송을 만드는 곳입니다. 하지만 방송의 이면에는 한 컷의 화면을 위해 온갖 정성을 아끼지 않는 엔지니어, 카메라맨, 디자이너, 작가, 세트제작요원, 분장사, 오디오맨, 효과맨 등 수많은 사람들이 함께 하고 있습니다.′기획행정′은 이러한 다양한 분야의 전문가들을 방송이라는 정점에서 어우르는 역할을 하고 있습니다. 편성운영부, 보도운영부, 콘텐츠운영부, 라디오운영부, 제작리소스운영부 등은 방송 현장에서 제작자들과 호흡을 같이 하고 있습니다.  KBS, 디지털 이성과 아날로그 감성이 맞물리는 곳사회는 생산성과 효율성에 입각한 정글의 법칙만이 존재하고 있습니다. 일상에 얽매여 자신보다는 조직의 논리에 갇히기 쉽습니다. 사회인이 된다는 것은 스스로의 생계를 유지하는 것 뿐만 아니라 사회 속에서 자신의 가치를 실현하고 존재의 의미를 확인하는 일입니다. KBS는 최소 투자, 최대 이익의 실현이라는 경영의 논리를 바탕으로 기업을 운영한다는 점에서는 사기업과 같지만 국가기간방송으로서 방송의 이념과 목표를 더욱 소중히 하는 곳입니다. 원리원칙을 지키는 디지털 경영이 KBS의 경영 목표지만, 구성원들이 아날로그의 개성과 장점을 마음껏 구현할 수 있도록 그 토대를 마련해 주는 곳이기도 합니다. KBS는 여러분을 향해 두 팔을 활짝 펼치고 있습니다!선택은 여러분의 몫입니다. #한국방송공사 #KBS #KBS공채 #직무정보 #직무소개
조회수 1915

제니퍼에서 새로운 가능성을 실험하라

제니퍼는 기업 내부망에 설치되는 On-Premise 방식의 소프트웨어 제품이다. 12년 넘게 국내 점유율 1위를 지키고 있는 제품이다보니 그만큼 고객의 요구사항도 다양하다. 대부분의 솔루션 회사는 제품 개발 초기에 단일 소스코드를 유지하며 개발하는 것을 추구했을 것이다. 하지만 비즈니스를 하다보면 특정 고객을 위한 기능을 추가할 수 밖에 없는 상황이 오게 된다. 보통 이런 경우에는 숨겨진 기능으로 개발하거나 고객사 별로 소스코드를 다르게 가져가기도 한다.기존의 제니퍼를 사용하는 고객들은 애플리케이션 모니터링만이 아닌 브라우저나 스마트폰 같은 클라이언트 영역과 데이터베이스 관리 시스템까지 연계된 통합 모니터링을 하고자하는 요구사항을 오랫동안 요청했었다. 모니터링 제품 간의 연계를 생각하면 약간 생소하게 생각할 수 있는데, 특정 데이터를 수집하고, 이를 가공하여 사용자에게 보여주는 단순한 매커니즘의 하나라고 생각하면 이해가 쉬울 것 같다.즉, 다른 종류의 데이터를 하나의 화면에서 볼 수 있는 통합 환경을 제공해야 한다. 그래서 최근에는 오픈소스로 배포되고 있는 엘라스틱서치나 상용 제품인 스플렁크 같은 로그분석 솔루션이 주목받고 있다. 하지만 위와 같은 제품들을 사용하여 제니퍼 성능 데이터와 연계하여 통합 환경을 구축한다는 것은 말처럼 간단하지 않다. 제품을 구매하고 학습하는 비용이 생각보다 크고, 통합을 위한 별도의 시스템이 갖춰져야 한다는 것은 고객의 입장에서 큰 부담이 된다. 이러한 부담을 덜어주기 위해서 제니퍼는 실험실이라 불리우는 확장 기능을 제공한다. 실험실은 워드프레스의 플러그인과 비슷한 성격을 가지며 코드 레벨 영역에서 확장될 수 있다. 실험실은 처음부터 다른 모니터링 제품과의 연계를 위해 개발된 것은 아니었다. 기획 초기에는 방대한 제니퍼 데이터를 좀 더 다양한 형태의 화면으로 제공하기 위함이었는데, 아무래도 실험적인 요소가 강하다보니 기존의 대시보드나 분석 같은 범주로 들어가기에는 완성도 측면이나 제니퍼의 방향성에 영향을 미칠 수 있다는 판단에 별도의 범주로 만들게 되었다.  실험실이란 이름은 구글 메일의 실험실에서 따온 것인데, 아직 개발 중인 실험적 기능을 위한 테스트 공간이고, 언제든지 변경 또는 중단되거나 사라질 수 있다. 그리고 모든 실험실 소스코드는 깃허브를 통해 공개하는 것이 기본 정책이다. 제니퍼소프트 깃허브에 가보면 실제로 다수의 실험실 프로젝트가 존재한다는 것을 알 수 있다. 그 중 한가지만 간략하게 소개하자면 사용자 관점의 웹 서비스 모니터링 제품인 아르고스와 연계하여 브라우저나 스마트폰 같은 사용자 관점의 성능 데이터를 제니퍼 트랜잭션 데이터와 연계하여 분석할 수 있는 기능을 제공한다. 실은 그동안 고객들에게 사용자 관점의 성능 모니터링에 대한 요구사항이 많았지만 제니퍼 본연의 영역과 확연하게 다른 측면이 있어서 요구사항을 수용하는데 많은 고민이 필요했다. 그래서 우리는 관련된 솔루션 업체를 찾았고, 상호 간의 비즈니스 협력을 통해 서로의 부족한 부분을 보완하기로 결정했다. 실험실은 제니퍼가 시도하고 있는 새로운 기능을 미리 체험해 볼 수 있을 뿐만이 아니라 오픈소스나 관련된 솔루션과의 연계를 하기 위한 화면을 제공할 수 있다. 뿐만 아니라 코드 레벨 영역에서 확장을 하는 것이다보니 제품의 커스터마이징 범위가 넓어진다. 즉, 화면에 대한 고객의 요구사항이 제니퍼의 방향성과 크게 다르더라도 많은 고민을 하지 않고 충분히 원하는 것을 구현해줄 수 있다. 과거와 달리 동일한 데이터라도 좀 더 시각적인 화면을 요구하는 요즘같은 시기에 실험실은 이러한 시도를 하기에 좋은 방법이 된다.제니퍼는 화면 단위의 확장 기능인 실험실 뿐만이 아니라 트랜잭션 데이터가 수집되는 시점이나 특정 이슈가 발생할 때, 생성되는 이벤트 데이터를 어댑터를 통해 전달받을 수 있다. 어댑터도 실험실과 마찬가지로 코드 레벨 영역에서 확장할 수 있다. 실시간으로 전달받은 트랜잭션 데이터는 별도의 스토리지에 저장하여 목적에 맞게 조회해서 사용할 수 있다. 특히 이벤트 관련 어댑터는 가장 많이 사용되는 제니퍼 확장 기능이며, 고객사의 관제시스템 연동에 주로 사용된다.  실험실은 어댑터와 달리 제니퍼 서버에서 전달받은 데이터를 처리만 하는 단순한 구조가 아니었다. 제니퍼와 독립적인 화면 구성에 필요한 모든 요소들을 갖춰야했기 때문에 고려해야할 것들이 너무 많았다.  그럼에도 불구하고 만들게 된 이유는 단순히 필자의 편리함을 위해서였다. 평소에 데이터 시각화에 관심이 많았기 때문에 이미 존재하는 방대한 제니퍼 데이터를 다양한 방식으로 표현하기 위한 시도를 했었다.하지만 상용 솔루션인 제니퍼에 테스트 코드를 필자 임의로 추가해서 배포하거나 숨긴 기능으로 만들기에는 꽤 부담스러운 일이었다. 그렇다고 별도의 소스코드로 다르게 가지고 가기에는 관리 측면에서 어려움이 있다. 그렇기 때문에 기존의 제니퍼 소스코드를 참조만 하되 서로 독립적으로 개발하는 형태를 생각하게 되었다. 이렇게 필자의 편리함을 위해 시작한 실험실이지만 오픈소스나 다른 솔루션과의 연동을 위한 화면을 제공하고, 새로운 제니퍼 기능에 대한 비전을 시사하거나 고객의 피드백을 수용하는 용도로 확장되었다.소프트웨어 개발을 하다보면 제품이 추구하는 방향과 달라서, 또는 구현은 가능하지만 소모되는 리소스 비용이 부담이 될 경우, 그리고 특정 사용자를 위한 특화된 기능을 구현할 때, 모두가 만족할만한 기능이라는 확신이 없다면 제대로 진행하기가 어려운게 현실이다. 사실 새로 시도하는 기능은 시기와 때에 따라 앞에서 고려했던 것들과 다르게 평가되는 경우도 있다.그래서 아무리 작은 아이디어라도 시도를 해보는 것 자체만으로도 큰 의미가 있으며, 새로운 가능성을 발견하는 계기가 될 수 있다. 다만 현재는 제니퍼 기능 확장에 대한 기반 정도만 갖춰진 시작 단계라서 관련된 API 문서나 개발 도구에 대한 지원이 미흡한 것이 아쉬움으로 남는다. 다음 편에서는 자바 개발자 대상으로 실험실을 직접 구현하는 방법에 대해 알아볼 것이다.
조회수 1096

앱 어트리뷰션 가이드 - 트래킹 URL

어트리뷰션 툴의 출현 배경과 어트리뷰션의 동작에 필요한 세 가지 축을 지난 글에서 살펴 보았습니다. 이번에는 어트리뷰션의 한 축을 이루는 트래킹 URL을 설명하며 내용을 이어 나가려 합니다. 트래킹 URL의 역할과 구조를 이해하게 되면 어트리뷰션 툴을 다루는 난이도가 크게 낮아집니다. 그만큼 실무에서 더욱 효과적으로 툴을 활용할 수 있게 되고 광고 성과 최적화에도 가속이 붙게 될 것입니다. 트래킹 URL을 사용하는 이유어트리뷰션이 가능하기 위해서는 전체 유저들 중에서 광고의 영향을 받은 유저를 구분해 낼 수 있어야 합니다. 누군가를 ‘광고의 영향을 받았다’고 평가하기 위해서는 확실한 근거가 필요한데요, ‘광고 클릭’이 바로 이 확실한 근거가 됩니다. 클릭은 유저의 능동적인 광고반응이기 때문입니다.이 ‘클릭’ 행위를 알아내기 위해 광고 클릭 시점에 동작(Fire)하는 장치를 활용할 필요가 있었고 랜딩 페이지 URL이 적합한 수단이라는 것을 알아내게 됩니다. 두 가지 이유가 있는데, 광고 클릭과 랜딩 페이지 URL 연결이 사실상 동일한 행위라는 것이 첫번째이며, URL을 통해 최종 페이지로 연결되는 중간에 어딘가를 경유하도록 설정할 수 있다는 것이 두번째입니다.트래킹 URL을 클릭하면 중간에 트래커 서버를 경유하게 된다. 트래커는 광고 클릭에 대한 정보를 기록하고, 유저를 랜딩 페이지로 리다이렉트한다.이 중간 경유지가 있음으로써 심도 있는 어트리뷰션이 가능해 집니다. 왜냐하면 광고를 클릭한 유저가 경유지를 거치면서 다양한 데이터를 알려주고 이동하기 때문입니다. 수집하는 데이터가 많을수록 당연히 더 정확한 어트리뷰션이 가능한데요, 더 많은 데이터를 수집하는 방법이 바로 어트리뷰션 툴에서 다양한 옵션을 추가하여 트래킹 URL을 생성하는 것입니다. 트래킹 URL은 낯선 것이 아니다트래킹 URL을 만들기 위해 어트리뷰션 툴을 처음 접하게 되면 복잡하고 어려운 느낌을 받기 쉽습니다. 입력해야 할 항목들이 다양해서 손이 많이 가고, 세부 옵션의 숫자에 압도당해 어떻게 사용해야 할지 판단하기 어렵습니다. 게다가 반신반의 하면서 만들어낸 트래킹 URL은 의미를 알 수 없는 문자로 가득해서 혼란스럽지요. 보는 사람으로 하여금 이 URL을 천천히 살펴보면서 의미를 알아내려는 시도 조차 하고싶지 않도록 만들기에 충분합니다.하지만 트래킹 URL을 만드는 프로세스를 구조적인 시각으로 바라보면 매우 익숙한 절차라는 것을 알게 되는데, Bitly로 단축 URL을 만드는 것과 어트리뷰션 툴로 트래킹 URL을 만드는 것이 절차상으로 다르지 않다는 것이지요. 단지 트래킹 URL 생성에는 생소한 옵션들이 많아서 어려워 보일 뿐입니다.원래의 URL을, 툴에 입력해서, 최종 URL로 변환하는 구조는 동일하다. 다만 툴에 입력하는 2번 과정에서 어트리뷰션 툴은 다양한 옵션을 지정해줘야 하기 때문에 할 일이 더 많은 것이다.결국 툴에 URL을 입력하는 2번 과정을 이해하게 되면 트래킹 URL을 자유자재로 다룰 수 있게 됩니다. 2번 과정에서 주로 사용하는 옵션들이 무엇이고 어떤 기능을 하는지에 대한 설명이 있다면 큰 도움이 될 것입니다. 트래킹 URL 톺아보기완성된 트래킹 URL을 살펴보면서 URL의 구조부터 세부 항목들의 역할까지 차근차근 알아보겠습니다.http://ads.wisetracker.co.kr/wa/wiseAdw.do?_wtno=502&_wthst=trk.wisetracker.co.kr&_wts=P1535606238444&_wtc=C1535606305460&_wtm=C0000013&_wtaffid={wff_id}&_wtbffid={wffsub_id}&_wtcid={clk_id}&_wtgpid={GAID}&_wtidfa={IDFA}&_wtdl=http://www.wisetracker.co.kr&_wtp=2위 예제 URL은 와이즈트래커 홈페이지 주소(http://www.wisetracker.co.kr)를 트래킹 URL로 변환한 결과물입니다. 구조를 파악하기 위해 URL을 두 가지 배경색으로 구분했습니다. 하늘색 부분은 Base URL, 회색 부분은 파라미터입니다.1. Base URL광고를 클릭한 유저가 경유하는 지점입니다. 유저는 이 곳에 단지 몇 밀리 세컨드 정도만 머무르는데, 이 때 파라미터가 담고 있는 정보들을 트래커가 수집하고 유저는 즉시 최종 목적지로 리다이렉트 됩니다. 비근한 표현을 빌리자면, Base URL은 ‘찍고 가는 곳’ 정도로 이해하면 좋습니다. 2. 파라미터어트리뷰션에 필요한 다양한 정보들이 담겨있는 부분입니다. 툴에서 트래킹 URL을 생성할 때 다양한 옵션들을 선택하게 되는데요, 선택하는 옵션의 숫자가 많아질수록 파라미터가 길어진다고 봐도 틀리지 않습니다. 더 많은 옵션을 사용할수록 더 많은 데이터를 트래킹 할 수 있고, 더 많은 데이터를 측정하기 위해 더 많은 파라미터가 필요하기 때문입니다.하나의 파라미터는 하나의 데이터를 의미합니다. 실무에서는 간혹 트래킹 URL이 측정할 수 있는 항목을 알아내기 위해 전체 URL에서 각각의 파라미터를 구분해낼 필요가 있는데, 이럴때는 앰퍼샌드(Ampersand, &) 단위로 끊어내면 됩니다. 앰퍼샌드가 보이면 ‘새로운 파라미터가 시작되는구나’ 라고 생각하면 되는 것입니다.와이즈트래커에서 주로 사용하게 되는 파라미터를 간략하게 정리하면 다음과 같습니다.파라미터 종류설명와이즈트래커 구현광고 매체광고가 게재된 매체 정보._wts광고 캠페인광고의 캠페인 정보._wtc하위 퍼블리셔DSP나 네트워크 매체에서 실제 광고가 나간 지면._wtaffid, _wtcffid…클릭 ID광고 클릭시 발생하는 고유 식별자._wtcid단말기 식별자광고 클릭이 발생한 단말기의 고유 식별자._wtgpid, _wtidfa랜딩 페이지리다이렉트 후 이동할 최종 목적지._wtdl룩백 윈도우성과 기여 인정기간. 룩백 윈도우 이후에 발생한 광고성과는 인정하지 않음._wtp3. 유저 에이전트유저 에이전트는 그 이름처럼 실제 유저를 소프트웨어 상으로 대신하는 역할을 합니다. 여기에서 말하는 소프트웨어란 일반적으로 브라우저, OS, 단말기 정보 등을 포함한 데이터를 의미합니다. 광고를 클릭한 유저가 트래커를 거쳐갈 때 서버는 접속자의 유저 에이전트 정보를 알 수 있으므로, 이런 값들은 파라미터에 포함시키지 않아도 분석이 가능합니다.유저가 광고를 클릭함으로써 트래킹 URL로 연결되고, 유저는 트래커를 거치며 파라미터에 포함된 다양한 데이터를 전달한 뒤, 앱을 다운로드 할 수 있는 최종 목적지로 연결됩니다. 이렇게 한 번의 클릭을 시작으로 어트리뷰션의 전체 여정이 전개되는 것입니다.지금까지의 내용을 정리하면 다음과 같습니다.유저가 광고에 반응했다는 것을 측정하기 위해 트래킹 URL을 사용한다트래킹 URL은 트래커 서버를 경유한 뒤 최종 랜딩 페이지로 유저를 이동시킨다유저의 트래커 경유 시점에 트래커는 파라미터에 포함된 데이터를 수집한다트래커는 수집한 정보를 바탕으로 어떤 유저가 어떤 매체의 광고를 언제 클릭 했는지를 알게 되었고 유저는 앱 다운로드 페이지로 이동 했습니다. 유저가 앱을 다운로드 했는지를 트래커는 어떻게 알 수 있을까요? 다음 글에서 설명하도록 하겠습니다.

기업문화 엿볼 때, 더팀스

로그인

/