우테코: 온보딩(자동차 경주) & 로또 미션 회고

우테코 크루가 되며

우아한테크코스에 들어오게 된 이후로 대략 한 달정도의 시간이 흐른 후에야 회고를 적게 되었다.
일단, 우테코 크루가 되면서 굉장히 정신이 없었고.. 할 일이 너무나도 많았기 때문에 회고를 적는 걸 많이 미뤘다.. 지금은 조금 적응되어서 이렇게 회고를 적을 짬이 생기게 되었다.

일단, 우테코에 들어오고 첫날은 OT여서 칼퇴를 했지만, 둘쨋날부터..ㅎ 7~8시 퇴근이 일상이 되었다. 집에 일찍 가기에는 해야 할 분량이.. 너무.. 많달까..
같이 지내는 크루들 모두 둘쨋날이 지나고 셋쨋날 입에 달고 산 말이 첫주부터 이렇게 늦게 집에 가게 될 줄 몰랐다. 였다…

그래도 그만큼 많이 성장해나가는게 느껴져서 늦게 집가는게 싫거나 그렇지는 않다. 나름 보람 넘치고 뭔가 뿌듯하달까? 고등학교때는 야자하는게 죽어도 싫었는데, 이건 자발적인 야자이다 보니 성취감이 생긴다.

이러니 우테코에 합격하지

연극조 사진

온보딩 기간에는 자동차 경주 미션과 연극을 하게 되었다.
음.. 사실 난 연극이 있는 줄도 몰랐다. ㅎㅎ; 다른 분들의 합격 후기 글만 엄청 찾아봤지, 어떻게 생활하셨는지의 글은 찾아본 적이 없어서.. 처음 연극을 해야 한다는 것을 들었을 때.. 당황했지만, 그래. 이게 우테코지. 싶어서 바로 납득되었다.

그리고 이 납득은 다른 곳에서도 일어났다.
연극을 준비하고 첫주 금요일인가? 연극 리허설이 있었는데, 다들.. I이면서.. 왜이리 열정적이고 웃기게 연극을 준비한거지..?
다른 팀의 리허설을 보고 승부욕이 불타올랐다. 우리 연극팀은 그간 준비했던 연극의 큰 틀만 남겨두고 싹- 갈아 엎었다.

그런데 웃긴 것은 그 누구도 갈아 엎는 것에 대해서 반대하지 않았다. ㅋㅋㅋㅋㅋㅋ. 연극을 준비하면서 느낀 것은 이 사람들.. 이 열정과 승부욕으로 우테코에 합격했구나.. 깨달았다. 나 뿐만 아니라 다른 크루들 모두.

우리 연극조는 처음에는 얌전히(?) 연극을 준비 했지만, 리허설 이후 자신을 내려 놓고 진지하면서 웃기게 연극을 준비했다.
뛰어난 결과를 얻지는 못했지만, 그래도 연극을 준비하며 빠르게 친해질 수 있었고 아무 생각없이 편하게 웃으며 준비할 수 있어서 행복했다.

언제 우리가 우테코를 하면서 이렇게 생각 없이 웃고, 영양가 없는 대화에 진지하고 깔깔거릴 수 있겠는가? 정말 행복한 시간이었다.

나는 자동차 경주를 F1으로 만들어

우테코 우아한형제들 로고

온보딩 기간에는 연극뿐만 아니라 프리코스 기간때 했던 미션인 자동차 경주도 페어와 함께 프로그래밍을 하는 시간이 있었다. 그래서 온보딩 기간은 굉장히 정신이 없었다. 연극도 준비하면서 페어 프로그래밍도 해야하고.. 근데 프로그래밍의 마감 기한은 짧고..
그래도 나름 프리코스 기간의 기억을 끄집어 내면서 페어와 함께 기능을 구현해 나갔다.

페어를 통해 JS Docs, deepFreeze, Map 객체에 대해서 새롭게 알 수 있었다. 아직 해당 개념에 대해서 명확하게 설명을 하거나 적용할 수는 없지만, 일단은 해당 개념을 인지하고 있다는 것에서 만족하기로 했다.
모두 챙기려고 아등바등 하다가는 결국 우테코조차 따라갈 수 없게 된다는 것이 나의 결론이었다.

그리고 나의 페어인 버건디는 나보다 JS에 대해 많은 지식을 가지고 있어서 솔직히.. 버스 탄 것 같다.. 정말 너무 고맙다.. 그래도 나도 나름(?) git에서 열심히 했으니까..! 1..1인분은 한..걸지도..? 이 자리를 빌어.. 페어 리뷰도 굉장히 길게 써주고 버스까지 태워준 버건디. 고마워요 ㅜ

로또는 사서 당첨된 적이 없는데요

왼손이 커피 쏜 날

로또는 아빠 돈을 빌려서(갈취) 만원 자동으로 사봤다. 물론, 5000원도 당첨되지 않았다. ^^
이번 미션은 프리코스 로또 미션 + UI 구현하기 였다.

페어와 로또를 구현하면서 정말 많은 대화와.. 고민과.. 방향에 대해서 생각했다. 그 당시에는 머리가 쥐날 것 같아서 힘들었지만, 후에 돌아보니 정말 기능 구현을 기똥차게 한 것 같다. 크게 건들게 없으면서 확장성은 좋은 것 같달까?ㅎ 이게 다 나의 페어 덕분에.. 또 버스를 타 버렸지만.. 정말 너무 고맙다..

이번 미션을 통해서 class에서 private를 사용하는 이유에 대해서 조금은 알게 되었다. 이전에 나는 private라고 명시해두고선 전혀 private하게 사용하지 않았다. 해당 class 외부에서 그냥 냅다 출력하기.. 등 ^^… (그럴 거면 왜 숨겼나고..)
이번 페어인 마스터위 (라고 쓰고 거의 과외 선생님) 덕분에 class에 대해서 한발짝 더 이해할 수 있었다. 덕분에 나, 혼자서 어느 정도 class로 구현할 수 있겠다는 자신감이 생겼어요!! setter도 알게 되고 getter도 알게 되고.. 일급객체도 들어보게 되었고

그리고 가장 가장 중요한 것을 깨닫게 되었다. 그건 바로..!! 페어와 미션을 구현하기 전에, 해당 문제를 어떻게 이해했는지 각자 말해보고 시작하기이다.
이게 좀 웃긴게.. 개발 막바지에 알게 된 것인데, 우리 둘이 로또 당첨에 대한 로직을 다르게 이해하고 있었다. 어쩐지.. 말을 하는데 약간 다르게 받아 들인다는 느낌이 들었는데, 이게 다르게 이해하고 있었을 줄은… 정말 생각도 못했다.
그러니, 꼭 페어하기 전에는 서로의 생각을 말하고 시작해야 한다는 엄청난 교훈을 얻었다. (덕분에 꽤 많은 시간은 날린 것 같다.)

로또 미션까지 마치면서

랫서의 요가 교실

온보딩 미션과 로또 미션을 마치며 깨달은 것은 나에게는 지식 싱크홀이 존재한다는 것이다. 그것도 엄청나게 큰 싱크홀이..
이전에 react로 팀 프로젝트도 진행하고 나름 배포해서 유저도 모았던 경험이 있어서, 어디가서 지식이 부족하다는 생각은 못했었다.
그렇다. 난 우물안의 개구리였다. 나의 세상이 너무 작아서 내가 착각하고 있던 것이다. 이번에 우테코에 들어오면서 그간 인턴에 떨어진 이유를 너무 잘 알 수 있었다.

이 짧은 시간동안 우테코에서 지내면서 당장 이전에 했던 유니버스 프로젝트조차 코드를 뒤집어 엎어버리고 싶다는 생각이 들었다. 나의 코드가 너무 지저분하고.. 리팩토링해야 할 것이 산더미.. 이 짧은 시간동안 커진 시야로 과거 나의 문제를 바로 알 수 있었는데, 회사 관계자들은 얼마나 잘 보였을까?

그래서 나는 점점 커지고 있는 나의 시야를 나의 발전에 쓰기로 결심했다.
일단, 나의 부족한 JS 지식을 메꾸기. 내가 순살 자이가 될 순 없으니! 진도 8.0도 버틸 수 있는 지식을 쌓아야 겠다고 생각했다. 이 생각은 스터디 결성으로까지 이어졌다. (스터디명은 “숨 참고 딥 다이브”이다. 누가 지었는지 참^^!)

또한, 우테코 미션에 먼저 집중을 하고 시간 여유가 생긴다면 공부하고 싶었던 지식에 대해 알아보고 블로그에 정리해서 올리는 것이다. 이건 정말 천천히 하고 있긴 하지만, 아에 못하는 것보다는 나으니까. 차근차근 해 나갈 생각이다.

나는 왜 생각이 많을까? 책

저번주동안 정말 생각이 많았다. 주변은 다 나보다 실력이 뛰어나고, 엄청 실력이 뛰어나신 크루도 존재하고.. 나만 이틀째 같은 곳에서 넘어지고 일어나고를 반복하고 있으니 정말 생각이 많아졌었다.
내가 주변 크루들의 실력을 따라가기 위해서는 이보다 더 열심히 해야 할 것 같은데, 어떻게 더 열심히 하지? 여기서 잠을 더 줄이기에는 통학하는데 너무 위험할 것 같은 상황인데..
공부하고 싶은 욕심은 생기고.. 마음은 조급해지고..
살다 살다 공부할 시간이 부족해서 걱정된 적은 처음인 것 같다.

그래서 결론은 위에 말한 것처럼 차근차근 해 나가자는 것이다. 이미 이전에 JS 쉽게 건너뛰고 react만 했다가 지금의 지식 싱크홀이 생긴 것 아닌가? 이게 바로 조급하게 뛰어 갔을 때의 안 좋은 결과라고 생각한다. 그러니, 이번에는 조급함은 조금 내려두고 천천히 경보해보고자 한다. 그래서 스터디도 딥 다이브 스터디 하나만 하기로 했다. 너무 많은 것을 하려다 보면 부담이 되고, 그러다 보면 결국 우테코 미션까지 놓치게 될 것 같아서 말이다.

짧은 기간동안 정말 많은 경험과 고민을 하게 되었다. 그렇지만, 이런 것들이 나를 한층 더 성장시켜주고 있는 것 같다. 아, 그리고 이번에 여러 사람들과 대화하며 깨달은 것은 단정짓지 말자!이다. 나의 한계든 다른 사람에 대한 나의 생각이던 단정짓지 말고! 유연하게! 바라보자.

JavaScript: Number.isNaN vs isNaN

NaN

NaN은 Not-A-Number(숫자가 아님)을 나타내는 전역 객체의 속성이다. Number.NaN의 값과 같다.

NaN을 반환하는 다섯 가지 연산 종류

  • 숫자로 변환 실패

    예시: parseInt("blabla"), Number(undefined)와 같은 명시적인 것 또는
    Math.abs(undefined)와 같은 암시적인 것

  • 결과가 허수인 수학 계산식

    예시: Math.sqrt(-1)

  • 정의할 수 없는 계산식

    예시: 0 * Infinity, 1 ** Infinity, Infinity / Infinity, Infinity - Infinity

  • 피연산자가 NaN이거나 NaN으로 강제 변환되는 메서드 또는 표현식

    예시: 7 ** NaN, 7 * "blabla"
    이것은 NaN이 전염성 있다는 것을 의미한다.

  • 유효하지 않은 값이 숫자로 표시되는 기타 경우

    예시: 잘못된 날짜 new Date("blabla").getTime(), "".charCodeAt(1)

isNaN()

isNaN()은 값이 숫자가 아니라면 형 변환을 한다.
즉, 숫자로 변환만 할 수 있다면 숫자가 아닌 문자열이 들어와도 true를 반환한다.

형변환을 진행하기 때문에 isNaN() 보다는 Number.isNaN()을 사용하는 것이 권장된다.

isNaN(NaN); // true
isNaN(Number.NaN); // true
isNaN(0 / 0); // true

isNaN('NaN'); // true
isNaN(undefined); // true
isNaN({}); // true
isNaN('blabla'); // true

isNaN('2'); //false
isNaN(2); //false
isNaN(true); // false
isNaN(null); // false

Number.isNaN()

Number.isNaN()은 엄격한 방식으로 NaN인지만 확인한다.
isNaN()과 달리, Number.isNaN()은 강제로 매개변수를 숫자로 변환하지 않는다. 오직 숫자형이고 NaN인 값에만 true를 반환한다.

Number.isNaN(NaN); // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0); // true

Number.isNaN('NaN'); // false
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN('blabla'); // false

Number.isNaN('2'); //false
Number.isNaN(2); //false
Number.isNaN(true); //false
Number.isNaN(null); //false

참고자료
[JS] NaN, isNaN()과 Number.isNaN()의 차이
MDN: NaN
MDN: isNaN()
MDN: Numeber.isNaN()

JavaScript: `Object.freeze` vs `Object.deepFreeze`

프리코스때 처음 알게 되었고, 지금까지도 항상 사용해왔던 Object.freeze
이번에 온보딩 미션인 자동차경주 페어 덕분에 Object.deepFreeze라는 것을 새롭게 알게 되었다.
비슷하게 생긴 둘은 도대체 무슨 차이가 있는지 알아보자.

freeze

freeze는 객체를 얕게 얼린다. 그렇기에 객체 프로퍼티는 얼리지만 객체 안의 객체를 얼리지 않아, 변경이 가능하게 된다.

const person = {
	name: 'soha',
	hobby: ['drawing', 'swimming'],
};

위의 예시에서는 name은 변경이 불가능하지만, hobby는 변경이 가능하다.
hobby의 값은 객체 안의 객체이기 때문이다.

그렇다면 freeze는 왜 중첩된 객체들까지 얼리지 못하는 걸까?

JavaScript라는 언어의 유연성을 유지하면서 성능과 복잡성을 고려하여 설계했기 때문이다.

동적인 언어이기 때문에 객체의 구조가 런타임 중에도 동적으로 변경될 수 있다. 그렇기에 객체의 중첩된 프로퍼티를 얼리는 것이 복잡하고 예측하기 어렵다.

따라서 JavaScript는 성능, 유연성 및 설계 복잡성 등을 고려하여 중첩된 객체까지 얼리지 않는 설계를 채택했다. 필요한 경우 사용자 정의 함수를 작성하여 깊은 얼림을 구현할 수 있다.

deepFreeze

위에서 사용자 정의 함수를 작성하여 깊은 얼림을 구현할 수 있다.라고 했다. 그렇다. deepFreeze는 사용자가 정의하여 사용해야 하는 함수이다.

deepFreezefreeze를 재귀적으로 돌면서 모든 객체와 그 하위 객체까지 깊게 얼린다. 따라서 deepFreeze는 객체 안의 객체도 변경이 불가능하다.

그렇다면 deepFreeze가 무조건 좋은거 아니야?

꼭 그렇지만은 않다.
deepFreeze는 재귀를 사용하여 구현하기 때문에 많은 메모리와 처리 시간을 소비할 수 있기에 비용이 더 커질 수 있다.

그렇기에 프로젝트에 따라서 deepFreeze 사용이 좋지 않을 수도 있다.

freezedeepFreeze 중에서 어떤 것을 사용할 지는 프로젝트의 규모에 따라서 달라질 것 같다!

참고자료
객체의 확장을 막는 방법

VSCode 파일 대소문자 충돌 해결

이번에도 어김없이 등장한.. 파일 대소문자 충돌 이슈…

처음에 파일을 생성할때 이름을 OutPutView.js로 지어버렸다.
그래서 파일 이름을 OutputView.js로 변경해줬다.

그러나.. VSCode에서 OutputView.js로 작성하고 import를 해도 처음에 작성했던 OutPutView.js로 찾는 것이다.. 그러니 해당 파일을 찾을 수 없어 블라블라..

