우아한테크코스

"프리코스 3주 차 회고" 지식 공유와 성장의 발자취

kanado 2024. 11. 4. 22:22

📝 오늘의 Todo 리스트 체크 

  • 오류 해결 ✅
  • 3주 차 미션 회고 작성  
  • 마지막 검토 및 제출  


목차

  • 테코톡을 경험하기
  • 경험으로 배운 테스트 코드의 가장 큰 장점
  • README.md를 더 상세하게
  • 메서드가 한 가지 기능을 하는지 확인하는 나만의 기준
  • 의존성 주입을 통해 높은 결합도 해결
  • 마무리 및 앞으로의 Plan

[ 일주일을 돌아보기 ]

[우아한테크코스] - JUnit5와 AssertJ를 활용한 단위 테스트(Unit Test), TDD를 곁들인

[우아한테크코스] - "프리코스 16일차" 2주 차 미션 피드백 숙지, 3주 차 미션 설계, 일주일 plan 설정

[우아한테크코스] - "프리코스 17일차" 설계 방식에 대해 고민해보기, 3주 차 미션 MVC 구조 설계 완료

[우아한테크코스] - "프리코스 18일차" 클래스 간에 강한 결합의 해결책: 팩토리 클래스

[우아한테크코스] - "프리코스 19일차" 코드에 팩토리 클래스와 다양한 Exception의 유형 적용

[우아한테크코스] - "프리코스 20일 차" 메서드 분리, 클래스 다이어그램, 예기치 못한 오류...

 


 

저는 3주 차 회고를 거의 밤을 새고 작성하고 있습니다. 그 이유는...

우테코 사이트에서 예제 테스트 실행 과정에서 “예기치 못한 오류” 경고 메시지가 떴습니다. 처음에는 당황하지 않고 패키지명, 파일 위치, 파일 이름 등을 점검하고 빌드와 PR 링크를 재시도 등과 같은 작업들을 여러번 했지만 문제가 해결되지 않았습니다.

 

마지막에 혹시 push 과정에서 문제가 있었나 싶어 GitHub에서 브랜치를 다시 클론해보니, 다행히 그때 OutputView 클래스의 이름이 로컬에서는 올바르게 반영됐지만 GitHub에서는 잘못 적용된 것을 확인했습니다. 구현 과정에서 클래스명을 중간에 변경했는데, 로컬에서만 반영되고 GitHub에는 제대로 적용되지 않은 것이 원인이었습니다.

 

이번 경험을 통해 중간에 파일명을 수정하지 않기로 결심했으며 이름을 잘못 입력했을 때는 파일을 삭제하고, 새로 만드는 것이 더 안전하다는 교훈을 얻었습니다.

 

[ 테코톡을 경험하기 ]

이번 주차 미션이 시작되자, "JUnit5와 AssertJ를 활용한 단위 테스트(Unit Test), TDD를 곁들인"이라는 블로그 글을 작성해 프리코스 커뮤니티에 공유하며 테코톡을 경험했습니다. 테코톡이라는 학습 방식을 경험하면서 가장 좋았던 것은 혼자 학습할 때보다 '이 내용이 정말 맞는 걸까?'에 대해 더 많은 신경을 썼던 것이였습니다. 이를 통해 저도 더욱 정확하고 깊이 있는 학습을 할 수 있었던 것 같습니다.

 

이 블로그를 통해 저처럼 테스트 도구를 처음 접하는 분들을 위해, 제가 이번에 공부하면서 궁금했던 점이나 헷갈렸던 부분을 최대한 쉽게 풀어 설명하려고 노력했습니다. 또한 이해를 돕기 위해 2주 차 미션에 적용한 테스트 코드 예시도 포함했습니다. 마지막으로, 프리코스 미션에 TDD를 적용하는 것이 과연 좋을까?에 대한 제 생각도 함께 담았습니다.  테스트 도구라는 새로운 개념에 다가가기가 어려웠던 분들에게 조금이나마 도움이 되었으면 좋겠습니다.

 

[ 경험으로 배운 테스트 코드의 가장 큰 장점 ]

단위 테스트의 여러 장점 중 제가 가장 공감하는 것은 ‘학습 도구’로서의 가치입니다. 테스트 코드는 코드의 예상 동작과 실제 동작을 비교하여 즉각적인 피드백을 제공하는 도구로 널리 알려져 있습니다. 하지만 제가 느낀 또 하나의 중요한 장점은 테스트를 통해 애플리케이션의 요구사항을 다시 점검할 기회를 제공한다는 점입니다.

 

지난주와 이번 주 프리코스 미션을 구현하면서 단위 테스트 작성과 실행 과정에서 테스트하려는 기능의 세부사항과 요구사항을 더욱 깊이 고민하게 되었고, 설계 과정에서 놓친 예외 사항들도 여러 번 발견할 수 있었습니다. 이 경험을 통해 테스트 코드가 단순히 기능을 검증하는 도구를 넘어, 애플리케이션의 정확성과 완성도를 높이는 중요한 역할을 한다는 것을 깨달았습니다.

 

[ README.md를 더 상세하게 ]

2주 차 미션 피드백 중 첫 번째는 "README.md를 상세히 작성하라"는 내용이었습니다. 이 피드백을 보고, 제 리드미가 애플리케이션을 충분히 잘 소개하고 있는지 고민하게 되었습니다.

 

스스로 질문하며 1, 2주차 미션의 리드미를 다시 읽어보았습니다. 기능 목록, 예외 처리, 유스케이스 시나리오, MVC 패턴 설계, 클래스 다이어그램, 확장성 고려 사항 등을 상세히 작성해 두었기에, 각 기능의 구현 방식과 설계 의도가 충분히 전달되었을 거라고 생각했습니다. 실제로 제 코드를 리뷰해주신 분들도 리드미에 대해 별다른 피드백 없이 오히려 칭찬을 주었습니다.

 

그런데 문득, 나와 리뷰 해주신 분들의 공통점이 떠올랐습니다. 우리는 모두 프리코스를 수행하고 있었고, 매일 매일 각 미션에 대해 고민해 온 사람들이었습니다. 그런 만큼 애플리케이션 설명이 다소 부족하더라도 우리는 프로젝트의 맥락을 이미 잘 알고 있었기 때문에 쉽게 이해했을 수 있지 않을까? 라는 생각이 들었습니다. 이 점을 확인하기 위해 프리코스에 참여하지 않은 친구에게 리드미를 보여주고 애플리케이션이 어떤 것인지 이해가 되는지 물어보았습니다. 친구는 기능 설명과 코드 구조는 이해했지만 애플리케이션의 목적이나 사용자 조작 범위가 잘 와닿지 않았다고 했습니다. 특히, 왜 하필 이 기능들로 선택했는지가 제일 궁금해했다는 피드백을 받았습니다.

 

이 피드백을 통해, 애플리케이션의 핵심 기능과 구조를 설명하는 것뿐 아니라, 해결하려는 문제와 사용자가 어떻게 사용할 수 있는지, 특정 기능의 설계 이유도 리드미에 포함되어야 한다는 점을 깨달았습니다. 그래서 이번 주차 미션에서는 리드미의 첫 부분에 애플리케이션의 간단한 소개와 추가 설명을 추가해보았습니다. 그 결과, 처음부터 애플리케이션의 전체 그림과 목적, 사용 범위를 이해할 수 있어, 이후의 기능 목록과 상세 설명이 훨씬 더 명확하고 빠르게 이해된다는 느낌을 받았습니다.

 

 

[ 메서드가 한 가지 기능을 하는지 확인하는 나만의 기준 ]

지난 2주 동안 2개의 미션 애플리케이션을 설계하고 구현하면서, 다음과 같은 원칙을 지키려 노력했습니다.

1. TDA(Tell, Don’t Ask) 원칙 준수

2. 단일 책임 원칙(SRP) 준수

3. 클래스, 메소드, 변수 이름을 축약하지 않기

4.각 메소드를 "뭐뭐 하기"로 설명 가능하게 설계하기 (예: "자동차 위치 확인하기")

 

이 중 네 번째 규칙은 저만의 기준으로, 메소드 설명이 "뭐뭐 하기" 형태로 이루어지도록 했습니다. 이렇게 하면 메소드의 목적이 명확해지고, 한 메소드가 여러 가지 일을 하지 않도록 유도할 수 있다고 생각했습니다.

 

그러나 MVC 구조를 설계한 후 실제 구현에 들어가면서 단일 책임 원칙을 위반하는 클래스나 메소드들이 반복해서 나타났습니다. 이에 "내가 객체를 올바르게 바라보고 있는 걸까?" 또는 "한 가지 일을 하는 메소드를 확인하는 나만의 기준이 잘못된 건 아닐까?" 라는 생각이 들었습니다.

 

객체를 분리하는 기준이 불명확하다 보니, 한 클래스에 여러 역할이 몰리곤 했습니다. 이를 개선하기 위해 다시 '객체지향의 사실과 오해' 책을 펼쳤습니다. 이 책에서는 객체 설계를 할 때 객체의 상태를 먼저 결정하고 그에 필요한 행동을 추가하는 방식이 잘못되었다고 지적했습니다. 저 역시 상태를 기준으로 객체를 나누었음을 깨달았고, 이는 객체를 바라보는 저의 잘못된 개념의 근원이였던 것 같습니다. 상태 기준으로 객체를 나누게 되면 캡슐화 문제, 다른 객체들과 협력에 불적절함, 객체의 재사용성 저하 등과 같은 여러 문제점들이 발생할 수 있음을 알게 되었습니다. 그래서 앞으로는 객체가 협력할 수 있도록 행동을 우선 고려하는 방식으로 설계해야겠다고 다짐했습니다.

 

그렇다면, 적절하게 객체를 나누기만 하면 클래스 안에 있는 메소드가 한 가지 일을 하게 될까? 2주 차 코드 리뷰에서 가장 많이 받은 피드백이 메소드 이름에 관한 것이었습니다. 예를 들어 startRacing -> initializeRacing -> Racing.startRacing의 흐름이 이름이 비슷해 역할을 예측하기 어렵다는 지적이 있었고, updateWinnerLocation 메서드는 car 모델 내부에 winnerLocation이라는 필드가 있다는 착각을 불러일으켰습니다. 이 피드백을 통해 메소드 이름만으로도 역할과 의도를 직관적으로 파악할 수 있도록 해야 한다는 점을 깨달았습니다. 그것이 특정 메서드가 한가지 역할만 할 수 있게 도와줄 것이라고 생각했습니다.

 

이번 3주 차부터는 개선된 기준을 다음과 같이 업그레이드해 적용했습니다. 객체는 상태가 아닌 행동을 기준으로 나누고, 각 행동(메소드)의 이름만 봐도 역할과 의도가 명확히 전달되는지 확인하며, 최종적으로 메소드가 "뭐뭐 하기"로 설명될 수 있는지 점검했습니다.

 

[ 의존성 주입을 통해 높은 결합도 해결 ]

2주 차 미션에서 클래스 다이어그램으로 클래스들 간에 관계를 시각화하니까 몇 클래스들이 합성관계를 맵고 있다는 것을 발견했습니다. 합성관계는 한 클래스가 다른 클래스의 객체를 생성하고 참고한다는 것을 의미합니다. 하지만 그것은 높은 결합도를 형성하게 되고, 생명주기가 다른 클래스 중에 한 클래스의 수정이나 삭제가 다른 클래스에 영향을 미치게 되어 유지보수가 어렵게 만들어줍니다.

 

3주 차 미션에서 이러한 합성 관계를 해결하기 위해 팩토리 클래스를 통해 객체 생성 로직을 캡슐화하고 의존성 주입(DI)을 함께 활용했습니다. 팩토리 클래스는 특정 객체가 항상 동일한 인스턴스를 반환하도록 싱글톤 패턴과 함께 사용할 때 매우 효과적입니다. 이 경우 팩토리 클래스가 객체 생성 책임을 가지며 생성된 객체를 재사용하여 불필요한 메모리 사용을 줄일 수 있습니다. 프리코스 미션처럼 상대적으로 단순하고 싱글톤 패턴이 필요한 구조에서는 팩토리 클래스를 활용하는 것이 가장 적합한 방법이라고 판단했습니다.

 

[ 마무리 및 앞으로의 Plan ]

이번 주에 테코톡을 직접 진행하면서 우테코 문화에 더 가까워진 느낌이 들었습니다. 주도적인 학습의 중요성과 그 결과를 공유하는 테코톡 방식의 가치를 직접 체험할 수 있었습니다.

 

이번 주 성장한 부분을 돌아보면, 먼저 객체지향적 사고가 한층 깊어졌습니다. 객체의 상태에 집중하기보다 협력을 위한 행동 중심으로 사고하니 미션 설계가 더욱 수월해졌고, 리팩토링 과정에서 시간을 덜 들인 것 같습니다. 또한, 작은 단위의 테스트 코드가 단순히 동작을 검증하는 것을 넘어 애플리케이션의 정확성과 완성도를 높이는 데 중요한 역할을 한다는 점도 깨달았습니다. 마지막으로 클래스 간 결합도와 의존성 주입에 대해 학습하며 프리코스 미션에 가장 적합한 방식을 찾기 위해 많은 고민과 학습을 했습니다.

 

프리코스 마지막 4주 차 동안 저의 목표는 저만의 철학과 색깔이 담긴 방식으로 미션 코드를 구현하고, 그 방식을 명확하고 논리적으로 설명할 수 있는 수준에 도달하는 것입니다.

끝입니다.