Close

15.10.2015

АРхитектура и История web интерфейсов (GUI)

Сначала хотел рассказать Вам историю веб интерфейсов для браузера.  Как менялись технологии за последние 20 лет и какие тренды актуальны сейчас?

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

Текст предполагал сравнительный анализ фреймворков, их свойств.

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

А ещё мы будем выявлять полезные и поганые качества по ходу расказа, чтобы сформулировать ответ на вопрос «как нам сделать веб фреймворк будущего?»

изложение с иллюстрациями и даже картинками   😉 

Web-приложения первого поколения

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

ria-architecture-1.png

Будучи странично-ориентированным, каждое действие приложения обычно вкладывалось в свой собственный сценарий веб-страницы. Каждый сценарий был как отдельная транзакция, которая содержала логику приложения, и генерировался графический интерфейс для отправки обратно в браузер после запуска логики приложения. Вот иллюстрация природы веб-приложений первого поколения:

ria-architecture-2.png

Графический интерфейс был довольно «тупым» . Браузер показал страницу . Когда пользователь нажал что-то на странице , браузер был обычно перенаправлен на новую страницу (сценарий) . Технологии веб-страницы первого поколения включают сервлеты (Java ), JSP ( JavaServer Pages ) , ASP, PHP и CGI скрипты в Perl и т.д. Любой, кто работал с веб-приложения первого поколения, знает , что в таких проектах был беспорядок. Логика графического интерфейса и логика приложения чередовалась , было трудно найти любую из них , когда нужно было внести изменения в графический интерфейс или логики приложения. Повторное использование кода было низким, так как код растягивался на большое количество сценариев веб-страницы . Состояние GUI (например, нажата кнопка) должно было быть сохранено на нескольких страницах, оно сохранялось либо в данных сессии на сервере , или должно было быть отправлено вместе с каждой страницей и передано обратно в браузер снова. Если Вы хотели изменить язык программирования веб-страницы скриптов ( как из PHP в JavaServer Pages (JSP )) , то часто требовалось полностью переписать веб-приложения. Это был кошмар.

Web приложения второго поколения

В приложениях второго поколения разработчики нашли способы для отделения логики GUI от логики приложения на сервере. Веб-приложения также стали более объектно-ориентированный, чем они были, когда код растягивался на несколько страниц. Часто скрипты веб-страницы были использованы для логики GUI, а реальные классы и объекты были использованы для логики приложения. Здесь показана схема, иллюстрирующая конструкцию веб-приложений второго поколения:

ria-architecture-3.png

Фреймворки (каркасы) были разработаны , чтобы помочь сделать веб-приложения второго поколения проще в разработке . Примерами таких структур являются ASP.NET ( . NET ) , Struts + Struts 2 (Java) , Spring MVC (Java) , JSF ( JavaServer Faces ) , Wicket (Java) Tapestry (Java) и многие другие. В сообществе Java появилось два типа фреймворков: Model 2 и компонентные. Я не буду вдаваться в подробности здесь, потому что, на мой взгляд, обе конструкции являются устаревшими. Веб-приложения второго поколения было легче разрабатывать , чем веб-приложения первого поколения, но они все еще имели некоторые проблемы. Несмотря на лучшее разделение GUI и логики приложения, эти две области по-прежнему часто были переплетены друг с другом. Кроме того, поскольку логика GUI написана на том же языке , что и логика приложения, изменения языка программирования снова требовало  переписывать все приложение. Из-за пределов технологий веб-приложений во втором поколении  GUI  зачастую был более примитивным, чем люди привыкли видеть в настольных приложениях. Таким образом, даже если технологии веб-приложений второго поколения сделали шаг вперед, они все еще доставляли головную боль при работе с ними.

RIA Web Applications

RIA (Rich Internet Applications) веб-приложения третьего поколения. RIA веб-приложения стали в первую очередь известны тем, что этот пользовательский интерфейс выглядит намного ближе к настольным приложениям. Для получения этих, более сложных, пользовательских интерфейсов, технологии RIA обычно выполняются в браузере, используя, например,  AJAX, Flash, JavaFX или Silverlight. Часто ошибочно думают, что RIA напрямую связано с использованием JS библиотек, но, работая на одной только стороне браузера, проблема высокой интерактивности не может быть решена. Вот схема, иллюстрирующая RIA архитектуру приложений веб и дизайн:

ria-architecture-4.png

подробнее:

ria-architecture-5.png

