Рефакторинг — это крайне важная часть процесса разработки. Писать код «который работает» не есть залогом производительного приложения. Рефакторинг дает возможность привести код в надлежащий вид, что позволит в дальнейшем этот код легко читать, использовать повторно, поддерживать и расширять саму систему.

Проектирование


Начало хорошего кода — это всегда проектирование. Программисты, которые не умеют утихомирить страсть к написанию кода, этим опуская проектирование, пишут обычно быстро, но не качественно. Я это знаю, так как сам имел ту же проблему. Проектирование дает возможность взглянуть на систему, которой еще фактически нету, продумать правильную структуру приложения и данных, увидеть тонкости, риски, подумать о производительности и безопасности. При этом проектирование это не только прерогатива начала проекта. Проектирование — это неотъемлемая часть, при разработке любой «Feature».

Начать проектировать можно очень легко. Всегда держите на рабочем месте блокнот и несколько цветов ручек. Прежде чем писать код, нарисуйте схему — как приложение будет работать в целом, UML-диаграмму классов (продумайте как можно с минимальным количеством классов, достигнуть максимального результата), структуру баз данных (оптимизируйте БД еще до ее создания, подумайте какие запросы у вас должны будут «бегать» к вашей БД, продумайте индексы, конечно же нормализируйте вашу модель данных).

Для тех же целей подойдет простая программа для проектирования starUML. Минус ее в том, что нельзя нормально устанавливать мощность отношений (кратность), но сам интерфейс очень удобный.

Проектировать нужно даже для того, чтобы потом не пришлось рефакторить структурные ошибки, а еще хуже переписывать вообще весь модуль.

Несколько принципов, которые точно нужно знать при проектировании классов вашей «Feature»:

1. SOLID (single responsibility, open-closed, Liskov substitution, interface segregation и dependency inversion)

Это основа основ в проектировании классов. Если вы еще не знакомы с SOLID, здесь можно ознакомиться.

2. DRY (do not repeat yourself)

Повторяющейся функционал делает приложение громоздким, а его поддержку более дорогостоящей и неудобной. Это относится как к модулям, так и к небольшим фрагментам кода.

К примеру:

— Вместо того, чтобы использовать три строчки кода в нескольких местах, можно поместить их в функцию и использовать всего лишь одну строку кода — вызов функции.

— Вместо использования функции progress50(), лучше применить более абстрактную progress($percent).

— Отдавать предпочтение внешним зависимостям между модулями, внутренним (DI), что делает модуль более гибким и позволяет его использовать в нескольких местах.

3. KISS (keep it simple, stup...)

Чем проще ваше решение для сложной задачи, тем более оно совершенно, так же это правило работает в обратную сторону. Чтобы научиться делать простые решения, нужно научиться разделять вашу задачу на очень маленькие подзадачи. Двигаясь от меньшего к большему. В последствии, мы получаем результат сложной задачи.

К примеру:

Вам нужно написать класс для генерации Excel отчета с вашей БД. Нужно весь отчет разделить на части: установка заголовков таблицы, вывод статистических данных в документ, вывод подвала документа, создание диаграммы. Некоторые части функционала можно вынести в отдельные классы, что даст возможность использовать их повторно.

Стиль кода


Рефакторинг стиля кода вообще не влияет на производительность приложения. Тем не менее, он дает преимущество для его читаемости и поддержки. Другой программист должен легко читать ваш код, без вникания в реализацию деталей, а это, конечно же, экономит время и деньги.

Стандарт стиля кода (и не только) PSR (PHP Standards Recommendations), здесь можно ознакомиться. Содержимое на английском языке, так как английский более ясно дает понять степень применения одного или другого правила («MUST», «MUST NOT», «REQUIRED», «SHALL», «SHALL NOT», «SHOULD», «SHOULD NOT», «RECOMMENDED», «MAY», and «OPTIONAL»).

Несколько замечаний, которые автор счел важными:

1. Ознакомьтесь с PHPDOC для написания комментариев к вашему коду.

2. Лучший комментарий — это правильно названный класс, метод, параметр или переменная.

