8 ноября 2011 г.

Процедуры, классы, компоненты...

Хотя это не очень-то видно из заголовка, но это - дополнение к посту "Чего не хватает в Delphi". Поговорим о модели компонентов в Delphi и её недостатках.

Но для начала - введение.

Процедурный подход

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

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

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

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

Хотя позже в процедурном программировании сформировалось "модульное направление" - это когда набор процедур объединяется в модули (библиотеки); но это лишь частичное решение, поскольку ничто не запрещает вам точно так же "размазывать" код по модулям.

Объектное программирование

Потом появились классы и объектно-ориентированное программирование (ООП). Суть явления достаточно проста. Раз уж в программном коде есть логические единицы (в терминологии ООП - "объекты") - так почему бы не ввести языковую поддержку для них? Пусть язык предоставит конструкции для их оформления. Т.е. если в процедурном программировании данные и подпрограммы их обработки формально не связаны и могут располагаться как угодно (в этом-то и проблема), то в ООП они объединяются в единое целое на уровне синтаксиса языка, так что произвольно разбросанный код более не допускается. Т.е. вас "тоталитарно" ограничивают в свободе, диктуя вам как писать код (некоторые наивные люди могут подумать, что свобода процедурного программирования - это хорошо, а ограничения свободы в ООП - это плохо).

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

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

Итак, кратко: ООП - это абстракция, инкапсуляция, наследование, полиморфизм.

Как мы видим, при таком подходе логически связанные данные насильно стаскиваются в одно место - объект. Теперь для проверки и понимания кода уже не надо перелопачивать весь код, достаточно изучать код объекта (который всегда в одном месте) - по объекту за раз. Модульность, автономность, возможности повторного использования кода? Ну, они только улучшились, разве нет? Да ещё бонусом мы получили возможность писать абстрактный код, поддерживаемую на уровне языка. Чем плохо?

Тут надо отметить два момента. Во-первых, код в стиле ООП вполне можно писать и на процедурах. Вот только будет это... гм, не очень приятно. Полиморфизм? Указатели на процедуры. Откуда следуют проблемы инициализации, проверок, косвенных вызовов. Наследование? Включение в одни структуры данных других. А чтобы обеспечить общий доступ к этому зоопарку прибавим ещё указателей на методы доступа... В общем, замучаетесь писать. Потому что язык, опять же, не предоставляет вам такой поддержки, т.е. не облегчает вам эту задачу. "Пишите в стиле аппаратного обеспечения" - вот что он вам говорит. Что ещё хуже - этот код не всегда выглядит особо единым целым, не всегда будет очевидно, что вот это, это и вон то - это (оказывается) один объект, логически связанный код. А раз это не очевидно, то всегда найдётся кто-то, кто сделает что-то не то. Вопрос в другом: если вы пишете процедурный код и выделяете в нём логические единицы - ну так чего бы не оформить это объектом, если уж язык это поддерживает?

Справедливо и обратное. Тот факт, что вы используете язык с поддержкой ООП и объекты (к примеру, создали в Delphi VCL приложение), ещё не означает, что вы пишете ООП код. Мы уже знакомы с таким примером. Ладно, это не очень удачный пример - потому что когда человек пишет процедурный код с объектами - это ещё ладно: он хотя бы применяет процедурное программирование (хоть какую-то структуризацию кода). Но многие люди, практикующие "волшебную кнопку", не применяют вообще никакой структуризации! Они даже не выделяют подпрограммы (если это без этого совсем уж никак), а пишут код "в одной большой куче". Такой код легко опознать: если вы видите гигантское определение TForm1 - это почти всегда означает, что никаких попыток структуризации кода никогда и не предпринималось.

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

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

Компоненты

В Delphi реализована надстройка над ООП - в целом, дальнейшее развитие идей ООП. При этом идея "строительных кирпичиков" программы выносится на новый уровень. Она заключается в том, что программа строится путём соединения т.н. компонентов - универсальных классов с хорошо определёнными интерфейсами. В целом это включает в себя наложение дополнительных ограничений и введение набора правил. При этом программирование приложения в основном сводится к написанию новых компонентов. Т.е. изменения в существующую систему вносятся путём создания новых компонентов в дополнение или в качестве замены ранее существующих.

