Расширенный OOP для WordPress Часть 7: Рефакторинг это возможность принять тест-driven развития

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

Мы также не написали ни одного кода, который делает что-то практически полезное. Идея заключается в том, чтобы показать, как настроить поиск через WordPress REST API. Пример плагина, в точке, где я остановился просто возвращает массив WP_Posts . Но, общедоступный API для системы в настоящее время полностью разработан и имеет тесты, описывающие ее правильное поведение.

В моем личном путешествии в качестве разработчика, я принял тестирование более серьезным и менее серьезно в разы. Прямо сейчас, я в «TEST ALL THE THINGS!!!» режиме и одна из причин, я люблю это свобода рефакторинга. С непроверенным кодом, трудно рефакторинг, как вы не знаете, что побочные эффекты будут.

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

Обзор кода перед движением вперед

Когда я начал эту серию, Тоня Морк из Know The Code протянула руку и предложила обзор кода первой статьи. Она писала код обзор статей, что я надеюсь, что вы наслаждаетесь столько, сколько я.

Пример кода этой статьи действительно начинается с запроса, который Тоня добавила, чтобы пойти вместе со своей статьей Проектирование Swappable Search Request Реализации. Я согласился с ее отзывом и принял изменения, а затем мы обсудили дальнейшие изменения. Комментарии по этому запросу на вытягивание, по существу, являются черновой частью этой статьи и следующей в этой серии.

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

Что такое намерение?

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

Тоня подытожил наш разговор здесь, мы решили пройти вокруг и , как эти WP_Query WP_REST_Request объекты выразили намерение запроса HTTP для того, чтобы выполнить намерение нашего кода — мы хотим, чтобы запросы, чтобы получить возможность отправлять тип маршрутов, таких как / wp/v2/posts, чтобы быть более полезно для поиска на некоторых типах постов. Под более полезными мы подразумеваем различные WP_Query типы или результаты, генерируемые с другой системой.

Интерфейсы планирования как клей

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

Честно говоря, здесь я часто борюсь. У меня будет две или три системы, которые работают в изоляции, а затем будет трудно положить их вместе. Добавление новых интерфейсов, для ModifySchema которых изменяет схему конечных точек и ModifyQueryArgs которая изменяет WP_Query разрешенные args, было моим первым шагом к склеиванию всего вместе. Начиная там позволило мне определить форму, как они будут соединяться позже.

Ни один из этих классов не имел интерфейса. У них обоих есть shouldFilter() метод, но у них разные подписи. FiltersPreWPQuery shouldFilter() Это плохо пахло для меня.

Учитывая, что мне нужно провода произвольное количество реализаций, я предположил, что нам нужно будет подключить rest_{$post_type}_collection_params и для каждого типа rest_{$post_type}_query поста. Я на самом деле получил эту идею, когда я искал моей местной среде WordPress для этих крючков. Я пытался найти эти крючки в REST API и нашел, где Гутенберг использует их вместо Гутенберг крючки в обоих фильтров мы должны работать с rest_{$post_type}_collection_params и rest_{$post_type}_query здесь

Просмотр кода на Gist.

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

Начнем с рефакторинга класса, моделирующего схему REST API. Первым шагом является добавление интерфейса. Тем самым мы будем готовы преобразовать этот класс из класса, который изменяет схемы маршрута REST API, и превратить его в подменную реализацию класса, который изменяет схемы маршрута REST API.

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

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

Мой первый шаг при создании интерфейса для существующего класса заключается в добавлении пустого интерфейса и реализации исходного класса:

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

Вот ModifySchema прежде чем я начал рефакторинг:

Просмотр кода на Gist.

Я уже говорил ранее, моя цель состояла в том, чтобы сделать filterSchema метод ненужным. Хотя моя первая мысль была сделать интерфейс и filterSchema() shouldFilter() методы, потому что это то, что в настоящее время необходимо разоблачить публично. Но я хотел сделать так, чтобы «lt;код»gt;filterSchema»lt;/код»gt; ушел, поэтому я подумал о том, какую информацию этот класс должен сообщить:

  • Дополнительные аргументы схемы
  • Следует ли добавлять дополнительные аргументы схемы.

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

