about

10주간의 항해를 마치며 part 2.

Cover Image for 10주간의 항해를 마치며 part 2.

지난주 토요일(25.06.07) 길다면 길고 짧다면 짧다고 할 수 있는 10주간의 항해가 끝났습니다.

이번 포스트에서는 마지막 네트워킹 자리에서 최종 발표 때 사용했던 자료와 새롭게 추가한 내용을 토대로 항해 플러스 5기에 대한 회고를 진행해 보고자 합니다.
이번 회고 중 일부는 테오의 멘토링에서 제시해 주셨던 키워드를 바탕으로 만들게 되었습니다.

🚢항해를 시작하기 전 생각했던 막연한 기대

항해를 시작하기 전 생각한 막연한 기대는 다음과 같습니다.

재미있게 테스트 스펙으로 기대들을 나타내보겠습니다.

(항해에서는 매주 과제를 통해 기대하는 교육생의 모습을 테스트 스펙으로 정의합니다😂)

expect(
  HanghaePlus_5th('노기훈')
).toEqual({
	'항해의 커리큘럼을 완벽히 소화한다',
	'블랙뱃지를 받는다',
	'현업 개발자에 버금가는 실력을 가진 학부생이 된다',
})

네. 정말 막연한 기대였습니다ㅎㅎ

먼저 첫 번째 기대부터 하나씩 살펴보자면 항해에서 ‘열심히 하다’ 와 ‘완벽히 소화하다’는 다른 것이었습니다.

10주라는 기간 동안 프론트엔드의 핵심이 되고 코어 한 것들을 공부하다 보니 긴 시간 의자에 앉아있더라도 단기간에 받아들일 수 있는 지식의 양은 한계가 있어 완벽하게 커리큘럼을 따라갈 수 없음을 차차 깨닫게 되었습니다.

**다음으로 블랙뱃지에 대한 기대입니다.
**

사실 처음 오프라인 발제를 들으면서 바로 “아ㅋㅋ 블랙뱃지 어떻게 받아~”싶었습니다.

이번 5기에는 블랫뱃지에 대한 기준이 올라가 과제 통과 100%, BP(Best Practice) 2개를 받아야 했으며,
발제 자료와 과제를 이해하는 과정도 힘든데 BP를 받는다는 것은 꿈도 꾸기 힘들 것 같았습니다.

그리고 마지막 기대인 현업 개발자의 실력을 가진 학부생이 되겠지에 대한 생각은 학부생 수준의 코드는 현업에서 몸으로 부딛히며 개발을 하는 분들과 상대가 안 된다고 느꼈습니다. 또 동시에 그만큼 배울 수 있는 코드가 많았기에 실력이 많이 늘겠다는 생각을 했습니다.


🌆10주간의 여정을 회고해보자

사실 10주동안 인상 깊었던 주차들을 리뷰하려고 하다가 모든 챕터에서 선명하게 기억나는 것들을 더 오래 기억하고 기록하고 싶어 주차별 회고로 수정했습니다. 회고가 다소 길어지더라도 양해 바랍니다.😊

chapter 1-1 프레임워크 없이 SPA만들기.

첫 번째 주차의 과제는 프레임워크 없이 SPA 만들기 입니다.
저는 부끄럽지만 바닐라 JS를 깊이 다루지 못하고 리액트를 접하여 바닐라 JS를 깊이 이해하지 못해

dom api를 다루는 방법, 이벤트를 관리하는 방법, 테스트 코드를 통과할 수 있는 코드 짜기(?) 등 많은 것을 배우고 생각해야 했습니다.

여러모로 어려움이 많았던 챕터였지만 학습메이트분의 도움과 다른 분들의 코드 그리고 코치님의 멘토링을 통해서 과제를 제출하고 패스를 받을 수 있었습니다.

과제 제출 이후 1주차 과제에 대한 solution 코드가 주어졌는데, 이때 프론트엔드에서의 디자인 패턴(옵저버 패턴)을 처음 접할 수 있었습니다.

chapter 1-2 프레임워크 없이 SPA만들기 - Part 2

2주차에서는 1주차의 solution코드에 다음과 같은 추가 요구사항을 만족하는 코드를 만들어야 했습니다.

  • 가상돔을 직접 구현하고, 가상돔을 돔으로 변환할 수 있어야 한다.
  • 가상돔에 대한 diff알고리즘을 수행하면서 렌더링을 최소화시키고 이벤트를 최적화한다.

2주차는 1주차보다는 할만하겠지 싶었는데 그렇지 않았습니다.

밑은 2주차를 진행하며 특별히 기억나는 내용들입니다.

  • vNode를 정규화하는 함수 normalizeVnode를 구현

프론트를 공부하면서 재귀를 사용할 일이 있을까 했는데 해당 과정에서 재귀를 통해 vNode를 정규화할 수 있었기에 기억에 남습니다. (여기서 정규화란 표준화된 형태로 변환한다 정도로 이해해 주시면 좋겠습니다.)

  • Map을 이용해 이벤트를 위임하고 등록하는 과정

map역시 자주 사용하는 방식이 아니었기에 map을 통해 이벤트를 등록시키고 삭제하는 과정이 생소했습니다. 또한 초반에는 2개의 map을 사용해 이벤트타입과 핸들러를 관리하는 비효율적인 코드를 작성하고 심지어 동작도 제대로 안 하는 코드를 작성했었습니다.

(+2주차 과제를 하는 동안 구름톤 유니브 교내ot 때문에 열차 안에서 코딩을 할 수 밖에 없었던 기억이 얼핏 납니다.. 그리고 생각보다 열차가 집중이 잘되는 환경이어서 좋았습니다.👍)

chapter 1-3 React, Beyond the Basics

3주차는 학메님께서 쉬어가는 주차라고 하셨지만.. 저에게는 여전히 힘들었던 주차였습니다.
(지금 생각해 보면 3주차는 쉬어가는 주차가 맞는것 같기도 합니다 ㅎㅎ)

과제를 설명해 보자면 기본과제에서는 리액트의 기본 훅들을 직접 구현하고 context의 관심사를 분리하는 과제를 진행했습니다.
구현해야 하는 훅들에는 useRef, useMemo, useCallback 등이 있었고 useMemo를 위한 shallowEquals와 deepEquals를 구현해야 했습니다.

기본과제를 통해 리액트가 해결해 주는 문제들을 경험할 수 있었고 위의 훅들을 만들기 위해 더 깊이 있게 훅들을 학습할 수 있었습니다.

심화 과제에서는 context의 관심사 분리를 진행하였습니다.

심화 과제를 하면서 전역 상태 관리를 위해 사용하는 줄 알았던 context가 의존성 주입을 위해 사용된다는 점을 배웠으며,

위와 같이 텍스트, 프로바이더, 컨텍스트 훅을 한 파일에서 관리하는 코드를 작성하며 다음과 같은 고민을 하여 과제 피드백을 요청드리게 됩니다.

# 질문
제가 생각한 바로는 위의 코드는 응집도가 강해 각각의 함수와 훅을 분리하는 것보다 관리하기 수월하다고 판단하였습니다.
그리고 위의 코드를 단일 책임 원칙에서 생각해 보고자 하였습니다.
위의 코드를 단일 책임 원칙으로 생각하면서 생긴 궁금증은 책임이라는것을 얼마나 크고 작게 분리할 수 있는지가 궁금하였습니다.
예를 들자면 Theme를 관리한다.라는 책임(기능)으로 보았을때는 하나의 책임을 지킨것으로 볼 수 있지만,
context를 생성하고, Provider를 제공하고,useContext로 컨텍스트를 제공하는 작은 책임(기능)들로 보았을때는
해당 코드가 분리되는게 맞다고 생각합니다.
제가 접근한 방식이 단일책임원칙을 온전히 이해하지 못하여 발생하였을지 모르지만,.. 코치님의 의견을 여쭤보고 싶습니다!!

그리고 다음과 같은 답변을 받으며,

# 답변
우선 context / provider / useContext같은 관점으로 '책임'을 정의하는 건 아닌것 같아요! ㅎㅎ
사실 R에 해당 하는 책임 / 책무라고 번역될 수 있는 내용은 보는 사람에 따라 다양하게 해설되곤 하는데요.
전에 소개드렸던 이 글을 기억하실지 모르겠지만 ..
결국 여기서 말하는 '책임'은 동작이나 기능을 의미하기 보다는 요구사항을 전달하는 책무에 가깝다고 얘기해요..(생략).
 

