Все говорят - делайте рефакторинг по чуть-чуть. Не накапливайте технический долг. Супер. Но я не видел, кроме как в книге Мартина Фаулера, демонстрации рефакторинга "по чуть-чуть".
Не так давно мы с другом Виталиком учились ТДД. Мы играли в tetris coding dojo, но в отличие от ребят игравших одновременно с нами мы делали акцент в сторону обучения. И вот в какой-то момент на руках у нас был код.
Очень неидеальный код. Но дело в том, что нам надо было чтобы фигурки тетриса расскладывались, и ТДД привело нас именно сюда. В какой-то момент я предложил - а давай порефакторим этот код - тут чертовски много дублирования. Виталик согласился. Глядя на этот код сразу видно, что тут необходим цикл. Но написать родить его одним махом не получилось. Прошло 15 минут, а кода рабочего небыло. И тут я предложил тот самый рефакторинг "по чуть-чуть". Еще через 20 минут у нас был код, отражающий ход наших мыслей.
В ходе этого рефакторинга было проделано около полсотни мелких рефакторингов. Настолько этот пример мне приглянулся, что я воспроизвел его по памяти и сохраню тут. Скачать svn репозиторий с историей коммитов можно тут. Там же есть тесты, есл вдруг (что очень похвально) захочется повторить этот рефакторинг.
Прошу простить меня за то, что не озвучил или как минимум не наложил музычку, я даже не репетировал как обычно 3 раза перед записью. Времени было не много на этот пост, не до монтажа мне сейчас, да и кашляю/болею - запись вышла бы еще та.
В тот день Виталик спросил "и хорошо, а сколько по времени стоит делать рефакторинг?". Вопрос хороший. У меня есть свой фирменный ответ. Делай рефакторинг до тех пор, пока код не станет оражать твои мысли настолько просто, насколько у тебя это получится. В целях практики делай рефакторинг даже немного дольше. Не беда, если забрел не туда - откатись и попробуй еще раз, но после перерыва. Пиши тесты - без них ты сапер без миноискателя. Как только сделал хорошо - коммить. Всегда можно сделать еще чуть лучше, но не всегда за один ход, порой надо сделать шаг в сторону усложнения, чтобы потом код упростился. Экспериментируй с кодом.
Надеюсь, пригодится. Виталик, спасибо тебе! Классно покодили в тот день!
Не так давно мы с другом Виталиком учились ТДД. Мы играли в tetris coding dojo, но в отличие от ребят игравших одновременно с нами мы делали акцент в сторону обучения. И вот в какой-то момент на руках у нас был код.
String answer(String figure, int x, int y, String glass, String next) {
if (glass.charAt(0) == ' ') {
return "left=4, drop";
}
if (figure.equals("I") && glass.charAt(1) == ' ') {
return "left=3, drop";
}
if (glass.charAt(2) == ' ') {
return "left=2, drop";
}
if (figure.equals("I") && glass.charAt(3) == ' ') {
return "left=1, drop";
}
if (glass.charAt(4) == ' ') {
return "drop";
}
if (figure.equals("I") && glass.charAt(5) == ' ') {
return "right=1, drop";
}
if (glass.charAt(6) == ' ') {
return "right=2, drop";
}
if (figure.equals("I") && glass.charAt(7) == ' ') {
return "right=3, drop";
}
if (glass.charAt(8) == ' ') {
return "right=4, drop";
}
if (figure.equals("I") && glass.charAt(9) == ' ') {
return "right=5, drop";
}
throw new UnsupportedOperationException();
}
Очень неидеальный код. Но дело в том, что нам надо было чтобы фигурки тетриса расскладывались, и ТДД привело нас именно сюда. В какой-то момент я предложил - а давай порефакторим этот код - тут чертовски много дублирования. Виталик согласился. Глядя на этот код сразу видно, что тут необходим цикл. Но написать родить его одним махом не получилось. Прошло 15 минут, а кода рабочего небыло. И тут я предложил тот самый рефакторинг "по чуть-чуть". Еще через 20 минут у нас был код, отражающий ход наших мыслей.
String answer(String figure, int x, int y, String glass, String next) {
boolean isO = figure.equals("O");
int dx = 0;
while (dx <= 10) {
if (isFree(glass, dx)) {
return getCommand(dx);
}
dx += (isO)?2:1;
}
throw new UnsupportedOperationException();
}
private String getCommand(int dx) {
if (dx < 4) {
return left(dx);
} else if (dx == 4) {
return drop();
} else {
return right(dx);
}
}
private String left(int dx) {
return "left=" + (4 - dx) + ", drop";
}
private boolean isFree(String glass, int dx) {
return glass.charAt(dx) == ' ';
}
private String drop() {
return "drop";
}
private String right(int dx) {
return "right=" + (dx - 4) + ", drop";
}
Да, тут осталось пару магических констант, но в контексте исходного класса, не сложно догадаться что это за 4-ки, 2-ка и 1-ка.В ходе этого рефакторинга было проделано около полсотни мелких рефакторингов. Настолько этот пример мне приглянулся, что я воспроизвел его по памяти и сохраню тут. Скачать svn репозиторий с историей коммитов можно тут. Там же есть тесты, есл вдруг (что очень похвально) захочется повторить этот рефакторинг.
Прошу простить меня за то, что не озвучил или как минимум не наложил музычку, я даже не репетировал как обычно 3 раза перед записью. Времени было не много на этот пост, не до монтажа мне сейчас, да и кашляю/болею - запись вышла бы еще та.
В тот день Виталик спросил "и хорошо, а сколько по времени стоит делать рефакторинг?". Вопрос хороший. У меня есть свой фирменный ответ. Делай рефакторинг до тех пор, пока код не станет оражать твои мысли настолько просто, насколько у тебя это получится. В целях практики делай рефакторинг даже немного дольше. Не беда, если забрел не туда - откатись и попробуй еще раз, но после перерыва. Пиши тесты - без них ты сапер без миноискателя. Как только сделал хорошо - коммить. Всегда можно сделать еще чуть лучше, но не всегда за один ход, порой надо сделать шаг в сторону усложнения, чтобы потом код упростился. Экспериментируй с кодом.
Надеюсь, пригодится. Виталик, спасибо тебе! Классно покодили в тот день!







