코드스쿼드 4주 회고

2023. 4. 2. 22:40카테고리 없음

1주차

 cs 과정이 끝나고 오프라인으로 처음 동료들의 얼굴을 봤던 1주차. 모든게 어색했다. 적응하느라 바빴고 cs 과정동안 javascript 코드만 작성하다 html, css를 다시 작성하려니 꽤나 걱정이 앞섰다. 사람들이랑은 어색해 질문도 하지 못했고 내가 기대한 코드스쿼드의 모습과는 달라서 잠깐의 후회도 있었던 듯 (물론 현재는 단 1의 후회도 없다. 혼자 했으면 못했을 공부를 너무 많이 한다). 지금은 말을 너무 많이해서 문제지만..ㅋ

 

 1주차때 난 어떤걸 학습했고 어떤 문제들을 마주쳤었지? 기억을 되살려보려고 한다.

 

풀리퀘

 

 언제나 손에 땀을 쥐게 하는 git. 나름 강의도 듣고 꽤 다양한 명령어 옵션들도 노션에 정리해놨는데 막상 내 프로젝트에서 revert나 reset을 적용하기 전엔 긴장이 돼서 다른 사람들에게 물어보고 문제가 없다는 답변을 받고나서야 엔터를 쳤던 것 같다. 사실상 내가 사용하던 명령어는 add, commit, push 밖에 없었던 것 같은데 갑자기 upstream이니 뭐니.. 레포를 또 따로 fork하고 거기서 다시 풀리퀘를 날려야 한다는 개념이 정말 와닿지 않아서 풀리퀘 과정만 이해하기도 꽤나 벅찼던 것 같다. 나는 여전히 git에 서툴다. 그래도 git에서 가장 많이 사용되는 명령어들을 한 두번씩은 사용해봤으니 다시 한번 이론 강의를 보면 꽤 능숙해질 것 같다.

BEM

 언젠가 한 번은 알아둬야지 했던 주제인데, 막연히 미뤄뒀던 BEM. 사실 작성해야 할 코드가 많진 않아서 막무가내로 html 태그에 클래스 이름을 부여하고 css를 작성해도 됐겠지만, 항상 해왔던 방식대로 미션을 진행하면 내가 발전하지 못할 것 같다는 직감이 강하게 들었다. 나는 정적인 사람이라 컴포트 존에 있는걸 매우 매우 굉장히 선호하는데, 역설적으로 내가 성장했던 순간들은 모두 새로운 걸 도전해봤을 때였다. 비단 개발 뿐만 아니라 삶에 있어서도. 그리고 대부분의 경우.. 새로운 걸 접했을 때 걱정했던 것 만큼 어렵진 않았다. 고작 BEM 적용하는데 뭐이리 거창해? 라고 할수도 있지만 꽤나 갇힌 사람(?)이었던 나에겐 이런 사소한 순간들이 꽤나 자랑스럽고 내 자존감을 올려주는 요소다.

 

 하필 BEM이었던 이유는 1) 그 유명한 프론트엔드 로드맵에 나와있던 방법론이기도 했고  2) html 구조가 달라졌을 때 css 코드를 하나하나 수정하기가 싫었다. html 구조가 크게 수정되도 최소한으로 css를 수정하고 싶었다. html 구조 수정 후 사이트를 켰을 때 하얀 글자들이 검은 상자에서 튀어나와 여기저기 흩어져 있을 때의 심정이란..

 

