Недавно написал свой велосипед и выложил его на хабре. Вот он: «Простейший Connection pool без DataSource в Java». Статья не из самых удачных, только прошу больше не минусовать. Итак, чтобы никто не повторял такие ошибки, и, возможно, предостеречь кого-то от таких ошибок, решил перевести статью «Seven Things You Should Never Code Yourself» достаточно известного в среде open-source деятеля IT-области — Andy Lester'а. Итак, кому интересно, прошу под кат.
Мы, программисты, любим решать задачи. Мы любим, когда идеи возникают в наших головах, перенаправляются на наши пальцы и тем самым создаются великолепные решения.
Но порой мы слишком быстро вскакиваем и начинаем проворачивать свой код без учета всех последствий, к которым это может привести. Мы не учитываем, что кто-то, возможно, уже решил эту проблему, и что уже есть код, доступный для использования, который был написан, протестирован и продебажен кем-то другим. Иногда нам просто необходимо остановиться и подумать, прежде чем начать что-то печатать.
Например, если вы столкнетесь с одной из этих семи задач программирования, то почти всегда вам лучше поискать существующее решение, чем пытаться реализовывать что-то самостоятельно:
1. Парсинг HTML или XML
Задачей, сложностью которой зачастую пренебрегают, по крайней мере на основе того, сколько раз про него спросили на StackOverflow — является парсинг HTML или XML. Извлечение данных из произвольного HTML выглядит обманчиво просто, но на самом деле эта задача должна решаться применением библиотек. Скажем, вы хотите извлечь URL из тега такого, как
<img src="">
На самом деле это простое регулярное выражение, которое соответствует шаблону.
/<img src="(.+?)">/
Строка “” будет выдана в результатах поиска по шаблону и она может быть присвоена строковой переменной. Но будет ли такой код находить нужные значения в тегах, в которых имеются другие атрибуты:
<img id="bar" src="">
После изменения кода, чтобы он обрабатывал такие случаи, будет ли он рабочим, если кавычки имеют другой вид:
<img src=''>
или кавычек не будет вовсе:
<img src=>
Что делать, если тег занимает несколько строк и является самозакрывающимся:
<img id="bar"
src=""
/>
И будет ли ваш код знать, игнорировать ли закомментированные теги:
<!--
<img src="">
-->
К тому времени, как вы сделаете еще один цикл в поисках случаев, с которыми ваш код не может иметь дело, при этом исправляя и тестируя свой код, вы бы могли уже использовать нужную библиотеку и решили бы все свои проблемы.
Я вам привел наглядную историю с примерами: вы потратите намного меньше времени на поиски существующей библиотеки и на ее изучение, нежели на попытки написать свой велосипед, который затем придется расширять, чтобы он работал в тех случаях, о которых вы и не думали, когда начинали его писать.
2. Парсинг CSV и JSON
CSV файлы обманчиво просты, но таят в себе некую опасность. Файлы с величинами, разделенными запятыми тривиальны для парсинга, не так ли?
# ID, name, city
1, Queen Elizabeth II, London
Безусловно, пока вам не придется иметь дело с запятыми, заключенными в двойные кавычки:
2, J. R. Ewing, "Dallas, Texas"
Если вы решили проблему с использованием таких двойных кавычек, что будет, если в строке будут встроенные кавычки, которые нужно пропустить:
3, "Larry "Bud" Melman", "New York, New York"
Вы можете справиться и с этим, пока не придется иметь дело с переводами строк в середине записи.
JSON имеет те же самые опасности, связанные с типами данных, что и CSV, с дополнительной проблемой, возникающей из-за возможности хранить многоуровневые структуры данных.
Уберегите себя от хлопот и неточностей. Любые данные, которые не могут быть обработаны разделением строки по запятым должны быть обработаны библиотекой.
Если читать структурированные данные неструктурированным методом это плохая идея, то идея изменять данные на месте еще хуже. Люди часто говорят что-то вроде «Я хочу изменить все теги с такими-то и такими URL так, чтобы у них появивлся новый атрибут.» Но даже такое, казалось бы, простое дело, как «Я хочу изменить в каждом пятом поле в этом CSV имя Боб на Стив» таит в себе опасность, потому что, как было отмечено выше, вы не сможете считывать запятые должным образом. Чтобы все было правильно, вам необходимо прочитать данные с помощью грамотной библиотеки во внутреннюю структуру, изменить данные, а затем записать измененные данные обратно с помощью той же библиотеки. Ничто не представляет такой риск искажения данных, как если их структура не соответствует вашим ожиданиям.
3. Проверка Email адресов
Есть два способа проверки адреса электронной почты. Можно проверить по-простому, сказав, «мне нужно иметь некоторые символы перед знаком @, а затем какие-то символы после него», эту идею реализует регулярное выражение:
/.+@.+/
Оно, конечно же, не полное, и допускает наличие неверных элементов, но по крайней мере мы имеем знак @ посередине.
Или вы можете проверить на соответствие правилам RFC 822. Эти правила покрывают все случаи, которые встречаются редко, но все же допустимы. Простое регулярное выражение не выдает такой срез. Вам придется использовать библиотеку, написанную кем-то другим.
Если вы не собираетесь проверять на соответствие RFC 822, то все, что вы делаете будет использованием правил, которые могут казаться разумными, но могут оказаться и не правильными. Этот подход является компромиссным, но не обманывайте себя, думая что вы охватили все случаи, если в итоге вы не обратились к RFC, или просто используйте библиотеку, написанную кем-то другим.
(Для дальнейшего обсуждения вопроса валидации электронных адресов, см. Stackoverflow)
4. Работа с URL
URL-адреса не столь противны, как адреса электронной почты, но они по-прежнему полны раздражающих мелких правил, которые вы должны помнить. Какие символы должны быть закодированы? Как вы обрабатываете пробелы? Как насчет знаков +? Какие символы могут идти вслед за знаком #?
Вне зависимости от языка, который вы используете, существует код для разбиения URL на компоненты и для сборки URL из должным образом оформленных компонент.
5. Работа с датой/временем
Манипуляции с датой/временем являются основной из проблем, в которых вы скорее всего не сможете охватить все аспекты самостоятельно. При обработке даты/времени должны учитываться часовые пояса, летнее время, високосные годы, и даже високосные секунды. В Соединенных Штатах есть только четыре часовых пояса, и они отличаются друг от друга на час. В остальном мире не все так просто.
Будь то для арифметики c датами, сводящейся к вычислению даты, которая настанет по прошествии трех дней от определенной даты, или для валидации строки на входе на соответствие формату даты, используйте существующие библиотеки.
6. Системы шаблонов
Это почти обряд посвящения. Младший программист должен создать огромное количество шаблонного текста и придумывает какой-нибудь простенький формат наподобие:
Dear #user#,
Thank you for your interest in #product#...
Этот формат работает некоторое время, но затем все завершается тем, что возникает необходимость добавления форматов на выходе, численное форматирование, вывод структурированных данных в таблицу, и т.д. пока не возникнет некий монстр, требующий бесконечного ухода и кормления.
Если вы делаете что-нибудь посложное, чем просто замещение строки строкой, сделайте шаг назад и найдите хорошую библиотеку шаблонов. Дела обстоят еще проще, если вы пишете на PHP, сам язык в данном случае является системой шаблонов (хотя в наши дни об этом зачастую забывают).
7. Фреймворки для логирования
Инструменты логирования являются еще одним примером проектов, которые начинаются с малого и вырастают в монстров. От небольшой функции, предназначенной для логирования в файл, в скором времени может потребоваться логирование в несколько файлов, или отправка электронного письма по завершении процесса, или чтобы она поддерживала уровни логирования и т.д. Вне зависимости от языка, который вы используете, существует по крайней мере три готовых пакета для логирования, используемые годами и которые уберегут вас от описанных выше проблем.
Не является ли библиотека излишеством?
Перед тем, как относиться с пренебрежением или презрением к идее подключения стороннего модуля, следует обратить пристальное внимание на ваши протесты и возражения. Первое возражение обычно такое: «Зачем мне нужна целая библиотека просто для того чтобы сделать это (проверить эту дату/распарсить этот HTML/и т.д..),» Мой ответ: «А что в этом плохого?» Вы же скорее всего, не пишете код микроконтроллера для тостера, где вы должны выжать каждый байт пространства для кода.
Если у вас есть скоростные ограничения, то учтите, что избежание использования библиотеки может оказаться преждевременной оптимизацией. Загрузка целой библиотеки для работы с датой/временем может сделать валидацию в 10 раз медленней чем ваше решение на коленках, но проверьте свой код, на самом ли деле он так хорош.
Мы программисты гордимся нашими навыками, и нам нравится процесс создания кода. Это нормально. Просто помните, что ваша обязанность в качестве программиста не просто писать код, а решать задачи, и зачастую лучший способ решить проблему заключается в том, чтобы написать как можно меньше кода, насколько это возможно.
Примечание переводчика:
Кстати, последний абзац очень гармонично перекликается с основной идеей из статьи «Как улучшить свой стиль программирования?».
Автор: maratvildan