Comments 76
А теперь, персонально для делфи-разработчиков!!!
Я к тому, что несмотря на некоторые моменты специфичные для Delphi, большинство рекомендаций актуальны для всех языков :)
О общих принципах писали уже 328 тис. 8 млн. раз, немного надоело читать одно и тоже, но как говорится «повторение — мать учения» :)
Для нашего молодняка требовалось максимально сжатое изложение с конкретными рекомендациями именно по Delphi. В сети подходящего не нашел, пришлось писать самому.
Спасибо! Отличный материал. Для молодых кадров, почти руководство к выполнению, чуток подкрасить и подредактировать и можно вручать при приёме на работу программиста.
Собственно в этом качестве полгода и используется. А где конкретно подкрасить и подредактировать?
«2 Цикл разработчика» на «2 Цикл разработки», будет правильние, у человека цикла нет, а у рабочего процесса есть.
UFO landed and left these words here
> И чего это вам не понравилось хранение данных в классе и запись в БД ну и некоторые другие функции?
Тем, что мешают читать, использовать, тестировать и модифицировать класс без физической реализации «этих других функций».
> Соответственно и все поведение мы и должны в один класс записать.
Это будет известный антипаттерн «божественный класс» — сложный для чтения, отладки, модификации и повторного использования.
> Допустим у нас есть класс tDoc мы должны описать его сохранение в БД, загрузку из базы, проверку на валидность, объект этого класса — единственное достоверное хранилище данных.
Не должны — для сохранения есть сериализаторы, для проверки — валидаторы и т.п. На собственно документ ложится хранение данных. Остальное вполне реально выделить в отдельные классы.
>Опять же не совсем понятно требование на приватность полей — да в подавляющем большинстве случаев это действительно важное требование, но бывают и исключения…
В Delphi таких исключений не бывает. Хочешь показать снаружи — опиши свойство. С тривиальными геттером и сеттером оно даже по скорости исполнения полю не проиграет.
UFO landed and left these words here
Я до разбора полетов предпочитаю не доводить в принципе.
Именно для этого сделано двойное рецензирование: неформальное — решения задачи перед кодированием (отвергается только явно косячное по дизайну) и формальное — ревью кода после (отвергается опять-таки только явно косячное и неправильно оформленное).
На молодых работает отлично.
UFO landed and left these words here
Зачем задрюкивать? Обучать надо. Если решение не имеет явных косяков, то все равно, совпадает оно с тем, что предполагалось или нет.
Я тоже против жесткого запрета на strict protected поля.
Одно дело показывать наружу (не в коем случае), а другое — парочке наследников, доступность поля которым не ломает инкапсуляцию в широких масштабах.
Полагаю экономию одной строчки на описание свойства (и одного хоткея на генерацию простого сеттера) совершенно недостаточной компенсацией за потерю возможности контроля над данными.
Хорошо, кратко и по сути. А чтобы всё это ушло в подкорку — практика, еще раз практика и Макконнелл.
Один момент: практика с обязательным рецензированием решений и кода. И таки да, молодняк умудряется еще и ветеранов обгонять.
UFO landed and left these words here
Тема написания конструкторов раскрыта не полностью (возможность реинициализирующего вызова)
Можно подробнее? Полностью тему в таком формате все равно раскрыть нереально, но что бы вы сказали про реинициализирующие вызовы молодым разработчикам?
Сказал бы, что в конструкторе нельзя считать что объект заполнен нулями, и необъодимо обрабатывать ситуацию когда часть полей (или все) уже инициализированны ранее. В этом случае наверное нужно освободить старые ресурсы, занулить содержащие их поля и тогда действовать по ранее утвержденному плану. Ну для вложенных объектов можно просо вызывать FreeAndNil перед инициализацией.
Полагаю такую ситуацию ошибкой программиста и предпочитаю тратить силы на ее предотвращение, а не пытаться минимизировать вред после ее возникновения.
Какого программиста?
Автора конструктора или пользователя класса?
Которую я полагаю одной из возможностей выстрелить себе в ногу.
А если ваш класс к этому не готов, то это ваша недоработка. «Ваш» я говорю не как что-то личное
Что нельзя считать что в начале конструктора объект всегда заполнен нулями, и перед инициализацией нужно освободить то что там было раньше (для объектов — хотябы просто вызвать FreeAndNil(FObjectField) перед присваиванием)
Ну вобщем как то, что у вас написано про деструктор
4.Приделать doxygen или javadoc и не сношать другим мозги.
5.Выкинуть эту венгерскую нотацию на помойку, НИКАКИХ T ПЕРЕД НАЗВАНИЕМ КЛАССА: ОНИ НЕ НУЖНЫ.

