2023년 회고록

이전부터 회고록을 작성하다 보면 뇌를 빼고 작성하는 경우가 많았다. 그래서 이번에는 좀 정리된 내용으로 작성해보려고 한다. 나중에 나의 글을 읽을 때 재미가 있었으면 하는 마음으로 작성해보았다.

1분기

신규사업

작년과 이어지는 상황이었다. 그냥 회사 돈을 벌어다 주어야 했다. 작년 연말에 이어 돈을 벌 사업을 구상하기 바빴다. 회사의 특징을 살려 게임과 관련된 사업을 구상하였고, 경쟁을 할 서비스들을 보며 레퍼런스를 수집했다. 그렇게 많은 아이디어들이 모여 하나의 사업을 시작했는데, 발로란트를 이용한 전적 검색과 게임 통계를 제공하는 서비스를 만들기로 정했다.

2분기

WASD의 탄생

위에 작성했던 것처럼 1분기는 개발자로서 업무가 없었다. 그리고 빠른 개발을 하기 위해 제일 익숙한 방법을 선택했다. Next와 Emotion. 논의조차 할 수 없었다. 기획과 디자인, 개발 모두 3개월도 안되는 시간에 만들어서 결과를 만들어야 했다.

⛔ 나는 아직도 가능할 수 있었다는 것이 놀랍다.
(참고로 인원은 디자인 1명 + 프론트 2명 + 백엔드 2명)

그렇게 WASD를 런칭하게 되었다.

메이플스토리 월드와 Lua

회사 일이 매우 바쁘게 돌아갔지만, 재미있는 일도 있었다. 메이플스토리 월드라는 것을 알게 되었다. 내 동년배면 누구나 한번은 리스항구에서 친구를 기다렸을 그 게임. 메이플스토리의 애셋을 이용하여 게임을 만들 수 있는 툴이다. 묘하게 옛날 생각이 나고, 타입 선언과 컴포넌트만 만드느라 루즈해진 머리에 새로운 재미를 넣어줄 수 있었다.

처음 시작은 유튜브 채널 오늘 코딩을 통해 접했다. 당시 이상하게 게임 개발에 관심이 있던 상황이라 3시간 짜리 영상을 스킵없이 보았다. 영상을 따라하며 개발 툴에 대한 이해도를 올렸다. Lua를 기반으로 하기에 자연스럽게 새로운 언어도 배울 수 있었다.

⛔ 하지만 index의 시작이 1이라는 점은 아직도 용납할 수 없다.

이것 저것 해보고는 있었지만 실제 게임을 출시하지는 않았다. 그냥 지루하면 한번 열어서 가지고 놀다가 끄는 정도로 사용했다. 정확히 일주일 뒤 돈을 벌어야 하는 상황이 되기 전까지는…

이것을 이용해 게임을 만들고 싶다는 내용을 보았다. 솔직히 처음은 멀리서 보고 싶었다. Lua라는 언어와 툴에 대한 이해가 매우 적었다. 심지어 게임에 대한 개발이 전무한 경험이 크게 다가왔다.

👉 하지만… 손가락은 이미 지원서를 작성하고 있더라…

그렇게 나는 게임을 출시하였고, 그 게임은 의뢰인의 힘으로 인기 게임까지 올라갔다. 어쩌다 보니 실제 업무보다 큰 성공을 이루게 되었다.

왁타버스

올해 다양한 경험을 진짜 많이 했다. 위에 작성된 내용처럼 충분히 재미있는 상황이 많았는데, 여기에 추가로 사이드프로젝트까지 하게 되었다.

당시 Electron을 이용해 윈도우 앱을 만들어 보며 시야를 넓히고 있었다. 그러다 마침 해당 기술을 이용한 프로젝트를 발견하였고, 참여하고 싶다는 내용으로 DM을 보냈다. 그렇게 합류하게 되었다.

게임을 모아 쉽게 찾을 수 있게 해주는 서비스를 만들고 있었다. 웹버전은 진행이 많이 된 상태였지만, 앱은 아직 시작하는 단계였다. 나는 그 앱을 개발하기 위한 프로젝트 세팅을 진행했고, 실제 오픈 직전까지 개발을 완료했었다. (결국 어떠한 이유로 오픈을 할 수 없게 되었다.)

웹은 정상적으로 오픈하였다.

3분기

함수형과 에러가 없는 코드

나는 fxts를 자주 사용했고, 사용한다. 함수형을 사용하는 다양한 이유가 있지만, 나는 pipe를 사용한 코드가 너무 아름답게 보인다. 절차도 눈에 잘 보이고, 그 절차가 완료되면 결과가 바로 닮기는 그 코드가 진짜 너무 좋았다.

이런 생각으로 코딩을 하는데, 마침 fxts창시자 유인동님의 짧은 강의를 청강할 기회를 잡았다. 그 강의에서 굉장히 재미있는 내용을 들을 수 있었다. 바로 에러가 나지 않는 코드를 만다는 것이었다.

굉장히 이상적인 내용이었지만, 방법은 되게 단순했다. 언어 자체가 지원하는 기능들을 적극적으로 활용하는 것이었다. 그 기능들이 요구하는 스펙을 맞추어 해당 기능을 활용한다면, 실제로 에러가 발생하지 않는 것이었다.

예를 들면,

const sum = (iterator) => {
	let result = 0

	for (const item of iterator) {
		result += item
	}

	return result
}

sum([1, 2, 3]) // 6
sum([4, 5, 6]) // 15

배열의 모든 숫자들을 더하는 함수를 제작했는데, 이 함수의 코드는 숫자로 이루어진 배열을 넣으면 에러가 발생하지 않는다. 그런데 숫자가 아닌 다른 값들이 있다면 에러가 발생한다. 이런 경우 보통은 함수 안에 숫자만 찾는 조건을 추가할 것이다.

우리는 여기서 에러가 발생하기 시작한다.

이따 아래에서 다시 설명을 하겠지만, 더하기 함수는 숫자를 걸러주는 일을 할 필요가 없다. 오히려 숫자만 찾아서 걸러주는 함수가 있고, 이후 더하기를 하면 된다.

const filterNumber = (iterator) => {
	const result = []

	for (const item of iterator) {
		if (typeof item !== 'number')
			continue
		
		result.push(item)
	}

	return result
}
const sum = (iterator) => {
	let result = 0

	for (const item of iterator) {
		result += item
	}

	return result
}

sum(filterNumber([1, '2', 3])) // 4

나는 이번 내용으로 코드를 작성하는 방향을 새롭게 바꾸었다.

WASD 망함

WASD는 결국 사업을 철수하기로 하였다. 생각보다 굉장히 빠르게 정해졌다. 투자되는 자원에 비해 괜찮은 결과는 나오지 않았고, 몇몇 홍보를 하면 그 순간만 이용자 수가 늘어나는 정도로 그쳤다. 유튜브에 영상을 올리면서 서비스 홍보를 진행해보았다. 영상의 조회수는 상당히 잘 나왔지만, 실제 서비스 이용자 수에 영향을 주지는 못했다.

결국 서비스를 내리기로 했다.

백수

프로젝트가 망하면서 결국 회사는 IT 사업을 철수했다. 개발팀은 빠르게 해산되었다. 나는 제일 먼저 퇴사를 했다. 갑작스러운 퇴사라 정신이 없었다. 그리고 오랫동안 쉬지 않고 일을 하고 있으니 많이 지친 상황이었다.

결국 휴식을 선언하고, 최소한 연말까지 쉬기로 하였다.

Waktaverse Games

회사는 나왔으나 사이드는 계속 진행되었다. 기존에 작업하던 내용이 아닌, 게임 업로더를 만들기로 하였다. 기존에 테스트하던 코드를 실제 서비스로 만들어야 하는 이슈가 있었다. 단순 API 테스트를 위한 코드이기에 정리도 없었고, 정적 파일이라 디자인 적용도 쉽지 않았다. 우선 급하게 퍼블리싱을 진행하여 오픈을 하였고, 이후 리펙토링을 진행하는 방법을 선택했다.

리펙토링을 진행하며 아주 많은 난관이 있었다. 모든 조건이 완벽할때 작동하던 코드라 예외처리가 없었다. 추가로 정적인 파일을 이용한 배포라 화면 구성이 쉽지 않았다. 가장 먼저 화면 구성을 React로 만들어야 했다.

기존 Electron에 정적 파일이 종속되던 방식에서 React에 Electron을 미리 추가한 후 빌드를 하며 폴더 구성이 바뀌게 만들어야 했고, 동시에 Electron의 파일을 하나로 묶어 main.js로 떨구는 작업이 필요했다. 나는 아래의 스펙을 선택하여 진행했다.

  1. React: 컴포넌트를 구성하는 용도
  2. Typescript: 이것은 선택이 아니라 필수다.
  3. Gulp: Electron을 구성하는 파일들을 하나로 합쳐주는 용도.

여기서 마지막 Gulp가 힘들었다. 익숙하지 않았고, TS파일을 JS로 만든 후 React의 Public에 떨군 후 다시 React 빌드를 하는 로직을 만들어야 했다.

🚨 사실 더 좋은 방법이 있었겠지만… 당시의 나로서 이게 최선이었다.

