SlideShare a Scribd company logo
1 of 77
Download to read offline
Безудержный REFACTORING
   или как не убиться об стену

        Бибичев Андрей
        2008 год, декабрь

                            www.custis.ru
   Определение
   Поводы
   Каталог
   Самые популярные
   Автоматический рефакторинг


НА ПРАВАХ ВВЕДЕНИЯ

              «Безудержный Refactoring», (с) 2008   2 из 77
Классический труд




                                         XP

   «Безудержный Refactoring», (с) 2008    3 из 77
Цитируем wikipedia…
  Рефакторинг или Реорганизация — процесс
  полного или частичного преобразования
  внутренней структуры программы при
  сохранении еѐ внешнего поведения.

  В его основе лежит последовательность
  небольших эквивалентных
  (т.е., сохраняющих поведение)
  преобразований


Источник: http://ru.wikipedia.org/wiki/Рефакторинг


                      «Безудержный Refactoring», (с) 2008   4 из 77
Продолжаем цитировать …
  Рефакторинг изначально не предназначен для
  исправления ошибок и добавления новой
  функциональности, но помогает избежать
  ошибок и облегчить добавление
  функциональности. Он выполняется для
  улучшения понятности кода или изменения
  его структуры, для удаления «мѐртвого кода»
  — всѐ это для того, чтобы в будущем код
  было легче поддерживать и развивать


Источник: http://ru.wikipedia.org/wiki/Рефакторинг


                      «Безудержный Refactoring», (с) 2008   5 из 77
Откуда может возникнуть
необходимость в рефакторинге?




         «Безудержный Refactoring», (с) 2008   6 из 77
1. Унаследованный (legacy) код




 «Код надо писать так, как будто его будет
 поддерживать и сопровождать законченный
 маньяк, который знает ваш домашний адрес…»

             «Безудержный Refactoring», (с) 2008   7 из 77
2. «Второй проход» по
свеженаписанной функциональности




     «Первое лезвие бреет чисто,
        второе – еще чище»
           «Безудержный Refactoring», (с) 2008   8 из 77
3. Инкрементальный дизайн




       «Безудержный Refactoring», (с) 2008   9 из 77
Так как это делать?
- Есть целый каталог рефакторингов!!!

http://www.refactoring.com/catalog/index.html




              «Безудержный Refactoring», (с) 2008   10 из 77
•   Add Parameter                                                                    •    Pull Up Constructor Body
•   Change Bidirectional Association to Unidirectional                               •    Pull Up Field
•   Change Reference to Value                                                        •    Pull Up Method
•   Change Unidirectional Association to Bidirectional                               •    Push Down Field
•   Change Value to Reference                                                        •    Push Down Method
•   Collapse Hierarchy                                                               •    Reduce Scope of Variable by Mats Henricson
•   Consolidate Conditional Expression                                               •    Refactor Architecture by Tiers (Link Only)
•   Consolidate Duplicate Conditional Fragments                                      •    Remove Assignments to Parameters
•   Convert Dynamic to Static Construction by Gerard M. Davison                      •    Remove Control Flag
•   Convert Static to Dynamic Construction by Gerard M. Davison                      •    Remove Double Negative by Ashley Frieze and Martin Fowler
•   Decompose Conditional                                                            •    Remove Middle Man
•   Duplicate Observed Data                                                          •    Remove Parameter
•   Eliminate Inter-Entity Bean Communication (Link Only)                            •    Remove Setting Method
•   Encapsulate Collection                                                           •    Rename Method
•   Encapsulate Downcast                                                             •    Replace Array with Object
•   Encapsulate Field                                                                •    Replace Assignment with Initialization by Mats Henricson
•   Extract Class                                                                    •    Replace Conditional with Polymorphism
•   Extract Interface                                                                •    Replace Conditional with Visitor by Ivan Mitrovic
•   Extract Method                                                                   •    Replace Constructor with Factory Method
•   Extract Package by Gerard M. Davison                                             •    Replace Data Value with Object
•   Extract Subclass                                                                 •    Replace Delegation with Inheritance
•   Extract Superclass                                                               •    Replace Error Code with Exception
•   Form Template Method                                                             •    Replace Exception with Test
•   Hide Delegate                                                                    •    Replace Inheritance with Delegation
•   Hide Method                                                                      •    Replace Iteration with Recursion by Dave Whipp
•   Hide presentation tier-specific details from the business tier (Link Only)       •    Replace Magic Number with Symbolic Constant
•   Inline Class                                                                     •    Replace Method with Method Object
•   Inline Method                                                                    •    Replace Nested Conditional with Guard Clauses
•   Inline Temp                                                                      •    Replace Parameter with Explicit Methods
•   Introduce A Controller (Link Only)                                               •    Replace Parameter with Method
•   Introduce Assertion                                                              •    Replace Record with Data Class
•   Introduce Business Delegate (Link Only)                                          •    Replace Recursion with Iteration by Ivan Mitrovic
•   Introduce Explaining Variable                                                    •    Replace Static Variable with Parameter by Marian Vittek
•   Introduce Foreign Method                                                         •    Replace Subclass with Fields
•   Introduce Local Extension                                                        •    Replace Temp with Query
•   Introduce Null Object                                                            •    Replace Type Code with Class
•   Introduce Parameter Object                                                       •    Replace Type Code with State/Strategy
•   Introduce Synchronizer Token (Link Only)                                         •    Replace Type Code with Subclasses
•   Localize Disparate Logic (Link Only)                                             •    Reverse Conditional by Bill Murphy and Martin Fowler
•   Merge Session Beans (Link Only)                                                  •    Self Encapsulate Field
•   Move Business Logic to Session (Link Only)                                       •    Separate Data Access Code (Link Only)
•   Move Class by Gerard M. Davison                                                  •    Separate Query from Modifier
•   Move Field                                                                       •    Split Loop by Martin Fowler
•   Move Method                                                                      •    Split Temporary Variable
•   Parameterize Method                                                              •    Substitute Algorithm
•   Preserve Whole Object                                                            •    Use a Connection Pool (Link Only)
                                                                                     •    Wrap entities with session (Link Only)



                                                                  «Безудержный Refactoring», (с) 2008                                                 11 из 77
