우테코 2주 차도 어느덧 끝이 났다.
주 차를 거듭하면 생각의 깊이가 점점 깊어지는 듯한 느낌을 받는다.
이전 주 차에서의 부족함을 발판 삼아 더 좋은 코드를 짜려고 하니 고민해야 할 것들이 점점 늘어나는 것 같다.
1주 차때 나는 많은 실수들을 했기 때문에, 2주 차에서는 최대한 1주 차에서 느꼈던 아쉬움을 해소하기 위해 노력했다.
1주 차에서 가장 아쉬웠던 점은 요구사항을 꼼꼼하게 반영하지 못했다는 점이 많이 아쉽게 다가왔다.
결론적으로 얘기하면 2주 차에서는 요구사항에 관한 점은 잘 지킨 것 같다! 다만 조금의 실수를 곁들인..ㅋㅋㅋㅠㅠ
이번의 실수는 놓쳤다기 보단 몰라서 하지 못한 실수들이 많았지만 그래도 분명 몰랐던 것들은 아니었는데 생각이 짧았던 것 같다.
이번 회고를 통해 3주 차에서도 2주 차에서 했던 실수들을 최대한 개선해보려고 한다. 🔥
목표설정
2주 차의 목표는 요구사항을 잘 지키고 피드백 반영하기 였다.
어찌 보면 정말 당연하고 간단한 목표인데.. 가장 어려운 점인 것 같다.
주 차를 거듭할수록 공부해야 할 것도 늘어나고 피드백도 반영해야 한다.
피드백을 제대로 반영하려면 공부하는 데 시간을 써야 하고 그러다 보면 이번 주 차의 개발을 할 시간이 모자라게 된다.
이런 악순환 속에서 개발을 하다 보면 내가 과제를 하는 것인지 공부를 하는 것인지 헷갈리게 되는데
그럴 때마다 시간관리와 계획 중요성을 느끼게 되는 것 같다.
공통 피드백
대부분 잘 지켜서 했던 것 같은데.. 내가 놓친 부분도 있는 것 같다.
이번에 놓친 부분들 같은 경우에는 표시해주고 3주 차에 반영할 수 있도록 해보자!
- README.md를 상세히 작성한다
- 해당 프로젝트가 어떤 프로젝트인지 소개
- 주요 기능이 무엇인지 소개
- 마크다운 문법 잘 쓰기
- 기능 목록을 재검토한다
- 기능 목록을 작성할 때 클래스 설계와 구현, 메서드 설계와 구현 같은 상세한 내용은 포함하지 않는다.
- 클래스 이름이나 메서드 시그니처, 반환값 등은 언제든지 변경될 수 있다.
- 기능 목록을 업데이트한다
- 시작부터 모든 기능을 완벽하게 정리해야 한다는 부담을 가지기 보단,
- 기능을 구현하면서 문서를 지속적으로 업데이트하자
- 값을 하드 코딩하지 않는다
- 상수(const)를 정의하고 의미 있는 이름을 부여한다
- 해당 값이 어떤 역할을 하는지 명확히 드러낸다
- 구현 순서도 코딩 컨벤션이다
- 한 메서드가 한 가지 기능만 담당하게 한다
- 메서드가 한 가지 기능을 하는지 확인하는 기준을 세운다
- 메서드의 길이가 길어지면 여러 기능을 포함하고 있을 가능성이 커진다.
- 15라인이 넘지 않도록 구현하면 의식적으로 메서드를 분리하는 연습을 할 수 있다.
- 테스트를 작성하는 이유에 대해 본인의 경험을 토대로 정리해본다
- 처음부터 큰 단위의 테스트를 만들지 않는다
- JavaScript에서 객체를 만드는 다양한 방법을 이해하고 사용한다.
고민했던 부분
1. 구조에 대한 고민
1주 차에선 MVC 패턴을 사용했었다.
MVC 패턴을 사용한 이유는 효과적으로 역할을 잘 분리하고 유지보수성 및 확장성을 높일 수 있을 것이라 판단했기 때문이다.
다만 피드백 중에 과한 것 아닌가? 하는 의견을 받았고 2주 차 과제를 하기 전 구조에 대한 깊은 고민을 하게 되었다.
1-1. 패턴을 써야 하는가
2주 차 과제에 대한 구현할 사항들을 작성하면서 큰 덩어리로 역할을 나누자면 다음과 같았다.
- 게임을 컨트롤하는 역할
- 자동차의 역할
- 사용자의 입, 출력을 담당하는 역할
- 그 외 (검증, 파싱)
우선 프로젝트의 규모를 패턴의 기준으로 잡게 되면 구현해야 하는 게 서비스가 아니다 보니 당연히 과분할 수밖에 없다는 생각이 들어서 제외하고 생각했다.
그랬을 때 MV* 모델을 쓰면 당연히 유지보수나 확장성이 좋아진다는 건 당연하다.
하지만 1주 차 때 굳이 MVP를 썼어야 했나 하는 리뷰에 대해 깊게 생각해 보니, 해당 미션에선 MVP를 썼을 때의 이점이 적절한 클래스와 함수의 모듈화를 통해서도 충분히 나타날 수 있겠다는 생각이 들어 이번 미션에선 패턴을 쓰지 않았다.
1-2. Class와 함수 형태의 모듈화
그러다 보니 추가적으로 든 생각이 어떤 것을 Class로 만들고 함수 형태의 모듈로 만들어야 하는지 고민이 되었다.
"Class는 붕어빵이야"라는 말은 컴퓨터 관련 학부라면 한 번씩은 들었을 것이다. 앙금과 반죽이라는 필드, 메서드는 뭐.. 없을 수도 있지만.. 여튼 이런 요소들이 모여 Class를 생성하듯 여러 개로 복사가 되더라도 하나의 명확한 역할을 할 수 있는 것을 Class로 만들어야겠다는 생각을 했다.
Class에 대한 기준
- 데이터와 그 데이터를 다루는 메서드가 함께 필요할 때 (#carName과 getCarName)
- 인스턴스별로 상태를 유지해야 할 때 (자동차별 이름과 포인트)
- 비슷한 객체를 여러 개 생성해야 할 때 (여러 개의 자동차)
1주 차에선 "아ㅋㅋ 묶어서 가져다 쓰기 좋네"라던지, 내부의 요소들이 비슷한 역할(ex. 입력담당)을 하고 있으면 바로 class 형태로 만들었기 때문에 전부 Class로 만들어 썼다. 다만 큰 오산이었다. 비슷한 역할을 한다고 해서 묶는 건 Class가 아니어도 폴더나 파일명으로 충분히 할 수 있다.
그래서 앞서 말한 기준에서
- 게임을 컨트롤하는 역할 (Race)
- 자동차의 역할 (Car)
- 사용자의 입, 출력을 담당하는 역할 (input, output)
- 그 외 (validator, sort, parser, error)
다음과 같이 나누었다.
해당 구조는 utils에 불필요하게 들어가 있는 기능들이 많아 잘못 짜인 코드다.
다음부터는 함수형 모듈에 대한 기준을 명확히 해 Class와 함수형 모듈 중 어느 것을 택할지 잘 고민해 봐야겠다.
함수형 모듈에 대한 기준
- 단일 책임을 가진 독립적인 동작을 수행할 때
- 입력값을 받아 결과를 반환하는 순수 함수로 구현 가능할 때
- 상태 관리가 필요 없는 유틸리티 기능일 때
2. 네이밍
나는 아래와 같은 느낌으로 폴더 구조를 작성했다.
src
┣ constants
┃ ┣ message.js
┃ ┗ threshold.js
┣ utils
┃ ┣ validator
┃ ┃ ┣ car.js
┃ ┃ ┗ count.js
┃ ┣ view
┃ ┃ ┣ input.js
┃ ┃ ┗ output.js
┃ ┣ error.js
┃ ┣ parser.js
┃ ┗ sort.js
┣ App.js
┣ Car.js
┣ Race.js
┗ index.js
되게 난잡해 보일 수 있는데 기준은 아래와 같았다.
- 클래스는 PascalCase (Car.js)
- 일반 모듈은 camelCase (parser.js)
- 폴더 이름이 파일의 의미를 내포하고 있다면, 폴더 이름을 굳이 접미사로 달아주지 않음.
이게 좋은 방식인지 아닌지는 잘 모르겠다.
일반적인 개발 케이스를 잘 따라갔다고 생각했는데, 리뷰에 가독성 관련 멘트가 달리고 곰곰이 생각해 보니 관점에 따라선 일리 있는 말이었다고 생각한다.
어떻게 해야 할지 잘 모르겠어서 2주 차 미션이 끝난 시점에서 ai를 통해 피드백을 받아보니, 다음과 같이 폴더 구조를 짜면 좋다고 한다.
- constants/
- message.js
- threshold.js
- utils/
- validators/
- car.js
- count.js
- views/
- components/
- input.js
- output.js
- error.js
- helpers/
- parser.js
- sorter.js
- models/
- Car.js
- Race.js
- App.js
- index.js
내가 짠 구조보다 역할이 명확해지고 utils에 넣은 것들이 동등한 계층으로 분리되었다.
지금과 그리 큰 차이는 없지만 utils에 다 때려 박는 건 그만해야겠다...
3. 디버거 활용하기
나는 Webstorm이란 IDE를 쓰고 있는데 디버거를 사용하려고 하니까 어디서부터 사용해야할지 사실 막막했다.
그래서 2주 차에서도 console.log를 가끔 썼었는데.. 1주 차 공통 피드백에 있는 디버거를 사용하라는 점이 찔려서 사용해 보았다.
해당 영상을 참고하니 쉽게 할 수 있었다.
만약 아래 코드에서 this.#winner에 들어간 객체의 정보를 알고 싶다면, this.#winner가 입력되는 라인 아래에 stop point를 지정해 준다.
그리고 index.js로 가서 디버거를 돌려보면?
위의 이미지와 같이 해당 매서드 내부의 정보들과 함께 this.#winner에 들어간 정보를 쉽게 확인할 수 있었다.(왜.. 진작 몰랐을까..)
실수했던 부분
1. 함수 모듈과 utils 파일
1, 2주 차 모두 그랬지만 나는 클래스를 제외한 기능적인 역할을 하는 모듈들을 전부 utils에 밀어 넣었다.
하지만 다음과 같은 방식은 잘못되었다는 것을 리뷰를 통해 알게 되었고 유틸함수의 조건은 다음과 같다는 것을 알게 되었다.
유틸함수에 대한 기준
- 순수 함수여야 한다 (같은 입력에 항상 같은 출력)
- 외부 상태에 의존하지 않는다
- 특정 도메인에 종속되지 않고 범용적으로 사용 가능하다
export const sortScore = (cars) => {
return cars.sort((n, m) => m.getPoints() - n.getPoints());
};
내가 utils/sort.js에서 작성한 위의 코드는 cars객체에 따라 다른 결과를 내보내기 때문에 utils에 적합하지 않았다.
또한 cars와 직접적인 연관이 있기 때문에 Race 클래스 내부의 매서드 였어야 했다.
Race가 의미상 지니는 역할에 맞는 코드를 짜는 것도 중요하지만, 불필요하게 분리할 필요는 없었다.
2. 유틸함수에서 에러를 처리하는 건에 대해
이 부분도 사실 유틸 함수에 대한 이해가 잘못되어서 validator이 utils로 들어가서 받은 피드백인데,
다음과 같이 유틸함수는 범용적으로 사용되어야 하기 때문에 내부에서 에러를 일으키는 게 바람직하지 않을 수도 있다고 말씀해 주셨다.
이 부분에 대해서 앞으로 어떻게 코드를 짜야할지 고민이 되었다.
validator에서 에러를 일으키지 않으면 호출하는 함수에서 에러를 던져야 하는데, 그렇게 되면 호출 매서드가 검증에 대한 의존성이 높아지는 게 아닐지 의문이었다.
하지만 특정 클래스를 위한 매서드라면 범용성이 조금 떨어져도 괜찮을 것 같았고 validator에서는 에러를 던지는 것보다 결과를 boolean 형태로 반환해 주는 것이 더 낫겠다는 생각이 들었다.
3. airbnb 코드 스타일
나는 이번에 eslint와 prettier 파일을 repo에는 올리지 않았지만 사용하긴 했다.
1주 차 때 손으로 린트를 하려니까 너무 힘들어서 이번엔 사용해 봤는데, 대체로 잘 적용되긴 했으나 IDE와 github에서 보는 것이 달라서 조금 당황스러웠다.
분명 IDE에서 봤을 땐 tabWidth가 2만큼 잘 된 것처럼 보였는데 리뷰 때 보니 들여 쓰기가 2번 된 건 맞지만 tabWidth가 4처럼 보였다.
다음번엔 꼭 미리미리 git push를 해서 repo에도 잘 적용되고 있는지 확인해야겠다는 생각이 들었다.
4. 상수 값에 대한 고차함수 사용
이번 리뷰를 통해 알게 된 것인데 다음과 같이 상수값을 고차 함수를 통해 반복시킬 수 있는지 처음 알았다.
다음번엔 조금 더 명령형으로 프로그래밍하기 전 선언형으로 할 수 있는 방법이 있는지 확인해 봐야겠다.
5. 테스트 케이스 작성하기
사실 테스트 케이스를 여태껏 작성해 본 적이 없어서 새로운 개념을 익히는데 애를 많이 먹었다.
가급적이면 미리 제공된 케이스를 따라서 작성해보려고 했는데, 결국 코드를 이해하고 짜려면 공부가 필요했다.
그래서 TDD는 꿈도 못 꾸고 개발을 다 한 뒤에 테스트 코드를 짰다..
이 때문에 테스트 코드는 아쉬운 부분이 참 많은데, 특히 반복되는 코드들을 test.each()로 묶어 처리하거나 했었어도 되었을 것 같은데 그냥 케이스마다 테스트를 만들어 버린 부분이 아쉬웠다.
회고를 마치며
이번 2주 차는 네이밍, 범용성과 확장성 등 근거 있는 개발을 하기 위해, 필요한 다양한 관점들에 대해서 많이 생각을 해보게 된 것 같다.
1주 차에 대한 아쉬웠던 점을 잘 커버했지만 그래도 실수는 조금 있었던 것 같다.
요즘 우테코에서 배운 것들을 에이전시에서 종종 써먹어 보고 있는데 야무지다.
최근에는 라이브러리를 직접 구현하면서 구조에 대한 고민을 하게 되었는데 우테코를 하면서 공부한 것들이 큰 도움이 되었다.
물론 코드는 여전히 부족하지만..ㅎㅎ 의문을 제기하고 배우고 현업에서 써먹어 보면서 예전보다 코드의 품질이 높아지는 게 보인다.
요즘 컨퍼런스나 활동을 통해 많은 인풋을 얻고 있는데 이를 통해 아웃풋을 낼 수 있는 개발자가 되고 싶다.
성장하고 있는 자신이 너무 대견하고 즐겁다.
앞으로의 목표라면 현재처럼 피드백을 잘 받고 근거 있는 코드를 작성하며, 보기 좋은 코드를 작성하고 싶다.
3주 차도 파이팅!! 🔥
'Programming' 카테고리의 다른 글
[우테코 프리코스/7기] 프리코스 최종 코딩테스트 후기 (36) | 2024.12.17 |
---|---|
[우테코 프리코스/7기] 프리코스 3주 차 회고 (4) | 2024.11.07 |
[우테코 프리코스/7기] 프리코스 1주 차 회고 (4) | 2024.10.24 |
[우테코 프리코스/7기] 커밋 방식 알아보기 (4) | 2024.10.16 |
[우테코 프리코스/7기] 본격적인 시작 전 준비 (0) | 2024.10.15 |