Лучший подход к модульному программированию в 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 вместе с папкой общих файлов. Каждое изменение в общем коде должно вызывать перекомпиляцию каждого проекта, который использует этот код.

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

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


person Mariusz Schimke    schedule 15.08.2011    source источник
comment
Не создавайте двух копий одной и той же функции. Всегда. SVN затрудняет достижение того, что вы хотите сделать, но я думаю, вам нужны внешние элементы SVN. Я голосую за то, чтобы перейти в раздел «Программисты», где у вас должен быть лучший отклик.   -  person David Heffernan    schedule 15.08.2011
comment
@David Microsoft делает это в исходном коде своих продуктов Office. (Скотт Беркун, Искусство управления проектами) Почему? Если ошибка будет обнаружена в одной копии, другие продукты не будут затронуты.   -  person mjn    schedule 15.08.2011
comment
@mjn Я не могу в это поверить. Я думаю, вы пересказываете историю, слегка искаженную.   -  person David Heffernan    schedule 15.08.2011
comment
@mjn, а если в одном ошибка исправлена, в других не исправят?   -  person Darian Miller    schedule 16.08.2011


Ответы (2)


Ты говоришь:

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

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

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

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

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

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

Projects
  ComponentInstaller
    Common
    D2007
    D2009
    D2010
    DXE

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

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

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

person Rudy Velthuis    schedule 15.08.2011
comment
Спасибо, что поделились своим опытом. Позвольте задать вам еще один вопрос. Ваш пример основан на нескольких версиях одного и того же BPL. Каждая версия BPL использует один и тот же каталог с файлами .pas. Но позвольте мне создать еще один BPL с совершенно другим кодом, который ссылается на некоторые модули из вашего общего каталога. И теперь, должен ли он ссылаться непосредственно на эти файлы (прикрепленные к проекту) или он должен просто использовать один из этих общих BPL (путем ссылки на него в списке требований проекта)? Какой способ считаете лучшим? - person Mariusz Schimke; 15.08.2011
comment
Единицы должны быть только в одной и только одной BPL одновременно. Другие BPL, которым нужна такая единица, должны требовать BPL, которая ее содержит. Имеет смысл еще немного подумать, какой юнит куда должен идти. Я бы нарисовал график, какой исполняемый файл и какой модуль что нужно, переставил бы, пока вы не будете удовлетворены, а затем примете решение. - person Rudy Velthuis; 15.08.2011
comment
Хорошо, это то, что я хотел услышать. Спасибо. - person Mariusz Schimke; 15.08.2011
comment
Позвольте мне завершить, чтобы завершить обсуждение. Общий код помещается в BPL. Pas-файлы никогда не копируются - в этом подходе принимаются только зависимости BPL. Каждый программист устанавливает все общие BPL на свой компьютер и обновляет их (вместе с принадлежащими им файлами .pas) всякий раз, когда кто-то изменяет любой из этих BPL. Это кажется простым, пока используется SVN. Это все правильно? - person Mariusz Schimke; 15.08.2011
comment
Если один из BPL исправлен, но интерфейс (функции, процедуры, классы, типы, константы и т. Д., Которые он предоставляет) не исправлен. изменено, необходимо заменить только этот BPL. BPL или исполняемые файлы в зависимости от этого не подлежат замене. Вы можете добавить в интерфейс BPL, но не можете удалить что-либо или изменить. - person Rudy Velthuis; 15.08.2011

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

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

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

Еще кое-что:

  1. Конечно, вы должны следовать предложению @CodeInChaos и делиться одной копией исходного файла между всеми проектами вместо того, чтобы копировать ее в каждый проект вручную. Это может быть полезно, если вы примете какой-либо стандарт для среды сборки, который будет обязательным для всех разработчиков (та же структура папок, расположение библиотек, настройки среды).
  2. Попробуйте проанализировать процесс сборки и развертывания: для меня это выглядит ненормально, когда решение построено не с использованием последней версии кода и не протестировано перед развертыванием. (это для вашей фразы «Если я исправлю ошибку в BPL, каждый программист ...»).
  3. Вариант с автономными исполняемыми файлами выглядит лучше, поскольку значительно упрощает организацию среды тестирования и развертывание проекта. Просто выберите подходящие соглашения для управления версиями.
person ThinkJet    schedule 15.08.2011