[JAVA] Refactor yourself two days ago.

I am currently receiving training as an engineer after being picked up by a certain company. The coin game created during the training was very poor, and I will leave the corrected version as a commandment to myself after receiving the opinions of the instructor.

The code I wrote

This is the code I wrote first.

public Integer execute() {
    if(this.possessionCoin == 0) {
        return 0;
    } else {
        System.out.println("You have" + this.possessionCoin + "Coin, Start the game? y / n");
        while(true) {
            try {
                int getCoin = 0;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                String inputChoice = br.readLine();
                System.out.println(inputChoice);
                if(inputChoice.equals("y")) {
                    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
                    while(true) {
                        try {
                            BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
                            String inputStr = br2.readLine();
                            Integer inputBetCoin = Integer.parseInt(inputStr);
                            if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
                                this.possessionCoin -= inputBetCoin;
                                int sumCardScore = this.getCard();
                                if(this.judgeCard(sumCardScore)) {
                                    getCoin = inputBetCoin * 2;
                                    System.out.println("You Win! Get" + getCoin + "Coin!");
                                    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
                                    int winCoinCount = doubleUpChanceGame.execute();
                                    if(winCoinCount == 0) {
                                        return 0;
                                    } else {
                                        System.out.println("You got " + winCoinCount + "Coin !!");
                                        this.execute();
                                    }
                                } else {
                                    this.possessionCoin = 0;
                                    break;
                                }
                                
                            } else {
                                break;
                            }
                        } catch(IOException | NumberFormatException e) {
                            
                        }			
                    }
                } else if(inputChoice.equals("n")) {
                    return this.possessionCoin;
                } else {
                    System.out.println("Please enter y or n.");
                }
                if(getCoin > 0) {
                    System.out.println("You got " + getCoin + "Coin !!");
                } else {
                    System.out.println("You are losing");
                }
                PlayLogs playLog = new PlayLogs();
                playLog.export();
                this.execute();
                
            } catch(IOException | NumberFormatException e) {
                
            }					
        }
    }
    
}

Even if you are not familiar with programming, you can see how terrible the code is. It is an amazing 10-stage nest. (Lol) However, two days ago, I was calm and wrote: Perhaps those who read this article will press the back button the moment they see this code. By the way, please note that the nesting is too deep and you can't do it yourself, and the code is not completed in some places.

Let's go back in time and let yourself go back in time to fix it. By the way, since the processing is too long, you should separate the method normally, but this time I want to focus on making the nest shallow, so I do not mention method extraction. Please note that as well.

Point 1 Use early return to delete else

First from the top if statement If the current coin is 0, it returns 0, otherwise it is the next process.

before


