Лучший подход к модульному программированию в Delphi

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

Позвольте мне опубликовать то, что я уже написал там.

Программное обеспечение, разработанное компанией, в которой я работаю, состоит из более чем 100 модулей (большинство из них являются чем-то вроде драйверов для разных устройств). Большинство из них имеют один и тот же код - в большинстве случаев - классы. Проблема в том, что эти классы не всегда помещаются в отдельные автономные блоки PAS. Я имею в виду, что общий код часто помещается в единицы, содержащие код, специфичный для модуля. Это означает, что при исправлении ошибки в общем классе недостаточно скопировать блок PAS, который он определен во всех программных модулях, и перекомпилировать их. К сожалению, вы должны копировать и вставлять фиксированные фрагменты кода в каждый модуль, один за другим, в соответствующий блок и класс. Это занимает много времени, и это то, что я хотел бы устранить в ближайшем будущем, выбрав правильный подход - пожалуйста, помогите мне.

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

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

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

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

Это решение кажется ОК в отношении редко модифицированного кода. Но у нас также есть модули pas с функциями и процедурами общего пользования, которые часто претерпевают изменения. Было бы невозможно выполнить ту же процедуру (копирование и перекомпиляцию так много проектов) каждый раз, когда кто-то добавляет новую функцию в этот файл.

  • Создайте BPL для всего общего кода, но свяжите их с EXE, чтобы EXE были автономными.

Теперь мне кажется, что это лучшее решение, но есть некоторые минусы. Если я исправлю ошибку в BPL, каждый программист должен будет обновить BPL на своем компьютере. Что, если они забудут это сделать? Однако, я думаю, это небольшая проблема. Если мы позаботимся об информировании друг друга об изменениях, все должно быть в порядке. Как вы думаете?

  • И последняя идея, предложенная CodeInChaos (я не знаю, правильно ли я ее понял). Совместное использование файлов PAS между проектами. Вероятно, это означает, что нам нужно будет хранить общий код в отдельной папке и делать все проекты для поиска этого кода, верно? И всякий раз, когда необходимо изменить проект, он должен быть загружен из SVN вместе с папкой с общими файлами, я думаю. Каждое изменение в общем коде должно было бы перекомпилировать каждый проект, который использует этот код.

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

Большое спасибо.

Ответ 1

Вы говорите:

  • Создавайте BPL для всего общего кода, но связывайте их с EXE, поэтому что EXE являются автономными.

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

BPL предназначены для использования в качестве общего кода, т.е. вы помещаете код, который разделяется на одну или несколько BPL, и используйте их из каждого из .exes,.dll или других .bpl. Исправления ошибок (если они не изменяют публичный интерфейс BPL) просто требуют перераспределения этой фиксированной BPL.

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

Но обратите внимание, что BPL сильно зависят от версии компилятора. Если вы используете новую версию компилятора, вам также придется перекомпилировать BPL. Вот почему имеет смысл давать суффиксы BPL, такие как 100, 110 и т.д., В зависимости от версии компилятора. Исполняемому, скомпилированному с компилятором версии 15.0, будет сказано использовать BPL с суффиксом 150, а исполняемый файл, скомпилированный с версией 14.0, будет использовать BPL с суффиксом 140. Таким образом, различные версии BPL могут мирно сосуществовать. Суффикс можно задать в параметрах проекта.

Как вы управляете разными версиями? Создайте каталог со структурой, как у меня для ComponentInstaller BPL (это эксперт, который вы можете увидеть в Delphi/С++ Builder/RAD Studio XE IDE в меню "Компоненты" → "Установить компонент" ):

Projects
  ComponentInstaller
    Common
    D2007
    D2009
    D2010
    DXE

Общий каталог содержит файлы и ресурсы .pas(растровые изображения и т.д.), которые разделяются каждой версией, и каждый из каталогов Dxxxx содержит .dpk,.dproj и т.д. для этой конкретной версии BPL. Каждый из пакетов использует файлы в общем каталоге. Конечно, это можно сделать для нескольких BPL одновременно.

Система управления версиями может сделать это намного проще, BTW. Просто не забудьте дать каждой версии BPL другой суффикс.

Если вам действительно нужны автономные исполняемые файлы, вы не используете BPL и просто связываете отдельные блоки. Опция "скомпилировать с помощью BPL" регулирует это.

Ответ 2

С моей точки зрения, пытаясь управлять артефактами, такими как подразделения, библиотеки и исполняемые файлы Delphi, вы выполняете поиск в неправильном месте. Я предлагаю вам развернуться и начать с рефакторинга кода, основываясь на Design patterns.

например. все общие функции могут быть помещены в один класс Singleton, экземпляры общих классов могут быть построены с помощью Аннотация Factory, классы могут взаимодействовать через встроенную реализацию интерфейсов Delphi вместо прямого использования и так далее. Даже вы можете выбрать Facade для всех общих частей проектов.

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

Некоторые другие вещи:

  • Конечно, вы должны следовать предложению @CodeInChaos и делиться одной копией исходного файла между всеми проектами, а не копировать его в каждый проект вручную. Это может быть полезно, если вы примете некоторый стандарт для среды здания, который будет обязательным для всех разработчиков (та же структура папок, расположение библиотек, настройки среды).
  • Попробуйте проанализировать процесс построения и развертывания: для меня это выглядит ненормально, когда решение не построено с последней версией кода и не проверено перед развертыванием. (это для вашего "Если я исправлю ошибку в BPL, каждый программист..." ).
  • Вариант с автономными исполняемыми файлами выглядит лучше, потому что значительно упрощает организацию тестовой среды и развертывание проекта. Просто выберите подходящие соглашения для версий.