Flex mojos 3.1 released »

Package organization

Организация кода в пакеты

Словарь

Рефакторинг - Классическая книга описывающая практики рефакторинга - http://www.ozon.ru/context/detail/id/1308678/
DSL - Domain-specific language

Введение

Пакеты это механизм для организации кода и разрешения конфликта уникальности наименования классов. Это техническое определение, но по какому принципу создавать наименования? Какими критериями руководствоваться? И зачем вообще об этом задумываться?
К сожалению этот вопрос слабо освещен в классической литературе. В данной статье я хочу поделиться своим опытом и некоторыми исследованиями по данному вопросу. Первая часть статьи это моя попытка выделить общие принципы. В частности много идей я подчеркнул из презентации Juergen Hoeller, http://www.infoq.com/presentations/code-organization-large-project. Вторая часть статьи - описание вымышленного flex проекта и пошаговое развитие его структуры на основе сформулированных принципов и моего личного опыта.

Общие принципы

Можно сформулировать следующие архитектурные принципы:

      Избегать циклических зависимостей;
      Избегать дублирования;
      Формировать модули;
      Стремиться создавать слабо связанные модули;
      Выбирать модули на основе логической, концептуальной организации (домена)

Далее о каждом их них более подробно:

Избегать циклических зависимостей между пакетами

картинка

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

Избегать дублирования

Часто альтернативой циклической зависимости является дублирование кода. Но такой код уже плохо пахнет. Дублирование загромождает код и затрудняет его модификацию. Попробуйте переосмыслить местоположение нового кода и не прятать его глубоко в иерархии.

Формировать модули

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

Стремиться создавать слабо связанные модули

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

Выбирать модули на основе логической, концептуальной организации (домена)

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

Зачем об этом заботиться?

Правильная организация пакетов и модулей позволит:
- создать устойчивый внешний API для поддержки обратной совместимости;
- уменьшить время на понимание кода;
- упростить тестирование;
- облегчить повторное использование;
- уменьшить время компиляции, что немаловажно для большого приложения;
- привнести в работу программиста творчество.

Пример и несколько практических советов

В последнее время я часто встречаю в flex приложении структуру пакетов следуещего вида:
vo
view
model
control
commands
business
events
Такое разделение на пакеты пришло к нам из фреймворка Cairngorm, где, видимо его применение оправдано. Но оно встречается и в приложениях, где Cairngorm не используется. Как показывает моя практика, такое разделение плохо развивается при разрастании приложения, пакеты получаются сильно связанные и их практически невозможно использовать повторно в другом приложении.
Я использую разбиение по логике или функциональности. Попробую привести пример.

Рассмотрим приложение AdminPanel

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

Начальная структура

rootpackage = com.agakhov.examples.adminpanel
rootpackage.ApplicationView.mxml // определяется размещение всех компонентов приложения
rootpackage.MainDataModel.as // модель данных всего приложения
rootpackage.MainEventMap.xml // сущность из фреймворка mate, её можно заменить обычным классом контроллера
rootpackage.AdminApplucationEvent.as // событие уровня приложения, например ApplicationStart
defaultpackage.Main.xml //создает и инициализирует основные компоненты)

То, что я делал до сих пор, относилось ко всему приложению, поэтому я не выделял никаких специализированных пакетов. Приложение запускается показывает пустое окно и закрывается. Но уже работает.

Login

Допустим, что первая по приоритету задача это аутентификация, для неё я создаю пакет login, собирающий все что связано с этой задачей:
rootpackage.login.LoginView
rootpackage.login.LoginEvent
rootpackage.login.LoginLocalEventMap // содержит методы обращения к сервису
rootpackage.login.LoginModel

Теперь после загрузки наше приложение открывает форму авторизации LoginView и после её заполнения отправляет запрос на сервер. В случае успешной аутентификация и авторизации, посылается сообщение основному приложению и закрывается LoginView.

Registration

