이 조건 3개를 모두 기억하고 있어야 하는 문제가 있다.
Early Return을 하게 되면,
앞에 있던 조건들은 잊어도 되는 장점이 있다.
Early return으로 else의 사용을 지양하는 것을 추천한다.
길이가 짧다면 쓰게 될 수도 있겠지만, 굳이 써야 하지 않아도 되는 곳에는 지양하자.
switch case도 마찬가지다. 전체 케이스에 대한 정보가 명확하면 그렇겠지만, 최대한 사용하지 않는 것이 좋다.
private static void actOnCell(String cellInput, String userActionInput) {
int selectedColIndex = getSelectedColIndex(cellInput);
int selectedRowIndex = getSelectedRowIndex(cellInput);
if (doesUserChooseFlag(userActionInput)) {
BOARD[selectedRowIndex][selectedColIndex] = FLAG_SIGN;
checkIfGameIsOver();
return;
}
//사실상 필요없었던 else문을 없앤다.
if (doesUserChooseOpen(userActionInput)) {
if (isLandMineCell(selectedRowIndex, selectedColIndex)) {
BOARD[selectedRowIndex][selectedColIndex] = "☼";
changeGameStatusToLoose();
return;
}
open(selectedRowIndex, selectedColIndex);
checkIfGameIsOver();
return;
}
System.out.println("잘못된 번호를 선택하셨습니다.");
}
do something을 읽을 때 쯤은 기억해야 하는 것이 너무 많다.
이런 식으로 최대한 depth를 줄여서 정리해준다.
추상화의 의미가 있다면 변화를 가져오자. 이중 for loop자체로 의미가 전달이 잘 된다면, 만지지 않아도 괜찮다.
Code Example:
// private static boolean isAllCellOpened() {
// boolean isAllOpened = true;
// for (int row = 0; row < 8; row++) {
// for (int col = 0; col < 10; col++) {
// if (BOARD[row][col].equals(CLOSED_CELL_SIGN)) {
// isAllOpened = false;
// }
// }
// }
// return isAllOpened;
// }
// 삼중 depth를 해결하는 방법:
private static boolean isAllCellOpened() {
return Arrays.stream(BOARD)
.flatMap(Arrays::stream)
.noneMatch(cell->cell.equals(CLOSED_CELL_SIGN));
}
선언을 너무 멀리 선언한 것을 고쳐보자.
사용할 변수는 사용하는 부분에 가깝게 선언한다.
method를 복사하여 하나 더 만들고 이름을 A라면 A2로 바꾸어주고, A를 사용하던 경우를 모두 A2로 바꿔준 후 A의 Refactoring을 진행한다.
에러 없이 진행할 수 있는 방식으로 추천한다.
복잡한 로직의 의미 단위를 나누어 보여줌으로써 읽는 사람에게 추가적인 정보를 전달할 수 있다.
사고과정을 두 번 거치는 수고를 하지 말고, 이해도를 높이기 위해서 이렇게 변경하자:
부정어구를 쓰지 않아도 되는 상황인지 체크하고, 부정의 의미를 담은 다른 단어가 존재하는지 고민하자.
Code Example
// for (int row = 0; row < BOARD_ROW_SIZE; row++) {
// for (int col = 0; col < BOARD_COL_SIZE; col++) {
// if (!isLandMineCell(row, col)) {
// int count = countNearbyLandMines(row, col);
// LAND_MINE_COUNTS[row][col] = count;
// continue;
// }
// LAND_MINE_COUNTS[row][col] = 0;
// }
// }
//부정연산문을 쓰지 않아도 되는 방법:
for (int row = 0; row < BOARD_ROW_SIZE; row++) {
for (int col = 0; col < BOARD_COL_SIZE; col++) {
if (isLandMineCell(row, col)) {
LAND_MINE_COUNTS[row][col] = 0;
continue;
}
int count = countNearbyLandMines(row, col);
LAND_MINE_COUNTS[row][col] = count;
}
}
해피 케이스: 내가 의도한 대로 사용자가 사용하는 가장 최상의 상태
예외처리를 위해 Null에 대한 경각심을 가져야 한다.
Code Example: Exception
while (true) {
try {
showBoard();
if (doesUserWinTheGame()) {
System.out.println("지뢰를 모두 찾았습니다. GAME CLEAR!");
break;
}
if (doesUserLooseTheGame()) {
System.out.println("지뢰를 밟았습니다. GAME OVER!");
break;
}
String cellInput = getCellInputFromUser();
String userActionInput = getUserActionInputFromUser();
actOnCell(cellInput, userActionInput);
} catch (IllegalArgumentException e){
System.out.println(e.getMessage());
}
}
}
Code Example: NPE avoiding
private static boolean isAllCellOpened() {
return Arrays.stream(BOARD)
.flatMap(Arrays::stream)
// .noneMatch(cell->cell.equals(CLOSED_CELL_SIGN));
//cell값에 null이 들어가있을 수 있으니:
.noneMatch(cell->CLOSED_CELL_SIGN.equals(cell));
}