-
Notifications
You must be signed in to change notification settings - Fork 415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[또링] 체스 4~5단계 미션 제출합니다. #154
Conversation
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
또링 코드 깔끔하게 잘 작성하셨어요
board 데이터를 가져와서 처리하기 위한 부분을 조금 다듬어보면 좋을 것 같네요
피드백 반영해보시고 궁금한 점 생기면 코멘트 남기거나 dm 주세요
1. Board 클래스 내에 어느 부분을 말하는걸까요? getRanks 메서드 말고 출력을 위한 기능이 안보여서 질문을 잘 파악 못했어요; BoardConverter 부분 말하는걸까요?제가 너무 질문을 이상하게 한 것 같네요..! private static void printRank(List<Piece> rank) {
for (int i = MIN_COLUMN_COUNT; i <= MAX_COLUMN_COUNT; i++) {
final int columnNumber = i;
String pieceSymbol = rank.stream()
.filter(p -> p.equalsColumn(columnNumber))
.map(Piece::showSymbol)
.findFirst()
.orElse(EMPTY_CELL_SYMBOL);
System.out.print(pieceSymbol);
}
System.out.println();
} 이런 함수도 OutputView에서 처리하는 게 아닌, Rank의 한 가지 기능(빈 부분을 empty symbol로 채워주어 리턴하는 기능)이라고 보고, Rank에 해당 메서드를 추가할 수 있을지가 궁금했습니다. 여기부터는 위와 관련된 저의 생각들입니다..!
-> 사실 구구님이 처음에 제안해주신 부분(위의 첫 문장)은 다른 크루들과 이야기를 나누며 지금은 조금 정리가 되었습니다. -> 하지만 제가 제시한 경우(위의 두번째 문장)에도 마찬가지로 적용될 수 있을지는 아직 생각이 정리되지 않았습니다. 처음 코드를 구현할 때에는 아래와 같은 이유로 OutputView에 해당 메서드를 넣어주었습니다.
하지만 웹이 추가되고 나서 빈 자리를 알아야하는 상황이 발생하였고, OutputView의 printRank가 거의 비슷하게 재작성되는 일이 발생했습니다. 이런 상황에서, 여러가지 뷰/클라이언트에서 해당 기능이 필요하다는 것은 곧 domain이 갖고있어도 마땅한 기능이라고 생각하면 되는 걸까요? 물론 여러 프로그램을 구현해보면서 저만의 생각을 정리해나가야겠지만 조금 혼란스러워서 드렸던 질문입니다..!😊 2. Score, Rank 클래스로 계산 로직이 각각 있는 것도 문제네요. board에서 getRank해서 Score에 넘기지 말고 board에서 아예 piece 리스트를 전달하면 계산 로직을 score로 모을 수 있겠네요getter와 객체 책임에 대한 고민을 모두 해결해줄 수 있는 좋은 방법인 것 같습니다! 아무래도 글로 제 복잡한 생각들을 표현하다보니 지저분해졌습니다..!😥 |
Q. 여러가지 뷰/클라이언트에서 해당 기능이 필요하다는 것은 곧 domain이 갖고있어도 마땅한 기능이라고 생각하면 되는 걸까요? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
또링, 피드백 반영 잘 하셨어요 👏
몇 가지 간단한 피드백 남겼어요
확인해보시고 궁금한 점 생기면 코멘트 남기거나 dm 주세요!
import web.util.PieceFactory; | ||
import web.util.ScoreConverter; | ||
|
||
public class PieceService { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PieceService인가요?
보드게임과 관련된 로직들로 보이는데 클래스명이 적절해보이진 않네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
초기에 piece와 관련된 기능을 수행할 용도로 클래스 명을 pieceService로 지었는데, 중간에 turn 등이 추가되면서 게임과 관련된 클래스가 되었습니다..! 해당 로직에 맞게 클래스명 변경하였습니다😄
.orElseThrow(() -> new IllegalArgumentException("해당 말이 존재하지 않습니다.")); | ||
} | ||
|
||
public static String convert(String symbol) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
팩토리 클래스에서 값을 변환하는 기능도 제공할 필요는 없어보이네요
클래스명처럼 Piece를 생성하는 책임만 가져야 하지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다른 코멘트 수정하며 이 부분도 함께 해결되었습니다! 감사합니다☺
import domain.piece.team.Team; | ||
|
||
public enum PieceFactory { | ||
WHITE_PAWN("p", "♙", position -> new Pawn(Position.of(position), Team.WHITE)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unicode는 원래 뷰에서 처리할 값으로 보이는데 자바스크립트를 따로 활용하지 않고 백단에서 처리하려다 보니 나온 값으로 보이네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
자바스크립트를 잘 사용할줄 몰라서 최대한 백단에서 처리하려했습니다..! 우선은 UnicodeConverter로 분리하였는데, 아무래도 js를 활용해서 앞에서 보여줄 때 변환하는 것이 맞을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
보통은 프론트에서 처리하는게 좋다고 생각합니다.
UnicodeConverter 같이 뷰 레이어에서 처리하도록 분리하는 방법도 괜찮네요
import domain.piece.position.Position; | ||
import domain.piece.team.Team; | ||
|
||
public enum PieceFactory { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
팩토리가 util 패키지로 묶이는게 이상하네요
유니코드 처리와 dao에 저장할 객체를 생성하는 용도로 쓰면서 이것저것 혼합된 클래스에요
이 클래스가 필요한지 잘 모르겠네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유니코드 처리는 UnicodeConverter를 따로 생성하여 역할을 분리하였습니다!
추가로 이 클래스는 symbol과 position을 받아 piece로 변환해주는 역할을 하기 때문에 PieceConverter로 이름 수정하였습니다..!😅😊
src/main/java/web/dao/PieceDao.java
Outdated
private static final PieceDao PIECE_DAO = new PieceDao(); | ||
private static final String TABLE_NAME = "piece"; | ||
|
||
private DBConnector connector = new DBConnector(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DBConnector를 싱글톤으로 만들면 어떨까요
dao마다 다른 DBConnector를 유지할 필요가 없어 보여요
getConnection를 static 메서드로 만들거나요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 지적 감사합니다~ getConnection을 static으로 선언하여 해당 문제 해결하였습니다😀
src/main/java/web/dao/PieceDao.java
Outdated
public void add(PieceDto pieceDto) throws SQLException { | ||
String query = "INSERT INTO " + TABLE_NAME + " VALUES(?,?,?)"; | ||
try ( | ||
PreparedStatement pstmt = connector.getConnection().prepareStatement(query) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PreparedStatement pstmt = connector.getConnection().prepareStatement(query) | |
Connection conn = connector.getConnection(); | |
PreparedStatement pstmt = conn.prepareStatement(query) |
지금처럼 작성하면 PreparedStatement만 close 동작하지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 지적 감사합니다😀
connection의 close도 동작시키기 위해서 따로 선언을 한 후 사용을 해줘야겠네요!
try with resources 문을 처음 사용해봐서 이런 부분을 놓친 것 같아요..😂
관련된 부분들 모두 수정하였습니다.
src/main/java/web/dao/PieceDao.java
Outdated
) { | ||
rs = pstmt.executeQuery(); | ||
while (rs.next()) { | ||
PieceFactory piece = PieceFactory.of(rs.getString("symbol")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
보통 PieceFactory로 객체를 생성하면 Piece가 반환될 것을 기대하는데 PieceFactory가 반환되네요
Piece를 바로 생성하도록 바꿔볼까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
symbol과 position을 함께 전달하여 해당 piece가 바로 반환되도록 수정 완료하였습니다! 어쩐지 어색하다고 느껴졌던 부분인데 코멘트덕에 잘 해결되었습니다👍👍👍
src/main/java/web/dao/TurnDao.java
Outdated
) { | ||
rs = pstmt.executeQuery(); | ||
if (!rs.next()) | ||
return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
null 반환하지 않는게 좋습니다
NPE 발생 시키는 원인이 됩니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
좋은 지적 감사합니다! rs가 존재하지 않을 때에는 TurnDto에 빈 문자열을 넣어주어 예외를 발생시키도록 수정하였습니다 😊
String originalPosition = moveCommand.getSourcePosition().toString(); | ||
String newPosition = moveCommand.getTargetPosition().toString(); | ||
updateTurn(boardGame); | ||
return updateBoard(boardGame, originalPosition, newPosition); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateBoard 메서드가 두 가지 일을 하네요
위치 정보 저장하는 일
dto로 변환하는 일
메서드는 한 가지 일만 하는게 좋습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dto로 변환하는 메서드를 작성하여 해당 문제 해결하였습니다! 감사합니다😀😊
return new BoardDto(symbols, ScoreConverter.convert(score)); | ||
} | ||
|
||
private List<String> convert(List<Rank> board) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ScoreConverter처럼 컨버터를 따로 두는게 낫겠네요
2뎁스는 1뎁스로 줄일 필요도 있겠네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
원래 UnicodeConverter로 관리했다가, 각각의 piece에 따른 unicode라고 생각해서 다시 합쳤는데 역시 따로 두는 게 더욱 깔끔해보이네요! depth도 메소드를 분리하여 수정완료하였습니다!😀
구구님! 코멘트 달아주신부분 수정 완료하여 리뷰요청 드렸습니다! web으로 프로그램을 구현할 때 테스트는 어느 부분까지 이루어져야하는지 모르겠습니다! console로 프로그램 작성 시, 주로 도메인을 테스트 하였는데 web은 dao service controller 중 어느정도까지 테스트가 되는게 보편적인가요? dao와 service 테스트를 하면 되는건지... 현업에서는 어떻게 테스트를 하시는지 궁금해서 여쭤봅니다!😊 (지금 web 프로그램을 작성하면서 테스트코드를 많이 못짰는데, 답변주시면 테스트코드도 더 보완해보겠습니다😂!) |
레벨1 과정에서는 도메인 테스트로 충분하다고 생각합니다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
또링 피드백 반영 잘 하셨어요 👏
질문 주신 내용은 다음 과정 진행하면서 해결될거에요
미리 공부해보고 싶으시면 최근 최범균님이 새로 출판하신 tdd 책 참고하세요
https://book.naver.com/bookdb/book_detail.nhn?bid=16267566
pr은 머지 처리할게요
미션 진행하느라 수고하셨어요!
안녕하세요, 구구님! 1~3단계 마무리 하면서 주셨던 코멘트들 수정 완료하였습니다 😄
꼼꼼히 봐주셔서 정말 감사합니다. 코멘트 관련해서 질문이 있는데, 여기가 더 보기 편하실 것 같아 질문 몇 개 남깁니다!
board에서 역순서로 반환하는 기능을 만들라고 하셨고, 그건
View의 기능으로 보기보다는 Rank 리스트를 역순으로 반환하는 기능 추가
라고 생각하라고 하셨는데요,그렇게 되면 Board에서 출력을 위해
piece가 없는 column에 .을 갖고 있게 하는 로직
도 그렇게 생각할 수 있을까요? 저만의 기준이 잡히지 않는 것 같아 리뷰어님의 생각을 여쭤봅니다..!😅기존 Rank와 Board내에 계산하는 로직이 섞여있었고, 해당 기능들을 score로 분리하였는데요! 이 과정에서 board내의 rank를 알아야하고 rank내의 존재하는 piece들을 알아야하는 상황이 발생하여 get을 이용하게 되었습니다..😥 구구님이 코멘트 달아주신대로 rank가 점수를 계산하는 함수를 갖고 있다면 getter를 사용하지 않고 점수를 구할 수 있는데요, 이렇게 된다면 다시 계산을 하는 로직이 여기 저기로 분산된다고 생각합니다..! 이 때, 어떻게 구현해야 더욱 객체지향적으로 짤 수 있는지 고민이 되네요.
이러지도 저러지도 못하는 상황이 발생하게 된 건 설계가 잘못된 것일까요?... 구구님의 생각이 궁금해서 질문 남깁니다..!