ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,97 @@
+package christmas.Controller;
+
+import christmas.Domain.PromotionService;
+import christmas.Util.Parser;
+import christmas.View.InputView;
+import christmas.View.OutputView;
+
+
+public class PromotionController {
+
+    private PromotionService promotionService;
+
+    public void run() {
+        setPromotion();
+        printOrderList();
+        printTotalPrice();
+        if (hasNoEvent()) {
+            printNoEvent();
+            return;
+        }
+        printEligibleGift();
+        printAppliedDiscount();
+        printTotalBenefit();
+        printTotalPayment();
+        printChristmasBadge();
+    }
+
+    private void setPromotion() {
+        setUpService();
+        setDate();
+        setOrder();
+    }
+
+    private void setUpService() {
+        promotionService = new PromotionService();
+    }
+
+    private void setDate() {
+        try {
+            int visitDay = InputView.requestVisitDay();
+            promotionService.createDate(visitDay);
+        } catch (IllegalArgumentException e) {
+            System.out.println(e.getMessage());
+            setDate();
+        }
+    }
+
+    private void setOrder() {
+        try {
+            String orders = InputView.requestOrder();
+            promotionService.createOrder(Parser.convertStringToMap(orders));
+        } catch (IllegalArgumentException e) {
+            System.out.println(e.getMessage());
+            setOrder();
+        }
+    }
+
+    private void printOrderList() {
+        OutputView.printOrder(promotionService.getOrderList());
+    }
+
+    private void printTotalPrice() {
+        OutputView.printTotalPrice(promotionService.getTotalPrice());
+    }
+
+    private void printNoEvent() {
+        OutputView.printNoEvent(promotionService.getTotalPrice());
+    }
+
+    private boolean hasNoEvent() {
+        boolean isEventOn = promotionService.isEventOn();
+        if (!isEventOn) {
+            return true;
+        }
+        return false;
+    }
+
+    private void printEligibleGift() {
+        OutputView.printGift(promotionService.hasGift());
+    }
+
+    private void printAppliedDiscount() {
+        OutputView.printDiscount(promotionService.getDiscount(), promotionService.hasGift());
+    }
+
+    private void printTotalBenefit() {
+        OutputView.printTotalBenefit(promotionService.getTotalBenefit());
+    }
+
+    private void printTotalPayment() {
+        OutputView.printTotalPayment(promotionService.getTotalPayment());
+    }
+
+    private void printChristmasBadge() {
+        OutputView.printBadge(promotionService.getChristmasBadge());
+    }
+}

리뷰: ```suggestion
    private boolean hasNoEvent() {
        return !promotionService.isEventOn();
    }
```
간단하게 바꿔줄 수 있을 것 같아요!☺️
@@ -0,0 +1,54 @@
+package christmas.Util.Validator;
+
+import christmas.Domain.Menu;
+import java.util.Map;
+
+public class OrderValidator {
+
+    public static final String INVALID_ORDER = "[ERROR] 유효하지 않은 주문입니다. 다시 입력해 주세요.";
+    public static final int MAX_ORDER = 20;
+    public static final int MIN_ORDER_QUANTITY = 1;
+
+    public static void validateOrder(Map<String, Integer> order) throws IllegalArgumentException {
+        validateMenu(order);
+        validateAllBeverage(order);
+        validateNumber(order);
+        validateNumberRange(order);
+    }
+
+    private static void validateMenu(Map<String, Integer> order) throws IllegalArgumentException {
+        boolean isContain = order.keySet().stream()
+            .allMatch(Menu::hasContain);
+        if (!isContain) {
+            throw new IllegalArgumentException(INVALID_ORDER);
+        }
+    }
+
+    private static void validateAllBeverage(Map<String, Integer> order)
+        throws IllegalArgumentException {
+        boolean allBeverage = order.keySet().stream()
+            .allMatch(Menu::isBeverage);
+        if (allBeverage) {
+            throw new IllegalArgumentException(INVALID_ORDER);
+        }
+    }
+
+    private static void validateNumber(Map<String, Integer> order) throws IllegalArgumentException {
+        int menuCount = order.values().stream()
+            .mapToInt(Integer::intValue)
+            .sum();
+        if (menuCount > MAX_ORDER) {
+            throw new IllegalArgumentException(INVALID_ORDER);
+        }
+    }
+
+    private static void validateNumberRange(Map<String, Integer> order)
+        throws IllegalArgumentException {
+        boolean allQuantitiesValid = order.values().stream()
+            .allMatch(quantity -> quantity >= MIN_ORDER_QUANTITY);
+        if (!allQuantitiesValid) {
+            throw new IllegalArgumentException(INVALID_ORDER);
+        }
+    }
+
+}

리뷰: 와,, `allMatch` 를 활용해서 정말 깔끔하게 해주셨네요! 배워갑니다!👍
@@ -0,0 +1,53 @@
+package christmas.Domain;
+
+import christmas.Constant.December;
+import christmas.Constant.DiscountPrice;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Discount {
+
+    public Map<String, Integer> applyDiscount(int visitDay, int dessertCount, int mainCount) {
+        Map<String, Integer> appliedDiscount = new HashMap<>();
+        calculateChristmasDiscount(visitDay, appliedDiscount);
+        calculateWeekendDiscount(visitDay, mainCount, appliedDiscount);
+        calculateSpecialDiscount(visitDay, appliedDiscount);
+        calculateWeekdayDiscount(visitDay, dessertCount, appliedDiscount);
+        return appliedDiscount;
+    }
+
+    private void calculateChristmasDiscount(int visitDay, Map<String, Integer> appliedDiscount) {
+        if (December.FIRST_DAY.getDay() <= visitDay && visitDay <= December.CHRISTMAS.getDay()) {
+            appliedDiscount.put("크리스마스 디데이 할인",
+                ((visitDay - December.FIRST_DAY.getDay()) * DiscountPrice.DAILY_INCREASE.getPrice())
+                    + DiscountPrice.DEFAULT_DISCOUNT.getPrice());
+        }
+    }
+
+    private void calculateWeekendDiscount(int visitDay, int mainCount,
+        Map<String, Integer> appliedDiscount) {
+        if (getDayOfWeek(visitDay) == December.FRIDAY.getDay()
+            || getDayOfWeek(visitDay) == December.SATURDAY.getDay()) {
+            appliedDiscount.put("주말 할인", DiscountPrice.WEEKEND_DISCOUNT.getPrice() * mainCount);
+        }
+    }
+
+    private void calculateSpecialDiscount(int visitDay, Map<String, Integer> appliedDiscount) {
+        if (getDayOfWeek(visitDay) == December.SUNDAY.getDay()
+            || visitDay == December.CHRISTMAS.getDay()) {
+            appliedDiscount.put("특별 할인", DiscountPrice.SPECIAL_DISCOUNT.getPrice());
+        }
+    }
+
+    private void calculateWeekdayDiscount(int visitDay, int dessertCount,
+        Map<String, Integer> appliedDiscount) {
+        if (December.SUNDAY.getDay() <= getDayOfWeek(visitDay)
+            && getDayOfWeek(visitDay) <= December.THURSDAY.getDay()) {
+            appliedDiscount.put("평일 할인", DiscountPrice.WEEKDAY_DISCOUNT.getPrice() * dessertCount);
+        }
+    }
+
+    private static int getDayOfWeek(int visitDay) {
+        return visitDay % December.WEEK_DAYS.getDay();
+    }
+}

리뷰: 제가 찾던건데 감사합니다.
@@ -0,0 +1,28 @@
+# 기능 요구 사항
+
+1. 상품 목록 조회
+
+   - [x] API를 통해 상품 목록을 가져올 수 있다.
+   - [x] 맨 처음 API 호출 시 20개의 목록을 불러온다.
+   - [x] 이 후 추가 API 호출 시 4개의 목록을 불러온다.
+   - [x] 무한 스크롤을 할 수 있다.
+
+2. 상품 정렬 및 필터링
+
+   - [x] 상품 카테고리별 필터링을 할 수 있다.
+   - [x] 상품을 정렬 할 수 있다. (낮은 가격 순, 높은 가격 순)
+
+3. 상품 장바구니 담기
+
+   - [x] 사용자가 담기 버튼을 누르면, API를 통해 장바구니에 추가 될 수 있다.
+   - [x] 이 때 장바구니에 담긴 상품 '종류'의 갯수로 장바구니 아이콘에 숫자를 표시한다.
+   - [x] 장바구니에서 빼기 버튼을 누르면, 장바구니에서 해당 아이템이 제거되고 상품 목록 페이지의 담기 버튼은 활성화된다.
+
+4. 테스트
+
+   - [x] API 요청 시 MSW 서버를 모킹한다.
+   - [x] API 요청 상태에 따른 변화(로딩상태 표시, 에러메세지 표시)를 검증한다.
+
+5. 에러
+   - [ ] 장바구니 담기/빼기 요청 중 에러가 발생한 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.
+   - [x] 상품목록을 불러오는 중 에러가 발생할 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.

리뷰: 사소하지만, 여기 마지막 부분 체크리스트가 빠져있네요! 아직 구현 못한 부분일까요?!
@@ -4,17 +4,21 @@
   "version": "0.0.0",
   "type": "module",
   "scripts": {
-    "dev": "vite",
+    "dev": "vite --host",
     "build": "tsc && vite build",
     "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
     "preview": "vite preview",
     "test": "vitest"
   },
   "dependencies": {
+    "@tanstack/react-query": "^5.40.1",
+    "lv2-modal-component": "^0.0.20",
     "react": "^18.2.0",
-    "react-dom": "^18.2.0"
+    "react-dom": "^18.2.0",
+    "styled-components": "^6.1.11"
   },
   "devDependencies": {
+    "@tanstack/eslint-plugin-query": "^5.35.6",
     "@testing-library/react": "^15.0.7",
     "@types/jest": "^29.5.12",
     "@types/node": "^20.12.11",
@@ -24,9 +28,12 @@
     "@typescript-eslint/parser": "^7.2.0",
     "@vitejs/plugin-react-swc": "^3.5.0",
     "eslint": "^8.57.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-prettier": "^5.1.3",
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-react-refresh": "^0.4.6",
     "msw": "^2.3.0",
+    "prettier": "^3.2.5",
     "ts-node": "^10.9.2",
     "typescript": "^5.2.2",
     "vite": "^5.2.0",

리뷰: 제이드는 styled-components를 사용한 이유가 있을까요? 제이드의 의견이 궁금하네요! 🐫
@@ -0,0 +1,28 @@
+# 기능 요구 사항
+
+1. 상품 목록 조회
+
+   - [x] API를 통해 상품 목록을 가져올 수 있다.
+   - [x] 맨 처음 API 호출 시 20개의 목록을 불러온다.
+   - [x] 이 후 추가 API 호출 시 4개의 목록을 불러온다.
+   - [x] 무한 스크롤을 할 수 있다.
+
+2. 상품 정렬 및 필터링
+
+   - [x] 상품 카테고리별 필터링을 할 수 있다.
+   - [x] 상품을 정렬 할 수 있다. (낮은 가격 순, 높은 가격 순)
+
+3. 상품 장바구니 담기
+
+   - [x] 사용자가 담기 버튼을 누르면, API를 통해 장바구니에 추가 될 수 있다.
+   - [x] 이 때 장바구니에 담긴 상품 '종류'의 갯수로 장바구니 아이콘에 숫자를 표시한다.
+   - [x] 장바구니에서 빼기 버튼을 누르면, 장바구니에서 해당 아이템이 제거되고 상품 목록 페이지의 담기 버튼은 활성화된다.
+
+4. 테스트
+
+   - [x] API 요청 시 MSW 서버를 모킹한다.
+   - [x] API 요청 상태에 따른 변화(로딩상태 표시, 에러메세지 표시)를 검증한다.
+
+5. 에러
+   - [ ] 장바구니 담기/빼기 요청 중 에러가 발생한 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.
+   - [x] 상품목록을 불러오는 중 에러가 발생할 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.

리뷰: ++ README에 작성하기보다, REQUIREMENTS에 작성하신 이유가 있을까요?
@@ -4,17 +4,21 @@
   "version": "0.0.0",
   "type": "module",
   "scripts": {
-    "dev": "vite",
+    "dev": "vite --host",
     "build": "tsc && vite build",
     "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
     "preview": "vite preview",
     "test": "vitest"
   },
   "dependencies": {
+    "@tanstack/react-query": "^5.40.1",
+    "lv2-modal-component": "^0.0.20",
     "react": "^18.2.0",
-    "react-dom": "^18.2.0"
+    "react-dom": "^18.2.0",
+    "styled-components": "^6.1.11"
   },
   "devDependencies": {
+    "@tanstack/eslint-plugin-query": "^5.35.6",
     "@testing-library/react": "^15.0.7",
     "@types/jest": "^29.5.12",
     "@types/node": "^20.12.11",
@@ -24,9 +28,12 @@
     "@typescript-eslint/parser": "^7.2.0",
     "@vitejs/plugin-react-swc": "^3.5.0",
     "eslint": "^8.57.0",
+    "eslint-config-prettier": "^9.1.0",
+    "eslint-plugin-prettier": "^5.1.3",
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-react-refresh": "^0.4.6",
     "msw": "^2.3.0",
+    "prettier": "^3.2.5",
     "ts-node": "^10.9.2",
     "typescript": "^5.2.2",
     "vite": "^5.2.0",

리뷰: styled-component와
emotion 의 선택

사실 저는 둘 다사용해보고 emotion을 더 선호하지만, 
이번 미션에서는 이 둘의 선택에 대해선 크루의 의견을 따랐습니다.

emotion을 좀 더 선호하는 이유:
styled-component를 다른파일에 계속 만들어 줄 필요 없음
동적인 css를 사용하고싶을 때 좀 더 편하다고 느꼈음

입니다.
@@ -0,0 +1,28 @@
+# 기능 요구 사항
+
+1. 상품 목록 조회
+
+   - [x] API를 통해 상품 목록을 가져올 수 있다.
+   - [x] 맨 처음 API 호출 시 20개의 목록을 불러온다.
+   - [x] 이 후 추가 API 호출 시 4개의 목록을 불러온다.
+   - [x] 무한 스크롤을 할 수 있다.
+
+2. 상품 정렬 및 필터링
+
+   - [x] 상품 카테고리별 필터링을 할 수 있다.
+   - [x] 상품을 정렬 할 수 있다. (낮은 가격 순, 높은 가격 순)
+
+3. 상품 장바구니 담기
+
+   - [x] 사용자가 담기 버튼을 누르면, API를 통해 장바구니에 추가 될 수 있다.
+   - [x] 이 때 장바구니에 담긴 상품 '종류'의 갯수로 장바구니 아이콘에 숫자를 표시한다.
+   - [x] 장바구니에서 빼기 버튼을 누르면, 장바구니에서 해당 아이템이 제거되고 상품 목록 페이지의 담기 버튼은 활성화된다.
+
+4. 테스트
+
+   - [x] API 요청 시 MSW 서버를 모킹한다.
+   - [x] API 요청 상태에 따른 변화(로딩상태 표시, 에러메세지 표시)를 검증한다.
+
+5. 에러
+   - [ ] 장바구니 담기/빼기 요청 중 에러가 발생한 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.
+   - [x] 상품목록을 불러오는 중 에러가 발생할 경우, 에러 메시지를 사용자에게 알려주는 UI를 표시한다.

리뷰: 요구사항이라서 REQUIREMENTS로 명명했습니다.
README에는 프로젝트 내용에대한 소개 등을 쓰는 편인 것 같습니다
@@ -0,0 +1,86 @@
+package store.controller;
+
+import static store.util.Constant.ANSWER_NO;
+import static store.util.InformationMessage.WELCOME_MESSAGE;
+import static store.util.Validator.validateAnswer;
+import static store.view.InputView.readForAdditionalPurchase;
+import static store.view.OutputView.displayReceipt;
+
+import camp.nextstep.edu.missionutils.Console;
+import java.io.IOException;
+import store.service.PaymentService;
+import store.domain.Inventory;
+import store.domain.Order;
+import store.domain.Promotions;
+import store.view.InputView;
+import store.view.OutputView;
+
+public class StoreController {
+
+    private final Inventory inventory;
+    private final Promotions promotions;
+
+    public StoreController() {
+        inventory = prepareInventory();
+        promotions = preparePromotions();
+    }
+
+    public void run() {
+        do {
+            OutputView.printMessage(WELCOME_MESSAGE);
+            OutputView.printInventory(inventory);
+            Order order = inputOrder(inventory);
+            PaymentService paymentService = new PaymentService(inventory, promotions, order);
+            displayReceipt(paymentService.getReceipt());
+        } while (!inputAdditionalPurchase().equals(ANSWER_NO));
+        closeConsole();
+    }
+
+    Inventory prepareInventory() {
+        Inventory inventory;
+        try {
+            inventory = new Inventory();
+            return inventory;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Promotions preparePromotions() {
+        Promotions promotions;
+        try {
+            promotions = new Promotions();
+            return promotions;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Order inputOrder(Inventory inventory) {
+        while (true) {
+            try {
+                Order order = new Order(InputView.readOrder());
+                inventory.checkOrder(order);
+                return order;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e.getMessage());
+            }
+        }
+    }
+
+    String inputAdditionalPurchase() {
+        while (true) {
+            try {
+                String answer = readForAdditionalPurchase();
+                validateAnswer(answer);
+                return answer;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e.getMessage());
+            }
+        }
+    }
+
+    void closeConsole() {
+        Console.close();
+    }
+}

리뷰: 이부분 깔끔한거 같습니다!
@@ -0,0 +1,86 @@
+package store.controller;
+
+import static store.util.Constant.ANSWER_NO;
+import static store.util.InformationMessage.WELCOME_MESSAGE;
+import static store.util.Validator.validateAnswer;
+import static store.view.InputView.readForAdditionalPurchase;
+import static store.view.OutputView.displayReceipt;
+
+import camp.nextstep.edu.missionutils.Console;
+import java.io.IOException;
+import store.service.PaymentService;
+import store.domain.Inventory;
+import store.domain.Order;
+import store.domain.Promotions;
+import store.view.InputView;
+import store.view.OutputView;
+
+public class StoreController {
+
+    private final Inventory inventory;
+    private final Promotions promotions;
+
+    public StoreController() {
+        inventory = prepareInventory();
+        promotions = preparePromotions();
+    }
+
+    public void run() {
+        do {
+            OutputView.printMessage(WELCOME_MESSAGE);
+            OutputView.printInventory(inventory);
+            Order order = inputOrder(inventory);
+            PaymentService paymentService = new PaymentService(inventory, promotions, order);
+            displayReceipt(paymentService.getReceipt());
+        } while (!inputAdditionalPurchase().equals(ANSWER_NO));
+        closeConsole();
+    }
+
+    Inventory prepareInventory() {
+        Inventory inventory;
+        try {
+            inventory = new Inventory();
+            return inventory;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Promotions preparePromotions() {
+        Promotions promotions;
+        try {
+            promotions = new Promotions();
+            return promotions;
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    Order inputOrder(Inventory inventory) {
+        while (true) {
+            try {
+                Order order = new Order(InputView.readOrder());
+                inventory.checkOrder(order);
+                return order;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e.getMessage());
+            }
+        }
+    }
+
+    String inputAdditionalPurchase() {
+        while (true) {
+            try {
+                String answer = readForAdditionalPurchase();
+                validateAnswer(answer);
+                return answer;
+            } catch (IllegalArgumentException e) {
+                OutputView.printError(e.getMessage());
+            }
+        }
+    }
+
+    void closeConsole() {
+        Console.close();
+    }
+}

리뷰: 따로 static선언을 안하신 이유가 궁금합니다
@@ -0,0 +1,83 @@
+package store.domain;
+
+import static store.util.Constant.BLANK;
+import static store.util.ErrorMessage.INVALID_ORDER_MESSAGE;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Order {
+
+    private final Map<String, Integer> orders;
+
+    public Order(String orderInput) {
+        this.orders = new LinkedHashMap<>();
+        validate(orderInput);
+        putToOrders(orderInput);
+    }
+
+    private void putToOrders(String orderInput) {
+        List<String> orderParts = List.of(orderInput.split(","));
+        for (String orderPart : orderParts) {
+            parseOrder(orderPart);
+        }
+    }
+
+    private void parseOrder(String orderPart) {
+        String orderPartNoBracket = removeSquareBracket(orderPart);
+        List<String> productNameAndQuantity = List.of(orderPartNoBracket.split("-"));
+        String name = productNameAndQuantity.getFirst();
+        String quantityPart = productNameAndQuantity.getLast();
+        int quantity = Integer.parseInt(quantityPart);
+        orders.put(name, quantity);
+    }
+
+    private void validate(String orderInput) {
+        List<String> splitComma = List.of(orderInput.split(","));
+        for (String productNameAndQuantity : splitComma) {
+            checkSquareBracket(productNameAndQuantity);
+            checkSeparatedTwoPart(productNameAndQuantity);
+        }
+    }
+
+    private void checkSquareBracket(String order) {
+        if (!isStartAndEndWithSquareBracket(order)) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+    }
+
+    private void checkSeparatedTwoPart(String order) {
+        String orderNoBracket = removeSquareBracket(order);
+        List<String> splitHyphen = List.of(orderNoBracket.split("-"));
+        if (splitHyphen.size() != 2) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+        String quantity = splitHyphen.getLast();
+        checkQuantityPart(quantity);
+    }
+
+    private void checkQuantityPart(String quantityPart) {
+        try {
+            int quantity = Integer.parseInt(quantityPart);
+            if (quantity <= 0) {
+                throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+            }
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+    }
+
+    private boolean isStartAndEndWithSquareBracket(String order) {
+        return order.startsWith("[") && order.endsWith("]");
+    }
+
+    private String removeSquareBracket(String orderPart) {
+        return orderPart.replaceAll("[\\[\\]]", BLANK);
+    }
+
+    public Map<String, Integer> getOrders() {
+        return Collections.unmodifiableMap(orders);
+    }
+}

리뷰: order에 넣는 부분이 parserOrder에 있어서 이 부분에서 파라미터를 전달해주고 putToOrders에서 직접 orders에 넣는 방식으로 변경하면 메서드 이름에 적합한 기능을 할거같다는 생각이 들어서 작성해봅니다.
@@ -0,0 +1,83 @@
+package store.domain;
+
+import static store.util.Constant.BLANK;
+import static store.util.ErrorMessage.INVALID_ORDER_MESSAGE;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class Order {
+
+    private final Map<String, Integer> orders;
+
+    public Order(String orderInput) {
+        this.orders = new LinkedHashMap<>();
+        validate(orderInput);
+        putToOrders(orderInput);
+    }
+
+    private void putToOrders(String orderInput) {
+        List<String> orderParts = List.of(orderInput.split(","));
+        for (String orderPart : orderParts) {
+            parseOrder(orderPart);
+        }
+    }
+
+    private void parseOrder(String orderPart) {
+        String orderPartNoBracket = removeSquareBracket(orderPart);
+        List<String> productNameAndQuantity = List.of(orderPartNoBracket.split("-"));
+        String name = productNameAndQuantity.getFirst();
+        String quantityPart = productNameAndQuantity.getLast();
+        int quantity = Integer.parseInt(quantityPart);
+        orders.put(name, quantity);
+    }
+
+    private void validate(String orderInput) {
+        List<String> splitComma = List.of(orderInput.split(","));
+        for (String productNameAndQuantity : splitComma) {
+            checkSquareBracket(productNameAndQuantity);
+            checkSeparatedTwoPart(productNameAndQuantity);
+        }
+    }
+
+    private void checkSquareBracket(String order) {
+        if (!isStartAndEndWithSquareBracket(order)) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+    }
+
+    private void checkSeparatedTwoPart(String order) {
+        String orderNoBracket = removeSquareBracket(order);
+        List<String> splitHyphen = List.of(orderNoBracket.split("-"));
+        if (splitHyphen.size() != 2) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+        String quantity = splitHyphen.getLast();
+        checkQuantityPart(quantity);
+    }
+
+    private void checkQuantityPart(String quantityPart) {
+        try {
+            int quantity = Integer.parseInt(quantityPart);
+            if (quantity <= 0) {
+                throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+            }
+        } catch (NumberFormatException e) {
+            throw new IllegalArgumentException(INVALID_ORDER_MESSAGE);
+        }
+    }
+
+    private boolean isStartAndEndWithSquareBracket(String order) {
+        return order.startsWith("[") && order.endsWith("]");
+    }
+
+    private String removeSquareBracket(String orderPart) {
+        return orderPart.replaceAll("[\\[\\]]", BLANK);
+    }
+
+    public Map<String, Integer> getOrders() {
+        return Collections.unmodifiableMap(orders);
+    }
+}

리뷰: split하는 부분의 regex도 상수화하면 좋을거같다고 생각듭니다