Статьи

Использование PHP CodeSniffer с WordPress: понимание запахов кода

Часто способ написания кода зависит от того, как мы начали программировать.

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

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

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

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

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

Но сначала давайте познакомимся с запахами кода.

В зависимости от типа разработчика, которого вы спрашиваете, вы, вероятно, получите вариант следующего определения:

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

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

  1. «Длинный метод является хорошим примером этого — просто глядя на код и мой нос дергается, если я вижу больше дюжины строк Java».
  2. «Запахи сами по себе не являются плохими — они часто являются показателем проблемы, а не самой проблемы».
  3. «Классы данных (классы со всеми данными и без поведения) являются хорошими примерами».

Если вы не читали статью, он заканчивает этим:

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

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

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

Конечно, когда речь заходит о такой теме, как запахи кода, часто проще говорить о них на абстрактном уровне, чем на самом деле что-то с ними делать. Но это не практично и не применимо к нашей повседневной работе.

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

Один из самых простых запахов кода — это когда программист решил использовать нечеткие имена переменных. То есть в контексте кода неясно, что должна представлять данная переменная.

Конечно, бывают случаи, когда это приемлемо (например, использование i в цикле for ). Но в более длинном методе это не совсем то же самое, что и for цикла).

Например:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<?php
public function get_things( $x ) {
 
  $l = array();
 
  for ( $i = 0; $i < count( $x ); $i++ ) {
 
    if ( true === $x[ $i ] ) {
      array_push( $l, $x[ $i ] );
    }
 
  }
 
  return $l;
 
}

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

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

Вместо этого давайте сделаем рефакторинг так, чтобы это выглядело так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?php
 
public function get_flagged_items( $items ) {
 
  $flagged_items = array();
 
  for ( $i = 0; $i < count( $items ); $i++ ) {
 
    $current_item = $items[ $i ] ;
 
    if ( true === $current_item ) {
      array_push( $flagged_items, $current_item );
    }
  }
 
  return $flagged_items;
 
}

Намного легче понять, не так ли?

Обратите внимание, что сам алгоритм не изменился, но изменились имя функции и имена переменных. Это сильно повлияло на чтение этого кода. Если спросить, что этот код должен делать, мы можем легко сказать что-то вроде:

Возвращает массив элементов, помеченных как истинные, из предварительно определенного массива элементов.

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

В программировании вам будет сложно найти разработчика, который не слышал о KISS или DRY (вы знаете, «не повторяйтесь»). Несмотря на это, мы часто повторяем себя.

Это свидетельствует о том, что попытки придерживаться принципов DRY по-разному связаны с разными типами программистов. И это нормально! Нет единого способа продемонстрировать, как придерживаться этого принципа.

Но поскольку есть несколько способов сделать это, мы можем привести пример того, как он не должен выглядеть и как он должен выглядеть.

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

1
2
3
4
5
6
7
8
9
<?php
 
public function save_posts() {
 
  save_post( 1, ‘Hello World!’ );
  save_post( 2, ‘Goodbye World!’ );
  save_post( 3, ‘What is this new world?’ );
 
}

Но зачем нам вручную вводить вызов save_post три раза? Вместо этого давайте настроим ассоциативный массив, пройдемся по нему и затем вызовем метод один раз за итерацию.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<?php
 
public function save_posts() {
 
  $posts = [
    1 => ‘Hello World!’,
    2 => ‘Goodbye World!’,
    3 => ‘What is this new world?’,
  ];
 
  foreach ( $post as $post_id => $post_title ) {
    save_post( $post_id, $post_title );
  }
   
}

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

Если вы обнаружите, что вызываете один и тот же метод несколько раз в функции, но с другими параметрами, возможно, у вас запах кода. А если вы это сделаете, то поищите способы его рефакторинга, чтобы вызывать метод только один раз.

В конце концов, вы не хотите повторяться.

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

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

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

01
02
03
04
05
06
07
08
09
10
11
<?php
 
public function submit_order( $first, $last, $address1, $address2, $city, $state, $zip, $phone, $cc, $expiration ) {
 
  /* Attempt to submit the order.
   * then return an instance of an Order object with the success status;
   * otherwise, return an instance of an Order object with the failed status
   * and a message.
   */
   
}

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

Это даже не касается темы проверки и валидации. Но я отвлекся на это.

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

Детали этого могут быть реализованы с использованием бизнес-логики в другом месте приложения, но абстракция будет выглядеть примерно так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
 
class Contact_Information {
  /* Maintains attributes of the person’s contact information.
}
 
class Payment_Information {
  /* Maintains the credit card number and other information for a person.
}
 
class Order {
 
  public function submit( $contact_info, $payment_info ) {
 
    /* Attempt to submit the order.
     * then return an instance of an Order object with the success status;
     * otherwise, return an instance of an Order object with the failed status
     * and a message.
     */
     
  }
}

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

  1. Создан класс Contact_Information который позволяет нам создавать экземпляр объекта, который включает в себя всю платежную информацию для человека.
  2. Создан класс Payment_Information который позволяет нам поддерживать номер кредитной или дебетовой карты для человека, а также другие данные, связанные с этим методом оплаты.
  3. Создал класс Order , поместил в submit_order функцию submit_order , переименовал его для отправки (поскольку submit_order был бы избыточен) и сократил список параметров до двух значений: экземпляр класса Payment_Information класс Payment_Information ).

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

Но дело не в этом.

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

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

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

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

И вот куда мы направляемся дальше. В частности, мы собираемся использовать PHP CodeSniffer, чтобы помочь нам избежать запахов кода в нашем коде. Затем мы увидим, как включить правила WordPress в PHP CodeSniffer и подключить их к нашей IDE.

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

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

Помните, что вы можете просмотреть все мои курсы и учебные пособия на странице моего профиля , и вы можете следить за мной в моем блоге и / или Twitter по адресу @tommcfarlin, где я рассказываю о различных методах разработки программного обеспечения и о том, как мы можем использовать их в WordPress.

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