Возможно, данного пользователя нет в системе и он захочет зарегистрироваться. Для этого мы создаем пакет registration
rootpackage.registration.RegistrationView
rootpackage.registration.RegistrationEvent // события регистрации
rootpackage.registration.RegistrationlEventMap // содержит методы обращения к сервису регистрации
rootpackage.registration.RegistrationModel // данные о регистрации

Теперь пользователь может открыть окно регистрации, заполнить поля. Если все в порядке, информация отправляется на сервер.

В случае удовлетворительного ответа от сервера, RegistrationView закрывается, основное приложение получает соответствующее сообщение. Дальнейшее развитие этих пакетов зависит от сложности процесса регистрации и авторизации, например регистрация может использовать OpenId, капчу, автозаполнение и т.п. Если процессы многообразны, то возможно создать для их обработки отдельную EventMap. Некоторые функции попросятся в собственный модуль. Но сосредоточимся пока на доменах registration и login
картинка

Переход к высокоуровневому домену

Сейчас явно напрашивается желание собрать регистрацию и логи в общий пакет (модуль).
Я придумал наименование accessmanagment.
rootpackage.accessmanagment.AccessManagementModel.as
rootpackage.accessmanagment.AccessManagementLocalEventMap.xml
rootpackage.accessmanagment.AccessManagmentEvent
rootpackage.accessmanagment.login.LoginView
rootpackage.accessmanagment.login.LoginEvent
rootpackage.accessmanagment.login.LoginLocalEventMap // содержит методы обращения к сервису
rootpackage.accessmanagment.login.LoginModel
rootpackage.accessmanagment.registration
rootpackage.accessmanagment.registration.RegistrationView
rootpackage.accessmanagment.registration.RegistrationEvent
rootpackage.accessmanagment.registration.RegistrationlEventMap
rootpackage.accessmanagment.registration.RegistrationModel

Ортогональный домен

Думаю, идея создания пакетов на основании домена понятна, но напрашивается вопрос, что делать, если один и тот же класс необходимо использовать в нескольких модулях?
Для задач ортогональных домену предметной области я обычно завожу папку common на соответствующем уровне иерархии. Например мне необходимо выделить базовый класс для всех mate моделей или общего предка для всех модальных окон:

rootpackage.ApplicationView.mxml
rootpackage.MainDataModel.as
rootpackage.MainEventMap.xml
rootpackage.AdminApplucationEvent.as
defaultpackage.Main.xml
rootpackage.common
rootpackage.common.model.AbstractMateModel.as
rootpackage.common.view.ModalView.as
rootpackage.accessmanagment.*
rootpackage.accessmanagment.login.*
rootpackage.accessmanagment.registration.*

картинка
Для пакета common основным доменом будет именно ортогональная задача. Далее сommon может быть вынесен в самостоятельный проект используемый различными приложениями. Собственно, это и есть его продвижение по иерархии. Если мы выделим common на уровне accessmanagment, он будет использоваться задачами регистрация и аутентификация. Далее он может полностью или частично двигаться вверх в common для всего приложения и еще выше для нескольких приложений. Ну и наконец превратиться в публичный API.

Резюме

Основную идею которую я хотел передать - создание пакетов на основе домена предметной области. Такая техника оправдывает себя в моей практике. Хорошо работает в больших проектах. Для маленьких проектов я бы рекомендовал не создавать пакетов совсем. Зачем два события отделять в отдельный пакет? Как только приложение начнет расти, появятся пакеты предметной области это позволит всегда работать с маленьким приложением.

Ссылки

Всем заинтересовавшимся вопросом рекомендую к ознакомлению видео презентацию Juergen Hoeller, одного из основателей Spring Framework http://www.infoq.com/presentations/code-organization-large-projects и (или) её текстовые пересказы http://mikenereson.blogspot.com/2007/06/spring-on-code-organization-for-large.html,
http://www.kimchy.org/spring-one-code-organization/
Немного странный источник, но идеи примерно те же http://docstore.mik.ua/orelly/oracle/advprog/ch02_01.htm

