WON JI EUN

겸손한 프론트엔드 개발자입니다. 멋지고 화려한 코딩 스타일보다 명확하고 이해하기 쉬운 코딩 스타일을 선호합니다. 코드 리팩터링을 습관화하기 위해 노력합니다. 새로운 것을 접하고 배우는 일에 도전적이고 적극적입니다. 기능을 분석하여 문제를 해결하고 결과물을 만들어내는 개발의 과정을 즐깁니다. 사람들과 다양한 분야의 대화를 즐깁니다. 대화에 있어서 상대방의 이야기를 경청하는 편입니다. 학습 방식은 책, 스터디를 통해 이론을 공부하고 회사 업무에 적용해 보거나 Github 개인 프로젝트 공간에서 실습합니다. 최신 기술에 대한 소식을 접하는 곳은 공식 레퍼런스 또는 Github, 개발자 커뮤니티, YouTube, Reddit, Tech 컨퍼런스입니다. 배운 것을 주변에 공유할 때 많이 배운다고 믿고 있고 매주 스터디 활동을 통해 실천합니다. 도움을 주는 개발자가 되는 것에 목표를 두고 있습니다. 함께 성장할 수 있는 환경에서 서로를 존중하며 일하고 싶습니다.
Work Experiences
Frontend Developer
- 얼라인업 v2 개발
- Vuejs, Nuxt Framework 프로젝트 설정
- TypeScript 구축 및 개발
- Token을 이용한 클라이언트 인증 및 권한 처리
- AWS S3, CloudFront 정적 웹 호스팅 환경 구성
- Github Action 배포 자동화 구축
기업의 조직 문화 변화를 돕고 구성원들의 업무 몰입도를 높여주는 OKR 성과 관리와 인재 관리 시스템인 HR-tech 얼라인업v2 프론트엔드 개발을 담당하였습니다. 주 언어로 JavaScript, TypeScript, Vuejs를 사용하였습니다. AWS S3, CloudFront, Github Action으로 배포 자동화 프로세스를 구축하였습니다.
Frontend Developer
- 숨고, 백오피스 개발 및 유지보수
- Vuejs, Bootstrap Vue
- React, Redux Toolkit, material-UI
- TypeScript 개발 및 운영
- Node.js 기반 Server-side Rendering
- Viewport에 맞는 반응형 웹 개발
- 크로스 브라우징 (IE11, Chrome, Safari, Mobile browser)
- 페어코딩, 코드리뷰, 기술리뷰 경험
숨고 웹 프론트엔드와 백오피스 개발 및 유지보수에 참여하였습니다. 주 언어로 JavaScript, TypeScript, Vuejs, React를 사용하였습니다. 숨고는 Vuejs, 백오피스는 React 기반으로 개발하였습니다. 백오피스 프로젝트는 상태 관리 도구로 redux-toolkit을 이용했고 material-UI로 퍼블리싱 작업을 진행하였습니다.
Frontend Developer
- CMS 프론트엔드 개발 및 유지보수
- CRA Boilerplate Project
- Nodejs 환경에서 개발, Expressjs를 통해 배포
- React 16의 Context API로 상태 관리
- Window 백그라운드 서비스에 Nodejs를 등록하기 위해 NSSM을 서비스 관리자로 이용
초/중/고 도서관 대상 교과연계 도서관리 프로그램인 스쿨북스와 도서 큐레이션 서비스인 인생서가 프론트엔드 개발을 담당하였습니다. 전자도서관 유지보수 업무로써 다른 플랫폼과의 대출정보, 회원정보 동기화 업무를 진행하였습니다. 도서관에서 주문받은 전자책 납품을 위해 DRM 패키징 업무를 맡았습니다.
Projects
인생서가
인생서가는 7가지 콜렉션과 도서/상황 카테고리 별로 이용자가 선택한 정보에 대해 적합한 도서 목록을 추천해주는 큐레이션 서비스 입니다. 이 서비스의 CMS 관리자 페이지의 프론트엔드 개발을 맡아 진행하였습니다. 보일러 플레이트 프로젝트로 생성하여 Express 서버에 배포하였습니다. 데이터의 기본적인 CRUD를 개발하였습니다. 로그인 정보는 JWT로, 상태는 React 16 버전의 context API로 관리하였습니다. 페이지 이동이 잦고, 데이터가 많이 오고 가는 만큼 프로젝트 개발 초기에 설계하는 데에 어려움이 있었습니다. 공통이 되는 컴포넌트를 효율적으로 사용하기 위해 state와 라이프사이클이 필요한 컴포넌트는 stateful로, props를 통해 부모의 데이터를 받아 렌더링의 역할만 하는 컴포넌트는 stateless로 구현하였습니다. REST api를 호출하는 방식은 Axios로, 폴더 구조는 container, presenter, index 패턴으로 구성하였습니다.
숨고 캐시 결제 개발
6개월의 진행 기간 동안 멤버쉽에서 숨고캐시로의 BM모델 전환하는 프로젝트에서 캐시 결제 기능을 개발하였습니다. Iamport 결제 모듈을 사용하여 결제연동을 진행하였습니다. 데스크탑웹과 모바일웹 결제 플로우의 차이점을 고려하여 개발하였습니다. 데스크탑웹은 결제창이 모달 방식으로 띄워져 결제완료 후에 자동으로 이전 페이지로 리다이렉트 되는 방식이라면, 모바일웹은 redirect_url 속성을 명시하여 결제창 동작 방식을 제어합니다. 결제창을 요청하기 전, 서버와의 통신을 통해 아임포트 요청에 필요한 값을 받아오고, 유저가 결제 완료 후 캐시를 지급하는 플로우를 개발하였습니다. 캐시 구매 어뷰징 방지를 위해 productId와 transactionId, userId를 검증하였고 어뷰징으로 의심되는 요청에 대해서는 캐시 지급 실패 처리하여 고객센터로 인입하여 처리하도록 구현하였습니다.
크로스 브라우징 IE11
크로스 브라우징을 위하여 인터넷 익스플로러 버전 11 이상을 지원하며 개발하였습니다. 그 과정에서 첫 페이지 렌더링 후, 동일한 페이지 새로고침 시 데이터를 불러오지 못하는 이슈가 있었습니다. 이슈를 분석해보니 HTTP Option Request는 정상적으로 요청하지만 이후에 발생하는 Main Request GET 요청이 발생하지 않는 현상이 있었습니다. 인터넷 익스플로러 Network단의 HTTP 캐싱 전략으로 인한 이슈였고, HTTP Request Header에 Cache-Control: no-cache 옵션을 추가하였고, 조금 더 확실한 방식으로 API 요청 쿼리 파라미터에 Date.now() 함수를 넣어 이슈를 회피할 수 있었습니다.
django + vue template 레거시 페이지 마이그레이션
숨고에 있는 레거시 시스템을 마이그레이션하는 작업에 참여하였습니다. 레거시 시스템은 python django + vue template 한 프로젝트 내에 서버, 프론트 코드가 공존하고 있는 MPA였습니다. 레거시 시스템에 존재하는 모든 페이지를 Node express + Vuejs SPA로 마이그레이션 과정에서 1주일 개발 기간 동안 마이페이지 관련 페이지를 담당하여 진행하였습니다. 마이그레이션의 핵심 요구사항은 TypeScript 기반 Vue 컴포넌트를 구현하는 것이었습니다. vue 컴포넌트를 class 기반으로 작성하고 vuex-module-decorators 모듈을 사용하여 하나의 모듈 클래스 파일에서 type, state, mutations, getters, actions를 덕 패턴으로 구현하였습니다.
숨고 바로견적 기능 백오피스 개발
바로견적 기능에 대한 백오피스 개발 및 내부 직원을 위한 유지보수를 하였습니다. 백오피스는 React 기반으로, 상태 관리 도구로 redux-toolkit을 이용했고 material-UI로 UI 퍼블리싱 작업을 진행하였습니다. 숨고의 요청폼은 간단한 기본 텍스트 유형의 질문과 답변부터 기본타입, 서브타입을 가지는 질문과 검증 타입, 직접 입력 유형 형태 (달력, 텍스트)를 가지는 답변까지 복잡한 스키마 유형을 가지고 있습니다. 백오피스 개발 요구사항은 새로 생긴 기능인 바로견적 요청폼 복제하는 기능이었습니다. 백엔드 리소스가 없는 상황에서 질문과 답변 추가/수정/삭제 API만을 가지고 요청폼 복제 기능을 구현하기 위해 Bluebird 라이브러리를 사용하여 Promise.map을 구현하였습니다. concurrency 옵션을 통해 반복하는 개별 작업의 Promise resolve를 보장하였습니다. 프론트엔드 리소스만으로 기능을 개발하여 내부 직원들의 만족도 향상에 기여하였습니다.
마케팅팀과의 협업, 서드파티 사와의 의사소통
마케팅팀과는 트래커 관련 협업이 주로 이루어졌습니다. 이벤트 트래커 통합 솔루션인 Segment를 활용하여 트래커를 쌓고 있고 이를 통하여 커뮤니케이션을 했습니다. 협업 과정 중 Facebook Pixel 트래커가 누락되는 현상을 겪었습니다. Segment 내의 Facebook Pixel 트래커와 Facebook Pixel Console에 보이는 트래커가 특정 날짜 이후로 수집이 되지 않는 현상이었습니다. 광고 집행의 큰 타격을 입을 수 있는 중요한 사안이었습니다. 결론적으로 이 이슈는 Facebook Pixel 쪽에 DLU (Data Limited Use)라는 데이터 프로세싱 방식에 대한 정책이 배포 되었기 때문이었습니다. 트래커 누락이 시작된 날짜에는 배포사항도 없고, 아무런 코드 변경사항이 없었기 때문에 파악하기 힘든 이슈였습니다. 이 이슈를 통해서 깨달은 점은 서드파티 간에 알 수 없는 원인으로 발생하는 이슈는 성급하게 코드를 수정하기 보다 서드파티 사에 적극적인 지원을 받자는 것이었습니다.
채팅방에서 거래할 수 있는 숨고페이 개발
채팅방에서 고수/고객 간에 안전거래(숨고페이 이전 버전) 기능을 개선하고 더 나은 사용자 경험을 위한 숨고페이 개발에 참여하였습니다. 기존 거래는 가상계좌 결제 방식만을 제공하였고 가상계좌 거래를 위한 서드파티 라이브러리에 대한 이슈가 잦아 수기로 입금을 해주는 일이 빈번하였습니다. 숨고페이는 이런 문제를 개선하기 위해 카드결제, 간편결제 방식을 도입하여 편리성을 제공하고자 했습니다. 채팅방 도메인과 결합도가 높았던 안전거래 기능을 분리하여 코드에서 제거하고 숨고페이의 새로운 도메인을 생성하여 작업하였습니다. 고수/고객 간에 거래가 이루어지는 채팅방 페이지의 데스크탑웹과 모바일웹의 매우 다른 UI/UX를 표현하는 데에 어려움이 있었습니다. 채팅방 헤더는 채팅방의 상태에 따른 헤더 UI, 데스크탑웹과 모바일웹 다른 UI, 유저가 고수인지 고객인지, 고용 상태에 따른 버튼의 상태, 추가로 거래 상태마다 다른 프로그레스바와 버튼의 상태를 분기하여 구현하였습니다. 확장성과 유지보수성을 고려하여 복잡한 조건 분기는 이름이 있는 변수로 분리하였고 코드의 가독성을 해치지 않기 위해 템플릿 레이아웃을 작은 단위로 분리하여 리펙터링하였습니다.
TypeScript 구축 및 마이그레이션
Nuxtjs Framework 기반의 프로젝트에 컴파일러 옵션 설정을 위한 tsconfig.json을 추가하고 기존 코드를 TypeScript로 마이그레이션 하였습니다. IDE의 컴파일 시간을 개선하기 위해 exclude 속성으로 컴파일 옵션을 적용하지 않을 디렉터리를 추가하였습니다. 컴파일 결과물의 JavaScript 버전은 ES5로 target 속성에 정의해주었고, 모듈 시스템은 commonjs으로 module 속성에 정의해주었습니다. TypeScript 마이그레이션 작업은 API 요청 payload와 응답 response를 interface로 정의하여 개발 환경에서 타입 추론이 가능하도록 하였습니다. 사용 중인 서드파티 라이브러리의 타입 정의를 위하여 선언 파일이 번들되지 않은 서드파티 라이브러리는 Definitely Typed 저장소에서 라이브러리를 설치하였습니다. 선언 파일을 제공하지 않을 경우 types/ 디렉터리 하위에 glob pattern의 *.d.ts 로컬 선언 파일을 생성하였습니다.
Safari 브라우저에서 렌더링 성능 개선
Safari 브라우저에서 테스트 중 로그인 페이지에서 동작이 느린 성능 장애를 겪었습니다. 입력, 드래그 등과 같은 사용자 액션에 대한 버벅거림이 심한 현상이었습니다. 이슈 파악을 위해 페이지가 로드 될 때까지 브라우저 inspector의 타임라인을 확인하였습니다. Energy Impact가 매우 높은 수준이고 주 스레드의 Paint 비율은 85.5%였습니다. 로그인 페이지는 아이디와 비밀번호를 입력할 수 있는 폼이 있는 간단한 페이지입니다. 배경은 background 속성의 linear-gradient와 filter 함수를 사용하여 그라데이션을 구현했습니다. Safari 브라우저의 Webkit 엔진은 CSS의 gradient, shadow, filter 등의 그리기 속성은 꼭 필요한 경우에만 사용하도록 권장하고 있고 그렇지 않으면 정적 이미지를 권장합니다. 이 점으로 미루어보아 로그인 페이지의 배경 UI가 성능 저하의 원인이었습니다. 문제가 되는 CSS 속성을 제거하고 정적 이미지를 배경으로 사용하여 동작이 느린 현상을 해결하였습니다. 개발자 도구 타임라인의 주 스레드 Paint 비율이 85.5%에서 12.8%로 내려갔습니다. 브라우저마다 다른 엔진의 특성을 인지하여 성능을 개선하는 방법을 배울 수 있었습니다.
Token 기반 인증 및 권한 처리
OAuth2 인증 방식의 클라이언트 측을 구현하였습니다. 기본 플로우는 유저가 입력한 로그인 정보, client_id, client_secret, grant_type을 서버 측에 전달합니다. 서버는 인증에 필요한 access_token, refresh_token을 응답으로 보내줍니다. 매 요청의 인증 헤더에 access_token을 실어 서버에 전달하여 권한 처리를 합니다. 토큰이 만료가 되면 HTTP 요청에 의한 401 응답 코드를 받습니다. refresh_token을 사용하여 토큰 재발급 과정을 거쳐 토큰을 갱신합니다. 갱신한 토큰으로 매 요청의 인증 헤더에 실어 보내는 일련의 과정을 반복합니다. 로그아웃을 하면 저장된 두 토큰을 모두 삭제합니다. 토큰은 클라이언트에 저장 및 관리하였습니다. access_token은 상태 관리 도구인 vuex의 store에서 관리하였습니다. 토큰을 재발급할 때 사용하는 refresh_token은 브라우저 쿠키에 저장하였습니다. 쿠키의 속성에 Secure, SameSite 설정을 추가하여 보안을 향상시켰습니다.