스토리 홈

인터뷰

피드

뉴스

개발에 관심있다면 꼭 읽어야하는 글
조회수 2292

블로그 운영 방법에서 엿보는 VCNC의 개발문화

VCNC에서 엔지니어링 블로그를 시작하고 벌써 새로운 해를 맞이하였습니다. 그동안 여러 글을 통해 VCNC 개발팀의 이야기를 들려드렸습니다. 이번에는 엔지니어링 블로그 자체를 주제로 글을 적어보고자 합니다. 저희는 워드프레스나 텀블러와 같은 일반적인 블로깅 도구나 서비스를 사용하지 않고 조금은 개발자스럽다고 할 수 있는 특이한 방법으로 엔지니어링 블로그를 운영하고 있습니다. 이 글에서는 VCNC 개발팀이 엔지니어링 블로그를 운영하기 위해 이용하는 방법들을 소개하고자 합니다. 그리고 블로그를 운영하기 위해 방법을 다루는 중간중간에 개발팀의 문화와 일하는 방식들에 대해서도 간략하게나마 이야기해보고자 합니다.블로그에 사용하는 기술들Jekyll: Jekyll은 블로그에 특화된 정적 사이트 생성기입니다. GitHub의 Co-founder 중 한 명인 Tom Preston-Werner가 만들었으며 Ruby로 작성되어 있습니다. Markdown을 이용하여 글을 작성하면 Liquid 템플릿 엔진을 통해 정적인 HTML 파일들을 만들어 줍니다. VCNC 엔지니어링 블로그는 워드프레스같은 블로깅 도구를 사용하지 않고 Jekyll을 사용하고 있습니다.Bootstrap: 블로그 테마는 트위터에서 만든 프론트엔드 프레임워크인 Bootstrap을 이용하여 직접 작성되었습니다. Bootstrap에서 제공하는 다양한 기능들을 가져다 써서 블로그를 쉽게 만들기 위해 이용하였습니다. 덕분에 큰 공을 들이지 않고도 Responsive Web Design을 적용할 수 있었습니다.S3: S3는 AWS에서 제공되는 클라우드 스토리지 서비스로서 높은 가용성을 보장합니다. 일반적으로 파일을 저장하는 데 사용되지만, 정적인 HTML을 업로드하여 사이트를 호스팅하는데 사용할 수도 있습니다. 아마존의 CTO인 Werner Vogels 또한 자신의 블로그를 S3에서 호스팅하고 있습니다. VCNC Engineering Blog도 Jekyll로 만들어진 HTML 파일들을 아마존의 S3에 업로드 하여 운영됩니다. 일단 S3에 올려두면 운영적인 부분에 대한 부담이 많이 사라지기 때문에 S3에 올리기로 하였습니다.CloudFront: 브라우저에서 웹페이지가 보이는 속도를 빠르게 하려고 아마존의 CDN서비스인 CloudFront를 이용합니다. CDN을 이용하면 HTML파일들이 전 세계 곳곳에 있는 Edge 서버에 캐싱 되어 방문자들이 가장 가까운 Edge를 통해 사이트를 로딩하도록 할 수 있습니다. 특히 CloudFront에 한국 Edge가 생긴 이후에는 한국에서의 응답속도가 매우 좋아졌습니다.s3cmd: s3cmd는 S3를 위한 커맨드 라인 도구입니다. 파일들을 업로드하거나 다운로드 받는 등 S3를 위해 다양한 명령어를 제공합니다. 저희는 블로그 글을 s3로 업로드하여 배포하기 위해 s3cmd를 사용합니다. 배포 스크립트를 실행하는 것만으로 s3업로드와 CloudFront invalidation이 자동으로 이루어지므로 배포 비용을 크게 줄일 수 있었습니다.htmlcompressor: 정적 파일들이나 블로그 글 페이지들을 s3에 배포할 때에는 whitespace 등을 제거하기 위해 htmlcompressor를 사용합니다. 또한 Google Closure Compiler를 이용하여 javascript의 길이도 줄이고 있습니다. 실제로 서버가 내려줘야 할 데이터의 크기가 줄어들게 되므로 로딩속도를 조금 더 빠르게 할 수 있습니다.블로그 관리 방법앞서 소개해 드린 기술들 외에도 블로그 글을 관리하기 위해 다소 독특한 방법을 사용합니다. 개발팀의 여러 팀원이 블로그에 올릴 주제를 결정하고 서로의 의견을 교환하기 위해 여러 가지 도구를 이용하는데 이를 소개하고자 합니다. 이 도구들은 개발팀이 일할 때에도 활용되고 있습니다.글감 관리를 위해 JIRA를 사용하다.JIRA는 Atlassian에서 만든 이슈 관리 및 프로젝트 관리 도구입니다. VCNC 개발팀에서는 비트윈과 관련된 다양한 프로젝트들의 이슈 관리를 위해 JIRA를 적극적으로 활용하고 있습니다. 제품에 대한 요구사항이 생기면 일단 백로그에 넣어 두고, 3주에 한 번씩 있는 스프린트 회의에서 요구사항에 대한 우선순위를 결정합니다. 그 후 개발자가 직접 개발 기간을 산정한 후에, 스프린트에 포함할지를 결정합니다. 이렇게 개발팀이 개발에 집중할 수 있는 환경을 가질 수 있도록 하며, 제품의 전체적인 방향성을 잃지 않고 모두가 같은 방향을 향해 달릴 수 있도록 하고 있습니다.VCNC 개발팀이 스프린트에 등록된 이슈를 얼마나 빨리 해결해 나가고 있는지 보여주는 JIRA의 차트.조금만 생각해보시면 어느 부분이 스프린트의 시작이고 어느 부분이 끝 부분인지 아실 수 있습니다.위와 같은 프로젝트 관리를 위한 일반적인 용도 외에도 엔지니어링 블로그 글 관리를 위해 JIRA를 사용하고 있습니다. JIRA에 엔지니어링 블로그 글감을 위한 프로젝트를 만들어 두고 블로그 글에 대한 아이디어가 생각나면 이슈로 등록할 수 있게 하고 있습니다. 누구나 글감 이슈를 등록할 수 있으며 필요한 경우에는 다른 사람에게 글감 이슈를 할당할 수도 있습니다. 일단 글감이 등록되면 엔지니어링 블로그에 쓰면 좋을지 어떤 내용이 포함되면 좋을지 댓글을 통해 토론하기도 합니다. 글을 작성하기 시작하면 해당 이슈를 진행 중으로 바꾸고, 리뷰 후, 글이 발행되면 이슈를 해결한 것으로 표시하는 식으로 JIRA를 이용합니다. 누구나 글감을 제안할 수 있게 하고, 이에 대해 팀원들과 토론을 하여 더 좋은 글을 쓸 수 있도록 돕기 위해 JIRA를 활용하고 있습니다.JIRA에 등록된 블로그 글 주제들 중 아직 쓰여지지 않은 것들을 보여주는 이슈들.아직 제안 단계인 것도 있지만, 많은 주제들이 블로그 글로 발행되길 기다리고 있습니다.글 리뷰를 위해 Pull-request를 이용하다.Stash는 Attlassian에서 만든 Git저장소 관리 도구입니다. GitHub Enterprise와 유사한 기능들을 제공합니다. Jekyll로 블로그를 운영하는 경우 이미지를 제외한 대부분 콘텐츠는 평문(Plain text)으로 관리 할 수 있게 됩니다. 따라서 VCNC 개발팀이 가장 자주 사용하는 도구 중 하나인 Git을 이용하면 별다른 시스템의 도움 없이도 모든 변경 내역과 누가 변경을 했는지 이력을 완벽하게 보존할 수 있습니다. 저희는 이런 이유로 Git을 이용하여 작성된 글에 대한 변경 이력을 관리하고 있습니다.또한 Stash에서는 GitHub와 같은 Pull request 기능을 제공합니다. Pull request는 자신이 작성한 코드를 다른 사람에게 리뷰하고 메인 브랜치에 머지해 달라고 요청할 수 있는 기능입니다. 저희는 Pull request를 활용하여 상호간 코드 리뷰를 하고 있습니다. 코드 리뷰를 통해 실수를 줄이고 개발자 간 의견 교환을 통해 더 좋은 코드를 작성하며 서로 간 코드에 대해 더 잘 이해하도록 노력하고 있습니다. 새로운 개발자가 코드를 상세히 모른다 해도 좀 더 적극적으로 코드를 짤 수 있고, 업무에 더 빨리 적응하는데에도 도움이 됩니다.어떤 블로그 글에 대해 리뷰를 하면서 코멘트로 의견을 교환하고 있습니다.코드 리뷰 또한 비슷한 방법을 통해 이루어지고 있습니다.업무상 코드 리뷰 뿐만 아니라 새로운 블로그 글을 리뷰하기 위해 Pull request를 활용하고 있습니다. 어떤 개발자가 글을 작성하기 위해서 가장 먼저 하는 것은 블로그를 관리하는 Git 리포지터리에서 새로운 브랜치를 따는 것입니다. 해당 브랜치에서 글을 작성하고 작성한 후에는 새로운 글 내용을 push한 후 master 브랜치로 Pull request를 날립니다. 이때 리뷰어로 등록된 사람과 그 외 개발자들은 내용에 대한 의견이나 첨삭을 댓글로 달 수 있습니다. 충분한 리뷰를 통해 발행이 확정된 글은 블로그 관리자에 의해 master 브랜치에 머지 되고 비로소 발행 준비가 끝납니다.스크립트를 통한 블로그 글 발행 자동화와 보안준비가 끝난 새로운 블로그 글을 발행하기 위해서는 일련의 작업이 필요합니다. Jekyll을 이용해 정적 파일들을 만든 후, htmlcompressor 통해 정적 파일들을 압축해야 합니다. 이렇게 압축된 정적 파일들을 S3에 업로드 하고, CloudFront에 Invalidation 요청을 날리고, 구글 웹 마스터 도구에 핑을 날립니다. 이런 과정들을 s3cmd와 Rakefile을 이용하여 스크립트를 실행하는 것만으로 자동으로 이루어지도록 하였습니다. VCNC 개발팀은 여러 가지 업무 들을 자동화시키기 위해 노력하고 있습니다.또한, s3에 사용하는 AWS Credential은 IAM을 이용하여 블로그를 호스팅하는 s3 버킷과 CloudFront에 대한 접근 권한만 있는 키를 발급하여 사용하고 있습니다. 비트윈은 특히 커플들이 사용하는 서비스라 보안에 민감합니다. 실제 비트윈을 개발하는데에도 보안에 많은 신경을 쓰고 있으며, 이런 점은 엔지니어링 블로그 운영하는데에도 묻어나오고 있습니다.맺음말VCNC 개발팀은 엔지니어링 블로그를 관리하고 운영하기 위해 다소 독특한 방법을 사용합니다. 이 방법은 개발팀이 일하는 방법과 문화에서 큰 영향을 받았습니다. JIRA를 통한 이슈 관리 및 스프린트, Pull request를 이용한 상호간 코드 리뷰 등은 이제 VCNC 개발팀의 문화에 녹아들어 가장 효율적으로 일할 수 있는 방법이 되었습니다. 개발팀을 꾸려나가면서 여러가지 시행 착오를 겪어 왔지만, 시행 착오에 대한 반성과 여러가지 개선 시도를 통해 계속해서 더 좋은 방법을 찾아나가며 지금과 같은 개발 문화가 만들어졌습니다. 그동안 그래 왔듯이 앞으로 더 많은 개선을 통해 꾸준히 좋은 방법을 찾아 나갈 것입니다.네 그렇습니다. 결론은 저희와 함께 고민하면서 더 좋은 개발문화를 만들어나갈 개발자를 구하고 있다는 것입니다.저희는 언제나 타다 및 비트윈 서비스를 함께 만들며 기술적인 문제를 함께 풀어나갈 능력있는 개발자를 모시고 있습니다. 언제든 부담없이 [email protected]로 이메일을 주시기 바랍니다!
조회수 4691

자바스크립트 기초 문법 정리 Part 2 - 객체

지난 Part 1 포스팅에 이어 자바스크립트 기초 문법에 대해 정리해보았습니다. 이번 포스팅에서는 여러 객체와 그 객체에서 제공하는 각 메서드에 대해 정리하였습니다. 다루는 객체의 여러 메서드에 대해 정리하였기 때문에 전 포스팅처럼 간략하지는 않지만 이번 포스팅을 저장해 두고 자바스크립트로 개발하면서 필요할 때마다 참고하여 보기에는 좋을 것 같습니다. 다만, 메서드 사용 예의 코드는 넣지 않았으니 예제 부분이 필요하다면 필히 공식 문서를 참고해주세요. 익히는 것 자체도 공식 문서를 통하여 보는 것이 가장 좋지만 혹여 영어에 취약하신 분이라면 이 포스팅을 참고하는 것도 괜찮을 것 같습니다. :)내장 객체브라우저의 자바스크립트 엔진에 내장된 객체. String/Date/Array/Nath/RegExp Object 등이 있음.날짜 객체 DateDate 객체 생성new Date()new Date(milliseconds)new Date(dateString)new Date(year, month, day, hours, minutes, seconds, milliseconds)Date Get 메서드getDate() - 일 정보를 가져옴.getDay() - 요일 정보를 가져옴. 0(일요일)-6(토요일)getFullYear - 연도 정보를 가져옴. (yyyy)getHours() - 시간 정보를 가져옴.getMilliseconds() - 밀리초 정보를 가져옴. 0-999 (1/1000 초의 단위)getMinutes() - 분 정보를 가져옴.getMonth() - 월 정보를 가져옴. 현재 월에서 -1한 값으로 옴.getSeconds() - 초 정보를 가져옴.getTime() - 1970년 1월 1일부터 경과된 시간을 밀리초로 가져옴.Date Set 메서드setDate() - 일 정보를 설정.setFullYear() - 연도 정보를 설정. 원한다면 월과 일 정보도 설정할 수 있다.setHours() - 시간 정보를 설정.setMillseconds() - 밀리초 정보를 설정.setMinutes() - 분 정보를 설정.setSeconds() - 초 정보를 설정.setTime() - 1970년 1월 1일부터 경과된 시간을 밀리초로 설정.기타 Date 메서드now() - 1970년 1월 1일부터 지금까지의 밀리초를 반환.parse() - 날짜 형태의 문자열을 변환하여 1970년 1월 1일부터 입력한 날짜까지의 밀리초를 반환.toString() - Date 객체를 문자열로 변환.toJSON() - Date 객체를 JSON 데이터로 변환.valueOf() - Date 객체를 밀리초로 반환.숫자 객체 NumberNumber 생성var num = 1;      var num2 = new Number(1);Number 객체의 속성MAX_VALUE - 표현 가능한 가장 큰 수.MIN_VALUE - 표현 가능한 가장 작은 수.POSITIVE_INFINITY - 무한대 수 표기.NEGATIVE_INFINITY - 음의 무한대 수 표기.NaN - 숫자가 아닌 경우 표기.Number 객체 메서드toExponential(n) - 자수 표기법으로 소수점 n자리만큼 문자형 데이터로 반환.toFixed(n) - 소수점 n자리만큼 반올림하여 문자형 데이터로 반환.toPrecision(n) - 유효 숫자 n의 개수만큼 반올림하여 문자형 데이터로 반환.toString() - 숫자형 데이터를 문자형 데이터로 반환.valueOf() - 객체의 원래 값을 반환.parseInt(값) - 데이터를 정수로 변환하여 반환.parseFloat(값) - 데이터를 실수로 변환하여 반환.수학 객체 MathMath 메서드 및 상수Math.abs(숫자) - 숫자의 절댓값을 반환.Math.max(숫자1, 숫자2, 숫자3) - 숫자 중 최댓값을 반환.Math.min(숫자1, 숫자2, 숫자3) - 숫자 중 최솟값을 반환.Math.pow(숫자, 제곱값) - 숫자의 거듭제곱한 값을 반환.Math.random() - 0~1 사이의 난수를 반환.Math.round(숫자) - 소수점 첫째 자리에서 반올림하여 정수를 반환.Math.ceil(숫자) - 소수점 첫째 자리에서 무조건 올림에서 정수를 반환.Math.floor(숫자) - 소수점 첫째 자리에서 무조건 내림해서 정수를 반환.Math.sqrt(숫자) - 숫자의 제곱근 값을 반환.Math.PI - 원주율 상수를 반환.배열 객체 ArrayArray 생성var array = new Array();array[0] = 1;array[1] = 2;var array2 = new Array(1, "temp", true);var array3 = [1, true, "문자열도 가능"];Array 객체의 메서드 및 속성join(연결문자) - 배열 객체에 데이터를 연결 문자 기준으로 1개의 문자형 데이터로 반환.reverse() - 배열 객체에 데이터의 순서를 거꾸로 바꾼 후 반환.sort() - 배열 객체에 데이터를 오름차순으로 정렬.slice(index1, index2) - 배열 객체에 데이터 중 원하는 인덱스 구간만큼 잘라서 배열 객체로 가져옴.splice() - 배열 객체에 지정 데이터를 삭제하고 그 구간에 새 데이터를 삽입할 수 있음.concat() - 2개의 배열 객체를 하나로 결합.pop() - 배열에 저장된 데이터 중 마지막 인덱스에 저장된 데이터 삭제.push(new data) - 배열 객체에 마지막 인덱스에 새 데이터를 삽입.shift() - 배열 객체에 저장된 데이터 중 첫 번째 인덱스에 저장된 데이터를 삭제.unshift(new data) - 배열 객체의 가장 앞의 인덱스에 새 데이터를 삽입.length - 배열에 저장된 총 데이터의 개수를 반환.문자 객체 StringString 생성var str = "hello";      var str2 = new String("hi");String 객체 메서드 및 속성charAt(index) - 문자열에서 인덱스 번호에 해당하는 문자 반환.indexOf("찾을 문자") - 문자열에서 왼쪽부터 찾을 문자와 일치하는 문자를 찾아 최초로 일치하는 문자의 인덱스 번호를 반환. 찾는 문자가 없으면 -1 반환.lastIndexOf("찾을 문자") - indexOf와 동일하나 문자열의 오른쪽부터 찾음.match("찾을 문자") - indexOf와 동일하나 찾는 문자가 없으면 null을 반환.replace("바꿀 문자", "새 문자") - 문자열에서 왼쪽부터 바꿀 문자와 일치하는 문자를 찾아 최초로 찾은 문자를 새 문자로 치환.search("찾을 문자") - 문자열 왼쪽부터 찾을 문자와 일치하는 문자를 찾아 최초로 일치하는 인덱스 번호를 반환.slice(a, b) - a개의 문자를 자르고 b번째 이후에 문자를 자른 후 남은 문자를 반환.substring(a, b) - a 인덱스부터 b 인덱스 이전 구간의 문자를 반환.substr(a, 문자 개수) - 문자열에 a 인덱스부터 지정한 문자 개수만큼 문자열을 반환.split("문자") - 지정한 문자를 기준으로 문자 데이터를 나누어 배열에 저장하여 반환.toLowerCase() - 문자열에서 영문 대문자를 모두 소문자로 바꿈.toUpperCase() - 문자열에서 영문 소문자를 모두 대문자로 바꿈.length - 문자열에서 문자의 개수를 반환.concat("새로운 문자") - 문자열에 새로운 문자열을 결합.charCodeAt("찾을 문자") - 찾을 문자의 아스키 코드 값을 반환.fromCharCode(아스키 코드 값) - 아스키 코드 값에 해당하는 문자를 반환.trim() - 문자의 앞 또는 뒤에 공백 문자열을 삭제.브라우저 객체 모델(BOM)브라우저에 내장된 객체. window 객체브라우저 객체의 최상위 객체.window 객체 메서드open("url 경로", "창 이름", "옵션 설정") - 새 창을 열 때 사용.- open() 메서드 옵션 설정: width/height/left/top/location/status/scrollbars/tollbarsalert("메세지") - 경고 창을 띄움.prompt("질의 내용", "기본 답변") - 질의응답 창을 띄움.confirm("질의 내용") - 확인/취소 창을 띄움.- 확인 클릭시 true 반환, 취소 클릭시 false 반환.moveTo(x 위치값, y 위치값) - 창의 위치를 이동시킬 때 사용.resizeTo(너빗값, 높잇값) - 창의 크기를 변경시킬 때 사용.setInterval("스크립트 실행문", 시간 간격) - 일정 간격으로 반복하여 실행문을 실행시킬 때 사용.clearIntervar(참조 변수) - 참조 변수에 참조되어 있는 setInterval() 삭제.setTimeout("스크립트 실행문", 시간 간격) - 일정 간격으로 한 번만 실행문을 실행시킬 때 사용.clearTimeout(참조 변수) - 참조 변수에 참조되어 있던 setTimeout() 삭제.screen 객체사용자의 모니터 정보를 제공하는 객체.screen 객체 속성width/height/availWidth/availHeight/colorDepth(사용자 모니터가 표현 가능한 컬러 bit)location 객체사용자 브라우저의 주소 창에 url에 대한 정보와 새로 고침 기능을 제공하는 객체.location 객체 속성 및 메서드href - 주소 영역에 참조 주소를 설정하거나 URL 반환.hash - URL의 해시값을 반환.hostname - URL의 호스트 이름을 설정하거나 반환.host - URL의 호스트 이름과 포트 번호를 반환.port - URL의 포트 번호를 반환.protocol - URL의 프로토콜을 반환.search - URL의 쿼리를 반환.reload() - 새로 고침.history 객체사용자가 방문한 사이트 중 이전에 방문한 사이트와 다음 방문한 사이트로 다시 돌아갈 수 있는 속성과 메서드를 제공하는 객체.history 메서드 및 속성back() - 이전 방문한 페이지로 이동.forward() - 다음 방문한 페이지로 이동.go(이동 숫자) - 이동 숫자만큼의 페이지로 이동. 음의 값이면 이전 페이지로 이동.length - 방문 기록에 저장된 목록의 개수 반환.navigator 객체현재 방문자가 사용하는 브라우저 정보와 운영체제의 정보를 제공하는 객체.navigator 속성appCodeName - 방문자의 브라우저 코드명을 반환.appName - 방문자의 브라우저 이름 반환.appVersion - 방문자의 브라우저 버전 정보를 반환.language - 방문자의 브라우저 사용 언어를 반환.product - 방문자의 브라우저 사용 엔진 이름을 반환.platform - 방문자의 브라우저를 실행하는 운영체제를 반환.userAgent - 방문자의 브라우저와 운영체제의 종합 정보를 제공.문자 객체 모델(DOM)HTML 문서의 구조.선택자직접 선택자직접 문서에서 요소를 선택함. (id/class/폼 명/요소 명 등)document.getElementById("아이디 명") - 아이디를 이용해 요소를 선택.document.getElmentsByTagName("요소 명") - 요소의 이름을 이용해 요소를 선택.document.formName.inputName - 폼 요소에 name 속성을 이용해 요소를 선택.인접 관계 선택자직접 선택자를 사용해 선택해 온 문서 객체를 기준으로 가까이에 있는 요소를 선택함. (parentNode/childeNodes 등)parentNode - 선택한 요소의 부모 요소를 선택.childNodes - 선택한 요소의 모든 자식 요소를 선택. 선택한 모든 요소가 저장됨.firstChild - 선택한 요소의 첫 번째 자식 요소만 선택.previousSibling - 선택한 요소의 이전에 오는 형제 요소만 선택.nextSibling - 선택한 요소의 다음에 오는 형제 요소만 선택.문서 객체 이벤트 핸들러 적용하기onclick - 선택한 요소를 클릭했을 때 이벤트 발생.onmousevoer - 선택한 요소에 마우스를 올렸을 때 이벤트 발생.onmouseout - 선택한 요소에 마우스가 벗어났을 때 이벤트 발생.submit - 선택한 폼에 전송이 일어났을 떄 이벤트 발생.버튼document.getElementById("btn").onclick = function() {    alert("welcome");}일단은 참고하는 책을 기준으로하여 정리해보았는데 후에 시간이 될 때마다 공식 문서를 참고하여 번역한다는 생각으로 보다 세부적인 사항을 정리해도 좋을 것 같다는 생각이 드네요. 우선적으로는 빠르게 함수와 이벤트에 대해 배우고 객체에 대한 더 자세한 사항을 정리하도록 하겠습니다. 다음 포스팅은 자바스크립트의 함수와 이벤트에 대해 다룰 예정입니다!참고문헌:Do it! 자바스크립트+제이쿼리 입문 - 정인용JavaScript 튜토리얼 문서 (http://www.w3schools.com/js/default.asp)티스토리 블로그와 동시에 포스팅을 진행하고 있습니다.http://madeitwantit.tistory.com#트레바리 #개발자 #안드로이드 #앱개발 #Node.js #백엔드 #인사이트 #경험공유
조회수 1645

워크인사이트 프론트엔드 개발환경

조이코퍼레이션은 오프라인 고객 분석 서비스인 워크인사이트를 만들고 있습니다. 워크인사이트는 스마트폰 신호를 통해 매장 방문객의 출입 및 체류 패턴을 측정하고 분석합니다. 분석된 데이터는 웹 대시보드를 통해 한 눈에 파악하기 쉬운 형태로 매장에 제공됩니다. 매장들은 이 대시보드를 보고 중요한 판단과 의사 결정을 내리기 때문에 대시보드는 보기 쉬워야 하고 쓰기 편해야 하며 무엇보다 아름다워야 합니다. 조이의 빅데이터 기술을 통해 분석된 데이터를 매장에 효과적으로 전달하기 위해 프론트엔드 기술에 많은 노력을 기울이고 있습니다. 이 글에서는 조이의 대시보드를 만들기 위해 사용하고 있는 기술과 개발 환경 그리고 기술적인 관점에서 고민하고 있는 부분들을 간략하게 공유하고자 합니다.그림1. 대시보드 화면사용하는 기술AngularJS: AngularJS를 기본 프레임워크로 사용하고 있습니다. AngularJS는 SPA (Single Page Application) 형태의 웹 애플리케이션을 빠르게 개발할 수 있도록 도와주는 MVC 프레임워크입니다. 조이에서는 현재 프로덕션 버전인 1.3.x를 사용하고 있습니다. 대시보드는 사용자의 이벤트에 따라 동적으로 데이터를 변경해야하는 애플리케이션적 요소가 많기 때문에 AngularJS의 양방향 데이터 바인딩의 유용함을 느끼고 있습니다.D3.js: 다양한 그래프를 아름답게 보여주기 위해서 D3.js를 사용합니다. D3.js는 데이터 시각화를 위한 자바스크립트 라이브러리로, HTML/CSS/SVG 등의 웹 기술을 이용해 그래프를 그릴 수 있습니다. 자유도가 매우 높아서 생각할 수 있는 많은 형태의 그래프를 그릴 수 있으며 부드러운 전환이나 애니메이션도 추가할 수 있습니다. 다만 초기 학습 비용이 높고 신경쓰지 않으면 너저분한 코드가 양산될 수 있다는 단점도 있습니다.CoffeeScript: 자바스크립트를 더 깔끔하고 효율적으로 사용할 수 있도록 Compile to JS 언어를 사용하는데, 여러 선택 사항 중 CoffeeScript를 사용하고 있습니다. CoffeeScript는 문법적 간결함 덕분에 타이핑을 줄이고 빠르게 코드를 작성할 수 있습니다. 특히 클래스와 클래스 상속 등을 문법적으로 지원하기 때문에 OOP적인 설계를 할 때 도움을 받았습니다. 하지만 자바스크립트와는 다른 새로운 문법을 익혀야하고 그마저도 일관성이 떨어지는 문제가 있습니다. 또 특별한 신경을 쓰지 않으면 가독성이 안 좋은 코드를 작성하기 쉽습니다. 조이에서는 Lint 툴과 코드 리뷰를 통해 코딩스타일을 엄격히 제한하고 있습니다.개발 환경빌드 및 배포: Bower와 npm(Node Package Manager)을 이용해서 패키지를 관리합니다. 빌드 시에는 JS Minify & Uglify, HTML/CSS 최적화, CoffeeScript Lint를 통한 코드 품질 검증, Karma를 이용한 테스트 수행 등의 과정을 거치며 이 모든 빌드 과정은 Grunt를 사용하여 자동화하고 있습니다. 빌드가 끝난 파일들은 AWS (Amazon Web Service)의 S3 저장소로 배포하고 있습니다. 배포 과정 역시 Grunt의 task로 자동화되어 있습니다.코드 관리: 모든 코드는 Jenkins로 통합되어 자동화된 테스트를 통과해야 합니다. 모든 커밋은Gerrit을 통해 다른 엔지니어의 리뷰를 거쳐야만 머지를 할 수 있습니다. 따라서 모든 코드는 적어도 둘 이상의 엔지니어가 이해하고 있습니다. 같은 코드에 대해 더 좋은 설계가 있는지 논의하면서 함께 코드를 발전시켜 나갑니다. 더 좋은 설계가 발견될 때마다 수시로 리팩토링을 진행합니다.프로젝트 관리: 디자이너와 엔지니어 그리고 기획에 참여하는 데이터 분석가 등은 Trello를 이용해 태스크와 이슈를 관리합니다. 일주일을 한 번의 스프린트로 보고 매주 월요일에 일을 분배하고 금요일에 회고를 합니다. 이 과정에서 엔지니어도 기획에 능동적으로 참여할 수 있으며, 어떤 데이터를 어떤 형태의 그래프로 보여주어야 효과적인지를 함께 고민할 수도 있습니다.그림2. 트렐로를 이용한 프로젝트 관리지속적으로 고민하는 부분성능 이슈: 대시보드에는 많은 수치 데이터를 다룹니다. API 서버로부터 하나의 큰 JSON 데이터를 받아서 시간별/일별/요일별/날씨별/최고기온별/평일휴일별 방문객 정보, 방문전환율/체류전환율/구매전환율 등의 지표를 그리기 위한 데이터로 가공합니다. 여기에는 계산량이 적지 않기 때문에 성능에 대한 고민을 많이 하게 됩니다. 연산 로직을 더 간단히 하거나 더 적게 Draw/Redraw 하는 방법을 고민하고 응답성을 향상시키기 위해 Async하게 연산하는 등의 고민을 합니다. 설계: 대시보드는 빠르게 업그레이드됩니다. 기능이 추가되고 변경됨에 따라 그에 맞는 좋은 설계도 계속해서 변합니다. 수시로 진행하는 리팩토링이 좋은 설계를 만든다고 생각합니다. 따라서 리팩토링에 쓰는 시간을 아까워하지 않습니다.테스트: 테스트는 매우 중요합니다. 특히 버그로 인해 잘못된 데이터가 보여지는 것은 용납될 수 없습니다. 그래서 데이터를 가공하는 로직에 대한 테스트는 엄격하게 수행됩니다. 설계 단에서도 테스트하기 쉬운 코드를 작성하려고 노력합니다.최신 기술: 조이의 프론트엔드 팀은 최신 기술에 민감합니다. Gulp, Angular 2.0, EcmaScript6, TypeScript, React와 같은 자바스크립트 최신 기술들에 관심을 갖고 그들의 기본 철학이나 장단점들을 파악하려고 노력합니다. 때때로 우리에게 더 잘 맞는 기술이 등장하면 과감하게 적용하기도 합니다.맺음말조이는 임베디드 기술과 빅데이터 기술을 보유한 기술 회사입니다. 그러나 프론트엔드 기술 역시 그 못지 않게 중요하게 생각하고 있습니다. 말뿐이 아니라 며칠 전에는 OKKY 자바스크립트 컨퍼런스에 후원을 하고 좋은 자바스크립트 개발자들을 만나기 위해서 부스를 차리기도 했습니다. 앞으로도 프론트엔드 기술 관련 컨퍼런스에 후원도 하고 기여도 계속 할 계획입니다.저도 조이에서 엔지니어로 일하면서 훌륭한 동료 엔지니어들과 함께 많은 성장을 했습니다. 무엇보다 기술적인 욕심과 의욕이 넘치는 분위기 속에서 일하는 것 자체가 즐겁고요. 혹시 이 글을 읽고 위와 같은 고민을 공유하고 폭풍 성장을 함께 할 멋진 자바스크립트 개발자가 있다면 이 글을 읽어보시길 바래요 :)그림3. OKKY 자바스크립트 컨퍼런스 부스#조이코퍼레이션 #개발팀 #개발자 #개발환경 #업무환경 #기업문화 #조직문화
조회수 1415