Наиболее популярные
•   Rename
•   Extract method
•   Change signature
•   Encapsulate field
•   Introduce variable

• Extract superclass
• Replace constructor with factory
  method
                «Безудержный Refactoring», (с) 2008   12 из 77
Современные среды автоматизируют
 выполнение многих рефакторингов,
        избавляя от рутины




          «Безудержный Refactoring», (с) 2008   13 из 77
Даже автоматические рефакторинги
не гарантируют полную корректность
• Чисто синтаксического анализа кода не
  хватает – нужен семантический (и
  зачастую весьма продвинутый)

• Далее пример весьма распространенной
  ситуации с переименованием члена
  класса, имя которого используется как
  литерал
• Современные инструменты решают эту
  проблему, но в полуавтоматическом
  режиме (т.е. остается место для ошибки!)

              «Безудержный Refactoring», (с) 2008   14 из 77
«Безудержный Refactoring», (с) 2008   15 из 77
 Примеры «запахов»
 «Броузинг» при чтении кода
 Дублирование кода:
  пример выполнения рефакторинга
 Всегда ли плохо дублирование?

 КОД С ДУШКОМ

              «Безудержный Refactoring», (с) 2008   16 из 77
«Код с душком» (запахи, smells)
• Имя не отражает функциональность
    • Тыква => Карета


• Длинные методы
    • Что такое «длинные»? Несколько экранов?
    • Есть и обратная ситуация (много мелких
      методов)


• Дублирование кода

                «Безудержный Refactoring», (с) 2008   17 из 77
Размер метода и концепция
        «броузинга» при чтении кода
public void PrintSpecialText()                • Много мелких
{
                                                приватных методов,
                                                используемых в одном
    PrintAlfa();
    PrintBeta();
    PrintGamma();                               месте – тоже плохо
}                                               (на ровном месте
private void PrintAlfa()
                                                увеличивается
{                                               «косвенность» при
    Console.WriteLine("alfa");                  чтении кода)
}

private void PrintBeta()                      • Обратите внимание,
{                                               что для многих
                                                рефакторингов есть
    Console.WriteLine("beta");
}
                                                обратные:
private void PrintGamma()                                  • Extract Method
{
                                                           • Inline Method
    Console.WriteLine("gamma");
}


                          «Безудержный Refactoring», (с) 2008                 18 из 77
Самый популярный «запах»
- дублирование кода

Пример из реального кода
 • C# 1
 • WinForms-приложение
  • Метод вычисления стиля
    элемента грида (по XML-
    описанию)


               «Безудержный Refactoring», (с) 2008   19 из 77
«Безудержный Refactoring», (с) 2008   20 из 80
«Безудержный Refactoring», (с) 2008   21 из 77
«Безудержный Refactoring», (с) 2008   22 из 80
«Безудержный Refactoring», (с) 2008   23 из 77
Итак, как было
                                                                   RowCol

                                                            …
          XMLTableHelper
                                                            ...
…                                                           get_Style() : CellStyle
                                                            set_Style(CellStyle)
...                                                         ...
NewStyleFromXML(RowCol, …)
NewStyleFromXML(inout CellRange, …)
...
                                                                  <<value>>
                                                                  CellRange
                                                            ...
                                                            Style : CellStyle
                                                            ...


                                                            …


                      «Безудержный Refactoring», (с) 2008                        24 из 77
К чему преобразуем
                                                    XMLTableHelper



                                                      StyledElement


                                        get_Style() : CellStyle {abstract}
                                        get_NewClearStyle() : CellStyle {abstract}

                                        NewStyleFromXML(XMLNode, bool)




       RowCol                StyledElementForRowCol                   StyledElementForCell
                                                                                                      <<value>>
…                                                                                                     CellRange
                           .ctor(RowCol, …)                     .ctor(CellRange, …)
...                                                                                               ...
get_Style() : CellStyle    get_Style() : CellStyle              get_Style() : CellStyle           Style : CellStyle
set_Style(CellStyle)       get_NewClearStyle() : CellStyle      get_NewClearStyle() : CellStyle   ...
...
                                                                                                  …




                                       «Безудержный Refactoring», (с) 2008                            25 из 77
«Безудержный Refactoring», (с) 2008   26 из 77
«Безудержный Refactoring», (с) 2008   27 из 80
«Безудержный Refactoring», (с) 2008   28 из 80
«Безудержный Refactoring», (с) 2008   29 из 77
«Безудержный Refactoring», (с) 2008   30 из 77
А если бы был C# 2.0 или выше
    – то всё было бы проще!


• За нас всѐ сделал бы компилятор:
  – Анонимные делегаты
  – Автоматические замыкания

  – И не надо городить иерархии классов…


              «Безудержный Refactoring», (с) 2008   31 из 77
«Безудержный Refactoring», (с) 2008   32 из 77
Дублирование кода
– это всегда плохо?

Моѐ авторское мнение:


   НЕ ВСЕГДА!




    «Безудержный Refactoring», (с) 2008   33 из 77
Пример
                            CustIS::DataAccess



                                 Cursor




CustIS::DataAccess::MySql
                                                 CustIS::DataAccess::OdpNet


       MySqlCursor                                      OdpNetCursor




                          Реализации похожи,
                     но должны быть независимы

                  «Безудержный Refactoring», (с) 2008                         34 из 77
Ингода борьба с дублированием
  кода начинает мне напоминать
         «охоту на ведьм»
• Я видел много кода с большим
  дублированием, который было не
  сложно сопровождать и развивать

• И видел код вообще без
  дублирования, который очень сложно
  развивать и сопровождать
            «Безудержный Refactoring», (с) 2008   35 из 77
 Две крайности
 Traceability исправлений
 Чем плох
  «безудержный» рефакторинг
 Пример
 Темная сторона инструментов
  автоматического анализа кода

