장애물을 다루는 기술: 다국어 처리부터 웹에서 유튜브 하이라이트 기능까지
Obstacles don’t have to stop you.
If you run into a wall, don’t turn around and give up.
Figure out how to climb it, go through it, or work around it
– Michael Jordan
“장애물을 마주했다고 반드시 멈춰 서야 하는 건 아니다.
벽에 부딪힌다고 돌아서거나 포기하지 말라.
어떻게 벽을 오를지, 뚫고 나갈지 또는 돌아갈지 생각하라.”
– 마이클 조던 –
얼마 전 베이징 동계올림픽 쇼트트랙 남자 1,000m 준결승에서 조 1위로 결승선을 통과하고도 편파 판정으로 실격을 당하고 결승에 진출하지 못했던 황대헌 선수를 기억하시나요? 해당 경기를 지켜봤던 많은 스포츠 팬들이 허탈감과 분노에 차 있을 때, 황대헌 선수가 개인 SNS에 위 문장을 언급하면서 좌절감 대신 더욱 의지를 불태웠고, 결국 1,500m 금메달을 거머쥐며 당당히 시상대에 오른 모습이 저에겐 정말 인상 깊었습니다.
안녕하세요! 저는 라이너 팀의 프론트엔드 엔지니어 데이브라고 합니다. 🙂
서론이 쓸데없이 길긴 했지만 저는 오늘 프론트엔드 엔지니어로서 장애물을 만났을 때 어떤 고민을 했었는지 그리고 라이너 팀이 장애물을 만났을 때 어떤 식으로 장애물을 극복했는지, 장애물을 다뤘던 경험에 대해 간단하게 이야기 해볼까 하는데요. 글재주가 없는 편이라 두서없이 써 내려가진 않을까 걱정이 앞서긴 하지만 그래도 재미있게 읽어봐 주시면 좋겠습니다. 🙏
다양한 언어를 제공하는 글로벌 서비스 라이너! 👍
라이너는 의외로 국내보다 해외 유저 비율이 훨씬 더 높은 글로벌 서비스입니다. 현재 라이너 서비스는 유저의 브라우저 언어 설정에 따라 영어, 한국어, 일본어, 그리고 중국어 간, 번체를 나눠 총 5가지 언어로 번역된 UI를 제공하고 있는데요. 만약 브라우저의 언어가 현재 라이너에서 번역을 지원할 수 없는 언어인 경우에는 영어로 번역된 서비스를 제공하고 있습니다.
서비스가 이렇게 다양한 언어를 지원하게 되면 유저에게 좀 더 편안한 환경을 제공해 줄 수 있다는 장점이 있긴 하지만, 한편으로는 새로운 기능을 개발한다거나 프로모션 모달같은 것들을 제작할 때마다 각 언어를 사용하는 국가의 문화적인 특성을 반영해서 우리가 전달하고자 하는 문장으로 번역하는 과정과 번역한 언어별 데이터를 관리하는 과정이 있을 수밖에 없고, 당연히 이 과정에서 적지 않은 리소스가 필요하다는 분명한 단점도 존재합니다.
특히나 프론트엔드에서는 이 번역된 언어를 화면에 반영했을 때 언어마다 보이는 영역의 크기가 다양해져 버리는 경우가 빈번히 발생하기 때문에 상황에 따라 적절한 크기에서 의도적으로 줄 바꿈을 한다거나, 혹은 어떤 크기가 오더라도 자연스러운 화면이 그려지도록 최대한 유연하게 스타일 코드를 작성하는 등의 노력을 하고 있는데, 때론 간단하게 잘 정리될 때도 있긴 하지만 항상 그렇게 뚝딱뚝딱할 만큼 간단한 작업은 아니랍니다. 😅
언어별 데이터 관리는 어떻게?
당연히 번역하는 작업을 엔지니어가 직접 하진 않습니다. 언어별로 전문적인 역량을 가지신 라이너 팀원들이 노션 번역문서에 잘 정리해 주시면 그 번역 데이터들을 기획한 의도에 맞게 아름답게 보여주는 게 프론트엔드 엔지니어들의 역할인데요.
현재 라이너 서비스는 필요한 언어의 번역 데이터를 보여주기 위해 Format.JS라는 라이브러리를 활용하고 있습니다.
위 사진은 Format.JS 공식 문서를 캡처한 사진인데요. 자바스크립트 진영에서 다국어 서비스를 지원하도록 도와주는 다양한 라이브러리들이 있지만, 대부분의 활용 구조는 위 사진과 비슷합니다. 보이는 그대로 언어별 파일을 만들고, 번역이 필요한 언어에 맞는 파일을 가져가 사용하는 방식이죠!
당연히 라이너도 이 방식을 따라 위 사진처럼 각각의 문자열 값만, 다른 똑같은 형태의 파일 5개를 관리하고 있었습니다.
“우리가 활용하는 라이브러리가 애초에 이렇게 설계를 했으니 이렇게 쓰는 게 당연하지”라는 생각으로 처음에는 저도 이 방식에 별다른 불편함을 느끼지 못했었는데요. 어느 날 우연히 이 구조가 장애물로 찾아왔습니다.
실수는 발견의 시작이다.
실수는 발견의 시작이다.
– 제임스 조이스 –
앞서 설명했던 구조로 번역 데이터를 관리하다가 어느 날 제가 실수를 저질러버리게 되는데요. 바로 중국어 번체자와 간체자를 반대로 반영해버린 겁니다. 심지어 전체도 아니고 일부분에서 드문드문 말이죠. 그뿐만 아니라, 일본어에서 번역할 키워드(문장 혹은 단어)의 프로퍼티 네임을 한 번 잘못 쓰는 바람에, 해당 문장은 번역조차 제대로 이뤄지지 않았던 것이죠.
결국 잘못 반영한 부분들을 하나하나 번역본과 비교해가면서 제대로 맞춰놓고서도 혹시나 또 다른 문장은 실수하지 않았는지 결국 처음부터 끝까지 하나하나 다시 확인하는 대참사를 겪고야 말았습니다. 당연히 그날 하루는 그렇게 날려버렸죠…🥲
그렇게 거사(?)를 치르고 나니 지금 이 방식이 여러 방면에서 극복해야 할 장애물로 인식되기 시작했습니다.
장애물 인식하기?
기존의 라이브러리 구조를 따라 관리하는 방식의 가장 근본적인 장애물은 여러 가지 언어 파일에서 내가 번역하고자 하는 키워드들을 관리해야 하는 언어 > 키워드 방식의 방향성이었습니다.
그렇기 때문에 각 언어 파일별로 번역 키워드가 반드시 일치한다는 보장이 있어야 하는데, 위 사진에서 볼 수 있는 것처럼 email이라는 키워드를 각 언어로 번역하고자 할 때 프로퍼티 네임을 email 이 아닌 eamil로 오타를 내는 실수를 하게 될 가능성이 분명히 있다는 것이죠. 당연히 이렇게 파일을 저장하고 배포를 하게 되면 일본어 번역은 제대로 이뤄지지 않겠죠?
이렇게 오타를 내는 실수를 하고 나니 실제로 저지른 실수는 아니지만, 정신없이 파일을 오가다 보면 오타가 아니라 아예 한 언어에서 키워드를 빼먹는 실수를 할 수도 있겠다는 생각도 들었었습니다.
그리고 언어 > 키워드 방식의 방향성은 유지보수 측면에서도 문제가 되었는데요. 특정 키워드가 언어별로 어떤 값으로 반영되는지 확인하려면, 파일별로 돌아다니면서 내가 찾고자 하는 키워드를 검색해야만 했었습니다. 제가 중국어 간체자, 번체자를 서로 바꿔 작성한 실수를 할 때 그 두 파일을 몇 번이나 왔다 갔다 하며 헤맸는지 모르겠어요.
장애물 해결하기!
그래서 저는 이 언어 > 키워드의 방향성을 바꾸기로 마음먹었습니다. 키워드 > 언어로 말이죠.
이렇게 하나의 파일에서 키워드별로 각 언어의 번역 값들을 관리하니 엔지니어가 새로운 번역 데이터를 추가할 때 특정 언어 파일에서 실수를 할 가능성도 줄어들고, 유지보수 측면에서도 특정 키워드가 어떻게 번역되는지 직관적으로 확인이 가능하니 매번 파일을 옮겨 다니면서 키워드를 찾아다닐 필요도 없었죠. 또, 번역하는 과정에서 실수가 있어서 만약 나중에 추가적으로 수정이 필요할 때에도 훨씬 더 쉽고 빠르게 대응할 수가 있었습니다.
물론 언어별 값을 서로 바꿔 입력한다거나, 잘못 입력할 수 있다는 실수는 여전히 존재하지만, 기존 보다 훨씬 더 그 실수를 쉽게 만회할 수 있는 구조가 된 건 확신할 수 있게 된 것이죠!
당연히 이대로 끝나는 게 아니라, 엔지니어가 번역 데이터를 관리할 때는 이 포맷을 활용하되 Format.JS 는 이 포맷을 활용할 수 없으니 라이브러리가 우리 데이터를 잘 활용할 수 있도록, 작업한 코드가 실제 서비스 환경에 배포되기 전에 빌드 단계에서 언어 > 키워드 형태로 변환하는 함수를 만들었고 덕분에 라이너 팀만의 번역 데이터 관리 방식을 성공적으로 개선할 수 있었습니다.
아무튼 애초에 다국어를 지원하고자 할 때 특정 단어나 문장을 언어별로 어떻게 보여주느냐가 근본적인 문제니깐 이렇게 관리하는 게 더 직관적이라고도 생각이 들었는데요. 왜 진작에 이 생각을 못 했었는지 한편으론 아쉽기도 했었습니다. 이후에는 노션에서 표로 정리한 번역 데이터를 CSV로 가져오면 자동으로 프론트엔드 프로젝트에 번역 객체 파일을 생성해주는 작업을 해볼까도 고민중에 있어요!
누구나 실수는 할 수 있지만,
구글에 조금만 검색해봐도 실수에 대한 명언들이 쏟아져나옵니다. 그리고 일상생활에서 이런저런 이야기들을 나눠봐도 실수에 대한 이야기는 한 번쯤 하게 되는데요. 실수했을 때 그 실수를 대하는 생각이나 행동들은 정말 다양한 것 같습니다.
그래서 저는 실수했다고 해서 그저 좌절하고 대충 반성하고, ‘다음엔 그러지 말아야지’ 하며 다짐하는 데서 그치는 것이 아니라, 다음에도 실수할 수 있다고 인정하고 실수를 줄이기 위한, 혹은 실수를 하더라도 빠르게 수습할 방안을 마련하는 라이너 팀의 생각과 노력을 나누고자 장애물을 다루는 기술의 첫 번째 주제로 다국어 지원 프로세스 개선 이야기를 가지고 와봤습니다. 우리의 실수도 하나의 장애물이니까요.
이 글을 읽고 계신 여러분은 실수에 대해 어떤 생각을 가지고 계신가요?
갑작스런 마무리.
사실 이 글을 작성할 땐, 정말 다양한 주제로 많은 이야기들을 하고 싶었습니다. 21년 7월에 멋지게 등장한 유튜브 하이라이트 이야기, 하이라이트 컬러 테마 도입기, 지금의 커뮤니티가 있게 도와준 AOC(always on community) 개발기, 그리고 지금의 커뮤니티 기능을 품은 22년 서비스 개편 이야기, 그리고 최근에 추가된 라이너 모바일 웹에서의 유튜브 하이라이트 기능까지..!
이 모든 것들이 사실은 하나하나 저마다의 장애물을 인식하고 극복하는 방식이 녹아있었기에 가능했던 일 들이였단 말이죠?
하지만 욕심이 너무 많았던 탓일까요. 이 많은 이야기를 하나의 글에 담기에는 오히려 너무 장황하고 지루한 글이 될까 봐 우려되어 시리즈로 나눠볼까 합니다. 이번 이야기가 흥미로우셨다면 저의 다음 글도 많이 많이 기대해 주세요!
그런데,
혹시 다음 시리즈를 기다리긴 현기증나고 너무 궁금해 미치겠다면, 저희와 함께 장애물을 직접 다뤄보시는건 어떠신가요?
저희는 함께 실수를 두려워하지 않고 불편함을 극복해 나가며, 성장의 즐거움을 느끼고 싶으신 모든 분들을 기다리고 있습니다. 저는 이 과정이 단순히 개인의 성장에 도움이 되는 것뿐만 아니라, 다양한 형태로 라이너 팀에게, 나아가 라이너를 사용하는 모든 유저들에게도 도움이 이어질 것이라고 믿습니다.