16 сентября 2010 в 14:34

Заповеди молодого разработчика Delphi

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

1 Коротко и неясно


  1. ЧИТАЙ КОД!
  2. Пиши код, который удобно читать всем остальным
  3. Пиши в комментарии не ЧТО делает код, а ЗАЧЕМ
  4. Предупреждения и подсказки опаснее ошибок компиляции — проект собирается без их устранения

2 Цикл разработки


  1. Постановка задачи руководителем
  2. Выработка решения
  3. Рецензирование решения
  4. Реализация решения
  5. Рецензирование кода
  6. Размещение в системе контроля версий

3 Оформление исходного кода


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

4 Комментарии


  • Первая строка комментария перед объявлениями процедур, классов и т.п. должна давать понять их назначение. Последующие строки описывают те или иные особенности реализации.
  • Комментарии к виртуальным методам должны описывать обстоятельства вызова, а не реализацию — она может быть перекрыта в наследниках.
  • Комментарии в теле процедур и методов не должны описывать, ЧТО делает тот или иной оператор или блок, а должны указывать ЦЕЛЬ, для которой он (оператор) используется.
    1. Цели меняются гораздо реже, чем средства ее реализации
    2. Понять что делает код можно из него самого, понять ЗАЧЕМ по коду бывает нереально.


5 Выбор имен


  • Классы — существительное единственного числа с обязательным префиксом T и опциональными в виде названия фирмы (SMS), если существует библиотечный класс с похожим именем и проекта (ZVK, Plan), если класс не может быть задействован в нескольких наших проектах.
  • Интерфейсы — существительные с префиксом I
  • Процедуры — глагол.
  • Функции — существительное единственного числа при возврате значения и множественного — коллекции. Используется префикс Get для методов чтения свойств и функций, предназначенных для получения внешних данных, префикс Is для логических функций, префикс Create для создающих функций. Функции, которые вызываются для выполнения действия (а не только получения результата) называются как процедуры, так как де-факто ими и являются.
  • Свойства — существительное единственного числа, за исключением свойств-массивов. Для свойств-массивов с целочисленным индексом определяется свойство-спутник с суффиксом Count. Свойство-событие должно иметь префикс On, Before или After. Методы чтения и записи свойств имеют обязательные префиксы Get и Set.
  • Виртуальные методы — глагол с префиксом Do для protected и без префикса для public методов.
  • Название виртуального метода должно отражать цель его вызова, а не реализацию.

6 Операторы


  • Глубина вложения операторов друг в друга должна быть как можно меньшей — большая глубина очень сильно ухудшает читаемость кода.
  • Для уменьшения глубины вложения ветвлений полезно использовать операторы перехода (кроме goto) и raise
  • Для уменьшения глубины вложения конструкций try..finally полезно использовать присвоение очищаемым объектам nil перед try

7 Инкапсуляция


  • Не следует использовать без крайней необходимости имеющиеся глобальные переменные и никогда не стоит добавлять свои
  • Все поля классов — только private
  • Один класс должен выполнять одну задачу, а не совмещать в себе хранение, отображение, редактирование и запись в БД
  • Доступ к полям для потомков и извне класса может осуществляться через свойства
  • Все методы, реализующие интерфейс — обязательно protected и невиртуальные
  • Все, что не используется вне модуля — в implementation
  • Если использование класса тянет за собой большую часть проекта, следует написать для данного использования интерфейс, реализовать его в классе и пользоваться только интерфейсом

8 Обработка ошибок


  • Для обработки ошибок следует использовать только исключения
  • Исключения следует использовать только для обработки ошибок
  • В блоках except следует перевозбуждать (raise) все исключения, которые не обрабатываются явно
  • Категорически не следует «глотать» исключения (except end)
  • Категорически не следует возбуждать исключения базового класса Exception: если нет подходящего библиотечного — надо определить свой
  • Не следует обрабатывать исключения только для записи в лог — это делается автоматически.
  • Любой код должен быть написан с учетом того, что в любом его месте может возникнуть исключение.
  • Всегда возбуждайте исключение при ошибках в конструкторе и никогда не возбуждайте и не ловите исключений в деструкторе — деструктор должен корректно завершаться всегда.

Исчерпывающий источник по обработке ошибок в Delphi

9 Отладка


  • Следует полностью избавляться от всех предупреждений и подсказок компилятора, разумеется, не путем их отключения.

Настройки проектов Delphi с точки зрения поиска ошибок
Как читать лог-файлы
Access Violation в деталях
Почему всегда нужно использовать FreeAndNil вместо Free

10 Утечки ресурсов


  • Возможность утечки ОДНОГО любого ресурса, используемого в пределах подпрограммы, устраняется с помощью try..finally, при этом захват ресурса производится непосредственно перед try, а освобождение — в finally.
  • Возможность утечки ресурсов в создающей (захватывающей) функции, устраняется с помощью try..except, при этом захват ресурса производится перед try, а высвобождение в except с последующим raise.
  • Возможность утечки ресурсов в конструкторе устраняется с помощью сохранения ссылок на захваченные ресурсы в полях объекта и учетом и написанием деструктора, корректно удаляющего частично инициализированный объект. Это связано с порядком создания объекта в Delphi

  1. Выделяется память под объект и заполняется нулями
  2. Выполняется конструктор
  3. Если на предыдущем шаге возбуждено исключение, то вызывается деструктор, освобождается занятая память и перевозбуждается исключение.

  • Если ресурсы представляют собой ссылки на объекты, то в деструкторе достаточно использовать для них FreeAndNil
  • В пределах подпрограммы можно использовать аналогичную технику вместо многократного вложения блоков try..finally, помещая «конструктор» сразу после try и «деструктор» в finally. Так как локальные переменные не инициализируются, то это надо делать вручную, присваивая им nil перед try.
  • Если ресурс не реализован в виде класса и используется неоднократно — надо создать класс, в конструкторе которого осуществляется захват ресурса, а в деструкторе — освобождение. Это сделает использование ресурса более простым и единообразным, а отлов его утечек сведется к отлову утечек памяти.

Поиск утечек ресурсов
Поиск утечек, продолжение

11 Наследование, композиция, реализация, расширение


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


12 Интерфейсы


  • Об утечках при использовании интерфейсов можно не беспокоиться.
  • Методы, реализующие интерфейс должны быть невиртуальными и не публичными, обычно защищенными.
  • Любой интерфейс содержит как минимум три метода — QueryInterface, AddRef и Release.
  • Эти методы вызываются неявно: первый приведением к ссылке на интерфейс операцией as, второй и третий — при создании новой ссылки на интерфейс и удалении (или выходе из поля видимости).
  • При реализации интерфейсов потомками TObject необходимо реализовывать все три вышеупомянутых метода.
  • Потомки следующих классов имеют реализации QueryInterface, AddRef и Release по умолчанию:
    • TInterfacedObject реализует автоматическое удаление, когда на интерфейсы класса не остается ссылок, поэтому его потомки сразу после создания надо приводить к ссылкам на интерфейс.
    • TComponent игнорирует ссылки на реализуемые интерфейсы и удаляется только вручную, поэтому надо следить чтобы после удаления его потомка не оставалось висячих ссылок на интерфейсы.


13 Визуальные компоненты


  • Фреймы и формы не должны содержать в себе никакой логики, кроме логики отображения и передачи (не исполнения!) команд пользователя.
  • Все возможные варианты команд пользователя должны оформляться в виде Action и помещаться в один ActionList в том же фрейме, в котором эта команда доступна.
  • Автоматически созданные Delphi имена компонентов можно оставлять только для тех из них, на которые нет ссылок в коде методов и нет обработчиков. Осмысленное имя надо задавать до создания первого обработчика для данного компонента, иначе потом придется править имя обработчика вручную.
  • Автоматически созданные имена обработчиков следует менять только при крайней необходимости.
  • Обработчики событий визуальных компонентов не должны занимать более пяти строк. Комментарии к методам-обработчикам должны разъяснять не просто обстоятельства вызова (их как раз видно уже из имени обработчика), но прежде всего его назначение — зачем этот обработчик вообще понадобился.

14 Модули


  • Модуль, используемый более чем в одном проекте — библиотечный модуль.
  • Модуль, не содержащий ничего, кроме констант, интерфейсов, типов (не классов), исключений и вспомогательных процедур — интерфейсный модуль.
  • Модуль, содержащий код обмена данными с пользователем, файловой системой БД. сетью и тп. — модуль ввода-вывода.
  • Все остальные модули — модули логики.
  • Идеальная структура межмодульных зависимостей: интерфейсные модули зависят только от интерфейсных; модули логики — только от интерфейсных и других модулей логики; модули ввода-вывода — только от интерфейсных и других модулей ввода-вывода. Это позволяет эффективно использовать модульные тесты для логики и менять реализацию разных частей проекта независимо друг от друга.