И вообще не начинать новые проекты на Дельфи
Префикс Т в начале класса не имеет отношения к венгерской нотации
Можете не тратить напрасно свое время и силы — вы отвечали человеку, для которого Delphi как красная тряпка для бычка.
Хорошо, нафига он нужен? Понимаю еще если так исторически сложилось, понимаю когда это первая буква из названия библиотеки и при этом она вполне красиво вписывается. Но блин в остальных то случаях зачем? Чем namespace'ы не угодили?
Она отличает типы от нетипов. Поля — F, аргументы сеттеров — А, интерфейсы I
Венгерская нотация же про другое.
Но суть то та же самая, просто теперь буквами обозначаем семантику, мне это кажется излишним. Всё прекрасно и без букв лишних просматривается в любом нормальном IDE.
Нет, суть совершенно разная.
Пойдите лучше повоюйте с сишниками по поводу капслока в идентификаторах типов и знаков подчеркивания в макросах, а мне пожалуй хватит.
И да, IDE женского рода.
У сишников вообще странный стиль… Впрочем воевать с цппшниками, которые пишут как на си тоже приходится иногда воевать, а иначе что-то странное совсем выходит из под клавиатуры
Когда я начинал программировать под Windows, пользовался продуктами борланда: delphi, builder, c++. меня тоже это как-то коробило, точнее, я не понимал, зачем нужны эти префиксы, хотя против T ничего не имел, но вот названия аргументов в VCL с этими F, A меня раздражали :)

В то же время, в MFC все классы имели префикс С, о чем у меня была дискуссия с другом, который ею пользовался. Он мне объяснял, что это — правильная концепция, потому что CWnd — это класс, а вот у борланда как раз ничего непонятно с этими Т :)

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

И только когда начал изучать джаву по двухтомнику Хорстмана все наконец встало на свои места — наконец-то префиксы были признаны ненужными и нарушающими «концепцию» :)

Кстати говоря, Макконнелл так же пишет, что префиксы — это хорошо
Т — это type, все понятно же.
F и А жизненно необходимы, когда у вас есть свйство, поле для его хранения и аргумент в сеттере. Когда в в контексте метода SetOwner, то очень удобно иметь свойство Owner, поле FOwner и аргкмент AOwner
да я это все понимаю, я же говорю, сам очень много программировал на дельфи и билдере. и также использовал Т :)

я просто привел в пример MFC-шника, у которого концепции несколько отличаются. Видимо, в микрософте решили, что класс — это не тип, следовательно, ему нужно свой префикс :)
>AOwner FOwner

как же это ужасно выглядит, особенно две гласные буквы подряд. Лучше уж методы и поля класса писать с маленькой буквы, а private поля или прятать в приватный класс или же слова разделять через нижнее подчеркивание и добавлять префикс m_
UFO landed and left these words here
Жесткое рецензирование кода? Понимаю, хочется иногда, но надо спокойно не пропускать такое в репозиторий и вести разъяснительную работу.
Да, я даже могу понять из за чего это так сложилось, но всё же это не отменяет устарелость этого стиля и то, что есть более современные и удобные в нынешнее время. Так зачем предлагать в качестве советов то, что осталось нам в наследство и нынче уже не подкрепляется необходимостью?
Т.е. из-за одной буквы вы готовы горы свернуть и привнести в программу смешение стилей?
Почему же? В собственных программах у меня никаких буков T и в помине нету, есть только вот префикс V в модуле для работы со вконтакте, с ним что ли названия классов красивее смотрятся, но мне лично не нравятся любые излишние соглашения в стиле. Буква T явно излишняя.
Это в хаскеле раздельные пространства имен для функций с параметрами, конструкторов данных, типов данных, переменных типов данных. Ни в дельфи, ни в плюсах, ни в яве, ни в сишарпе такой роскоши нет, приходится использовать те или иные соглашения для улучшения читаемости кода. Плюс в делфи еще нельзя полноценно использовать разный регистр. Отсюда и префиксы — уже по коду видно, где тип, где переменная, где поле, где параметр. С венгерской нотацией (что прикладной, что системной) это не имеет ничего общего.
А что тут толстого? На Коболе тоже вот не рекомендуют новые проекты создавать.
Я не знаток Delphi и мне интересны некоторые аспекты.

В Delphi есть библиотеки, которые позволяют делать модульное тестирование? Если есть, почему о нем не упомянуто?