프론트엔드에서의 solid원칙에 대해 깊이 고민할 수 있었습니다.

chapter 2-1. 클린코드와 리펙토링

긴말 필요없이 제가 리펙토링해야했던 코드의 일부를 보여드리겠습니다.

var prodList, sel, addBtn, cartDisp, sum, stockInfo;
var lastSel, bonusPts=0, totalAmt=0, itemCnt=0;
function main() {
  prodList=[
    {id: 'p1', name: '상품1', val: 10000, q: 50 },
    {id: 'p2', name: '상품2', val: 20000, q: 30 },
    {id: 'p3', name: '상품3', val: 30000, q: 20 },
    {id: 'p4', name: '상품4', val: 15000, q: 0 },
    {id: 'p5', name: '상품5', val: 25000, q: 10 }
  ];
  var root=document.getElementById('app');
  let cont=document.createElement('div');
  var wrap=document.createElement('div');
  let hTxt=document.createElement('h1');
  cartDisp=document.createElement('div');
  sum=document.createElement('div');
  sel=document.createElement('select');
  addBtn=document.createElement('button');
  stockInfo=document.createElement('div');
  cartDisp.id='cart-items';
  sum.id='cart-total';
  sel.id='product-select';
 
//이하 생략..

작정을 하시고 어지럽게 만든 코드입니다.
적절한 줄바꿈과 주석을 통해 코드를 논리적 단위로 명확히 구분하고 매직 넘버와 문자열을 상수로 추출하는 등의 과정을 해야했습니다.

그리고 핵심적으로 리팩토링이기 때문에 기존의 기능을 그대로 유지하면서 점진적으로 개선해야 했습니다.
(_ 당연한거지만 ai야 해줘~ 딸깍 불가._)


요런식으로.. 점진적으로 코드를 고쳐야 했습니다.

제출 마감 하루 전(목요일 밤), 마침 테오코치님의 멘토링이 있었고 질문을 하던 중에 다음과 같은 피드백을 받게 됩니다.
“코드와 폴더 구조가 어떤 목적으로 분리되었는지 파악하기 힘들고, 하나의 로직이 파편화 되어있다”

심화과제도 중요했지만, 멘토링에서 받은 피드백을 검토하는것이 더 중요하다고 생각했고 피그잼을 통해서 제 과제를 다시 들여다 보게 됩니다.
(이때를 기점으로 피그잼으로 기록하고 공부하는것에 재미를 들렸습니다.)


결론적으로 처음으로 fail을 받은 심화과제가 되었습니다.

하지만 과제의 취지인 나쁜 코드를 경험하고 좋은 코드와의 차이를 몸소 느껴보며, 클린코드가 무엇인지 리펙터링은 어떻게 진행되야 하는지 많이 배울 수 있었던 챕터였습니다.

chapter 2-2. 디자인 패턴과 함수형 프로그래밍

5주차 과제의 목적은 다음과 같습니다.

  • 비즈니스 로직 분리하기
  • 뷰 데이터와 엔티티 데이터의 분리
  • entities-features-ui 계층에 대한 이해

해당 목적에 맞게 커스텀훅과 유틸 함수를 분리하고 테스트 코드를 통과하도록 해야합니다.

5주차 과제는 6주차 과제와 함께 가장 많은 고민을 하면서 진행한 챕터로 소개 드릴 수 있습니다.

아무 생각 없이 작성하던 프론트엔드 코드에서 비즈니스 로직을 분리하고 엔티티를 이해하는 것은 처음 자바를 접했을 때 메소드, 객체 등의 개념을 접한것 처럼 벙찌게 만들었습니다.

또 내가 작성하던 코드에서 안 보이는 것을 볼려고 노력하다 보니(엔티티? 액션?) 뭐가 뭔지 잘 감이 안잡혔습니다..

그렇지만 과제에서 제공해주는 함수형 프로그래밍에 대해 배우게 되었고 액션과 계산을 분리하는것에 초점을 두어 과제를 진행하였습니다.
(엔티티는 5주차 과제가 끝나고도 완벽히 뭐다!라는 느낌이 오지 않았습니다.)

지금 생각해보면 챕터 2를 진행하면서 명확하게 구분할 수 있는것을 먼저 분리(구분)하는것이 과제를 하는데 있어서 앞으로 나아가는데 큰 도움이 됐다고 느껴집니다.

(이번 챕터에 대한 더 자세한 회고는 밑의 pr을 참고해주시면 무척 감사하겠습니다. )

https://github.com/hanghae-plus/front_5th_chapter2-2/pull/17

BP를 받다!

그리고 믿기지 않게도 해당 주차에서 BP에 뽑히게 됩니다.

받은 순간에 내가 받아도 되나라는 생각을 했습니다. ㅎㅎ

항해를 마친 지금의 시점에서 BP를 받을 수 있었던 이유를 생각해 보자면 과제를 진행하며 사고했던 과정을 자세히 기록하고 과제에서 수행한 바를 자세히 기록했던 것이 BP의 이유이지 않을까 생각이 듭니다. (코치님 감사합니다.🙇‍♂️🙇‍♂️🙇‍♂️)

chapter 2-3. 관심사 분리와 폴더구조

해당 챕터에서는 전역상태관리를 이용한 적절한 분리와 계층에 대한 이해를 통핸 FSD 폴더 구조를 적용해야 했습니다.

FSD에 대한 자세한 내용은 밑의 공식문서 확인해보시길 권해드립니다.

https://feature-sliced.design/

<코드 레벨 이전의 분석 단계>

사실 이번 과제에서는 구현해야 하는 페이지에 들어가는 요소들의 성질을 잘 파악해서 적절한 위치에 배분하는 것이 매우 중요했습니다.

그렇기 때문에 분리하기 전 페이지의 요소들을 분석해야한다고 생각을 하였습니다.

또한 FSD에서 제공하는 각 층이 잘 와닿지 않아 공식문서에서 제공하는 예제들을 분석하면서 6주차 과제에 어떻게 적용할 수 있을까를 고민하였습니다.

관심사 분리에 대한 과제를 진행하면서 위와 같은 과정들이 도움이 될줄 알았으나, 코드를 보고 FSD에 맞게 구성하는것은 큰 괴리감이 있었습니다.

FSD는 아키텍쳐이지만 멘탈 모델이고 사람마다 각기 다른 방식으로 구현할 수 있습니다.
또한 좋은 형태는 있어도 정답이 존재하지 않았습니다.

따라서 앞서 분석한 프로젝트는 그 프로젝트에 맞는 최적의 형태로 구성이 되어있었고, 본인은 이번 프로젝트에 맞게 새롭게 각 레이어를 구성해야 했습니다.

<코드 레벨>

  1. 타입 분리: 기존의 코드에서 적용되 않은 엔티티에 대한 타입을 정의하고, 여러 타입 오류를 수정하였습니다.
  2. 헷갈리지 않을, 명확하게 분리할 수 있는 요소들 위주로 분리
    • Header, Footer를 shared/ui에 위치
  3. Entities레이어에 각 도메인의 타입을 정의: post, comment, user에 대한 타입을 명시하여 Entities 상위의 레이어에서 재사용할 수 있도록 하였습니다.
  4. Widget과 Pages 구성
    • 4번 과정까지 만든 요소들을 조합하여, Widget과 Pages룰 구성하였습니다.
    • Widget에서는 최대한 write를 줄이고 read로 만들기 위해서 선언적으로 컴포넌트를 위치시켰습니다.

더 자세한 기록은 밑의 pr에서 확인해주세요.

https://github.com/hanghae-plus/front_5th_chapter2-3/pull/13

두번째 BP를 받다!

그리고 뜻밖에도 다시 BP를 받게 됩니다..
BP를 받은 이유는 5주차와 비슷하지 않을까 싶습니다. (코치님 감사합니다🙇‍♂️🙇‍♂️🙇‍♂️🙇‍♂️)

6주차까지의 챕터들을 회고하다 보니 생각보다 포스트가 길어져서 한번 끊고 가고자 합니다! 감사합니다.