В последние годы у меня была возможность работать над некоторыми интересными проектами, сложными по своему характеру, с постоянным развитием, постоянным обновлением, рефакторингом и добавлением к ним новых функций.
Эта статья расскажет о самых больших недостатках кода, которые делают большинство разработчиков PHP при работе со средними и большими проектами. Недостатки, такие как отсутствие различий между средами разработки или отсутствие реализации кэширования и резервного копирования.
Приведенные ниже примеры приведены на PHP, но идея каждой проблемы является общей.
Корень этих проблем лежит в основном в знаниях и опыте разработчиков, особенно в его отсутствии. Я не пытаюсь кого-то ругать, я не считаю себя идеальным разработчиком, который знает все, так что терпите меня.
По моему опыту, мы могли бы разделить эти проблемы на три основные группы: уровень разработки, уровень приложений и упущения на уровне базы данных. Мы будем разбивать каждого по отдельности.
Контроль уровня приложений
Разработка с сообщением об ошибках
Единственный вопрос, который я могу задать: почему? Почему вы не включаете отчеты об ошибках при разработке приложения?
PHP имеет много уровней сообщений об ошибках, и его ВСЕ следует включить на этапе разработки.
Если вы думаете, что ошибки никогда не произойдут, вы кодируете идеальный сценарий, который происходит только в идеальном мире.
Отчеты об ошибках и их отображение тоже не совпадают. error_reporting()
display_errors
Отчет об ошибках всегда должен быть на самом высоком уровне в разработке: error_reporting(E_ALL);
и ini_set('display_errors', true);
Примечание: E_ALL является самым высоким с PHP 5.4+, потому что ошибки E_STRICT стали частью E_ALL в PHP 5.4. Если вы используете более старую версию PHP, чем 5.4, используйте error_reporting(E_ALL | E_STRICT);
включить строгие предупреждения об ошибках тоже.
Подавление ошибок
Подавлять ошибки с помощью оператора @ еще хуже, чем вообще его не включать , потому что вы сознательно подметаете грязь под ковром. Вы знаете, что ошибка происходит, вы просто хотите скрыть ее, закрыть задачу и вернуться домой пораньше. Чего вы не понимаете, так это того, что создание чего-то на шаткой основе будет иметь гораздо более серьезные последствия в дальнейшем.
Вы можете прочитать подробное объяснение этого здесь .
Никакой регистрации нигде в коде
Разработка проекта должна осуществляться с самого начала. Вы не можете просто забить на регистрацию в конце.
Большинство разработчиков так или иначе используют ведение журналов, но почти никто из них не тратит время на то, чтобы действительно проверить эти журналы на наличие ошибок. Какой смысл регистрироваться, если никто не просматривает журналы?
Рекомендации PSR существуют для ведения журнала, точнее PSR-3 , и в этой превосходной статье объясняется, как реализовать ведение журнала PSR-3.
Не реализует кеширование
Кэширование может выполняться различными способами на нескольких уровнях приложения, например на уровне сервера, уровне приложения, уровне базы данных и т. Д.
Кэширование тоже должно быть реализовано с самого начала. Вы всегда можете отключить его в процессе разработки, но убедитесь, что все работает, как только оно передано в производственную среду.
На уровне сервера вы можете использовать Varnish , который является обратным HTTP-прокси, он хранит файлы в памяти и должен быть установлен перед веб-сервером.
Чтобы ускорить PHP, вы можете установить / включить кэш кода операции, который оптимизирует компиляцию в байт-код сценариев PHP. Для PHP 5.5 и более поздних версий кэш кода операции уже скомпилирован в ядре под названием OpCache .
Вы можете прочитать об этом подробно в этой статье: SitePoint PHP — Непонятный OpCache .
До PHP 5.5 вы могли использовать APC , который также имеет функцию кэширования пользователей.
На уровне приложения вы можете использовать APCu, который является пользовательским кешем, извлеченным из APC, Yet Another Cache, который имеет схожую функциональность с APCu, или Memcached, который является распределенной системой кеширования и имеет надежную поддержку PHP . Memcached также можно использовать для кэширования запросов к базе данных.
Существует несколько способов реализации кэширования в приложении. Хорошей практикой является кэширование данных, которые меняются не очень часто, но запрашиваются неоднократно.
Кэширует запросы к базе данных, потому что база данных всегда является самым большим узким местом в каждом приложении PHP.
Не обращая внимания на лучшие практики и шаблоны проектирования
Сколько раз вы видели, как кто-то реализовывал свой алгоритм шифрования пароля? К сожалению, это все еще происходит сегодня, потому что нехватка знаний или более опасно, из-за отношения «я знаю это лучше».
Ну, я ненавижу сообщать вам плохие новости, но в 99% случаев вы не знаете это лучше.
Эти передовые практики и шаблоны проектирования были продуманы и созданы специалистами-программистами по причине, более умной, чем вы и я, единственная задача разработчика — выбрать правильный шаблон для работы.
Есть много книг и ресурсов на эту тему. Я упомяну два:
- Шаблоны корпоративной архитектуры приложений от Мартина Фаулера
- PHP объекты, шаблоны и практика Мэтта Зандстры
Не использовать автоматические тесты
Тесты должны быть добавлены для каждой функции веб-приложения, но тесты бесполезны, как и журналы, если никто не смотрит на них и фактически не запускает тестовый код, чтобы увидеть, что что-то ломается.
Выполнение тестов вручную — утомительный процесс. К счастью, есть приложение инструмент для этого ». На самом деле, существует множество инструментов, которые могут помочь автоматизировать ваши тесты, целая практика, называемая непрерывной интеграцией .
Один из таких инструментов, который широко используется в сообществе PHP, называется Jenkins , который является CI-сервером и может сделать гораздо больше, чем просто тестировать приложение. Себастьян Бергманн создал отличный шаблон для Jenkins, специально созданный для работы с PHP-проектами.
Если вы находите это слишком сложным, то хотя бы напишите модульные тесты для своего приложения, используя PHPUnit , Behat или PHPSpec . Поначалу это может показаться трудоемким, но бесчисленное количество раз доказывалось, что тесты помогают проектам в долгосрочной перспективе.
Не проверять / проверять код
Работа в команде может быть сложной, особенно если каждый член команды привык к различным стилям программирования, и без хорошей спецификации проект может очень быстро развиваться.
Если вы в команде и не проверяете код друг друга, вам действительно следует это сделать. Как и модульные тесты, это помогает проекту оставаться чистым и последовательным.
Разница между проверкой и аудитом заключается в том, что вы проверяете код. Проверка обычно происходит до слияния любого кода с базой кода и аудита после слияния кода.
Обзор гораздо лучше, потому что у вас есть возможность поговорить о коде, предложить улучшения или исправления до того, как он будет объединен с кодом других членов команды.
Недостаток обзоров заключается в том, что он блокирует разработку, потому что перед каждым слиянием (после того, как все тесты выделены зеленым цветом), по крайней мере два разработчика должны обсудить код, и именно здесь в игру вступает аудит.
Аудит происходит после слияния, и он не блокирует, но он значительно менее мощный, потому что он упускает возможность ловить ошибки на ранней стадии.
Аудит все же лучше, чем вообще не проверять код.
Чтобы этот процесс прошел максимально гладко, вы можете использовать инструмент под названием Phabricator , который был создан специально для этой цели хорошими инженерами в Facebook. Он поддерживает обе стратегии проверки кода.
Кодирование по идеальному сценарию
Когда-нибудь оказывались или слышали о случаях, когда какой-то незначительный шаблонный код был объединен, и весь ад раскрылся? Я уверен, что сделал.
В большинстве случаев это происходит потому, что разработчики ленивы и пишут код для идеального сценария, в котором происходит сбой базы данных, неустранимые ошибки PHP и взлом сервера.
Код должен быть написан с учетом совершенно противоположного сценария, разработчики должны написать код для наихудшего возможного сценария, о котором они могут подумать, и даже тогда код не будет охватывать какой-то непонятный угловой случай, когда пользователь вводит знак $
Предполагая, что ваш сервер не будет взломан или ваш код не сломается в какой-то момент, и ваша база данных всегда будет работать и работает просто неправильно. Рабочий код должен охватывать эти сценарии и регистрировать ошибки соответственно.
В PHP так легко совершать ошибки, даже не осознавая этого. Это происходит главным образом из-за плохих решений по дизайну языка, которые были приняты в прошлом и не были исправлены вовремя.
PHP хочет, чтобы разработчикам было проще не думать о безопасности, кодировках и других случаях, когда разработчики должны быть в курсе этого и всегда практиковать защитное программирование.
Не правильно использует принципы ООП
Большинство PHP-разработчиков, не знакомых с PHP, не используют объектно-ориентированное программирование в своем коде, потому что эта концепция поначалу немного сложна для понимания. ООП был впервые использован в 1960-х годах и постоянно совершенствовался на протяжении многих лет, в Интернете имеется масса информации об этом.
Кроме того, ООП — это намного больше, чем просто процедурный код, организованный в классах.
Концепция объектов, свойств, методов, наследования, инкапсуляции и т. Д. Является неотъемлемой частью ООП.
Разработчик, правильно использующий эти принципы, знает о шаблонах проектирования ОО, принципах SOLID (единая ответственность, открытый-закрытый, подстановка Лискова, сегрегация интерфейса и инверсия зависимостей) и о том, как писать чистый код в целом, гибкий код, не имеющий жестко закодированные зависимости, которые легко расширять и расширять.
Алехандро Гервасио освещает эти принципы сверху вниз.
Никогда не поздно узнать о ООП и начать писать чистый код, который не зависит от жестких зависимостей (глядя на вас, фреймворки PHP).
Кодирование «на лету»
То, что большинство разработчиков делают, когда им кричат «Быстро, клиенту нужна эта функция и работает как можно скорее» , — это взламывать некоторый код вместе и отправлять его прямо на работающий сервер. Это называется кодированием на лету или кодированием ковбоя .
Как и в любой другой отрасли, в разработке программного обеспечения также должны быть реализованы рабочие процессы и нормальные процессы, чтобы проект был успешным.
PHP и динамические языки в целом поощряют быстрые изменения в кодовой базе, видя результаты модификации мгновенно, но эти изменения должны быть ограничены в производственной среде.
Только критические ошибки должны быть зафиксированы и отправлены непосредственно на рабочий сервер. В остальном, должен быть реализован рабочий процесс, такой как Github’s fork и pull request или Gitflow. Подробнее о рабочих процессах, использующих Git, можно найти здесь: https://www.atlassian.com/git/workflows .
Менеджеры и клиенты, которые считают эти процессы ненужными, должны быть образованы, чтобы увидеть иное. Я никогда не встречал клиента, который не мог подождать пару часов или день, пока небольшая функция не выполнила необходимые шаги для развертывания вживую.
Еще одна вещь, которую стоит отметить, не путайте Continuous Delivery с ковбойским кодированием и хаотичным управлением. Непрерывная доставка — это как раз реализация и оптимизация рабочего процесса разработки, поэтому код можно развернуть в производственной среде в максимально короткие сроки.
Недостатки в уровне базы данных
Не различать запросы на чтение / запись
Для поддержки долгосрочного сложного проекта масштабирование должно быть в голове каждого разработчика. 99% времени веб-приложение не нуждается в масштабировании, потому что оно не достигнет такого трафика.
Если вы точно знаете, что веб-приложение будет использоваться многими, например, корпоративным приложением, которым пользуются сотни сотрудников внутри компании, вы можете сделать необходимые шаги, чтобы упростить масштабирование проекта.
Так зачем раздавать запросы на чтение / запись?
База данных всегда является первым узким местом в каждом приложении. Это будет первый сбой в условиях огромного трафика. Для разгрузки трафика на несколько серверов баз данных разработчики используют репликацию Master-Slave или Master-Master. Ведущий — ведомый — более популярный, который говорит, что каждый оператор SELECT должен быть направлен на подчиненные серверы базы данных, а другие — на ведущий, чтобы сбалансировать трафик.
Если ваше приложение не знает разделения между запросами на чтение и запись, оно не будет знать, к какому серверу базы данных подключиться.
Имейте это в виду, если вы знаете, что в конечном итоге вам потребуется настроить схему репликации «ведущий-ведомый».
Только кодирование для одного подключения к базе данных
Это сильно относится к вышеуказанному упущению, но иногда у разработчиков могут быть другие причины для подключения к нескольким базам данных. Например, если вы храните пользовательские журналы, потоки активности, аналитику или другие данные, в которых вы знаете, что операции чтения / записи происходят часто, хорошо перенести этот трафик на другой сервер базы данных.
Убедитесь, что вы используете библиотеку базы данных, которая позволяет вам подключаться к нескольким серверам баз данных, и между ними легко переключаться. Хорошее решение — реализовать PDO и использовать Aura.SQL, расширяющий PDO.
Не тестирует запросы на эксплойты
Этот недосмотр связан с вышеприведенным упущением «кодирования для идеального сценария». То же самое, другая платформа.
Если вы не протестируете свою базу данных (и ваше приложение) на наличие эксплойтов, то какой-нибудь хакер сделает это, и он может добиться успеха.
Базы данных уязвимы для целого ряда эксплойтов, наиболее распространенными являются атаки с использованием SQL-инъекций.
Используйте этот шпаргалку и выполните запросы через библиотеку доступа к базе данных вашего приложения. Запишите эти утверждения в полях вашего внешнего интерфейса, таких как имя пользователя, поля пароля на странице регистрации.
Если ни один из запросов не пройден, вы можете купить себе пиво и отпраздновать.
Не добавление индексов в таблицы
Индексы похожи на оглавление таблицы, они повышают производительность и должны добавляться к каждой таблице, к столбцам, по которым выполняется запрос (например, столбцы после предложения WHERE).
За индексами базы данных стоит целая теория: когда ее создавать, какие столбцы и что нужно охватывать. Об этом была написана целая серия статей.
Не используя транзакции
Целостность данных очень важна для веб-приложений. Целые сайты могут сломаться, если данные обрабатываются неправильно.
Вы используете транзакции для связанных данных, которые обрабатываются вместе, сохраняются или удаляются вместе.
Например, вы сохраняете данные о пользователе, такие как: электронная почта, пароль имени пользователя в таблице 1, и данные профиля, такие как имя, фамилия, пол и т.д., в таблице 2.
Теперь, если пользователь хочет удалить свою учетную запись, это должна быть одна операция, связанная с выполнением SQL-запроса с использованием транзакций. Если вы не используете транзакции, вы рискуете потерять целостность данных, потому что операции с данными выполняются отдельно.
Если удаление данных из таблицы 1 завершается успешно, но в таблице 2 происходит сбой, данные профиля для пользователя останутся в базе данных и, что еще хуже, они не будут ни с чем связаны, они будут потеряны.
При использовании транзакций этого не произойдет, потому что вся операция будет успешной, только если все отдельные операции (например, удаление данных из таблицы 1 и таблицы 2) в транзакции завершатся успешно, в противном случае база данных откатится до предыдущего состояния.
Не защита конфиденциальных данных
Хранение паролей в виде простого текста или использование собственного алгоритма шифрования в 2014 году недопустимо. Сообщество PHP уже достаточно развито, чтобы знать лучше.
Тем не менее, вероятно, существуют тысячи баз данных, в которых конфиденциальные данные хранятся в незашифрованном виде и просят их украсть хакерами.
PHP 5.5 уже добавил сильные хеш-функции только для этого, просто называя его хешированием паролей . Это действительно просто в использовании — вы создаете хеш из простого текстового пароля с помощью этого метода:
$hash = password_hash( $password, PASSWORD_BCRYPT );
Примечание: нет необходимости засолять этот пароль, потому что он уже обработан для вас.
Сохраните $hash
if ( password_verify( $password, $hash ) ) { ... }
Примечание: если у вас нет PHP 5.5 (вы действительно должны сейчас), вы можете использовать библиотеку password_compat , которая реализует точно такие же методы.
Обработка финансовых данных намного сложнее, потому что вам нужно иметь соответствие PCI на уровне сервера, приложения и базы данных. Более глубокая статья уже написана на эту тему здесь: SitePoint PHP — PCI Compliance и PHP Developer .
Контроль разработки приложений
Не делать различий между средами разработки
Я видел, как многие разработчики и даже небольшие команды настраивали плохие среды разработки для себя.
Например, работа над новой функцией или исправление ошибки и FTP-файлы прямо на веб-сайте. Это не правильно на многих уровнях.
Существует бесконечное количество рабочих процессов, которые могут создавать команды, но классическим для веб-разработки является использование как минимум трех сред: разработка, подготовка и производство.
Среда разработки может быть локальной для каждого программиста, подготовка и производство обычно являются удаленными и разделяют некоторые части между ними. Разработка для кодирования, постановка для тестирования и, наконец, производство для потребления.
Надзор происходит, когда эти среды не настроены одинаково. Например, каждый разработчик, работающий с другой версией PHP или промежуточной конфигурацией, отличается от рабочей.
Угадай, что происходит? Ты прав. Все будет работать в разработке и даже в постановке, и когда вы отправите его на производственный сервер, все начнёт ад, что приведет к долгим ночам и большому количеству кофеина.
Неудивительно, что самая распространенная фраза в кругах разработчиков: «Это работает для меня».
Так в чем же решение? Убедитесь, что все настроено одинаково в КАЖДОЙ среде. Операционная система должна быть одинаковой, PHP, база данных, веб-сервер, все должны иметь одинаковую версию для всех сред.
С момента создания Vagrant , Docker и VirtualBox теперь очень легко создавать идентичные среды с одинаковой точной конфигурацией в каждой. Если вы ранее не использовали эти инструменты, вам следует прекратить все, что вы делаете, и немедленно начать их использовать.
Нет резервной копии
Все идет хорошо, сайт работает, запускается вовремя, все работает, пользователи потребляют красивые данные. Ном, ном, ном … Пока вы не получите электронное письмо в 3 часа ночи.
Резервное копирование, так же как ведение журнала, кэширование, защита и программирование защиты, должно быть неотъемлемой частью при разработке веб-приложения, но большинство разработчиков (или системных администраторов) забывают это делать.
Резервное копирование также должно быть автоматизировано, или, если это невозможно, следует делать как минимум еженедельное резервное копирование вручную. Любое резервное копирование лучше, чем отсутствие резервного копирования.
Сохраните базу кода в системе контроля версий и используйте распределенную систему контроля версий, такую как Git или Mercurial . Эта настройка делает кодовые базы очень избыточными, потому что каждый разработчик, работающий над проектом, имеет версию кодовой базы. Аналогично, храните кодовую базу на Github или Bitbucket , у них есть резервные копии.
Резервное копирование базы данных является более важным, потому что это пользовательский контент. ВСЕГДА храните фактические данные и резервную копию в разных местах.
Отсутствие резервного копирования данных может разрушить бизнес, и это сделает это — посмотрите на известный случай Ma.gnolia , одного из лучших сайтов социальных закладок в те времена. У Wired есть прикрытие всей катастрофы.
Нет мониторинга
«Все удивительно, и никто не счастлив». — Луи К.К.
Вы не счастливы, потому что вы не знаете, что происходит. Реализация интеллектуальной инфраструктуры мониторинга для вашего приложения действительно важна. Мониторинг отвечает на следующие вопросы:
- Кто-нибудь получил доступ к основному серверу приложений?
- Находятся ли серверы под большой нагрузкой?
- Нужно ли масштабировать на другой сервер базы данных?
- Где происходит сбой приложения?
- Это в автономном режиме или не работает только для меня?
Важно знать ответы на эти вопросы в любой момент, и в режиме реального времени вы узнаете. Чтобы это произошло, такие инструменты, как Nagios или New Relic, должны быть частью инфраструктуры вашего приложения.
Вывод
Используйте эти знания, чтобы стать лучшим программистом. Запомните эти упущения и постарайтесь не совершать их. Упущения на уровне приложений и баз данных являются наиболее важными из них.
Резервное копирование очень важно, всегда практикуйте защитное программирование и будьте готовы к худшему, именно так работает веб-разработка. Программирование сложное, но когда все сделано правильно, очень весело.
контрольный список
Ниже вы найдете контрольный список всех упущений, найденных в этой статье. Посмотрите, сколько вы можете вычеркнуть прямо сейчас и всегда старайтесь вычеркнуть их всех.
- Включены ли отчеты об ошибках и отображаются ли ошибки в процессе разработки и выключены в работе?
- Не подавляйте ошибки в вашем коде.
- Реализовать каркас регистрации.
- Используйте стратегию кеширования.
- Помните и используйте шаблоны проектирования и лучшие практики программирования.
- Используйте тесты в своем коде и пытайтесь автоматизировать запуск этих тестов каждый раз, когда происходит изменение в базе кода.
- Просмотрите или хотя бы проверяйте код членов команды.
- Практика защитного программирования.
- Изучите и используйте принципы ООП правильно.
- Иметь надежный рабочий процесс и процессы для разработки и развертывания кода.
- Различать запросы чтения / записи к базе данных.
- Используйте надежную библиотеку базы данных, которая может подключаться к нескольким базам данных.
- Тест SQL-запросов на эксплойты.
- Изучите и используйте индексы для таблиц базы данных
- Используйте транзакции базы данных.
- Защита конфиденциальных данных в базе данных.
- Используйте разные среды кодирования: разработка, постановка, производство.
- Реализуйте стратегию резервного копирования и мониторинга.