Итак, компонент - это независимый модуль программного кода, предназначенный для повторного использования и развертывания. Обратите внимание, что в этом определении упор делается на автономность и независимость кода.

Обычно в языках программирования (и Delphi тут не исключение) нет каких-либо языковых конструкций для компонентов и компоненты реализуются просто на классах. Поэтому иногда граница между ними может пониматься неверно. К примеру, спроси начинающего Delphi программиста в лоб: "что такое компонент?" - почти наверняка он приведёт в пример TButton, TLabel, TEdit. Тут налицо путаница между "оконный элемент управления" и "компонент". Компонент не обязан быть элементом управления. Он не обязан быть визуальным. Компонент - это специальный автономный класс. Всё, точка. И в обратную сторону: элемент управления в окне вовсе не обязан быть компонентом (и в других языках программирования он часто им не является).

Собственно, компонентный подход заключается в написании автономных компонентов, а потом просто соединении их вместе (почему-то мне кажется, что пропагандистом этого подхода является Рей Конопка).

Чего же не хватает в Delphi?

Итак, я наконец-то подобрался к сути этого поста. Введение в проблему заняло некоторое время, но без этого основная мысль была бы не понятна.

Как мы видим, основная концепция компонентного программирования ("пишите автономные компоненты, а потом просто соедините их вместе") не очень-то работает в Delphi.

Что же пошло не так? Почему такая соблазнительная идея собрать программу из кирпичиков не сработала?

Примечание: ниже я приведу лишь своё мнение, вы можете быть с ним не согласны.

Проблема №1

Компоненты в Delphi нуждаются в установке. Это первейшая причина. Как говорится, too much friction. Конечно же, вы можете использовать компоненты, создавая их в коде, но это не слишком-то согласуется с концепцией "собери программу из кирпичиков"/"брось компоненты на форму/модуль и соедини их". Ну а установить компоненты - это слишком много возни. Гораздо проще написать класс, да. Или процедурку. А потом просто скопировать их в другой проект, если там возникнет такая же задача.

Что могла бы сделать тут Delphi? Думаю, что можно что-нибудь придумать. Появляется же во всяких инспекторах объектов и просмотрщиках структуры конструкции, которые вы только что вставили/написали - ещё до компиляции программы. Почему бы тогда не добавлять в палитру компонент, если в текущем коде нашлось его корректное определение? Сложно, да. Но не невозможно. Этот пункт могут облегчить нижеследующие вещи.

Проблема №2

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

Что могла бы тут сделать Delphi? Во-первых, надо позволить регистрировать компонент не только пакету, но и проекту. Да, тут возникают проблемы с тем, что код компонента должен выполняться в IDE. Но мы вполне можем ввести какие-нибудь ограничения, чтобы среда могла автоматически извлечь из проекта код компонента и оформить его авто-сформированным пакетом. В конце концов, у нас есть настройки проектов. Чего бы не добавить в них настройку "авто-установка вот этого пакета при открытии пакета и его удаление после закрытия"? Вполне реальная задача, делай хоть сейчас. Уже сейчас можно исключать из IDE некоторые пакеты на per-project базисе (т.н. excluded packages). Осталось немного доработать эту идею.

Проблема №3

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

Что могла бы тут сделать Delphi? Как промежуточное решение - сделать команду "экспорт проекта", которая занесёт в одну папку весь код проекта, включая требуемые им компоненты. А на второй IDE компоненты будут "авто-установлены" как локальные - по пункту 2 выше. Полноценное решение - полная реализация пункта 2: локальные компоненты.

А вообще, все первые три пункта это ровно одна проблема - необходимость регистрации компонентов. Фактически, именно из-за этого ограничения "компонент" в Delphi - практически синоним "визуальный контрол". Придумайте что-то, чтобы можно было обходится без неё, и использование компонентов сразу же взлетит. Как насчёт новой сущности вроде "контейнер компонентов", куда можно складывать компоненты и соединять их? В отличии от TDataModule, такой контейнер не будет создаваться в design-time и такие недо-компоненты не будут нуждаться в регистрации. В общем, тут есть над чем подумать, вариантов много.

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

Проблема №4

