[우아한 프리코스] 1주차 미션 회고 - 온보딩
업데이트:
1주차 미션이 끝났다 !
1주차 미션은 온보딩으로 프로그래밍 문제 7개를 푸는 것이었다.
미션에 대한 내용과 내가 작성한 코드는 아래 링크에서 확인할 수 있다.
1주차를 진행하면서 고민이 정말 많았다.
그래서 피드백을 듣기 전 문제를 해결하면서 혼자 고민했던 부분들과 1주차 피드백을 통해 이 고민들에 대해 내가 내린 결론까지 정리해보았다.
기능 목록을 어떻게 생성할까 ? 🤷🏻♀️
미션을 받고 문서를 읽다가 처음으로 고민이 생겼던 부분이다.
주어진 문제 7개는 알고리즘 문제와 비슷했다. 그런데 평소 알고리즘 문제를 풀 때는 기능 목록을 세분화해서 목록을 만들고 그 목록에 맞추어 구현한 적은 없었다. 아래 그림은 내가 만든 기능 목록이다.
함수형 프로그래밍 기법으로 문제를 풀어낸다면 처음 작성한 목록대로 기능 구현을 할 수 있을 거라고 생각하여 함수 단위로 기능을 만들었다.
함수 하나가 하나의 기능을 가지게 하려고도 최대한 노력했다.
1주차 피드백을 듣고 … 😥
사실 깔끔하게 정리된 기능 목록을 만들고 싶어서 매 문제마다 거의 몇 시간을 투자했었다.
그런데 피드백을 듣고 나니 처음부터 설계를 잘하기 위해 몇시간을 투자하는게 좋은 방식이 아니었다는 것을 깨달았다 ..
기능을 쪼갠 후에 테스트 코드를 작성하여 설계 단계의 오류를 잡아내는 방식으로 코드를 짰다면 더 많은 예외 사항을 처리한 퀄리티 높은 코드가 나왔을텐데 하는 아쉬움이 있다.
그리고 나는 위의 제한사항에 주어진 내용이 지켜져서 입력이 되는 것이라고 판단하고 예외를 따로 구현하지 않았다.
1번 문제같은 경우에 제한사항이 지켜진다면 1페이지와 400페이지를 입력받는 경우와 책 페이지가 연속하지 않은 경우만 예외라고 생각했다. 정말 큰 오산이었다 !
실제 이 게임을 사용자가 한다고 생각했을 때, 사용자가 입력을 제맘대로 줄 수 있는 상황이 너무나도 많다. (400 페이지 이상의 값을 입력한다거나 페이지 번호를 반대로 입력하는 등 ..)
2주차엔 이렇게 해보자 !
코수타(코치와 수다 타임)에서 테스트 도구에 익숙해져 보고 좋은 테스트 코드도 만들어보라고 하셨다. 그리고 TDD 방식에 대한 언급도 하셨었다.
그래서 아직 테스트 코드를 작성해본 적도 없고 jest 언어도 모르지만 좋은 테스트 코드를 만드는 방법도 공부해볼 예정이다.
그리고 한 가지 기능을 해결할 때 어떻게 하면 기능을 더 작은 단위로 쪼갤 수 있을지도 충분히 고민해봐야겠다.
변수와 함수 네이밍
이번 주차에서 내가 중점을 두었던 부분이다.
아무래도 누군가 나의 코드를 본다고 생각하니 좀 더 가독성 좋고 클린한 코드를 짜고 싶었다.
가독성이 좋으려면 최대한 길이를 줄이는 것이 맞지 않을까? 라고 처음에는 생각하였다.
예를 들어 2번 문제 같은 경우,
const removeDuplicate = (cryptogram) => {
return cryptogram.replace(/([a-z])\1+/g, "");
};
const isNotDuplicate = (cryptogram) => {
return !/([a-z])\1+/g.test(cryptogram);
};
정규표현식을 코드 안에 넣어 코드의 길이를 줄이고자 했었는데 누군가 봤을 때 저 정규표현식이 무엇을 의미하는지 알 수 없을 거 같았다.
const searchDuplicateRegExp = /([a-z])\1+/g;
const removeDuplicate = (cryptogram) => {
return cryptogram.replace(searchDuplicateRegExp, "");
};
const isNotDuplicate = (cryptogram) => {
return !searchDuplicateRegExp.test(cryptogram);
};
코드는 조금 길어졌지만 정규표현식에 이름을 지어줌으로써 함수 내 코드의 의미가 더 명확해졌다.
이러한 점을 깨닫고 뒷 문제들도 코드가 조금 길어지더라도 작은 변수 하나에도 의미를 부여하려고 노력했다.
하지만 이에 따른 부작용도 생겼다.
처음부터 변수명과 함수명을 지을 때 엄청 고민을 하느라 코드 짜는 시간이 매우 길어졌다. 그래서 뒷 문제로 갈수록 더 난이도가 높음에도 불구하고 시간 할애를 많이 못했고 구현에 급급하여 코드의 퀄리티가 안좋아져버린 것 같다 😥
그런데 이 부분도 코수타에서 얘기해주셔서 놀랐다. 처음부터 너무 잘 지으려고 하면 어려우니 먼저 기능 목록대로 기능을 만들고 변수명을 수정하는 편이 좋다고 피드백을 주셨다.
2주차부터는 기능 목록을 만들고 테스트 하는데 먼저 집중하고 변수명과 함수명은 남는 시간에 리팩토링을 해봐야겠다 !!
클린한 코드 만들기
이전에 유데미에서 클린코드 자바스크립트라는 강의를 들은 적이 있다.
전역 공간의 사용을 줄이고 함수 내의 임시변수를 최대한 줄이는 연습을 해야한다고 배웠다.
그래서 이번 문제 풀이에서도 이 점을 적용해보려 노력해보았다.
아래 코드는 1번 문제에서 각 자리 수의 최댓값을 구하는 함수이다.
const getMaxSum = (pageArr) => {
const sumArr = [];
pageArr.forEach((pageNum) =>
sumArr.push(
String(pageNum)
.split("")
.reduce((acc, curr) => acc + Number(curr), 0)
)
);
return Math.max(...sumArr);
};
처음에는 sumArr
이라는 빈 배열을 만들고 왼쪽, 오른쪽 각 페이지 자릿수의 합을 push했다.
문득 sumArr
변수가 꼭 필요할까? 라는 의문이 들었다.
그러던 중 forEach가 아닌 map을 쓰면 새로운 배열로 반환되니까 빈 배열을 생성하고 넣어주는 작업을 굳이 할 필요가 없다는 것을 깨달았다.
아래는 임시변수를 제거하고 forEach 대신에 map 함수를 이용한 코드이다.
const getMaxSum = (pageArr) => {
return Math.max(
...pageArr.map((pageNum) =>
String(pageNum)
.split("")
.reduce((acc, curr) => acc + Number(curr), 0)
)
);
};
바로 반환문에서 최댓값을 구하는 깔끔한 코드로 변했다 !
나름 5번 문제까지는 이런식으로 클린하게 잘 짜고 있다고 생각했는데 …
6번 문제부터는 임시변수를 완벽히 제거하긴 어려워서 어쩔 수 없이 사용해버렸다.
시간 부족으로 더 좋은 코드를 만들지 못한 것에 아쉬움이 남지만 이렇게나마 배운 내용을 활용해볼 수 있었던 것만으로 의미가 있었던 1주차였다.
회고를 마치며 …
나는 우테코 프리코스에 참여하기 3달 전부터 모던 자바스크립트 딥다이브 책을 정독하는 스터디를 해왔다.
불과 3달전까지만 해도 정규표현식, 화살표 함수, 스프레드 문법도 모르는 자바스크립트 문외한었는데 나름 고차함수도 사용하고, es6 이후 생겨난 다양한 문법을 사용할 수 있게 된 것도 사실 신기하다.
그동안의 노력이 성장으로 보여진 것 같아 미션을 진행하면서 너무 뿌듯했다.
2주차부터는 함수별로 테스트를 작성하는데 초점을 두고 공부해볼 것이다.
그리고 1주차에서 공부했던 클린코드와 좋은 커밋도 더 발전시켜보고 싶다.
아직 공부할 거리도 정말 많고 부족한 점이 많지만 그만큼 남들보다 2배 3배 시간을 투자하고 노력해서 프리코스를 후회없이 완주해보자 !
남은 3주도 화이팅 ✊🏻
댓글남기기