[내배캠] Swift 심화 팀 과제

nbcamp swift
Written on Jul 21, 2023


본 캠프가 시작되고 3주차가 되었습니다! (2023년 7월 24일 ~ 28일)

이번 주차에서는 팀 프로젝트로서 Swift 심화 내용을 학습하고 간단한 키오스크 CLI 프로그램을 작성했습니다. 저번 개인 프로젝트에서 진행했던대로 터미널 환경에서 Swift 프로젝트를 생성하여 진행했습니다.

팀 과제인만큼 소통에 보다 많은 노력을 쏟았습니다. 매일 오전 회의와 코드 리뷰를 진행하며 자신이 개발했던 내용과 어려움에 대해 공유했고, 페어 프로그래밍을 진행하며 하나의 기능을 함께 개발해보았습니다. 아무래도 부트캠프 과정 자체가 빠르게 진행되고 있기 때문에 프로그래밍을 처음 접한 팀원이 어려움을 많이 느꼈습니다. 정말 스파르타코딩클럽의 스

구현한 키오스크 프로그램은 다음의 기능을 제공합니다.

  1. 메뉴 화면 및 세부 메뉴 화면 표시
  2. 숫자를 입력하여 메뉴 선택 가능
  3. 메뉴를 장바구니에 추가하고 관리
  4. 장바구니에 있는 메뉴를 주문

결과 미리보기

SHAEKSHACK 메뉴 선택 화면

Language:plaintext
[ ⭐️ WELCOME SHAKESHACK ⭐️ ]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Burger                 ┃ 앵거스 비프 통살을 다져만든 버거
2. Flat-Top Degs          ┃ 참나무칩으로 훈연한 소시지가 들어간 핫 도그
3. Frozen Custard         ┃ 매장에서 신선하게 만드는 아이스크림
4. Drink                  ┃ 매장에서 직접 만드는 상큼한 음료
5. Beer                   ┃ 뉴욕 브루클린 브루어리에서 양조한 맥주
6. Order                  ┃ 장바구니를 확인합니다.
7. Exit                   ┃ 프로그램을 종료합니다
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
No. 1

SHAEKSHACK 메뉴 선택 화면
Burger 메뉴 선택 화면

Language:plaintext
[ 🍔 Burger MENU 🥤 ]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Shack Burger           ┃ W 6.9 ┃ 토마토, 양상추, 쉑소스가 토핑된 치즈버거
2. Smoke Burger           ┃ W 8.9 ┃ 베이컨, 체리 페퍼, 쉑소스가 들어간 치즈버거
3. Shroom Burger          ┃ W 9.4 ┃ 치즈로 속을 채운 베지테리안 버거
4. Shack Stack            ┃ W 9.9 ┃ 슈룸 버거, 쉑버거의 맛을 즐길 수 있는 메뉴
5. Cheeseburger           ┃ W 6.9 ┃ 포테이토 번, 비프패티, 치즈를 담은 치즈버거
6. Hamburger              ┃ W 5.4 ┃ 포테이토 번, 비프패티, 신선한 재료를 담은 버거
0. Back                   ┃ 홈 화면으로 돌아갑니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
No. 3

3. Shroom Burger          ┃ W 9.4 ┃ 치즈로 속을 채운 베지테리안 버거
장바구니에 추가할까요? (Y/n):  Y
정상적으로 추가되었습니다.

Burger 메뉴 선택 화면
장바구니 화면

Language:plaintext
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[ ⭐️ WELCOME SHAKESHACK ⭐️ ]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Burger                 ┃ 앵거스 비프 통살을 다져만든 버거
2. Flat-Top Degs          ┃ 참나무칩으로 훈연한 소시지가 들어간 핫 도그
3. Frozen Custard         ┃ 매장에서 신선하게 만드는 아이스크림
4. Drink                  ┃ 매장에서 직접 만드는 상큼한 음료
5. Beer                   ┃ 뉴욕 브루클린 브루어리에서 양조한 맥주
6. Order                  ┃ 장바구니를 확인합니다.
0. Exit                   ┃ 프로그램을 종료합니다
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
No. 6

장바구니 화면
주문 화면

Language:plaintext
[ 🍕 Order List 💳 ]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Buy                    ┃ 장바구니에 담은 제품을 구매합니다.
2. Clear                  ┃ 장바구니를 비웁니다.
0. Back                   ┃ 홈 화면으로 돌아갑니다.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
품목 목록
Shroom Burger x 1

🧾 Total Order Price: 9,400 WON
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
No. 1

결제가 정상적으로 처리되었습니다. 감사합니다.

주문 화면

프로젝트 구조

Language:plaintext
.
├── Options/
│  └── Option.swift
├── Services/
│  ├── CoreService.swift
│  ├── OrderService.swift
│  ├── Receipt.swift
│  └── WaitService.swift
├── Viewers/
│  ├── ConsoleViewer.swift
│  └── Viewer.swift
├── App.swift
└── main.swift

프로젝트 구현

이번 프로젝트에선 enum 형식의 Associated Value를 적극적으로 활용하여 메뉴 화면에 표시될 옵션을 구현했습니다.

Language:swift
enum Option: Equatable, Hashable {
    struct Attr {
        let id: Int
        let name: String
        let desc: String
    }

    case category(attr: Attr, menus: [Option])
    case menu(attr: Attr, price: Int)

    case order(attr: Attr, actions: [Option])
    case action(attr: Attr)
}

Option enum은 재귀적으로 작성되어 메뉴를 선택하면 하위 메뉴가 표시되는 구조입니다. main.swift 파일에서 세부적인 모든 옵션을 추가하고 App 클래스에 서비스를 등록합니다.

Language:swift
import Foundation

let viewer = ConsoleViewer()

let app = App(core: CoreService(
    viewer: viewer,
    orderService: OrderService(),
    waitService: WaitService(
        viewer: viewer,
        queue: DispatchQueue(
            label: "waiting",
            attributes: .concurrent)))
)

app.register(option: .category(
    attr: Option.Attr(id: 1, name: "Burger", desc: "앵거스 비프 통살을 다져만든 버거"),
    menus: [
        .menu(attr: Option.Attr(id: 1, name: "Shack Burger", desc: "토마토, 양상추, 쉑소스가 토핑된 치즈버거"), price: 6900),
        .menu(attr: Option.Attr(id: 2, name: "Smoke Burger", desc: "베이컨, 체리 페퍼, 쉑소스가 들어간 치즈버거"), price: 8900),
        .menu(attr: Option.Attr(id: 3, name: "Shroom Burger", desc: "치즈로 속을 채운 베지테리안 버거"), price: 9400),
        .menu(attr: Option.Attr(id: 4, name: "Shack Stack", desc: "슈룸 버거, 쉑버거의 맛을 즐길 수 있는 메뉴"), price: 9900),
        .menu(attr: Option.Attr(id: 5, name: "Cheeseburger", desc: "포테이토 번, 비프패티, 치즈를 담은 치즈버거"), price: 6900),
        .menu(attr: Option.Attr(id: 6, name: "Hamburger", desc: "포테이토 번, 비프패티, 신선한 재료를 담은 버거"), price: 5400),
    ])
)

// 더욱 많은 메뉴 추가...

app.register(option: .order(
    attr: Option.Attr(id: 6, name: "Order", desc: "장바구니를 확인합니다."),
    actions: [
        .action(attr: Option.Attr(id: 1, name: "Buy", desc: "장바구니에 담은 제품을 구매합니다.")),
        .action(attr: Option.Attr(id: 2, name: "Clear", desc: "장바구니를 비웁니다.")),
    ])
)

app.run()

최대한 App 클래스가 구체적인 클래스에 의존하지 않도록 Protocol을 적극 사용하였습니다. 또한, 변경될 수 있는 세부 사항의 경우 main.swift에서 주입할 수 있도록 작성해주었습니다.

Viewer도 이와 마찬가지로 메뉴를 보여주는 화면의 경우 또한 콘솔창이든 실제 키오스크 기기든 언제 어떻게든 변경될 수 있으므로, 프로토콜로 작성해주어서 주입해주는 방식으로 작성하였습니다.

회고

이번 프로젝트에서는 Swift 문법의 enum associated values 기능을 활용하여 메뉴 목록을 나열하고 여러가지 기능을 구현해보았습니다. OOP에 대해 처음 공부할 때 추상화, 캡슐화, 상속, 다형성 그리고 SOLID 원칙에 대해 암기하느라 바빴지 그 개념에 대한 이해나 활용을 전혀 하지 못했었는데, 이번 프로젝트를 진행하면서 프로토콜과 클래스를 적극 활용하며 현재 내가 구현하고 있는 코드가 OOP의 특징과 원칙을 잘 준수하고 있는지에 대해 고민해보며 깊은 이해를 할 수 있었습니다.