Tag Archive for 'Framework'

Гениальная статья про программистов

Прочитал сегодня интересную статью посвященную архитектуре софта и программированию в целом. Многое в ней так до боли знакомо, а кое-что прямо с языка сорвали.

Кто читал старые книги по программированию помнит термины “программирование сверху вниз”, “программирование снизу вверх”, и, самое невероятное – “от центра к краям”. Удивительная особенность этих терминов в том, что они просты и понятны, но ни один нормальный человек, примеряя объяснения на себя, понимает, что так работать не может. Это модели понятные, но к реальности никак не относящиеся. Так же, как и «легенда агилистов о ватерфоле».

Действительно. Как раз тот случай, когда “в теории между теорией и практикой не должно быть различий, а на практике…”. Далее автор описывает два граничных подхода: push и pull.

Приступая к задаче, вы осознаете, что есть некая общая проблема, для разработки которой совершенно необходимо разработать фреймворк… Программисты любят это. Занимаясь фреймворком, они, подобно фундаментальным математикам, уходят в небеса абстракций, теряя контакт с внешней решаемой проблемой. Это психологически очень комфортно. Не приходится иметь дело с практикой, которая способна внести в теорию свои неожиданные и неприятные коррективы. Вернее, этот момент оттягивается. И это приятно.

Это первый экстремальный подход. Разработка фреймворка ради самого фреймворка. Глаз радует структура и красота кода, но часто на практике не все работает так идеально как хотелось бы. И хорошо, если до осознание этого вообще доходят.

Это у нас гордые и способные программисты. Они, бывает, называют программистов, описанных выше “архитектурными астронавтами”. Почему? Да потому, что они ерундой какой-то занимаются, когда надо просто взять и написать код. И они умеют колбасить этот код тоннами, и делать это быстро. И этот код – работает.

И еще, они обычно работают в одиночку. Либо у них весь жизненный опыт такой, либо они просто не любят работать в группах. Либо, когда они пытаются работать в группах, их гонят оттуда коллеги ссаными тряпками то у них не складывается. Ибо, для того, чтобы продуктивно писать код группой, надо хоть как-то договорится о том, каковы общие принципы устройства этого кода, а это – “архитектурная астронавтика”.

А вот такие большинство флэшеров фрилансеров. Что уж тут, сам таким был, ога.

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

Вот тут я улыбнулся. Я думал я один сижу в блокноте накидываю примеры кода, которые могли бы использовать проектируемую библиотеку. Получаются такие мини-тесты, которые не компилируются и не выполняются, но по ним уже видны разного рода косяки и неудобства API.

В общем, читайте дальше.

Dependency Injection

Dependency Injection и принцип Inverse of Control в программировании используются уже давно. Я как понял DI — это термин, который Мартином Фаулером используется для обозначения того же IoC. Что же это такое и как его использовать нам, простым флэш разработчикам.

Все просто. Основная идея — при создании объекта ему даются (инжектируются) уже готовенькие объекты, в которых он нуждается (зависимости). Каждый из нас, интуитивно полагая, что это гуд, использовал Dependency Injection в той или иной мере. Вот простой код.

public class One{
    public function One( two: ITwo )
    {
        this.two = two;
    }
}

public class Two implements ITwo {
    ...
}

new One( new Two() );

Как видно, объекту класса One мы передаем объект с интерфейсом ITwo при создании. Перед нами простой пример так называемого Constructor Injection. Также есть Property Injection, когда класс предоставляет public свойство или сеттер, через который ожидает получить некоторый объект, в котором нуждается. Идея проста до безобразия и позволяет проще переиспользовать классы, которые друг на друга не завязаны.

Противоположный подход — создавать все dependency внутри класса, при этом классы становятся привязанными друг к другу, что усложняет внесение изменений.

Интереснее же все становится, когда на сцену выходит IoC Contaner. Под контейнером понимается некоторое пространство для объектов, который по определенным правилам эти объекты сам конфигурирует и сам подставляет dependencies куда и кому нужно. Проще говоря, некоторый фреймворк, который сам соображает (с нашими подсказками) как собрать те или иные объекты и какие зависимости им нужны.

AS3.