3. Используйте утилиты PHPMD, PHPCS, их применение шире, чем только для определения несоответствий в стиле кода. Вот документация: PHPMD, PHPCS.

4. Используйте продвинутое IDE.

Рефакторинг в чистом виде


Очень простая аксиома — на продакшн должен попадать только код, прошедший рефакторинг. Иногда после разработки вы сами делаете рефакторинг, что очень даже не плохо (к примеру, разработка через тестирование вообще включает рефакторинг, как обязательный шаг, так как изначально пишется «работающий код», а потом уже «чистый»), но для того, чтобы код был по-настоящему качественным, он должен пройти проверку кода (code-review) другим программистом. Если проект позволяет выделить время на проверку кода, то на таком проекте ты будешь учиться писать код чище и чище, что в последствии приведет к автоматическому написанию качественного кода.

Я помню, как работал на одну компанию, и проверку кода у меня делал человек, который не всегда мог сдерживать свои эмоции, из-за чего о моем не чистом коде слышали все в open space. Поэтому мне приходилось учиться писать качественный код, очень быстро, чтобы избежать подобных случаев.

Вернемся к теме. В этой части статьи я бы хотел дать несколько практических подходов к рефакторингу, которыми пользуюсь сам.

1. Длинные методы (лучше разделить функционал на несколько методов).

2. Громоздкие классы (ваш класс должен исполнять одну функциональную задачу в вашей системе).

3. Неясная структура класса (методы в хаотическом порядке, конструктор в середине класса, вместо констант — магические значения в коде — класс должен легко отображать, что он делает в правильной последовательности).

4. Слишком много параметров в методе (некоторые расчеты можно сделать внутри метода, используя внутренние константы, значения полученные с атрибутов и геттеров).

5. Классы, содержащие одинаковые переменные и методы. Проблему можно решить через создание дополнительного класса).

6. Сложно читаемый IF (выражение можно вынести в отдельную переменную и разделить на логические части, которые также вынести в переменные, если много проверок на null, то лучше всего использовать NullObject — количество проверок значительно уменьшится).

7. Громоздкий SWITH (выносим в отдельный метод).

8. Использование наследования из-за одинаковых методов и свойств, в разных по своей сути сущностях (кошка и стул имеют ноги, но их нельзя группировать в категорию «животные»).

9. Слишком большое количество маленьких классов для выполнения одной задачи, которые в последствии сложнее поддерживать.

10. Слишком сложный функционал в одном классе, который можно разделить на несколько классов.

11. Класс делает слишком мало, чтобы его оставлять в системе.

12. «Мертвый код» — его следует удалить.

13. Не использованные структуры классов, которые вы проектировали на будущее, но они так и не пригодились — такие лучше удалить.

14. Методы класса больше используются в другом классе, а в своем вообще не используются или же реже (стоит перенести метод в тот класс, где он больше используется).

15. Слишком длинная цепочка вызовов ($a->b()->c()->d()->e()), в этом случае стоит создать дополнительные методы.

16. Класс, содержащий только один метод, который создает другой класс. (Такой класс нужно использовать с умом, к примеру, для паттерна «Прокси», в противном случае этот класс только увеличивает время и ресурс на поддержку проекта).

17. Слишком много действий в конструкторе. (Конструктор должен только устанавливать свойства класса, если же в конструкторе создаются другие классы, происходят какие-то расчеты, то это делает его сложным для понимания, приходится вникать в суть реализации. Чтобы создать объект и выполнить какие-то действия, добавьте статический метод create($param1, ...), который создаст экземпляр класса с дополнительными действия над ним, этот метод можно назвать более подходящим к тому, что он будет все же делать).

Список литературы


» Source Making
» PSR
» UML
Поделиться с друзьями
-->

Комментарии (61)


  1. claygod
    15.08.2016 14:02
    +4

    Предлагаю в статье упормянуть и принцип YAGNI,
    хотя он именно с рефакторингом имеет некоторые противоречия.


    1. nekrasov_dmytro
      15.08.2016 15:37
      -1

      +


  1. alexhott
    15.08.2016 14:18
    -2

    А еще проектировать должен проектировщик, периодически консультируясь с постановщиком и кодером


    1. Delphinum
      15.08.2016 17:14

      Часто проектировщик и кодер (брр… не люблю это слово) это одно и то же лицо.


    1. Fesor
      15.08.2016 17:47
      +2

      проектировщик должен кодить, что бы адекватно все было. Если он только проектирует — это бесполезная трата времени и ресурсов.


    1. ilnuribat
      15.08.2016 18:21
      +1

      Такая модель практиковалась на моей прошлой работе — это действительно идеальный вариант.
      Проектировщик — программист со стажем более 20 лет, который досконально знает все подводные камни, просто «рисует», как должно быть, а также может и ТЗ составить. Конечный программист реализует тело функции, у которого уже есть имя, входные-выходные параметры и что она должна делать.
      Так вот, этот человек на моей старой работе, сам никакого когда не пишет — только дает указания, как сделать то или иное, а также и советуется с программистами.
      Так что, в хороших компаниях всё построено именно так, как Вы говорите


      1. Delphinum
        15.08.2016 18:30
        +1

        Конечный программист реализует тело функции, у которого уже есть имя, входные-выходные параметры и что она должна делать

        Называйте вещи своими именами, не «конечный программист», а «печатная машинка».


        1. igorch96
          16.08.2016 10:02

          Печатная машинка отлаживать баги не умеет…


          1. Delphinum
            16.08.2016 11:08
            +1

            Печатная машинка с функцией отладки багов? Ну можно так.


  1. JustLuckyGuy
    15.08.2016 14:40

    *удалено*


  1. SamDark
    15.08.2016 15:03
    +2

    Ещё стоит упомянуть принцип разделения контекстов, из которого следует, что не всё то DRY, что на DRY похоже.


    1. nekrasov_dmytro
      15.08.2016 15:37

      Да, это верно!


  1. AndreyRubankov
    15.08.2016 15:06

    оптимизируйте БД еще до ее создания, подумайте какие запросы у вас должны будут «бегать» к вашей БД, продумайте индексы, конечно же нормализируйте вашу модель данных

    Совет правильный — ко всему нужно подходить с умом. Но тут нужно быть осторожными, т.к. очень легко свалиться в Преждевременную оптимизацию. А от этого в перспективе вреда будет на много больше, чем пользы.

    Например, хорошо нормализованная база данных на старте проекта в перспективе выльется в большое количество запросов или в сложный запрос с множеством джоинов, чтобы вытянуть одно поле.


    1. samizdam
      15.08.2016 20:59

      Совет содержит взаимоисключающие параграфы.
      >>> оптимизируйте БД еще до ее создания… конечно же нормализируйте вашу модель данных
      преждевременная оптимизация, имхо зло. А вот совершенно нормализованная структура, ну никак не сможет быть оптимальной, с точки зрения производительности.
      К базе данных применимы свои методики рефакторинга, описанные кстати как в литературе и так и интернет статьях.

      А, так, после труда Фаулера, и упомянутого в комментариях Макконнелла, сложно что-либо добавить к теме. Для себя нового не почерпнул, но считаю, подобные статьи всё же на правильную мельницу воду льют: глядишь, кто-то с сотой статьи всерьёз для себя вопросом задумается, и до первоисточников дойдёт.


    1. igorch96
      16.08.2016 10:10

      Где-то в 90х-2000х ходил принцип: сделай, чтобы работало, потом профилируй и оптимизируй.


      1. samizdam
        21.08.2016 14:02

        Я склонен и в 2010-ых его придерживаться.


  1. ErickSkrauch
    15.08.2016 15:26

    Я бы ещё добавил про максимальное использование phpdoc блоков для прописывания типов переменных, получаемых, скажем, из того же DI, что в последствии значительно упростит статический анализ в «продвинутой IDE».


    1. nekrasov_dmytro
      15.08.2016 15:26

      100%


    1. samizdam
      21.08.2016 14:03

      С php 7 это уже мало актуально.


      1. ErickSkrauch
        21.08.2016 20:54

        Нет. Возможно, это актуально в том случае, когда ты внутри (условно) модели выносишь получение объекта из DI в метод. Ок, можно поставить возвращаемый тип как интерфейс этого объекта. Но что ты будешь делать в пободном кейсе (пример на Yii2):

        $someResult = Yii::$app->myContainer->myMethod();
        


        В таком случае уместно решить эту проблему 2-мя путями: использовать этот метод или же писать так:

        /** @var MyContainerClass $myContainer */
        $myContainer = Yii::$app->myContainer; 
        $someResult = $myContainer->myMethod();
        


        1. samizdam
          21.08.2016 21:04

          Да, по поводу DI Вы правы, «этот метод» мы используем с Yii до сих пор, и после перехода на 7.
          В тоже время можно писать в переопределённом Application геттеры для всех компонентов и статически типизировать возвращаемые значения. Приняв такое соглашение, можно вовсе обойтись без док-блоков.


          1. Fesor
            21.08.2016 22:37

            Да, по поводу DI Вы правы

            это не DI, это сервис локатор, в этом то и проблема.


            1. Delphinum
              22.08.2016 00:39

              Это как вы определили паттерн по вызову метода у переменной приложения? Или я что то упустил?


              1. Fesor
                22.08.2016 02:07
                +1

                ну вот смотрите. Это сервис локатор:


                $myContainer = Yii::$app->myContainer; 

                То есть все динамичненько, и мы понятия не имеем какой тип у объекта хранящегося в myContainer.


                А вот dependency injection:


                class SomeClass
                {
                    public function __construct(MyContainer $container)
                    {
                        // ...
                    }
                }

                То есть все зависимости и их типы декларируются явно и при таком раскладе никаких "проблем с автокомлитом" быть не может. Проблемы с определением типов могут быть только при использовании service locator.


                Ну и в целом использование контейнера напрямую — моветон. Это можно делать только на уровне фреймворка.


                1. Delphinum
                  22.08.2016 11:38
                  -1

                  Все равно не понял, что там ErickSkrauch дергал у контейнера и как вы узнали, что этот контейнер именно локатор. Ну да ладно, видимо это я дурак.


                  1. Fesor
                    22.08.2016 16:50

                    Yii::$app->myContainer

                    вот это — сервис локатор. Что такое myContainer мне не известно. Как и статическому анализатору. Отсюда проблемы с автокомплитом. В случае инъекции зависимостей они декларируются как правило явно, и проблем быть не должно.


                    1. Delphinum
                      22.08.2016 16:55

                      $app это локатор? Может myContainer это локатор?


                      1. Fesor
                        22.08.2016 16:58

                        в Yii вы к зависимостям обращаетесь как? Yii::app->someComponent или Yii::app->myContainer->get(SomeComponent::class)?


                        1. Delphinum
                          22.08.2016 17:25

                          в Yii вы к зависимостям обращаетесь как?

                          Я хз, Yii не пользовался, потому и интересуюсь.


                          1. Fesor
                            22.08.2016 17:36

                            в любом случае. Если у вас есть что угодно, будь это Yii::app-> или же $container->get — это все сервис локатор. И возвращаемые типы можно узнать только в рантайме (или при помощи кастылей и плагинов к IDE).


                            В случае dependency injection получение зависимостей происходит сверху, а не по требованию. А стало быть зависимости и их типы прописаны явно. Мой комментарий относился преимущественно к этой фразе:


                            Возможно, это актуально в том случае, когда ты внутри (условно) модели выносишь получение объекта из DI в метод

                            и я пытаюсь объяснить что это никакого отношения к dependency injection не имеет. А сервис локатор и так признанный антипаттерн.


                            1. Delphinum
                              22.08.2016 17:38
                              -1

                              и я пытаюсь объяснить что это никакого отношения к dependency injection не имеет

                              Понятненько. Не увидел просто там ни SL, ни DI, вот и поинтересовался.
                              А сервис локатор и так признанный антипаттерн

                              А поделитесь ссылочкой.


                              1. Fesor
                                22.08.2016 18:08
                                +1

                                Не увидел просто там ни SL

                                как жеж? когда мы просим какой-то объект (Yii::$app в нашем случае) дать нам зависимость — это service locator. Точно так же как ларавелевские Cache::get, симфоневый $controller->get('cache') и тд.


                                А поделитесь ссылочкой.

                                и тут более подробнее по проблемам которые привносит хреново реализованный (а это 99% реализаций) сервис локатор:



                                В частности там описан "правильный" сервис локатор который решает большую часть проблем.


                                Справедливости ради, есть кейсы где сервис локатор норм. например в контроллерах: http://davedevelopment.co.uk/2016/06/01/service-locators-have-their-place.html


                                1. Delphinum
                                  22.08.2016 18:12

                                  когда мы просим какой-то объект (Yii::$app в нашем случае) дать нам зависимость

                                  Если мы просим какой то объект дать нам нашу зависимость, то да.
                                  и тут более подробнее по проблемам которые привносит хреново реализованный...

                                  Так проблема скорее не в SL, а в том, что он используется субъектами напрямую (агрегируется в субъектах). Разве нет?


                                  1. Fesor
                                    22.08.2016 22:08

                                    а в том, что он используется субъектами напрямую (агрегируется в субъектах). Разве нет?

                                    ну не только. В плане тестируемости самый удобный вариант это все же Dependency Injection. У DI есть свои недостатки, например необходимость делать прокси для лэйзи инициализации (что бы по мелочи не тянуть весь граф зависимостей а только по требованию). Это существенно усложняет реализацию. Но зато если использовать готовый контейнер — все мегаудобно.


                                    SL банально проще.


                                    1. Delphinum
                                      22.08.2016 22:43

                                      Тот же Zend советует использовать качественно сконфигурированный SL, вместо DI, ибо:
                                      * Проще отлавливать ошибки
                                      * Проще сконфигурировать
                                      * Быстрее работает

                                      Тем более не так давно они добавили в свой SL фабрику для создания proxy для lazy load сервисов на базе стороннего пакета.


  1. Delphinum
    15.08.2016 17:12

    Можно так же добавить, что unit-тесты являются лакмусовой бумажкой для кода проекта, а проект поддерживающий unit-тесты как правило куда более чистый, нежели проект, его не поддерживающий.


    1. Fesor
      15.08.2016 17:49
      -1

      только если unit-тесты были написаны до кода. Тогда это мощный интерфейс проектирования и выявления ошибок проектирования (когда тесты тяжело писать становится или неудобно). Не говоря уже о том что мы перед тем как что-то написать должны будем подумать что оно будет делать.


      1. Delphinum
        15.08.2016 17:50

        только если unit-тесты были написаны до кода

        Не обязательно. Если тесты пишутся после и их становится сложно писать, то становится понятно — проблема в коде и его пора рефакторить. Лакмусовая бумажка же.


        1. Fesor
          15.08.2016 21:20

          Итого мы имеем следующие расходы времени:


          • Программист потратил время на продумывание того что он хочет сделать
          • Программист потратил время на реализацию
          • Программист потратил время на тестирование (ему ж как-то надо было проверить что все работает?)
          • Программист потратил время на тесты и выявил необходимость рефакторинга
          • Программист потратил время на рефакторинг.

          Как-то много впустую потраченного времени, вам так не кажется?


          1. Delphinum
            15.08.2016 21:40

            При чем тут потраченное в пустую время и мой комментарий про «unit-тест = лакмусовая бумажка»?


            1. Fesor
              16.08.2016 00:11
              -1

              Это я к тому что тесты это хорошо, но эффективность страдать не должна. Когда тесты пишутся до кода, оверхэд на это значительно меньше. Причем этот оверхэд слихвой окупается в долгосрочной перспективе (даже если рассматривать 3-4 месяца разработки).


              Я не знаю кому нравится впустую тратить время.


              1. Delphinum
                16.08.2016 11:10

                Дак кто же спорит…


          1. nekrasov_dmytro
            15.08.2016 21:50

            Расход времени это цена за качественный продукт, проектирование, тестирование и рефакторинг просто необходимы для того что бы ваш код имел ценность.

            Я когда то работал на компанию где денег не было на нормальное проектирование, тестирование и рефакторинг соответственно. При этом начальство всегда было не довольно многими багами и даже на продакшене.
            Для меня эта работа сильно опустила мой проф. уровень и я лично не советую работать на компанию где пишут плохой код, потому что заказчик считает что проектирование, тестирование это фигня и кстати, он ещё говорит что сам все протестируют.
            Эти места работы портят программистов, делают с них кодеров из за чего в сети куча г. кода.

            Представьте себе что инженеры бы не проектировали айфон, а вот сразу приступили к разработке… Было бы что то ужасное, типо та фигня которая с Китая к нам лезет. Мы тоже инженеры, только софта.

            Надеюсь ответ был полным.


            1. Fesor
              16.08.2016 00:30
              -1

              Расход времени это цена за качественный продукт

              Есть масса способов получить качественный продукт без этих оверхэдов.


              проектирование, тестирование и рефакторинг просто необходимы для того что бы ваш код имел ценность.

              Я это не отрицаю. Я лишь говорю о нюансах влияющих на общую эффективность. То что тесты после кода (если это не автоматизация UI тестов какая) — это вэйстадж (в терминологии lean).


              Я когда то работал на компанию где денег не было на нормальное проектирование, тестирование и рефакторинг соответственно.

              У меня "тестирование/рефакторинг" отдельным пунктом не билится. Это часть моей работы. Клиенту важен только результат а не как "его туда довезли".


              Для меня эта работа сильно опустила мой проф. уровень и я лично не советую работать на компанию где пишут плохой код

              Плохой код пишут люди. Вообще есть такая проблемка… многие разработчики могут лет 5 работать и так и не увидеть нормальный код. А есть несчем сравнивать — то и свой код кажется неплохим. Со временем все это приобритает привычку.


              потому что заказчик считает что проектирование, тестирование это фигня и кстати, он ещё говорит что сам все протестируют.

              Знаете, годика 4 назад я так же рассуждал. Что мол "ох уж эти клиенты, опять не захотели тестирование", и мне очень просто сказали "А зачем ты предлагал? Они ж не понимают зачем это нужно, просто включи это в оценку по проекту и радуйся себе."


              В целом "нежелание клиента платить за непонятное для него" не должно влиять на те практики, которые конкретно вы применяете в работе. Например вы же не говорите ему "ну вот мой рейт на пару центов выше чем мог быть потому что мне надо оплачивать лицензию на PhpStorm" например.


              Представьте себе что инженеры бы не проектировали айфон, а вот сразу приступили к разработке…

              проектирование айфона и его разработка в глазах инженера это один и тот же процесс если что.


              Да и айфон к слову является неплохим исключением из правил. Это пример того, как компания работает с клиентом, который знает чего он хочет. Просто потому что клиентом выступал Стив Джобс, чья уникальность в том и заключалась, что он умел видеть что нужно кастомерам еще до того как те осознают что им это нужно. Таких людей оооочень мало.


              Подавляющее же количество людей понятия не имеет что они хотят. Как правило им нужно показывать результат что бы выяснить "попали или нет". А от того нужна итеративная разработка. Чуть-чуть попроектировали (возможно через тесты, TDD и BDD там всякие), чуть-чуть покодили, показали. И так по непрерывному кругу. И чем короче цикл обратной связи тем дешевле становится разработка, поскольку "неверные решения" будут выявлены раньше и не приведут к значительным расходам.


              p.s. вы когда-нибудь сидели на дэйли митинге? Ну тот который стандап но настолько долгий что люди садятся? Прикидывали примерно сколько денег это стоит вашим клиентам? Или плэнинги бесполезные по 4 часа… Или проекты которые начинаются с разработки второстепенного функционала вроде регистрации?


              1. nekrasov_dmytro
                16.08.2016 09:11

                p.s. вы когда-нибудь сидели на дэйли митинге? Ну тот который стандап но настолько долгий что люди садятся? Прикидывали примерно сколько денег это стоит вашим клиентам? Или плэнинги бесполезные по 4 часа… Или проекты которые начинаются с разработки второстепенного функционала вроде регистрации?


                Да, я знаю сколько обходиться это клиенту. И экономить деньги клиента это правильный подход, если можно исключить всякие бесполезности, то лучше это сделать.
                Как раз за счёт проектирования, тестирования(того же tdd, bdd), рефакторинга, мы секономим время и деньги.

                А так как мы говорили о рефакторинге, как раз код после рефакторинга дешевле поддерживать, — легче/быстрее изучать новому программисту, так как он без проблем читаеться, нету мусора (мертвого кода, избыточного кода, повторов, ...), все находиться на своих местах и т.д.

                Я понял вашу позицию о бесполезности использования времени и ресурсов на то что можно в конкретной ситуации не делать, я с вами согласен. Делать что бы было, тоже не надо…


                1. Fesor
                  16.08.2016 12:33

                  Как раз за счёт проектирования, тестирования(того же tdd, bdd)

                  интересный момент. TDD и BDD являются больше практиками проектирования а не тестирования. Тесты — это скорее побочный (и полезный) продукт этого вида деятельности.


            1. AndreyRubankov
              16.08.2016 10:15

              Для меня эта работа сильно опустила мой проф. уровень и я лично не советую работать на компанию где пишут плохой код

              Это демотивирует, это угнетает, но такой опыт тоже полезен. Чтобы понять, что не все в мире идеально, чтобы понять, зачем все же нужны эти тесты, проектирование, и почему не стоит спешить накодить.

              Да и в целом, чтобы понять, что ИТ мир полностью построен на костылях, на сколько грязных и коварных, что можно лишь удивляться, как это все еще работает.


      1. nekrasov_dmytro
        15.08.2016 19:38
        -1

        Да, tdd безусловно мощный инструмет, в любом случае до того как писать код(не имеет значение код теста или код самого класса), нужно проектировать структуру классов, связи между классами.

        Насчёт tdd, эта штука действительно учит мозг мыслить правильно и писать код с учетом того что в результате должно быть.


  1. ilnuribat
    15.08.2016 18:25
    +1

    Каждый раз, когда читаю такие статьи, думаю — неужели никто не читает Совершенный Код?
    Там ведь буква в букву написано то же самое
    А тут на хабре каждый раз всё это заново поднимается — как правильно называть функции, как проектировать…
    Все эти вопросы хорошо разобраны до 7 главы
    По сути, эта книга — настольная книга каждого разработчика


    1. Delphinum
      15.08.2016 18:29

      А в какой главе «Совершенного кода» обсуждается рефакторинг проекта? Видимо я что то недочитал (


      1. ilnuribat
        15.08.2016 19:38

        Там говорится, что нужно изначально писать так, чтобы не было нужно делать рефакторинг, который описывает автор
        В том числе там учитывается, что заказчик захочет поменять условия, задачи, и нужно делать архитектуру с неким запасом прочности, гибкости
        В общем, первые 5-7 глав — для проектировщиков
        остальные — для программистов
        ЗЫ: я сам читаю главу 8


        1. Delphinum
          15.08.2016 20:28

          Там говорится, что нужно изначально писать так, чтобы не было нужно делать рефакторинг, который описывает автор

          Ну теория часто далека от практики.


    1. KvanTTT
      15.08.2016 22:21
      +1

      Также порекомендую "Чистый код".


    1. Fesor
      16.08.2016 00:36
      +1

      У меня сложилось впечатление от этой книги что:


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

      p.s. Сам я от начала и до конца ее не читал, только отдельные главы. Потому мое мнение чисто субъективно и основано исключительно на общении людей, прочитавших эту книгу.


      1. Delphinum
        16.08.2016 11:12
        +1

        Периодически перечитываю эту книгу для повышения мотивации. Пока помогает.


      1. ilnuribat
        16.08.2016 11:15
        +1

        Хорошее замечание по поводу перечитывания
        Ведь недаром я написал — «настольная книга», то есть, его нужно перечитывать. Там слишком много деталей, слишком много тонкостей. Пока читаешь одну главу, успеваешь забыть все предыдущие
        Поэтому очень эффективным является применение всех знаний сразу после прочтения


      1. LifeKILLED
        18.08.2016 23:25

        Я читал то ли «Чистый код», то ли «Совершенный код», не помню, да и есть ли особая разница. Вещи банальные, но такому любителю, как я, открыли глаза. Как-то до этого я больше задумывался о лихости оптимизаций и хитрости алгоритмов, но когда прочёл, то понял, почему, когда я пытаюсь наваять что-то серьёзное, это тонет в багах и превращается в разлапистое Ктулху.

        Хорошо, что у профессионалов слово «рефакторинг» — обыденное и ходовое. Но блин… заглядывал в код к людям, которые зарабатывают этим на жизнь, и возникает ощущение, что слова с делами частееенько расходятся :(


        1. Fesor
          19.08.2016 12:39

          что слова с делами частееенько расходятся :(

          тут зависит от ситуации. Возможно чуваку на самом деле пофигу. А есть еще такая тема как traidable quality.


  1. nekrasov_dmytro
    15.08.2016 19:57

    Одну штуку которую я реально опустил в рефакторинге это рефакторинг клонов классов.
    Это очень распространённая проблема особенно когда проект переход из одной команды в другую или же приходит новый супер дев, в вашу команду, который не изучив структуру классов создаёт классы которые уже существуют или же классы функционал которых уже есть в других классах.

    На мой взгляд именно эта проблема в конечном счете уничтожает проект и рефакторинг делать очень сложно так как в разных частях проекта для исполнения одних и тех же действий используются разные классы.

    Так же не упомянул о важности разбираться с магическими циферками и буквочками в проекте, типа
    if ($a * 5) {
    Что значит 5 помнил программист который писал этот код, кстати помнил… но сам забыл…

    Очень важно для таких создавать дополнительную переменную если циферка 5 используется только в конкретном методе и не несёт в себе смыл такой что бы её поместить в константу класса, если же несёт выносим, или несёт смысл для нескольких классов выносим в глобальную.

    Я ещё много не написал я думаю вы сможете в коментах это сделать до меня и уже делаете, за что спасибо. Писал то что больше всего легло…


  1. LifeKILLED
    19.08.2016 00:22

    Придерусь к формулировкам, не более. Не ради критики или собственного ЧСВ, я не собираюсь спорить с автором… вы всё пишете правильно. Просто хочется помочь вам уточнить изложение мыслей в паре мест… сугубо по вашему желанию.

    продумайте как можно с минимальным количеством классов, достигнуть максимального результата


    Не совсем хорошо написано. Можно ведь вообще сделать один огромный неуклюжий класс, который никуда не сопроводишь и повторно нигде не используешь :) Понятно, что вы имели в виду именно более простую архитектуру, но не в числе классов ведь дело (поменять слово «класс» на «сущность»?). Тем более, далее по тексту у вас высказана противоположная мысль, показывающая, что вы как раз со мной согласны:

    Некоторые части функционала можно вынести в отдельные классы, что даст возможность использовать их повторно


    Вот-вот, всё же лучше будет больше классов, но лаконичных, типа вспомогательных или интерфейсов, но каждый из них будет независим и прост.

    Слишком много параметров в методе (некоторые расчеты можно сделать внутри метода, используя внутренние константы, значения полученные с атрибутов и геттеров)


    Как-то конкретно в коде PHP от этого не уйдёшь :( В итоге приходится передавать целые структуры данных в виде ассоциативных массивов, а конкретно — от backend во frontend. Но поскольку у всех элементов backend есть frontend, таких передач данных очень и очень много. Весь frontend на этом зиждется :(

    Классы, содержащие одинаковые переменные и методы. Проблему можно решить через создание дополнительного класса)


    Этого я вообще не понял, если честно :( Хотелось бы формулировку поточнее. Одинаковые переменные — внутри класса? Или одинаковые в том и в другом классе, и нужно вынести их и из первого, и из второго, в новый третий класс? Ну хоть убейте, не понял :(


    1. LifeKILLED
      19.08.2016 00:48

      Может, это и в личку стоило послать, как багфикс, но уж слишком пространные у меня тут размышления, поэтому решил оставить у всех на виду. Может, кто-то будет со мной не согласен, предложит свои варианты. Статейка-то хорошая, коротко, по делу, и есть ссылки на более подробную инфу, но тем не менее не нужно недооценивать желание некоторых читателей вырывать из контекста слова, поэтому советую всё же присмотреться к упомянутым мной формулировкам, дабы до некоторых читателей лучше дошёл посыл :)