ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,35 @@
+package christmas.domain.discount.policy;
+
+import christmas.domain.common.Date;
+import christmas.domain.common.Money;
+import christmas.domain.discount.DateDiscountPolicy;
+import christmas.domain.discount.DiscountResult;
+
+public class ChristmasDDayDiscountPolicy extends DateDiscountPolicy {
+
+    private static final Date DISCOUNTABLE_STANDARD_DATE = Date.from(25);
+    private static final Money BASE_DISCOUNT_AMOUNT = Money.from(-1_000);
+    private static final Money ADD_AMOUNT = Money.from(-100);
+    private static final String POLICY_NAME = "크리스마스 디데이 할인";
+
+    @Override
+    protected boolean isSatisfied(Date date) {
+        return !date.isLaterThan(DISCOUNTABLE_STANDARD_DATE);
+    }
+
+    @Override
+    protected DiscountResult bulidDiscountResult(Date date) {
+        Money discountAmount = calculateDiscountAmount(date);
+
+        return new DiscountResult(POLICY_NAME, discountAmount);
+    }
+
+    private Money calculateDiscountAmount(Date date) {
+        Money discountAmount = BASE_DISCOUNT_AMOUNT;
+        for (int day = 1; day < date.getDayOfMonth(); day++) {
+            discountAmount = discountAmount.add(ADD_AMOUNT);
+        }
+
+        return discountAmount;
+    }
+}

리뷰: 개인적으로 전 할인된 금액을 양수 값으로 유지하고, View로 보여주는 시점에 "-" 마이너스 부호를 붙여주도록 활용함으로써 
이 금액이 주문 금액에서 얼마나 빼야 할 금액인지를 직관적으로 이해할 수 있도록 의도했는데

하늘님은 어떤 이유 때문에 처음부터 할인된 금액을 음수 값으료 유지하고자 하셨나요~? 😄
@@ -0,0 +1,35 @@
+package christmas.domain.discount.policy;
+
+import christmas.domain.common.Date;
+import christmas.domain.common.Money;
+import christmas.domain.discount.DateDiscountPolicy;
+import christmas.domain.discount.DiscountResult;
+import java.util.List;
+
+public class SpecialDiscountPolicy extends DateDiscountPolicy {
+
+    private static final List<Date> specialDays;
+    private static final Money DISCOUNT_AMOUNT = Money.from(-1_000);
+    private static final String POLICY_NAME = "특별 할인";
+
+    static {
+        specialDays = List.of(
+                Date.from(3),
+                Date.from(10),
+                Date.from(17),
+                Date.from(24),
+                Date.from(25),
+                Date.from(31)
+        );
+    }
+
+    @Override
+    protected boolean isSatisfied(Date date) {
+        return specialDays.contains(date);
+    }
+
+    @Override
+    protected DiscountResult bulidDiscountResult(Date date) {
+        return new DiscountResult(POLICY_NAME, DISCOUNT_AMOUNT);
+    }
+}

리뷰: 특별한 날짜를 관리하기 위해서 List를 활용하셨는데, Set은 어떨까요~ ? 😄
@@ -0,0 +1,46 @@
+package christmas.domain.menu;
+
+import static christmas.global.util.ObjectUtil.requireIncludeNonNull;
+import static christmas.global.util.ObjectUtil.requireNonNull;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+
+public class Menus {
+
+    private static final String UNKNOWN_MENUS_MESSAGE = "알 수 없는 메뉴 목록입니다.";
+    private static final String UNKNOWN_MENU_MESSAGE = "알 수 없는 메뉴가 포함되어 있습니다.";
+
+    private final List<Menu> menus;
+
+    private Menus(List<Menu> menus) {
+        this.menus = menus;
+    }
+
+    public static Menus from(List<Menu> menus) {
+        requireNonNull(menus, UNKNOWN_MENUS_MESSAGE);
+        requireIncludeNonNull(menus, UNKNOWN_MENU_MESSAGE);
+
+        return new Menus(menus);
+    }
+
+    public boolean containsAll(Menus other) {
+        requireNonNull(other, UNKNOWN_MENUS_MESSAGE);
+
+        return new HashSet<>(menus).containsAll(other.menus);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Menus menus1 = (Menus) o;
+        return Objects.equals(menus, menus1.menus);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(menus);
+    }
+}