Есть, конечно, некоторые негативные последствия технологии RIA. Полное разделение логики GUI и логики приложения иногда означает, что логика графического интерфейса реализована с использованием другого языка программирования. Ваша логика GUI может быть реализована в JavaScript, ActionScript (Flash) или Dart, а логика приложения в Java, C # или PHP. Разработчики Java могут использовать Google Web Toolkit (GWT) для программирования JavaScript — создавать графические интерфейсы с использованием Java. Новые технологии RIA означают, что команда разработчиков должна освоить больше технологий. Это, конечно, минус. Но я думаю, Вы можете жить с этим, учитывая все преимущества RIA веб-приложений.

RIA Technologies

Вот список наиболее прославленных RIA технологий:

  • HTML5 + CSS3 + JavaScript + JavaScript frameworks
    • jQuery
    • jQuery Mobile
    • AngularJS
    • Sencha EXT-JS
    • SmartClient
    • D3
    • Dart
  • GWT (Google Web Toolkit)
  • JavaFX
  • Flex (Flash)
  • Silverlight (now unsupported)

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

The GUI

wikipedia GUI (англ. Graphical user interface, GUI) — разновидность пользовательского интерфейса, в котором элементы интерфейса (меню, кнопки, значки, списки и т. п.), представленные пользователю на дисплее, исполнены в виде графических изображений.

Нужно решить сверхзадачу: «создать GUI для согревания души, создать приветливую систему для разработчиков и web дизайнеров.»

Я пробовал многие системы и утверждаю:

сегодня использование «любого» GUI web фреймворка — это смерть от 1000 порезов.

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

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

Чтобы разобраться с причинами изменний в прочих фреймворках, нужно понять, какие из требований разумно вообще применять к ним. Я бы отметил, что система должна быть:

  • удобной
  • быстрой
  • надежной
  • с защитой свободы выбора
  • безопасной
  • позволять свободу проектирования
  • автоматизированной

И , очевидно — это не просто сделать одновременно, поэтому мы наблюдаем столько различных фреймворков.

Фреймворки, которые я сравнивал и изучал

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

  • WICKET
  • php (как средство разработки для web)
  • YUI
  • tapestry
  • GWT
  • (C)Click
  • Spring MVC & WebFlow
  • Fx
  • ExtJS
  • jQuery
  • dojo
  • Grails
  • Vaadin
  • RoR = Ruby on Rails
  • JSF
  • ICEFaces
  • OpenFaces
  • RichFaces
  • PrimeFaces
  • SmartClient Ajax GUI System
  • Elipse Rich Ajax Platform
  • ZK
  • Struts 2

Все они меня сильно не устроили, ведь я-то хочу их обойти и сделать как можно более  качественный инструмент. Конечно, сначала  я пробовал что-то выбрать для себя. Как я выбирал? А вот как:  взял критерии и, если фреймворк не соответствоал,  его применение мной переставало рассматриваться. Так получилось, что некоторые фреймворки «вылетали» по несколько раз, я им давал шанс снова и снова, но увы.

Критерии, которым должна соответствовать web-платформа

  • надежная платформа на сервере
  • широкая возможность работы с фрейворком из разных языков
  • чистый web client
  • сервер-центрированная архитектура VS клиент-центрированная — выбор не однозначен
  • сама платформа не должна строиться на динамическом языке
  • одностраничность. Нужен настоящий одностраничный интерфейс- это моя точка зрения. Чуть ниже я объясню, почему так считаю.
  • не форсированный web
  • шаблоны должны базироваться на чистом HTML без всякой логики
  • PUSH шаблоны
  • простота создания своих AJAX компонентов
  • при изучении не засыпать
  • необязательность XML и декларативного программирования
  • одностраничный интерфейс в множестве мобильных браузеров
  • совместимость с SPI SEO

Далее рассмотрим, что же имеется ввиду под этими пунктами.

Надежная серверная платформа

Я ругаю JVM за то, что это «VM одного процесса».

Но она хороша. Например, все пользовательские сессии легко распределить по таким процессам. В корпоративном сегменте многие решения «скатываются в Java / Jvm» и для этого масса оснований.

ООП модель для GUI часто сложна, а Java платформа одновременно:

  • очень крепка
  • очень безопасна
  • быстра
  • и удобна для разработки

Java — язык со статической типизацией. И всем очень нравятся инструменты рефракторинга NetBeans или Eclipse, а я люблю JetBrains.

В проектах с 1000 и более классами очень трудно приходится без FindUsages и без Ctrl-R — это бесспорно.

 

свободная возможность работы с GUI фрейворком из разных языков

Вооот!

Я обещал обосновать, почему сама система должна быть написана не на днамическом языке … и т.д. — позже, но это наши требования, как разработчика системы.

Мы же не должны ограничивать пользователей языком, ибо

границы моего языка - границы моего мира

