ORCINUS: 공군인터넷편지 UX 개선 프로젝트
개요
최근 산업요원 준비를 하면서 예전에 해두었던 프로젝트를 다시 뒤적거리는 중이다. 육군, 해군을 위한 인터넷 편지 모바일 웹 어플리케이션은 개발을 한 전적이 있지만 공군은 내가 아직 안했더라. 마침 동아리 후배가 공군 훈련소를 들어갔다고 해서 공군기본군사훈련단 인터넷 편지를 위한 서비스를 만들어보기로 했다.
사실 이 모습을 보면 프로덕트 개발자라면 누구든 뜯어고치고 싶은 마음이 들 수 밖에 없다. (모바일도 똑같은 UI로 뜬다.)
기획
목표하는 기능은 딱 하나였다. ‘원하는 훈련생에게 편지보내기’
기존 공군기본군사훈련단 인터넷 편지 시스템은 다음과 같은 순서를 거쳐 편지를 전송한다.
- 공군기본군사훈련단 홈페이지 접속
- 인터넷 편지 메뉴 선택
- 교육생 이름 및 교육생 생년월일을 통해 교육생 검색
- 입영일과 소속을 확인하고 편지를 작성할 교육생 선택
- 작성된 편지 목록에서 인터넷 편지쓰기 버튼을 누르기
- 주소, 발신자 이름, 관계, 제목, 내용, 비밀번호를 입력하고 작성완료 누르기
위 프로세스에서 발견한 문제점은 크게 두 가지였다.
- 해당 서비스를 이용하려는 사람은 위 과정에서 매번 3~4번에 해당하는 교육생 검색 및 선택 기능을 거쳐야한다.
- 6번에서 한 화면에 입력해야하는 정보의 값이 과도하게 많다.
1번 문제점은 미리 필요한 정보가 입력된 링크를 제공하는 것이다. 이렇게 하면 편지 작성자가 매번 훈련생 정보를 입력하고 검색하고 선택할 필요가 없어진다.
6번은 한 화면을 여러 화면으로 나누어 구성하기로 했다. 작성자 정보 / 편지 내용 / 비밀번호 3개로 분류했다.
디자인
디자인은 ‘모바일 퍼스트’ 원칙을 세우고 시작했다. 데스크탑 UI를 모바일에서 보면 정말로 끔찍하지만, 그 반대는 봐줄만 하다. 더 편할 때도 있고.
빠르게 Figma를 이용해 디자인했다. 컴포넌트도 적고 구성해야할 화면도 얼마되지 않았기 때문에 30분 정도 소요됐다.
컴포넌트를 재사용하는 일도 많지 않았기 때문에 디자인시스템도 최소한의 요소(색상, 폰트, 아이콘)만 구성했다. 아이콘은 라이선스 문제가 없는 Feather Icon을 가져다 썼다.
개발
새로운 스택을 적용하기 보다는 평소에 제일 즐겨쓰는 스택들을 사용했다.
- React + Typescript를 사용했다. 바닐라 JS를 쓸 수도 있었지만 이제는 타입이 없으면 더 불편하다…
- tailwind… 써볼까 하다가 그냥 익숙한 styled-components로 했다.
- Vite + pnpm + swc 로 빌드 환경을 구성하여 가장 빠르게 빌드가 가능하도록 했다. (진짜 빠르다)
- 배포는 vercel에 github 레포지토리를 연결하여 CI/CD를 구성했다.
- 백엔드는 필요가 없었다. API는 공군기본군사훈련단의 api 엔드포인트만 따와서 필드에 알맞은 값을 집어넣고 전송하면 되니깐.
UI 개발에서 크게 특별하거나 설명할 부분은 없다. 깨지거나 크게 문제 생기는 것 없게끔 작성했다.
API 연결에서는 CORS 문제를 오랜만에 겪었다.
CORS(Cross-Origin-Resource-Sharing)란?
보통 웹페이지를 구성할 때 사용되는 리소스들은 내 서버에 있는 것들로 이뤄지는 경우가 많지만, 외부에 있는 리소스를 끌어다 사용해야 할 때가 있다. 예를 들어 이미지 같은 경우는 내 서버에 올려두지 않고 외부 이미지 저장소에 올려두고 이미지 주소만 가져와서 사용하는 식이다. 폰트도 외부 주소로 달아놓는 경우가 많다.
이미지나 비디오 같은 몇 가지 태그는 기본적으로 리소스를 요청하는 서버와 요청받는 서버가 서로 달라도 된다. (이걸 Cross-Origin 정책을 지원한다고 한다.)
하지만 fetch나 axios 같은 함수로 외부에 XMLHttpRequest를 요청하는 경우 (보통 우리가 api 호출이라 부르는거) 리소스 요청 서버와 요청 받는 서버가 다르면 보안상의 이유로 제한을 걸어버린다. (이건 Same-Origin 정책이라 부른다)
SOP(Same-Origin 정책)이 없으면 어떤 일이 일어날까? 만약 naver.com이 아닌 never2232.com 같은 피싱사이트가 네이버와 똑같은 모습을 하고서 네이버의 API를 사용하여 네이버의 검색결과를 보여준다고 하자. 그냥 보여주는거라면 괜찮겠지만, 피싱사이트 운영자가 악의를 갖고 중간의 검색결과를 무단으로 수집하거나, 변형해서 보여준다는 등의 문제가 발생할 수 있다.
CORS에 대한 설명은 여기까지만 하고, 더 자세한 설명은 아래 글에 잘 설명되어 있으니 읽어보면 좋다.
🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏
아무튼 저 문제는 브라우저단에서 발생하는 문제이기 때문에 브라우저를 속일 수 있도록 내 서비스와 origin이 동일한 프록시 서버를 만들고, 프록시 서버에서 원하는 서버로 요청을 주고 받은 다음, 프록시 서버에서 다시 내 서비스로 요청을 전달해준다면 CORS 문제를 피할 수 있다.
프록시 서버를 설정하는 일이 귀찮기 때문에 웬만해서는 요청을 받는 서버 개발자에게 CORS 설정을 열어달라고 하면 되지만, 공군에서 한낱 개인인 우리에게 그 부탁을 들어줄리가 없으므로 프록시 서버를 설정해서 해결했다.
앞서서 CORS와 관련하여 발생할 수 있는 보안문제 사례로 피싱사이트 예시를 들었는데, 사실은 우리가 만든 orcinus도 피싱사이트와 원리는 동일하다. 공군인터넷편지 서버로 가는 요청을 공군인터넷편지 페이지가 아닌 우리가 만든 orcinus 페이지에서 보내고 받게끔 한 것이다.
그래서 이 프로젝트의 모든 코드를 공개하고 누구나 확인할 수 있게끔 GitHub에 업로드했다. 이러면 Orcinus 서비스가 중간에서 이상한 짓을 하지 않는다는 것을 증명할 수 있다.
결과
lighthouse라는 구글에서 만든 웹 페이지 성능 테스트 툴을 사용하여 측정한 결과, 기존에 80점에 불과하던 공군 인터넷편지 페이지를 개선한 orcinus 페이지의 점수는 99점까지 끌어올릴 수 있었다. 속도와 관련된 수치에서 2배 이상의 향상을 확인할 수 있었다.
접근성 점수도 향상되었는데, 실제 사용성은 모바일 UI를 새로 만들었다는 점에서 체감이 더 클 것으로 예상된다.
결론
서비스를 배포하고 약 일주일간 143명의 유저가 다녀갔고, 이 중 실제 편지 작성으로 이어진 건수는 52건으로 확인되었다. 인터넷편지 링크를 훈련생의 SNS에 올리는 경우가 대부분인만큼 인스타그램 링크를 통해 들어온 유저가 제일 많았다.
훈련소에 들어간 동아리 친구도 꽤나 많은 편지를 받을 수 있게 되었고, 나는 뿌듯함을 얻어갈 수 있게 되었다.