Отсутствие официального места для поиска компонентов. Да, есть куча разрознённых и неофициальных мест. Но, ёлки-палки, на дворе 2011-й год, а не 1995-й. Не так уж сложно сделать официальный "ComponentStore", встроенный в IDE. Это вполне может быть и сама палитра компонент, расширенная поиском. В ней могут показываться все компоненты из хранилища. Бросаем что-то на форму - компонент сам скачивается и устанавливается. Ну или без авто-установки - тогда на Welcome-скин добавить веб-морду хранилища. Насколько проще станет поиск компонентов.

Что ещё важнее: если в проекте используются компоненты из хранилища, то его очень просто перетащить на другую машину - ведь IDE сможет автоматически скачать и установить все недостающие компоненты.

Проблема №5

Изначально в языке Delphi не было языковых конструкций для интерфейсов. Были лишь классы. Поэтому компоненты в Delphi (и вся VCL) оказались построены на базе классов. Из-за соображений обратной совместимости ничего не изменилось и в будущих версиях Delphi.

В чём тут проблема? На мой взгляд, использование классов вместо интерфейсов существенно снижает возможности автономности и повторного использования кода. Ну, первое что приходит в голову тут - так много проще обменивать компонентами между языками, ведь интерфейсы поддерживают почти все. Но я тут имел в виду несколько другое: в идеале компонент при наследовании должен наследовать интерфейс предка, без наследования реализации. Тогда изменения базового класса (контролем над которым у вас нет) не сломают его многочисленных наследников. Привет обратной совместимости и Реймонду Чену.

См. также:
Что могла бы тут сделать Delphi? Введите набор интерфейсов для реализации компонентов. IComponent, например. Включите в IDE поддержку компонентов на базе интерфейсов. Создавайте новые компоненты в виде интерфейсов. Оставьте старые компоненты "как есть". С течением времени, вводите в IDE новые варианты современных компонентов. Это не должно быть сложно, ведь вы меняете только интерфейс класса и ссылки на другие классы. В какой-то момент времени скройте под капот старые компоненты, оставив их только для совместимости. Всё, дело сделано.

Community

Вообще, некоторые из озвученных выше идей звучат как неплохие идеи для основы нового расширения IDE (IDE эксперта). Может быть, кто-то попробует создать эксперт, реализующий что-то из указанного. Проблема тут в том, что стороннее решение не имеет смысла. Любое стороннее расширение IDE, даже полностью реализующее решение проблем компонентов, не будет использоваться, потому что его в свою очередь надо установить - т.е. не решается проблема "автономности и переноса". Вы всё ещё не может взять проект и перетащить на другую машину - там тоже должно стоять это расширение IDE, чтобы проект можно было импортировать. Не слишком отличается от проблемы регистрации компонентов.

Я бы не писал всего этого, если бы не последние две версии Delphi. Как вы видите, в их состав интегрировано множество сторонних продуктов, что делает их практически де-факто стандартом. Так что если кто-то напишет подобное расширение IDE и оно понравится людям - вполне можно попробовать связаться с Embarcadero и спросить, не хотят ли они вставить такоё клёвое расширение IDE в очередную версию Delphi. К примеру, именно я посоветовал автору Documentation Insight спросить Embarcadero насчёт интеграции. Как видите, всё прошло более чем успешно.

P.S. Эй, Алексей Тимохин! У тебя есть Lazy Delphi Builder - утилита для авто-установки компонентов. Чего бы тебе это не допилить, интегрировать в Delphi и внести своё имя в историю, а? :D

Необязательно ведь даже реализовывать все моменты выше. Чего за примером далеко ходить. Возьмём Total Commander. Все знают? Думаю, что да. Вот есть у него плагины. Вообще говоря, в изначальном варианте, плагин в (тогда ещё) Windows Commander-е - это разрознённый набор никак не связанных файлов, лежащих в любом порядке. Лишь бы головной файл был бы зарегистрирован в IDE Windows/Total Commander. Знакомые слова? Да, ровно так же как (сейчас) регистрируются в IDE компоненты.

Это жутко неудобно.

Что можно тут сделать? Можно ввести несложный набор правил. "Если вы делаете а, б и с, то плагин компонент устанавливается в один щелчок". Да, вы можете делать по старинке, когда вы ничем не ограничены. Как угодно и что угодно. Используйте свою раскладку файлов по папкам, свой собственный custom (и ни с кем не совместимый) установщик и т.п. - пожалуйста. Или, вместо этого вы можете следовать несложным правилам, так что ваш компонент может быть установлен автоматически, "в один клик". Ваш выбор.

Надо ли упоминать про то, что сегодня 99.9% плагинов под Total Commander распространяются именно в "пакетах установки в один щелчок"?

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

А, быть может, всё это не имеет значения и "компонент=контрол" - вполне нормальное явление?

26 комментариев :

  1. >> К примеру, именно я посоветовал автору Documentation Insight спросить Embarcadero насчёт интеграции. Как видите, всё прошло более чем успешно.

    Т.е. Documentation Insight встроен в XE2?

    ОтветитьУдалить
  2. Еще бы решили бы вопросы с регистрацией компонент с одним именем но в разных пакетах.
    А то народ все жалуется что например SDAC и AnyDAC поставить не могут

    т.е. сделать что вида

    var
    ed1: TEdit(Standard)
    ed1: TEdit(Raize)

    когда понятно что ed1 - это едит из пакета Standard а ed2 из Raize
    + убрались бы TrxEdit TRxEdit TMyEdit а был бы TEdit разграниченный по пакетам

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

    ОтветитьУдалить
  3. Ответил отдельным постом, насколько затронула меня тематика данного поста:

    http://blogs.embarcadero.com/vsevolodleonov/2011/11/08/precedures-classes-components-alexander-alexeev/

    ОтветитьУдалить
  4. ссылку неправильно дал, нужно тэгом :)

    Ответ

    ОтветитьУдалить
  5. > Т.е. Documentation Insight встроен в XE2?

    Да.

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


    У меня раньше были мысли насчёт GUID, но с выходом XE2 акцент смещается на VCL.Controls и FMX.Controls.

    Сторонние поставщики могли бы использовать этот подход. Но, к сожалению, только если они не поддерживают совсем уж старые версии Delphi (в Delphi 7 была поддержка двойных идентификаторов? Вроде не было).

    ОтветитьУдалить
  6. Большинство проблем, связанных с компонентами – они от того, что Delphi не является полноценной 4GL средой. Это 3, 3+, можно называть как угодно – но факт, это развивалось как хороший язык и отличная IDE.
    Для сравнения можно взять именно 4GL системы, которые, кстати, развились и были весьма популярны ещё до победоносного шествия Delphi – Centura Team Developer, Sybase PowerBuilder и другие. Механизм создания компонентов там прекрасно интегрирован в среду, компоненты объединяются в библиотеки. Создать компонент, разместить его в библиотеке и подключить к паре-тройке проектов – задача на 45 секунд.
    Другое дело, что в таких средах существуют вполне естественные ограничения на прямое общение с примитивами операционной системы, и многие системные задачи можно решить только подключением сторонних платформозависимых библиотек, но… не надо забывать об их предназначении. К тому же, качественная изоляция программиста от ОС только способствует успешному портированию (кросс-компиляции) кода на другие системы.
    На мой вкус, путь развития Delphi лежит в части развития и унификации механизмов интеграции компонент – модуль, предоставлению дуального интефейса – изменения в GUI автоматически приводят к изменению текста компонента (в т.ч. формы), изменения, вносимые в код – немедленно интерпретируются GUI. Язык описания модулей – Object Pascal. В текущей его инкарнации уже есть всё, что для этого необходимо.
    Для меня идеальным механизмом работы был бы следующий – подключил к проекту папку, в которой лежит несколько модулей – получил в палитре компоненты. Выделил класс (функцию) в коде – указал Delphi – сделать компонент – и получил папки, модули и настройки в среде. Разработал (купил) новую версию – подключился к другой папке. Не понравилось – вернулся к тому, что, было.

    ОтветитьУдалить
  7. Да, хорошие и правильные мысли!

    Я последние 10 лет плотно работал с Delphi, но последний год отошел от данного инструмента и начал заниматься изучением и разработкой на Ruby и ROR.

    Дак вот, очень интересно знаете-ли из своего болота нырнуть в чужое новое :-) Познакомиться с новым языком, новой парадигмой программирования, новыми приемами и инструментами. И вы знаете, очень много интересного и полезного можно почерпнуть. В данный момент я считаю язык лучшим из известных мне. Ах если бы совместить его плюсы, с плюсами компилируемых языков...

    В мире ROR есть замечательный инструмент, Bundler (так же можно обратить внимание на RVM), который как раз и занимается установкой необходимых компонентов (gems), отслеживанием всех зависимостей, загрузкой, контролем версий. Причем все в простой, декларативной форме. Было бы классно иметь что-то подобное в Delphi + магазин + полный экспорт проекта.

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

    Всеволод, а вам просьба! Донесите до высокого руководство Embarcadero, эти полезные мысли! А так же предложите нанять Александра для сотрудничества. По моему очень достойный специалист.

    ОтветитьУдалить
  8. Насчет проблем установки компонентов - мне нравится, как это реализовано в Visual Studio / .NET: пишем, например, class MyListView : ListView - и в ToolBox'е уже появляется компонент MyListView, который можно бросать на формы также, как и любой другой библиотечный контрол/компонент. Никакой специальной регистрации не требуется. Также нет проблем с переносом - этот MyListView относится только к текущему проекту и переносится на другую машину вместе с ним.

    P.S. Надеюсь, мой пост с упоминанием VS не станет причиной очередного холивара :) Пишу на Delphi с 1998, начиная с Delphi 1; очень люблю и уважаю этот язык.

    ОтветитьУдалить
  9. Я продублирую тут ещё ответ Всеволоду Леонову - чтобы не было недоразумений.

    В общем, "пишем всё компонентами" было написано в определении компонентного подхода (С) Словарик. Из этого не нужно делать вывод "Delphi полностью следует компонентному подходу, поэтому должно быть так".

    И я этого не говорил (или нет? Если да, то я не это хотел сказать).

    Смысл поста был в том, что часто бывает так, что когда кто-то всё же пишет автономный и реюзабельный код - он не делает это в виде компонента, хотя это так и просится. Смысл в том, что в установке компонентов не менялось ничего с выхода Delphi 4 (13 лет). И, наконец, смысл в том, что многие люди отказываются от сторонних компонентов из-за проблем с регистрацией/переносом.

    Вот, наглядный пример: чтобы создать компонент, ты должен:
    1. Решить, как и что нужно хранить в папке. Правильный компонент должен иметь вещи вроде Lib, Source и (с XE2) ещё и Lib\Platform. Всё это надо прорабатывать самому, ручками.
    2. Тебе надо создать компонент с пакетом и вручную настроить его на пути, выбранные в п1.
    3. Чтобы твой компонент лучше использовали, его должно быть просто установить. Значит тебе надо написать установщик. Опять же самому. А в установщике надо предусмотреть определение установленной версии Delphi (и опять же, надо решить, куда компонент устанавливать, как регистрировать) - и всё это самому, потому что никаких готовых действий в каком-нибудь InnoSetup нет.

    Короче, сделать компонент - это куча возни. Использовать сторонний компонент - это куча возни.

    В этом смысл поста.

    Так неужели с этим нельзя что-то сделать?

    Почему бы мастеру создания компонента не создавать сразу стандартную структуру папок, прописывать в пакет все пути. Почему бы ему не подготовить скрипт для установщика (кто там в комплекте Delphi? InstallAware?). Не хотите установщика? Почему бы IDE не зарегистрировать себя на открытие, скажем, файлов .ecp (Embarcadero Component Package, здесь "пакет" не в смысле .bpl, а как "набор"). Дабл клик по файлу - установился компонент. А в редактор пакетов добавить опцию "Create/Export redistributable package (.ecp)".

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

    Вот это я хотел сказать своим постом.

    Дополнительное примечание по локальным компонентам, а то с ними тоже непонятки могут быть. Имелось в виду следующее: часто в программах вы видите код вида:

    // тут - настройка IdHTTP
    IdHTTP.Get(...);

    Ничего не замечаете? Код формы работает с внутренностями TIdHTTP - это задача, которую, вообще-то должен решать сам TIdHTTP. Вот и получается у нас "почтальон чинит телевизоры".

    Правильное решение - создать свой класс-наследник (компонент), куда внести все эти действия.

    Почему этого не происходит? Потому что компонент надо регистрировать, чёрт его побери!

    ОтветитьУдалить
  10. Ссылка в тему по самому последнему замечанию.

    Это - практически хак. А вообще-то, по-хорошему, такое решение должно было бы поддерживаться на уровне IDE.

    ОтветитьУдалить
  11. Мне, идея для всего-всего писать компоненты, кажется стрельбой из пушки по воробьям. Но все же за предложенные в статье идеи я готов голосовать, если их кто-нибудь выложит на QC. Особенно за Embarcadero Component Package :)

    ОтветитьУдалить
  12. Также очень не хватает привязки к текущему открытому проекту подключаемых пакетов компонентов. Т.е. чтобы при открытии проекта в IDE подключались только нужные пакеты.
    Например, у меня есть две версии приложения - старая и новая - которые требует двух разных версий одного и того же пакета компонентов. Чтобы внести исправления в старую версию приложения, необходимо удалить из IDE новую версию компонентов, установить старую и исправить пути. А если таких пакетов несколько, то все становится совсем плохо.

    ОтветитьУдалить
  13. To Chaa.
    А я, чтобы не было совсем всё плохо, проблему разных версий одних и тех же компонентов для разных версий проекта решаю с помощью переменных сред окружения (Environment Variables).

    Т.е. все пути в IDE в Library Path прописаны относительными, например так (пишу от фонаря):
    $(PAS_SOURCES)\Eureka Log 6\Lib
    $(PAS_SOURCES)\Virtual Tree\Sources

    В переменной Path есть ссылка на переменную $(BPL).
    Ну и собственно заведены переменные PAS_SOURCES (корневой каталог для исходников компонент) и BPL (каталог, куда "сваливаются" BPL и DCP файлы при компиляции и установке пакетов).

    И чтобы переключиться с одного проекта на другой остаётся поменять всего лишь эти 2 переменные в одном месте и перезапустить Delphi!
    А для того, чтобы можно было одновременно работать в двух Delphi с разными проектами, можно сделать программку-загрузчик, которая будет устанавливать значения этим переменным и запускать Delphi уже в своём окружении. А можно даже и без загрузчика всё в bat-файле сделать (но только будет ненужное консольное окно маячить).

    Одно лишь неудобство: процесс инсталляции новых/старых компонентов надо контролировать ручками, что может оказаться довольно трудоёмко. Но оно того стоит.

    ОтветитьУдалить
  14. Gunsmoker, больную тему затронул. Компоненты, и их установка - это сложно. А сложности начинаются с того как изначально сконфигурированы Дэлфи. Я говорю о том, что изначально в Delphi заданы только папки для скомпилированных BPL, DCP. Да и те находятся чёрт знает где. Еле нашёл C:\Users\Public\Documents\RAD Studio\7.0.
    А где остаются остальные файлы, полученные в процессе компиляции? Правильно, в папках с исходниками. А это значит, чтобы проекты, использующие эти компоненты собирались, эти папки надо добавить в Library Path IDE или проекта. А это в свою очередь влечёт за собой сложности с установкой другой версии того же компонента.

    Самая ненавистная для меня ошибка при установке компонентов, это когда компилятор сообщает о том, что не может скомпилировать что-то из-за того, где-то уже используется другая версия этого компонента. Или ещё лучше, когда всё компилируется, но вылетает из-за того, что entry point not found. А причина проста - где-то в путях валяются старые .dcu-файлы.

    И кстати, это же причина тому что я не особо активно продвигаю Lazy Delphi Builder. Ибо с ним всё будет хорошо только если у человека настроено рабочее место и все файлы bpl, dcu, dcp, res и debug-версии dcu-файлов находятся в соответствующих папках. Если же все настройки по умолчанию - то велики шансы получить больше проблем, чем бонусов. (по хорошему, конечно, надо бы допилить Lazy билдер, чтобы он перед компиляцией проверял наличие дублирующихся dcu-шек в путях).

    Очень понравилась идея с "Embarcadero Component Package(.ecp)".

    Федор очень в тему привёл пример ruby с их инсталляцией gem-ов. Я тоже об этом думал, что мол неплохо бы было сделать общий репозиторий компонент.
    И вроде даже начинали делать RADStore, и даже анонс выпустили, но так и заглохло всё.

    ОтветитьУдалить
  15. Дополню:

    Кстати создание структуры папок для проекта по шаблону было реализовано в CnWizards: MainMenu->CnPack->Project Enhancements->Project Dir Builder...

    ОтветитьУдалить
  16. RADStore? Нет, там не так всё мертво :)

    К сожалению, не могу говорить по этому вопросу, обещал молчать.

    ОтветитьУдалить
  17. Большое спасибо!
    читать этот блог сплошное удовольствие, очень познавательно.
    Всегда возникают проблемы с разными версиями компонентов.
    Еще было бы интересно иметь в IDE средство по поиску компонентов и их покупке.

    ОтветитьУдалить
  18. Похоже у Хейлсберга были подобные же мысли, что мы и видим в .NET сейчас. Один в один по каждому пункту.

    ОтветитьУдалить
  19. Я не в курсе, как там в .NET. Надо будет в свободное время посмотреть.

    ОтветитьУдалить
  20. Ну я немного слукавил, когда сказал что пункт в пункт, но там как то естественно получается что нет таких проблем. Главная причина, что нет проблем с версионностью сборок, потому что можно всегда заюзать ссылку именно на нужную сборку. Сборки не привязаны к IDE, а только к фреймворку .NET и либо находятся в глобальном кеше сборок (в папке Windows), либо вместе с проектом. Так же есть единой место распространения сборок/расширений Online Gallery http://visualstudiogallery.msdn.microsoft.com. Естественно проблемы при переносе бывают и если пакет переноситься на новую машину, то есть например NuGet http://nuget.codeplex.com/ , который выкачает нужные либы и как нужно установит.

    ОтветитьУдалить
  21. Александр, так как поживает RADStore? С презентацией XE2 мы о нем не услышали.

    ОтветитьУдалить
  22. Многочисленные примеры централизованных хранилищ показывают, что это дико удобно (надстройки для Firefox/Opera/Chrome, Android market, Apple store наконец), поэтому стопроцентно за стандартизацию и централизацию. Интерфейс поиска и установки компонентов из самой среды - мечта! Плюс стандартизация размещения файлов позволила бы автоматом делать всяческие приятные вещи вроде пакетного бэкапа/ребилда/апдейта/деплоя. В особенности здорово, что не надо было бы рыскать по прорве сайтов, репозитариев и форумов в поисках свежей версии.
    Что касается самих компонентов, то в текущей реализации я скорее склоняюсь в сторону чистых классов. Потому как имею дело в основном с невизуальными классами, которые могут быть использованы в DLL/консольных/winapi проектах, и наследование кучи фигни от TComponent для них - бесполезное раздутие. Вот если б было разделение по дефайну вроде $ifdef VCL, тогда другое дело.

    ОтветитьУдалить
  23. > Александр, так как поживает RADStore? С презентацией XE2 мы о нем не услышали.

    См. RADStore, Lua4Delphi, and why you’ve been waiting…

    ОтветитьУдалить
  24. "делать команду "экспорт проекта", которая занесёт в одну папку весь код проекта, включая требуемые им компоненты"

    Довольно стрёмная идея. Это вам не Эклипс.
    Занести идентификаторы для поиска на Торри, КомпСторе и т.д. - это полезно, весьма. Но только не сами компоненты. Грубо говоря я не хочу случайно кому -то подарить свою подписку DevExpress

    -------

    а насчёт GUID'ов - что забавно, так сделана ощутимая часть JediVCL
    И поэтому им пришлось перекрывать ощутимую часть стандартных классов - чисто для того чтобы туда вставить интерфейсы.

    ОтветитьУдалить
  25. "Это - практически хак."

    "метод Geo" - вообще говоря плохой метод. И компонентизация каждой процедуры ИМХО тут не вход. Скорее нужно задавать иерархические настройки компонентов a la CSS. И ведь зачатки этого - шаблоны - были как минимум в D5. Но до бесполезности примитивно-тупые. И, кажется, тоже не привязанные к проекту.

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и (опционально) ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

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