Современное «Облако» — рабочая лошадка. А ваш компьютер — креативная станция. Пользователь должен иметь возможность использовать любой удобный язык на любой удобной машине, чтобы добавлять функционал в облако и чтобы отлаживать так , как ему удобно.

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

По возможности,  нельзя не учитывать важность разных языков для юзера фреймворка.

Чистый web клиент

Flash/Flex (и другие RIA плагины…)

  • будут заменены HTML5 в скором будущем
  • HTML/CSS/JS более открыты и гибки, чем Flash/Flex
  • информационным системам не требуется максимально пестрить всякой графикой.
  • если нужно, то html5 это умеет сам
  • SEO совместимость — это не просто для бинарных встраиваемых объектов и контента в них.

Поэтому, чистый_web_client — это хорошо

 

клиент центрирование VS сервер центрирование

Что Вы предпочтете: «Кодирование на клиенте (браузере) VS Кодирование на сервере»?

Во-первых, кодирование на JavaScript:

  • неуправляемое, когда кода много
  • трудно-организуемое
  • трудно отлаживать и тестировать
  • тренд на генерацию криптованного кода
  • трудно разделить код в архиве от кода для разработки, сжатие, упаковка,…
  • медленный
  • «невозможно» сделать одностраничное приложение

Во-вторых, Вы реально хотите, чтобы у вас был такой код:

function printPersonCardT2(){
  var dlg = $ws.single.ControlStorage.getByName('СписокСкановНаКадровыхДокументах').getTopParent();
  if(!dlg.validate())
    return;
  var
    record_obj = dlg.getRecord().cloneRecord(),
    id_org = record_obj.get("Сотрудник.Контрагент");
  //id_org = $ws.single.OurOrganization.getCurrentOurOrg();
  var inf = new $ws.proto.BLObject('Сотрудник');
  inf.call('ТрудовойДоговор',
    {
        "ИдСотрудник" : record_obj.get('Сотрудник.@Сотрудник')
    }, $ws.proto.BLObject.RETURN_TYPE_RECORD).addCallback(function (res){
        //подставляем в рекорд трудовой договор номер дата
        record_obj.addColumn('ТрудовойДоговор.Номер', $ws.proto.Record.FIELD_TYPE_STRING);
        record_obj.addColumn('ТрудовойДоговор.Дата', $ws.proto.Record.FIELD_TYPE_STRING);
        record_obj.set('ТрудовойДоговор.Номер', res.get('Номер'));
        record_obj.set('ТрудовойДоговор.Дата', "");
        if(res.get('Дата') !== "" && res.get('Дата') !== " " && res.get('Дата') !== null){
        var date = new Date(res.get('Дата')),
            date_dogovor = $ws.render.defaultColumn.timestamp(date);
        record_obj.set('ТрудовойДоговор.Дата', date_dogovor);
        }
        var def = getInfoOurOrgForPrintForm(id_org, record_obj),
        new_def = new $ws.proto.Deferred;
        new_def.dependOn(def);
        new_def.addCallback(function (){
        var names = [
        "ЧастноеЛицо.НомерСтраховогоСвидетельства", "ЧастноеЛицо.ПолЧеловека",
        "ЧастноеЛицоРасширение.СемПол", "Сотрудник.Принят", "ЧастноеЛицо.ДокументСерия",
        "ЧастноеЛицо.ДокументНомер", "ЧастноеЛицо.ДокументДатаВыдачи", "ЧастноеЛицо.ДокументКемВыдан",
        "ДолжностьСотрудника.ХарактерРаботы", "ДолжностьСотрудника.ВидРаботы", "АдресФактическогоПроживания",
        "АдресФактическогоПроживанияИндекс", "АдресПрописки", "АдресПропискиИндекс",
        "ЧастноеЛицо.Образование", "ЧастноеЛицо.ПослевузовскоеОбразование", "ПослевузовскоеОбразование.Название",
        "ПослевузовскоеОбразование.ДокументНомерСерияДатаВыдачи", "ПослевузовскоеОбразование.НаправлениеСпециальность",
        "ПослевузовскоеОбразование.ГодОкончания", "ОбщийСтаж.Дней", "ОбщийСтаж.Месяцев", "ОбщийСтаж.Лет", "НепрерывныйСтаж.Дней",
        "НепрерывныйСтаж.Месяцев", "НепрерывныйСтаж.Лет", "СтажДающийПраво.Дней", "СтажДающийПраво.Месяцев",
        "СтажДающийПраво.Лет", "ЧастноеЛицо.ДатаРегистрацииПоМестуЖительства", "ВоинскийУчет.КатегорияЗапаса", "ВоинскийУчет.ВоинскоеЗвание",
        "ВоинскийУчет.Состав", "ВоинскийУчет.КодВУС", "ВоинскийУчет.КатегорияГодности",
        "ВоинскийУчет.НаименованиеВоинскогоКомиссариата", "ВоинскийУчет.СостоитНаВоинскомУчетОбщем",
        "ВоинскийУчет.СостоитНаВоинскомУчетСпециальном", "ВоинскийУчет.ОтметкаОСнятииСУчета",
        "РаботникКадровойСлужбы.Должность", "РаботникКадровойСлужбы.ФИО", "ТекущаяДатаСоставления"];
        for(var i in names){
        if(!record_obj.hasColumn(names[i])){
            record_obj.addColumn(names[i], $ws.proto.Record.FIELD_TYPE_STRING);
            record_obj.set(names[i], null);
        }
        else
            if(record_obj.hasColumn(names[i]) && record_obj.get(names[i]) == undefined){
            record_obj.set(names[i], null);
            }
        MakeNullStrEmpty(record_obj, names[i]);
        }
        var record_fornull = record_obj.toObject();
        for(var j in record_fornull)
        MakeNullStrEmpty(record_obj, j);
        var upd_datecome, day, month, year, sex_person_id = record_obj.get("ЧастноеЛицо.Пол")._curValIndex,
            sex = record_obj.get("ЧастноеЛицо.Пол")._availableValues[sex_person_id],
            family_info = (record_obj.hasColumn("ЧастноеЛицоРасширение.СемейноеПоложение") ? record_obj.get("ЧастноеЛицоРасширение.СемейноеПоложение")._curValIndex : ""),
            family = (record_obj.hasColumn("ЧастноеЛицоРасширение.СемейноеПоложение") ? record_obj.get("ЧастноеЛицоРасширение.СемейноеПоложение")._availableValues[family_info] : "");
        upd_datecome = new Date();
        day = upd_datecome.getDate();
        if(day < 10) day = '0' + day;
        month = upd_datecome.getMonth() + 1;
        year = upd_datecome.getFullYear();
        record_obj.set("ТекущаяДатаСоставления", day + "." + month + "." + year);
        record_obj.set("ЧастноеЛицо.ПолЧеловека", sex.toLowerCase());
        record_obj.set("ЧастноеЛицоРасширение.СемПол", (family !== null ? family.toLowerCase() : ""));
        // формирование адреса и индекса для адреса фактич и проживания
        var getAddressObject = function (str_address){
        var address_obj = new $ws.proto.Deferred();
        address_obj.dependOn($ws.core.attachInstance("КЛАДР@kladr:Kladr").addCallback(function (addr){
            return addr.parseGO(str_address).addCallback(function (parsego_address){
            //тут возьмем адрес целиком, чтобы его не формировать
            return addr.parse(str_address).addCallback(function (parse_address){
            //тут сформируем все данные по дому и квартире
            var str_house = '';
            str_house = (parsego_address['Дом'] !== '' ? parsego_address['ДомСокращение'] + '.' + parsego_address['Дом'] : '')
                + (parsego_address['Корпус'] !== '' ? ',' : '') + (parsego_address['Корпус'] !== '' ? ' ' + parsego_address['КорпусСокращение'] + '.' + parsego_address['Корпус'] : '')
                + (parsego_address['Литера'] !== '' ? ',' : '') + (parsego_address['Литера'] !== '' ? ' ' + parsego_address['ЛитераСокращение'] + '.' + parsego_address['Литера'] : '')
                + (parsego_address['Строение'] !== '' ? ',' : '') + (parsego_address['Строение'] !== '' ? ' ' + parsego_address['СтроениеСокращение'] + '.' + parsego_address['Строение'] : '')
                + (parsego_address['Квартира'] !== '' ? ',' : '') + (parsego_address['Квартира'] !== '' ? ' ' + parsego_address['КвартираСокращение'] + '.' + parsego_address['Квартира'] : '');
            var result_string_house = {};
            result_string_house["Адрес"] = parse_address['addr'] + (str_house !== '' ? ', ' + str_house : '');
            result_string_house["Индекс"] = parsego_address['Индекс'];
            return result_string_house;
            });
            });
        }));
        return address_obj;
        };
        if($ws.single.ControlStorage.containsByName("КнопкаСтаж")){
        var stash = $ws.single.ControlStorage.getByName("КнопкаСтаж").getCaption().split(" ");
        if(stash){
            record_obj.set("ОбщийСтаж.Лет", stash[0]);
            record_obj.set("ОбщийСтаж.Месяцев", stash[2]);
            record_obj.set("ОбщийСтаж.Дней", stash[4]);
        }
        }
        else{
        var date_boln = (record_obj.get("ДолжностьСотрудника.ДатаПринятия") !== ""
            ? record_obj.get("ДолжностьСотрудника.ДатаПринятия").toSQL()
            : (new Date()).toSQL());
        new $ws.proto.BLObject("ТрудоваяДеятельность").call("Стаж",
            { 'ИдСотрудника' : record_obj.get("Сотрудник.@Сотрудник"), 'ДатаНачалаБольничного' : date_boln },
            $ws.proto.BLObject.RETURN_TYPE_RECORD
        ).addCallback(function (rec){
            if(rec && (rec.get("СтажНаНачало"))){

                record_obj.set("ОбщийСтаж.Лет", rec.get("КоличествоЛет"));
                record_obj.set("ОбщийСтаж.Месяцев", rec.get("КоличествоМесяцев"));
                record_obj.set("ОбщийСтаж.Дней", rec.get("КоличествоДней"));

            }
            });
        }
        var person_rec;
        if(record_obj.get("ЧастноеЛицо.@Лицо") !== null && record_obj.get("ЧастноеЛицо.@Лицо") !== ""){
        new $ws.proto.BLObject("ДолжностьСотрудника").query("СписокДолжностейДляВкладкиДолжность", {
            "ИД_Контрагент" : record_obj.get("Сотрудник.Контрагент"), "ИД_ЧастноеЛицо" : record_obj.get("ЧастноеЛицо.@Лицо")
        }).addCallback(function (rec){
            if(rec){
                var
                    rec_set_pers = rec,
                    rec_pers = undefined;
                rec_set_pers.rewind();
                rec_pers = rec_set_pers.next();
                while(rec_pers){
                var reason = rec_pers.get("Признак");
                if(reason.get("Основная должность") === true && rec_pers.get("ДатаСнятия") === null){
                    record_obj.set("ДолжностьСотрудника.ВидРаботы", "основная");
                }
                else
                    if(reason.get("Почасовая оплата") === true){
                    record_obj.set("ДолжностьСотрудника.ВидРаботы", "по совместительству");
                    }
                rec_pers = rec_set_pers.next();
                }
                //сортируем по дате по возрастанию
                rec.setSorting([
                ["ДатаПринятия", false]
                ]);
                person_rec = rec;
                //получение даты увольнения
                new $ws.proto.BLObject("ПриказНаУвольнение").query("Список", {
                "Контрагент" : record_obj.get("Сотрудник.Контрагент"), "ИД_ЧастноеЛицо" : record_obj.get("ЧастноеЛицо.@Лицо")
                }).addCallback(function (fired_person){
                    var
                        rec_set_fired = fired_person,
                        rec_fired = undefined,
                        fired = new $ws.proto.Record();
                    rec_set_fired.rewind();
                    rec_fired = rec_set_fired.next();
                    while(rec_fired){
                    //берем самую первую запись об увольнении
                    fired = rec_fired;
                    break;
                    }
                    //состав семьи
                    new $ws.proto.BLObject("ЧленСемьи").query("СписокЧленовСемьиДляВкладкиДолжность", {
                    "ЧастноеЛицо" : record_obj.get("ЧастноеЛицо.@Лицо")
                    }).addCallback(function (family_rec){
                        var
                            rec_set = family_rec,
                            rec = undefined;
                        rec_set.rewind();
                        rec = rec_set.next();
                        while(rec){
                        var type_id = rec.get("Тип")._curValIndex,
                            type_name = rec.get("Тип")._availableValues[type_id];
                        rec.addColumn("ТипРодства", $ws.proto.Record.FIELD_TYPE_STRING);
                        rec.set("ТипРодства", type_name);
                        rec = rec_set.next();
                        }
                        new $ws.proto.BLObject("Образование").query("СписокДляВкладкиДолжность", {
                        "ЧастноеЛицо" : record_obj.get("ЧастноеЛицо.@Лицо")
                        }).addCallback(function (education){
                            if(education.getRecordCount() !== 0){
                                var educ_set = education,
                                educ_rec = undefined,
                                type_educ;
                                educ_set.rewind();
                                educ_rec = educ_set.next();
                                type_educ = educ_rec.get("ВидОбразования");
                                while(educ_rec){
                                if(educ_rec.get("ВидОбразования") < type_educ)
                                type_educ = educ_rec.get("ВидОбразования");
                                educ_rec = educ_set.next();
                                }
                                record_obj.set("ЧастноеЛицо.Образование", type_educ);
                                education.setSorting([
                                ["ВидОбразования", false]
                                ]);
                            }
                            new $ws.proto.BLObject("ИностранныеЯзыки").query("СписокИностранныхЯзыковЧастногоЛица", {
                                "ЧастноеЛицо" : record_obj.get("ЧастноеЛицо.@Лицо")
                            }).addCallback(function (lang){
                                if(lang.getRecordCount() !== 0){
                                    var
                                    rec_set_lang = lang,
                                    rec_lang = undefined;
                                    rec_set_lang.rewind();
                                    rec_lang = rec_set_lang.next();
                                    while(rec_lang){
                                    var type_id = rec_lang.get("Уровень")._curValIndex,
                                        type_name = rec_lang.get("Уровень")._availableValues[type_id];
                                    rec_lang.addColumn("УровеньЗнания", $ws.proto.Record.FIELD_TYPE_STRING);
                                    rec_lang.set("УровеньЗнания", type_name);
                                    rec_lang = rec_set_lang.next();
                                    }
                                }
                                //формирование адреса прописки и проживания

                                getAddressObject(record_obj.get("ЧастноеЛицо.АдресПрописки")).addCallback(function (addressObject){
                                    //адрес прописки вставим в рекорд
                                    if(addressObject["Адрес"] !== "null"){
                                    record_obj.set("АдресПрописки", addressObject["Адрес"]);
                                    if(addressObject["Индекс"] !== null)
                                    record_obj.set("АдресПропискиИндекс", addressObject["Индекс"]);
                                    }

                                    //адрес фактич проживания
                                    getAddressObject(record_obj.get("ЧастноеЛицо.АдресФакт")).addCallback(function (addressObject){
                                    if(addressObject["Адрес"] !== "null"){
                                    record_obj.set("АдресФактическогоПроживания", addressObject["Адрес"]);
                                    if(addressObject["Индекс"] !== null)
                                        record_obj.set("АдресФактическогоПроживанияИндекс", addressObject["Индекс"]);

                                    }

                                    MakeAllFieldsForCardT2(record_obj, person_rec, family_rec, lang, education, fired);
                                    });
                                });
                                });
                            });
                        });
                    });
            }
            });
        }
        else{
        person_rec = new $ws.proto.Record();
        MakeAllFieldsForCardT2(record_obj, null, null);
        }
        //  }
        });
    });
}