대시보드 만들다 문득,

 고수의 프레젠테이션은 늘 심플하다. 읽기 좋은 보고서는 한 페이지로 요약된다. 가진 정보가 많다는 건 좋은 일이지만 때론 감당할 수 없는 양에 압도 당하고 교란 당한다. 정보는 권력이 된다. 그것의 불균형은 누군가에겐 돈을 벌어다 주고 누군가에겐 좋은 일자리를 준다. 정보가 있는 곳엔 그래서 늘 사람과 힘이 몰린다. 하여, 정보제공자에겐 막중한 책임역시 따라야 한다 생각한다. 제공할 정보가 사실에 기반해야 하는 건 물론이고 더 중요한 건 진정 필요한 콤팩트(compact)한 정보만을 제공해야 한다는 것이다. 현재진행형인 대시보드(dashboard) 프로젝트 과정에서 위와 같은 생각이 들었다. 그러면, 주관과 사욕을 완전히 배제하고, 내가 드러내고 보여주고 싶은 정보가 아니라 최대한 많은 이에게 가치롭게 활용되는 정보는 어떤 형태여야 할까? 스스로 답을 내렸다.  우선 사람별, 상황별로 다른 관점과 해석이 양립할 수 없는 요소로 구성돼야 하고, 전달과정에서 요구되는 추가적 배경지식은 불필요해야 하며 필요하다면 극히 적은 양이어야 한다. 무엇보다 관련된 이는 누구나 궁금해 해야 할 것이어야 하고 부차적인 것을 제외한 본질만을 담고 있어야 한다. 이 같은 정보를 핵심정보라고 정의하면 핵심정보는 각각의 업이 가진 '본질적 성장 방정식(fundmetal growth equation)'과 연관이 깊다. 본질적 성장 방정식이란 현 시점에서 비즈니스의 성장을 추진하는 모든 핵심요소, 즉 핵심적인 성장 지렛대를 표현한 간단한 공식을 뜻한다. 제아무리 시가총액 1조를 넘은 기업일지라도 그들의 성장공식을 대여섯 가지의 핵심요소로 도식화하는 것은 가능하며 그것은 제품, 서비스가 가진 성격별로 달라진다. 본질적 성장 방정식을 <진화된 마케팅 그로스 해킹>이란 책에서 나온 사례를 인용해 예시를 들면 아래와 같다.# 이베이의 방정식{아이템을 등록한 판매자의 수}x{등록된 아이템의 수}x{구매자의 수}x{성공적인 거래의 수}=총 매출 성장# 어느 온라인 뉴스사이트의 방정식{웹사이트 트래픽}x{이메일 전환율}x{활성 사용자 비율}x{유료구독으로의 전환율}+다시 찾은 구독자 =총 구독자 매출 성장 이베이의 방정식을 보면 트래픽 양보다는, 거래량을 일정수준 이상 유지하는 것이 성장에 있어 더 중요한 미션일 것이다. 그래서 신규 셀러와 동시에 판매 아이템에 대한 공급이 지속적으로 원활히 이뤄져야만 한다. 아울러 매일, 매주 등록되는 아이템 개수와 그것의 품질, 카테고리 같은 것도 광장히 중요한 관리요소 중 하나일 것이다. 한편, 어느 온라인 뉴스사이트의 경우 트래픽의 양은 광고매출과 직결되고 신규 독자 확보의 가능성을 높여주는 성과의 선행지표다. 뉴스레터 이메일은 수신자를 이후 결제 - 유료구독 -할 확률이 높은 활성 사용자로 전환시키는 데 주력할 것이다. 그래서 사이트를 드나드는 빈도가 높은 활성 사용자층을 얼마나 두껍게 유지하느냐는 온라인 뉴스 비즈니스에서 관건 중 하나일 것이다.  참고: https://www.youtube.com/watch?v=PvSW0ri7AEg기본적인 매출 성장 방정식을 소개하는 강의 동영상이 있어 첨부한다 이처럼 본질적 성장 방정식을 구성하는 요소를 해부해보면 어떤 정보가 현 시점에 우리의 비즈니스를 이끄는 핵심정보이고, 비교적 불필요한 정보인지, 잘 드러난다. 또한, 생각한 것보다 관리해야 할, 혹은 제공해야 할 정보가 적다는 것에 놀란다 - 개인적으론 충격이었다.  페이스북 광고 관리자 페이지에서 관찰할 수 있는 데이터 필드 수는 맞춤설정 활용 시 약 300개까지 지원된다. 그들 중 절반은 서비스와 관련성이 적거나 매일 추적한다 해도 당장의 마케팅 관련 의사결정에 도움을 주지 못하는 것이 대부분일 수 있다. 구글애널리틱스에서 제공하는 지표 또한 마찬가지다. 이탈률을 체크하는 것이 중요하다고들 하지만, 서비스의 태생적 특성 상, 신규 사용자 유치를 위해 지속적이고 공격적인 온라인 광고가 불가피하다면? 때론 업계 평균보다 높은 이탈률이 당연한 것이고 그것이 가진 시사점은 적을 수도 있다. 단지 '쿨'해 보이는 지표를 관찰할 게 아니라 각각의 비즈니스 '실정'에 맞는 성장 방정식을 꾸리고 그것을 지켜 보는 게 중요하단 말이다. 결론적으로 다시 대시보드 이야기로 돌아가면, 정보판으로써 구실하기 위한 최소요건으로 대시보드에는 성장 방정식을 이루는 구성요소만 들어있으면 된다. 그것들이 최소요건이자 거의 대부분이다. 그 외 정보는 실제로는 불필요하거나 수요가 낮은 정보일 가능성이 높다. 물론 그런 정보는 필요에 따라 '드릴 다운' 방식으로 제공하는 것도 좋겠다. 하지만 당장의 우선순위는 아니란 것이다. 대시보드의 첫인상은 고수의 피티처럼 심플하고, 잘 짜여진 보고서 앞 한 장 요약본처럼 말하는 바가 적확해야 한다.블랭크 코퍼레이션의 CI내밀한 이야기가 될 수 있는데, 대시보드 프로젝트를 진행하며 자사 비즈니스의 본질적 성장 방정식은 어떻게 생겼을까, 혼자 그려봤다. 디지털 마케팅  중심적 사고이기 때문에 주관적이며 생각차는 있을 수 있다. 그리고 미래의 가변적 환경을 반영하지 않았다. 어차피 대시보드에선 미래를 projection하지 않기 때문이다.# (현 시점 기준) blank의 방정식{상품기획력}x{콘텐츠 파워}x{SNS 광고비}x{광고유입후 0일-1일내 구매하는 이의 비율}x{재구매율}x{고객생애가치}= 성장의 크기 방정식 안에 bold체로 표시된 요소를 살펴보자. 내가 생각하는 - 공식적인 내용이 아니다 - 우리의 모델 안에서 {SNS 광고비}는 성장(매출)의 크기를 좌우하는 핵심인자다. 광고를 통해 설득 당한 잠재고객을 단번에 구매로 이끌 수 있는 흡인력 - 앞선 방정식에선 {광고유입후 0일-1일내에 구매하는 이의 비율}로 표시했다 - 을 지속하느냐 또한 DR(direct response ; 직접 반응) 마케팅에서 관찰하고 관리해야 할 주요요소다. 이후 구매자의 {재구매율}과 {생애가치}도 이해하고 관리할 수 있다면 완벽할 것이다. 하지만 해당 지표의 정의와 계산은 마냥 쉽지 않기에 정밀한 설정 안에서 관련 정보의 해상도를 높이는 일이 요구된다. 이 정도의 정보가 현 시점에서 마케팅 유닛에서 필수적으로 관찰하고, 유관부서에 공유해야 할 핵심지표가 될 수 있을 것이다. 대시보드 상에 CTR(클릭률), CPC(클릭당비용), CPM(1,000회 노출당비용)과 같은 매일의 광고지표를 넣었다간 보는 이로 하여금 복잡성만 가중시킬 뿐이다. 전자상거래 마케팅 과정에서 오직 알아야 할 정보는 "광고비를 얼마나 효율적으로 투자해 얼마를 벌었는가"라고 생각한다. 현재 페이스북이 제공하는 구매 최적화 광고의 알고리듬 상에선 구매 수와 CPA(액션당비용, 구매당비용) 외 다른 지표들은 그때그때 알고리듬 컨디션에 따라 결정되는 후행지표이자 수단일 뿐이다 - 이 부분은 나중에 기회가 있다면 더 설명해보고 싶고 다른 이와 토의하고 싶다. 불과 얼마 전까지 - 아니면 지금까지; - 난 아마도, 엑셀 시트에 피봇테이블을 덕지덕지 붙여넣고 형형색색으로 트렌드를 표시하면 좋은 정보가 되는 줄 착각했었다. 그리고 난 데이터분석가도 아니고 고급통계지식이 풍부한 편도 아니다. 프로그래밍을 할 줄 알아 데이터 처리기술이 남다른가? 고작 엑셀 단축키와 기본 함수를 사용해 평균보단 빠르게 잔머릴 굴리는 정도다. 하지만 최근에는 시각화, 데이터분석, 고급통계지식 모두 중요한 정보를 전달하는 수단일 뿐이란 생각이 든다. 자기위로적 감상일 수 있지만, 정말로, 정보를 다루는 데 있어 그러한 스킬보다 중요한 건 진정 필요한 정보를 옥석 가리듯 가려내는 정보 분별력이라고 생각한다. 수단에 현혹돼 정작 알맹이는 없고, 누구에게도 도움되지 않는 보고서를 만드는 일이 어떤 마케터, 사업PM에게도 없었으면 하는 바람이다.(끝)Jin Young Choi회사원

기업문화 엿볼 때, 더팀스

로그인

/