Зачем разрабатывать внутренние библиотеки для внутренних приложений?

10

Мне трудно понять, почему вы должны разрабатывать внутренние библиотеки, которые будут использоваться исключительно для разработки внутренних приложений. Я ценю, что если я хочу использовать программное обеспечение, написанное кем-то за пределами организации, тогда они могут прислать мне свои заголовочные файлы и файлы .a или .so, и я могу просто связать его с моим проектом (при условии, что они скомпилированы в одной среде) ,

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

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

Когда я говорю «включить» файлы в каждый проект, я не имею в виду копировать и вставлять каждый файл в исходное дерево разрабатываемого в настоящее время проекта. Я имею в виду разработку некоторого каталога / библиотеки (отдельной для любого проекта), содержащей общий исходный код, который может быть включен в файлы проекта обычным способом, например #include.

ps Я говорю здесь о разработке c / c ++ для нескольких настольных приложений.

Эндрю Муртаг
источник

Ответы:

25

Существует множество причин для создания библиотек и общих библиотек (в файлах .dll или .so) даже для внутреннего использования:

  1. Повторное использование в разных проектах намного чище
  2. Разделение ответственности - часть вашего кода может больше подойти различным разработчикам или командам
  3. Вы можете извлечь выгоду из улучшений в библиотеках, которые делают другие команды без необходимости искать конкретный код
  4. Более быстрая сборка, если библиотека стабильна, ее не нужно перестраивать.
  5. Дисковое пространство - вы можете иметь только библиотеку и заголовки в проекте
  6. Если вы используете разделяемые библиотеки, вы можете сэкономить память, загрузив в ОЗУ только одну копию, даже если ее используют несколько программ.
  7. Обычно вы получаете лучшую документацию и тестирование библиотек
  8. Более чистый дизайн и код - размышления о структурировании объектов в библиотеках должны привести к появлению связанных групп функций в каждой библиотеке, и вы склонны отделять общий код в библиотеках от специфики приложения в приложении .
  9. Если у вас есть собственные алгоритмы в библиотеках, вы можете ограничить доступ к источнику, например, не позволяя подрядчикам или сторонним командам получить доступ к источнику.
  10. Код библиотеки может быть помещен под лицензию, отличную от той, для которой оно изначально было написано, некоторые компании даже знали библиотеки с открытым исходным кодом, которыми они гордятся - получившие признание в сообществе открытого исходного кода, а иногда и значительные улучшения обратно.

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

Стив Барнс
источник
1
Или в варианте пункта 9 вы можете освободить библиотеку под лицензией, отличной от кода основного приложения.
Майкл Боргвардт
@MichaelBorgwardt - Хороший пункт, подсказывающий пункт 10 выше.
Стив Барнс
Кроме того, наличие некоторого кода в качестве отдельной библиотеки помогает избежать ярлыков при программировании, таких как «Я просто добавлю этот дополнительный параметр здесь ...», и помогает найти более эффективные способы реализации требуемых функций.
Валдас
11

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

  • Время компиляции: огромные монолитные проекты C ++ с тысячами файлов, тысячами классов, функций и т. Д. Могут очень долго компилироваться (что снижает производительность, если вы хотите перекомпилировать каждый раз, когда вы меняете несколько строк кода). Статически связанные и динамически связанные библиотеки компилируются независимо, и их не нужно перекомпилировать, если их источник не изменился.

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

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

  • Код, который нельзя выпускать в живую среду : например, библиотеки модульных тестов или «фиктивные» библиотеки, которые используются для тестирования разработчиками для замены компонента работающей системы (аппаратного обеспечения, API, удаленных систем, баз данных и т. Д.)

  • Флаги компилятора : если вы оказались в очень неудачном положении для интеграции с каким-либо сторонним API, который ожидает странный флаг компилятора, то библиотека может быть «слоем дезактивации», расположенным между сторонним API и остальной частью приложения.

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


В целом, многие внутренние проекты часто представляют собой небольшие микроприложения, которые не получают выгоды от разделения на отдельные библиотеки. Если вы работаете над крошечным проектом как одинокий разработчик, вам не нужно беспокоиться о разделении вашего кода на библиотеки (пока ...). Не забывайте принцип ЯГНИ .

Бен Коттрелл
источник
3
@ downvoter - не могли бы вы объяснить причину понижения? Отзывы об ответах полезны для улучшения качества этого сайта для всех.
Бен Коттрелл
4

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

Обратите внимание, что это иногда (не всегда) разумный метод . Фактически, когда вы помещаете все исходные файлы, которые вы хотите использовать в разных проектах, в одну отдельную папку include, вы уже создали библиотеку - библиотеку исходного кода, а не двоичную библиотеку. Особенно в C ++, при создании универсальных библиотек с шаблонами, нет ничего необычного в том, чтобы иметь библиотеки с заголовками, которые просто нуждаются в простом включении, и не требуют отдельной подготовки к связыванию.

Поэтому я думаю, что ваш реальный вопрос - когда создавать библиотеки с исходным кодом или когда предпочитать предварительно скомпилированные двоичные библиотеки? В этом более старом ответе на этом сайте я обсуждал некоторые плюсы и минусы библиотек только для заголовков, возможно, это поможет вам. Основное преимущество библиотек с исходным кодом состоит в том, что они не требуют компиляции с теми же флагами времени выполнения и / или совместимыми компиляторами / компоновщиками, что и приложение, которое их использует. Недостатками являются дополнительное время компиляции и требование предоставления доступа к исходному коду (что, очевидно, не является проблемой для типа «внутренних» проектов, которые вы имеете в виду).

Док Браун
источник
Это правда, что я имел в виду библиотеку исходного кода, которая является общей для нескольких проектов, где вы просто ссылаетесь на нужные вам файлы с помощью типичной директивы #include - я не знал этого термина, пока вы не сказали это, и я отредактирую вопрос сейчас. Ваш связанный ответ тоже очень полезен.
Эндрю Муртаг
@AndrewMurtagh: тот факт, что вы так быстро приняли ответ Михаэля Боргвардта, поразил меня, потому что то, что он написал, похоже, является либо неправильным пониманием его или моего.
Док Браун
хорошо, он разъяснил начальную путаницу, которую я имел о том, когда группировать код, который будет общим для нескольких проектов, в один пакет (будь то в двоичных библиотеках или библиотеках исходного кода), но, разумеется, я говорил о наличии единого каталога исходного кода код, который можно было бы разделить между проектами, а не копировать и вставлять каждый файл в каждый проект, поскольку они могут мне понадобиться.
Эндрю Муртаг
2

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

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

Написание «библиотеки» для одного варианта использования может превратиться в очень дорогое занятие без какой-либо отдачи - меня это укусило несколько раз.

Пример стоимости:

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

Мое общее правило: не превращайте код в библиотеку, если у меня нет как минимум 2 отдельных мест, где требуется код.

Сэм
источник
2
Я видел почти те же самые причины, используемые некоторыми разработчиками, что и почему их код находится в одном исходном файле размером> 20 КБ. В сочетании со странными именами и плохими комментариями у вас скоро появляется код, который быстрее переписать, чем поддерживать.
Стив Барнс
Замечательный момент: я, конечно, не спорю с написанием поддерживаемого, читаемого кода. Отдельные файлы, хорошо названные методы / классы и структура пакета являются важными компонентами удобства обслуживания. Суть в том, что затраты на написание + распространение библиотеки велики, когда для «библиотеки» есть только один вариант использования.
Сэм
1
И наоборот, я не утверждаю, что вам обязательно нужно упаковывать и распространять библиотеку в каждом случае, просто написание и структурирование, как если бы ваш код мог однажды стать библиотекой, обычно стоит небольших усилий и часто приносит дивиденды, даже если код никогда не становится распространяется как библиотека.
Стив Барнс
1

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

Потому что, если вы «просто включаете их в мое дерево исходных текстов », вы дублируете код .

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

Вы можете подумать, что вы можете решить эту проблему, просто регулярно копируя новейшую версию кода в дерево исходных текстов, возможно, даже автоматически, используя подмодуль в git или что-то подобное. Но из-за несовместимых изменений API вы будете постоянно ломать сборку. Библиотека, с другой стороны, имеет «официальный» публичный API, который, как ее разработчики знают, не может быть изменен без советов с клиентами.

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

Майкл Боргвардт
источник
1
Итак, как я понимаю, основная причина превращения некоторого фрагмента кода в библиотеку заключается в том, что он будет использоваться в различных проектах (даже если они все внутренне разработаны), чтобы этот код не дублировался, не обновлялся и не обслуживался. раздельно? И если вы собираетесь разрабатывать только один проект, то нет необходимости превращать что-либо в библиотеку (если вы не собираетесь использовать это в дальнейших проектах позднее).
Эндрю Муртаг
@AndrewMurtagh: Да, именно так я бы и сказал. Хотя могут быть и технические причины; Я не очень знаком с разработкой на C / C ++ - может быть, необходимо хранить часть кода в виде библиотеки, чтобы он мог загружаться по желанию или даже загружаться и выгружаться по требованию, и, таким образом, уменьшать использование памяти, когда функциональность не нужна?
Майкл Боргвардт
Я считаю, что это может быть возможно через общие библиотеки. Спасибо за разъяснения, я отмечу ваш ответ как принятый.
Эндрю Муртаг
Почти каждое VCS за последнее десятилетие поддерживает внешние ссылки или подмодули. Это устранило проблему дублирования кода и исправления ошибок. Может содержать дополнительную информацию о том, почему они не являются жизнеспособным решением, если вы все еще считаете, что они являются действительными проблемами.
Сирисиан
Думайте также в обслуживании. 1) Библиотека может поддерживаться независимо и параллельно. 2) Код легко заменить. 3) Небольшая база кода проще в управлении для небольших команд и понятна для всех. 4) если время выхода на рынок имеет решающее значение, вы предпочтете иметь более быстрые сборки. Код в libs - это код, который вы не компилируете снова и снова в конвейере (IMO). 5) Это надежный код многократного использования ... Вы сделали это ;-)
Laiv
1

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

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

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

Что если ваша «псевдо-библиотека» используется другой «псевдо-библиотекой» B? Вы должны добавить свой новый cpp в кучу проектов больше. А если Bперейти на использование другой библиотеки? Вам придется удалить cpps из Aвсех проектов в зависимости только от B.

Это все будет бесплатно, если будет использоваться настоящая библиотека. Таким образом, вопрос в том, сколько cpps необходимо, чтобы оправдать переход к реальной библиотеке?

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

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

Свинец
источник
0

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

Если библиотека когда-либо используется только одним приложением, то вам, скорее всего, она не нужна как отдельная библиотека.

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

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

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

Если это только в исходном коде «локально» для каждого приложения, то вам нужно изменить, пересобрать, повторно протестировать и заново развернуть каждое приложение в отдельности . Это гораздо большее (то есть более дорогое) упражнение.

Фил В.
источник