그래서 BEM 방법론을 블로그에서 뒤져가며, 적용하고 떨리는 마음으로 첫 풀리퀘를 보냈었다. 다행히 크롱이 "클래스 네이밍의 어떤 규칙이 있는것 같군요. 일관성을 잘 지키신 듯 합니다." 라는 리뷰를 달아줬고, 나혼자 내색은 안했지만 속으로 얼마나 기뻐했는지. 나는 그동안 항상 모든걸 완벽히 학습하고 그걸 적용해야 한다는 강박증이 있었는데 BEM은 '에라 모르겠다' 심정으로 고작 몇 시간 공부한 채로 적용하고, 하다가 모르는 게 있으면 또 찾아보고 다른 사람한테 물어가면서 적용했던 첫 경험이었다. BEM을 또 나혼자 완벽히 공부하고 적용하려다가는 1주일 안에 내가 정한 양을 구현할 수 없을것 같아서 내 평소 학습 전략과 정반대되는 방법을 적용했고, 마음이 굉장히 찝찝한 채로 풀리퀘를 날렸지만 나름 긍정적인(?) 평가를 받아서 꽤 많이 힘이 됐다.

 

 미션 페이지에 "코드는 결코 완벽해지지 않습니다. 그러나 계속해서 개선하고 발전시키는 것이 중요합니다." - 조엘 스폴스키(Joel Spolsky) 이런 글이 있었는데 이 한 문장이 내 강박증을 없애는데 많은 도움을 줬다. 사람 마음 참 간사하다. 거꾸로 내 한마디에 누군가 좌절할 수도, 큰 힘이 될 수도 있다는 생각이 스쳤다.

 

 다만 아직도 block과 element를 잘 구분하는게 꽤나 어렵고 무엇보다도 적당한 이름 짓기가 굉장히 힘들다. 코드리뷰를 받지 않고 나혼자 작성할 땐 별 고민 없었는데 크롱과 동료들이 내 코드를 본다니 어떤 클래스 명이 적절할 지 고민을 정말 많이했다. 개발자들이 가장 많이 고민하는게 변수명 짓기라는 말을 그냥 밈처럼 받아들였는데 굉장히 작은 규모의 프로젝트였음에도 이 말을 체감할 수 있었다. 크롱이 항상 "내 코드의 의도를 명확히 하세요"라고 말씀을 하셨는데,  내가 지금 정확히 어떤 코드를 작성 중인지 의식적으로 생각하다보면 조금은 변수명 짓는게 쉬워지지 않을까.

 

.hidden.hidden

 display: none 스타일을 주기 위한 클래스였는데, 명시도 문제 때문에 .hidden.hidden 이런 식으로 css를 작성해놨다. 사실 BEM을 적용했다보니 모든 태그들이 클래스 명이 하나여서 잘 작동하기는 했는데, 누가 굳이 말해주지 않아도 나쁜 코드인 걸 스스로 느낄 수 있었다. 아직까지도 마음에 드는 해결법을 찾지 못했다.

 hidden은 유틸성 클래스라 이곳 저곳에서 사용되는데 hidden이 들어가는 곳 마다 .something.hidden 이렇게 적는건 마음에 들지 않았다. 분명 좋은 수가 있을텐데.. 4주가 지난 지금도 뾰족한 수를 찾진 못했다.

 

 

2주차

 

 아직도 동료들과 살짝 어색했지만 1주차보단 적응을 잘 했던 주차. 적응을 잘 했지만서도 심적으로 조금 힘들었었는데, 포코가 정말 잘 챙겨줬다. 내 블로그를 코드 스쿼드에 공유할지 안할지도 모르겠고, 다른 사람들이 생각보다 긴 이 글을 읽을 진 모르겠지만.. 그냥 고맙다는 말 하고 싶었다. 개인 회고잖아! 

 

 2주차는 css의 폴더 구조 고민에 대부분의 시간을 쏟은 것 같다.

 

SASS

 BEM으로 css를 작성하는게 꽤 익숙해지다보니, 또 2주차때 이런 느낌이 들었다. 지금 내게 편한 도구들로 노가다를 하고 있다. BEM 방법론을 적용했을 때와 같은 마음가짐으로 새로운 도구에 대한 두려운 감정과 괴로운 감정을 느끼며 sass를 공부하기 시작했다. 

 

 BEM과 마찬가지로 새로운 환경에 나를 던지고자 했던 동기도 있었지만, 그동안의 불편했던 점을 sass가 많이 해소해주었다. 1) 같은 block의 여러 element들의 css들을 적다보면 block의 이름을 반복해서 타이핑 했었는데, sass의 nesting이 이 부분을 해결해 줄 수 있었다. &기호가 마치 문자열 처럼 취급된다는 점이 이 부분을 매우 잘 해소해주었다. 제이든이 BEM과 sass가 궁합이 굉장히 잘맞는다고 말해줬는데 이해를 못하다가 &기호가 부모 클래스 명의 문자열 처럼 취급된다는 점을 깨닫고 이마를 쳤다. 2)  css 폴더 구조에 대한 정보를 찾기가 많이 어려웠다. 나는 항상 코드나 폴더의 구조에 집착하는데 참고할 만한 폴더 구조를 찾던 차에 7-1 폴더 구조를 알게 됐다. 

 

 컴파일 설정 해놓고, 그냥 nesting만 사용해서 기존의 css코드를 sass로 옮기는 건 그리 어렵지 않았다. 근데 또 다른 고민이 나를 찾아왔다. 7-1 폴더 구조는 알겠고 대략적으로 이런 파일들이 이 폴더에 들어가는건 알겠는데.. 내가 직접 적용하려니 어렵다.. base 폴더에 이런 css를 넣는게 맞을까? 이런 규칙들을 누가 속시원히 말해줬으면 좋겠다라는 생각을 하던 찰나에, 집에와서 제로초님 유튜브를 보다 제로초님이 이런 말을 했다. "명확한 규칙이 있으면 인공지능에 대체당해요" 이 말이 또 한번 내 강박을 낮춰줬다.

 

 cs과정 때 미션의 애매한 요구사항에 대해 슬랙에 질문을 꽤 많이 했었는데 매번 JK가 주는 답은 같은 맥락이었다. "스스로 생각했을 때 뭐가 옳나요? 스스로의 기준을 동료 개발자에게 자신의 생각을 설득시킬 수 있으면 됩니다. 현업에서도 누가 정해주지 않아요" 이 답변을 보고 가끔 JK를 원망하기도 했었는데 지금은 조금이나마 왜 JK가 답을 주지 않았는지 이해가 된다. 물론 판단의 기준이 개인마다 다른게 문제가 아니라 내가 명확히 틀린 경우도 있겠지만, 그런거 리뷰 받으려고 코드스쿼드 들어왔잖아? 많이 공부해서 내 생각에 근거를 대고 다른 사람을 설득하고, 다른 사람의 의견이 더 설득력 있으면 받아들이고 고치자.

 

 아무튼 폴더 구조까지 어느정도 정리하고 나니, 내가 사용한 기능은 nesting이 전부였다고 해도 과언이 아니다. 타이포그래피 쪽 부분에서 내장함수 nth와 함께 mixin을 사용하긴 했지만 그 외에는 글쎄. mixin, function, extend에 대해선 여전히 공부할 게 많이 남았다. 마음 한 구석에 불편한 부채들을 쌓아두고 나중에 갚자.

 

3주차

  스스로 마음가짐도 긍정적으로 바꾸고 사람들과 더 친해졌던 주차. 다들 많이 친해지다보니 이 때부터 엄청 토론을 많이 했다. 왜 함께 공부하는게 좋은 성장방법인지 느끼게 해줬던 주차.

 

 개인적으로는 내 javascript 코드 구조에 대해서 불만을 느끼고 별다른 해결책을 찾지 못해 답답해 했던 주차였다. 한 클래스 내에서 굉장히 많은 dom을 querySelector로 불러오고 있었고, 메서드 명을 짓기 굉장히 어려웠다. 또 메서드들의 계층(레이어? 뭐라해야 할지 모르겠다. 추상화 정도에 따른 계층이라 해야할까)이 다른데 한 클래스 내에 있기도 했다. 심지어 한 폴더 내의 같이 들어있는 클래스들이 그 당시엔 설명하기 어렵지만 다른 역할을 한다는 느낌이 있었다. 4주차때 MVC 패턴을 공부하다 보니 왜 이런 문제들을 느꼈는 지 알 수 있었다. 어떤 클래스는 모델 역할과 뷰 역할이 섞여 있기도 했고, 어떤 클래스는 모델 역할과 뷰 클래스가 분리돼서 한 컴포넌트를 이루기도 했다. dom을 동적으로 js로 넣어주려다 보니 이런 엉망인 구조가 나왔었다. 아무튼 3주차에는 이 구조들이 분명히 일관성이 있는듯 하면서도 굉장히 못생긴 구조인걸 어떻게 해결할까? 에 대한 고민이 많았다.

 

렌더링

 이 주제로 적어도 2시간은 프론트엔드에서 열띤 토론이 오갔던 것 같다. citical rendering path의 여러 단계 중 어디서부터를 렌더링까지 볼거냐? 로 많이 토론이 오갔고, 그럼 리렌더링은 어디서부터냐? 를 많이 얘기했던 것 같다. 답을 찾고 싶어서 미션도 제쳐두고 브라우저의 렌더링 부분을 공부했다. critical rendering path를 공부하다보니 reflow, repaint를 공부하게 됐다. reflow, repaint를 공부하다 보니 왜 transform으로 애니메이션을 구현하는게 left로 애니메이션을 구현하는 것보다 좋은 지 알게 됐다. 특히 performance 탭을 아주 간략히나마 사용하는 법을 배우고 직접 내가 만든 아마존의 슬라이더에  left와 translateX을 적용해서 각각의 경우 렌더링 과정을 확인했을 때 left에는 reflow와 repaint가 일어나지만 translateX에서는 reflow repaint 없이 composite 단계만 있는 걸 보고는 카타르시스를 느꼈다. will-change 속성 역시도 비슷한 맥락인 것 같은데 일단은 미뤄두었다. 쌓여만 가는 마음의 빚..

 

 나는 이론공부 하는걸 코딩 하는 방법(?)을 배우는 것보다 더 좋아하는 스타일인데, 이론과 실제 개발의 별다른 연관성을 찾지 못할 때마다 현타를 느꼈었다. 뭔가 머리에 든 건 많은 것 같은데 정작 개발은 그냥 강의 보면서 무작정 많이 만들어 본 사람보다 못하고 그렇다고 내가 아는 게 개발에 도움이 되지도 않고.. 근데 이 때 이론이 실제 개발에 연관이 되는 과정을 거의 처음 느껴보지 않았나 싶다. 너무 짜릿했고 왜 깊게 공부해야 하는지 알 수 있었다. 

 

 다만 내가 공부했던 렌더링 과정은 reflow -> repaint -> composite 단계가 끝이었는데, performance 탭에서 pre-paint가 있길래 pre-paint는 뭐지? 하고 찾다가

 

  

 

  이런 거대한 이론을 마주치게 됐고, 내가 공부한 내용은 빙산의 일각이라는 걸 깨달았다. life of pixel이라는 엄청 유명한  해외 발표인 듯 한데, 일단은 이 거대한 내용도 마음속의 부채로 남겨두기로 했다. 

 

Request Animation Frame 

 브라우저의 렌더링 과정을 알고 나니 크롱이 왜 이번 주에 raf를 공부하라고 던져주었는지 알 수 있었다. repaint 직전에 raf의 인자로 전달한 콜백함수를 브라우저가 실행하도록 약속해주는데, setInterval이나 setTimeout처럼 매번 지정해놓은 시간에 정확히 실행되지 않아 애니메이션이 janky해지는걸 방지한다고 한다.

 

 사실 내 아마존 프로젝트에 적용시키진 않았는데.. 좀 반성할 부분도 있고 해결되지 않은 부분도 있고 해서 글로 남긴다. 내가 이해했던 raf는 재귀적으로 애니메이션의 한 프레임을 조절하는 역할이었는데 다른 분은 raf를 마치 타이머처럼 사용했다. 그 분에게 직접 말하진 않았지만 내 생각엔 잘못된 사용법이라고 생각해서 적어도 타이머를 적용하는 부분엔 raf를 사용하면 안된다고 생각했다. 그 이후에 좀 더 깊게 생각해보지 않고 저건 잘못된 사용법이야 혼자 결론을 내고 대수롭지 않게 넘겼다. 정말 후회되는 부분인데, raf의 원래 의도는 한 프레임에 대한 call back 등록이 맞겠지만 원래 의도대로 사용되지 않는 css 속성이나 js들이 간혹 있지 않은가? 근데 나는 내 짧은 식견으로 혼자 너무 빠르게 판단하고 결론을 지어버렸다. 좋은 토론 주제였을텐데 이 기회를 날린 점이 굉장히 아쉽다. 다음부턴 상대가 기분 나쁘지 않게 예의 있게 의문점을 제시할 줄도 알아야 한다고 생각된다.