리뷰: List을 Set으로 변경해서 확인하는 부분이 좋네요 ~ 😄
@@ -0,0 +1,77 @@
+package christmas.domain.common;
+
+import static christmas.global.util.ObjectUtil.requireNonNull;
+
+import christmas.global.util.DateUtil;
+import java.util.Objects;
+
+public class Date {
+
+    public static final int BASE_MONTH = 12;
+    private static final int BASE_YEAR = 2023;
+    private static final int DAY_OF_MONTH_MIN_RANGE = 1;
+    private static final int DAY_OF_MONTH_MAX_RANGE = 31;
+    private static final String INVALID_DAY_OF_MONTH_RANGE_MESSAGE =
+            "날짜는 " + DAY_OF_MONTH_MIN_RANGE + "과 " + DAY_OF_MONTH_MAX_RANGE + " 사이의 수를 입력해주세요.";
+    private static final String UNKNOWN_DATE_MESSAGE = "알 수 없는 날짜입니다.";
+
+    private final int dayOfMonth;
+
+    private Date(int dayOfMonth) {
+        this.dayOfMonth = dayOfMonth;
+    }
+
+    public static Date from(int dayOfMonth) {
+        checkDayOfMonthRange(dayOfMonth);
+
+        return new Date(dayOfMonth);
+    }
+
+    private static void checkDayOfMonthRange(int dayOfMonth) {
+        checkDayOfMonthMinRange(dayOfMonth);
+        checkDayOfMonthMaxRange(dayOfMonth);
+    }
+
+    private static void checkDayOfMonthMinRange(int dayOfMonth) {
+        if (dayOfMonth < DAY_OF_MONTH_MIN_RANGE) {
+            throw new IllegalArgumentException(INVALID_DAY_OF_MONTH_RANGE_MESSAGE);
+        }
+    }
+
+    private static void checkDayOfMonthMaxRange(int dayOfMonth) {
+        if (dayOfMonth > DAY_OF_MONTH_MAX_RANGE) {
+            throw new IllegalArgumentException(INVALID_DAY_OF_MONTH_RANGE_MESSAGE);
+        }
+    }
+
+    public boolean isLaterThan(Date target) {
+        requireNonNull(target, UNKNOWN_DATE_MESSAGE);
+
+        return this.dayOfMonth > target.dayOfMonth;
+    }
+
+    public boolean isWeekDay() {
+        return DateUtil.isWeekday(BASE_YEAR, BASE_MONTH, dayOfMonth);
+    }
+
+    public boolean isWeekend() {
+        return DateUtil.isWeekend(BASE_YEAR, BASE_MONTH, dayOfMonth);
+    }
+
+    public int getDayOfMonth() {
+        return dayOfMonth;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        Date date = (Date) o;
+        return dayOfMonth == date.dayOfMonth;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(dayOfMonth);
+    }
+}

리뷰: 넵 맞습니다. 요구사항에 나오는 예외 메시지는 너무 일반적여서요. 개발하면서 로그를 찍어 볼 일이 었었는데, 불편하더라구요. 따라서, 위와 같이 구체적으로 내보내고, 다시 컨트롤러에서 메시지를 바꾸는 작업을 해줬습니다!
@@ -0,0 +1,18 @@
+package christmas.domain.discount.policy;
+
+import christmas.domain.common.Date;
+import christmas.domain.discount.DateDiscountPolicy;
+import christmas.domain.discount.DiscountResult;
+
+public class NoneDiscountPolicy extends DateDiscountPolicy {
+
+    @Override
+    protected boolean isSatisfied(Date date) {
+        return false;
+    }
+
+    @Override
+    protected DiscountResult bulidDiscountResult(Date date) {
+        return null;
+    }
+}