Речь пойдет о чисто AS3 проектах. Они обычно небольшие в отличие от Flex проектов, которые можно сравнить с Java Enterprise проектами. Если в Java существует толпа IoC фреймворков (как я понимаю самый популярный Spring Framework), то для ActionScript до недавнего времени все было как-то грустно. Конечно, AS3 язык гораздо моложе, чем Java, скажете вы.

Между тем я случайно наткнулся на Syringe, который мимикрирует со Spring, повторяя метод конфигурации через XML, но последняя версия выпущена в бородатом 2006м. Видим, что какие-то попытки перенести функциональность Spring на ActionScript3 велись, но не были поддержаны сообществом, потому что сообщество не было к этому готово. И, конечно же, потому, что большинство AS3 проектов небольшие, на одного программиста и дизайнера.

Какое-то время уже существует официальный Spring ActionScript (бывший Prana). Этот фреймворк вроде бы развивается и сейчас остановился на версии 0.8.

Favour of the month безусловно является Parsley, версия 2 которого радикально изменилась и поддерживает множество вкусных фишек. В том числе и для pure AS3 проектов.

Применение.

Как-то давно на основе Parsley 1.* я набросал себе небольшой фреймворк, который использую при создании и конфигурировании видео плееров и фото галерей.

Значит, допустим у нас есть видео плеер с архитектурой MVC. Разные проекты предусматривают разное расположение визуальных элементов и разные функции. Чтобы каждый раз не копипастить все это, делаем максимально decoupled компоненты и собираем их IoC контейнером при помощи XML конфига.

Вот пример такого конфига для одного из плееров. Видим команды контейнеру по сборке объектов. Любую можно убрать или добавить и плеер пересоберется подругому. Порой, даже не нужно перекомпилировать проект. Конечно, данный пример не использует таких мощных фишек контейнера, как инжектирование по типу, просто мой старенький этого не умеет.

<?xml version="1.0" encoding="UTF-8"?>
<container>
<commands>
<!-- Скин плеера -->
<object name="skin" class="com.qq.videoplayer.skin.PPSkin" />
<!-- Сам плеер -->
<object name="player" class="ru.valyard.media.mediaplayer.VideoPlayer">
<constructor-args>
<object ref="skin" />
</constructor-args>
<!-- Контейнер для контролов -->
<view name="controls" class="ru.valyard.upa.mvc.views.FixedContainer" />
<!-- Компонент показывающий картинку до проигрывания -->
<view name="preview" class="ru.valyard.media.mediaplayer.views.controls.PreviewView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Анимашка, которая моргает во время буферизации -->
<view name="buffering" class="ru.valyard.media.mediaplayer.views.controls.BufferingView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Большая кнопка Play в центре -->
<view name="bigPlay" class="ru.valyard.media.mediaplayer.views.controls.BigPlayButton" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
</view>
<!-- Экран как видео проигралось -->
<view name="stopView" class="ru.valyard.media.mediaplayer.views.controls.StopView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
</view>
<!-- Верхние контролы -->
<view name="dynamicpanel2" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">10</property>
<property name="xRule">5</property>
<property name="inactiveYRule">-70</property>

</view>
<view name="top" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel2">
<constructor-args>
<int>0</int>
</constructor-args>
</view>
<!-- Fullscreen -->
<view name="fullscreen" class="ru.valyard.media.mediaplayer.views.controls.FullscreenButtonView" parent="top"/>
<!-- Share -->
<view name="shareButton" class="ru.valyard.media.mediaplayer.views.controls.ShareButtonView" parent="top"/>
<view name="popout" class="ru.valyard.media.mediaplayer.views.controls.PopoutView" parent="top"/>
<!-- Основные контролы -->
<view name="dynamicpanel" class="ru.valyard.media.mediaplayer.views.containers.DynamicContainer" parent="controls">
<property name="yRule">H-42</property>
<property name="inactiveYRule">H</property>
</view>
<view name="panel" class="ru.valyard.upa.mvc.views.HorizontalContainer" parent="dynamicpanel">
<constructor-args>
<int>2</int>
</constructor-args>
</view>
<!-- Watermark -->
<view name="watermark" class="ru.valyard.media.mediaplayer.views.controls.SymbolView" parent="dynamicpanel">
<constructor-args>
<string>Watermark</string>
</constructor-args>
<property name="xRule">W</property>
</view>
<!-- Play/pause buttons -->
<view name="playpause" class="ru.valyard.media.mediaplayer.views.controls.PlayPauseView" parent="panel"/>
<view name="prev" class="ru.valyard.media.mediaplayer.views.controls.PreviousView" parent="panel"/>
<view name="next" class="ru.valyard.media.mediaplayer.views.controls.NextView" parent="panel"/>
<view name="line" class="ru.valyard.media.mediaplayer.views.controls.LineView" parent="panel">
<property name="widthRule">W-playpause.width-sound.width-next.width-prev.width</property>
<property name="leftSpace">1</property>
<property name="topSpace">12</property>
<property name="rightSpace">4</property>
<property name="scrollerDist">6</property>
</view>
<!-- Sound on/off button -->
<view name="sound" class="ru.valyard.media.mediaplayer.views.controls.HorizontalSoundView" parent="panel"/>
<!-- Share window -->
<array name="sizesArray">
<string>640x480</string>
<string>480x360</string>
<string>320x240</string>
</array>
<view name="shareView" class="ru.valyard.media.mediaplayer.views.controls.ShareView" parent="controls">
<property name="xRule">W*.5</property>
<property name="yRule">H*.5</property>
<property name="sizes" ref="sizesArray"/>
</view>
<!-- Ad -->
<view name="ad" class="ru.valyard.media.mediaplayer.views.thirdparty.TremorMediaAdsView" parent="controls">
<property name="widthRule">W</property>
<property name="heightRule">H</property>
<property name="id">123</property>
</view>

<module class="com.qq.videoplayer.modules.PlayCount" name="playcount">
<constructor-args>
<string>http://qq.com/qq.php</string>
</constructor-args>
</module>

<!-- Debug actions -->
<action class="ru.valyard.media.mediaplayer.actions.TestAction" name="*" priority="3" />

<!-- XML loader class -->
<object name="loader" class="ru.valyard.media.mediaplayer.loaders.PlaylistXMLLoader" />
<method name="registerLoader">
<object ref="loader" />
</method>

<!-- Embed HTML template -->
<property name="embedHTMLTemplate">
<![CDATA[<object width="%W%" height="%H%"><param name="movie" value="http://www.qq.com/swfs/embed.swf?id=%ID%"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.qq.com/swfs/embed.swf?id=%ID%" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="%W%" height="%H%"></embed></object>]]>
</property>
<!-- -->
<property name="pageURLTemplate">
<![CDATA[http://www.qq.com/video/%PAGE%]]>
</property>
<!-- -->
<property name="dataURLTemplate">
<![CDATA[http://www.qq.com/xml/%DATA%]]>
</property>

<property name="mediaURLTemplate">
<![CDATA[http://www.qq.com/videos_final/%URL%]]>
</property>
</object>
</commands>
</container>

С первого взгляда все сложно, хотя такая конфигурация успела сохранить мне кучу времени при создании однотипных модульных видео плееров немного отличающихся по скину и функциональности.

Плюсы.

Про конфигурирование плеера я уже сказал. Это несомненно плюс. Этот подход позволяет максимально разделить используемые объекты друг от друга и легко переиспользовать их в других проектах. В осноном, избавляет от неободимости писать кучу конфигурационного кода. Конечно, приведенный здесь конфиг не является идеальным примером. СтОит почитать хелп Parsley, который имеет куда более продвинутые способы конфигурирования.

Минусы.

Есть какая-то граница, при переходе которой конфигурирование контейнера превращается в более time consuming процесс, чем если бы я просто сел и руками все написал. Конечно, IoC позволяет создать задел на будущее для возможных исправление и переработок, но как показывает практика, часто нужно просто быстренько наклепать код и избавиться от него. В небольших проектах смысла использовать особо нет, если не имеет место сборка маленьких reusable компонентиков.

Детская болезнь — велосипеды изобретать

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

Что касается флэша, в мои юные годы сам флэш был молод, но уже где-то на шестерке помню программы представляли собой какое-то сборище кода на ключевых кадрах. Потом пришло осознание того, что надо бы как-то структурировать как минимум места с кодом. Тем временем флэш рос и развивался, я стал заводить что-то типа библиотек объектов и следовать некоторым логичным паттернам программирования. AS2 и AS3 вывел флэш программирование на новый уровень. Среднестатистический AS3 разработчик высунул голову в мир “старших” братьев-языков и спросил “Ну что тут у нас?”. На что получил уйму непонятных слов, типа паттерн, фреймворк, рефакторинг и всяческий юниттест.

В основном, конечно, стоит винить кривую развития AS, и то, что серьезным языком он стал совсем недавно.

В итоге имеем Флексеров, которые скорее всего пришли из Java, “покадровых разработчиков”, которые до сих пор не хотят учить AS3, и кто-то между ними.

Говоря о чекпоинтах, каждый программист рано или поздно понимает вроде бы очевидные на наш взгляд вещи. Из своего опыта он приходит к тому, что уже n-цать лет все знают и написали кучу книжек и библиотек. Но говоря об AS3 программистах, всякие интересные фреймворки стали появляться не так давно и преимущественно под Flex. А что делать тем, кто вынужден разрабатывать сложные вещи не используя Flex Framework…

Тут мы начинаем изобретать велосипеды. Часто вместо того, чтобы оглянуться вокруг и разобраться что же все-таки есть из того, что можно уже не изобретать. Почти все пользуются простыми опенсорс библиотеками, типа Tweener или TweenLite, делают простое 3D с помощью Papervision3d или Away3d. А вот с глобальными шаблонными фреймворками как-то более грустно. В основном у каждого по своему подходу и следовательно по своему велосипеду.

Хорошо еще, когда велосипед свою работу с горем пополам выполняет. Я видел такие чудеса, которые копипастились из проекта в проект и были больше похожи на какие-то проволочные велосипеды с бетонными колесами. Кто-то использует, например, PureMVC и старается придерживаться некоторых паттернов — это следующий чекпоинт. Но, даже например в PureMVC мне много чего не нравится и кажется ограничивающим, хотя фреймворк-то микроскопический.

В итоге начинаю изобретать свой велосипед по всем правилам и следуя паттернам. Через какое-то время взгляд в прошлое и полученные знания открывают глаза на то, какой велосипед-то получился никчемный. Начинается новый велосипед и так какое-то количество итераций.

Я думал над этим. Мне, видимо, чего-то не хватает, чтобы сразу закодить этакий титановый велосипед с непротыкаемыми колесами. Все время натыкаясь на какое-то косяк реализации, я придумываю как это сделать лучше и начинаю с начала. И что в итоге? На разработку уходит куда больше времени, чем этот фреймворк времени экономит.

Вот и сейчас. Я, можно сказать, загорелся некоторыми интересными принципами и реализациями.

Когда уже это пройдет и я займусь настоящим делом, которое приносит доход, а?

Велосипед

Джуик ну уж оооочень в тему

- Все имеюющиеся шаблонизаторы и фреймворки — говно. Пишу свой парсер.
- а потом твой парсер разрастется в большой шаблонизатор и тоже станет говном :)

Потому что я как раз пишу свой маленький уютный фреймворк, который по моим подсчетам вырастет во Flex Framework через этак год ((8

onEnterFrame.ru #5

Первый посленовогодний выпуск подкаста. На этот раз темы следующие:

  • Новый год, новые перспективы
  • Немного о кризисе, банкротстве Circuit City и Обаме
  • Как 20го числа умер CS4
  • Фреймворк, Parsley, Spring Actionscript (ex-Prana), IoC, DI, MVC, AOP и другие страшные слова
  • AsUnit и асинхронные тесты
  • TheFWA и ecodazoo.com
  • TheFWA и книжка
  • TheFWA и valyard.ru
  • С кем дальше записывать подкасты?

Ссылки по теме:

Audio clip: Adobe Flash Player (version 9 or above) is required to play this audio clip. Download the latest version here. You also need to have JavaScript enabled in your browser.

Скачать

FrameworkQuest

Отличный цикл статей на InsideRIA под общим названием FrameworkQuest. Рекомендую к прочтению тем, кто не знает чем отличается IoC ot PureMVC и чем закусывать Cairngorm. Чрезвычайно интересно. И не только флексерам.