????

В-третьих,  рассмотрим  миф , что  RIA = JS Library.

RIA — красивый веб, одностраничный интерфейс, с движением и изменением прозрачности, но, если разобраться:

  • Красивый web

    Это хороший дизайн HTML, CSS, картики (ничего общего с JS)

  • Одностраничный интерфейс

    частичные изменения на странице (одним клиент-центрированием этого не достигнуть)

  • Движение, изменение прозрачности

    игры с атрибутами стилей и таймерами: только часть из JS библиотек тут используема. Сейчас есть CCS3, animation…

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

Кодирование на JavaScript ?

НЕТ, СПАСИБО!

GWT — технология от Gooogle, может она дать что-то полезное ?
  • Позволяет делать JavaScript из Java
  • GWT компилирует Java в JavaScript и посылает его клиенту
  • Визуальная логика и некоторая бизнес логика исполняется только в клиенте
  • Решает проблему кодирования на JS
  • НО МНОГО ПРОБЛЕМ ОСТАЕТСЯ…
Проблемы:
  • Визуальный дизайн — это программа или это делается дизайнерами через специальные IDE

    веб-дизайнерами

  • Компоненты «Черные ящики»

    Большинство настраивается только через CSS Шифрованный JS получаем на выходе, отладка возможна только на Java

  • Параноидальный сервер

    нет доверия клиенту (повсеместно), дублируются проверки и везде валидация

  • Клиент-сервер обычно общаются через GWT-RPC
  • Дублируются управления данными и на сервере, и на клиенте
  • «SOFEA»: утопический подход

    вечный бой о том, что с каждой стороны. SOFEA (Service-Oriented Front-End Architecture), read this: Life above the Service Tier and SOFEA and SOUI — There is a Difference, After All