Постоянная ссылка 2009-08-14 16:51:40, от agahov Email , 6132 слов, Рубрики: Flex, AS3 , 3 комментариев »

3 комментариев

Комментарий от: Racer242 [Посетитель] Email · http://racer242.blogspot.com/
Отличная статья, обожаю эстетствовать с пакетами и классами.
Действительно, такой подход актуален для крупных проектов, но все же, для малых, я бы не советовал отказываться от пакетной структуризации, даже для демок. Ибо, как кто-то сказал, оно ум в порядок приводит :).
Кстати, я наоборот, с появлением в моей практике Mate, перешел на организацию vo/events/business/. И правда, модульность нарушается - разные по смыслу, хотя и однородные классы складируются в один пакет, что не есть хорошо. Но с другой стороны, в этом тоже есть плюсы. Возможно, для крупных проектов, есть смысл делать такие структуры как rootpackage. accessmanagment.vo/events/views, получая что-то типа суб-приложений и сохраняя принципы Mate/Cairngorm?

Кстати, хотел спросить - не встречались проблемы с работой Mate+Flex-модули?

ЗЫ: соверую перед публикацией копипастнуть пост в word, а то перлы типа "предметной обсласти" радуют глаз :)
2009-08-18 @ 10:53
Спасибо за обратную связь.
Действительно, такой подход актуален для крупных проектов, но все же, для малых, я бы не советовал отказываться от пакетной структуризации, даже для демок. Ибо, как кто-то сказал, оно ум в порядок приводит .

Я рекомендовал как раз не структурировать маленький проект формально по типам. И пока он реально соответствует домену, в котором находиться не создавать лишних пакетов. Как только он усложниться пакеты сами напрашиваются.


Кстати, я наоборот, с появлением в моей практике Mate, перешел на организацию vo/events/business/. И правда, модульность нарушается - разные по смыслу, хотя и однородные классы складируются в один пакет, что не есть хорошо. Но с другой стороны, в этом тоже есть плюсы. Возможно, для крупных проектов, есть смысл делать такие структуры как rootpackage. accessmanagment.vo/events/views, получая что-то типа суб-приложений и сохраняя принципы Mate/Cairngorm?

Думаю что если использовать Mate+Cairngorm, наверное нормально создавать пакеты по типам. Сам же Mate, не задает определенной структуры.
Я в своей практике пришел к разбиению по предметной области. Пакет views (events) с моей точки зрения имеет смысл если вы разрабатываете визуальную библиотеку или он находиться с пакете common и используется другими пакетами, на том же уровне иерархии.

Кстати, хотел спросить - не встречались проблемы с работой Mate+Flex-модули?

Мне требуется уточнение какие именно проблемы, у меня есть приложение которое построено именно так, но возможно я что- то упустил. Модуль там использует LocalEventMap. Часть внутренних событий модуля останавливается, что бы их не ловило главное приложение.

2009-08-18 @ 13:12
Комментарий от: Racer242 [Посетитель] · http://racer242.blogspot.com/
> Mate+Flex-модули

Ничего конкретного, просто активно использую модули, но без Mate, и т.к. сталкивался с разного рода проблемами, прощупываю почву. Нет проблем - и отлично :).


2009-08-21 @ 12:41

Оставить комментарий


Ваш email адрес. (Не будет показан на сайте.)

Ваш URL будет показан.
:!: :?: :idea: :) :D :p B) ;) :> :roll: :oops: :| :-/ :( :'( |-| :>> :yes: ;D :P :)) 88| :. :no: XX( :lalala: :crazy: >:XX
(Заменить прерывания строк на <br />)
(Имя, email и сайт)
(Разрешить пользователям посылать вам сообщения (ваш email не отображается).)
3 + 2 + 7 - 1?
antispam test

Вы можете использовать OpenID чтобы предоставить ваше имя, email и url.