Портируем, рефакторим, оптимизируем
В нескольких топиках обсуждались вопросы оптимизации кода и возникла идея рассмотреть это на конкретном примере: взять готовый код, причесать и оптимизировать. Поскольку предложенный пакет классов на AS2, то добавился еще один шаг - портирование на AS3.
Собственно код, который будем использовать взят с сайта Helen Triolo: http://www.flash-creations.com/notes...svgtoflash.php Немаловажным моментом является то, что Helen разрешает (даже приветствует) подобные действия с ее кодом и своими действиями мы не нарушаем ее законных интересов.Хочется, чтобы процесс был коллективным, но чтобы как-то упорядочить и на выхлопе получить не тонну обсуждений, а что-то вроде статьи, прошу придерживаться следующего регламента: - до полного окончания прошу никого в этот топик не писать; Если вы хотите получать уведомления, просто в левом верхнем углу кликните на иконку "Подписаться на эту тему". - я выкладываю код - результат очередного этапа, с пояснениями что сделано и зачем. - предложения, вопросы, обнаруженные ошибки участники скидывают мне на мыло: ivan.dembicki на gmail, с сабжем "Flasher.ru - Портируем, рефакторим, оптимизируем". - мы их приватно обсуждаем, затем я резюмирую здесь результат, разумеется, с указанием авторства. - выкладывается исправленный код с пояснениями что сделано и зачем. - после этого переходим к следующему этапу. Буду очень благодарен, если кто-то из модераторов согласится помочь в поддержании порядка - удалении нерегламентированных постов. Процесс делим на этапы: I. Портируем II. Рефакторим III. Оптимизируем Поехали. |
Подготовка
Вложений: 1
Заходим на сайт http://www.flash-creations.com/notes...svgtoflash.php идем в конец страницы, открываем окно downloads и скачиваем себе на комп svgtoflash.zip - он 11-й по списку.
Создаем новый AS3 проект (я использую FDT и вам рекомендую), называем его SVGToFlash, затем в винде открываем папку SVGToFlash и закидываем в нее содержимое ZIP файла. В FDT выделяем папку SVGToFlash и жмем F5. Должна получиться структура файлов как на прилагаемой картинке. Вложение 19008 |
Портирование. Задачи
Теперь мы можем приступисть к этапу портирования проекта на AS3.
Задача этого этапа: при минимальном количестве изменений в проекте сделать его работоспособным. На этом этапе мы стараемся по возможности не касаться логики приложения, его структуры и именований. Не забываем: мы нацелены на то, чтобы проект просто запустился под AS3 и дал результаты, аналогичные AS2. |
Начинаем портировать
Подготовка FLA файла.
Открываем во Flash файл svg_displayinflash.fla. Изменяем настройки файла: File - Publish Settings - Flash устанавливаем FlashPlayer 9 и ActionScript 3.0 Заходим в настройки ActionScript 3.0 и устанавливаем все галочки кроме Strict Mode. OK.OK. Затем добавляем папку src в путь к классам: Edit - Prefences - ActionScript - Actionscript 3.0 добавляем строку ./src и выставляем ее второй по порядку. OK. Выделяем кадр actions и закомментируем единственную строку кода // #include "svg_displayinflash.as" Затем задаем Document class: SVGDisplayInFlash, Flash ругнется отвечаем OK. На этом пока заканчиваются изменения во FLA файле, сохраняем. Переходим в FDT, в проекте создаем папку src, добавляем ее в class path: правый клик на папке, Source Folder - Add to Classpath. Создаем в этой папке новый класс: SVGDisplayInFlash - если помните, мы класс с этим именем задали как Document Class. Поскольку у нас в руте есть именованые объекты holder и msg, инициализируем их в этом классе: Код AS3:
Код HTML:
SVGDisplayInFlash.initInstance() |
Повторяем структуру
Вложений: 1
Для того, чтобы файлы AS2 нам не мешались, создадим папку temp и забросим все AS2 файлы в эту папку.
Затем создадим иерархию папок com.itechnika.svg и создадим пустые классы Math2, PathToArray, String2. В итоге должна получиться вот такая картина происходящего: (спасибо, iNils за помощь в публикации материалов) |
Портирование классов пакета com.itechnika.svg
Порядок портирования классов определяестя следующим образом: вначале портируем классы, которые не требуют других классов проекта.
Затем переходим к тем классам, которые используют только портированные классы. Внутри классов действуем по этой же схеме: вначале портируем те функции, которые не используют других пользовательских функций, и затем переходим к функциям, которые используют уже портированные. Следуя этой логике, портирование классов начнем с Math2. Для этого откроем созданный нами пустой класс Math2, и рядом AS2 версию этого класса. Скопируем содержимое AS2 класса кроме первой и последней строки и вставим в тело AS3 класса. Оценим степень разрухи: всё не так уж и страшно. Явных ошибок FDT не нашел, только подсветил отсутствие или неверную типизацию. На этом этапе мы не будем приводить этот код в порядок, поскольку наши изменения могут повлиять на другие классы. Проделаем аналогичную операцию с остальными классами в папке svg. Класс String2, а его мы портируем вторым, также не доставил никаких хлопот. В классе PathToArray потребовалось только импортировать XMLNode: import flash.xml.XMLNode; Тестирование. На данном этапе мы не можем качественно протестировать соответствие кода стандартам AS3. Но минимальный тест всё-таки сделать необходимо. Поскольку класс PathToArray использует и Math2 и String2, то нам для теста достаточно создать экземляр такого класса для того, чтобы компилятор Flash сказал свое веское слово. Для того, чтобы создать экземпляр класса PathToArray нам потребуется посмотреть с какими параметрами он вызывается. С этой целью найдем исходный ZIP файл, распакуем его в папочку на рабочем столе, откроем класс PathToArray и добавим трейсы: Код AS3:
Теперь можем добавить тест. В классе SVGDisplayInFlash добавим метод testPathToArray: Код AS3:
Результатом компиляции станет ругань компилятора. При ближайшем рассмотрении видим, что нет ничего страшного: дважды он ругается на то, что Number не может быть undefined и несколько раз на дублирование объявления переменных. Это несложно исправить. В соответствующих местах заменяем проверку на равенство undefined на функцию isNaN: Код AS3:
Компилируем еще раз и убеждатемся в том, что компилятор не выдает ошибок. Если это так, то можем переходить к следующей части. |
Финальный этап портирования
Вложений: 1
На этом этапе мы портируем svg_displayinflash.as, который представляет собой код инициализации приложения.
Код состоит из двух функциональных частей: загрузка данных в SVG формате и отрисовка полученного пути. Загрузка данных - дело известное, начнем с этого. Добавим в класс SVGDisplayInFlash методы инициализации загрузки и обработчик полученных данных: Код AS3:
getSVGData(SVG_DATA_URL); Если в результате компиляции не возникло проблем, то можем переходить к следующему шагу: портированию метода getShapes и процедуре его вызова. Копируем и вставляем этот метод в класс SVGDisplayInFlash и видим, что FDT подсвечивает множество ошибок. Как это ни странно, но это очень хороший признак, что основная масса ошибок пришлась на последний этап портирования и говорит о правильно избранной стратегии действий. Сейчас у нас развязаны руки и мы можем вносить правки в код, не волнуясь о том, что это может чем-то навредить остальной части проекта. Однако мы не забываем, что на этом этапе наша задача - сделать код работоспособным с минимальными изменениями. Копируем и вставляем объявления переменных, делаем их приватными. Если мы внимательны, то увидим, что переменная x будет конфликтовать со свойством мувиклипа, в котором мы ее объявили. Если мы невнимательны, то компилятор Flash об этом нам напомнит при первом же тесте. Переименуем ее в svg: Код AS3:
Код AS3:
Приступаем к портированию обработки загруженных данных. Пока мы можем пропустить обработку ошибок, поэтому просто переносим строки инициализации из оригинального метода xmlLoaded в метод onSVGLoaded: Код AS3:
Добавляем парсинг полученных данных перед первым обращением к объекту svg: Код AS3:
Код AS3:
Что же нам позволило даже не вникая в суть кода добиться успеха? Методология. Мы следовали простым принципам и в каждый момент делали только то, что соответствовало нашей стратегии: - мы портировали код в строгом порядке: вначале портировались классы не использовавшие других пользовательских классов, только затем классы, использовавшие уже портированные классы, до тех пор, пока таким образом не закончили последний. - мы не изменяли код без крайней на то необходимости и оставили это на самый последний момент. - мы тестировали код при первой возможности. Чего мы избегали: - мы не пытались улучшить код, добавить недостающую типизацию, или изменить логику кода. Мы оставили это для следующих этапов: рефакторинга и оптимизации. |
Начинаем рефакторить
Итак, после успешного портирования мы переходим к следующему этапу - рефакторингу.
Вначале давайте определимся с тем, что такое рефакторинг, зачем он нужен, и затем перейдем к задачам, которые у нас стоят на этом этапе. Код, который мы портировали писался много лет назад. С тех пор изменился не только язык, но и культура написания кода, редакторы кода и общее понимание того, что такое хороший код. Рефакторинг - это улучшение таких свойств кода как читабельность, прозрачность, сопротивляемость ошибкам, а также облегчение его повторного использования, поддержки и дальнейшего развития. Рефакторинг состоит из множества небольших шагов не изменяющих поведения программы. Обратите внимание на то, что здесь ни слова не говорится об увеличении производительности кода, поскольку этот процесс, как правило, затрагивает логику программы, что на этапе рефакторинга недопустимо. Знающие люди могут возразить против самой постановки задачи: рефакторинг не один большой этап, а регулярно выполняемая процедура в процессе программирования. Я, конечно в курсе, но первый рефакторинг после портирования - довольно цельный и объемный этап работ не сопоставимый с обычным рефакторингом, проводящимся в процессе написания программы. Именно поэтому мы уделяем ему такое внимание, что даже выделяем в отдельный этап. Теперь можно определиться с целями: а что же конкретного в итоге мы желаем от нашей программы? Есть две полярные цели: просмотрщик svg файлов и редактор svg файлов. В первом случае стоит задача максимально производительного построения изображения, а во втором - возможность последующего расширения функциональности. Как уже было сказано выше, на этапе рефакторинга нас не интересует производительность приложения, но очень важны другие свойства кода. Этим требованиям более всего отвечает направление на возможность развития проекта в будущем вплоть до редактора svg файлов. А самой первой задачей рефакторинга станет наведение элементарного порядка в коде, до такой степени, что FDT перестанет нам подсвечивать ошибки. |
рефакторим String2
Первый класс, который мы поправим - String2. Он самый короткий, и не использует других наших классов. И для примера я поподробнее остановлюсь на самом процессе.
Подсвечиваются всего три ошибки: в методе shrinkSequencesOf не задана типизация локальных переменных. Зададим ее: Код AS3:
Займемся именованием. Для начала заменим имена аргументов функции. Думать тут особо не надо, поскольку автор позаботилась о комментариях: s заменяем на originalString, ch заменяем на characterToBeFound. Затем, поскольку сокращений мы не любим, заменим: len на length idx на startIndex idx2 на endIndex rs на resultString Также добавим фигурные скобки вложенному while. Давайте сравним, что было и что стало: Код AS3:
Обратите внимание на еще один положительный фактор: в процессе мы всё еще не изменяли логику программы, но уже начали более детально знакомиться с проектом. К тому моменту, когда мы закончим рефакторинг мы будем довольно неплохо представлять что в проекте имеется, где находится и как примерно работает. |
рефакторинг класса PathToArray
Следующий класс для причесывания - PathToArray. Он хоть и дает большое количество ошибок, однако подавляющее большинство - по одинаковой причине, и их можно исправить без существенных усилий.
В методе extractCmds динамически создается объект, содержащий перечень значений стандартных цветов. Эти цвета неизменны, а объект может быть использован неоднократно. Это прекрасный повод сделать объект статической константой и инициализировать его в теле класса. Так и поступим. Вырезаем из метода всю инициализацию объекта colors, до строчки yellowgreen : 0x9acd32 включительно и вставляем с тело класса непосредственно после объявления класса. Затем изменяем объявления и переносим закрывающую скобку в конец присвоений значений цветам. Должно получиться так: Код AS3:
В итоге должно получиться так: Код AS3:
Изучив текущее состояние увидим, что очень много ошибок дает нетипизированный доступ к атрибутам. Что-ж, создадим специальный метод доступа и заменим на него обращения к атрибутам. Код AS3:
заменяем "node.attributes." (с точкой на конце!) на "getAttribute(node, ", в результате чего редактор расцветет массой ошибок. Это очень хорошо. Кликая на красные точки справа от скроллера мы переходим от ошибки к ошибке и ставим закрывающую скобку сразу после первого слова, следующего за "node". Заодно берем это слово в кавычки, поскольку это имя атрибута. В процессе мы обнаруживаем еще одну прелесть рефакторинга: мы обнаружили ошибку несоответствия типов в строке: Код AS3:
При обнаружении ошибки нужно четко понимать, что процесс рефакторинга останавливается и начинается другой процесс - исправление ошибки логики. Обнаружение ошибки - серьезное происшествие и очень хорошее: будучи скрытой мы могли голову сломать откуда она берется и найти только с большим трудом. В данном случае это локальная ошибка, не влекущая за собой цепочку других. Но всё-таки рассмотрим ее отдельно. |
Часовой пояс GMT +4, время: 16:04. |
Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.