1주 차를 요약하자면 잘해보려고 이것저것 해보다가 말아먹은 상황인 것 같다.
기본기가 바탕이 되고 확장을 해야 한다는 말이 정말 뼈저리게 와닿았다.
다만, 실수를 해보니 많은 것을 깨달았고 이를 반면교사 삼아서 2주 차에선 더욱 노력해보려고 한다.
목표 설정
프리코스 미션을 처음 받았을때 느낀 점은 생각보다 제작해야 하는 기능이 어렵지 않았다는 것이었다. 그래서 주어진 학습 목표에 우선 충실하고자 하였다. 나의 1주 차 목표는 우테코에서 제공하는 가이드에 대해서 잘 인지를 하고, 구조적으로 역할이 잘 분리된 근거 있는 코드를 짜는 것이었다. 그래서 아래와 같이 단계를 세웠다.
- 요구사항 파악하기
- 진행 순서도 및 구현할 기능 목록 작성해보기
- 근거 있는 코드 작성하기
- 리뷰 및 회고하기
요구사항 파악하기
그냥 미션만 잘 수행하면 되는 거 아니야?라고 생각했지만 큰 오산이었다.
우테코에서는 3가지의 요구사항(과제 진행, 기능, 프로그래밍)이 주어졌는데 읽다 보니 잘 모르는 부분이 많아서 우선 이를 잘 이해하는 것부터 시작하였다.
그래서 미션 초반엔 코드를 작성하기보다 Git Commit Convention 이나 JS 스타일 가이드를 읽어 보면서 정리하고 IDE를 세팅하는 것부터 시작했던 것 같다.
1주 차 미션이 끝난 지금 돌이켜보면 요구 사항을 잘 지키지 못한 부분이 가장 아쉬웠다.
요구사항 중에 빈 문자열에 대해서는 0을 반환한다라는 조건이 있었는데, 이를 반영하지 못했다.. 또, 분명 webstorm에서 airbnb style guide를 auto로 반영되게끔 세팅해 두었는데 막상 repo에 올라간 코드에는 변환되지 않았다.. 너무 허무했다.
나름 요구사항에 대해서 정리도 했었는데, 미션을 잘해야 한다는 생각에 아키텍처나 특이한 예외케이스에 대해서만 몰두해있다 보니 오히려 기본적인 것들을 놓친 것 같다는 생각이 들었다.
2주 차 미션부터는 요구사항을 정확하게 준수하고 설계를 조금 더 꼼꼼히 해야겠다는 생각이 들었다.
진행 순서도 및 구현할 기능 목록 작성해 보기
우테코 과제 진행 요구 사항에 구현할 기능 목록을 정리하고 Git 커밋 단위를 정리한 기능 목록 단위로 추가하라는 말이 있었다.
그런데 구현할 기능 목록을 바로 짜려니까 내가 뭘 구현해야 하는지도 모르는 상황에서 바로 하려니까 쉽지 않았다. 그래서 우선 프로그램 진행 순서도를 작성해 보았고 이를 기반으로 구현할 기능 목록을 작성하였다.
진행 순서도를 작성해 보니까 확실히 내가 구현해야 할 기능들의 묶음이 보이는 것 같았고 이를 기반으로 기능 목록을 작성해 보았다.
기능 목록이 나오니 보다 내가 어떤 코드를 짜야할지 명확해진 것 같다.
근데 나는 기능목록이 한 번 작성하면 그 순서대로 commit 해야 되는 건 줄 알았는데.. 리뷰하면서 보니까 또 그건 아닌 것 같아 조금 헷갈리는 부분이었다.
근거 있는 코드 작성하기
1. 미션에 적합한 아키텍처는 무엇일까?
기능 목록에 나와 있듯이 나는 MVC 패턴을 사용해 미션을 수행했다.
사실 구현할 목록을 작성하기 전에 연습으로 코드를 짜 봤는데 App 클래스 안에 매서드가 다 들어가 있어도 코드는 잘 작동했다.
하지만, App 클래스 안에 문자열 입력과 출력, 문자열 검증과 추출 등 많은 기능이 들어가 있을 뿐만 아니라 여러 문제들이 보였다.
- SRP(Single Responsibility Principle) 위반
- 유지보수성 저하
- 재사용성 및 확장성 저하
이러한 부분들에 대해서 MVC 구조를 사용했을 때, 효과적으로 역할을 잘 분리하고 유지보수성 및 확장성을 높일 수 있을 것이라 판단하여 사용했다.
다만 해당 미션을 수행하는데 MVC 구조가 꼭 필요한가?라고 물어보면 그건 또 아닌 것 같다. MVC를 사용하지 않고도 기능별로 클래스를 잘 구별한다면 SOLID 원칙에 따라 잘 나눌 수 있을 것이라고 생각한다.
나는 이번 미션의 구조를 아래와 같은 기준으로 나눠 작성하였다.
- App - MVC 인스턴스 생성 및 Controller 실행
- Model - 비즈니스 로직 수행
- ViewIn - 입력 수행
- ViewOut - 출력 수행
- Controller - 뷰와 모델 중재자 & 흐름관리
- utils(Validator, Parser) - 비즈니스 로직 외 로직에 대한 역할 분리
아래 이미지는 커뮤니티에 "토론하기"에 좋은 댓글이 있어서 가져온 것이다.
2. 왜 MVC를 지역변수로 받아 의존성 주입을 하였는가?
나는 App 클래스를 다음과 같이 작성했다.
import Model from './Model.js';
import ViewIn from './ViewIn.js';
import ViewOut from './ViewOut.js';
import Controller from './Controller.js';
class App {
async run() {
const model = new Model();
const viewIn = new ViewIn();
const viewOut = new ViewOut();
const controller = new Controller();
await controller.control(model, viewIn, viewOut);
}
}
export default App;
MVC에 대한 부분을 지역변수로 받아 Controller에 의존성 주입을 하였는데 이렇게 했을 때 다음과 같은 장점이 있다고 생각했다.
- 유지보수성 증가 (클래스가 바뀌어도 주입되는 클래스만 바꿔주면 됨.)
- 단위 테스트 간편화 (Class를 모의(Mock) 객체로 대체 가능)
- 클래스 간 결합도 감소
- 가독성 증가
3. 매서드 앞에 static을 붙인 이유는?
나는 utils에 있는 Parser와 Validation 클래스들에 관해서는 내부 매서드에 static을 붙여주었는데, MVC에 해당하는 클래스에는 붙여주지 않았다.
왜냐면 Parser와 Validation 클래스는 인스턴스를 생성할 필요가 없었고 도구로써 사용하면 되었기 때문에 붙여주었다.
4. 문자열 추출을 가독성 있게 하려면?
처음엔 커스텀 구분자를 추출하는 메서드를 다음과 같이 작성했었다.
static customDelimiter(input) {
const trimmedInput = input.trim(); // 공백 제거
const regex = /\/\/(.)\n(.*)/;
const match = trimmedInput.match(regex);
if (match) {
const customDelimiter = match[1];
const numbers = match[2].split(customDelimiter);
return numbers.reduce((sum, token) => sum + parseInt(token, 10), 0);
}
return 0;
}
다음과 같이 코드를 작성했을 때 정규표현식이 그다지 가독성 있는 방식이라는 생각이 들지 않았다.
또한 match로 구별하는 과정과 이후 index 형태로 값을 가져와 쓰는 부분이 차후 잠재적인 에러를 일으킬 가능성이 있다는 생각이 들었다.
그래서 다음과 같이 코드를 수정하였다.
static customDelimiter(input) {
Validator.validateIsSplit(input);
const [delimiterStr, numbersStr] = input.split('\\n');
const customDelimiter = delimiterStr.slice(2);
const numbersArray = numbersStr.split(customDelimiter);
Validator.validateNegative(numbersArray);
return numbersArray;
}
Validator를 둠으로써 어떤 요소에 대한 validation을 진행하는지 한눈에 알 수 있어, 내부적으로 어떻게 동작하는지 알 필요 없이 가져다 쓰기만 하면 되어서 캡슐화되었다.
그리고 input.split('\\n') 같은 부분도 \n을 기준으로 나눌 것이라는 의도가 명확해 보여 더욱 가독성이 높아진 것 같다.
5. 어디까지 예외 처리를 해야 하는가?
이 부분은 앞서 말했듯이 잘 못 챙긴 부분이다. 여러 케이스들을 생각하다가 오히려 기본 요구사항을 지키지 못했고 추가적으로 생각한 예외상황들도 리뷰하면서 보니 다른 분들에 비해 그리 특출 나지 않았다.
내가 세운 기준은 다음과 같다.
기능 구현이 쉬웠던 만큼 예외 처리를 하는 부분이 그 범위를 어떻게 선정하느냐에 따라 실력이 많이 드러났던 것 같다.
2주 차 때는 기본 요구사항을 우선적으로 처리하고 다른 예외상황을 잘 고려할 수 있도록 해봐야겠다.
리뷰 및 회고하기
리뷰를 하면서도 많은 것을 배운 것 같다.
코드를 잘 짜려면 다른 사람의 코드를 볼 줄 알아야 한다고 하셨던 현재 회사의 개발 팀장님의 말이 떠오르기도 하였다.
사실 내가 받은 리뷰는 문제라기보다 실수적인 부분에서 지적을 받았다.
그래서 크게 깨우쳐지는 리뷰는 못 받았는데, 한 5명 정도 코드 리뷰를 해 드리면서 배울 점들이 조금씩 있었다.
에러메시지 같은 부분들을 상수로 빼서 관리하거나 에러 처리하는 로직, 어떤 패턴을 사용했는지, 커밋 방식은 어떻게 하셨는지 등등 나도 해드리면서 배우고 또 내가 알려드릴 수 있는 것들은 최대한 알려 드린 것 같다.
1주 차 미션이 마무리되었다.
아쉬움도 많지만 또 하면서 많은 것들을 배우는 것 같다.
다만 문제는 회사를 다니다 보니 퇴근하고 이걸 하는 게 정말 쉽지 않은 일이긴 하다..
지금도 퇴근하고 회고록 쓰고 있는데 어느덧 2시가 다 되어간다..ㅋㅋㅋ
하루에 내 시간이 4시간 밖에 없는데 이 시간을 다 우테코를 위해서 쓰고 있는 것 같다.
그렇지만 너무 재미있다. 커뮤니티로 토론을 하면서 평소 이런 질문했으면 개발 싑덕으로 오해받을 수 있는 주제인데도 다들 진지하게 답해주시는 것 보면 다들 개발에 진심이신 것 같다.
여튼! 이번 2주 차는 1주 차 때의 실수를 반복하지 않도록 열심히 잘해봐야겠다.
우테코 프리코스 1주 차 과제 링크
'Programming' 카테고리의 다른 글
[우테코 프리코스/7기] 프리코스 3주 차 회고 (4) | 2024.11.07 |
---|---|
[우테코 프리코스/7기] 프리코스 2주 차 회고 (1) | 2024.11.02 |
[우테코 프리코스/7기] 커밋 방식 알아보기 (4) | 2024.10.16 |
[우테코 프리코스/7기] 본격적인 시작 전 준비 (0) | 2024.10.15 |
"NET::ERR_CERT_DATE_INVALID" 에러 & SSL 인증서 재발급 (0) | 2024.09.13 |