이번 미션을 진행하면서 했던 시도와 고민을 간단하게 정리하려 한다. 최종 테스트까지 끝나고 코딩 테스트부터 느낀점을 정리해볼 생각이다.
이번 미션에서 가장 크게 신경 쓴 것은 모든 변수를 VO로 만들어본 것이다. 예를 들면 투입 금액, 상품명, 가격, 수량, 잔돈 등 평소라면 그냥 String 또는 int로 선언해서 사용했을 변수들을 모두 VO로 만든 것이다. 단순 변수를 사용해도 프로그램을 만들 수 있겠지만 VO를 이용해 프로그램을 만들어보다 보니 프로그램 안에서 좀 더 객체지향적으로 개발이 되는 것 같다고 느꼈다. 예를 들어 돈을 투입하는 경우 기존에는 money += payMoney;
이런 식으로 더했을 것이지만 이번엔 Money형을 만들고 add() 메소드를 이용해 money.add(payMoney);
이런 식으로 값을 더해주는 방식으로 구현했다. 객체에 메시지를 보내라는 피드백에도 맞는 방식인 것 같다.
이런 변수들을 VO로 만들면 그 안에 비즈니스 로직과 검증을 정리할 수 있는 장점도 있다. 단일 책임 원칙에 맞는다는 것 외에도 장점이 있다. 이번 미션으로 예를 들면 보유 금액, 가격, 투입 금액은 모두 "돈"이라는 공통점이 있다. 돈은 숫자여야 하고 음수면 안 되는 특징이 있다. Money 클래스를 만들면 보유 금액, 가격, 투입 금액에서 사용할 수 있다. 하지만 Money 클래스가 없다면 보유 금액, 가격, 투입 금액을 사용하는 모든 곳에서 검증 메소드를 작성하거나 검증용 클래스를 만들어야 한다. 여러 곳에 코드가 분산되기 때문에 관리도 복잡해질 것이고 한 클래스에 여러 메소드를 작성해야 하기 때문에 단일 책임 원칙에도 맞지 않을 수 있다. Money에서 값의 유효성을 검증하고 사용하면 어디서 사용하든 그냥 Money 객체를 만들어 사용하면 된다. 수정할 일이 생겨도 Money 객체 내부에 메소드만 수정하면 되기 때문에 수정도 쉽다.
여러 조건이 겹치더라도 VO를 이용하여 해결할 수 있었다. 이번 미션에서 자판기 보유 금액과 투입 금액은 돈이기 때문에 0원 이상이어야 한다. 따라서 Money에서는 값이 0 이상인지 아닌지 검증한다. 그런데 상품 가격은 100원 이상이어야 한다. 이때 나는 상품 가격을 검증하기 위해 두 가지 방법을 적용해 봤다. Price VO를 만들고 Money를 상속받아 100 이상이어야 한다는 검증을 추가하는 방법과 상품 VO인 Product에서 100원 이상인지 검증하는 방법이다. 나는 결국 Product에서 검증하는 방식을 적용했다. 그 이유는 혹시 나중에 콜라 가격은 100원 이상, 사이다 가격은 200원 이상이어야 한다는 조건이 생기면 Product를 상속받아서 검증 과정을 수정하는 게 더 맞는 방법 같았기 때문이다. (맞는 방식인지는 모르겠다) 이런 식으로 VO에서 검증 코드를 작성할 수 있는 점이 큰 장점 중 하나같았다.
또 객체의 상태를 확인하기도 쉬웠다. 예를 들어 어떤 상품이 매진인지 알고 싶다면 수량이 0인지 확인(quantity == 0
) 할 수도 있지만 VO를 사용한다면 quantity.isSoldOut()
으로 확인할 수 있다. 이번에 VO를 적용하면서 느낀점이지만 +, -, == 등 연산자를 이용해 값을 수정하거나 상태를 확인하는 것보다 객체의 메소드를 이용하는 것이 더 직관적이었다. quantity == 0
은 0인 걸 확인해서 뭘 하겠다는 건지 명확하지 않지만 quantity.isSoldOut()
은 딱 봐도 매진이냐고 묻는것이고 리턴형은 boolean형이겠구나 하고 알게 되기 때문이다. 이름을 통해 의도를 나타내라는 피드백에도 맞는다.
2주차 피드백에서 비즈니스 로직과 UI 로직을 분리하라는 내용이 있었다. 2주차 미션에서 나름대로 MVC 패턴으로 구현했다고 생각했었는데 내가 했던 놓쳤던 부분이 이 부분이었다. 그래서 이번 미션에서는 정말 극단적으로 M,V,C를 나눠서 작업해보려고 노력했다.
View는 입력받을 때(InputView), 출력만을 하는 경우(OutputView)로 나누어 구현했다. 그리고 모든 입/출력은 이 View 단계에서 하도록 했다. Controller는 View에서 받은 데이터를 Model로 이동만 시켜주거나 Model에서 나온 결과를 View로 이동만 시켜주는 것만 하도록 노력했다. Model, Controller, View 사이에 모든 이동은 Dto를 이용했다. View에서 Model로 이동하는 Dto는 Request로 시작하고 Model에서 View로 이동하는 Dto는 Response로 시작하도록 만들었다. Controller에서 바로 Domain의 데이터를 처리할 수 없기 때문에 Controller와 Domain 사이에 Service를 추가했다. Controller는 Service에게 명령만 내리고 Service에서 Domain을 이용해 원하는 데이터를 얻어 Controller에게 Dto로 감싸 보내주었다. Domain에서 모든 변수는 래핑하여 VO로 만들어 사용했다. 그리고 자판기에 투입한 돈, 보유 동전, 등록된 상품 등은 한번 설정되면 계속 값이 유지되어야 하기 때문에 Repository로 만들어 static 변수로 값을 관리했다.
신기한 점은 MVC 패턴을 적용하면서 최대한 각자의 역할만을 하도록 할수록 객체들이 엮이고 섞이지만, 기능의 추가나 수정할 때 오히려 간단했다는 점이다. 가장 큰 이유는 아마 VO를 만들었던 것 같다.
이번 미션은 클래스 분리를 극단적으로 연습하기에 아주 좋았던 것 같다. 우선 보유 금액, 가격, 투입 금액 등 같은 VO를 사용하는 여러 객체들이 있다. 그리고 보유 금액, 투입 금액은 0원 이상, 가격은 100원 이상이라는 다른 조건을 주면서 같은 VO면서도 다른 조건을 처리하기 위해 어떻게 해야 하는지 고민해보게 한다. Product는 Name, Money, Quantity를 멤버로 가진다. 그러면서 자동차 경주 게임 때와 같이 상품을 묶어 일급 컬렉션을 사용해볼 수 있다. 그리고 이런 것들이 서로 연결되어 자판기가 동작하도록 해야 한다. 이러한 과정이 복잡하면서도 신기했다. 이전 미션들부터 느낀 거지만 미션 설계를 얼마나 고민해서 하는지 느껴지는 것 같아서 너무 감사하고 꼭 합격해서 제대로 배워보고 싶다.
피드백과 요구사항에서 기능 목록을 정리하고 시작하라는 내용이 있다. 간단해 보이지만 더 잘해보려고 이것저것 해보다 보니 더 어려웠던 것 같다. 지금 생각해보면 진짜 구현할 기능, 예외 상황만을 정리하면 되는 것이었을 텐데 왜 그렇게 어렵게 생각했나 싶기도 하다. 1, 2, 3주차 기능 목록을 보면 다음과 같다.
1주차 기능 목록 일부
2주차 기능 목록 일부
3주차 기능 목록 일부
1주 차 때는 기능 목록이라기보다는 프로그램의 흐름대로 정리해둔 느낌이다. 2주차로 넘어가면서는 기능을 정리했지만, 구체적인 정리가 아니라 아쉬운 느낌이다. 3주차 미션을 하면서는 꼭 필요한 기능, 예외가 발생할 상황을 적고 정확하게 뭘 하겠다는 건지 정리하는 것에 집중했다. TODO 리스트, 체크리스트 같아진 것 같기도 하다. git 커밋을 기능 단위로 하라는 것이 좀 어려웠었는데 기능 목록을 잘 정리하고 나니 좀 나아진 것 같다. 커밋을 하면서 계속 기능 목록을 수정하면서 작업하다 보니 README의 히스토리가 기능 구현 순서대로 정리가 되는 것 같았다. 2주 차 때는 기능을 간단간단하게 정리한다고 생각했었는데 지금 생각해보면 기능을 간단하게 정리하더라도 정확하게 뭘 하는 것인지 적어야 한다고 생각한다. "자동차의 전진 기능"이 아닌 "무작위 값이 4 이상이면 자동차를 전진하는 기능" 이런 식으로 적는 게 나을 것 같다는 의미이다. 아직도 부족하다고 느껴지지만 더 나아지도록 노력해야 할 것 같다.
나는 같은 미션을 여러 번 구현해보면서 공부했다. 매번 구현하면서 했던 고민이나 어려웠던 것들을 스스로 피드백해보고 다른 사람들의 코드를 보면서 나와 다른 부분을 참고했다. 다른 사람은 왜 이렇게 코드를 작성했을까? 장점이 뭘까? 이런 고민을 하면서 내 코드에 적용을 해봤다. 다른 사람들의 코드를 단순히 베끼는 것이 아닌 왜 이렇게 하는지 고민해보는 것만으로도 좋은 경험이었고 코드를 보는 시야를 더 넓게 만들어준 것 같았다. 이렇게 새로 구현할 때마다 더 성장하는 걸 느꼈다.
프리코스에서 가장 좋았던 점은 단순하게 답을 알려주는 게 아닌 고민거리를 던져주는 것이었다. 어떤 문제를 해결하기 위해 고민할수록 여러가지 시도를 하게 되면서 좋은 경험을 할 수 있어서 좋았다. 그리고 피드백 하나하나가 지키면 코드가 좋아질 수밖에 없는 것 같아서 너무 좋았다.
배운 것들을 잘 복습하면서 최종 테스트까지 잘 마무리해야겠다.
👍