Readable Code (3) : 읽기 좋은 코드를 작성하는 사고법 (Section 3)

keymu·2024년 10월 4일
0

논리, 사고의 흐름

1. Early Return

이 조건 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("잘못된 번호를 선택하셨습니다.");

    }

2. 중첩 분기문, 중첩 반복문, 사용할 변수의 가까운 선언

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));
    }

선언을 너무 멀리 선언한 것을 고쳐보자.

사용할 변수는 사용하는 부분에 가깝게 선언한다.


조언 1. Refactoring을 현명하게 하는 법

method를 복사하여 하나 더 만들고 이름을 A라면 A2로 바꾸어주고, A를 사용하던 경우를 모두 A2로 바꿔준 후 A의 Refactoring을 진행한다.
에러 없이 진행할 수 있는 방식으로 추천한다.

조언 2. 공백 라인을 대하는 자세

복잡한 로직의 의미 단위를 나누어 보여줌으로써 읽는 사람에게 추가적인 정보를 전달할 수 있다.


3. 부정어를 대하는 법

사고과정을 두 번 거치는 수고를 하지 말고, 이해도를 높이기 위해서 이렇게 변경하자:

부정어구를 쓰지 않아도 되는 상황인지 체크하고, 부정의 의미를 담은 다른 단어가 존재하는지 고민하자.

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;
            }
        }

4. 해피 케이스와 예외 처리

해피 케이스: 내가 의도한 대로 사용자가 사용하는 가장 최상의 상태

예외처리를 위해 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));
    }

출처:
Readable Code: 읽기 좋은 코드를 작성하는 사고법

profile
Junior Backend Developer

0개의 댓글

관련 채용 정보