물론 나는 git 대소문자 충돌 문제는 이미 프리코스에서 겪어서 global로 설정해뒀다.

그러니 이건 순수히 VSCode의 문제..!!!

그래서 나는 전지전능한 ChatGPT에게 물어봤다.
답변은 다음과 같았다.

VSCode 대소문자 구분 무시

  1. VSCode를 열고 설정 메뉴를 연다. (ctrl+ , 또는 Cmd + ,)

  2. 검색 창에 “files.associations”를 입력한다.

  3. “Files: Associations” 항목을 클릭하고 “Add Item”을 클릭하여 새 항목을 추가한다.

  4. 추가된 항목에서 원래 파일 이름과 변경된 파일 이름을 입력한다.
    OutPutView -> OutputView

VSCode 설정 이미지

  1. 이제 변경된 파일 이름에 대한 대소문자 구분이 무시된다!

해당 방법의 문제점?

이건 글을 작성하다가 알게 된 것인데, 다른 프로젝트에서 VSCode 설정에 들어가서 항목을 추가했었다. 그런데, 해당 글을 작성하는 프로젝트에서 VSCode 설정에 들어가니 위 이미지처럼 그대로 추가된 항목이 존재했다.

ChatGPT는 해당 프로젝트에서만 적용된다고 했는데… 음…
조금 더 완벽한 방법을 찾아봐야 할 것 같다.

nvm use 사용: Your user's .npmrc file (${HOME}/.npmrc)...

우테코 교육이 시작되고, 온보딩 미션을 진행하던 중 node 버전을 변경해주기 위해서 nvm use <버전>을 실행했으나 실패했다.

nvm 버전을 변경하려는데 실패..?

Your user's .npmrc file (${HOME}/.npmrc)
has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.
Run `nvm use --delete-prefix v18.27.1` to unset it.

해당 메세지는 nvm을 사용하여 node 버전을 관리하는데 .npmrc 파일에서 globalconfig 또는 prefix 설정이 발견되었다는 것이다. globalconfig와 prefix는 nvm과 호환되지 않는다.

왜 호환되지 않는 걸까?

nvm과 prefix 및 globalconfig는 서로 다른 방식으로 node 버전을 관리한다.

  • prefix
    prefix는 특정 프로젝트에 대한 node 실행 파일과 패키지를 설치하는 위치를 가리킨다.
    그러나, nvm은 설치된 node의 버전을 관리하기 위해 사용된다.
    즉, prefix는 특정 프로젝트나 환경과 관련이 있어 nvm과는 별도로 작동된다.

  • globalconfig
    globalconfig는 node의 설정 파일을 가리킨다. nvm은 node 실행 파일 자체를 관리하는 데 중점을 둔다. 따라서 node의 실행 파일이나 버전을 변경할 때 globalconfig는 영향을 받지 않는다.

nvm은 시스템 전체의 node 버전을 관리하는 데 중점을 둔다. globalconfig와 prefix 설정은 npm이 전역적으로 설치된 패키지의 위치나 구성 파일의 경로를 지정하는 역할을 한다.
그렇기에 서로의 역할이 달라 prefix와 globalconfig는 nvm과 호환되지 않는다고 말할 수 있다.

.npmrc?

.npmrc 파일은 npm에서 설정을 저장해두는 파일로, npm의 구성 옵션들이 포함되어 있다.

해결 방법

nvm use -delete-presix v18.17.1는 특정 버전(v18.17.1)의 node를 사용할 때 .npmrc 파일에서 prefix 설정을 삭제하는 명령어이다. 이렇게 하면 해당 버전의 node와 npm이 올바르게 작동된다.

> nvm use <버전>

Your user's .npmrc file (${HOME}/.npmrc)
has a `globalconfig` and/or a `prefix` setting, which are incompatible with nvm.
Run `nvm use --delete-prefix v18.27.1` to unset it.

> nvm use --delete-prefix <버전>

Now using node <버전>

nvm prefix 설정 삭제 스크린샷