리뷰: ```java

@Override
public DiscountResult calculateDiscountBenefitWith(Date date, int quantity) {
    DiscountResult menuDiscountResult = policy.discount(date);

    return new DiscountResult(menuDiscountResult.policyName(), menuDiscountResult.amount().multiply(quantity));
}
```

DateDiscountPolicy를 사용하는 클라이언트 코드는 위와 같은 형태로 discount(내부에서 buildDiscountResult, isSatisfied 호출)를 호출하는데요. 메뉴가 정책이 없는 것을 이곳에서 판단하기 보다는, NoneDiscountPolicy를 만들어서 클라이언트 코드를 재사용하기 위함입니다.!
@@ -0,0 +1,35 @@
+package christmas.domain.discount.policy;
+
+import christmas.domain.common.Date;
+import christmas.domain.common.Money;
+import christmas.domain.discount.DateDiscountPolicy;
+import christmas.domain.discount.DiscountResult;
+
+public class ChristmasDDayDiscountPolicy extends DateDiscountPolicy {
+
+    private static final Date DISCOUNTABLE_STANDARD_DATE = Date.from(25);
+    private static final Money BASE_DISCOUNT_AMOUNT = Money.from(-1_000);
+    private static final Money ADD_AMOUNT = Money.from(-100);
+    private static final String POLICY_NAME = "크리스마스 디데이 할인";
+
+    @Override
+    protected boolean isSatisfied(Date date) {
+        return !date.isLaterThan(DISCOUNTABLE_STANDARD_DATE);
+    }
+
+    @Override
+    protected DiscountResult bulidDiscountResult(Date date) {
+        Money discountAmount = calculateDiscountAmount(date);
+
+        return new DiscountResult(POLICY_NAME, discountAmount);
+    }
+
+    private Money calculateDiscountAmount(Date date) {
+        Money discountAmount = BASE_DISCOUNT_AMOUNT;
+        for (int day = 1; day < date.getDayOfMonth(); day++) {
+            discountAmount = discountAmount.add(ADD_AMOUNT);
+        }
+
+        return discountAmount;
+    }
+}

리뷰: View에서 마이너스 부호를 추가해주는 것이 번거로워서 그런식으로 구현했던 것 같습니다.  확실히 양수로 하는 것이,  말씀 주신 것처럼 더욱 직관적인 것 같아요! 

++ Money에 substract 연산을 만든 이유도 처음에는 할인 값을 양수로 유지하려고 했던 것 같은데요. 지금보니, money.substract를 테스트 코드에서만 사용하는군요... 피드백 감사합니다.
@@ -0,0 +1,84 @@
+import { 비동기_요청 } from 'constants/';
+
+const errorReturn = (error) => ({
+  status: 비동기_요청.FAIL,
+  content: `서버와의 통신에 실패하였습니다. (${error.message})`,
+});
+
+const authorizedHeader = (header) => ({
+  ...header,
+  Authorization: `Bearer ${sessionStorage.getItem('accessToken')}`,
+});
+
+class RequestAsync {
+  constructor() {
+    this.HOST_NAME = process.env.REACT_APP_API_URL;
+    this.header = { 'Content-Type': 'application/json' };
+  }
+
+  async #getRefinedResponse(response) {
+    const responseString = await response.text();
+
+    return {
+      status: response.ok ? 비동기_요청.SUCCESS : 비동기_요청.FAILURE,
+      content: responseString ? JSON.parse(responseString) : {},
+    };
+  }
+
+  async get(path, authorize = false) {
+    try {
+      const response = await fetch(`${this.HOST_NAME}/${path}`, {
+        method: 'GET',
+        headers: authorize ? authorizedHeader(this.header) : this.header,
+      });
+
+      return this.#getRefinedResponse(response);
+    } catch (error) {
+      return errorReturn(error);
+    }
+  }
+
+  async post(path, bodyData, authorize = false) {
+    try {
+      const response = await fetch(`${this.HOST_NAME}/${path}`, {
+        method: 'POST',
+        headers: authorize ? authorizedHeader(this.header) : this.header,
+        body: JSON.stringify(bodyData),
+      });
+
+      return this.#getRefinedResponse(response);
+    } catch (error) {
+      return errorReturn(error);
+    }
+  }
+
+  async put(path, bodyData, authorize = false) {
+    try {
+      const response = await fetch(`${this.HOST_NAME}/${path}`, {
+        method: 'PUT',
+        headers: authorize ? authorizedHeader(this.header) : this.header,
+        body: JSON.stringify(bodyData),
+      });
+
+      return this.#getRefinedResponse(response);
+    } catch (error) {
+      return errorReturn(error);
+    }
+  }
+
+  async delete(path, authorize = false) {
+    try {
+      const response = await fetch(`${this.HOST_NAME}/${path}`, {
+        method: 'DELETE',
+        headers: authorize ? authorizedHeader(this.header) : this.header,
+      });
+
+      return this.#getRefinedResponse(response);
+    } catch (error) {
+      return errorReturn(error);
+    }
+  }
+}
+
+const requestAsync = new RequestAsync();
+export default requestAsync;

