Skip to content

[사다리 - 함수형 프로그래밍] 고건 미션 제출#86

Merged
boorownie merged 4 commits intonext-step:gopistolfrom
Gopistol:step4
Feb 14, 2026
Merged

[사다리 - 함수형 프로그래밍] 고건 미션 제출#86
boorownie merged 4 commits intonext-step:gopistolfrom
Gopistol:step4

Conversation

@Gopistol
Copy link

@Gopistol Gopistol commented Feb 10, 2026

🚀 1단계 - 사다리 출력

🚀 2단계 - 사다리 생성

필요한 객체

  • 한 row에서 연결 여부를 가진 Line 객체

  • Line들을 가진 Ladder 객체

  • 연결 여부를 결정할 때 한 Line의 연결 인덱스를 랜덤으로 설정해주는 객체

  • 연결되어있으면 "-----", 안되어있으면 "공백 5개" 출력

  • 출력은 output 객체가 담당

랜덤 인덱스 뽑는 방식

  • 확률을 정해놓고, 해당 확률에 따라 다리를 놓을지 결정
    • 해당 확률을 RandomLineIndexGenerator가 알고 있어도 괜찮을까 고민했습니다.

🚀 3단계 - 사다리 타기

고민

  • Ladder 객체가 시작 지점과 도착 지점을 탐색할 수 있어야 하는가?
    • 도메인 행위에 포함되는지
    • Ladder 자체가 사다리이므로, 자신이 가지고 있는 좌표값들 안에서 탐색할 수 있어도 괜찮을 것 같다고 생각했습니다.

🚀 4단계 - 게임 실행

가정사항

  • 네이버 사다리 타기 게임에서는 이름이 중복된 경우에 대한 제약이 없지만, 결과를 보고 싶은 사람을 입력받아야 하므로
    중복인 경우를 배제해야 한다고 생각했습니다.

  • 이름으로 결과를 알고 싶을 때, "q"를 누르거나 전체 결과를 보면 반복이 끝나도록 했습니다.

고민사항

  • 사다리 결과를 보고 싶은 사람, 전체 결과 출력 등의 조건을 분기하는 과정에서 메소드를 자꾸 쪼개며 흐름이 읽히지 않는다고 생각했습니다

  • 로직 구현에 필요한 데이터를 가지는 객체를 분리해보려고 생각했습니다.

  • 기존 List names, results -> Players와 Rewards 객체로 분리

  • 컨트롤러에서 조립하던 Ladder를 LadderFactory의 책임으로 분리 + 생성 시 사다리 높이 검증

  • 게임 참여자와 결과 개수를 검증하는 헬퍼 메소드 -> LadderGameRules에서 검증

Copy link

@jhan0121 jhan0121 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 고건님~
이번 사다리 미션 리뷰를 맡은 이주환입니다! 사정이 변경되어서 제가 리뷰를 맡게 되었습니다! 😄

사다리 미션 고생 많으셨어요! 어려우셨을 것 같은데 잘 구현해주셨네요! 몇 가지 코멘트 남겨두었으니 확인 부탁드려요~!

그런데 테스트 코드를 작성하지 않으셨는데 작성하지 않으신 이유가 있으신지 궁금해요!

이번 step은 몇 가지 보완하시면 될 정도로 미션 목표는 어느정도 달성하셨다고 생각해서 기능 실행이 정상적으로 동작하지 않는 부분과 간단한 테스트 코드 추가해주시면 다음 step으로 넘어가겠습니다!