public Integer execute() {
    if(this.possessionCoin == 0) {
        return 0;
    } else {
        System.out.println("You have" + this.possessionCoin + "Coin, Start the game? y / n");

Modify this as follows.

after


public Integer execute() {
    if(this.possessionCoin == 0) {
        return 0;
    } 
    System.out.println("You have" + this.possessionCoin + "Coin, Start the game? y / n");

If it is true depending on the result of the if statement, it is returned, so the else below it is not necessary. This alone made one nest shallower. If it applies to the process like this and returns, there is no need to write else. You can make the code easier to read by actively using this in the early return and guard clauses.

Point 2 Write only the processing that can cause exceptions in try

before


try {
    int getCoin = 0;
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String inputChoice = br.readLine();
    System.out.println(inputChoice);
    if(inputChoice.equals("y")) {
        System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
        while(true) {
            try {
                BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
                String inputStr = br2.readLine();
                Integer inputBetCoin = Integer.parseInt(inputStr);
                if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
                    this.possessionCoin -= inputBetCoin;
                    int sumCardScore = this.getCard();
                    if(this.judgeCard(sumCardScore)) {
                        getCoin = inputBetCoin * 2;
                        System.out.println("You Win! Get" + getCoin + "Coin!");
                        DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
                        int winCoinCount = doubleUpChanceGame.execute();
                        if(winCoinCount == 0) {
                            return 0;
                        } else {
                            System.out.println("You got " + winCoinCount + "Coin !!");
                            this.execute();
                        }
                    } else {
                        this.possessionCoin = 0;
                        break;
                    }
                    
                } else {
                    break;
                }
            } catch(IOException | NumberFormatException e) {
                
            }			
        }
    } else if(inputChoice.equals("n")) {
        return this.possessionCoin;
    } else {
        System.out.println("Please enter y or n.");
    }
    if(getCoin > 0) {
        System.out.println("You got " + getCoin + "Coin !!");
    } else {
        System.out.println("You are losing");
    }
    PlayLogs playLog = new PlayLogs();
    playLog.export();
    this.execute();
    
} catch(IOException e) {
    
}						

It's awesome (laughs) There are about 50 lines in the try alone. Try will work on this with the consciousness of focusing on the places where exceptions can occur. Exceptions can occur in the first try

String inputChoice = br.readLine();

Only this one sentence. Therefore, modify it as follows.

try {
    inputChoice = br.readLine();
} catch(IOException e) {

}

Other descriptions will be taken out. If you do so, an error will occur due to the scope of the variable, but you only need to create the variable outside, so create it. You can also make the nest shallower by narrowing down the description to try.

after


try {
    inputChoice = br.readLine();
    System.out.println(inputChoice);
    
} catch(IOException e) {

}					
if(inputChoice.equals("y")) {
    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
    while(true) {

It was a little refreshing to be able to issue an if statement from the try.

Next, let's clean up the if statement that was put out.

before


//Above this is a while statement.
if(inputChoice.equals("y")) {
    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
    while(true) {
        try {
            BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
            String inputStr = br2.readLine();
            Integer inputBetCoin = Integer.parseInt(inputStr);
            if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
                this.possessionCoin -= inputBetCoin;
                int sumCardScore = this.getCard();
                if(this.judgeCard(sumCardScore)) {
                    getCoin = inputBetCoin * 2;
                    System.out.println("You Win! Get" + getCoin + "Coin!");
                    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
                    int winCoinCount = doubleUpChanceGame.execute();
                    if(winCoinCount == 0) {
                        return 0;
                    } else {
                        System.out.println("You got " + winCoinCount + "Coin !!");
                        this.execute();
                    }
                } else {
                    this.possessionCoin = 0;
                    break;
                }
                
            } else {
                break;
            }
        } catch(IOException e) {
            
        }			
    }
} else if(inputChoice.equals("n")) {
    return this.possessionCoin;
} else {
    System.out.println("Please enter y or n.");
}

And further this removes the else as it can remove the else. By the way, let's change else if to if. (Here you like)

after


if(inputChoice.equals("y")) {
    break;
} 
if(inputChoice.equals("n")) {
    return this.possessionCoin;
}
System.out.println("Please enter y or n.");

At this point, it's much easier to see.

if(inputChoice.equals("y")) {
    break;
} 
if(inputChoice.equals("n")) {
    return this.possessionCoin;
}
System.out.println("Please enter y or n.");
while(true) {
        int getCoin = 0;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String inputChoice = "";
    try {
        inputChoice = br.readLine();
        System.out.println(inputChoice);
        
    } catch(IOException e) {

    }					
    if(inputChoice.equals("y")) {
        break;
    } 
    if(inputChoice.equals("n")) {
        return this.possessionCoin;
    }
    System.out.println("Please enter y or n.");
    
    if(getCoin > 0) {
        System.out.println("You got " + getCoin + "Coin !!");
    } else {
        System.out.println("You are losing");
    }
    PlayLogs playLog = new PlayLogs();
    playLog.export();
}
//Correction completed so far
//--------------------------------------------------------------

while(true) {
    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
    try {
        String inputStr = br.readLine();
        Integer inputBetCoin = Integer.parseInt(inputStr);
        if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
            this.possessionCoin -= inputBetCoin;
            int sumCardScore = this.getCard();
            if(this.judgeCard(sumCardScore)) {
                getCoin = inputBetCoin * 2;
                System.out.println("You Win! Get" + getCoin + "Coin!");
                DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
                int winCoinCount = doubleUpChanceGame.execute();
                if(winCoinCount == 0) {
                    return 0;
                } else {
                    System.out.println("You got " + winCoinCount + "Coin !!");
                    this.execute();
                }
            } else {
                this.possessionCoin = 0;
                break;
            }
            
        } else {
            break;
        }
    } catch(IOException e) {
        
    }			

After that, let's go out inside the try of the while statement below.

try {
    String inputStr = br.readLine();
    Integer inputBetCoin = Integer.parseInt(inputStr);
} catch(IOException | NumberFormatException e) {
    System.out.println("You typed incorrect value, please type of correct number");
}	

after


while(true) {
    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
    try {
        String inputStr = br.readLine();
        Integer inputBetCoin = Integer.parseInt(inputStr);
    } catch(IOException | NumberFormatException e) {
        System.out.println("You typed incorrect value, please type of correct number");
    }

    //Next fix below this
    if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
        this.possessionCoin -= inputBetCoin;
        int sumCardScore = this.getCard();
        if(this.judgeCard(sumCardScore)) {
            getCoin = inputBetCoin * 2;
            System.out.println("You Win! Get" + getCoin + "Coin!");
            DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
            int winCoinCount = doubleUpChanceGame.execute();
            if(winCoinCount == 0) {
                return 0;
            } else {
                System.out.println("You got " + winCoinCount + "Coin !!");
                this.execute();
            }
        } else {
            this.possessionCoin = 0;
            break;
        }
        
    } else {
        break;
    }
}

Point 3 Write the conditions for popping first (use continue)

Modify the if statement. This condition wants to process when the input value (bet amount) is larger than 0 and less than the maximum amount that can be bet, and when it is less than the current coin possession, so conversely, if it is other than this condition, it will be after that. It seems that you should write a process that pops the process and asks for input again. Use continue here.

if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
processing
}

This part

if(inputBetCoin <= 0) {
    continue;
}
if(inputBetCoin > this.possessionCoin) {
    continue;
}
if(inputBetCoin > this.maxBetCoin) {
    continue;
}
processing

I rewrote it like this. By doing this, if the input value is 0 or less, it will be redone, if it is larger than the possessed coin, it will be redone, and if it is larger than the maximum bet amount, it will be redone. I think this is simpler and easier to read.

Point 4 When the conditions are complicated, divide the processing into small parts.

You can connect them with &&, but it is easier for the human eye to read vertically than horizontally, and it is better to write one condition at a time so that you do not have to worry about the previous condition, so I wrote it as above.


Next, since the if statement is written in the if statement, modify it here.

before


if(this.judgeCard(sumCardScore)) {
    getCoin = inputBetCoin * 2;
    System.out.println("You Win! Get" + getCoin + "Coin!");
    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
    int winCoinCount = doubleUpChanceGame.execute();
    if(winCoinCount == 0) {
        return 0;
    } else {
        System.out.println("You got " + winCoinCount + "Coin !!");
        this.execute();
    }
} else {
    break;
}

First, put out the if statement inside.

after


int winCoinCoint = 0;
if(this.judgeCard(sumCardScore)) {
    getCoin = inputBetCoin * 2;
    System.out.println("You Win! Get" + getCoin + "Coin!");
    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
    winCoinCount = doubleUpChanceGame.execute();
} else {
    break;
}
if(winCoinCount == 0) {
    return 0;
} else {
    System.out.println("You got " + winCoinCount + "Coin !!");
    break;
}

If you set break when the first if statement becomes else, the behavior will be the same as before. An error occurs in the scope of the variable, so fix it.

Since it is an early return with the familiar if, delete the else at the bottom.

if(this.judgeCard(sumCardScore)) {
    getCoin = inputBetCoin * 2;
    System.out.println("You Win! Get" + getCoin + "Coin!");
    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
    winCoinCount = doubleUpChanceGame.execute();
} else {
    break;
}
if(winCoinCount == 0) {
    return 0;
}
System.out.println("You got " + winCoinCount + "Coin !!");
break;

Point 5 Think the conditions in reverse

There is another part in the above if statement that could be fixed. It means that only break is done when the process moves to else.

before


if(this.judgeCard(sumCardScore)) {
    getCoin = inputBetCoin * 2;
    System.out.println("You Win! Get" + getCoin + "Coin!");
    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
    winCoinCount = doubleUpChanceGame.execute();
} else {
    break;
}

The method called this.judgeCard is a method that returns a boolean. Now, when false is returned, break will exit the process, so you can also write this.

after


if(!this.judgeCard(sumCardScore)) {
    break;
}
getFromCardPickCoin += (inputBetCoin * 2);
System.out.println("You Win! Get" + (getFromCardPickCoin) + "Coin!");
DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame((getFromCardPickCoin), this.deckSetCount);
getFromDoubleUpCoin = doubleUpChanceGame.execute();

By doing this, when it becomes false, you can break and exit the process, otherwise you can continue the process. Now you can remove else again. However, the judgment of flipping boolean with! May be difficult to understand **, so it seems better to devise variable names or use it on a case-by-case basis.

Correction completed

Before correction

before


public Integer execute() {
    if(this.possessionCoin == 0) {
        return 0;
    } else {
        System.out.println("You have" + this.possessionCoin + "Coin, Start the game? y / n");
        while(true) {
            try {
                int getCoin = 0;
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                String inputChoice = br.readLine();
                System.out.println(inputChoice);
                if(inputChoice.equals("y")) {
                    System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
                    while(true) {
                        try {
                            BufferedReader br2 = new BufferedReader(new InputStreamReader(System.in));
                            String inputStr = br2.readLine();
                            Integer inputBetCoin = Integer.parseInt(inputStr);
                            if(0 < inputBetCoin && inputBetCoin <= this.possessionCoin && inputBetCoin <= this.maxBetCoin) {
                                this.possessionCoin -= inputBetCoin;
                                int sumCardScore = this.getCard();
                                if(this.judgeCard(sumCardScore)) {
                                    getCoin = inputBetCoin * 2;
                                    System.out.println("You Win! Get" + getCoin + "Coin!");
                                    DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame(getCoin, this.deckSetCount);
                                    int winCoinCount = doubleUpChanceGame.execute();
                                    if(winCoinCount == 0) {
                                        return 0;
                                    } else {
                                        System.out.println("You got " + winCoinCount + "Coin !!");
                                        this.execute();
                                    }
                                } else {
                                    this.possessionCoin = 0;
                                    break;
                                }
                                
                            } else {
                                break;
                            }
                        } catch(IOException | NumberFormatException e) {
                            
                        }			
                    }
                } else if(inputChoice.equals("n")) {
                    return this.possessionCoin;
                } else {
                    System.out.println("Please enter y or n.");
                }
                if(getCoin > 0) {
                    System.out.println("You got " + getCoin + "Coin !!");
                } else {
                    System.out.println("You are losing");
                }
                PlayLogs playLog = new PlayLogs();
                playLog.export();
                this.execute();
                
            } catch(IOException | NumberFormatException e) {
                
            }					
        }
    }
    
}

Revised

after


public Integer execute() {
    if(this.possessionCoin == 0) {
        return 0;
    }
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    while(true) {
        System.out.println("You have" + this.possessionCoin + "Coin, Start the game? y / n");
        String inputChoice = "";
        try {
            inputChoice = br.readLine();
        } catch(IOException | NumberFormatException e) {
            System.out.println("You typed incorrect value, please type of correct number");
        }					
        if(inputChoice.equals("n")) {
            return this.possessionCoin;
        }
        if(inputChoice.equals("y")) {
            break;
        }
        System.out.println("Please enter y or n.");
    }
    
    int inputBetCoin = 0;
    int getFromCardPickCoin = 0;
    int getFromDoubleUpCoin = 0;
    
    while(true) {
        System.out.println("Please bet Coin 1 ~ " + this.maxBetCoin);
        try {
            String inputStr = br.readLine();
            inputBetCoin = Integer.parseInt(inputStr);
        } catch(IOException | NumberFormatException e) {
            System.out.println("You typed incorrect value, please type of correct number");
        }	
        if(inputBetCoin <= 0) {
            continue;
        }
        if(inputBetCoin > this.maxBetCoin) {
            continue;
        }
        if(inputBetCoin > this.possessionCoin) {
            continue;
        }
        this.possessionCoin -= inputBetCoin;
        int sumCardScore = this.getCard();
        if(!this.judgeCard(sumCardScore)) {
            break;
        }
        getFromCardPickCoin += (inputBetCoin * 2);
        System.out.println("You Win! Get" + (getFromCardPickCoin) + "Coin!");
        DoubleUpChanceGame doubleUpChanceGame = new DoubleUpChanceGame((getFromCardPickCoin), this.deckSetCount);
        getFromDoubleUpCoin = doubleUpChanceGame.execute();
        if(getFromDoubleUpCoin == 0) {
            System.out.println("You are losing");
            return this.possessionCoin;
        }
        break;
    }
    if(getFromDoubleUpCoin > 0) {
        System.out.println("You got " + getFromDoubleUpCoin + "Coin !!");
        this.possessionCoin += getFromDoubleUpCoin + inputBetCoin;
    } else {
        System.out.println("You are losing");
    }
    PlayLogs playLog = new PlayLogs();
    playLog.export();
    return this.execute();
}

I was able to reduce the nesting to 3 levels. It may be difficult to read due to the large number of lines, but I think it is still much easier to read than before the correction. I think it will be easier to read if you isolate the method from here. (Before the modification, the app is incomplete and after the modification is the completed version of the app, so the logic and variable names have changed in some places, but this time the main focus was not to create the app but to make the nest shallow, so please refer to that. Please forgive me.)

Finally

I felt it was absolutely necessary to have the idea that there was some other way when the nesting was deep. For the time being, I'm okay because I skipped myself two days ago (laughs) If you have an opinion that it is better to do this to make it easier to see, or if you should pay attention to these points, I would appreciate it if you could comment!

Recommended Posts

Refactor yourself two days ago.