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 довольно просто случайно изменить какие-то свойства формы потеряв связи между компонентами, и потом приходится тратить время на поиск источника ошибок. Просмотр изменённого кода и откат изменений для тех строк, которые вы не собирались менять позволяет избежать этого. А также помогает писать историю изменений.
Posted by Aleksey Timohin at 15:12
Labels: Blogroll, Delphi, know how, грабли, организация проекта
http://tdelphi.blogspot.com/2009/06/delphi-2009.html