АНТИПАТТЕРНЫ ПРОВЕДЕНИЯ РЕФАКТОРИНГА

               «Безудержный Refactoring», (с) 2008   36 из 77
Две крайности




 «Безудержный Refactoring», (с) 2008   37 из 77
«Везде оставь свой след»
 убивает трассируемость изменений
       Кто изменил
            Что изменил
                 Зачем изменил

• Имея номер бага (дела, issue) нужно уметь отвечать
   • какие изменения в коде это повлекло?
   • кто их сделал?
• А для фрагмента кода:
   • в связи с чем он написан/исправлен?
   • кто это сделал?
• По номеру ревизии:
   • какие баги исправлены, какие фичи вошли?

                     «Безудержный Refactoring», (с) 2008   38 из 77
Источник: «Интеграция систем управления разработкой», Фомин С.

                           «Безудержный Refactoring», (с) 2008   39 из 77
Номер бага




«Безудержный Refactoring», (с) 2008   40 из 80
К этой картинке хочется добавить:
историю изменений тоже читают!




          «Безудержный Refactoring», (с) 2008   41 из 77
Итак, избыточный рефакторинг может
«зашумить» историю изменений
Далее следует пример

         «Безудержный Refactoring», (с) 2008   42 из 77
«Безудержный Refactoring», (с) 2008   43 из 80
«Безудержный Refactoring», (с) 2008   44 из 80
«Безудержный Refactoring», (с) 2008   45 из 80
Что мы видели?
• Под видом рефакторинга проведено
  банальное «причесывание» кода,
  причем вкусовое (ни качества, ни
  понятности оно не добавило)

• То, что действительно следовало бы
  поменять (заменить сложные условия на
  методы, избавиться от литеральных
  строк в пользу строковых констант и т.д.)
  – не сделано
              «Безудержный Refactoring», (с) 2008   46 из 77
Откуда это берется
1. Смена «окружения»
  –   Новая версия языка/библиотек
  –   Новые модные паттерны и/или изменение в
      осознании «мировых истин»
  –   Другой стандарт кодирования
2. Темная сторона инструментов
   автоматической проверки кода
  – Анекдот про то, кто такой зануда
3. «Я преобразую код, чтобы разобраться в
   нем»
  – Опасно, когда руки работают вперед головы!

                «Безудержный Refactoring», (с) 2008   47 из 77
Даже 100% покрытие кода
   UNIT-тестами не дает гарантий
• В императивных языках поведение
  одного и того же фрагмента кода может
  сильно отличаться в зависимости от
  «окружения» (side-эффекты)
• Особенно остро это чувствуется при:
  – многопоточном программировании
  – работе с СУБД
  – взаимодействии с внешними системами и
    устройствами
  – GUI

              «Безудержный Refactoring», (с) 2008   48 из 77
   Пример советов R#
   catch {}
   Опасности
   Опять семантика! Пример

ТЕМНАЯ СТОРОНА                       АВТОМАТИЧЕСКОЙ
                                     ПРОВЕРКИ КОДА

                «Безудержный Refactoring», (с) 2008   49 из 77
