녕의 학습 기록

레벨 1 - 장기 회고 본문

대외활동/우아한테크코스 7기

레벨 1 - 장기 회고

kjyyjk 2025. 4. 7. 02:17

드디어(벌써?) 레벨 1의 마지막 미션인 장기를 끝냈다. 마지막 미션이었던만큼 생각할 것도 많고 미션 기간도 길었던 것 같다.
장기 미션은 step1에서 기물 이동 구현을, step2에서 궁성 구현 및 db 적용을 요구로 했다.
 

변경에 유연한 코드

미션을 시작하며 페어인 제프와 가장 먼저 고민했던 것은 여러 종류의 기물을 어떻게 구현할 것인가였다. 우선 각 기물 클래스가 Piece라는 추상 부모 클래스를 상속 받게 하는 방법을 떠올렸다. 그리고 step2에서 궁성에 대한 기능 요구사항이 추가될 것을 대비해서 조합, 더 나아가 전략패턴도 함께 고려해봤다. 논의 끝에 우리는 상속을 사용하기로 했고 이유는 다음과 같았다.
1. 완벽한 is-A관계이다.
2. 궁성에 대한 것은 2단계 기능 요구사항이다.
3. 궁성이 추가된다고 한들 전략 패턴을 사용할만한 상황이 아닌 것 같다.
 
추후 리뷰어인 이프에게 이러한 선택들에 대해 여쭤봤었고, 다음과 같은 인사이트를 얻을 수 있었다.
 
변경에 유연한 코드와 미래를 예측하여 작성한 코드는 다른 것이다. 체스 미션이 하루 아침에 장기로 변했듯이 미래는 변하기 쉽다. 내가 궁성을 미리 고려해서 1단계에 전략 패턴을 사용했다면 어떨까? 만약 2단계 요구사항의 궁성이 사라지게 된다면 이를 고려해 미리 가져간 설계는 오버 엔지니어링이 되어버리는 것이다. 그리고 오히려 변경에 유연하지 못하게 된다. 즉, 미래를 예측하고 그에 걸맞는 설계를 미리 가져가는 것은 지양해야한다. 대신 미래에 어떤 추가 요구사항이 생기더라도 확장하기 쉽게끔 작성하면 좋다. 이것이 곧 변경에 유연한 코드이다.

 

그럼 어떻게 하면 변경에 유연한 코드를 작성할 수 있을까? 이에 대해서는 여러 답이 있을테지만 아직 나만의 답을 찾지 못했다. 굳이 지금 말해보라고 한다면 "static을 지양한다"와 같이 작은 규칙들을 말할 수 있을 것이다. 

 

오버 엔지니어링

추가로 오버 엔지니어링을 나만의 언어로 표현할 수 있게 되었다. 내가 생각하는 오버 엔지니어링은 현재 필요하지 않은 설계 및 구조를 미리 가져가는 것이다. 이러한 오버 엔지니어링을 피하려면 내가 작성하는 코드에 대해 왜?라는 질문을 의식적으로 던지는 것이 중요하다.

물론 저번 블랙잭 미션때 회고했듯이 우테코 내에서는 학습을 위한 오버 엔지니어링을 적절히 섞어갈 필요가 있다. 필요에 따라 오버 엔지니어링을 하며 여러 방법의 장단점을 모두 경험해보고 나만의 기준을 세워나가야한다.

주변으로부터 함께 성장하기

제프와 나는 각 기물이 갈 수 있는 모든 경로를 하드코딩하고 전부 탐색하기로 했다. 분명 비효율적이고 유지보수성이 좋지 않다는 것을 알고 있었다. 하지만 마땅히 떠오르는 방법이 없었기 때문에 그냥 계속 구현했다.
 