И еще про зависимости. В разделе «15 Устранение лишних зависимостей» ничего не сказано про IoC-контейнеры. Вместо них много упоминаний про глобальные переменные. Есть ли в Delphi реализация IoC-контейнера?
> В Delphi есть библиотеки, которые позволяют делать модульное тестирование?
Да. DUnit идет в стандартной поставке.
> Если есть, почему о нем не упомянуто?
Конкретные вспомогательные инструменты не упоминаются специально.
> В разделе «15 Устранение лишних зависимостей» ничего не сказано про IoC-контейнеры. Вместо них много упоминаний про глобальные переменные.
Глобальные переменные и эквивалентные им паттерны (например, синглтон) есть типичная ошибка молодого разработчика.
> Есть ли в Delphi реализация IoC-контейнера?
Для версий от 2009 и выше есть как минимум OpenSource библиотеки. Для младших версий IoC нет ввиду наличия отсутсвия генериков и недостаточных возможностей интроспекции (RTTI есть, но неполная и неудобная для таких целей). Для проектов на Delphi 2007 у нас используется ServiceLocator. Конкретные паттерны и инструменты для устранения зависимостей не упоминаются сознательно — здесь нет однозначно лучшего решения и я не вижу смысла его навязывать.
> Да. DUnit идет в стандартной поставке
А вы пишете на нем тесты или на какой-то другой библиотеки? Думаю эта информация будет полезна для начинающих разработчиков.

> Конкретные вспомогательные инструменты не упоминаются специально
Вообще это не просто инструмент. Написание модульных тестов (желательно до кода), которые запускаются постоянно — это способ написание программ, который практически устраняет пункт «9 Отладка»

> Для проектов на Delphi 2007 у нас используется ServiceLocator
Т.е. есть реализация только «пассивного» внесения зависимостей?
>Вообще это не просто инструмент. Написание модульных тестов (желательно до кода), которые запускаются постоянно — это способ написание программ, который практически устраняет пункт «9 Отладка»

Ну не уверен. Скорее сильное сокращение отладки, но все ситуации тестами не отловишь.
> Ну не уверен. Скорее сильное сокращение отладки, но все ситуации тестами не отловишь

Согласен, можно переформулировать «практически устраняет», а «сильно уменьшает» :)
Для реально сильного уменьшения меры должны быть комплексными:
1. Устранение зависимостей.
2. Рецензирование дизайна.
3. Рецензирование кода.
4. Модульные тесты.
5. Непрерывная сборка.
6. Логирование.
7. Автоматическое функциональное тестирование.
8. Ручное функциональное тестирование.
Попытка сэкономить на чем-то одном уменьшает эффективность всего остального.
> А вы пишете на нем тесты или на какой-то другой библиотеки? Думаю эта информация будет полезна для начинающих разработчиков.
Полагаю, что не будет — в команде у молодых выбора инструмента нет. Тем кто работает один — нужны не краткие рекомендации, а толстые книжки и много чужого кода.
> Написание модульных тестов (желательно до кода), которые запускаются постоянно — это способ написание программ, который практически устраняет пункт «9 Отладка»
Модульные тесты являются серебряной пулей только для некоторого класса задач и никоим образом не избавляют от отладки. ЕМНИП по Макконнеллу формальное рецензирование кода ловит больший процент ошибок. Плюс использование способа (TDD) априори важнее выбора инструмента. Но согласен: наличие отдельного пункта про модульные тесты логично и обоснованно.

> Т.е. есть реализация только «пассивного» внесения зависимостей?
Ну изнутри сервиса это наоборот «активное», но увы, в дельфи до 2009 IoC контейнеры слишком сложны в реализации. И у локатора свои плюсы при межязыковом взаимодействии — под Win32 на единую объектную платформу рассчитывать не приходится.
«Все методы, реализующие интерфейс — обязательно protected и невиртуальные»

Это почему так важно?

Выходит этот код опасен чем-то? Не пойму, где могут от этого неприятности быть.
TCommand = class(TInterfacedObject, ICommand, IInfoCommand)
private
FInfo: TInfo;
protected
procedure DoExecute; virtual; abstract;
function GetName: WideString; virtual; abstract;
function GetPriority: TCommandPriority; virtual; abstract;
public
constructor Create(const AШтащ: TInfo);
destructor Destroy; override;
procedure Execute;
function GetMux: TMuxInfo;
end;
Спасибо, хороший пост, много о чем сказано в кратком лаконичном виде.
Only those users with full accounts are able to leave comments. Log in, please.