ReSharper (R#) – отличный инструмент
Но даже на солнце бывают пятна…

Далее идет пример его советов на
фрагментах кода


            «Безудержный Refactoring», (с) 2008   50 из 77
«Безудержный Refactoring», (с) 2008   51 из 80
To «var» or not to «var»
                                              Илья Рыженков
                                                из JetBrains
                                               перечисляет
                                               ряд выгод от
                                              использования
                                                    VAR




                                               Dare Obasanjo
                                               из RSS Bandit
                                              не соглашается




        «Безудержный Refactoring», (с) 2008      52 из 77
А более «тяжеловесные»
      инструменты типа FxCop?
• Здесь любимый пример, когда они
  эффективны:

  – Контроль соглашений по именованию
    • при этом семантику названия они проверить
      не могут!


  – Контроль типичных «ляпов» a la
  catch (Exception) { /*пусто*/ }
               «Безудержный Refactoring», (с) 2008   53 из 77
Пытался найти по кодам наших
    проектов, но обнаружил только в
    MS Visual Studio 2005 SDK ver. 4.0

Скачать можно отсюда:
•   http://www.microsoft.com/downloads/details.aspx?familyid=51A5C65B-C020-4E08-8AC0-
    3EB9C06996F4&displaylang=en


Далее идут выдержки из файлов:
• .VSSDK40MPFShellTaskProvider.cs
• .VSSDK40MPFShellPackage.cs




                              «Безудержный Refactoring», (с) 2008               54 из 77
Я понимаю, когда подавляют все исключения при финализации,
но здесь же ситуация явного вызова освобождения ресурса!




                  «Безудержный Refactoring», (с) 2008   55 из 80
А вот вообще «волшебный» фрагмент кода с такими же «волшебными»
комментариями:
- что-то пытаемся сделать
- а если не смогли, то это оказывается не проблема!
  (и можно ничего не делать…)
- зачем тогда вообще пытались что-то сделать?!




                        «Безудержный Refactoring», (с) 2008   56 из 77
А вот всё же вставлена хоть какая-то диагностика.
НО! Она будет только в Debug-варианте…

А как разбираться и диагностировать проблемы,
имея на руках только Release?

Не лучше бы было писать файловый лог
или использовать Windows Event Log,
который как раз и задуман на случаи, когда программе надо на что-то
пожаловаться, а куда жаловаться – не понятно ?!




                           «Безудержный Refactoring», (с) 2008        57 из 77
Итак, опасности:
• Слепое следование советам этих
  инструментов

• Формальное исправление замечаний (без
  понимания, лишь бы отвязалась)

• Ложное чувство уверенности в качестве
  кода

• При этом, на настройку этих
  инструментов может уходить много сил
             «Безудержный Refactoring», (с) 2008   58 из 77
«Безудержный Refactoring», (с) 2008   59 из 77
Опять же, не хватает семантики!
• Пример из жизни достаточно
  распространенного и опасного ляпа,
  который не ловится инструментами
  автоматической проверки кода:

  • Immutable (неизменный) класс для
    хранения многополевого
    первичного ключа

            «Безудержный Refactoring», (с) 2008   60 из 77
«Безудержный Refactoring», (с) 2008   61 из 80
Этот класс весьма уязвим,
и то, что _values объявлен как readonly –
                не спасает:




             «Безудержный Refactoring», (с) 2008   62 из 77
Исправление ситуации




     «Безудержный Refactoring», (с) 2008   63 из 80
Книга насчитывает около сотни весьма ценных
практических статей-советов, только процентов 5
 из которых можно проверить автоматически…




                «Безудержный Refactoring», (с) 2008   64 из 77
   Преемственность
   Дополнения к стандарту кодирования
   Общие аккуратные настройки инструментов
   Code review, как эффективная профилактика

ТАК КАК ЖЕ БЫТЬ

                «Безудержный Refactoring», (с) 2008   65 из 77
1. Культивируйте преемственность
• Умение понимать и следовать
  чужим идеям:
  – прежде чем изменять код,
    его следует понять
  – прежде чем реализовывать новую
    функциональность, поищите – не реализовано
    ли уже где-то что-то аналогичное
  – если что-то не нравится в том, как
    аналогичную задачу решили до вас, то не
    надо молча делать новое по-своему, а старое
    оставлять по-прежнему (либо менять и там, и
    там, либо наступить себе на горло и делать
    аналогично старому)
                «Безудержный Refactoring», (с) 2008   66 из 77
Про преемственность
Если до вас рыли норы, то не нужно начинать рыть траншеи
только на том основании, что лично вам оно так удобнее



               «Безудержный Refactoring», (с) 2008         67 из 77
2. Дополнения к
      стандарту кодирования

• Стандарт кодирования должен быть! 

• Дополните его разделом «Внесение
 изменений в существующий код»
 примерно со следующим
 содержанием



            «Безудержный Refactoring», (с) 2008   68 из 77
• следует уважать и по возможности
  сохранять авторский стиль форматирования:
  – если объем исправлений мал и код не
    удовлетворяет текущим правилам
    форматирования, то исправления должны быть
    внесены в стиле форматирования
   существующего кода
  – если объем исправлений достаточно велик, то
    новые куски могут быть отформатированы в
    соответствии с текущими представлениями о
    правильном стиле, а форматирование остальных
    частей должно быть оставлено как есть
  – весь файл может быть переформатирован только
    в случае почти полного его переписывания (т.е.
    почти полной замены старой реализации на
    новую)
                 «Безудержный Refactoring», (с) 2008   69 из 77
• формальное следование советам
  инструментов автоматического анализа
  кода не может считаться "выполнением
  рефакторинга"
  – это допустимо выполнять (например,
    устранять warning-и ReSharper-а) только при
    условии необходимости внесения в данный
    файл существенных исправлений логики
   (мелкий патчинг, который выражается в
   правке одной-пяти строк кода не может
   считаться существенным исправлением)

                «Безудержный Refactoring», (с) 2008   70 из 77
• Объемные рефакторинги следует
  фиксировать отдельными (от
  исправлений функциональности) commit-
  ами с соответствующим комментарием




             «Безудержный Refactoring», (с) 2008   71 из 80
3. Настройка инструментов




       «Безудержный Refactoring», (с) 2008   72 из 77
• Обеспечьте, чтобы у всех
  разработчиков были одинаковые
  настройки используемых
  инструментов (форматирования и
  проверки кода)

• Причем эти настройки должны
  соответствовать принятым у вас
  соглашениям


             «Безудержный Refactoring», (с) 2008   73 из 77
4. Code review:
   лучшее лечение – это профилактика

            коллега                                   аналитик
                                                       или PO



                             (2) Code Review
сборочный                                              (3) Сделано то, что нужно?     Feedback
сервер      (1) автоматические
                                                       Оно работает? Это удобно?

            сборка + тесты
                                                                                    демо

                                                               Feedback




                         «Безудержный Refactoring», (с) 2008                        74 из 77
Советы по проведению Code Review:
1. Code review выполнять обязательно и сразу
   после реализации бага (как часть Defenition-
   of-Done)
2. Пары автор-проверяющий должны
   образовываться «самопроизвольно» и меняться
3. Найденные недочеты лучше изложить в
   системе ведения дел, чтобы сам автор их
   устранил. Если их много и они сложные –
   проверяющий и автор садятся за клавиатуру
   вместе
  –   это важно, чтобы был «обучающий» эффект
      (ошибки/проблемы больше не повторялись)
  –   разногласия обсуждаются устно (можно с
      привлечением других членов команды)

                  «Безудержный Refactoring», (с) 2008   75 из 77
Сильно повышает качество!
  Проверено практикой




       «Безудержный Refactoring», (с) 2008   76 из 77
Контакты: andrew@custis.ru
Материал опубликован: www.custis.ru



СПАСИБО ЗА ВНИМАНИЕ!
ВОПРОСЫ?
                 «Безудержный Refactoring», (с) 2008   77 из 77

More Related Content

More from Andrey Bibichev

Быстрое введение в TDD от А до Я
Быстрое введение в TDD от А до ЯБыстрое введение в TDD от А до Я
Быстрое введение в TDD от А до ЯAndrey Bibichev
 
Фрактальная природа IT-проектов (блиц)
Фрактальная природа IT-проектов (блиц)Фрактальная природа IT-проектов (блиц)
Фрактальная природа IT-проектов (блиц)Andrey Bibichev
 
Usability-for-programmers
Usability-for-programmersUsability-for-programmers
Usability-for-programmersAndrey Bibichev
 
Natural User Interface (WUDRU-2011)
Natural User Interface (WUDRU-2011)Natural User Interface (WUDRU-2011)
Natural User Interface (WUDRU-2011)Andrey Bibichev
 
Архитектура в Agile: слабая связность
Архитектура в Agile: слабая связностьАрхитектура в Agile: слабая связность
Архитектура в Agile: слабая связностьAndrey Bibichev
 
Пользовательский автоматизм
Пользовательский автоматизмПользовательский автоматизм
Пользовательский автоматизмAndrey Bibichev
 
Обзор Feature-Driven Development и Domain-Driven Design
Обзор Feature-Driven Development и Domain-Driven DesignОбзор Feature-Driven Development и Domain-Driven Design
Обзор Feature-Driven Development и Domain-Driven DesignAndrey Bibichev
 
О текстовом вводе замолвите слово
О текстовом вводе замолвите словоО текстовом вводе замолвите слово
О текстовом вводе замолвите словоAndrey Bibichev
 
Проектирование больших ИС в Agile (статья)
Проектирование больших ИС в Agile (статья)Проектирование больших ИС в Agile (статья)
Проектирование больших ИС в Agile (статья)Andrey Bibichev
 
Проектирование больших ИС в Agile
Проектирование больших ИС в AgileПроектирование больших ИС в Agile
Проектирование больших ИС в AgileAndrey Bibichev
 
Enterprise Level Agile The Art Of Start
Enterprise Level Agile   The Art Of StartEnterprise Level Agile   The Art Of Start
Enterprise Level Agile The Art Of StartAndrey Bibichev
 
Humane Interface (Гуманный интерфейс)
Humane Interface (Гуманный интерфейс)Humane Interface (Гуманный интерфейс)
Humane Interface (Гуманный интерфейс)Andrey Bibichev
 

More from Andrey Bibichev (20)

Быстрое введение в TDD от А до Я
Быстрое введение в TDD от А до ЯБыстрое введение в TDD от А до Я
Быстрое введение в TDD от А до Я
 
Фрактальная природа IT-проектов (блиц)
Фрактальная природа IT-проектов (блиц)Фрактальная природа IT-проектов (блиц)
Фрактальная природа IT-проектов (блиц)
 
Usability-for-programmers
Usability-for-programmersUsability-for-programmers
Usability-for-programmers
 
Geeks vs Managers
Geeks vs ManagersGeeks vs Managers
Geeks vs Managers
 
Tdd and decomposition
Tdd and decompositionTdd and decomposition
Tdd and decomposition
 
Mockist vs Classicist
Mockist vs ClassicistMockist vs Classicist
Mockist vs Classicist
 
Natural User Interface (WUDRU-2011)
Natural User Interface (WUDRU-2011)Natural User Interface (WUDRU-2011)
Natural User Interface (WUDRU-2011)
 
Puasson burning
Puasson burningPuasson burning
Puasson burning
 
Архитектура в Agile: слабая связность
Архитектура в Agile: слабая связностьАрхитектура в Agile: слабая связность
Архитектура в Agile: слабая связность
 
Пользовательский автоматизм
Пользовательский автоматизмПользовательский автоматизм
Пользовательский автоматизм
 
Augmented Reality
Augmented RealityAugmented Reality
Augmented Reality
 
Agile: Think different
Agile: Think differentAgile: Think different
Agile: Think different
 
BDD
BDDBDD
BDD
 
DDD Workshop
DDD WorkshopDDD Workshop
DDD Workshop
 
Обзор Feature-Driven Development и Domain-Driven Design
Обзор Feature-Driven Development и Domain-Driven DesignОбзор Feature-Driven Development и Domain-Driven Design
Обзор Feature-Driven Development и Domain-Driven Design
 
О текстовом вводе замолвите слово
О текстовом вводе замолвите словоО текстовом вводе замолвите слово
О текстовом вводе замолвите слово
 
Проектирование больших ИС в Agile (статья)
Проектирование больших ИС в Agile (статья)Проектирование больших ИС в Agile (статья)
Проектирование больших ИС в Agile (статья)
 
Проектирование больших ИС в Agile
Проектирование больших ИС в AgileПроектирование больших ИС в Agile
Проектирование больших ИС в Agile
 
Enterprise Level Agile The Art Of Start
Enterprise Level Agile   The Art Of StartEnterprise Level Agile   The Art Of Start
Enterprise Level Agile The Art Of Start
 
Humane Interface (Гуманный интерфейс)
Humane Interface (Гуманный интерфейс)Humane Interface (Гуманный интерфейс)
Humane Interface (Гуманный интерфейс)
 

Безудержный рефакторинг: как не убиться об стену

  • 1. Безудержный REFACTORING или как не убиться об стену Бибичев Андрей 2008 год, декабрь www.custis.ru
  • 2. Определение  Поводы  Каталог  Самые популярные  Автоматический рефакторинг НА ПРАВАХ ВВЕДЕНИЯ «Безудержный Refactoring», (с) 2008 2 из 77
  • 3. Классический труд XP «Безудержный Refactoring», (с) 2008 3 из 77
  • 4. Цитируем wikipedia… Рефакторинг или Реорганизация — процесс полного или частичного преобразования внутренней структуры программы при сохранении еѐ внешнего поведения. В его основе лежит последовательность небольших эквивалентных (т.е., сохраняющих поведение) преобразований Источник: http://ru.wikipedia.org/wiki/Рефакторинг «Безудержный Refactoring», (с) 2008 4 из 77
  • 5. Продолжаем цитировать … Рефакторинг изначально не предназначен для исправления ошибок и добавления новой функциональности, но помогает избежать ошибок и облегчить добавление функциональности. Он выполняется для улучшения понятности кода или изменения его структуры, для удаления «мѐртвого кода» — всѐ это для того, чтобы в будущем код было легче поддерживать и развивать Источник: http://ru.wikipedia.org/wiki/Рефакторинг «Безудержный Refactoring», (с) 2008 5 из 77
  • 6. Откуда может возникнуть необходимость в рефакторинге? «Безудержный Refactoring», (с) 2008 6 из 77
  • 7. 1. Унаследованный (legacy) код «Код надо писать так, как будто его будет поддерживать и сопровождать законченный маньяк, который знает ваш домашний адрес…» «Безудержный Refactoring», (с) 2008 7 из 77
  • 8. 2. «Второй проход» по свеженаписанной функциональности «Первое лезвие бреет чисто, второе – еще чище» «Безудержный Refactoring», (с) 2008 8 из 77
  • 9. 3. Инкрементальный дизайн «Безудержный Refactoring», (с) 2008 9 из 77
  • 10. Так как это делать? - Есть целый каталог рефакторингов!!! http://www.refactoring.com/catalog/index.html «Безудержный Refactoring», (с) 2008 10 из 77
  • 11. Add Parameter • Pull Up Constructor Body • Change Bidirectional Association to Unidirectional • Pull Up Field • Change Reference to Value • Pull Up Method • Change Unidirectional Association to Bidirectional • Push Down Field • Change Value to Reference • Push Down Method • Collapse Hierarchy • Reduce Scope of Variable by Mats Henricson • Consolidate Conditional Expression • Refactor Architecture by Tiers (Link Only) • Consolidate Duplicate Conditional Fragments • Remove Assignments to Parameters • Convert Dynamic to Static Construction by Gerard M. Davison • Remove Control Flag • Convert Static to Dynamic Construction by Gerard M. Davison • Remove Double Negative by Ashley Frieze and Martin Fowler • Decompose Conditional • Remove Middle Man • Duplicate Observed Data • Remove Parameter • Eliminate Inter-Entity Bean Communication (Link Only) • Remove Setting Method • Encapsulate Collection • Rename Method • Encapsulate Downcast • Replace Array with Object • Encapsulate Field • Replace Assignment with Initialization by Mats Henricson • Extract Class • Replace Conditional with Polymorphism • Extract Interface • Replace Conditional with Visitor by Ivan Mitrovic • Extract Method • Replace Constructor with Factory Method • Extract Package by Gerard M. Davison • Replace Data Value with Object • Extract Subclass • Replace Delegation with Inheritance • Extract Superclass • Replace Error Code with Exception • Form Template Method • Replace Exception with Test • Hide Delegate • Replace Inheritance with Delegation • Hide Method • Replace Iteration with Recursion by Dave Whipp • Hide presentation tier-specific details from the business tier (Link Only) • Replace Magic Number with Symbolic Constant • Inline Class • Replace Method with Method Object • Inline Method • Replace Nested Conditional with Guard Clauses • Inline Temp • Replace Parameter with Explicit Methods • Introduce A Controller (Link Only) • Replace Parameter with Method • Introduce Assertion • Replace Record with Data Class • Introduce Business Delegate (Link Only) • Replace Recursion with Iteration by Ivan Mitrovic • Introduce Explaining Variable • Replace Static Variable with Parameter by Marian Vittek • Introduce Foreign Method • Replace Subclass with Fields • Introduce Local Extension • Replace Temp with Query • Introduce Null Object • Replace Type Code with Class • Introduce Parameter Object • Replace Type Code with State/Strategy • Introduce Synchronizer Token (Link Only) • Replace Type Code with Subclasses • Localize Disparate Logic (Link Only) • Reverse Conditional by Bill Murphy and Martin Fowler • Merge Session Beans (Link Only) • Self Encapsulate Field • Move Business Logic to Session (Link Only) • Separate Data Access Code (Link Only) • Move Class by Gerard M. Davison • Separate Query from Modifier • Move Field • Split Loop by Martin Fowler • Move Method • Split Temporary Variable • Parameterize Method • Substitute Algorithm • Preserve Whole Object • Use a Connection Pool (Link Only) • Wrap entities with session (Link Only) «Безудержный Refactoring», (с) 2008 11 из 77
  • 12. Наиболее популярные • Rename • Extract method • Change signature • Encapsulate field • Introduce variable • Extract superclass • Replace constructor with factory method «Безудержный Refactoring», (с) 2008 12 из 77
  • 13. Современные среды автоматизируют выполнение многих рефакторингов, избавляя от рутины «Безудержный Refactoring», (с) 2008 13 из 77
  • 14. Даже автоматические рефакторинги не гарантируют полную корректность • Чисто синтаксического анализа кода не хватает – нужен семантический (и зачастую весьма продвинутый) • Далее пример весьма распространенной ситуации с переименованием члена класса, имя которого используется как литерал • Современные инструменты решают эту проблему, но в полуавтоматическом режиме (т.е. остается место для ошибки!) «Безудержный Refactoring», (с) 2008 14 из 77
  • 16.  Примеры «запахов»  «Броузинг» при чтении кода  Дублирование кода: пример выполнения рефакторинга  Всегда ли плохо дублирование? КОД С ДУШКОМ «Безудержный Refactoring», (с) 2008 16 из 77
  • 17. «Код с душком» (запахи, smells) • Имя не отражает функциональность • Тыква => Карета • Длинные методы • Что такое «длинные»? Несколько экранов? • Есть и обратная ситуация (много мелких методов) • Дублирование кода «Безудержный Refactoring», (с) 2008 17 из 77
  • 18. Размер метода и концепция «броузинга» при чтении кода public void PrintSpecialText() • Много мелких { приватных методов, используемых в одном PrintAlfa(); PrintBeta(); PrintGamma(); месте – тоже плохо } (на ровном месте private void PrintAlfa() увеличивается { «косвенность» при Console.WriteLine("alfa"); чтении кода) } private void PrintBeta() • Обратите внимание, { что для многих рефакторингов есть Console.WriteLine("beta"); } обратные: private void PrintGamma() • Extract Method { • Inline Method Console.WriteLine("gamma"); } «Безудержный Refactoring», (с) 2008 18 из 77
  • 19. Самый популярный «запах» - дублирование кода Пример из реального кода • C# 1 • WinForms-приложение • Метод вычисления стиля элемента грида (по XML- описанию) «Безудержный Refactoring», (с) 2008 19 из 77
  • 24. Итак, как было RowCol … XMLTableHelper ... … get_Style() : CellStyle set_Style(CellStyle) ... ... NewStyleFromXML(RowCol, …) NewStyleFromXML(inout CellRange, …) ... <<value>> CellRange ... Style : CellStyle ... … «Безудержный Refactoring», (с) 2008 24 из 77
  • 25. К чему преобразуем XMLTableHelper StyledElement get_Style() : CellStyle {abstract} get_NewClearStyle() : CellStyle {abstract} NewStyleFromXML(XMLNode, bool) RowCol StyledElementForRowCol StyledElementForCell <<value>> … CellRange .ctor(RowCol, …) .ctor(CellRange, …) ... ... get_Style() : CellStyle get_Style() : CellStyle get_Style() : CellStyle Style : CellStyle set_Style(CellStyle) get_NewClearStyle() : CellStyle get_NewClearStyle() : CellStyle ... ... … «Безудержный Refactoring», (с) 2008 25 из 77
  • 31. А если бы был C# 2.0 или выше – то всё было бы проще! • За нас всѐ сделал бы компилятор: – Анонимные делегаты – Автоматические замыкания – И не надо городить иерархии классов… «Безудержный Refactoring», (с) 2008 31 из 77
  • 33. Дублирование кода – это всегда плохо? Моѐ авторское мнение: НЕ ВСЕГДА! «Безудержный Refactoring», (с) 2008 33 из 77
  • 34. Пример CustIS::DataAccess Cursor CustIS::DataAccess::MySql CustIS::DataAccess::OdpNet MySqlCursor OdpNetCursor Реализации похожи, но должны быть независимы «Безудержный Refactoring», (с) 2008 34 из 77
  • 35. Ингода борьба с дублированием кода начинает мне напоминать «охоту на ведьм» • Я видел много кода с большим дублированием, который было не сложно сопровождать и развивать • И видел код вообще без дублирования, который очень сложно развивать и сопровождать «Безудержный Refactoring», (с) 2008 35 из 77
  • 36.  Две крайности  Traceability исправлений  Чем плох «безудержный» рефакторинг  Пример  Темная сторона инструментов автоматического анализа кода АНТИПАТТЕРНЫ ПРОВЕДЕНИЯ РЕФАКТОРИНГА «Безудержный Refactoring», (с) 2008 36 из 77
  • 37. Две крайности «Безудержный Refactoring», (с) 2008 37 из 77
  • 38. «Везде оставь свой след» убивает трассируемость изменений Кто изменил Что изменил Зачем изменил • Имея номер бага (дела, issue) нужно уметь отвечать • какие изменения в коде это повлекло? • кто их сделал? • А для фрагмента кода: • в связи с чем он написан/исправлен? • кто это сделал? • По номеру ревизии: • какие баги исправлены, какие фичи вошли? «Безудержный Refactoring», (с) 2008 38 из 77
  • 39. Источник: «Интеграция систем управления разработкой», Фомин С. «Безудержный Refactoring», (с) 2008 39 из 77
  • 41. К этой картинке хочется добавить: историю изменений тоже читают! «Безудержный Refactoring», (с) 2008 41 из 77
  • 42. Итак, избыточный рефакторинг может «зашумить» историю изменений Далее следует пример «Безудержный Refactoring», (с) 2008 42 из 77
  • 46. Что мы видели? • Под видом рефакторинга проведено банальное «причесывание» кода, причем вкусовое (ни качества, ни понятности оно не добавило) • То, что действительно следовало бы поменять (заменить сложные условия на методы, избавиться от литеральных строк в пользу строковых констант и т.д.) – не сделано «Безудержный Refactoring», (с) 2008 46 из 77
  • 47. Откуда это берется 1. Смена «окружения» – Новая версия языка/библиотек – Новые модные паттерны и/или изменение в осознании «мировых истин» – Другой стандарт кодирования 2. Темная сторона инструментов автоматической проверки кода – Анекдот про то, кто такой зануда 3. «Я преобразую код, чтобы разобраться в нем» – Опасно, когда руки работают вперед головы! «Безудержный Refactoring», (с) 2008 47 из 77
  • 48. Даже 100% покрытие кода UNIT-тестами не дает гарантий • В императивных языках поведение одного и того же фрагмента кода может сильно отличаться в зависимости от «окружения» (side-эффекты) • Особенно остро это чувствуется при: – многопоточном программировании – работе с СУБД – взаимодействии с внешними системами и устройствами – GUI «Безудержный Refactoring», (с) 2008 48 из 77
  • 49. Пример советов R#  catch {}  Опасности  Опять семантика! Пример ТЕМНАЯ СТОРОНА АВТОМАТИЧЕСКОЙ ПРОВЕРКИ КОДА «Безудержный Refactoring», (с) 2008 49 из 77
  • 50. ReSharper (R#) – отличный инструмент Но даже на солнце бывают пятна… Далее идет пример его советов на фрагментах кода «Безудержный Refactoring», (с) 2008 50 из 77
  • 52. To «var» or not to «var» Илья Рыженков из JetBrains перечисляет ряд выгод от использования VAR Dare Obasanjo из RSS Bandit не соглашается «Безудержный Refactoring», (с) 2008 52 из 77
  • 53. А более «тяжеловесные» инструменты типа FxCop? • Здесь любимый пример, когда они эффективны: – Контроль соглашений по именованию • при этом семантику названия они проверить не могут! – Контроль типичных «ляпов» a la catch (Exception) { /*пусто*/ } «Безудержный Refactoring», (с) 2008 53 из 77
  • 54. Пытался найти по кодам наших проектов, но обнаружил только в MS Visual Studio 2005 SDK ver. 4.0 Скачать можно отсюда: • http://www.microsoft.com/downloads/details.aspx?familyid=51A5C65B-C020-4E08-8AC0- 3EB9C06996F4&displaylang=en Далее идут выдержки из файлов: • .VSSDK40MPFShellTaskProvider.cs • .VSSDK40MPFShellPackage.cs «Безудержный Refactoring», (с) 2008 54 из 77
  • 55. Я понимаю, когда подавляют все исключения при финализации, но здесь же ситуация явного вызова освобождения ресурса! «Безудержный Refactoring», (с) 2008 55 из 80
  • 56. А вот вообще «волшебный» фрагмент кода с такими же «волшебными» комментариями: - что-то пытаемся сделать - а если не смогли, то это оказывается не проблема! (и можно ничего не делать…) - зачем тогда вообще пытались что-то сделать?! «Безудержный Refactoring», (с) 2008 56 из 77
  • 57. А вот всё же вставлена хоть какая-то диагностика. НО! Она будет только в Debug-варианте… А как разбираться и диагностировать проблемы, имея на руках только Release? Не лучше бы было писать файловый лог или использовать Windows Event Log, который как раз и задуман на случаи, когда программе надо на что-то пожаловаться, а куда жаловаться – не понятно ?! «Безудержный Refactoring», (с) 2008 57 из 77
  • 58. Итак, опасности: • Слепое следование советам этих инструментов • Формальное исправление замечаний (без понимания, лишь бы отвязалась) • Ложное чувство уверенности в качестве кода • При этом, на настройку этих инструментов может уходить много сил «Безудержный Refactoring», (с) 2008 58 из 77
  • 60. Опять же, не хватает семантики! • Пример из жизни достаточно распространенного и опасного ляпа, который не ловится инструментами автоматической проверки кода: • Immutable (неизменный) класс для хранения многополевого первичного ключа «Безудержный Refactoring», (с) 2008 60 из 77
  • 62. Этот класс весьма уязвим, и то, что _values объявлен как readonly – не спасает: «Безудержный Refactoring», (с) 2008 62 из 77
  • 63. Исправление ситуации «Безудержный Refactoring», (с) 2008 63 из 80
  • 64. Книга насчитывает около сотни весьма ценных практических статей-советов, только процентов 5 из которых можно проверить автоматически… «Безудержный Refactoring», (с) 2008 64 из 77
  • 65. Преемственность  Дополнения к стандарту кодирования  Общие аккуратные настройки инструментов  Code review, как эффективная профилактика ТАК КАК ЖЕ БЫТЬ «Безудержный Refactoring», (с) 2008 65 из 77
  • 66. 1. Культивируйте преемственность • Умение понимать и следовать чужим идеям: – прежде чем изменять код, его следует понять – прежде чем реализовывать новую функциональность, поищите – не реализовано ли уже где-то что-то аналогичное – если что-то не нравится в том, как аналогичную задачу решили до вас, то не надо молча делать новое по-своему, а старое оставлять по-прежнему (либо менять и там, и там, либо наступить себе на горло и делать аналогично старому) «Безудержный Refactoring», (с) 2008 66 из 77
  • 67. Про преемственность Если до вас рыли норы, то не нужно начинать рыть траншеи только на том основании, что лично вам оно так удобнее «Безудержный Refactoring», (с) 2008 67 из 77
  • 68. 2. Дополнения к стандарту кодирования • Стандарт кодирования должен быть!  • Дополните его разделом «Внесение изменений в существующий код» примерно со следующим содержанием «Безудержный Refactoring», (с) 2008 68 из 77
  • 69. • следует уважать и по возможности сохранять авторский стиль форматирования: – если объем исправлений мал и код не удовлетворяет текущим правилам форматирования, то исправления должны быть внесены в стиле форматирования существующего кода – если объем исправлений достаточно велик, то новые куски могут быть отформатированы в соответствии с текущими представлениями о правильном стиле, а форматирование остальных частей должно быть оставлено как есть – весь файл может быть переформатирован только в случае почти полного его переписывания (т.е. почти полной замены старой реализации на новую) «Безудержный Refactoring», (с) 2008 69 из 77
  • 70. • формальное следование советам инструментов автоматического анализа кода не может считаться "выполнением рефакторинга" – это допустимо выполнять (например, устранять warning-и ReSharper-а) только при условии необходимости внесения в данный файл существенных исправлений логики (мелкий патчинг, который выражается в правке одной-пяти строк кода не может считаться существенным исправлением) «Безудержный Refactoring», (с) 2008 70 из 77
  • 71. • Объемные рефакторинги следует фиксировать отдельными (от исправлений функциональности) commit- ами с соответствующим комментарием «Безудержный Refactoring», (с) 2008 71 из 80
  • 72. 3. Настройка инструментов «Безудержный Refactoring», (с) 2008 72 из 77
  • 73. • Обеспечьте, чтобы у всех разработчиков были одинаковые настройки используемых инструментов (форматирования и проверки кода) • Причем эти настройки должны соответствовать принятым у вас соглашениям «Безудержный Refactoring», (с) 2008 73 из 77
  • 74. 4. Code review: лучшее лечение – это профилактика коллега аналитик или PO (2) Code Review сборочный (3) Сделано то, что нужно? Feedback сервер (1) автоматические Оно работает? Это удобно? сборка + тесты демо Feedback «Безудержный Refactoring», (с) 2008 74 из 77
  • 75. Советы по проведению Code Review: 1. Code review выполнять обязательно и сразу после реализации бага (как часть Defenition- of-Done) 2. Пары автор-проверяющий должны образовываться «самопроизвольно» и меняться 3. Найденные недочеты лучше изложить в системе ведения дел, чтобы сам автор их устранил. Если их много и они сложные – проверяющий и автор садятся за клавиатуру вместе – это важно, чтобы был «обучающий» эффект (ошибки/проблемы больше не повторялись) – разногласия обсуждаются устно (можно с привлечением других членов команды) «Безудержный Refactoring», (с) 2008 75 из 77
  • 76. Сильно повышает качество! Проверено практикой «Безудержный Refactoring», (с) 2008 76 из 77
  • 77. Контакты: andrew@custis.ru Материал опубликован: www.custis.ru СПАСИБО ЗА ВНИМАНИЕ! ВОПРОСЫ? «Безудержный Refactoring», (с) 2008 77 из 77