Все говорят - делайте рефакторинг по чуть-чуть. Не накапливайте технический долг. Супер. Но я не видел, кроме как в книге Мартина Фаулера, демонстрации рефакторинга "по чуть-чуть".
Не так давно мы с другом Виталиком учились ТДД. Мы играли в 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 раза перед записью. Времени было не много на этот пост, не до монтажа мне сейчас, да и кашляю/болею - запись вышла бы еще та.
В тот день Виталик спросил "и хорошо, а сколько по времени стоит делать рефакторинг?". Вопрос хороший. У меня есть свой фирменный ответ. Делай рефакторинг до тех пор, пока код не станет оражать твои мысли настолько просто, насколько у тебя это получится. В целях практики делай рефакторинг даже немного дольше. Не беда, если забрел не туда - откатись и попробуй еще раз, но после перерыва. Пиши тесты - без них ты сапер без миноискателя. Как только сделал хорошо - коммить. Всегда можно сделать еще чуть лучше, но не всегда за один ход, порой надо сделать шаг в сторону усложнения, чтобы потом код упростился. Экспериментируй с кодом.
Надеюсь, пригодится. Виталик, спасибо тебе! Классно покодили в тот день!
Знаю проект в продакшині з схожим методом, всі плювались з нього, але так як тестів не було, то всі боялись рефакторити... А тести до нього не написались бо ніхто не знав, що ж то воно таке взагалі і як конкретно повинно працювати - код в спадщину дістався.
ОтветитьУдалитьТоха, может помочь вот это
Удалитьhttp://xpdays.com.ua/archive/xp-days-ukraine-2011/materials/approval-tests/
Я про "сколько по времени стоит делать рефакторинг?"
ОтветитьУдалитьНе надо подходить к этому прямолинейно, типа, как врач сказал чистить зубы 3 минуты. Вам даются рекомендации и при этом не забирают свободу действий. Пользуйтесь этим по ситуации. Слаба Богу, мы живём в нелинейном мире и можно допускать отклонения.
Если вы трудитесь над своим домашним шедевром, то можно тратить сколько угодно времени, есть же примеры когда писатели переписывали целые главы по несколько раз (пример классического рефаторинга). А вот если вы наёмный работник, то вы себе не принадлежите с 09:00 до 18:00 и ваши планы и задачи нужно согласовывать с тем, кому вы принадлежите с 09:00 до 18:00 :)
Вот вроде как правда все, справедливо все, правильно. Согласен, что учиться стоит дома. А то, чему научился использовать на работе.
ОтветитьУдалитьНо если не разделять, работа, !работа. Старый проект, новый проект. Старая компания, новая компания. Это я отдал в рабочее время и мне за это заплатили - это моя работа, а это я отдал во время личное и это мое хобби.
Выкладываться везде по полной, работаешь ли ты в найме или сам на себя. Везде одна планка. При собеседовании говорить об этой планке, чтобы не ошибиться с ожиданиями. Да, я рефакторю вот так вот. Вам на проекте это надо? Нет, ну тогда вы мне не подходите.
Я за то, чтобы найти проект на который тебя наймут за то, что ты переписываешь главы по несколько раз (если тебе это в кайф).
Я за то, чтобы на собеседовании собеседовался не только кандидат на проект, но и сам проект тем кандидатом. Про проект надо узнать все, что только можно. Хорошенько прособеседовать его. Чтобы потом не ныть, что там не дают делать то, на что ты учился. На этом обжигался не раз.
"Вам даются рекомендации и при этом не забирают свободу действий. Пользуйтесь этим по ситуации."
Вот за это спасибо! Сейчас для айтишников благодать! Они могут воротить носом на проекте просто потому, что видите ли там новую технологию использовать не будут. С одной стороны - первые месяцы в тебя проект вкладывает, чтобы ты потом отдавал ему. Так что будь добр - Hibernate 2.0 значит Hibernate 2.0. Но с другой стороны новые технологии выходят пачками, и все хочется попробовать, и хоть учился то спец на Hibernate 2.0, а всю жизнь писать на нем одном не сильно-то и выгодно, потому что в какой-то момент станет понятно - устарел, увольтесь. Это чувствуют. Но иногда это уходит в крайности.
Я же люблю изучать новое. Люблю крайности. Потому еще в прошлой компании учил что-то и потом рассказывал всем переваренное. И чтобы было эффективнее работал один на несколько комманд. Теперь вот тренерством занимаюсь. Платят за то, что мне нравится.
И к чему я вообще. Спрашивают - а как ты так делаешь. Отвечаю - делаю много, ибо нравится, вот и наловчился. Я тоже так хочу. Делай значит много. Но проект не позволяет. Делай на выходных, может проект заметит твое увлечение и научится его конвертировать в пользу/деньги. А если не научится? Со временем все равно будешь искать новый - вот тогда на собеседовании уточни, а ценно ли у них такое.
От такое..
Я взагалі не розумію як програміст працюючи над чимось по замовлюенню може на рефакторінг просити _додатковий_ час :) Він, програміст, або загавнокодить, або напише файно; а у мега програміста - "ол інклюзів" - це і код, і тести, і дока.
ОтветитьУдалитьДруга справа - отримали код "зовні" - і тут експерт (наприклад, той з ким "задачи нужно согласовывать") дивиться і каже, що цей код важко буде підтримувати - тре рефакторити. А якшо коже - що не тре, ну що ж - "Вас попереджали" :)
А якшо програмєр "трудится над своим домашним шедевром" - і при цьому довго рефакторить і рефакторить, скоріш за все це або просто освоення нових інструментів, або програмер не знає що хоче зробити.
Рефакторінг - це інструмент який прямо корелюється зі способом мислення.