Motto

В тихом саду здравомыслия
Пусть на вас постоянно падают
кокосовые орехи пробужденности.
Чогьям Трунгпа РИНПОЧЕ


Версия для мобильного


среда, 3 июня 2009 г.

О переходе крупного проекта на Delphi 2009(перевод)

Перевод статьи: “Upgrading a major project to Delphi 2009”,  Lars B. Dybdahl.

Вот и закончен перевод на Delphi 2009 крупного проекта, который в течении нескольких лет разрабатывался довольно большой командой программистов. Теперь я готов поделиться опытом.

Если Вы хотите оценить объём работ, которые потребуется для конвертации проекта, примите во внимание, что объём строк в проекте не является таким уж и значимым показателем. Более важно, какой код у Вас есть, насколько он сегментирован, и насколько согласованно написаны сегменты. Вещи относящиеся к пользовательскому интерфейсу, бизнес логике и т.п. очень легко конвертировать. Я бы даже сказал, что достаточно просто перекомпилировать и запустить. А вот с другими частями, всё будет не так просто.

Наш код был четко сегментирован. Так что любой модуль можно было отнести к одной из групп:

  • Очень старый код. Некоторые части содержали прямо-таки доисторический код, особенно это касалось сторонних компонентов, но здесь многие проблемы были решены путем простого переименования string => ansistring, char => ansichar, pchar => pansichar. Обращения к Windows API были изменены на обращения к Ansi-версиям функций. После этого все стало работать так же как и раньше, хотя и не приобрело поддержки Unicode.
  • Сторонние компоненты. Мы купили обновления для большей части, а кое-какие старые бесплатные компоненты с исходными кодами мы обновили своими силами.
  • Пользовательский интерфейс. Кроме покупки обновлений, здесь не пришлось ничего менять.
  • Самодельные компоненты. Здесь иногда попадались оптимизации, которые требовали особого внимания при приведении их в соответствие с Delphi 2009, но в основном они заработали без изменений.
  • Бизнес-логика. Здесь были заменены некоторые общие вещи, но их было очень легко обнаружить и исправить. Это было почти так же просто, как воспользоваться функцией Найти и заменить(search & replace).
  • Модули манипулирования битами. Эти модули работали с байтами, и лучшим рецептом оказалось, сначала заставить их работать в новой системе как обычный старый код, а после этого уже перевести на юникод.
  • Процедуры ввода/вывода в основном пришлось переписывать. Мы перевели некоторые выходные текстовых файлов в кодировку UTF-8, а некоторые оставили как было. Основная проблема была с кодом, который пытался использовать юникод в Delphi 2006/2007, поскольку старые версии хранят UTF-8 в ansistring. Решение заключается в том, чтобы устранить перекодирование в UTF-8 внутри алгоритма, и преобразовывать строки в UTF8 в операциях ввода/вывода.

Самой сложной частью оказались блобы, которые могут содержать как бинарные данные так и текст. К несчастью, если в Delphi 2007 .AsString работал с обоими типами, то теперь каждый тип должен обрабатываться по-своему. Мы решили создать дубликаты кучи процедур, один экземпляр для RawByteString, а другой для String, и потом уже использовать подходящий в зависимости от типа поля. Сделать перевод было нетрудно, и теперь большая часть нашей системы поддерживает unicode, а остальное мы переведём в скором время. Однако для более эффективного перевода приложения, очень полезен опыт рефакторинга[1]. Если такого опыта нет – перевод может занять значительно больше времени.

Я хотел бы дать несколько советов для тех кто собирается идти тем же путём:

  • Преобразуйте код постепенно - это проще чем пытаться перевести весь код с первой попытки. Конвертируйте модули постепенно, пока не преобразуете все.
  • Сделать чтобы код мог одновременно компилироваться и в Delphi 2006, 2007 и в Delphi 2009 не так уж и сложно. И я рекомендую делать именно так, чтобы ваша команда могла продолжать работать с проектом, даже пока он не переведён до конца.
  • Когда Вы преобразуете модуль, заменя в нём string на ansistring, старайтесь, чтобы замена коснулась только cекции implementation, а в секции interface сохраните тип string. Это позволит избежать лишней правки кода использующего данный модуль[2].
  • Старайтесь исправлять(а не игнорировать) warning-и связанные со строками. Большую часть из них очень легко исправить.
  • Всегда просматривайте ваши изменения перед тем как отправить их в хранилище кода(репозиторий), чтобы убедиться что изменения коснулись только того, что Вы хотели изменить:-) [3]
Примечания переводчика

[1] Рефакторинг – рулез. =) Грамотно проведённый рефакторинг способен существенно упростить процесс перевода. И я считаю, что именно с него стоит начинать, ещё до того, как какие-либо шаги по переводу были сделаны. Я недавно закончил перевод большого приложения с BDE на FibPlus и рефакторинг старого кода очень серьёзно упростил мне жизнь.

[2] Интерфейсную часть модулей лучше всего сохранить неизменной. Это позволит избежать лишних правок в местах использующих эти интерфейсы и ограничить область появления и правки ошибок только этим модулем. Т.е. по сути, это даёт некоторую гарантию того, что вы не внесёте новые ошибки в другие модули, только потому, что вы исправили этот.

