Search
Duplicate

2. [클린 코드 with Java] 2단계 - 2단계 - 사다리(생성)

링크
점수
⭐️⭐️⭐️⭐️
완료일
2023/05/19
상태
완료
유형
인강

기능 요구사항

사다리 게임에 참여하는 사람에 이름을 최대5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다.
사람 이름은 쉼표(,)를 기준으로 구분한다.
사람 이름을 5자 기준으로 출력하기 때문에 사다리 폭도 넓어져야 한다.
사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다.
|-----|-----| 모양과 같이 가로 라인이 겹치는 경우 어느 방향으로 이동할지 결정할 수 없다.

프로그래밍 요구사항

자바 8의 스트림과 람다를 적용해 프로그래밍한다.
규칙 6: 모든 엔티티를 작게 유지한다.

실행 결과

위 요구사항에 따라 4명의 사람을 위한 5개 높이 사다리를 만들 경우, 프로그램을 실행한 결과는 다음과 같다.
참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요) pobi,honux,crong,jk 최대 사다리 높이는 몇 개인가요? 5 실행결과 pobi honux crong jk |-----| |-----| | |-----| | |-----| | | | |-----| | |-----| |-----|
Plain Text
복사

피드백

리뷰어 : 생성자에서 많은 역할을 하고 있는건 아닌지 고민해보시면 좋을 것 같아요 개인적으로 생성자의 실행 코드는 객체를 생성하면서 즉시 실행되기 때문에 코드가 많아질 수록 절차 지향과 가까워 진다고 생각되는데 혹시 어떻게 생각하시나요??  제가 고민하고 참고했던 내용 남겨드리겠습니다!
public Line(int countOfPerson) { int rangeEnd = countOfPerson - 1; IntStream.range(RANGE_START, rangeEnd) .forEach(count -> { if (count == ZERO || !points.get(count - 1)) { connectLine(() -> RANDOM.nextBoolean()); return; } connectLine(() -> false); }); }
Java
복사
생각정리 : 위에 해당하는 글은 좋은 글이라고 생각된다. 전달 주신 엘레강트 오브젝트 라는 책도 읽어봐야 겟다. 정리하자면
생성자에서 너무 많은 일을 하게되면 생성 할때 마다 매번 생성자에 있는 동작을 진행해야되고, cpu 시간을 소모해야 된다.
생성자 안에 있는 동작이 필요하지 않을경우 제어하기가 힘들다. 함수로 해당하는 동작을 따로 둔다면, 필요할 때 사용하고 언제든지 나의 바운더리 안에서 변경이 가능하다.
가벼운 생성자는 설정하기 쉽고 투명하게 사용할수 있기 때문에 객체를 더 빠르게 만들수 있다.
void calculatorLine(int countOfPerson) { int rangeEnd = countOfPerson - 1; IntStream.range(RANGE_START, rangeEnd) .forEach(count -> { if (count == ZERO || !points.get(count - 1)) { connectLine(() -> RANDOM.nextBoolean()); return; } connectLine(() -> false); }); }
Java
복사
또한 이 부분이 인터페이스로 따로 필요한건지도 고민해보시면 좋을 것 같아요.오버 엔지니어링이 된건 아닌지, 그게 아니라면 라이브러리에 있는 Supplier 를 이용해도 좋을 것 같은데 혹시 어떠신가요??이 부분도 제가 참고한 자료 남겨드리겟습니다!!
package ladder.domain.model.Param; public interface BaseParam { Object convertParamToModel(); } public class LadderHeightParam implements BaseParam { private static int MINIMUM_HEIGHT = 1; private int height; public LadderHeightParam(int height) { if (isHeightNegative(height)) { throw new LadderHeightArgumentException("비어 있거나 잘못된 값을 입력하였습니다."); } this.height = height; } private boolean isHeightNegative(int height) { return height < MINIMUM_HEIGHT; } }
Java
복사
생각정리 : 굳이 interface 를 쓰면서 까지 구현 할 필요가 없을 것 같았는데, 공통이라고 생각하다보니 사용하게 되었다.
Object를 사용한 것은 전달받은 객체라 여러가지 리턴 받아서 사용하게되었는데, 제너릭을 사용해서 푸는것이 더 안전하고 깔끔하다는 것을 알 았다.
package ladder.domain.model.Param; import ladder.domain.model.LadderHeight; import ladder.exception.LadderHeightArgumentException; import java.util.function.Supplier; public class LadderHeightParam { private static int MINIMUM_HEIGHT = 1; private int height; public LadderHeightParam(int height) { if (isHeightNegative(height)) { throw new LadderHeightArgumentException("비어 있거나 잘못된 값을 입력하였습니다."); } this.height = height; } private boolean isHeightNegative(int height) { return height < MINIMUM_HEIGHT; } public LadderHeight convertParamToModel() { Supplier<LadderHeight> supplier = () -> new LadderHeight(height); return supplier.get(); } }
Java
복사
Param 이라는 객체가 뷰에서 dto 처럼 사용되고 있는 것 같아요  그런데 모델을 만들기 위해 과도하게 비즈니스 로직이 실행되고 있는 건 아닌지 고민해보시면 좋을 것 같아요  혹시 이 부분에 대해 어떻게 생각하시나요?
package ladder.domain.model.Param; import ladder.Utils; import ladder.domain.model.PlayerName; import ladder.domain.model.PlayerNames; import ladder.exception.PlayerCountArgumentException; import ladder.exception.PlayerNameArgumentException; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; public class PlayerNamesParam { private static final String DELIMITER = ","; private static final String TRIM = " "; private static final int MINIMUM_NUMBER_OF_PEOPLE = 2; private static final int MAX_NAME_SIZE = 5; private String playersName; public PlayerNamesParam(String playersName) { if (playersName.isEmpty()) { throw new PlayerNameArgumentException("비어 있는 값을 입력하였습니다."); } this.playersName = playersName; } public PlayerNames convertParamToModel() { List<String> playersNames = Arrays.stream(playersName.replaceAll(TRIM, "") .split(DELIMITER)).collect(Collectors.toList()); if (isSmallerThanMinimum(playersNames.size())) { throw new PlayerCountArgumentException("최소인원 보다 작습니다."); } playersNames = Utils.fillOrRightAlign(playersNames); List<String> finalPlayersNames = playersNames; return new PlayerNames(finalPlayersNames.stream() .map(name -> new PlayerName(name)) .collect(Collectors.toList())); } boolean isSmallerThanMinimum(int count) { return count < MINIMUM_NUMBER_OF_PEOPLE; } List<String> fillOrRightAlign(List<String> playersNames) { return playersNames.stream() .map(name -> name.length() < MAX_NAME_SIZE ? String.format("%5s", name) : name) .collect(Collectors.toList()); } }
Java
복사
생각정리 이부분은 전달 받은 값을 객체로 변경하는 것인데, 너무 많은 기능을 첨부한 것인가?.. 어느 부분에서 과도한 스팩인지 궁금하여서, 물어보게되었다. 답변이 오면 정리하도록 하겠다.
리뷰어 : 저도 오버엔지니어링에 대한 기준은 고민되는 부분 같습니다  다만
1.
특별한 검증없이 한 가지의 데이터를 담기 위해 클래스가 자료구조처럼 사용되고 있는지
2.
특정 객체의 메소드를 호출만 하는 메소드가 분리가 되어 있는지
3.
같은 역할의 객체가 여러번 생성되지는 않았는지
4.
과한 추상화로 인해 사용되지 않는 인자나 상태가 존재하는지
5.
도메인 역할이 아닌 뷰나 컨트롤러 영역까지 추상화가 고려되고 있는 건 아닌지
현재는 생각나는건 이 정도 체크하는 것 같은데 개인 편차가 클 수 있기 때문에 참고만 해주시고 편하게 생각해주시면 감사하겠습니다
생각정리 : 위에 전달해준 내용을 토대로 생각하고, 구현해보자!
깃허브 링크 :
pulls?q=is%3Apr+author%3A%40me+is%3Aclosed
java-ladder
출처