그러다가 다른 크루에게서 모든 기물의 움직임을 일반화하여 간단하게 풀어내는 방법을 듣게 되었다. 너무나도 납득 되었고 좋은 방법이라고 생각했다. 하지만 사용하지 않았다. 정답을 훔쳐본 느낌이 들었기 때문이다. 내 머릿속에서 나온 아이디어가 아니기 때문에 내 것이 아니라고 여겼다. 그 당시의 나는 나만의 길을 간다는 자존심을 부렸던 것 같다. 그렇게 끝까지 하드코딩과 모든 경로 탐색을 고집했다. 아니나 다를까 코드가 너무 더러웠고 예외 발생 시 오타가 있는지 하나 하나 찾아야만 했다. 이에 관련해 리뷰어인 이프는 최적화 해볼 것을 요구했다. 하지만 이미 다른 크루에게서 들은 좋은 방법이 머릿속에 남아있는 상태였어서 별다른 최적화 방법이 떠오르지 않았다. 결국 이프에게 왜 이런 방식을 고집하게 되었는지 당시의 속마음을 말씀 드렸다. 그리고 다음과 같은 답변을 받아볼 수 있었다.

 
 
성장의 기회..! 이프의 말이 백번 맞다고 생각했다. 내가 우테코에 들어오고 싶어했던 가장 큰 이유도 다른 사람들과 같이 고민하고 생각을 공유할 수 있는 환경 때문이었다. 하지만 그러한 환경 내에 있으면서 전혀 이용하지 못하고 있었다. 앞으로 꼭 개선해 나가야 할 부분이었기에 마음 속 깊이 새겨두었다. 그리고 다른 크루의 아이디어를 차용해 방향을 계산하고 특정 방향의 경로만 탐색할 수 있게끔 리팩터링 했다. 확실히 코드의 가독성과 효율성 측면에서 개선됨을 확인할 수 있었다. 무엇보다도 우려했던 것과는 다르게 완전 동일한 코드가 나오지 않았다. 남은 우테코 기간 동안에는 다른 크루들에게서도 배우고자 하는 겸손한 자세로 학습하기를 노력해야겠다.
 

피드백

페어인 제프의 피드백

 

제프는 추상 클래스와 상속에 대해서 더 공부해볼 것을 추천했다. 이에 대해 공감하는 것이, 최근 오브젝트를 읽다가 내가 사용하는 상속이 오로지 중복 코드를 줄이기 위한 상속(구현 상속)에 가깝다는 것을 인지했다. 그리고 이는 지양해야하는 방식이라는 것을 학습했다. 단순히 책에 나와서 그대로 받아들인 것은 아니고, 지난 블랙잭 미션에서의 경험을 돌이켜보며 납득한 것이다. 딜러와 플레이어의 중복 코드를 제거하기 위해 상속을 사용했었다. 하지만 추후에 베팅이라는 기능이 추가되며 딜러와 플레이어의 인터페이스가 달라져야만 했고, 결국 상속이 아닌 조합을 사용하게끔 리팩터링했다. 이처럼 중복 코드를 줄이기 위한 무분별 상속은 지양해야한다고 생각한다. 물론 이번 장기 미션에서는 중복 코드 제거만을 위해서 상속을 사용했던 것은 아니었다. 하지만 하위 클래스를 구현하는 과정에서 중복 코드를 제거하는 것에 욕심이 생겼고, 무분별한 템플릿 메서드 패턴과 추상 메서드를 사용했다. 아마 제프는 그러한 부분에 대해 더 고민해볼 것을 집어준 것 같다.

 

그렇다면 이를 어떻게 개선할 수 있을까? 최근 이프가 던져준 질문을 따라 객체지향에 대해 철학적인 고민이 더 이루어져야만 무언가 개선되지 않을까 싶다. 하지만 막연히 `객체지향이란 무엇일까..` 생각한다고 답변이 나오는 것은 아닌 것 같아 어렵다.

 

<아직 받지 못한 이프의 피드백 자리>

 

마치며

좋았던 것
- 우선 하드코딩으로 돌아가는 쓰레기를 구현했다.
- 리뷰어가 제안한 캐싱 사용에 대해 직접 성능을 테스트하여 리뷰어를 설득했다.
 
아쉬웠던 것

- 아직 깊이 있는 학습을 하고 있는 것 같지 않다.
- 타인으로부터 학습할 수 있는 기회를 잘 이용하지 못했다.

 
해보면 좋을 것
- 끊임없이 철학적인 고민하기.
- 타인으로부터 학습하기.