리뷰: 오~
@@ -0,0 +1,67 @@
+package com.codesquad.airbnb.business;
+
+import com.codesquad.airbnb.exception.ErrorMessage;
+import com.codesquad.airbnb.exception.custom.EntityNotFoundException;
+import com.codesquad.airbnb.common.utils.DAOUtils;
+import com.codesquad.airbnb.dao.AccommodationMapper;
+import com.codesquad.airbnb.dao.BookingMapper;
+import com.codesquad.airbnb.dao.FeePolicyMapper;
+import com.codesquad.airbnb.domain.dto.AccommodationDTO;
+import com.codesquad.airbnb.domain.model.Accommodation;
+import com.codesquad.airbnb.domain.model.Booking;
+import com.codesquad.airbnb.domain.model.Filter;
+import com.codesquad.airbnb.domain.model.User;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Service
+public class BookService {
+
+    private AccommodationMapper accommodationMapper;
+    private FeePolicyMapper feePolicyMapper;
+    private BookingMapper bookingMapper;
+
+    public BookService(AccommodationMapper accommodationMapper,
+                       FeePolicyMapper feePolicyMapper,
+                       BookingMapper bookingMapper) {
+        this.accommodationMapper = accommodationMapper;
+        this.feePolicyMapper = feePolicyMapper;
+        this.bookingMapper = bookingMapper;
+    }
+
+    public AccommodationDTO getAccommodation(Integer id, Filter filter) {
+        if(accommodationMapper.countById(id) == 0) {
+            throw new EntityNotFoundException(ErrorMessage.ENTITY_NOT_FOUND.getMessage());
+        }
+
+        Map<String, Object> parameters = DAOUtils.createParameters(filter, id);
+        Accommodation accommodation = accommodationMapper.findAccommodationChargeInfoById(parameters);
+
+        float accommodationTaxRate = feePolicyMapper.findAccommodationTax();
+
+        return new AccommodationDTO.Builder(accommodation.getId())
+                .pricePerNight(accommodation.getOriginalPricePerNight())
+                .pricePerNightDiscounted(accommodation.getDiscountedPricePerNight())
+                .priceDuringPeriod(accommodation.getPriceDuringPeriod(filter))
+                .cleaningFee(accommodation.getCleaningFee())
+                .serviceTax(accommodation.getServiceTax(filter))
+                .accommodationTax(accommodation.getAccommodationTax(filter, accommodationTaxRate))
+                .totalPrice(accommodation.getTotalPrice(filter, accommodationTaxRate))
+                .build();
+    }
+
+    public boolean booking(Integer id, Filter filter, User user) {
+        if(accommodationMapper.countById(id) == 0) {
+            throw new EntityNotFoundException(ErrorMessage.ENTITY_NOT_FOUND.getMessage());
+        }
+
+        Booking newBooking = new Booking(user, id, filter);
+
+        if (bookingMapper.countByAccommodationIdAndPeriod(newBooking) > 0) {
+            return false;
+        }
+        bookingMapper.insertBooking(newBooking);
+        return true;
+    }
+}