Сервер-центрированный подход — иная альтернатива

Часто корпоративные клиенты исповедуют именно этот вариант. Если Вы хотите работать в БОЛЬШОЙ компании, где постоянно идут сборки, релизы, «дымят трубы» и т.д. — это ваш вариант, это просто надежней, но Это существенно более трудоемко.

В сервер-ориентированном подходе бизнес логика и клиент логика обе выполняются на сервере.

  • сервер генерирует разметку и / или JavaScript

    не требуется JavaScript программирование (пока не вы разрабатываете компоненты)

  • данные и визуальные эффекты совмещены
  • безопасней
  • большая свобода разработки веб дизайна (шаблоны, хотя они часто выглядят как костыли — часто это работает и экономит время)
  • легче оптимизировать движок (если есть знатоки)
  • как правило, жизнь на сервере более комфортна

Динамические языки как средство разработки платформы

Рассмотрим недостатки такого подхода и его привлекательные стороны.

  • Внутренне очень продуктивен
  • Но проблемы приходят, когда:

    исходный код велик (более 1000 классов? ), несколько сущностей в одном коде, а  IDE не может сильно помочь

  • МЕЕЕДЛЕННЫЕ
  • Вы реально можете жить без «Find Usages» из NetBeans ?
  • Можете ли вы жить без инструментов рефакторинга ?

