[Spring_4기 본캠프] 키오스크 과제&트러블 슈팅 | Day 27
1. 객체 지향 키오스크 프로그램을 설계해보자
키오스크 과제가 발제되고 처음 작성된 코드는 철저한 절차 지향의 프로그램이었다. 단순히 프로그램의 작동 순서대로 조건문과 반복문이 떡칠된 가독성이 매우 떨어지는 하드 코딩을 하고나서 깨달은 점을 바탕으로 설계를 새롭게 해 코드를 작성해봤다.
우선 가장 먼제 과제의 요구사항을 살펴봤다.
<키오스크 프로그램 필수 가이드>
- 객체 지향 개념을 학습하고, 데이터를 구조적으로 관리하며 프로그램을 설계하는 방법을 익힌다.
- 메뉴를 MenuItem 클래스와 List를 통해 관리한다.
- main 함수에서 MenuItem 클래스를 활용하여 햄버거 메뉴를 출력한다.
- Kiosk 클래스를 생성해 전체 로직 제어를 관리한다.
- 키오스크 프로그램을 시작하는 메서드가 구현되어야 한다.
- Menu 클래스를 생성해 MenuItem클래스를 관리한다. (각 카테고리 내에 여러 MenuItem을 포함)
- Menu 클래스가 여러 버거들을 포함하는 상위 개념 '버거' 같은 카테고리 이름 필드를 갖게한다.
- MenuItem, Menu, Kiosk 등의 클래스의 필드에 직접 접근하지 못하도록 설정한다.
- Getter와 Setter 메서드를 사용해 데이터를 관리한다.
원래는 lv1 부터 차근차근 작성해서 리팩토링을 거쳐 lv5까지 넘어가는 순서인데, 내가 구현한 lv1 프로그램은 리팩토링을 할 수 없는 지경이라, 처음부터 요구사항을 보고 필요할 것 같은 클래스를 미리 나누어놓고 코드를 작성하기 시작했다.
클래스는 각각 담당하게 되는 기능에 따라 총 5개로 구분했다.
- MenuItems : 개별 메뉴 세부 항목(음식 이름, 가격, 설명)을 관리하는 클래스
- MenuCategory : 메뉴 카테고리(버거, 사이드, 음료)를 관리하며, 각 카테고리마다 세부 메뉴 리스트를 포함한다.
- Order : 사용자가 주문한 메뉴 항목 리스트를 관리한다. 주문 추가, 취소, 내역 조회 등의 기능을 제공한다.
- Kiosk : 키오스크 프로그램의 중심 클래스로 사용자 입력에 따라 메뉴 출력, 주문 추가, 주문 취소 등의 기능을 관리한다.
- KioskApp : 프로그램의 시작점으로 Kiosk 객체를 생성해 프로그램을 실행한다.
외부에서 보게 되는 KioskApp 클래스는 최대한 간단하게 작성해 메서드를 통해 실행되게 하고 실질적인 로직은 Kiosk 클래스에서 관리되게 했다. 또한 처음부터 구현하고자 했던 상위에서 하위로 옮겨가는 메뉴 선택을 위해 MenuItems와 MenuCategory 두 개의 클래스로 나누어 메뉴들을 관리했다. 주문 추가, 취소, 내역 조회등은 따로 Order 클래스에서 관리하게 해 Kiosk에게 너무 막중한 의존관계가 생기지 않게 했다.
또한 클래스 별로 코드를 나누어 작성하면서 튜터님이 일전에 알려주신 JavaDoc 을 활용해 주석을 남겼는데, 내가 아닌 다른 사람이 내 코드를 볼 때 도움이 되라고 이용하는 것이겠지만 내가 보기에도 너무 편해서 정말 잘 활용했다.
특히 이름이 비슷한 변수를 여러 개를 만들어야 하는 상황에 @param으로 변수와 인자값을 설명해주니 헷갈리지 않고 좋았다.
2. 피할 수 없는 트러블슈팅
아직 1차적으로 작성한 거라 완벽하지 않지만 나름대로 만족스러운 코드가 작성되었다.
테스트로 실행을 해보면서 발견된 몇 가지 문제점과 이에 대한 문제 파악, 해결, 그리고 결과에 대해 말하고자 한다.
문제 상황 1) 메서드 사용 불가
- Kiosk 클래스에서 getPrice메서드를 사용할 수 없는 에러가 발생했다. getName() 메서드는 괜찮은데, 가격을 가져오는 부분 어딘가에 문제가 있는 듯했다.
- getPrice 메서드를 생성했던 MenuItems 클래스로 가보았다.
- 코드를 작성하다보면 정말 흔하게 나타나는 오타로 인한 에러.. getPrce로 i가 빠져있었다. 수정 후에 정상적으로 메서드가 기능하는 것을 확인할 수 있었다. 자동완성 기능이 지원되는데도 철자를 직접 타이핑 하곤 하는데 과한 자신감이었나보다. 작성을 마친 후에 오타가 난 부분이 있는지 더 확인을 잘 해야겠다고 생각했고, 자동완성 기능도 어느 부분 잘 활용해야겠다는 생각이 들었다.
문제 상황 2) 메뉴의 설명이 출력되지 않음
- 분명 getInformation() 메서드에 오타도 없고, 생성도 잘 되었는데도 메뉴 설명이 나오지 않는 문제가 있었다.
- 메뉴를 출력하는 부분에 items.getInformation이 빠져있었다. getName(), getPrice()까지만 작성하고 설명을 가져오는 메서드를 빼먹은 것이다. items.getInformation 메서드를 출력 부분에 추가해주고 정상적으로 결과가 출력되는 것을 확인했다.
문제 상황 3) 주문 내역 출력 시 Missing Format Argument Exception 에러 발생
- 코드를 수정하고 실행을 했더니 처음 보는 에러가 났다. 출력 부분에 작성한 서식 지정에 문제가 있을 것이라는 예감이 들었다.
- 자세히 보면 컴마 ( , ) 가 있어야 할 자리에 + 기호가 들어가있다. 원래 항상 간단하게 복사 붙여넣기를 해서 결과를 출력하다가 영빈님이 서식 지정자라는 개념을 알려주셔서 처음 써봤는데 에러가 나서 굉장히 당황했다. 생긴 것부터 너무 복잡하게 생겨서 문제가 어디인지 찾을 수 없을 줄 알았는데 다행히 기호의 오타여서 문제점을 금방 찾을 수 있었다.
- 지정한 대로 메뉴 이름,가격은 소수점 둘째 자리까지, 음식에 대한 설명 역시 잘 출력되는 것을 확인할 수 있었다.
<문제점>
- getPrice() 메서드 사용 불가
- 메뉴의 설명이 출력되지 않음
- 주문 내역 출력 시 Missing Format Argument Exceotion 에러 발생
<해결 방안>
- getPrice() 메서드가 생성되었던 MenuItems 클래스에서 getPrce로 오타가 있는 것을 확인, 수정 후 정상 작동
- 정보를 가져오는 items.getInformation() 메서드가 작성되지 않아있는 것을 확인, 메서드 추가 후 정상 작동
- printf 사용 시 사용자 지정 부분에 기호 , 가 아닌 +로 작성되어 있는 것을 확인, 수정 후 정상 작동
3. 클래스 의존관계와 SOLID 원칙
코드를 1차적으로 모두 작성하고 나서 세민님이 내가 작성한 코드들의 의존관계성을 보여주는 다이어그램을 확인할 수 있는 방법을 알려주셨다. 인텔리제이에서 기본적으로 제공하는 기능인데, 확인하고 싶은 패키지를 우클릭하면 맨 하단에 show Diagram클릭, 툴 바에 있는 링크 버튼을 클릭하면 위 그림처럼 클래스끼리의 의존 관계를 볼 수 있다.
처음 보는 다이어그램이라 어떻게 연결되어있는 지 확실하게 알 수 없었다. 자세한 개선점을 찾기 위해 챗GPT에게 객체 지향 설계의 다섯 가지 주요 원칙인 SOLID 원칙에 기반하여 해당 다이어그램을 평가하도록 해봤다.
평가된 내용 :
<강점>
- 클래스의 역할 분리가 비교적 명확하여 단일 책임 원칙(SRP)이 대부분 준수됨
- 새로운 메뉴나 카테고리를 추가할 때 기존 코드를 수정하지 않아도 되는 개방-폐쇄원칙(OCP)을 잘 따르고 있음
<개선점>
- Kiosk 클래스의 책임 분리 : 입력 처리, 출력 처리, 주문 관리를 별도의 클래스로 나눌 필요가 있음
- 인터페이스 도입 : Kiosk와 다른 클래스 간 결합도를 낮추기 위해 인터페이스와 의존성 주입(DI) 활용
- 확장성을 위해 전략 패턴 등 디자인 패턴 적용 검토
나름대로 설계할 때 기능 별로 클래스를 나누었다고 생각했는데 의존성 관계를 다이어그램으로 확인하고 나니 Kiosk가 많은 책임을 갖고있다는 것을 알았다. 리팩토링을 통해 입력, 출력, 주문 관리를 클래스로 따로 빼 Kiosk의 책임을 덜어보는 방식으로 코드 수정이 이루어지면 될 듯하다.
4. 정리
<총 개선점>
- Kiosk 클래스 책임 분리
- 클래스 간 결합도 축소를 위해 인터페이스와 의존성 주입 활용
- 확장성을 고려해 디자인 패턴 적용 검토
- 캡슐화를 위한 접근제어자 수정
- 주문 내역 확인 시 총 가격 출력 기능 추가
- 세부 메뉴 출력시 버거/사이드/음료 를 따로 분리해서 고를 수 있게 사용자 편의성 향상시키기
- 예외 처리 추가하기
Opinion
SOLID 원칙에 의거한 평가와 내가 생각한 개선점을 더해 2차 수정 때 더 좋은 프로그램이 나올 수 있게 노력해야겠다!
또 코드가 많아지다보니 변수명을 직관적으로 짓기 힘들 때가 많은데, 나만의 규칙을 정해서 통합적으로 사용할 수 있는 변수명을 미리 정해놓는 것도 좋을 것 같다!