리뷰: 단순히 null-safety를 위해 카운트 로직을 한 번 더 넣은 거라면, 
null check를 하는 것이 성능상에 더 큰 이점이 있을 것 같네요.
@@ -0,0 +1,67 @@
+package com.codesquad.airbnb.business;
+
+import com.codesquad.airbnb.exception.ErrorMessage;
+import com.codesquad.airbnb.exception.custom.EntityNotFoundException;
+import com.codesquad.airbnb.common.utils.DAOUtils;
+import com.codesquad.airbnb.dao.AccommodationMapper;
+import com.codesquad.airbnb.dao.BookingMapper;
+import com.codesquad.airbnb.dao.FeePolicyMapper;
+import com.codesquad.airbnb.domain.dto.AccommodationDTO;
+import com.codesquad.airbnb.domain.model.Accommodation;
+import com.codesquad.airbnb.domain.model.Booking;
+import com.codesquad.airbnb.domain.model.Filter;
+import com.codesquad.airbnb.domain.model.User;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Service
+public class BookService {
+
+    private AccommodationMapper accommodationMapper;
+    private FeePolicyMapper feePolicyMapper;
+    private BookingMapper bookingMapper;
+
+    public BookService(AccommodationMapper accommodationMapper,
+                       FeePolicyMapper feePolicyMapper,
+                       BookingMapper bookingMapper) {
+        this.accommodationMapper = accommodationMapper;
+        this.feePolicyMapper = feePolicyMapper;
+        this.bookingMapper = bookingMapper;
+    }
+
+    public AccommodationDTO getAccommodation(Integer id, Filter filter) {
+        if(accommodationMapper.countById(id) == 0) {
+            throw new EntityNotFoundException(ErrorMessage.ENTITY_NOT_FOUND.getMessage());
+        }
+
+        Map<String, Object> parameters = DAOUtils.createParameters(filter, id);
+        Accommodation accommodation = accommodationMapper.findAccommodationChargeInfoById(parameters);
+
+        float accommodationTaxRate = feePolicyMapper.findAccommodationTax();
+
+        return new AccommodationDTO.Builder(accommodation.getId())
+                .pricePerNight(accommodation.getOriginalPricePerNight())
+                .pricePerNightDiscounted(accommodation.getDiscountedPricePerNight())
+                .priceDuringPeriod(accommodation.getPriceDuringPeriod(filter))
+                .cleaningFee(accommodation.getCleaningFee())
+                .serviceTax(accommodation.getServiceTax(filter))
+                .accommodationTax(accommodation.getAccommodationTax(filter, accommodationTaxRate))
+                .totalPrice(accommodation.getTotalPrice(filter, accommodationTaxRate))
+                .build();
+    }
+
+    public boolean booking(Integer id, Filter filter, User user) {
+        if(accommodationMapper.countById(id) == 0) {
+            throw new EntityNotFoundException(ErrorMessage.ENTITY_NOT_FOUND.getMessage());
+        }
+
+        Booking newBooking = new Booking(user, id, filter);
+
+        if (bookingMapper.countByAccommodationIdAndPeriod(newBooking) > 0) {
+            return false;
+        }
+        bookingMapper.insertBooking(newBooking);
+        return true;
+    }
+}

리뷰: 메소드 이름을 조금 더 직관적으로 바꿔주세요. 
`insertNewBooking` 이랄지 `saveNewBooking` 이랄지....
@@ -0,0 +1,6 @@
+package com.codesquad.airbnb.common.utils;
+
+public class CurrencyConvertor {
+
+    public static final float EXCHANGE_RATE_FROM_USD_TO_KRW = 1231.54f;
+}

