Статьи

Poka Yoke — Сохранение проектов с гиперзащитным программированием

Эта статья была рецензирована Дежи Акала и Марко Пиветта . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!


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

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

Обнаруженная ошибка

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

Итак, как мы можем предотвратить это? Введите «Покское иго» .

Что такое пока йок?

Poka Yoke — это японский термин, который примерно переводится как «защита от ошибок». Срок
возникла из бережливого производства, где речь идет о любом механизме, который помогает оператору машины избежать ошибок.

Вне производства Poka Yoke также часто используется в бытовой электронике. Возьмите, к примеру, SIM-карту, которая из-за своей асимметричной формы может быть вставлена ​​в лоток только одним способом.

SIM-карта и лоток, иллюстрирующие, как SIM-карта может быть установлена ​​только одним способом.

Примером отсутствия аппаратного обеспечения в Poka Yoke является порт PS / 2, который имеет точно такую ​​же форму для разъема клавиатуры и разъема мыши. Их можно различить только с помощью цветовых кодов, поэтому легко случайно переключить разъемы и вставить их в неправильные порты, поскольку они оба подходят одинаково.

Порты PS / 2 для клавиатур и мышей, иллюстрирующие, как они используют взаимозаменяемый формат, упрощающий случайную вставку одного в другой.

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

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

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

  • Предотвращение ошибок
  • Обнаружение ошибки

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

Механизмы обнаружения ошибок, с другой стороны, живут вне нашего кода. Они отслеживают наши приложения, чтобы отслеживать возможные ошибки и предупреждают нас о них. Примером может служить программное обеспечение, которое обнаруживает, имеет ли устройство, подключенное к порту PS / 2, правильного типа, и если не показывает предупреждение пользователю, поясняющее, почему оно не работает. Это конкретное программное обеспечение не может предотвратить ошибку, потому что разъемы являются взаимозаменяемыми при их подключении, но оно может обнаружить один и предупредить нас об этом, чтобы ошибка могла быть исправлена.

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

Примеры предотвращения ошибок

Целевой вирус, молекулярный масштаб CG рендер

(Скалярные) объявления типов

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

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

Например, давайте возьмем это Notification которое мы можем захотеть отправить пользователю:

 <?php class Notification { private $userId; private $subject; private $message; public function __construct( $userId, $subject, $message ) { $this->userId = $userId; $this->subject = $subject; $this->message = $message; } public function getUserId() { return $this->userId; } public function getSubject() { return $this->subject; } public function getMessage() { return $this->message; } } при <?php class Notification { private $userId; private $subject; private $message; public function __construct( $userId, $subject, $message ) { $this->userId = $userId; $this->subject = $subject; $this->message = $message; } public function getUserId() { return $this->userId; } public function getSubject() { return $this->subject; } public function getMessage() { return $this->message; } } 

Без объявлений типов мы можем легко внедрить неправильные типы переменных, которые, вероятно, сломают наше приложение. Например, мы можем предположить, что $userId должен быть string , тогда как на самом деле это может быть int .

Если мы введем неправильный тип, ошибка, вероятно, останется незамеченной, пока приложение не попытается что-то сделать с Notification . К тому времени мы, вероятно, получим какое-то загадочное сообщение об ошибке неожиданного типа, но ничего, что бы сразу указывало на наш код, где мы вставляем string вместо int .

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

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

 <?php declare(strict_types=1); class Notification { private $userId; private $subject; private $message; public function __construct( int $userId, string $subject, string $message ) { $this->userId = $userId; $this->subject = $subject; $this->message = $message; } public function getUserId() : int { return $this->userId; } public function getSubject() : string { return $this->subject; } public function getMessage() : string { return $this->message; } } 

Однако обратите внимание, что по умолчанию PHP будет пытаться привести неверные аргументы к ожидаемым типам. Чтобы предотвратить это, важно, чтобы мы strict_types чтобы на самом деле мы получали фатальную ошибку при совершении ошибки. Из-за этого объявления скалярных типов не являются идеальной формой Poka Yoke, но они являются хорошим началом для уменьшения ошибок. Даже с отключенным strict_types они могут служить указанием того, какой тип ожидается для аргумента.

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

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

Объекты значения

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

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

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

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

 class UserId { private $userId; public function __construct(int $userId) { $this->userId = $userId; } public function getValue() : int { return $this->userId; } } class Subject { private $subject; public function __construct(string $subject) { $this->subject = $subject; } public function getValue() : string { return $this->subject; } } class Message { private $message; public function __construct(string $message) { $this->message = $message; } public function getMessage() : string { return $this->message; } } class Notification { /* ... */ public function __construct( UserId $userId, Subject $subject, Message $message ) { $this->userId = $userId; $this->subject = $subject; $this->message = $message; } public function getUserId() : UserId { /* ... */ } public function getSubject() : Subject { /* ... */ } public function getMessage() : Message { /* ... */ } } 

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

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

Проверка

Список проверяемых флажков, аналогия с проверкой

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

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

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

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

Чтобы предотвратить такие ошибки, мы могли бы добавить некоторую проверку в конструктор UserId :

 class UserId { private $userId; public function __construct($userId) { if (!is_int($userId) || $userId < 0) { throw new \InvalidArgumentException( 'UserId should be a positive integer.' ); } $this->userId = $userId; } public function getValue() : int { return $this->userId; } } 

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

Обратите внимание, что мы могли бы добавить объявление скалярного типа вместо использования is_int здесь, но это заставило бы нас включать strict_types везде, где мы используем UserId .

Если бы мы не strict_types , PHP молча попытался бы принудительно заставить другие типы UserId к int всякий раз, когда они передаются в UserId . Это может быть проблематично, так как мы можем, например, ввести float которое на самом деле может быть неверной переменной, поскольку идентификаторы пользователя обычно не являются floats .

В других случаях, когда мы можем, например, работать с объектом значения Price , отключение strict_types может привести к ошибкам округления, поскольку PHP автоматически преобразует переменные с float в int .

неизменность

По умолчанию объекты передаются по ссылке в PHP. Это означает, что когда мы вносим изменение в объект, он мгновенно изменяется во всем приложении.

Лего блоки, пожалуй, самый неизменный объект в известной вселенной

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

 interface NotificationSenderInterface { public function send(Notification $notification); } class SMSNotificationSender implements NotificationSenderInterface { public function send(Notification $notification) { $this->cutNotificationLength($notification); // Send an SMS... } /** * Makes sure the notification does not exceed the length of an SMS. */ private function cutNotificationLength(Notification $notification) { $message = $notification->getMessage(); $messageString = substr($message->getValue(), 160); $notification->setMessage(new Message($messageString)); } } class EmailNotificationSender implements NotificationSenderInterface { public function send(Notification $notification) { // Send an e-mail ... } } $smsNotificationSender = new SMSNotificationSender(); $emailNotificationSender = new EmailNotificationSender(); $notification = new Notification( new UserId(17466), new Subject('Demo notification'), new Message('Very long message ... over 160 characters.') ); $smsNotificationSender->send($notification); $emailNotificationSender->send($notification); 

Поскольку объект Notification передается по ссылке, мы вызвали непреднамеренный побочный эффект. SMSNotificationSender длину сообщения в SMSNotificationSender , ссылочный объект Notification был обновлен во всем приложении, что означает, что оно также было обрезано, когда оно было отправлено EmailNotificationSender позже.

Чтобы это исправить, мы можем сделать наш объект Notification неизменным. Вместо того, чтобы предоставлять set методов для внесения изменений, мы можем добавить некоторые with методами, которые делают копию оригинального Notification перед применением изменений:

 class Notification { public function __construct( ... ) { /* ... */ } public function getUserId() : UserId { /* ... */ } public function withUserId(UserId $userId) : Notification { $c = clone $this; $c->userId = clone $userId; return $c; } public function getSubject() : Subject { /* ... */ } public function withSubject(Subject $subject) : Notification { $c = clone $this; $c->subject = clone $subject; return $c; } public function getMessage() : Message { /* ... */ } public function withMessage(Message $message) : Notification { $c = clone $this; $c->message = clone $message; return $c; } } 

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

Однако обратите внимание, что очень трудно (если не невозможно) сделать объект действительно неизменяемым в PHP. Но ради того, чтобы сделать наш код защищенным от ошибок, это уже очень помогает, если мы добавляем «неизменяемый» with методами вместо методов set , поскольку пользователям класса больше не нужно забывать самим клонировать объект перед внесением изменений.

Возврат нулевых объектов

Иногда у нас могут быть функции или методы, которые могут либо возвращать какое-то значение, либо null . Эти возвращаемые значения, допускающие значение NULL, могут представлять проблему, поскольку они почти всегда требуют проверки, чтобы увидеть, являются ли они null прежде чем мы сможем что-то с ними сделать. Опять же, это то, что мы могли бы легко забыть. Чтобы мы не всегда проверяли возвращаемые значения, мы могли бы вместо этого возвращать нулевые объекты.

Пустой покерный чип, аналог нулевого объекта

Например, у нас может быть ShoppingCart с примененной скидкой или нет:

 interface Discount { public function applyTo(int $total); } interface ShoppingCart { public function calculateTotal() : int; public function getDiscount() : ?Discount; } 

При расчете окончательной цены нашей ShoppingCart мы теперь всегда должны проверять, возвращает ли getDiscount() null или фактическую Discount перед вызовом метода applyTo :

 $total = $shoppingCart->calculateTotal(); if ($shoppingCart->getDiscount()) { $total = $shoppingCart->getDiscount()->applyTo($total); } 

Если бы мы не делали эту проверку, мы, вероятно, получили бы предупреждение PHP и / или другие непреднамеренные эффекты, когда getDiscount() возвращает getDiscount() .

С другой стороны, эти проверки можно было бы полностью удалить, если бы мы возвращали нулевой объект вместо этого, когда не установлена Discount :

 class ShoppingCart { public function getDiscount() : Discount { return !is_null($this->discount) ? $this->discount : new NoDiscount(); } } class NoDiscount implements Discount { public function applyTo(int $total) { return $total; } } 

Теперь, когда мы вызываем getDiscount() , мы всегда получаем объект Discount даже если скидка недоступна. Таким образом, мы можем применить скидку к нашей общей сумме, даже если ее нет, и нам больше не нужно утверждение if :

 $total = $shoppingCart->calculateTotal(); $totalWithDiscountApplied = $shoppingCart->getDiscount()->applyTo($total); 

Необязательные зависимости

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

Возьмем для примера следующий класс:

 class SomeService implements LoggerAwareInterface { public function setLogger(LoggerInterface $logger) { /* ... */ } public function doSomething() { if ($this->logger) { $this->logger->debug('...'); } // do something if ($this->logger) { $this->logger->warning('...'); } // etc... } } 

У этого подхода есть две проблемы:

  1. Нам постоянно приходится проверять наличие регистратора в нашем doSomething() .
  2. При настройке класса SomeService в нашем сервисном контейнере кто-то может забыть на самом деле установить регистратор, или он может даже не знать, что у класса есть возможность установить регистратор.

Мы можем упростить это, сделав LoggerInterface обязательной зависимостью:

 class SomeService { public function __construct(LoggerInterface $logger) { /* ... */ } public function doSomething() { $this->logger->debug('...'); // do something $this->logger->warning('...'); // etc... } } 

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

Кроме того, мы исключили необходимость в операторах if чтобы проверить, введен ли регистратор или нет, что делает наш doSomething() легче для чтения и менее подвержено ошибкам, когда кто-то вносит в него изменения.

Если в какой-то момент мы захотим использовать SomeService без регистратора, мы могли бы применить ту же логику, что и с операторами return, и вместо этого просто использовать нулевой объект:

 $service = new SomeService(new NullLogger()); 

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

Публичные интерфейсы

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

Стрелки, указывающие на машинный центр, обозначают открытые методы, входящие в основные функции класса

Чтобы свести public методы к минимуму, это может помочь рассматривать публичные методы как транзакции.

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

 $account1->withdraw(100); $account2->deposit(100); 

Хотя базовая база данных может предоставить транзакцию, чтобы убедиться, что деньги не будут сняты, если депозит не может быть сделан, или наоборот, база данных не может помешать нам забыть вызвать либо $account1->withdraw() либо $account2->deposit() , что приведет к неправильным балансам.

К счастью, мы можем легко исправить это, заменив два наших отдельных метода одним транзакционным методом:

 $account1->transfer(100, $account2); 

В результате наш код становится более устойчивым, так как становится все труднее ошибиться, только завершив транзакцию частично.

Примеры обнаружения ошибок

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

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

Модульные тесты

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

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

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

Отчеты о покрытии кода и мутационные тесты

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

Графики, показывающие изменение трендов с течением времени

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

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

Анализаторы кода

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

Помимо анализаторов, встроенных в большинство сред IDE, в процесс сборки наших приложений можно включать сторонние и даже пользовательские анализаторы для выявления конкретных проблем. Неполный список анализаторов, подходящих для проектов PHP, можно найти в exakat / php-static-analysis-tools , начиная от кодирования стандартных анализаторов и заканчивая анализаторами, которые проверяют наличие уязвимостей в безопасности.

Существуют также онлайн-решения, например SensioLabs Insights .

Сообщения журнала

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

Иллюстрация свитка с указанием длинного журнала

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

Хотя большинство приложений регистрируют хотя бы некоторые сообщения, информация, которую они предоставляют, становится действительно интересной только тогда, когда они активно анализируются и отслеживаются с помощью таких инструментов, как Kibana или Nagios . Подобные инструменты могут дать новое понимание того, какие ошибки и предупреждения возникают в нашем приложении, когда пользователи активно его используют, а не когда оно проходит внутреннее тестирование. У нас есть отличный пост о мониторинге приложений PHP с помощью этого стека ELK здесь .

Не подавляйте ошибки

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

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

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

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

Использование вне PHP

Поскольку Poka Yoke является скорее концепцией, а не специфической техникой, ее также можно применять к областям вне (но связанным с) PHP.

инфраструктура

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

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

API REST

При создании REST API мы можем использовать Poka Yoke, чтобы сделать наш API более простым в использовании. Например, мы могли бы убедиться, что мы всегда возвращаем ошибку, когда неизвестный параметр передается в запросе URL или теле запроса. Это может показаться странным, поскольку мы, очевидно, хотим избежать «взлома» клиентов нашего API, но обычно лучше как можно скорее предупредить разработчиков, использующих наш API, о неправильном использовании, чтобы ошибки могли быть исправлены в самом начале процесса разработки.

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

Конфигурация приложения

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

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

Предотвращение ошибок пользователя

Иллюстрация полицейского, держащего открытую ладонь к смотровому окну, словно говоря «стоп»

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

Вывод

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

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

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

Если у вас есть какие-либо советы о том, как Poka Yoke можно применять для разработки PHP или программирования в целом, не стесняйтесь делиться ими в комментариях!

Дальнейшее чтение

Покага иго

Пока Йок в PHP