Просмотр кода на Gist.

Этот новый метод getAdditionalSchemaArguments() имеет тип-подсказку для того чтобы возвратить блок. Мы можем надежно использовать его позже, чтобы получить массив аргументов схемы. Оригинальный класс не имеет getAdditionalSchemaArguments() . Он имеет целый ряд аргументов, но они в настоящее время определены внутри filterSchema() , который не является то, что должно нести ответственность filterSchema() за, это вторая ответственность.

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

Просмотр кода на Gist.

В этой новой версии у нас все еще есть, filterSchema() но все, что он делает, это ручка фильтрации схемы. Данные предоставляются новым getAdditionalSchemaArguments() . Все три метода были там влинейные документы заменить с @inheritdoc аннотации. Это потому, что все они присутствуют в интерфейсе.

Просмотр кода на Gist.

Рассказывая историю сейчас, это спорно, если это стоило filterSchema() добавить в интерфейс, зная, что я собираюсь удалить это того стоило. Мне пришлось рефакторинг моего теста макеты в соответствии с этим интерфейсом, а также. После того, как интерфейс используется в реальном мире, изменение его назад изменения совместимости. Изменения подписи интерфейса происходят в обновлениях основной версии Laravel. Вы должны изменить ваши конкретные реализации, чтобы соответствовать или обновление вызывает фатальные ошибки.

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

У нас также есть ModifyQueryArgs класс, который отвечает за добавление аргументов в WP_Query белый список разрешенных аргументов запроса REST API.

Вот она реализована, чтобы добавить аргумент «пост тип» в разрешенный список:

Просмотр кода на Gist.

С этим классом, я чувствую тот же вопрос, как последний, это не общаться, что он будет изменять белый список с. Прежде чем мы сможем сделать filterQueryArgs() метод уйти, нам нужен метод, чтобы сообщить, что добавляется на фильтре. На этот раз getAdditionalQueryArguments() метод может сообщить, что:

Просмотр кода на Gist.

Мой первый шаг рефакторинга оригинального класса, чтобы сделать его соответствовать этому интерфейсу, который на данный момент поддерживает
filterQueryArgs().

Просмотр кода на Gist.

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

Создание частей подходят

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

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

В то время как мы играем с метафорами, стоит отметить, что одним из преимуществ Laravel является то, что его контейнер обслуживания обеспечивает автоматическое впрыск зависимости для автоматических зависимостей к классам. Например, в WordPress, если у меня есть маршрут REST API, который должен получить доступ к пользователю, я использую get_user_by() или WP_User новый, внутри метода обратного отвоза. В Laravel, я бы просто сделать модель пользователя аргумент контроллера обратного вызова и на основе его typehint, Laravel будет обрабатывать инъекционных пользовательской модели для моего обратного вызова.

Перекладывая эту ответственность за предоставление зависимости в контейнере обслуживания, мы называем это инверсией контроля, замена конкретных реализаций, например, использование макетов для тестирования гораздо проще.

Тоня имеет действительно хорошую серию на насмешливые объекты в WordPress. Мокинг является очень полезным навыком. Я считаю, что это самая медленная часть написания тестов и считаю, что, когда я пишу тесты для Laravel или React, насмешки приходит более естественным и включает в себя меньше макетов.

Я не говорю все это, чтобы вызвать WordPress. Напротив, я иду по касательной, чтобы объяснить преимущества подхода, который мы здесь преподаем. Вы можете иметь эти вещи в вашей разработке PHP и JavaScript. Код в этой статье и следующей статье был добавлен в пример плагина через этот запрос притяжения. В моем следующем посте, я буду продолжать показывать, как использовать тесты, чтобы помочь рефакторинг и лучше склеить систему.

Источник: torquemag.io

Добавить комментарий

%d такие блоггеры, как: