Итак, вам понадобилось реализовать в проекте функциональность X. Теоретики разработки программного обеспечения в этот момент говорят, что для этого нужно взять уже существующую библиотеку Y и использовать её для реализации необходимых вам вещей. Собственно, это классический подход в разработке программного обеспечения - повторное использование своих или чужих наработок (сторонних библиотек). И именно этим путём движется большинство программистов.
Однако, теоретики в статьях и книгах, забывают упомянуть, в какой ад превращается поддержка несколько десятков сторонних библиотек, живущих в вашем проекте, скажем по прошествии 10 лет.
Я рекомендую всячески сопротивляться добавлению в проект каждой новой библиотеки. Но прошу понять меня правильно. Я вовсе не говорю, что не надо использовать библиотеки и писать всё самостоятельно. Это просто-напросто глупо. Однако, часто новая библиотека добавляется в проект по прихоти одного разработчика, с целью использовать в ней какую-то маленькую "фитюльку". Добавить новую библиотеку не сложно. Вот только потом всей команде много лет придётся нести груз её поддержки.
Наблюдая за развитием некоторых больших проектов, я могу перечислить ряд проблем наличия большого количества сторонних библиотек. Наверное, я перечислю далеко не все проблемы, но даже следующий список должен побудить вас задуматься:
Ещё раз подчеркну. Я не призываю вас отказаться от использования сторонних библиотек. Если в программе вам понадобилось работать с изображениями в формате PNG, то вам надо взять библиотеку LibPNG и не изобретать велосипед.
Но даже работая с PNG надо остановиться и подумать. А нужна ли библиотека? Какие операции нужно выполнять с изображениями? Быть может, если вся задача сводится к тому, чтобы сохранить какое-то изображение в *.png - файл, можно обойтись системными функциями. Например, если у вас Windows приложение, то вам поможет WIC. А если вы уже используете библиотеку MFC, та вообще не надо усложнять код, ведь есть класс CImagе (см. обсуждение на сайте Stack Overflow). Минус одна библиотека - отлично!
Приведу пример из собственной практики. В процессе разработки анализатора PVS-Studio, в паре диагностик потребовалось применять простые регулярные выражения. Вообще, я убеждён, что регулярным выражениям не место в статическом анализе. Это крайне неэффективный подход. Я даже писал статью на эту тему. Однако иногда, в какой-то строке нужно бывает что-то найти с помощью регулярного выражения.
Можно было-бы "прикрутить" какую-то из существующих библиотек. Было понятно, что все они будут избыточны, но ведь регулярные выражения все равно нужны и нужно было принять какой-то решение.
Совершенно случайно, именно в тот момент я читал книгу "Beautiful Code" (ISBN 9780596510046). Эта книга о простых и изящных решениях. И в ней я повстречал крайне простую реализацию регулярных выражений. Буквально несколько десятков строк. И всё!
Я взял из книги эту реализацию и начал использовать в PVS-Studio. И знаете, что? До сих пор возможностей этой реализации нам хватает. Какие-то сложные регулярные выражения нам просто не нужны.
Итог. Вместо того, чтобы в проекте появилась какая-то дополнительная библиотека, было потрачено около получаса времени на написания нужной функциональности. Было подавлено желание использовать библиотеку "на все случаи жизни". И оказалось это было правильное решение. Это подтверждается, тем что в течении нескольких лет эта самая функциональность "на все случаи" не понадобилась.
Этот случай окончательно убедил меня, что надо по возможности искать простые решения. По возможности, отказываясь от библиотек вы делаете проект более простым.
Возможно читателям будет интересно узнать, что же это за такой код для поиска по регулярным выражениям. Перепечатаю его из книги. Посмотрите, как элегантно. Это код был мной немого изменён при интеграции в PVS-Studio, но его суть не изменилась. Итак, код из книги:
// Формат регулярного выражения.
// c Соответсвует любой букве "с"
// .(точка) Соответсвует любому одному символу
// ^ Соответсвует началу входящей строки
// $ Соответствует концу входящей строки
// * Соответствует появлению предыдущего символа от нуля до
// нескольких раз
int matchhere(char *regexp, char *text);
int matchstar(int c, char *regexp, char *text);
// match: поиск соответствий регулярному выражению по всему тексту
int match(char *regexp, char *text)
{
if (regexp[0] == '^')
return matchhere(regexp+1, text);
do { /* нужно посмотреть даже пустую строку */
if (matchhere(regexp, text))
return 1;
} while (*text++ != '\0');
return 0;
}
// matchhere: поиск соответствий регулярному выражению в начале текста
int matchhere(char *regexp, char *text)
{
if (regexp[0] == '\0')
return 1;
if (regexp[1] == '*')
return matchstar(regexp[0], regexp+2, text);
if (regexp[0] == '$' && regexp[1] == '\0')
return *text == '\0';
if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text))
return matchhere(regexp+1, text+1);
return 0;
}
// matchstar: поиск регулярного выражения вида с* с начала текста
int matchstar(int c, char *regexp, char *text)
{
do { /* символ * соответствует нулю или
большему количеству появлений */
if (matchhere(regexp, text))
return 1;
} while (*text != '\0' && (*text++ == c || c == '.'));
return 0;
}
Итак, мой совет
Сопротивляйтесь добавлению в проект новых библиотек. Добавлять следует только когда, когда очевидно, что без библиотеки не обойтись.
Вот некоторые возможные манёвры:
P.S. Многим рассказанное здесь придется не по душе. Например, то что я рекомендую использовать не переносимую универсальную библиотеку, а допустим WinAPI. На это будут возражения, основанные на том, что тем самым мы привязываем проект к одной операционной системе. И потом будет очень сложно сделать программу переносимой. Я с этим не согласен. Часто идея "потом перенесем на другу операционную систему" живет только в голове разработчика. На самом деле такая задача вообще может быть никогда не поставлена руководством. Или проект "загнётся" из-за излишней сложности и универсальности, ещё до момента популярности и необходимости портирования. Плюс не забывайте пункт (7) в списке проблем, приведенный выше.