리뷰: 호오오.... 환율이 언제 이렇게 올랐죠
@@ -0,0 +1,13 @@
+package com.codesquad.airbnb.common.utils;
+
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.ObjectError;
+
+import java.util.stream.Collectors;
+
+public class CustomValidatorUtils {
+
+    public static String getErrorMessage(BindingResult result) {
+        return result.getAllErrors().stream().map(ObjectError::getCode).collect(Collectors.joining(", "));
+    }
+}

리뷰: `Collectors.joining` 활용 좋습니다!
@@ -0,0 +1,16 @@
+package com.codesquad.airbnb.domain.model;
+
+public class City {
+
+    private Integer id;
+
+    private String name;
+
+    private String country;
+
+    public City() {}
+
+    public String getName() {
+        return name;
+    }
+}

리뷰: 기본생성자 사용 좋습니다. 
그러나 각 필드들을 초기화해줄 필요는 전혀 없나요?
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
+    <data-source source="LOCAL" name="baseball-10" uuid="873ec135-86e5-491d-a981-98740f2170c3">
+      <driver-ref>mysql</driver-ref>
+      <synchronize>true</synchronize>
+      <jdbc-driver>com.mysql.jdbc.Driver</jdbc-driver>
+      <jdbc-url>jdbc:mysql://baseball-10-proeject.csjhbz8c8oyh.ap-northeast-2.rds.amazonaws.com:3306</jdbc-url>
+    </data-source>
+    <data-source source="LOCAL" name="baseball-10-real" uuid="24139289-bb1d-4da5-b58f-bd3fb57713eb">
+      <driver-ref>mysql.8</driver-ref>
+      <synchronize>true</synchronize>
+      <jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
+      <jdbc-url>jdbc:mysql://baseball-10-rds.csjhbz8c8oyh.ap-northeast-2.rds.amazonaws.com:3306</jdbc-url>
+    </data-source>
+  </component>
+</project>
\ No newline at end of file

리뷰: 인텔리제이 Datasource 기능 사용해보신 것 좋네요.
@@ -0,0 +1,21 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Gradle documentation](https://docs.gradle.org)
+* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/gradle-plugin/reference/html/)
+* [Spring Web](https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/htmlsingle/#boot-features-developing-web-applications)
+
+### Guides
+The following guides illustrate how to use some features concretely:
+
+* [Building a RESTful Web Service](https://spring.io/guides/gs/rest-service/)
+* [Serving Web Content with Spring MVC](https://spring.io/guides/gs/serving-web-content/)
+* [Building REST services with Spring](https://spring.io/guides/tutorials/bookmarks/)
+
+### Additional Links
+These additional references should also help you:
+
+* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
+

리뷰: 기본 생성된 마크다운 파일은 과감히 날려주세요.
@@ -0,0 +1,65 @@
+import InputView from './view/InputView.js';
+import OutputView from './view/OutputView.js';
+import Service from './Service.js';
+import { print } from './utils/missionUtils.js';
+
+class Controller {
+  constructor() {
+    this.service = new Service();
+  }
+
+  async run() {
+    await this.inputControl();
+
+    const totalPrice = this.service.totalOrderPrice();
+    const BenefitDetails = this.service.BenefitsDetails();
+    const totalBenefitPrice = this.service.totalBenefitsPrice();
+    const badge = this.service.calculateBadge();
+
+    OutputView.printTotalPriceAndGift(totalPrice);
+    OutputView.printBenefits(totalPrice, BenefitDetails, totalBenefitPrice);
+    OutputView.printTotalBenefitAmount(totalPrice, totalBenefitPrice);
+    OutputView.printEstimatedAmount(this.service.calculatePayment());
+    OutputView.printBadge(badge);
+  }
+
+  async inputControl() {
+    OutputView.printWelcome();
+    const date = await this.#inputDate();
+    const order = await this.#inputOrder();
+    OutputView.printGuide(date);
+    OutputView.printMenu(order);
+  }
+
+  async #inputDate() {
+    let date;
+
+    while (!date) {
+      try {
+        const getDate = await InputView.readDate();
+        date = this.service.benefitsCreate(getDate);
+      } catch (error) {
+        print(error.message);
+      }
+    }
+
+    return date;
+  }
+
+  async #inputOrder() {
+    let order;
+
+    while (!order) {
+      try {
+        const getOrder = await InputView.readMenu();
+        order = this.service.orderMenuCreate(getOrder);
+      } catch (error) {
+        print(error.message);
+      }
+    }
+
+    return order;
+  }
+}
+
+export default Controller;

리뷰: 접근제한을 두지 않으신 이유가 있으실까요?
@@ -0,0 +1,113 @@
+import Benefits from './domain/Benefits.js';
+import OrderMenu from './domain/OrderMenu.js';
+import {
+  BENEFITS_THRESHOLD,
+  GIFT_THRESHOLD,
+  MENU_PRICE,
+} from './utils/constants.js';
+
+const BADGE = {
+  산타: 20000,
+  트리: 10000,
+  별: 5000,
+};
+
+class Service {
+  #benefits;
+
+  #orderMenu;
+
+  benefitsCreate(date) {
+    this.#benefits = new Benefits(date);
+    return date;
+  }
+
+  orderMenuCreate(order) {
+    this.#orderMenu = new OrderMenu(order);
+    return order;
+  }
+
+  totalOrderPrice() {
+    const price = this.#orderMenu.totalOrderAmount();
+    return price;
+  }
+
+  // 혜택 내역
+  BenefitsDetails() {
+    const dessertCount = this.#orderMenu.dessertCount();
+    const mainCount = this.#orderMenu.mainCount();
+    const benefitsArray = [
+      [
+        this.#benefits.christmasDiscount(),
+        this.#benefits.weekdayDiscount(dessertCount),
+        this.#benefits.weekendDiscount(mainCount),
+        this.#benefits.specialDiscount(),
+      ],
+      [this.#giftEvent()],
+    ];
+
+    return benefitsArray;
+  }
+
+  // 증정 이벤트
+  #giftEvent() {
+    let giftDiscount = 0;
+
+    if (this.totalOrderPrice() >= GIFT_THRESHOLD) {
+      giftDiscount += MENU_PRICE.샴페인;
+    }
+    return ['증정 이벤트', giftDiscount];
+  }
+
+  // 총 혜택금액
+  totalBenefitsPrice() {
+    const BenefitsDetails = this.BenefitsDetails();
+
+    const totalBenefitsPrice = BenefitsDetails.reduce(
+      (acc, innerArray) =>
+        acc +
+        innerArray.reduce(
+          (total, [, discountAmount]) => total + discountAmount,
+          0,
+        ),
+      0,
+    );
+
+    return totalBenefitsPrice;
+  }
+
+  // 예상 결제 금액
+  calculatePayment() {
+    const totalPrice = this.totalOrderPrice();
+    const totalBenefitPrice = this.totalBenefitsPrice();
+
+    if (totalPrice < BENEFITS_THRESHOLD) {
+      return totalPrice;
+    }
+
+    return this.calculateEstimatedAmount(totalPrice, totalBenefitPrice);
+  }
+
+  calculateEstimatedAmount(totalPrice, totalBenefitPrice) {
+    if (totalPrice >= GIFT_THRESHOLD) {
+      const benefitPrice = totalBenefitPrice - MENU_PRICE.샴페인;
+      const payment = totalPrice - benefitPrice;
+      return payment;
+    }
+
+    const payment = totalPrice - totalBenefitPrice;
+    return payment;
+  }
+
+  calculateBadge() {
+    const totalBenefitPrice = this.totalBenefitsPrice();
+
+    const badge = Object.keys(BADGE).find(
+      (key) => totalBenefitPrice >= BADGE[key],
+    );
+
+    return badge;
+  }
+}
+
+export default Service;

리뷰: innerArray보다 다른 변수명으로 무슨 값을 의미하는지 나타내주시면 좋을 것 같아요.