Comment on lines 11 to 20
public static void main(String[] args) {
LineIndexGenerator lineIndexGenerator = new RandomLineIndexGenerator(new Random());
LadderFactory ladderFactory = new LadderFactory(lineIndexGenerator);

InputView inputView = new InputView();
OutputView outputView = new OutputView();

new LadderController(ladderFactory, inputView, outputView)
.run();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실행 결과를 확인해보니 전체적으로 잘 출력되는데 "사다리 결과" 출력 부분이 맞지 않네요...! 줄맞춤 부분은 어렵다면 넘어가도 괜찮아요! 사다리 도착지에서 입력 순서대로 출력되지 않고 있는 것 같은데 출력 문제를 해결해볼까요?

Image

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존에 이미 playResult의 결과를 순서대로 출력하던 것 같아 입력 순서대로 출력하도록 변경했습니다!
줄맞춤 부분도 각 글자 수의 자릿수를 5칸으로 가정하여 부족한 만큼 공백을 추가하는 방식으로 맞춰보겠습니다

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다!! 출력 포맷팅이 더 깔끔해졌네요! 👍

README.md Outdated
Comment on lines 18 to 19
- 확률을 정해놓고, 해당 확률에 따라 다리를 놓을지 결정
- 해당 확률을 RandomLineIndexGenerator가 알고 있어도 괜찮을까?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 고민이네요!! 👍 기능 요구 사항에 "사다리 분기 비율이나 분기 갯수를 입력받을 수 있다"고 명시되어 있지는 않았었지만 시간 여유가 있으시다면 나중에 요구 사항이 추가된다면 어떻게 변경하면 좋을 지 생각해봐도 좋을 것 같네요!!

Copy link
Author

@Gopistol Gopistol Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말씀하신 것처럼 분기 비율을 RandomLineIndexGenerator에서 주입받아 생성해보는 방식이 있을 것 같습니다! 수정해보겠습니다. 다만 사용자가 저 비율을 입력받는 것이 사다리 게임을 진행하는 사용자 입장에서 고려할 사항이 아니라고 생각하여, 별도의 정책 클래스로 분리하여 주입하는 방식으로 수정해보겠습니다.

int height = readLadderHeight();

Ladder ladder = ladderFactory.create(height, players.size());
PlayerResults playerResults = PlayerResults.from(ladder, players, rewards);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파라미터가 하나면 from을, 여러개면 of를 사용합니다! 헷갈리기 쉽더라구요~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여러 개인 경우에 대한 컨벤션을 헷갈렸네요 수정하겠습니다!

Comment on lines 68 to 74
if (nameForResult.equals("q")) {
return false;
}
if (nameForResult.equals("all")) {
outputView.printAllResult(playerResults.findAllResults());
return false;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Players 객체에서도 qall을 사용하고 있는데, 관리 포인트가 분리되어 있는 문제를 어떻게 해결할 수 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q와 all 등의 금지어를 담은 상수 관리 클래스를 만들어 한 번에 관리할 수 있도록 수정하겠습니다.

List<Line> lines = new ArrayList<>();

for (int i = 0; i < height; i++) {
List<Integer> randomIndexes = lineIndexGenerator.generate(playerCount);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 기능에서 "랜덤"이라는 맥락이 필요한지 궁금해요! 상세 구현에 의존하지 않도록 수정해볼까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RandomLineIndexGenerator의 랜덤을 추상화하려고 LineIndexGenerator를 만들었는데, 저기서 랜덤이라는 맥락을 보여줄 이유가 없을 것 같습니다. 수정하겠습니다.


public record Line(List<Boolean> points) {

public static Line fromRandomIndex(List<Integer> indexes, int size) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메서드명에 "랜덤"이라는 컨텍스트가 필요한지 궁금해요~ 더 적절한 이름으로 변경해볼까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

정적 팩토리 메서드 컨벤션을 고려하여 of로 변경하였습니다

.toList();
}

public static PlayerResults from(Ladder ladder, Players players, Rewards rewards) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 정적 팩토리 메서드 컨벤션을 맞춰볼까요~


import java.util.List;

public record Ladder(List<Line> lines) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

레코드를 사용하셨군요! 일반 클래스와 record의 차이점은 무엇이 있을까요? LadderLine에 record를 사용하신 이유가 궁금해요!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

record는 일반 클래스에서의 필드를 final로 자동으로 만들어주고, 생성자와 getter와 equals, toString 등을 자동 생성해줍니다.

Ladder와 Line에 record를 사용한 이유는, 해당 객체가 불변임을 고정해두고 값을 가지는 객체로써 쓰이기 자연스럽다고 생각해서 사용했습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

record에 대해서 잘 정리해주셨네요 😄 이후에 여유가 되신다면 record를 사용할 때 주의해야 할 점이나 한계점은 무엇이 있는지 학습해보시는 것도 추천드려요!

README.md Outdated
Comment on lines 29 to 31
- Ladder 객체가 시작 지점과 도착 지점을 탐색할 수 있어야 하는가?
- 도메인 행위에 포함되는지
- Ladder 자체가 사다리이므로, 자신이 가지고 있는 좌표값들 안에서 탐색할 수 있어도 괜찮을 것 같다고 생각했습니다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋은 고민이네요! 👍 이미 많은 고민을 하신 것 같아서 제 생각을 바로 공유드릴게요~

저도 Ladder에서 "시작 지점과 도착 지점을 탐색"하는 책임을 가지고 있는 것이 좋다고 생각이 드네요...! "특정 시작점에서 도착지가 어디인지 물어볼 수 있는 전문가가 누구인가?"를 생각해보면 모든 분기 정보를 모두 가지고 있기 때문에 적절한 판단이라고 생각해요~

Comment on lines 46 to 51
private static void validateForbiddenPlayerName(List<String> names) {
if (names.stream()
.anyMatch(FORBIDDEN_PLAYER_NAMES::contains)) {
throw new DomainRuleViolationException("q, all은 참가자 이름으로 사용할 수 없습니다.");
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 메서드는 사용되고 있지 않네요! 의도한 사항이신지 궁금해요~

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate 메소드에서 한 번에 검증하려고 추가했는데 놓친 것 같습니다. 사용하도록 수정하겠습니다.

@Gopistol Gopistol requested a review from jhan0121 February 13, 2026 19:03
Copy link

@jhan0121 jhan0121 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요! 리뷰 반영 고생 많으셨어요!!
리뷰 반영 잘 해주셨네요~ 코멘트 몇 개 남겼는데 다음 step에서 같이 고려해도 좋을 것 같아서 머지하겠습니다! 다음 step도 화이팅이에요!! 👍


import java.util.List;

public record Ladder(List<Line> lines) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

record에 대해서 잘 정리해주셨네요 😄 이후에 여유가 되신다면 record를 사용할 때 주의해야 할 점이나 한계점은 무엇이 있는지 학습해보시는 것도 추천드려요!

Comment on lines +5 to +13
public final class QueryCommand {

public static final String QUIT = "q";
public static final String ALL = "all";
public static final Set<String> FORBIDDEN_PLAYER_NAMES = Set.of(QUIT, ALL);

private QueryCommand() {
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 클래스는 상수값을 저장하는 역할을 수행하고 있는 상황이네요! 일반 class보다 enum 객체가 더 적절할 것 같은데 일반 클래스로 구성하신 배경이 궁금해요! 만약 상수값 관리만 필요하다면 enum으로 관리해볼까요?

Comment on lines +3 to +9
public final class LadderPolicy {

public static final double DEFAULT_BRIDGE_PROBABILITY = 0.35;

private LadderPolicy() {
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 상수만 존재하는 클래스로 보이는데 enum을 사용하지 않으신 의도가 있으셨는지 궁금해요! 만약 상수값 관리만을 원하는 객체라면 enum을 활용하도록 변경해볼까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum 클래스를 사용하는 게 상수값 관리에 더욱 효율적인 것 같습니다. 변경하여 리팩토링해보겠습니다

Comment on lines 11 to 20
public static void main(String[] args) {
LineIndexGenerator lineIndexGenerator = new RandomLineIndexGenerator(new Random());
LadderFactory ladderFactory = new LadderFactory(lineIndexGenerator);

InputView inputView = new InputView();
OutputView outputView = new OutputView();

new LadderController(ladderFactory, inputView, outputView)
.run();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋습니다!! 출력 포맷팅이 더 깔끔해졌네요! 👍

Comment on lines 66 to 71
### 태스트코드

- Players
- 참여자 수가 1명보다 작으면 DomainRuleViolationException 예외를 반환한다.
- 이름 컨벤션이 맞지 않으면 DomainRuleViolationException 예외를 반환한다.
- 참여자 이름으로 q, all이 입력되면 DomainRuleViolationException 예외를 반환한다.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

테스트 케이스가 무엇이 있는지 한눈에 볼 수 있어서 좋네요! 👍

@boorownie boorownie merged commit 59a4fb6 into next-step:gopistol Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments