2020년 회고
올해부터 블로그에 1년 단위로 뭘 했는지 회고를 써 보기로 했습니다. 나중에 잊어버리면 슬프잖아요.
애초에 애인도 친구도 없어서 약속 없는 핑계를 코로나 때문이라고 둘러댈 수 있는 좋은 한 해였습니다. 이른바 명예로운 자가격리를 당한 거죠. 저희 집에서 가장 가까운 박쥐 동굴 방향으로 하루에 세 번 절하고 있습니다.
그래도 코로나가 12월에는 끝나있을 줄 알았는데 그것도 아니더라구요. 일일 확진자 수 최고치 연일 갱신 중이고 저는 집에서 재택근무를 하고 있습니다. 엇 그래도 이제 직장은 있군요 다행이에요
소프트웨어 개발
solved.ac
올해는 solved.ac 개발에 꽤 집중했습니다. 올해 솔브드에 새로 생긴 큼직한 기능들은 다음과 같습니다.
- 문제 정렬. (2월) 문제 목록에서 문제 순서를 쉽게 정렬할 수 있습니다.
- 고급 검색. (2월) 문제 제목뿐 아니라, 맞은 사람 수, 문제 레벨, 내가 푼 문제 등에 필터를 걸 수 있고, AND, OR 등의 연산자를 이용해 검색하는 것이 가능해졌습니다. 검색 쿼리 문법을 직접 만들고, 이를 해석하는 파서 등도 만들었습니다.
- 프로필 배경. (2월) 프로필을 배경으로 꾸밀 수 있게 되었습니다.
- 라이벌. (4월) 다른 유저를 라이벌로 등록하고, 라이벌들과 나의 순위를 볼 수 있습니다.
- 프로필 사진. (5월) 프로필 사진을 올릴 수 있게 되었습니다.
- 화이트리스트제 종료 및 베타 종료. (6월 5일) 지금은 상상하기 힘들지만, 6월 이전에는 솔브드를 사용하려면 제게 이메일을 보내서 화이트리스트에 등록되어야 했습니다. 6월부터는 기존처럼 크롤링 및 파싱을 하는 방식에서 BOJ에서 유저 정보를 직접 받아오는 방식으로 바뀌어서, 누구나 사이트를 사용할 수 있게 되었습니다.
- 코드 교환. (8월) 리딤 코드를 입력해 배경과 프로필 뱃지 등을 교환할 수 있게 되었습니다.
- 자동 갱신. (11월) 이것도 지금은 상상하기 힘들지만, 11월 이전에는 문제를 풀고 나서 프로필에 있는 ‘갱신’ 버튼을 직접 눌러줘야 했습니다. 지금은 문제를 푸는 즉시 경험치가 반영되기 때문에 굳이 갱신 버튼을 누를 필요가 없습니다.
이제 BOJ와의 통합 작업도 거의 마무리되어 solved.ac에 굳이 들어오지 않고도 BOJ에서 solved.ac 문제 난이도와 태그 정보를 확인할 수 있게 되었습니다. 또한, 길라잡이 등의 새로운 기능들이 공개를 앞두고 있습니다. 내년에도 잘 부탁드려요!
Javascript 프레임워크의 세계로
solved.ac의 소스 코드는 원래 대부분 PHP로 되어 있었습니다. 프론트엔드 코드가 복잡해지면서 유지보수에 무리가 갔고, PHP의 특징적인 여러 요소들 때문에 코드 베이스가 PHP인 이상 추가적인 무언가를 개발하기는 힘들겠다 싶었습니다.
그래서 컴포넌트를 만들고 재사용하기 좋다고 들은 React로 무작정 프론트엔드 포팅을 시작했습니다. 검색엔진 최적화도 해야 해서 SSR을 지원해 주는 Next.js도 같이 사용했고요.
당시에는 리액트에 대해 하나도 몰랐지만 지금은 현업에서 매일 사용하고 있을 정도로 익숙해지기 쉬운 프레임워크라고 느낍니다. 진작에 이걸 왜 안 했지? 싶을 정도로요. 참고로 리액트를 쓰기 이전에는 제가 만들었던 사이트들은 아무 프레임워크도 사용하지 않고 오직 vanilla JS로만 돌아갔습니다.
이후에는 Typescript도 적용해 프로젝트를 리팩터했습니다. 타입 추론이 상당한 개발 효율을 가져다주는 것을 체감할 수 있었습니다. 가령 기존에는 API response에 대한 타입 정의가 없어서(게으르게도 명세도 딱히 해 두지 않았었습니다), 필드나 타입을 헷갈려서 오류가 발생하거나 개발 속도가 느렸었는데, 지금은 타입 정의를 열심히 만들어서 제 human error로 오류가 발생할 수 있는 가능성을 대폭 줄였습니다. 되게 기본적인 거지만 나름 뿌듯했던 경험이라 소스 코드를 첨부해 공유해 봅니다.
type SolvedPageContext = NextPageContext & GlobalProps export type SolvedPage< P = { siteTitle?: string[] }, IP = P > = NextComponentType< SolvedPageContext, IP & { siteTitle?: string[] }, P & { siteTitle?: string[] } > export default SolvedPageContext
이렇게 정의하면 페이지의 Props의 타입 정의가 어떤지에 따라 getInitialProps
에서 반환해 줘야 하는 타입이 결정됩니다. 아래 페이지의 경우 props.result
의 타입이 Problem[]
으로 정해져 있기 때문에 ProblemList
에서 렌더 로직을 짜기가 상당히 편해집니다. 에디터 연동은 두말할 것도 없구요.
type Props = SolvedApiResponse<SearchProblems> const LevelProblems: SolvedPage<Props> = (props) => { // ... return ( <PageLayout> <h1> <TierMark value={level} locked={false} showName={true} /> {caption ? ` — ${caption}` : null} </h1> <ProblemSortController currentSort={newQuery.sort} currentDirection={newQuery.direction} /> <div> <ProblemList result={props.result} page={page} keys={['id', 'title', 'solved_count', 'average_try']} /> </div> </PageLayout> ) } LevelProblems.getInitialProps = async (ctx) => { // ... try { const response = await SolvedApi<SearchProblems>(token).get( '/search/problems.json', { params: { query: queryString, page: +(page ?? 1), sort: sort ?? ctx.currentSettings?.problem_sort_by, sort_direction: direction ?? ctx.currentSettings?.problem_sort_direction, }, } ) return { siteTitle: ['문제', '레벨', levelName(+(level ?? 0))], ...response.data, } } catch (e) { // ... } }
여하튼 이런 식으로 기존에 PHP로 짜여 있었던 프론트엔드를 몇 달에 걸쳐 전부 React + Typescript + Next.js로 다시 짰습니다.
안타깝게도 백엔드는 아직도 PHP로 되어 있습니다. 현재는 길라잡이를 만들면서 백엔드도 Node + Express로 다시 구현하려는 계획을 갖고 있습니다. 완료되면 solved.ac에서 PHP 코드를 찾아보기 힘들게 되겠네요.
취업
위의 개발 경험 덕분에 6월 중순부터 넥슨컴퍼니 산하의 엔진스튜디오에서 일하게 되었습니다. 회고를 쓰고 있는 지금 시점으로 입사한 지 벌써 반 년이 넘었네요.
게임회사지만 제 주 업무는 웹 프론트엔드 엔지니어입니다. 사내외 여러 서비스의 개발을 맡아 하고 있습니다. 어떤 서비스라고 말하긴 그렇지만 아마 이 글을 읽고 계신 분들 중 적지 않은 분들께서 제가 작업했던 서비스를 이미 사용해 보셨을 겁니다. 😉
여담으로, 회사에서 매달 넥슨캐시를 일정량 지급하는데 쓸 데가 딱히 없어서 메이플스토리를 시작했습니다. 이제 모라스 코앞이네요. 12월 30일에 모라스에 갔습니다. 어쩌다 보니 받는 것보다 많이 결제하고 있지만 결제한 만큼 월급으로 돌려(?)주니 괜찮지 않을까라고 생각하고 있어요..
대회 프로그래밍
코드포스
올해는 그토록 염원하던 오렌지를 드디어 갔습니다.
근데 레이팅이 딱 2100점입니다.
근데 이 어려운 걸 한 번 더 해냅니다.
이 사람은 대체 뭐 하는 사람일까요? 대체 어떻게 했던 걸까요?
그래프가 딱 2100에 걸쳐 있습니다.
오렌지가 되니까 Div 1 이외에서는 레이팅 변동이 일어나지 않습니다. 근데 Div 1은 자주 열리지도 않고, 열리는 날에는 제가 뭔가 바빠서 매번 못 치게 되더랍니다. 뭐 한마디로 게을러진 거죠. 복학할 때 적의환향하겠다던 시프트는 대체 어디로 가고? 다시 열심히 쳐야겠어요.
대회 개최
UCPC 2020을 개최하고, 많은 대회에서 검수 및 출제를 했습니다.
- 진짜 최종 구데기컵 2 – 출제, 검수
- UCPC 2020 (전대프연 여름 대회) – 운영 총괄, 출제, 검수, 조판
- SUAPC 2020 (신촌지역 연합 여름 대회) – 출제, 검수, 조판
- 신촌지역 연합 캠프 2020 – 검수
- SNUPC 2020 (서울대학교) – 검수
- Uni-CODE 2020 (UNIST) – 검수, 조판
- SPC 2020 (서강대학교) – 검수, 조판
알고리즘 문제 제작과 검수, 프로그래밍 대회 진행 프로세스에 대해 과도할 정도로 많은 것들을 배울 수 있었던 한 해였습니다. 특히 글을 잘 쓰는 법을 배울 수 있었어요. 기회가 되면 SUAPC/SPC 출제/검수 후기도 작성해 보고 싶습니다.
대회 참가
여러 대회에 참가했으나 올해는 다소 부진했습니다.
- ICPC Asia-Seoul 2020 National First Round – 팀 Redshift로 출전, 5/12솔브 #36
- 풀이를 옳게 생각했던 건 3문제나 더 있었는데.. 강의실 키보드 탓을 했습니다.
- SCPC 2020 – Finalist, 172/1000
- 4번 문제가 되게 풀릴 거 같이 생겼길래 3시간동안 4번 문제만 잡다가 결국 못 풀고 망했습니다. 점수를 긁읍시다 여러분.
팀 연습 때는 NxxRC 8~10솔브 밀고 다녀서 잘하겠지 싶었는데 막상 한국 예선에서 저런 성적이 나와서 당황스러웠습니다. 개인 연습 부족인 거 같네요.
…적의환향 할 수 있을까요?
스터디 진행
Sogang ICPC Team에서 연초에 아래 주제들을 다루는 스터디를 진행했습니다.
- 세그먼트 트리 느리게 업데이트하기 lazy propagation
- 트리에서의 무게를 이용한 분할 정복 heavy-light decomposition
- 퍼시스턴트 세그먼트 트리 persistent segment tree
- 게임 필승법과 Sprague-Grundy 정리
- 정수론적 알고리즘
그래픽 디자인
많은 프로그래밍 대회 운영에 참가하면서, 자연스럽게도 관련 포스터를 만들게 됐습니다.
서강 프로그래밍 대회 2020 서강 프로그래밍 대회 2020 오픈 컨테스트 신촌지억 대학생 프로그래밍 대회 동아리 언합 여름 대회 2020 Local Optima January 2020 전국 대학생 프로그래밍 대회 동아리 연합 여름 대회 2020
프로그래밍 대회 문제들에 들어가는 그래픽도 많이 만들었습니다.
solved.ac 공식 SNS 계정이 생기면서 정사각형 모양의 그래픽도 만들었습니다.
solved.ac 웹 디자인은 포토샵이나 일러스트를 켜서 하지 않고 CSS로 직접 하기 때문에 따로 목업 디자인 같은 건 따로 없습니다.
아쉽게도 예전처럼 개인작을 만들거나 할 여유는 없었네요.
이외에
휴학하고 회사 다니면서 아무것도 안 한 줄 알았는데 정리해 보니까 뭔가 한 게 꽤 있었네요. 건강검진에서 많이 쉬라는 소리를 들어서 내년 목표는 바쁘지 않게 한 해를 보내는 것으로 해야겠습니다.
휴대폰을 갤럭시 노트 20으로 바꿨어요. 흰색이 정말 예쁘길래 흰색으로 샀는데 잘한 선택인 거 같아요. 5G폰이지만 5G가 너무 안 터진다는 소리가 많아서 5G를 쓰지 않기 위해 자급제로 샀습니다. 근데 정작 노트에서 가장 중요한 기능이라고 할 수 있는 S펜은 자주 안 쓰게 되더라구요. 왼쪽에 달려 있어서 그런가..
저어어엉말 오랜만에 애니메이션을 열심히 봤습니다. 넷플릭스도 열심히 봤습니다. 베스 하먼을 보고 체스 세트를 샀어요. 근데 잘 못 두는 거 같네요.
신도림역 출발열차의 존재를 알고 삶의 질이 올라갔어요.
세가의 리듬게임 ‘츄니즘’이 한국에 정식 발매되어서 휴가 쓰고 한주 내내 다녀왔어요.
자전거를 유난히 많이 탔던 해였던 거 같기도 하네요. 특히 학교에서 놀거나 문제 풀다가 or 상수역 오락실에서 놀다가 서강대교 건너서 집에 따릉이 타고 자주 왔는데, 이제는 코로나 시국이 심해져서 자전거 타고 밖에 돌아다니기도 눈치 보이게 되었어요. 코로나가 없던 시절이 너무 그립네요..
솔브드 백엔드 Node.js 포팅도 마치고 싶었고, 그림도 그릴 줄 알게 되면 좋겠다 싶었고, 코드포스 레드도 가고 싶었고, 되게 하고 싶었던 게 많았어요. 다 못 이뤄서 올해 별로 한 게 없었던 줄 알았는데.. 정리해 보니까 이런 시국 속에서도 올해 되게 뭔가 많이 했었네요 😅 제가 너무 하고 싶은 게 많았나봐요. 좀 한가하게 살아도 되겠습니다. 건강검진에서도 많이 쉬라는 소리를 들었구요.
이 정도면 올해 나름 잘 보냈네요. 신년 목표도 한 해 적당히 잘 보내는 걸로 해야겠습니다. 새해 복 많이 받으세요~ 🔔