вторник, 9 декабря 2008 г.

Проектирование больших приложений в Ext

Вступление

Я решил написать эту статью для тех пользователей Ext2.x которые уже выросли из детских потребностей, создавая одну HTML страницу c простыми скриптами которые создают одно простое окно или форму, для тех кто уже решил что Ext - это путь, и для тех кто борется со слишком большими файлами, трудными для поиска и чувствующих, что их приложениям нужна структура.

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

Все что я хочу сказать, то что этот вариант рабочий, достаточно структурированный, легко разрабатываемый - просто сказать - Он работает!

Что такое Большое приложение?

Если вы сделали Viewport с BorderLayout, таблицой и формой и все это находится в одном файле - это большое приложение, не так ли? Если вы создали десяток окон с таблицами, формами или границами - это большое приложение, да?

У немцев есть отличные слова: Jein - комбинация слов Да и Нет.
Ответ для обоих вариантов - Jein (и да и нет). Когда приложение становится большим? Ответ простой: оно становится большим когда вы чувствуете, что оно большое. Это начинается тогда, когда у вас у самих начинаются проблемы в ориентировании в множестве файлов или вы не можете найти нужный код в одном файле., когда вы уже не понимаете взаимосвязь компонентов и так далее. Я это пишу, но представьте когда у программиста с в 2-3 раза большим опытом появляется это чувство?
Мы может просто установить, что каждое приложение становится большим, когда оно хорошо написано и у нас не вызовет проблем добавиьт в него дополнительные возможности, дописать новый код, новые CSS правила и так далее.
Лучший и безопасный вариант старта нового приложения это чувство : я начинаю большое приложение!

Файлы и директории
Это первое что нам нужно организовать. Всегда существует корневая директория DocumentRoot на Apache или другом HTTP сервере, так что все поддиректории которые я опишу позже расположены относительно нее.
Рекомендуемая структура директорий такова:
./css (optionally link)
./ext (ссылка)
./img (ссылка)
./js
index.html

Ссылка в вышеупомянутой структуре означает мягкую ссылку, указывающую на реальное месторасположение файлов. Это нужно для того, когда вы например, скачаете новую версию Ext в директорию, то просто измените ссылку на нее, без изменений кода, ссылающегося на нее и можете испытать что все работает правильно в новой версии. Если да, можно оставить все как есть, если нет, просто изменить ссылку на прежнюю.

* css содержит все таблицы стилей. Если у вас есть глобальные стили с цветами компании или шрифтами вы можете создать и эту директорию как ссылку.
* ext ссылается на библиотеку Ext JS как было описано выше
* img ссылается на ваши изображения. Также она может иметь поддиректорию с иконками.
* js будет содержать все JavaScript файлы приложения.
* index.html HTML файл, который является стартовой точкой приложения. Вы можете назвать его как захотите и можете добавить другие файлы, например файлы для процесса аутентификации. В любом случает должна быть одна стартовая точка - файл.
* опционально вы можете создать директорию или ссылку на серверную часть приложения (у меня например ./classes). Вы можете называть их как пожелаете, но придерживаться целостности для приложений, которые пишите (./server, ./php хорошие примеры)

index.html

Самое минимальное содержание файла index.html такое

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="./ext/resources/css/ext-all.css">

<link rel="stylesheet" type="text/css" href="./css/application.css">
<script type="text/javascript" src="./ext/adapter/ext/ext-base.js"></script>

<script type="text/javascript" src="./ext/ext-all-debug.js"></script>
<script type="text/javascript" src="./js/application.js"></script>

<title>A Big Application</title>
</head>
<body></body>
</html>


Чтобы я рекомендовал сделать в файле выше, добавить описательный заголовок не только в этот файл но и во все создаваемые файлы. Также маркер End of file имеет значение. Смотрите File Patterns как пример таких заголовков.

js/application.js

Нам нужен файл, где будет располагаться функция onReady, давайте назовем его application.js. Его минимальное содержимое такое:
// vim: sw=4:ts=4:nu:nospell:fdc=4
/**
* An Application
*
* @author Ing. Jozef Sakáloš
* @copyright (c) 2008, by Ing. Jozef Sakáloš
* @date 2. April 2008
* @version $Id$
*
* @license application.js is licensed under the terms of the Open Source
* LGPL 3.0 license. Commercial use is permitted to the extent that the
* code/component(s) do NOT become part of another Open Source or Commercially
* licensed development library or toolkit without explicit permission.
*
* License details: http://www.gnu.org/licenses/lgpl.html
*/

 
/*global Ext, Application */
 
Ext.BLANK_IMAGE_URL = './ext/resources/images/default/s.gif';
Ext.ns('Application');

 
// application main entry point
Ext.onReady(function() {
 
Ext.QuickTips.init();

 
// code here
 
}); // eo function onReady
 
// eof


Ваш заголовок и подвал может изменяться но удостоверьтесь что установили Ext.BLANK_IMAGE_URL на ваш сервер. Это путь на прозрачное изображение 1х1 пикселей которое используется Ext как указатель расположения ихображения, и если он указывает на неверное месторасположение вы можете получить проблемы при отрисовке, такие как потеря изображений в элементах, отсутствие иконок или что-то подобное.
Вам может также понадобится новой глобальной переменной объекта для приложения ( здесь это Application).
В чем вы должны быть уверены то что Ext.onReady это главная начальная точка приложения.

css/application.css

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

Ошибочный путь

Что обычно следует когда мы начинаем создавать что то? Давайте напишем. Итак, мы сидим и начинаем писать:
var vp = new Ext.Viewport({
layout:'border'
,items:[

new Ext.grid.GridPanel({
store:new Ext.data.Store({

proxy:new Ext.data.HttpProxy({ ...


Подождите минутку. С таким подходом у нас будет 10000 строк в нашем application.js очень скоро и это то, чего мы хотим в последнюю очередь. Очевидно, мы пропустили какой-то шаг, как будто мы не могли написать это все сразу в index.html?

Правильный путь: Разбиваем все на части

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

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

Предопределенные классы

Теперь, когда вы проанализировали приложение и определили его компоненты вы можете начать писать. Но как? Самый лучший подход - написать расширение для классов Ext компонент, у которых есть все конфигурационные опции, или они передаются встроенными в конфигурационный объект. Я использую такие предопределенные классы расширения так как они удобнее и более функциональны чем базовые Ext классы, но их главное назначение - это их настройка для своих нужд. Например, чтобы создать таблицу Персонал со специфичной моделью колонок, хранилищем, опциями сортировки, редакторами и тд.
Если у нас такой подход, наше конфигурационное Окно могло мы выглядеть так:
var win = new Ext.Window({
title:'Personnel'
,width:600

,height:400
,items:{xtype:'personnelgrid'}
});
win.show();


Создание предопределенных классов.

(Запомните: Следующая структура может работать не во всех ситуациях, есть исключения)

Давайте обсудим один пример:

Application.PersonnelGrid = Ext.extend(Ext.grid.GridPanel, {
border:false

,initComponent:function() {
Ext.apply(this, {
store:new Ext.data.Store({...})

,columns:[{...}, {...}]
,plugins:[...]

,viewConfig:{forceFit:true}
,tbar:[...]
,bbar:[...]

});
 
Application.PersonnelGrid.superclass.initComponent.apply(this, arguments);
} // eo function initComponent

 
,onRender:function() {
this.store.load();

 
Application.PersonnelGrid.superclass.onRender.apply(this, arguments);
} // eo function onRender

});
 
Ext.reg('personnelgrid', Application.PersonnelGrid);


Что мы здесь делаем? Мы расширяем класс Ext.grid.GridPanel создавая новый класс (расширение) Application.PersonelGrid и мы регистрируем его как новый xtype с именем personnelgrid.
Мы передаем главноей табличной панели все конфигурационные опции необходимые для специфичной таблицы персонала. С этой точки у нас есть новый компонент, строительный блок для нашего приложения, который мы сможем использовать где-либо (окна, регион, отдельно-стоящий) где нам понадобится список персонала. Мы можем создать его так:
var pg = new Application.PersonnelGrid();


или с помощью xtype (для ленивых)
var win = new Ext.Window({
items:{xtype:'personnelgrid'}

,....
});


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

Код выше не должен и не нужно запускать его внутри функции onReady, потому что он ничего не делает с DOM структурой документа; он только создает JavaScript объект. Вот почему он может и должен быть написан в отдельном файле (js/Application.PersonnelGrid.js) и он может и должен быть включен в заголовок index.html файла как:
<script type="text/javascript" src="./js/Application.PersonnelGrid.js></script>

Шаг за шагом мы продолжаем создавать наши предопределенные классы, складывать их в /js директорию, включать их в index.html и строить наше приложение из них, как пазл, собирая из кусочков.
Выглядит хорошо, так?

В любом случае, есть еще что добавить.

Межкомпонентное взаимодействие

Представьте что нам нужен экран с каймой со списком ссылок на западе и таб-панелью в центре. Нажатие ссылки в списке должно создавать новую закладку в центре. Теперь, куда мы должны положить логику этого события и процедуру обработки? На запад или в центр?
Ни в одно из них. Почему? Если у нас есть предопределенные классы которые создают и показывают ссылки на западе (слева) и мы положили всю логику в них, то они больше не могут существовать без центрального региона. Мы можем просто не сможем их использовать без центра, так как не сможем создавать закладки в центре.
Если положить логику в центр - результат будет тот же: центр не сможет существовать без запада.
Единственный компонент, который будет независим в этом случае это их контейнер - border layout, и это единственно правильное место куда следует поместить межкомпонентную связь.
Что мы затем должны сделать? Контейнер (с border layout) должен прослушивать все события с запада и должен создавать закладки в центре как ответ на эти клики. Пример такого межкомпонентного взаимодействия можно найти по ссылке http://examples.extjs.eu/?ex=compcomm

Система представлений

По мере создания приложения число файлов растет, число включений JavaScript файлов тоже (у меня в одном приложении включается около 80 файлов и их количество каждый день растет). Это може уменьшить производительность и продуктивность системы.
Лучший путь решения - это слияние всех javascript файлов и создание одного большого файла, и минимизирование его с помощью JavaScript или других инструментов сжатия. Также вам не понадобится отладка библиотеки Ext для готовой системы.

На продуктивной системе нам надо включить:

  • ext-all.js

  • app-all.js and

  • application.js


Для дополнительной информации о минимизации исходных кодов и создания комбинированных файлов у нас есть другой учебник, который раскрывает эту тему более подробно (http://extjs.com/learn/Tutorial:Building_Ext_From_Source).

Заключение
Вот и все почти... Есть специфичные техники для специальных Ext классов, есть множество других ноу-хау сервер-клиентских приложений, но выше изложена практически основная концепция.
Удачного кодинга!

Источник: http://extjs.com/learn/Tutorial:Writing_a_Big_Application_in_Ext

Комментариев нет:

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