Подумайте 10 раз: если Вы тим лид команды и сроки горят,а вы не фига не можете понять, откуда беда,  и уже неделю в отладке видите чудеса — надо оно вам ?

С динамикой  вы обязательно на это нарветесь. Подумайте 10 раз.

Статические языки — наоборот «не динамический» вариант

  • Компилятор даст нам качественный и быстрый код
  • Компилятор- это ваш друг
  • Инструменты, как «FindUsages» и «Refactor», позволяют управлять тысячами классов
  • Программист знает, как изменения скажутся на любой части кода

Возможные типовые проблемы:

  • неверно воспользовались инструметом и мозгом и использовали динамику.
  • самоуверенность разработчиков, которые уже не работают в команде
  • использовали много «магии», «рефлекшена», набрали «технический долг»…

одностраничный интерфейс

SPI — Single Page Interface

  • При одностраничном интерфейсе приложение работает в одной странице (без перезагрузки)

    используя AJAX, мы получаем новую разметку и обновления частей

  • Событийная модель — только частичные изменения проектируются и кодируются

    также, как и в десктопных программах

  • Больше не требуется Назад/Вперед/Обновить и повторной отправки данных форм

    больше не нужен «post-redirect», кнопки назад и вперед могут опционально работать в таких приложениях и это происходит управляемо

  • Не надо больше ненужного кеширования GET
  • Не надо больше надоедливого автозаполнения форм

    измененные данные предоставляются сервером при перезагрузке страницы

  • Больше не надо глупой полной перерисовки страницы, когда меняется часть содержимого

    во время этого часто все мигает и появляется прокрутка, маленькая производительность

  • Больше не надо includes в incudes в includes

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

  • Нет больше прямого доступа к внутренностям страницы
  • Нет больше проблемы, когда один пользователь открыл две страницы

    страницы одностраничного приложения не расшаривают состояние по умолчанию,  жизнь сессии НЕ дольше,чем хранение временных данных

  • Не надо больше проблем с модальными окнами

    браузер не любит их (это хак), в SPI Вы можете такие окна симулировать

  • Конечный пользователь получит бОльшую производительность
  • Факт: ни одна десктопная программа не разбита на страницы (многостраничная)

    Нет, «мастер» -это просто одиночное модальное окно, находится он всегда в том же фрейме (=странице)

  • Одностраничный подход — НЕ НОВ.

    масса исследований в области построения интерфейсов продвигают именно его.

не форсированный web

Инструменты, подобные EclipseRAP и AjaxSwing, предлагают интересный способ запуска дескторного приложения сразу в web. Опа!

В результате получим — «форсированное» web приложение

Почему эта идея не может стать основой для лучшей в мире онлайн-системы, думаю,  объяснять не нужно…

шаблоны должны базироваться на чистом HTML без всякой логики

  • Распределим роли между программистом и дизайнером:
    • Две независимых роли: визуальный дизайн и программирование логики (визуально и бизнес логики)
    • Повторное использование визуальных дизайнов (визуальные шаблоны проектирования)
    • Повторное использование в логике => ООП и паттерны

      Можем ли мы быть полностью независимы от визуального дизайна ?

  • Полный контроль разметки (верстки) «Живая верстка»

Вкус JSF …. НЕТ!

Вкус JSF - НЕТ

  • Компоненты — черные ящики:
    • нет визуальной эстетики
    • трудно изменить «is what you get»
  • Смешаны визуальный дизайн и логика (много Java привязок и спец выражений)
    • масса отображения в Java — риск безопасности (security hole)
  • Нужны специальные визуальные редакторы (=ПЛОХО)

ZK ? ….. NEITHER!

  • То же, что и JFS

ZK ? - NO

«Я не думаю, что UI-дизайнер будет прилежно изучать способы, как спортировать его сайт в ZUL файл, он хочет HTML + CSS»

Vaadin ? Вообще НЕТ шаблонизации!