[3] Просматривать изменения перед отправкой(commit) в репозиторий(например SVN) – это очень хорошая практика. Во-первых она позволяет отследить и своевременно удалить забытый отладочный код, ещё до того, как он начнёт создавать проблемы. Во-вторых, в Delphi довольно просто случайно изменить какие-то свойства формы потеряв связи между компонентами, и потом приходится тратить время на поиск источника ошибок. Просмотр изменённого кода и откат изменений для тех строк, которые вы не собирались менять позволяет избежать этого. А также помогает писать историю изменений.

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

  1. У меня проектик на 200 тыс. строк. Полгода собираюсь с силами для перехода на 2009. Проблемы аналогичные, но после прочтения скорее всего соберусь с силами.

    ОтветитьУдалить
  2. Roman, а как ты полашаешь, сколько приблизительно времени займёт у тебя переход?

    У меня два проекта примерно по 40 тысяч строк + 50 пэкэджей на 350 тысяч строк(в основном авторские, но есть пара сторонних, которые уже не поддерживаются). Из этих 50 пэкэджей по предварительным оценкам дополнительной доработки потребуют только штук 10, остальные состоят в основном из пары юнитов. Из них реальные проблемы вызовет только один, состоящий из 150 тысяч строк.
    А в двух проектах осталось ещё достаточно дублирующегося кода. И я точно знаю, что перед тем как начать переход, я обязательно займусь этим кодом и вынесу его в пэкэджи, чтобы не переводить дважды.

    По моим грубым прикидкам переход займёт минимум 2-3 месяца. При этом первая версия программы будет доступна в течение первого месяца. Оставшееся время будет посвящено тестированию и исправлению ошибок.

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

    ОтветитьУдалить
  3. Про ansichar можно посмотреть в справочнике по Delphi www.delphizone.ru там написано, как его использовать. Вот.

    ОтветитьУдалить
  4. У меня на работе тоже 2 проекта на 150 и 250 т. строк

    Основан проблема - и там и там вовсю используются миксованные форматы фалов - бинарные данные + текст (через объявления структур)
    Ну и не уверен что AsyncPro нормально на юникоде заработает

    ОтветитьУдалить
  5. Зависит от того, насколько грамотно был написан код. Если широко использовались допуски Sizeof(char)=1, size(s)=Length(s), Move над частями строк, PChar в качестве буфера, динамически выделяемые записи с полями-строками - понадобится вдумчивое и кропотливое исправление. Помимо своих проектов (небольшие), перевёл SimpleXML и TurboPower Internet Pro - в первом понадобилось менять только некоторые места, во втором пришлось попариться чуть больше. А вот EhLib переводится элементарно, если бы автор не налажал с закладками, можно было бы вообще ничего не исправлять.

    ОтветитьУдалить
  6. (n)00 тысяч строк - ручками набранного кода? Или до кучи всё вместе со сгенерированным Делфи кодом? А может еще и пакеты сюда входят?
    Перевод крупного проекта (например программа кадрового учета крупного учреждения вышеупомянутые 300 000 строк - реально набранные ~10 000) - менее часа рабочего времени. Причем Delphi5->Delphi2007 сходу путём открытия dpr файла проекта. Главное установить все пакеты (Rx и некоторые иные). Причем всё работает абсолютно корректно! Проблемы могут быть в переводе самих компонент, но в течение 1 недели (максимум!) всё решается, а потом все остальные проекты пошли "со свистом". Но вот версии delphi выше 2007... Здесь всё интереснее. Здесь String это уже строго WideString, Pchar - PwideChar и т.д. Автор статьи тут совершенно прав и тестировать придется довольно длительное время. Лучше всего по возможности избавиться от устаревших компонентов и заменить их на JVCL. Особое внимание обратить следует на компоненты типа MemoryData. Скажем из Rx он совершенно не работает в Delphi выше 2007. Но переводить проект 2-3 месяца... С работы уволят за такую работу! Дается максимум дней 10-15, обычно рабочая неделя и пуск в реальной обстановке - ошибки правяться "на лету". Сложно конечно в такой нервозной обстановке, но иначе ничего не получиться. Программист не в состоянии смоделировать реальную рабочую обстановку службы-пользователя, поскольку интуитивно будет обходить ситуации которые могут вызвать сбой. Кроме того разрабатывая и сопровождая одновременно десяток, другой проектов предметные области по ним детально изучить не реально.

    ОтветитьУдалить
    Ответы
    1. > Но переводить проект 2-3 месяца... С работы уволят за такую работу! Дается максимум дней 10-15, обычно рабочая неделя и пуск в реальной обстановке - ошибки правяться "на лету".
      Не завидую я такой работе. =)

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

      Кстати, о тех 2-3 месяцах. Реально получилось намного дольше, раза в 3. 2-3 месяца ушло только на замену скриптового движка с DreamVCL на TMS Scripter Pro и допиливание TMS-ного движка до необходимого функционала. А потом еще написание конвертера форм и кода было.

      Удалить

Постоянные читатели