뭐 자세한 내용은 나중에 따로 작성하겠지만… 아무튼 빌드 환경 구성을 새롭게 만드는 작업이었다. 그동안의 귀동냥으로 얻은 지식들 덕분인지 생각한 순서대로 잘 작동되었다.

4분기

쿠팡과 단계 vs 결과

퇴사가 확정이 되고, 링크드인에 프로필을 오픈하면서 쿠팡에서 먼저 연락이 왔다. 나에게 입사 지원을 해볼 생각이 없냐고 했다. (실제 쿠팡 인사팀에서 연락옴. 헤트헌터 아님) 휴식을 하고 싶었지만, 누가 쿠팡을 거절할까? 당장 이력서를 정리해 보냈다.

생각보다 프로세스는 빠르게 진행되었다. 서류를 통과하고, 1차 면접을 통과하고 마지막 2차면접까지 진행할 수 있게 되었다. 그리고 떨어졌다.

2차면접에 대해 많은 것을 느꼈다. 정확한 질문이나 프로세스를 작성할 수 없지만, 나에 대해 많은 것을 뒤돌아 볼 수 있었다. 급박한 상황에서 내가 작성하는 코드들은 매우 위태롭게 보였다. 위에 작성한 에러가 없는 코드를 작성하겠다는 생각은 면접을 진행하는 과정에서 모두 까먹었다.

나는 이 면접이 진행되기 전까지 결과를 만들기 위한 코드를 작성했다. A부터 Z까지 가는 과정에 수많은 알파벳들이 존해하는데, 나는 A와 Z만 보고 코드를 작성했다. 그 사이에 많은 과정들을 생각하지 않고 있으니 에러가 터지는 코드가 작성되었다.

예를 들면,

// 입력된 문자열에서 숫자만 뽑아 모두 더한 값에서 5를 빼는 코드를 작성해주세요.

이런 문제를 받았다고 예시를 두겠다. 그동안은 하나의 함수에 위 내용들을 다 넣으면서 작성했겠지만, 달라졌다. 단계를 나누기로 했다.

// 입력된 문자열에서 숫자만 뽑아 모두 더한 값에서 5를 빼는 코드를 작성해주세요.
//
// 1. 문자열을 배열로 만든다.
// 2. 1번의 배열의 값을 숫자 타입으로 바꾼다.
// 3. 해당 배열에서 숫자만 찾는다.
// 4. 2번의 결과를 모두 더한다.
// 5. 3의 결과에서 5를 뺀다.

이제 코드를 작성한다.

// 입력된 문자열에서 숫자만 뽑아 모두 더한 값에서 5를 빼는 코드를 작성해주세요.
//
// 1. 문자열을 배열로 만든다.
// 2. 1번의 배열의 값을 숫자 타입으로 바꾼다.
// 3. 해당 배열에서 숫자만 찾는다.
// 4. 2번의 결과를 모두 더한다.
// 5. 3의 결과에서 5를 뺀다.

const split = (text) => text.split(' ')
const makeNumber = (iterator) => iterator.map(Number)
const findNumber = (iterator) => iterator.filter((item) => !Number.isNaN(item))
const sum = (iterator) => {
	let result = 0

	for (const item of iterator) {
		result += item
	}

	return result
}

sum(
	findNumber(
		makeNumber(
			split('Hello 10 World 20')
		)
	)
) - 5

아래 최종 실행 코드를 pipe로 돌리면 더 아름다운 코드로 확인이 가능하다.

pipe(
	'Hello 10 World 20',
	split,
	makeNumber,
	findNumber,
	sum,
	(result) => result - 5
)

// 이건 그냥 단적인 예시의 pipe이다.

내년에는 일을 하고 있을까?

1년을 진짜 알차게 보내기는 했다. 휴식이 무조건 필요하다. 하지만 2024년 연초에는 일을 하고 싶었다. 11월이 되어서 입사 준비를 다시 시작했다. 그동안 경험이 있어서 그런지 제발 망하지 않을 서비스를 가진 회사에 입사하고 싶었다. 그리고 단순 서비스를 만드는 것이 아닌 코어 개발을 해보고 싶었다.

원티드를 탐색하는 과정에서 밀리의 서재를 발견할 수 있었다. 마침 책에 대한 취미를 가지고 있었고, 동시에 뷰어를 개발할 수 있는 기회가 매우 마음에 들었다.

☝ 일단 집과 가깝다.

준비하는 과정에서 묘하게 기대감이 생기는 것이… 욕심이 생긴다.

정리하며

글을 쓰는 지금 이 시점.. 옛날 대항해시대 게임이 하고 싶다.

회고란 이런 것…