4주차

 

 

 fetch().then(cb1).then(cb2)을 콜스택과 이벤트 루프, 콜백 큐, 마이크로 큐 관점에서 설명해보라는 크롱의 한마디가 프론트엔드 멤버 전원을 며칠간 혼란의 늪으로 빠지게 할 줄 크롱은 알았을까? 3주차 부터 토론에 적응해있던 우리는 이 주제로 며칠을 다시금 침 튀겼는지 모르겠다. 많은 의견이 있었다. 저 코드가 내부적으로는 콜백 헬 형태로 콜스택에 들어가서 한꺼풀씩 벗겨지는거다, fetch는 동기 함수인데 then 자체는 콜백 큐로 들어가서 나중에 실행되는 거다.. 등등

 

 나는 then이 addEventListner함수와 같은 역할이라고 주장했다. 하지만 아무도 내 의견에 동의해주지 않았고 나 역시도 직관적으로 이벤트론(ㅋㅋㅋ)을 생각해냈지만, 그들을 설득할 명확한 근거는 없었다. 토론이 치열해지다 보니 크롱도 미션이고 뭐고 다 제쳐두고 토론만 하는 우리의 모습이 재밌어 보였는지 토론 2일차인가? 한 명에게 지금까지 정리된 내용을 발표해보라고 했다. 내 이벤트론은 아무도 지지해주지 않았기 때문에 다른 가설을 발표했고 크롱은 그건 답이 아니라고 좀 더 고민해보라고 했다. 그러던 중에 아무리 이런저런 예제 코드를 돌려봐도 then 함수는 동기 함수인게 명확하고 그냥 콜백 함수를 addEventListner처럼 등록해주는 역할 뿐인것 같아서, XMLHttpRequest 함수의 기본 사용 예제를 봤는데 이게 웬걸.    

const req = new XMLHttpRequest();

req.onload = function(){
	const data = JSON.parse(this.responseText);
}

 내가 예전에 노션에 기록해 놓은 걸 보니 이런식으로 XHR을 사용하더라. 나는 여기서 확신을 얻었다. 그 때쯤 서서히 한두명의 사람들이 나의 이벤트론이 맞는것 같다, 빨리 다시 발표해보라고 해서 발표도 연습할 겸, 답답했던 마음도 풀 겸 크롱에게 직접 다시 발표하겠다고 찾아갔다 ㅋㅋㅋ

 

지금 생각하면 되게 간단한 내용이다.

0.  fetch().then(cb1).then(cb2) 가장먼저 fetch()를 평가해야 된다. 

1. fetch() 함수는 동기 함수이며 콜스택에 올라가 실행된다. 이 때 pending 상태의 Promise 객체 (p1이라 하자.)를 리턴하고 즉시 콜스택에서 제거된다.

2. 객체 p1의 메서드 then 역시 동기 함수이며 콜스택에 올라가 실행된다. 이 때 인자로 들어온 cb1을 addEventListner와 같이 등록만 해놓고 또다른 pending 상태의 Promise 객체 (p2)를 리턴하고 즉시 콜스택에서 제거된다. 

3. 객체 p2의 메서드 then 역시 동기 함수이며 콜스택에 올라가 실행된다. 이 때 인자로 들어온 cb2를 등록만 해놓고 pending 상태의 Promise 객체 (p3)을 리턴하고 즉시 콜스택에서 제거된다.

 

따라서 fetch와 then 함수 자체는 동기 함수다. 

 

여기에 관해서는 추후 다른 글로 한번 더 정리해보려고 한다. 아무튼 resolve, reject의 내용은 제외하고서라도 fetch와 then에 대해서는 적어도 내 발표가 100% 맞다고 크롱이 답을 주었고 우리는 fetch then then 지옥에서 벗어날 수 있었다. 

 

 

MVC 

 

 3주차 때부터 내 js 코드의 구조가 이상하다는걸 느끼기 시작했다. 클래스 하나에 컴포넌트에 대응되는 메서드들을 다 넣어놨는데 각 클래스마다 init 역할을 하는 메서드에 저 메서드들을 다 담아서 실행해주었다. 근데 난 이 구조가 굉장히 마음에 들지 않았다. init 역할을 하는 메서드와 다른 메서드들의 레이어가 다르다고 느꼈다. 원래는 index.js의 main 함수에 메서드들을 다 빼놨었는데 크롱이 라이브 코드 리뷰에서 main 함수가 너무 뚱뚱하다고 리뷰를 해서 이런식으로 구조를 어쩔 수 없이 바꿨었다. 중간에 레이어를 하나 더 둬서 클래스에는 원래대로 기본적인 메서드들만 넣고 이들을 묶고 이 함수들을 다시 main함수에서 호출하면 main도 가볍고 레이어 문제도 해결될 것 같았지만 이 방법 역시도 마음에 들지 않았다. 물론 나중에 크롱이 이런 식으로 레이어를 분리하고 각 레이어의 수준이 동일하도록 코드를 짜보라는 말을 듣고 한번 해보기나 할걸 그랬나 생각도 들었다.  

 

 또 다른 문제점이 있었는데 동적으로 dom을 삽입하는 templating을 하면서 기존의 클래스와 dom을 삽입하는 클래스 간의 의존성 문제가 생겼다. templating을 해주는 클래스의 인스턴스를 기존의 클래스가 변수로 가져주고 init을 해준 후에야만 기존 클래스에서 querySelctor을 실행할 수 있는 문제가 있었다. 코드가 너무 지저분해지다보니 나는 또 아키텍쳐를 찾아 떠났다. 

 

 예전에 리액트를 공부할 때 리액트가 해결하고 있는 문제가 mvc 패턴에서의 굉장히 복잡한 관계들이란 걸 본 적이 있다.

 사실상 리액트가 현재 프론트엔드 프레임워크(물론 리액트는 라이브러리지만,, 사실상 프레임워크가 아닐까)의 대표 주자라고 생각한다. 리액트가 해결하고자 했던 문제를 내가 몸소 느껴보고 싶어서, 또 리액트가 등장하기 전까진 가장 대표적인 아키텍처가 MVC였다는 걸 현재 리액트의 인기가 반증한다고 생각해서 MVC 패턴에 (BEM, Sass에 이어) 나를 던져 보았다.

 

 기존의 클래스들도 모두 MVC로 바꿔보고 싶었는데 검색창의 자동 완성기능, 아래 위 방향키로 자동 완성 검색어를 선택하는 기능 등 자잘자잘한 기능들이 생각보다 구현 난이도가 높아서 검색창 기능만 MVC로 구현하게 됐다. 

 

 BEM과 Sass의 7-1 폴더와 마찬가지로 MVC또한 내가 끙끙앓던 고민거리를 꽤나 잘 해소해주었다. 폴더 구조도 model, view, controller로 단순했고, 한 폴더 내의 여러 파일들이 하는 역할들의 수준(추상화 수준이라 해야할까?)이 비슷했다. 또한 한 함수나 메서드의 크기가 비교적 작게 잘 유지되기도 했다. 또한 불필요한 레이어가 생기지 않았다. 또 구조가 비교적 명확해지니 변수명을 짓기가 비교적 쉬웠다. 크롱이 좋은 설계 하에서는 변수명 짓기가 쉽다고 했는데 MVC패턴으로 구현한 내 검색창의 변수명이 매우 적절했다기보단, 이전의 이상한 설계에서의 변수명 보다는 명확해졌다는 표현이 더 맞는것같다. 

 

 하지만 역시나 이 유서 깊은 아키텍처를 한 주만에 배우고 적용하려다 보니 BEM, Sass에서와 동일하게 이 코드가 여기에 들어가는게 맞나? 하는 고민들이 생겼다. 물론 일주일만에 이 아키텍처를 완벽히 이해해서 활용하는게 불가능하기도 하고 그렇다고 아키텍처 이론을 몇주를 공들여 공부했다고 해서 이런 고민을 안하진 않았을 것 같다.