ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,48 @@
+package christmas.domain;
+
+public enum Event {
+    NONE("없음", 0),
+    CHRISTMAS_D_DAY_DISCOUNT("크리스마스 디데이 할인", 1_000),
+    WEEKDAY_DISCOUNT("평일 할인", 2_023),
+    WEEKEND_DISCOUNT("주말 할인", 2_023),
+    SPECIAL_DISCOUNT("특별 할인", 1_000),
+    GIFT("증정 이벤트", 25_000);
+
+    private static final int BASE_AMOUNT_PER_DATE = 100;
+
+    private final String name;
+    private final int amount;
+
+    Event(String name, int amount) {
+        this.name = name;
+        this.amount = amount;
+    }
+
+    public int calculateTotalAmount(int count, Date date) {
+        if (this.equals(CHRISTMAS_D_DAY_DISCOUNT)) {
+            return getAmountOfDDayDiscount(date);
+        }
+
+        if (isOneTimeEvent()) {
+            return amount;
+        }
+
+        return count * amount;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getAmount() {
+        return amount;
+    }
+
+    private boolean isOneTimeEvent() {
+        return this.equals(SPECIAL_DISCOUNT) || this.equals(GIFT);
+    }
+
+    private int getAmountOfDDayDiscount(Date date) {
+        return CHRISTMAS_D_DAY_DISCOUNT.amount + (BASE_AMOUNT_PER_DATE * date.daysSince1Day());
+    }
+}

리뷰: 코드가 읽기 편해요!
@@ -0,0 +1,57 @@
+package christmas.domain;
+
+import christmas.exception.ExceptionMessage;
+import christmas.exception.InputException;
+import java.util.Arrays;
+
+public enum Menu {
+    MUSHROOM_CREAM_SOUP("양송이수프", 6_000, FoodType.APPETIZER),
+    TAPAS("타파스", 5_500, FoodType.APPETIZER),
+    CAESAR_SALAD("시저샐러드", 8_000, FoodType.APPETIZER),
+    T_BONE_STEAK("티본스테이크", 55_000, FoodType.MAIN),
+    BARBECUE_RIBS("바비큐립", 54_000, FoodType.MAIN),
+    SEAFOOD_PASTA("해산물파스타", 35_000, FoodType.MAIN),
+    CHRISTMAS_PASTA("크리스마스파스타", 25_000, FoodType.MAIN),
+    CHOCOLATE_CAKE("초코케이크", 15_000, FoodType.DESSERT),
+    ICE_CREAM("아이스크림", 5_000, FoodType.DESSERT),
+    ZERO_COLA("제로콜라", 3_000, FoodType.BEVERAGE),
+    RED_WINE("레드와인", 60_000, FoodType.BEVERAGE),
+    CHAMPAGNE("샴페인", 25_000, FoodType.BEVERAGE);
+
+    private final String name;
+    private final int price;
+    private final FoodType type;
+
+    Menu(String name, int price, FoodType type) {
+        this.name = name;
+        this.price = price;
+        this.type = type;
+    }
+
+    public static Menu findMenuByName(String name) {
+        return Arrays.stream(values())
+                .filter(value -> value.name.equals(name))
+                .findFirst()
+                .orElseThrow(() -> new InputException(ExceptionMessage.INVALID_ORDER));
+    }
+
+    public static boolean isBeverage(String name) {
+        return findMenuByName(name).type.equals(FoodType.BEVERAGE);
+    }
+
+    public boolean isDessert() {
+        return this.type.equals(FoodType.DESSERT);
+    }
+
+    public boolean isMain() {
+        return this.type.equals(FoodType.MAIN);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public int getPrice() {
+        return price;
+    }
+}

리뷰: Menu Enum에 FoodType Enum 을 가져와서 쓰시는 의도가 궁금합니다!
@@ -0,0 +1,19 @@
+package christmas.domain.discount;
+
+import christmas.domain.Date;
+import christmas.domain.Event;
+import christmas.domain.Orders;
+import java.util.List;
+
+public class GiftStrategy implements DiscountStrategy {
+    private static final int GIFT_BASE_AMOUNT = 120_000;
+
+    @Override
+    public List<Event> getShouldApplyEvents(Orders orders, Date date) {
+        if (orders.calculateTotalBeforeDiscount() >= GIFT_BASE_AMOUNT) {
+            return List.of(Event.GIFT);
+        }
+
+        return List.of(Event.NONE);
+    }
+}

리뷰: 인터페이스 활용 좋네요!
@@ -0,0 +1,9 @@
+package christmas.exception;
+
+public class InputException extends IllegalArgumentException {
+    public static final String PREFIX = "[ERROR] ";
+
+    public InputException(String message) {
+        super(PREFIX + message);
+    }
+}

리뷰: 저는 프로그램에서 발생하는 예외 처리 메소드를 한 패키지에 모아서 관리하고 있는데 어떻게 생각하실까요?
@@ -0,0 +1,72 @@
+package christmas.view;
+
+public class OutputView {
+    private static final String GREETING = "안녕하세요! 우테코 식당 12월 이벤트 플래너입니다.";
+    private static final String PREVIEW_TITLE = "12월 %d일에 우테코 식당에서 받을 이벤트 혜택 미리 보기!";
+    private static final String ORDERED_MENU = "<주문 메뉴>";
+    private static final String TOTAL_BEFORE_DISCOUNT = "<할인 전 총주문 금액>";
+    private static final String GIFT_MENU = "<증정 메뉴>";
+    private static final String BENEFIT_HISTORY = "<혜택 내역>";
+    private static final String TOTAL_BENEFIT = "<총혜택 금액>";
+    private static final String DISCOUNTED_TOTAL = "<할인 후 예상 결제 금액>";
+    private static final String EVENT_BADGE = "<12월 이벤트 배지>";
+
+    private OutputView() {
+    }
+
+    public static void printGreeting() {
+        print(GREETING);
+    }
+
+    public static void printPreviewTitle(int date) {
+        print(String.format(PREVIEW_TITLE, date));
+        printLineFeed();
+    }
+
+    public static void printOrderedMenu(String orders) {
+        print(ORDERED_MENU);
+        print(orders);
+    }
+
+    public static void printTotalBeforeDiscount(String amount) {
+        print(TOTAL_BEFORE_DISCOUNT);
+        print(amount);
+        printLineFeed();
+    }
+
+    public static void printGiftMenu(String menu) {
+        print(GIFT_MENU);
+        print(menu);
+        printLineFeed();
+    }
+
+    public static void printBenefitHistory(String history) {
+        print(BENEFIT_HISTORY);
+        print(history);
+    }
+
+    public static void printTotalBenefit(String amount) {
+        print(TOTAL_BENEFIT);
+        print(amount);
+        printLineFeed();
+    }
+
+    public static void printDiscountedTotal(String amount) {
+        print(DISCOUNTED_TOTAL);
+        print(amount);
+        printLineFeed();
+    }
+
+    public static void printEventBadge(String badge) {
+        print(EVENT_BADGE);
+        print(badge);
+    }
+
+    private static void print(String input) {
+        System.out.println(input);
+    }
+
+    private static void printLineFeed() {
+        System.out.println();
+    }
+}

리뷰: 해당 로직을 굳이 Enum으로 관리하지 않았는데도 가독성이 정말 좋네요!

인사이트 얻어갑니다!
@@ -0,0 +1,58 @@
+package christmas.domain;
+
+import christmas.exception.ExceptionMessage;
+import christmas.exception.InputException;
+import java.time.LocalDate;
+import java.time.format.TextStyle;
+import java.util.List;
+import java.util.Locale;
+
+public class Date {
+    private static final int MIN_DATE = 1;
+    private static final int MAX_DATE = 31;
+    private static final int OFFSET = 1;
+    private static final int CHRISTMAS = 25;
+    private static final String SUNDAY = "일";
+    private static final List<String> WEEKDAY = List.of(SUNDAY, "월", "화", "수", "목");
+
+    private final LocalDate date;
+
+    private Date(int date) {
+        validateRange(date);
+        this.date = LocalDate.of(2023, 12, date);
+    }
+
+    public static Date from(int date) {
+        return new Date(date);
+    }
+
+    public boolean isBetween1And25days() {
+        return getDay() <= CHRISTMAS;
+    }
+
+    public int daysSince1Day() {
+        return getDay() - OFFSET;
+    }
+
+    public boolean isSpecialDay() {
+        return getDay() == CHRISTMAS || getDayOfWeek().equals(SUNDAY);
+    }
+
+    public boolean isWeekday() {
+        return WEEKDAY.contains(getDayOfWeek());
+    }
+
+    public int getDay() {
+        return date.getDayOfMonth();
+    }
+
+    private String getDayOfWeek() {
+        return date.getDayOfWeek().getDisplayName(TextStyle.SHORT, Locale.KOREA);
+    }
+
+    private void validateRange(int date) {
+        if (date < MIN_DATE || date > MAX_DATE) {
+            throw new InputException(ExceptionMessage.INVALID_DATE);
+        }
+    }
+}

리뷰: "SUNDAY" 를 "일" 로 하지 않으신  이유가 있나요??
@@ -0,0 +1,61 @@
+package christmas.domain;
+
+import static christmas.Constants.BASE_COUNT;
+import static christmas.Constants.BLANK;
+import static christmas.Constants.COUNT;
+import static christmas.Constants.LINE_FEED;
+import static christmas.Constants.NONE;
+
+import christmas.exception.ExceptionMessage;
+import christmas.exception.InputException;
+
+public class Order {
+    private final Menu menu;
+    private final int count;
+
+    private Order(Menu menu, int count) {
+        validateCount(count);
+        this.menu = menu;
+        this.count = count;
+    }
+
+    public static Order of(String name, int count) {
+        return new Order(Menu.findMenuByName(name), count);
+    }
+
+    public int getTotalPrice() {
+        return menu.getPrice() * count;
+    }
+
+    public int getCountPerDessert() {
+        if (menu.isDessert()) {
+            return count;
+        }
+
+        return NONE;
+    }
+
+    public int getCountPerMain() {
+        if (menu.isMain()) {
+            return count;
+        }
+
+        return NONE;
+    }
+
+    public String getStringMenuAndCount() {
+        return new StringBuilder()
+                .append(menu.getName())
+                .append(BLANK)
+                .append(count)
+                .append(COUNT)
+                .append(LINE_FEED)
+                .toString();
+    }
+
+    private void validateCount(int count) {
+        if (count < BASE_COUNT) {
+            throw new InputException(ExceptionMessage.INVALID_ORDER);
+        }
+    }
+}

리뷰: 이건 OutputView  에서 해도 좋을것 같은데 어떻게 생각하시나요??
@@ -0,0 +1,36 @@
+package christmas.domain;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+public enum EventBadge {
+    NONE("없음", 0),
+    STAR("별", 5_000),
+    TREE("트리", 10_000),
+    SANTA("산타", 20_000);
+
+    private final String name;
+    private final int price;
+
+    EventBadge(String name, int price) {
+        this.name = name;
+        this.price = price;
+    }
+
+    public static EventBadge getEventBadge(int amount) {
+        return Arrays.stream(values())
+                .sorted(descendOrderByPrice())
+                .filter(badge -> badge.price <= Math.abs(amount))
+                .findFirst()
+                .orElse(NONE);
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    private static Comparator<EventBadge> descendOrderByPrice() {
+        return (o1, o2) -> o2.price - o1.price;
+    }
+
+}

리뷰: 정말  깔끔하네요!!
@@ -0,0 +1,17 @@
+package christmas.domain.discount;
+
+import christmas.domain.Date;
+import christmas.domain.Event;
+import christmas.domain.Orders;
+import java.util.List;
+
+public class DDayStrategy implements DiscountStrategy {
+    @Override
+    public List<Event> getShouldApplyEvents(Orders orders, Date date) {
+        if (date.isBetween1And25days()) {
+            return List.of(Event.CHRISTMAS_D_DAY_DISCOUNT);
+        }
+
+        return List.of(Event.NONE);
+    }
+}

리뷰: 전략 패턴 사용하셨네요! 👍👍
@@ -21,6 +21,7 @@ package
 		{
 			if (_instance)
 			{
+                // NOTE throw 시켜놓고 catch 안해주면 어떻게 될까요?
 				throw new Error("Use getInstance().");
 			} 
 			_instance = this;

리뷰: 사실 여기서 throw가 날 가능성은 거의 없어보입니다만...
바깥에 try catch 처리를 하지 않은 채로 throw가 발생해버리면 
어떻게 될까요?
@@ -0,0 +1,44 @@
+package subway.service;
+
+import static subway.domain.RouteInfo.calculateTotalDistance;
+import static subway.domain.RouteInfo.calculateTotalTime;
+import static subway.domain.RouteInfo.values;
+
+import java.util.List;
+import org.jgrapht.GraphPath;
+import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.WeightedMultigraph;
+import subway.domain.Result;
+import subway.domain.RouteInfo;
+import subway.domain.Station;
+
+public class MinimumTimeService {
+    public Result calculate(Station start, Station end) {
+        WeightedMultigraph<String, DefaultWeightedEdge> graph = createGraph(values());
+
+        DijkstraShortestPath<String, DefaultWeightedEdge> dijkstraShortestPath =
+                new DijkstraShortestPath<>(graph);
+
+        GraphPath<String, DefaultWeightedEdge> shortestPath =
+                dijkstraShortestPath.getPath(start.getName(), end.getName());
+
+        List<DefaultWeightedEdge> edges = shortestPath.getEdgeList();
+
+        int totalDistance = calculateTotalDistance(graph, edges);
+        int totalTime = calculateTotalTime(graph, edges);
+
+        return Result.createResult(totalDistance, totalTime, shortestPath.getVertexList());
+    }
+
+    private WeightedMultigraph<String, DefaultWeightedEdge> createGraph(RouteInfo[] routeInfos) {
+        WeightedMultigraph<String, DefaultWeightedEdge> graph =
+                new WeightedMultigraph<>(DefaultWeightedEdge.class);
+
+        for (RouteInfo routeInfo : routeInfos) {
+            routeInfo.calculateMinimumTime(graph, routeInfo);
+        }
+
+        return graph;
+    }
+}
\ No newline at end of file

리뷰: 오호!! 객체 생성하는 코드를 분리시켰군요!! 배워갑니다..!!
@@ -0,0 +1,59 @@
+package subway.view.Input;
+
+import subway.validation.EndStationValidation;
+import subway.validation.MainFunctionValidation;
+import subway.validation.SelectRouteValidation;
+import subway.validation.StartStationValidation;
+
+public class InputView {
+    private final MainFunctionValidation mainFunctionValidation;
+    private final SelectRouteValidation selectRouteValidation;
+    private final StartStationValidation startStationValidation;
+    private final EndStationValidation endStationValidation;
+
+    public InputView(MainFunctionValidation mainFunctionValidation, SelectRouteValidation selectRouteValidation,
+                     StartStationValidation startStationValidation, EndStationValidation endStationValidation) {
+        this.mainFunctionValidation = mainFunctionValidation;
+        this.selectRouteValidation = selectRouteValidation;
+        this.startStationValidation = startStationValidation;
+        this.endStationValidation = endStationValidation;
+    }
+
+    public String readMainFunc(String input) {
+        return mainFunctionValidate(input);
+    }
+
+    public String readSelectRoute(String input) {
+        return selectRouteValidate(input);
+    }
+
+    public String readStartStation(String input) {
+        return startStationValidate(input);
+    }
+
+    public String readEndStation(String start, String input) {
+        return endStationValidate(start, input);
+    }
+
+    private String mainFunctionValidate(String input) {
+        mainFunctionValidation.isBlank(input);
+        return mainFunctionValidation.isOneOrQ(input);
+    }
+
+    private String selectRouteValidate(String input) {
+        selectRouteValidation.isBlank(input);
+        return selectRouteValidation.isOneOrTwoOrB(input);
+    }
+
+    private String startStationValidate(String input) {
+        startStationValidation.isBlank(input);
+        return startStationValidation.isRegister(input);
+    }
+
+    private String endStationValidate(String start, String input) {
+        endStationValidation.isBlank(input);
+        endStationValidation.isRegister(input);
+        return endStationValidation.isDuplicate(start, input);
+    }
+}
+

리뷰: 이미 isBlank메소드가 static으로 할당되어있기때문에 mainFunctionValidation.isBlank가 아닌, MainFunctionValidation.isBlank로 하는게 더 적합할 것 같습니다!
@@ -0,0 +1,30 @@
+package store.contant;
+
+public enum Constant {
+    PRODUCTS_FILE_PATH("./src/main/resources/products.md"),
+    PROMOTIONS_FILE_PATH("./src/main/resources/promotions.md"),
+
+    Y("Y"),
+    N("N"),
+
+    YEAR("year"),
+    MONTH("month"),
+    DAY("day"),
+
+    DEFAULT_DELIMITER("-"),
+    COMMA_DELIMITER(","),
+
+    ITEM_DELIMITER("\\[(.*?)]"),
+    DATE_DELIMITER("(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})");
+
+    private final String detail;
+
+    Constant(String detail) {
+        this.detail = detail;
+    }
+
+    @Override
+    public String toString() {
+        return detail;
+    }
+}

리뷰: 저는 몰랐던 정규표현식 문법이라 찾아보니까 named capturing group 이라고 하는군요.. 새로운거 배워갑니다!
@@ -0,0 +1,14 @@
+package store.exception;
+
+public class CustomException extends IllegalArgumentException {
+    private final String errorMessage;
+
+    public CustomException(String errorMessage) {
+        super(errorMessage);
+        this.errorMessage = errorMessage;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+}

리뷰: CustomException 클래스를 따로 만드신 이유가 궁금합니다 (이 부분은 잘 몰라서).
@@ -0,0 +1,57 @@
+package store.view;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import store.contant.Constant;
+import store.dto.BuyDTO;
+import store.exception.CustomException;
+import store.exception.ErrorMessage;
+
+public class InputHandler {
+    private static final Pattern patternItem = Pattern.compile(Constant.ITEM_DELIMITER.toString());
+    private static final Pattern patternDate = Pattern.compile(Constant.DATE_DELIMITER.toString());
+
+    public static List<BuyDTO> splitItems(String input) {
+        Matcher matcher = patternItem.matcher(input);
+        return matcher.results()
+                .map(find -> {
+                    String content = find.group(1);
+                    validate(content);
+                    String[] item = split(content);
+                    return new BuyDTO(item[0], toInt(item[1]));
+                })
+                .toList();
+    }
+
+    private static void validate(String input) {
+        if (input.contains("[") || input.contains("]")) {
+            throw new CustomException(ErrorMessage.NOT_FIT_THE_FORM_MESSAGE.toString());
+        }
+    }
+
+    public static LocalDateTime parseDate(String input) {
+        Matcher matcher = patternDate.matcher(input);
+        if (matcher.matches()) {
+            int year = Integer.parseInt(matcher.group(Constant.YEAR.toString()));
+            int month = Integer.parseInt(matcher.group(Constant.MONTH.toString()));
+            int day = Integer.parseInt(matcher.group(Constant.DAY.toString()));
+            return LocalDate.of(year, month, day).atStartOfDay();
+        }
+        throw new CustomException(ErrorMessage.FILE_IOEXCEPTION_MESSAGE.toString());
+    }
+
+    public static int toInt(String input) {
+        try {
+            return Integer.parseInt(input);
+        } catch (NumberFormatException e) {
+            throw new CustomException(ErrorMessage.NOT_FIT_THE_FORM_MESSAGE.toString());
+        }
+    }
+
+    private static String[] split(String input) {
+        return input.split(Constant.DEFAULT_DELIMITER.toString());
+    }
+}

리뷰: Matcher.results()로 나누는건 깔끔하지만 품목을 나누는 구분자로 쉼표가 아니어도 작동해서, 요구사항에 맞추려면 수정해야 할 것 같아요.
@@ -0,0 +1,83 @@
+package store.view;
+
+import camp.nextstep.edu.missionutils.Console;
+import java.util.List;
+import store.contant.Constant;
+import store.dto.BuyDTO;
+import store.exception.CustomException;
+import store.exception.ErrorMessage;
+
+public class InputView {
+    public static List<BuyDTO> readItem() {
+        while (true) {
+            try {
+                System.out.println(InputMessage.INPUT_PURCHASE_PRODUCT_MESSAGE);
+                return InputHandler.splitItems(Console.readLine());
+            } catch (CustomException e) {
+                System.out.println(e.getErrorMessage());
+            }
+        }
+    }
+
+    public static String readMembership() {
+        while (true) {
+            try {
+                System.out.println(InputMessage.INPUT_MEMBERSHIP_MESSAGE);
+                String input = Console.readLine();
+                validate(input);
+                return input;
+            } catch (CustomException e) {
+                System.out.println(e.getErrorMessage());
+            }
+        }
+    }
+
+    public static String readPromotion(String name, int quantity) {
+        while (true) {
+            try {
+                System.out.printf(InputMessage.INPUT_PROMOTION_MESSAGE.format(name, quantity));
+                String input = Console.readLine();
+                validate(input);
+                return input;
+            } catch (CustomException e) {
+                System.out.println(e.getErrorMessage());
+            }
+        }
+    }
+
+    public static String readGetOneFree(String name, int quantity) {
+        while (true) {
+            try {
+                System.out.printf(InputMessage.INPUT_GET_ONE_FREE_MESSAGE.format(name, quantity));
+                String input = Console.readLine();
+                validate(input);
+                return input;
+            } catch (CustomException e) {
+                System.out.println(e.getErrorMessage());
+            }
+        }
+    }
+
+    public static String readRePurchase() {
+        while (true) {
+            try {
+                System.out.println(InputMessage.INPUT_RE_PURCHASE_MESSAGE);
+                String input = Console.readLine();
+                validate(input);
+                return input;
+            } catch (CustomException e) {
+                System.out.println(e.getErrorMessage());
+            }
+        }
+    }
+
+    private static void validate(String input) {
+        if (isCorrectInput(input)) {
+            throw new CustomException(ErrorMessage.INVALID_INPUT_MESSAGE.toString());
+        }
+    }
+
+    private static boolean isCorrectInput(String input) {
+        return !(input.equals(Constant.Y.toString()) || input.equals(Constant.N.toString()));
+    }
+}

리뷰: validate() 네이밍이 조금 더 구체적이면 좋을 것 같습니다.
@@ -0,0 +1,35 @@
+package store.dto;
+
+import java.util.List;
+
+public record ReceiptDTO(
+        List<PurchaseDTO> cart,
+        List<PurchaseDTO> free
+) {
+    public int getTotalQuantity() {
+        return cart.stream()
+                .mapToInt(PurchaseDTO::quantity)
+                .sum();
+    }
+
+    public int getTotalAmount() {
+        return cart.stream()
+                .mapToInt(PurchaseDTO::getTotalAmount)
+                .sum();
+    }
+
+    public int getFreeAmount() {
+        return free.stream()
+                .mapToInt(PurchaseDTO::getTotalAmount)
+                .sum();
+    }
+
+    public int getMembershipAmount(boolean isMembership) {
+        if (isMembership) {
+            return (int) (cart.stream()
+                                .mapToInt(PurchaseDTO::getNotApplyAmount)
+                                .sum() * 0.3);
+        }
+        return 0;
+    }
+}

리뷰: 0.3은 중요한 숫자라 상수로 바꾸면 좋을 것 같습니다!
@@ -0,0 +1,41 @@
+package com.example.firstproject.controller;
+
+import com.example.firstproject.service.ArticleService;
+import com.example.firstproject.service.BoardService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.*;
+
+
+@Controller
+@RequiredArgsConstructor
+@RequestMapping("boards")
+public class BoardController {
+
+    private final BoardService boardService;
+    private final ArticleService articleService;
+
+
+    @GetMapping
+    public String readAllBoard(Model model){
+        model.addAttribute("boards", boardService.readAllBoard());
+        return "board/home";
+    }
+
+
+    @GetMapping("{boardId}")
+    public String readBoard(@PathVariable("boardId") Long id, Model model) {
+        model.addAttribute("board", boardService.read(id));
+        model.addAttribute("articles", boardService.readByBoardId(id));
+        return "board/board";
+    }
+
+    // "전체 게시판"
+    @GetMapping("/entire-board")
+    public String entireBoard(Model model) {
+        model.addAttribute("articles", boardService.readAll());
+        return "board/entireBoard";
+    }
+
+}

리뷰: / 슬래시의 유무에 따른 차이점을 함께 공부해봅시다
@@ -0,0 +1,15 @@
+package config;
+
+import controller.UserController;
+import service.UserJoinService;
+
+public class AppConfig {
+
+    public static UserController userController() {
+        return new UserController(userJoinService());
+    }
+
+    public static UserJoinService userJoinService() {
+        return new UserJoinService();
+    }
+}

리뷰: AppConfig로 DI를 주입해주려는 시도👍