LINE에서 프론트엔드 업무를 담당하고 있습니다
사용자에게 유려한 UI(User Interface)와 좋은 UX(User eXperience, 사용자 경험)를 제공하는 일은 까다롭습니다. 간단한 동작을 만들 때도 많은 것들을 고민하고 만들지만 항상 좋은 결과물이 나오진 않습니다. 사용자를 생각하며 여러가지 시도를 멈추지 않는 것이 프론트엔드 개발자의 숙명이 아닐까 생각합니다. 안녕하세요. 저는 LINE UIT 조직에서 프론트엔드 업무를 담당하고 있는 이상원입니다. 이번 글에선 제가 LINE Search 프로젝트를 담당할 때 새로 추가된 UI를 조금 더 개선하기 위해 노력했던 내용을 공유하려고 합니다. 배경 설명 제가 LINE Search 프로젝트를 담당할 당시, LINE Search에서 이미지 뷰어를 실행할 때 화면 상단에 위치한 검색 바(bar)를 가리는 기능이 추가되었습니다. 개발 당시 여러 일정과 상황이 맞물려서 검색 바가 사라질 때 애니메이션 효과를 추가할 수 없었는데요. 결론적으로 프론트엔드에서 웹 뷰(web view) 영역만 제어하여 사용자가 최대한 좋은 UI를 경험할 수 있도록 만들어야 하는 상황이었습니다. 구현 당시 일정에 쫓기는 바람에 이 글에서 고려했던 모든 사항을 고려하지 못하고 단순하게 클라이언트 팀에서 제공한 API를 호출해 검색 바를 숨길 수 있는 기능을 추가하는 것으로 작업을 완료했습니다. 작업 완료 후 QA(quality assurance)가 시작되었고, QA 팀에서 해당 기능의 동작과 관련된 이슈를 등록했습니다. 아래 동영상은 QA에서 이슈 등록과 함께 제공한 동영상입니다. 위 동영상을 살펴보면서 발견한 첫 번째 문제점은 이미지 뷰어가 실행되기 전에 검색 바가 사라지면서, 웹 뷰 영역이 늘어나며 콘텐츠가 위로 올라가는 현상이 보인다는 점이었습니다. 처음엔 단순하게 '콘텐츠가 위로 밀려 올라가는 모습이 보이지 않으면 되겠지'라는 생각으로 로직 순서를 수정해서 구현해 봤습니다(아래 샘플은 이해를 돕기 위해 실제로 구현된 상태보다 느리게 재생한 상태입니다). 순서 샘플 1. 콘텐츠 영역을 가립니다. 2. 검색 바를 없앱니다. 3. 웹 뷰 영역 크기 변경이 완료되길 기다립니다. 4. 이미지 뷰어를 실행합니다. 첫 번째 시도에서 얻은 결과물을 함께 프로젝트를 진행하고 있던 팀원에게 공유한 뒤 여러 의견을 종합한 결과, 애니메이션을 추가하기로 결정했습니다. QA 시작 전에는 다른 기능들을 구현하느라 애니메이션을 추가할 여건이 되지 않았지만, 기획, 디자인, QA 팀과 협의해 보니 이번엔 추가할 수 있겠다고 판단했습니다. 애니메이션 효과를 추가하는 과정은 일반적인 개발 순서와 크게 다르지 않습니다. 먼저 애니메이션을 설계하고 코드를 작성한 뒤, 코드 리뷰와 QA 과정을 거쳤습니다. 애니메이션 설계 및 코드 작성 간단하게 CSS로 동작하는 애니메이션을 추가해서 몇 가지 샘플을 제작해 봤습니다. 샘플 1 샘플 2 제작한 샘플 중 팀원들과 함께 결정했던 건 첫 번째 샘플이었습니다. 하지만 좀 더 많은 사람들의 피드백을 받아보니 두 번째 샘플이 좋다는 의견이 더 많아 두 번째 샘플의 애니메이션 형태로 구현했습니다. 애니메이션은 아래와 같이 Vue.js 프레임워크의 transition 기능을 사용해 간단하게 구현할 수 있었는데요. 이 기능을 사용하면 CSS 애니메이션이 시작되고 종료되는 시점을 쉽게 제어할 수 있다는 장점이 있습니다. <transition name="layer" @after-enter="afterEnter"> <v-image-viewer /> </transition> <script type="text/javascript"> export default { methods: { afterEnter () { // call api : close search bar } } } </script> <style> .layer-enter-active, .layer-leave-active { transition: all ease 0.2s; } .layer-enter, .layer-leave-to { opacity: 0; } .layer-leave-to { transition: all linear 0.1s; } </style> 위 코드에서 이미지 뷰어를 실행하고 종료하는데 걸리는 시간을 각각 0.2초와 0.1초로 설정한 것도 피드백을 반영한 부분입니다. 단 0.1초 차이일 뿐이지만, 이미지 뷰어가 종료될 때 조금 더 빠른 반응을 보여주는 게 좋다는 의견이 많았습니다. 코드 리뷰와 QA QA 기간에 추가 기능을 개발하는 것은 금지되어 있었지만, 애니메이션을 추가하기로 결정한 시점엔 이미 QA가 진행되고 있었습니다. 또한 팀원들과 함께 여러 사람의 피드백을 받아 반영하는 와중에 QA 담당자도 현재 상황에서 조금 더 개선해 줄 수 있겠냐는 요청을 보내왔습니다. 아래 동영상을 보면 가장 먼저 화면 하단에 이미 렌더링된 콘텐츠가 이미지 뷰어 앞으로 올라온 것처럼 보인다는 점이 눈에 띕니다. 두 번째 문제는 이미지 뷰어가 종료될 때, 적용해 놓은 애니메이션이 정상적으로 동작하지 않는다는 점이었습니다. 완벽함을 도모하기 위해 아래와 같이 슬로우 모션으로 촬영해 보았더니 육안으로는 파악하기 힘들었던 몇 가지 문제점을 더 발견할 수 있었습니다. 발견한 문제점 이미지 뷰어를 종료할 때 애니메이션이 정상 동작하지 않는다 이 문제는 이미지 뷰어에 슬라이드로 적용된 DOM 객체가 많을 경우 애니메이션 동작에 영향을 미치게 되는 문제였습니다. 이미지 뷰어가 닫히는 시점에서 이미지 뷰어의 슬라이드 DOM 객체를 모두 삭제한 뒤 애니메이션이 동작하도록 수정하여 간단하게 문제를 해결할 수 있었습니다. 추후 사용자가 보고 있는 영역 근처의 DOM만 이미지 슬라이더에 그리도록 개선하는 계기가 되었습니다. 이미지 뷰어를 실행할 때 화면 하단에 콘텐츠 영역이 잠시 보인 뒤 사라진다 이 문제를 해결하기 위해서 z-index를 설정하여 뒤에 그려진 콘텐츠가 왜 이미지 뷰어 앞에 보이는지 원인을 파악했습니다. 원인 파악을 위해 아래 샘플 코드 조건에 맞는 단순한 샘플 코드를 작성해서 테스트해 보았습니다. 샘플 코드의 조건 버튼을 눌러 검색 바를 가리거나 다시 나타나게 조작할 수 있어야 합니다. 첫 번째 DOM 객체는 z-index 값이 없어야 합니다. 두 번째 DOM 객체는 position : fixed 값과 z-index 값을 갖고 첫 번째 DOM 객체 안에 존재해야 합니다. <html style="margin: 0; padding: 0;"> <head> <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,viewport-fit=cover,user-scalable=no,target-densitydpi=medium-dpi"> </head> <body style="margin: 0; padding: 0;"> <div style="width: 100%; height: 150%; display: block; background-color: red;"> <div style="width: 100%; height: 100%; display: block; z-index: 1; position: fixed; background-color: yellow; zoom: 1;"> <button id="openSearchBar"> open Search bar </button> <button id="closeSearchBar"> close Search bar </button> </div> </div> </body> <script> window.document.querySelector('#openSearchBar').addEventListener('click', function () { // call open search bar }) window.document.querySelector('#closeSearchBar').addEventListener('click', function () { // call close search bar }) </script> </html> 위 샘플 코드로 확인해 본 결과 검색 바를 가리도록 조작했을 때 배경 색상(background-color)을 빨간색(red)으로 넣은 DOM이 보이는 동일한 현상을 발견할 수 있었습니다. Chrome 개발자 도구에서 layers에 그려진 DOM 객체 상황을 확인해 보니 좀 더 쉽게 이유를 파악할 수 있었습니다. Layers 파악된 문제 검색 바가 사라지며 웹 뷰의 크기를 변경합니다. window → resize 이벤트가 발생합니다. 이때 이미 렌더링된 첫 번째 DOM 객체는 repaint 이벤트 이전에도 하단이 노출됩니다. 두 번째 DOM 객체에 적용된 height: 100%가 두 번째 DOM 객체의 크기를 변경하여 repaint를 실행합니다. 문제의 원인은 파악했지만 해결은 생각처럼 쉽지 않았습니다. height 값을 120%, 혹은 calc(100% + 150px)로 변경해도 position이 fixed로 지정된 상황에서는 브라우저가 화면을 넘어간 부분을 렌더링하지 않았습니다. 이 문제는 샘플 코드에서 몇 가지 테스트를 해 본 뒤 min-height 값을 브라우저 크기보다 조금 더 크게 설정하여 해결할 수 있었습니다. 화면 하단에 콘텐츠 대신 흰 부분이 보인다 이 이슈는 Android에서만 발생하는 이슈였는데요. 검색 바가 가려지면서 웹 뷰의 사이즈가 변경될 때 repaint되는 순서가 문제였습니다. 1. 검색 바 숨김 요청 2. 웹 뷰 영역의 크기 변경 3. 렌더링 트리의 루트 노드(<html>) 크기 변경 후 repaint 발생 4. 변경된 루트 노드(<html>)의 크기에 맞춰 DOM 객체 repaint 발생 이미지 뷰어의 배경이 검은색이라서 너무 눈에 띄었는데요. HTML에서 동일한 색상을 배경에 적용하는 방식으로 문제를 회피한 상태입니다(참고로 orientationchange 이벤트가 발생할 때는 해당 현상이 나타나지 않았습니다). 개선 전후 비교 첫 구현 결과물 마지막 구현 결과물 첫 구현 당시 예상치 못한 많은 문제점을 발견했고, 해결하고 나서 이미지 뷰어를 실행, 종료하는 과정에서 어색한 부분이 눈에 띄게 줄어든 것을 확인할 수 있습니다. 보통 애니메이션을 적용하면 실행할 때 더 많은 시간이 걸리게 되지만, 이미지가 뒤틀리는 현상 같은 게 보이지 않아 오히려 더 빨리 실행되는 것처럼 보이기도 합니다. 사용자들이 이미지 뷰어를 사용하면서 조금도 불편함을 느끼지 않길 바라 봅니다. 마치며 이쪽 분야를 잘 모르는 사람들의 관점에선 사용자의 UI와 UX를 개선하는 일이 별것 아닌 일에 큰 공수를 들이는 것처럼 보일 수 있습니다. 하지만 이렇게 심혈을 기울여 제작된 결과를 통해 사용자는 작은 경험들을 쌓아 나가고, 그렇게 쌓인 경험들이 결국 앱에 대해 사용자가 갖는 전체적인 이미지를 결정하게 됩니다. 제가 현재 몸담은 LINE UIT 조직엔 이렇게 작은 부분도 놓치지 않고 꼼꼼하게 확인하며 만들어 나가는 사람들이 함께 있습니다. 덕분에 사용자를 배려하는 코드가 무엇인지 고민하는 개발자로 조금씩 성장하고 있습니다. 이 글을 통해 함께 고민하고 노력해 주시는 팀원분들께 감사 인사를 전해 봅니다.
Developer Relations팀에서 LINE의 개발자와 개발자 문화를 세상에 알리는 Developer Advocate로 일하고 있습니다.
안녕하세요. 이번 글에서는 지난 12월 11일, Vuetiful Korea Meetup에 다녀온 이야기를 전해드리려고 합니다. Vuetiful Korea는 최근 핫한 프론트엔드 프레임워크인 Vue.js에 대한 관심 주제를 발표하고 서로 관련 경험을 공유하는 네트워킹 모임입니다. 2017년 4월에 시작하여 이번이 여섯 번째 밋업이었는데 90명 정원이 하루만에 마감되었다고 하니 Vue.js의 인기를 실감할 수 있었습니다. LINE은 이번 밋업에 장소와 샌드위치, LINE 캐릭터 상품을 후원했는데요. 귀여운 스티커들이 특히 인기가 많았습니다. 국내에서는 React에 비해 Vue.js의 활용이 상대적으로 적은 편입니다. 그래서 이번 밋업은 국내에서도 더 많은 개발자들이 Vue.js를 사용할 수 있도록 다양한 수준의 세션으로 구성됐는데요. 초급자를 위한 세션에서부터 SSR(Server Side Rendering)을 고민하는 중급자들을 위한 세션, 더욱 세부적으로 Vue.js의 코어 로직을 살펴보면서 문제점을 찾고 해결하는 높은 수준의 세션까지 준비되어 있었습니다. 발표 중간에는 LINE에서 테크 에반젤리스트로 활동하고 계신 박민우 님께서 LINE이 전세계에서 어떤 서비스들을 운영하고 있는지 소개하고, LINE 내부에서도 다양한 프로젝트에 Vue.js를 활용하고 있다는 이야기를 전했습니다. 그러면 각 세션에 대해 좀 더 자세히 전해드리겠습니다. Vue.js를 이용한 백오피스 구현기 - 마광휘 님 첫 번째 세션은 와인포인트에서 프론트엔드 개발자로 일하고 있는 마광휘 님이 발표해 주셨습니다. 마광휘 님은 새로 도입할 프론트엔드 프레임워크를 고민하면서 프론트엔드와 백엔드에서 모두 사용할 수 있는 언어는 JavaScript이기 때문에 러닝 커브의 기준을 JavaScript로 잡고, 그 중에서 Vue.js가 가장 낮은 러닝커브를 가졌다고 판단해서 Vue.js를 선택했다고 합니다. 기존에 HTML로 작성한 코드와도 잘 통합할 수 있었다고 하고요. 눈에 띄는 부분은 Vue.js에서 제공하는 모듈인 Vuex나 Vue Table-2를 사용하지 않고 직접 모듈을 제작하여 사용했다는 점이었습니다. 그 이유로는 첫째, Vuex는 충분히 검증된 모듈이지만 Vuex를 쓸만큼 프로젝트 규모가 크지 않았고 Vuex에 필요한 기능이 없을 경우 추가하기 어렵기 때문이었다고 합니다. 둘째, Vue Table-2는 아직 검증이 되지 않았고 기획에 따라 직접 구현하는 것이 오히려 빠른 경우가 있었다고 하네요. 발표자료 : https://www.slideshare.net/gwangwhima/vuejs-125681294 Nuxt.js vs Next.js - 임석민 님 두 번째 세션은 임석민 님께서 Nuxt.js와 Next.js의 장단점을 비교하여 설명해 주셨습니다. Nuxt.js는 Vue.js 애플리케이션을 편리하게 만들기 위한 프레임워크입니다. Nuxt.js의 대표적인 장점으로 다음 네 가지를 이야기해 주셨는데요. 우리말 가이드 문서를 제공 디렉터리 구조를 기본적으로 지원 SEO(Search Engine Optimization)에 최적화된 서버사이드 렌더링 코드 분할 자동화 최근에 프론트엔드 개발 환경을 구축하는 데 어려움이 많은데 이런 부분을 Nuxt.js를 통해 쉽게 해결할 수 있고, SPA(Single-Page Application)에서 신경써야 하는 부분들을 모두 포함하고 있어서 간단한 SPA 작업에 좋을 것 같다는 말씀을 해주셨습니다. 발표자료 : https://slides.com/imsukmin/nextjs_vs_nuxtjs#/ Deep dive into Vue.js - 이선협 님 마지막은 Vue.js의 동작 원리를 파헤쳐 공유해 주신 이선협 님의 세션이었습니다. 실제로 무언가를 만들 때 바로 도움이 되는 것은 아니지만 원리를 이해하고 만들다 보면 '1%의 버그를 수정할 수 있는 능력'을 기를 수 있을 거라는 말씀이 인상적이었는데요. 내부 소스 코드를 살펴보면서 Vue.js 내부 원리를 살펴볼 수 있는 시간이었습니다. Vue.js는 약간 변형된 MVVM(Model–View–ViewModel) 아키텍처를 기반으로 하고 있다고 하면서 Vue.js 구조가 왜 MVVM이 아닌지 잘 설명해 주셨습니다. 그리고 Vue.js에서 사용되고 있는 Virtual DOM이 어떻게 동작하는지 Vue.je 코드 설명과 함께 발표해 주셨습니다. 발표자료 : https://www.slideshare.net/sunhyouplee/deep-dive-into-vuejs 마치며 발표가 끝난 후 밋업 참가자분들과 발표자분들이 함께 동그랗게 둘러앉아 네트워킹 세션을 가졌습니다. Vue.js에 관련된 내용 뿐만 아니라 서버나 인프라 구축, AWS 사용팁, React나 다른 프레임워크로 개발하는 개발 방법, 디자이너와 개발자 사이의 업무 영역은 어디까지 나누는 것이 좋을지 등등 평소 답답했던 부분들을 서로 공유하고 토론하며, 자유롭게 질의응답 시간을 갖는 모습이 굉장히 인상적이었습니다. 분야를 가리지 않고 퇴근 후에도 열공하는 개발자들의 열정이 느껴졌습니다. LINE에서는 현재 다음과 같은 분야에서 프론트엔드 개발자 채용을 진행하고 있습니다. 많은 지원 부탁드립니다. Global Fintech 프론트엔드 개발 Web Frontend Engineer (Blockchain Platform/Service) Global Service Web FrontEnd 개발 LINE에서는 선순환하는 개발 생태계를 위해 개발자 커뮤니티를 지원하고 있습니다. 후원이 필요하시다면 LINE의 Dev Relations팀(dl_devrelations_kr@linecorp.com)으로 연락 주세요!