15 Устранение лишних зависимостей


  • От публичной глобальной переменной — самый плохой вид зависимости, избавляться как минимум преобразуя переменную в функцию
  • От приватной глобальной переменной — чуть лучше, так как локализует проблему в рамках модуля. Необходимо следить за возможностью многопоточной модификации и инициализацией-завершением. Например, для глобальных переменных-интерфейсов при финализации модуля неявно вызывается Release.
  • От интерфейсного модуля — ничего без крайней необходимости менять не надо.
  • От глобальных классов, процедур и функций для любого ввода-вывода (GUI, БД, связь с сервером приложений и т.п.) других модулей. Если модули проекта сами предназначены для ввода-вывода — то ничего менять не надо, иначе желательно избавиться, реализовав эту связь через интерфейс — в противном случае будет крайне затруднено внесение изменений и тестирование.
  • От модулей, содержащих вышеперечисленное — лучше избавиться, выделив из модуля, на который есть ссылка, интерфейсную часть и ссылаясь только на нее.
  • От любого содержимого библиотечного или общего модуля — без крайней необходимости ничего менять не надо.
@Bonart
карма
12,7
рейтинг –0,1
Программист
Самое читаемое Разработка

Комментарии (76)

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

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

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

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

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

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

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

                как же это ужасно выглядит, особенно две гласные буквы подряд. Лучше уж методы и поля класса писать с маленькой буквы, а private поля или прятать в приватный класс или же слова разделять через нижнее подчеркивание и добавлять префикс m_
        • +1
          А мне вот нравится первая буква, отвечающая за тип
          • НЛО прилетело и опубликовало эту надпись здесь
            • 0
              Жесткое рецензирование кода? Понимаю, хочется иногда, но надо спокойно не пропускать такое в репозиторий и вести разъяснительную работу.
        • 0
          Так исторически сложилось. Это стандартный стиль.
          • 0
            Да, я даже могу понять из за чего это так сложилось, но всё же это не отменяет устарелость этого стиля и то, что есть более современные и удобные в нынешнее время. Так зачем предлагать в качестве советов то, что осталось нам в наследство и нынче уже не подкрепляется необходимостью?
            • 0
              Т.е. из-за одной буквы вы готовы горы свернуть и привнести в программу смешение стилей?
              • 0
                Почему же? В собственных программах у меня никаких буков T и в помине нету, есть только вот префикс V в модуле для работы со вконтакте, с ним что ли названия классов красивее смотрятся, но мне лично не нравятся любые излишние соглашения в стиле. Буква T явно излишняя.
                • 0
                  А вот тут как раз — место для неймспейсов.
                  • 0
                    Это в хаскеле раздельные пространства имен для функций с параметрами, конструкторов данных, типов данных, переменных типов данных. Ни в дельфи, ни в плюсах, ни в яве, ни в сишарпе такой роскоши нет, приходится использовать те или иные соглашения для улучшения читаемости кода. Плюс в делфи еще нельзя полноценно использовать разный регистр. Отсюда и префиксы — уже по коду видно, где тип, где переменная, где поле, где параметр. С венгерской нотацией (что прикладной, что системной) это не имеет ничего общего.
                    • 0
                      Вы ошиблись ссылкой «ответить»
    • –4
      Здесь для вас еды нет
      • +4
        Вы на любую критику так отвечаете, да?
        • 0
          Это заклинание такое =)
        • –4
          Только на толстый троллизм
          • +2
            А что тут толстого? На Коболе тоже вот не рекомендуют новые проекты создавать.
  • +2
    Я не знаток Delphi и мне интересны некоторые аспекты.

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

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

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

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

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

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

          > Т.е. есть реализация только «пассивного» внесения зависимостей?
          Ну изнутри сервиса это наоборот «активное», но увы, в дельфи до 2009 IoC контейнеры слишком сложны в реализации. И у локатора свои плюсы при межязыковом взаимодействии — под Win32 на единую объектную платформу рассчитывать не приходится.
  • +1
    молодой разработчик Delphi — звучит как приговор…
    • –4
      Здесь для вас еды нет
      • –1
        От того, что вы эту фразу произнесете сто раз чуда не случится
  • 0
    «Все методы, реализующие интерфейс — обязательно 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;
  • 0
    Спасибо, хороший пост, много о чем сказано в кратком лаконичном виде.

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