우테코도 어느새 절반 이상을 넘겼다.
이제 곧 다가올 3주차만 하면 프리코스 과제도 끝이라니, 항상 마지막을 바라보는건 묘한 느낌이 들게 한다.
프리코스를 하는 지금, 학기중이다보니 이것저것 바쁜 일들이 참 많은데, 친구와 대화를 하다가 친구가
"근데 너, 힘들다고 하면서 되게 열심히 한다. 재밌어? 예전에 처음 코딩 배울때 모습 보는 것 같아."
라는 이야기를 들었다. 가끔 스스로 깨닫지 못한 것들을 지인들이 알려줄 때면, 서로 대화하는 것의 중요성을 느끼곤 한다. 우테코에서도 서로에게 깨달음을 줄 수 있는 크루가 되고싶다는 목표를 마음속에 하나 추가해보려고 한다.
처음은 항상 설렌다. 대체로 난도가 낮은 문제들을 접하니 내가 잘하는 것 같고, 해낼 수 있을 것 같다고 느낀다.
그런 점에선 사실 프리코스는 항상 즐거운것만은 아니었지만 (문제풀이가 어려울 때도 있었으니...) 친구의 말을 들어보니, 꼭 처음 배웠을 때 처럼 몰입해서 공부하고, 성취를 직접 느꼈던 것 같다. 아마도 배움과 실천이 즉각적으로 이루어져서 그런게 아닐까 싶다. 어쩌면, 우테코에서 바라는 '스스로 성장하는 모습'이라는게 이런 모습은 아닐까? 하는 생각도 가져본다. 그런 의미에서, 참 보람찬 2주차였다.
그럼 서론은 여기까지.
이번주차의 문제는 저번 기수들과 동일한 자동차 경주 게임이었다. (문제 및 코드는 아래에)
문제
내 코드
피드백 정리 및 적용한 내용
1주차를 끝내고 나서 피드백을 받을 수 있었는데, 피드백을 정리하자면 다음과 같다.
- 이름을 통해 의도를 드러내라.
- 축약하지마라.
- 공백도 코딩 컨벤션이다. (ex. if, for, while문 사이의 공백)
- 공백라인을 의미있게 사용하라.
문맥을 분리하는 부분에 사용하는 것이 좋다. - 반복하지마라.
중복은 소프트웨어에서 모든 악의 근원이다. - Space vs Tab 혼용
들여쓰기에 space와 tab을 혼용하지 않는다. - 의미없는 주석을 달지 않는다
최대한 이름을 통해 의도를 드러내고, 의도를 드러내기 힘든 경우 주석을 다는 연습을 한다. - 커밋메시지를 의미있게 작성하라
- 기능목록을 업데이트하라
시작할 때 완벽하게 정리해야한다는 부담보다는 기능을 구현하며 문서를 계속 업데이트 한다.
죽은 문서가 아닌, '살아있는' 문서를 만들기 위해 노력한다. - 기능목록을 재검토해라.
기능목록을 클래스 설계와 구현, 함수(메서드)설계와 구현과 같이 너무 상세히 적지 않는다. 이는 언제든지 변경될 수 있기 때문이다. 너무 세부적인 부분까지 정리하기보단 구현해야 할 기능목록을 정리하는데 집중한다.
정상적인 경우도 중요하지만, 예외사항도 추가하며, 계속해서 추가하며 진행한다. - 리드미를 상세히 작성하라
리드미는 해당 프로젝트가 어떠한 프로젝트인지 마크다운으로 작성해서 소개하는 문서다. 어떤 기능을 담고있는지 기술하기 위해 마크다운 문법을 검색해서 학습 및 적용해본다. - IDE 코드의 자동정렬 기능을 활용해라
- 매직넘버를 사용하지 마라
매직넘버는 의미를 나타낼 수 있는 상수 (static final)로 치환하여 코드의 가독성을 높인다. - 구현순서도 코딩 컨벤션이다.
클래스는 상수, 멤버변수, 생성자, 메서드순으로 작성한다.
이런 피드백을 통해서 앞으로 어떤 방식으로 해야되는지에 대해서 익힐 수 있었다.
특히 개인적으로 기능목록 관련된 피드백을 받을 수 있어서 좋았는데, 기능목록을 정말 세세히 적으신 분들의 코드를 보고 '저렇게 상세히 적어야하나? 내 방식이 맞나?' 라는 의문이 있었기 때문이었다. 우테코에서 제시해준 피드백 덕분에 나름의 방향성을 다시금 세울 수 있어서 뜻깊었던 것 같다.
뭐든 내 기준과 중심을 놓지는 않되, 타인의 것들을 보고 배우며 나만의 정도를 찾아가는 것이 중요하다는 것을 깨닫는 요즘이다.
또한 피드백에 더하여, 클래스와 함수의 적절한 네이밍이나 함수 및 클래스의 분리에 대해서도 많은 생각을 했다.
'개발자는 코드로 말한다' 라는 말이 있듯이, 코드를 통해 내 의도를 깔끔하게 보여주는 것은 개발자로서의 중요한 역량이라고 생각한다. 동시에, 유지보수성이 좋은, 객체지향적인 코드를 만드는 것은 꾸준한 노력이 필요하고, 스스로 계속 공부해야 함을 느꼈다.
1주차를 진행하며, 그리고 이러한 피드백을 받으며 내가 생각한 것은, 한 주차의 과제를 진행하며, 목표를 세우고 그에 맞춰서 공부해보자! 라는 것이었다. 따지자면 우테코에서 제공하는 과제 외의, 내 스스로의 목표라고 할까. 이것을 바탕으로 공부를 하며 개발했다.
목표
- 일급컬렉션 써보기
- MVC 패턴에 맞춰서 구성하기.
- domain (데이터를 담는 클래스.)
- view (입출력. Inputview & output view)
- controller (도메인과 view을 연결함)
- 내가 적어둔 한 기능씩. 천천히. 생각한대로 충분히 개발하기.
- 깃 commit은 목표한 기능의 순서대로 만들며, 충분히 refactor한다.
즉, refactor와 기능구현의 시간을 둘다 충분히 계획한다.
Refactor를 두려워하지도, 부끄러워하지도 않기. 충분한 시간을 가지고 고민하기. - 함수, 클래스, 변수명 생각해서 적어보기
- 클래스 / 함수 적절히 분리하기
공부 및 적용한 내용
1. 일급 컬렉션
일급 컬렉션이란 기존에 Collection을 활용해서 만들었던 아래의 코드를
Map<String, String> map = new HashMap<>();
map.put("1", "A");
map.put("2", "B");
map.put("3", "C");
아래와 같이 Wrapping 하는 것을 얘기한다. 이때, 그 외의 다른 멤버변수가 없다는 것이 특징이다.
public class FistCollectionExample {
private Map<String, String> exmaples;
public FistCollectionExample(Map<String, String> exmaples) {
this.exmaples = exmaples;
}
}
이러한 모습으로 인해 다음과 같은 장점을 갖게 되는데,
1. 비즈니스에 종속적인 자료구조
하나의 인스턴스 내에서 비즈니스 로직을 관리할 수 있다는 의미다.
public class RacingCar {
private final List<Car> racingCars;
public RacingCar(List<Car> racingCars) {
this.racingCars = racingCars;
}
public void moveRacingCars() {
for (Car car : racingCars) {
car.moveCar();
}
}
public Integer getMaxDistance() {
int maxDistance = Integer.MIN_VALUE;
for (Car car : racingCars) {
maxDistance = Math.max(maxDistance, car.getPosition());
}
return maxDistance;
}
}
이건 내가 제출한 코드의 일부인데, List를 만들고 각각의 Car 인스턴스를 추가해서 구현하는 것이 아니라, 일급 컬렉션인 racingCar로 관리하여 따로 관리할 수 있었다.
2. 리스트 내의 객체의 상태를 동일하게 관리할 수 있다.
몇몇 자료들을 보면 일급 컬렉션이 Collection의 불변성을 보장한다! vs 보장하지 않는다! 가 부딪히는 걸 볼 수 있었는데, 몇가지 예시들을 살펴본 결과, 불변성이 확실하게 유지되는 것은 아니라고 느꼈다.
일급 컬렉션이 주는 기능의 핵심은 불면이 아니다. 라는 것에 초점을 맞춰서 보면 좋을 것 같다.
3. 상태와 행위를 한 곳에서 관리
이는 Enum의 장점과 동일한데, 값과 로직이 함께 존재한다는 것이다.
위의 getMaxDistance 함수의 경우 로직과 컬렉션이 함께 있어야한다. 그렇기에 일급 컬렉션 내에서 한번에 처리할 수 있다.
4. 이름이 있는 컬렉션
이름을 추가로 넣음으로써 해당 컬렉션의 이름을 확실히 이해하고, 정리할 수 있다. 이는 비단 개발자뿐만 아니라 개발팀과 운영팀간의 소통 속에서도 효과적으로 사용할 수 있을 것이다.
참고자료
https://jojoldu.tistory.com/412
https://velog.io/@tigger/%EC%9D%BC%EA%B8%89-%EC%BB%AC%EB%A0%89%EC%85%98
2. MVC 패턴
MVC (모델-뷰-컨트롤러) 는 사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴으로, 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다.
이러한 "관심사 분리" 는 더나은 업무의 분리와 향상된 관리를 제공한다. MVC 에 기반을 둔 몇 가지 다른 디자인 패턴으로 MVVM (모델-뷰-뷰모델), MVP (모델-뷰-프리젠터), MVW (모델-뷰-왓에버) 가 있다.
기본적인 MVC 패턴의 세가지 부분은 다음과 같다.
- 모델: 데이터와 비즈니스 로직을 관리.
- 뷰: 레이아웃과 화면을 처리.
- 컨트롤러: 명령을 모델과 뷰 부분으로 라우팅
이런 MVC 패턴을 사용하겠다고 마음먹은 이유는, 내가 class 파일을 정리하고 이를 설명할 때, 1주차의 경우에는
player는 어떤 기능을 가지고 있고요, BaseballProvider는 이런 기능... 그리고 이건 이런기능...
이라고 파일을 설명하는데 있어 정확한 분류가 없다고 생각했기 때문이다. 그래서 명확한 기준과 디자인 패턴을 갖기 위해서
저는 MVC 패턴으로 짰습니다.
이렇게 말할 수 있는 구조를 찾았다.
또한, 나는 개인적으로 클래스의 분리에 있어서도 MVC 패턴이 효과적으로 사용되었다고 생각한다. 각각의 역할에 따라서 클래스를 나누고 진행할 수 있었기 때문이다.
개발하는 과정에 있어서 MVC는 다음과 같이 연결된다.
- 모델: 데이터와 비즈니스 로직을 관리. → 데이터와 관련된 부분 (domain 폴더)
- 뷰: 레이아웃과 화면을 처리. → 사용자에게 보여지는 부분 (view 폴더)
- 컨트롤러: 명령을 모델과 뷰 부분으로 라우팅 → Model과 View를 이어주는 부분 (controller 폴더)
또한 MVC 패턴을 지키기 위해서 지켜야 할 점은 다음과 같다.
1. Model은 Controller와 View에 의존하지 않아야 한다. ONLY 데이터.
Model 내부에 controller와 view에 관련된 코드가 있으면 안된다.
= controller와 view의 클래스를 import 해서 사용하면 안됨.
2. View는 model에만 의존해야 하고, Controller에는 의존하면 안 된다.
view 내부에 model의 코드만 있을 수 있고, controller의 코드가 있으면 안된다.
3. View가 Model로부터 데이터를 받을 때는, 사용자마다 다르게 보여주어야 하는 데이터에 대해서만 받아야 한다.
사용자에게 보여주는 UI중 사용자 데이터 가져와야 되는 부분만 model에서 가져옴.
4. Controller는 Model과 View에 의존해도 된다.
Controller가 model과 view의 중재자 역할을 하며 전체 로직을 구성하기 때문임.
Controller 내부에는 model, view와 관련된 코드가 있을 수 있다.
5.View가 Model로부터 데이터를 받을 때, 반드시 Controller에서 받아야 한다.
참고자료
https://hodol.dev/journal/mvc-pattern/
https://www.youtube.com/watch?v=ogaXW6KPc8I
3. 기능 목록과 깃 커밋
특히 1주차에 깃 커밋을 한 기능씩 (기존에 기능목록에 작성한 기능대로) 하지 못한 것 같다는 생각이 들었다.
따라서 이번의 경우에는 [경주 할 자동차 이름 입력] > [시도 회수 입력] > [시도 회수만큼 회수별 자동차 이동 > 출력] > [우승자 안내] 라는 게임의 흐름에 맞춰서 순서대로 개발을 하고, 커밋을 하는 것을 목표로 했다.
이런 방식으로 feat의 기준점을 잡고, 구현 과정에서 틈틈이 수정하는 것에 따라서 docs 수정을 진행하다보니, '이래서 기능 단위로 커밋을 하라고 한거구나!' 라는 것을 확실히 이해할 수 있었던 시간이었다.
4. 적절한 이름짓기
개발자들이 어렵다고 생각하는 것들중 하나가 바로 '이름 짓기'이다.
어떤 이름을 지어야 '잘 지은 이름'이라고 할 수 있을까? 일단은 코딩 컨벤션을 기반으로 고민을 시작했다.
자료들을 찾아보며, 내가 세운 규칙은 다음과 같다
- 관사(a, an, the)같은 불필요한 내용은 제외한다.
- 이름은 가능한 구체적이어야 한다. 모호하거나 하나 이상의 목적으로 사용될 수 있는 일반적인 이름은 보통 좋지 않은 이름이다.
- 의도가 불분명한 짧은 이름보다는 의미있는 맥락이 있는 긴 이름이 좋다. 맥락을 고려하자.
- 다만, 길기만 하다고 해서 좋은 이름은 아니다.
- List 등의 자료형을 세웠다고 해서 변수명에 붙이지 않는다.
- 검색하기 좋은 이름을 만들어라.
아직은 변수명이나 함수명을 정할때 조금씩 고민하는 과정이 항상 걸리는 것은 사실이다. 비단 나 뿐만 아니라 많은 개발자들 역시 그럴 것이다. 이런 부분에 있어 공부를 더 열심히 하고, 보다 읽기 좋은 코드를 만들어나가기 위해 계속 공부하는 것이 필요할 것 같다.
참고자료
https://devstarsj.github.io/study/2018/12/02/study.cleanCode.02/
5. 클래스 / 함수 분리하기
클래스와 함수의 분리같은 경우는, 기본적으로 MVC 기반으로 클래스를 나누고, 한 기능을 담당하는 함수로 나누기 위해 노력했다.
이번주차의 미션에서는 리팩토링을 거의 4일에 걸쳐 진행한 것 같은데, 그때마다 Application에서 부터 기능의 순서대로 클래스와 함수를 확인해보며
- 이 함수에서의 기능이 정말 하나인가?
- 이 클래스의 책임이 한가지인가? (객체지향 설계 원칙인 SOLID 중 SRP와 관련된 내용이다.)
를 확인하고자 노력했다. 일단 지금의 내가 내릴 수 있는 최선은 이런 형태일 것이라 생각해서 정리는 했지만, 아마 나중에 다시 리팩토링을 하면 또 수정할 점이 보이지 않을까. 앞으로도 객체지향적인 설계에 맞춰 클래스를 분리하고 역할을 나누는 것에 대해서 꾸준히 공부해서 3주차에는 보다 나아진 방식으로 구성하고 싶다는 생각을 했다.
여담
MVC 패턴을 공부할때 참고한 자료가 우연찮게도 모두 우테코 자료였다.
우테코를 준비하고, 또 나아가셨던 선배분들이 준비해주신 자료 덕분에 공부한다는 생각이 드니, 왠지 느낌이 신기하기도 하고, 새롭기도 한 느낌이다. 나도 조금은 크루다워진걸까? 하는 기분. 또한 나도 누군가에게 도움이 되기를 바라는 마음으로 열심히 기록하고 내 발자국을 남겨야겠다는 생각을 했다.
예전에 '개발자로서 내가 고민한 내용은 앞선 누군가가 이미 해본 질문이니, 두려워말고 찾고 질문해라.' 라는 말을 본적이 있는데, 그 것이 내앞에 정말 나타난 것 같은 기분이 들었다.
내가 기록하고 남긴 것들이 또다른, 나와 같은 고민을 하는 사람들에게 도움이 되면 좋을 것 같다.
그런 희망을 남기며 이번주 회고를 마치려고 한다.
'우아한 테크코스 > 회고' 카테고리의 다른 글
[우아한 테크코스 4기] 최종 합격 + 최종 코테 후기 (0) | 2021.12.31 |
---|---|
[우테코 프리코스 회고] 3주간의 프리코스를 마치며 (0) | 2021.12.14 |
[우테코 프리코스 회고] 3주차를 마치며 (0) | 2021.12.13 |
[우테코 프리코스 회고] 1주차를 마치며 (0) | 2021.11.30 |
우아한테크코스 1차심사 합격! (0) | 2021.11.24 |