Здесь визуальный дизайн полностью ПРОГРАММНЫЙ

Vaadin-no

Может WICKET спасет ?

  • Написано у них: «Wicket does not mix markup with Java code and adds no special syntax to your markup files»
    • Но посмотрите на AJAX «Tree» и «TreeTable», например.

      Где древовидная разметка ? — Да это же черный ящик! wicket-no

PUSH шаблоны

  • В PUSH шаблонах разметка вставляется в визуальную страницу внешним кодом.
    • Мы можем не из клиента контролировать весь цикл происходящего, начало и конец транзакций итд…
    • Повторное использование визуальных элементов и ООП
    • IoC|DI не навязывается, опционально.
  • Например, в Wicked фаза загрузки без AJAX
    • Но Wicked полностью отбрасывается по другим причинам.

Для одностраничного интерфейса это очень важно.

Для веб приложения, у которого может меняться страница и разметка много раз в одном окне, это необходимо — обязательно настанет время и вы просто не сможете без этого жить.

Простота создания своих AJAX компонентов

  • Вопрос «красиво, но сможем ли мы это сделать ?»
  • Минимум JS или совсем без него
  • Новая разметка — это разметка, определяемая как разметка (сорт шаблона)
    • Нет JavaScript
    • Мы можем решать, какие события шлет элемент
    • Обработка событий на сервере: сервер может вставлять/изменять/удалять элементы нашей разметки
Примеры сложности
JSF до 2.0
  • Тонны «хаков»
  • Управление разметкой с клиентским JavaScript
    • имеется несколько ссылок, что это плохо.
JSF после 2.0
ZK
Vaadin
  • Освоить их мануал -это не простая задача, выдержка из мануала, там прямо написано, что это не просто:

    «Creation of new wifgets involves a number of rather intricate tasks» http://vaadin.com/book/-/page/gwt.html

  • Новые GWT компоненты должны быть разработаны: одни для сервера, другие для клиент/сервера, компонент для координации клиента и сервера, для транспорта данных и несколько регистраторов.
  • Положительный момент — управление разметкой базируется на Java, но все еще оно не доступно дизайнерам, а доступно только программистам.

при изучении не засыпать!

Я попробовал много фреймворков и этот пункт — крик души.

  • Фреймворк должен давать простое API и стиль разработки
  • Должна быть возможность в короткое время создать нормальное одностраничное приложение
посмотрите детально
  • Все фреймворки имеют длинный список готовых компонентов
    • Но они скрывают базовые компоненты, разработка своих компонентов очень громоздкая задача
  • Вам потребуется свой тег и Custom API для создания простой кнопки или текcтового блока
    • Сотни собственных тегов включают базовый функционал
    • Веб знания здесь идут отдельно и совсем даже не пригождаются!

необязательность XML и декларативного программирования — это хорошо

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

Но, прошло время, я много думал, и все же отказываюсь от любви к XML и того вида декларативности, который мы там применяли (там было некое подобие XAML).

XML конфигурации и декларативное программирование
  • трудности повторного использования, не очень близко к ООП
  • владеющие подобными инструментами часто становятся «врагами» разработчиков прикладных решений
  • трудно отлаживать и находить ошибки во время исполнения
  • жесткое отношение в отношении необходимых альтернатив
  • очень жесткая борьба с кучей кастомных элементов
  • обычно огромные архивы связанных компонент — с ними сложно работать
примеры неудачного решения
JSF ? ZK?

Все пронизано XML и кастомные теги тоже (вид декларативного программирования)

Vaadin ?

Не свободна от XML на основе реестров

страничный интерфейс в множесве мобильных браузеров

Что из этих 23-х фреймворков хорошо работает на iPhone или Android ?

JSF ZK Vaadin не работали на ранних версиях мобильных браузеров.

Сейчас в мобильных браузерах полноценные WebKit и неплохие процессоры …

Теперь эти фреймворки работают, но ПЛОХО РАБОТАЮТ.

совместимость с SEO

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

Если исключить фреймворки, которые отпадают по остальным причинам, не остается вообще к рассмотрению вариантов.

 

Если же посмотреть на полный список этих фреймворков : «Что из этого SEO совместимо?» — риторический для многих вопрос.  Не так чтоб уж совсем плохо, но ничего хорошего.

 Немного разоблачающего юмора — пусть глаз отдохнет

Прикольная презентация, которая описывает отношение профессиональной команды к коробочным CMS и некоторым фреймворкам (к слову, в наше время вакханалия разрослась шире, чем представленно в презентации)

 

Что-то много текста получилось, обещаю продолжать писать про GUI моей мечты  в других постах.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *