Избранное сообщение

Фетісов В. С. Комп’ютерні технології в тестуванні. Навчально-методичний посібник. 2-ге видання, перероблене та доповнене / Мои публикации

В 10-х годах я принимал участие в программе Европейского Союза Tempus "Освітні вимірювання, адаптовані до стандартів ЄС". В рамк...

Благодаря Интернету количество писателей и поэтов увеличивается в геометрической прогрессии. Поголовье читателей начинает заметно отставать.

понедельник, 16 апреля 2018 г.

Блеск и нищета Java для настольных систем / Блог компании Haulmont / Хабрахабр / Программирование на Java

image

Вы не поверите, но в 2018 году всё ещё нужно разрабатывать Desktop приложения.

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

— Здравствуйте, меня зовут Юрий, я пишу Desktop приложения в 2018 году.
— Здравствуй, Юрий, давайте ему похлопаем, он смог поделиться своей проблемой!

Да, действительно, мы всё ещё пишем Desktop приложения. Обычно, не очень хочется этим заниматься, чаще всего это legacy проекты. Но бывает, что нужно писать и новые настольные приложения.

Зачем мы всё ещё это делаем, если есть web с его новыми продвинутыми возможностями: Progressive Web Apps, Service Worker, Web RTC, Web GL и т.д?

Под катом расскажу как с этим жить и при чём тут Java.

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

Например, можем использовать сканер отпечатка пальцев и другие модные устройства. Чаще всего дополнительное оборудование используется в enterprise приложениях: банках, ERP, бухучете и т.д. Вот там это всё точно нужно.

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

Особенно важно, если вашим приложением будут пользоваться на лаптопах. Будем считать, что в 2018 лаптопы окончательно победили и от них теперь никуда не деться. Очень часто люди работают с лаптопа в поездах и самолётах оффлайн и им нужно иметь возможность работать локально с данными, которые уже загружены на их машину. В web всё еще сложно реализовывать такое поведение.

А что там с Java?


В последнее время технологии Java для настольных систем не эволюционируют: разработка Swing заморожена навсегда, в SWT нет новых фич. Последняя живая технология для desktop — Java FX.

Влияние web-технологий на desktop-фреймворки очень велико. В Qt изобрели свой Qt Script и QML, основанный на JavaScript, а в Java FX реализовали поддержку CSS. Как это ни прискорбно, CSS в Java FX реализован частично и все свойства компонентов отличаются от свойств в web-UI.

В итоге — мы должны опять изучать конкретный фреймворк для desktop, вместо того чтобы переиспользовать гигантский объем готовых наработок для UI из мира web.

И кадровый вопрос тут выходит на передний план: никто не горит желанием писать настольные приложения на Swing и Java FX, но в то же время, на рынке полно хороших специалистов по web-UI.

Java на desktop вызывает боль не только из-за Java FX / Swing. Недавно, Oracle решил убить технологию Web Start.

Всё идёт к одному — специализированные UI фреймворки для desktop-приложений умирают.

Куда бежать!?


А теперь, о том как переиспользовать ваш опыт web-разработки и web-UI при разработке настольных систем на Java. Так, чтобы вам не пришлось разрабатывать отдельные web и desktop приложения.

Electron.js — это достаточно известный фреймворк, позволяющий использовать web-технологии для разработки desktop-приложений. Это технология, на базе которой построен редактор GitHub Atom. Atom — первое широко-известное приложение для desktop, построенное на HTML / JavaScript / CSS и Node.js.

Electron.js — это Open Source фреймворк, который позволяет вам писать UI для настольных приложений на web-стеке. Вы возможно удивитесь, но целая куча инструментов и приложений сейчас построены на этом фреймворке: Slack / Skype и VS Code используют для UI Electron.js.

В двух словах, Electron состоит из серверного JavaScript — Node.js и интегрированного web-браузера Chromium в одном исполняемом процессе, что позволяет использовать нативные фичи операционной системы: окна, нотификации, иконки в трее и многое другое.

До недавнего времени этот фреймворк предполагал разработку приложений только на JavaScript. Но мы придумали как применить его для наших приложений на Java!

Есть два варианта разработки приложений:

  1. Скомпилировать Java в JS
  2. Запустить JVM незаметно от пользователя и показать UI в web-браузере

Если у вас уже есть фронтенд на JS, то думать тут нечего, остаётся его запаковать в Electron.js и получить настольное приложение. Так делают, например, в мессенджере Slack.

А если у вас куча кода на Java? И при этом его нельзя просто так собрать в JS, вы сразу же лишитесь рефлексии, доступа к железу и возможности использования распространенных библиотек.

В таком случае можно использовать специальный модуль Node.js — child_process, позволяющий стартовать дочерние процессы во всех основных операционных системах. По сути, нам нужно реализовать один JS файл, который будет запускать JVM и открывать окно Electron:

if (platform === 'win32') {
    serverProcess = require('child_process')
        .spawn('cmd.exe', ['/c', 'demo.bat'],
            {
                cwd: app.getAppPath() + '/demo/bin'
            });
} else {
    serverProcess = require('child_process')
        .spawn(app.getAppPath() + '/demo/bin/demo');
}

Главное не забыть потом этот процесс убить, когда окно приложения будет закрыто, что легко сделать при помощи модуля tree-kill:

const kill = require('tree-kill');
kill(serverProcess.pid, 'SIGTERM', function (err) {
    console.log('Server process killed');

    serverProcess = null;
    mainWindow.close();
});

Полный код такой интеграции есть в моём туториале. В нём используется Vaadin в качестве фреймворка для UI, что позволяет писать весь код на Java без JS, а контейнер сервлетов Jetty интегрирован прямо в приложение. Мы можем запускать приложение без деплоймента, как тот же Spring Boot.

В таком варианте, наш фронтенд будет обращаться к JVM по сети, что как-то странно. Я несколько подсластил пилюлю, сменив транспорт между браузером и JVM на протокол WebSocket. Vaadin позволяет сделать это чрезвычайно просто. Так мы значительно снижаем время на отправку сообщений от фронтенда в JVM по сети, буквально до 1ms и избавляемся от ненужного HTTP мусора: заголовков и кукис, а также не создаём подключение, а всегда используем готовое.

На этом стеке я написал небольшое TODO приложение.

image

Там вы найдёте ещё несколько классных трюков:

  • загрузка статических файлов (CSS / JS) прямо с диска в обход JVM
  • доступ к API Electron.js из Java
  • кастомная шапка окна на HTML и CSS
  • автоматическая установка Node.js из Gradle

Ну а теперь давайте полностью избавимся от сети! С давних времён в операционных системах *nix и Windows существует API для межпроцессного взаимодействия — IPC. В Windows он называется named pipes, а в *nix — Unix sockets. Это буфер / виртуальный файл в оперативной памяти, который находится под управлением ОС и позволяет двум независимым процессам передавать данные.

Ради разнообразия, такой подход я реализовал на Kotlin и Kotlin.js.

В Node.js мы можем легко создавать как named pipe, так и Unix socket при помощи модуля — net

const pipeServer = net.createServer(function(stream) {
        stream.on('data', function(c) {
            console.log('Pipe: ', c.toString().trim());
        });
        stream.on('end', function() {
            pipeServer.close();
        });

        pipeStream = stream;
        console.log('Pipe is connected');

        global.pipe.send('hello', {});
    }).listen(PIPE_PATH, function () {
        
    });
}

Для работы с named pipe из Java / Kotlin нужно использовать класс RandomAccessFile:

val pipe: RandomAccessFile

try {
    pipe = RandomAccessFile("\\\\.\\pipe\\demo", "rw")
} catch (f: FileNotFoundException) {
    println("Unable to open communication pipe")
    exitProcess(-7)
}

var data: String? = pipe.readLine()
while (data != null) {
    
    data = pipe.readLine()
}

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

А нам то это зачем?


Как вы возможно знаете, мы делаем инструмент для разработчиков — CUBA Studio, позволяющий быстро писать бизнес-приложения на CUBA Platform.

Мы использовали фреймворк Vaadin в CUBA Platform и CUBA Studio, что позволяло переиспользовать большое количество наработок. С самого первого релиза CUBA Studio была web-приложением, которое запускается локально и показывает UI в web-браузере.

С применением этого подхода мы наконец-то смогли дать разработчикам удобство использования настольного приложения: окна, независимость от браузера, переключение по Alt+Tab и иконку в таскбаре.

image

CUBA Studio все еще использует сеть, но вместо AJAX там задействован WebSocket. Этого достаточно, чтобы пользователи не чувствовали никаких задержек UI.

Экосистема Electron.js порадовала нас и дополнительными инструментами.

  • модули для создания установочных файлов и пакетов
  • гладкое автообновление

Как можно догадаться, CUBA Studio это не конечная цель.

Как заменить Swing в наших приложениях


С самого первого публичного релиза платформы мы предоставляем две технологии для построения UI: Web-клиент на базе Vaadin и Desktop-клиент на базе Swing. Реализация Generic UI позволяет нам писать код, который работает в двух вариантах автоматически, конечно же, с соответствующими ограничениями.

Desktop-клиент был разработан в 2011 году на базе Swing, поскольку тогда не было другой стабильной и жизнеспособной технологии для настольных приложений на Java.

Но всё меняется.

Сегодня мы сталкиваемся с новыми требованиями к пользовательским интерфейсам на Desktop: responsive UI, анимации, интеграции с сетевыми сервисами, такими как Google. По сути, приложения двигаются навстречу web UI технологиям, и мы не можем игнорировать это движение.

Я вижу всего одну альтернативу Swing и Java FX — Electron.js. Поэтому и попробовал адаптировать этот подход для наших приложений:

  1. Берём Web-клиент
  2. Добавляем Electron.js
  3. Пакуем всё и отдаём клиенту

image

Приложения на CUBA Platform могут распространятся в виде Uber JAR. Этот вариант деплоймента позволяет запустить приложение простой командой:

> java -jar app.jar

Нам остаётся только добавить специальный скрипт запуска на Electron и получить Desktop-клиент из готового web-приложения!

Полный код приложения вы найдёте здесь.

Да вы с ума сошли!


Я тоже думал что ребята из GitHub сошли с ума. Но постепенно проникся. Мне хочется иметь гибкий инструмент создания UI, а самый гибкий инструмент сегодня — это HTML / JS / CSS.


Смотри также:

Зачем нужна Java. http://fetisovvs.blogspot.com/2014/07/java.html
Разбор основных концепций параллелизма. http://fetisovvs.blogspot.com/2018/04/java.html

Первый контакт с «var» в Java 10. http://fetisovvs.blogspot.com/2018/01/var-java-10-java.html
JAVA 9. Что нового? http://fetisovvs.blogspot.com/2017/10/java-9-java.html
Концепции объектно-ориентированного программирования — ООП в Java. http://fetisovvs.blogspot.com/2017/01/java-java.html
Анимации в Android по полочкам (Часть 1. Базовые анимации). http://fetisovvs.blogspot.com/2018/02/android-1-java.html
Двести пятьдесят русскоязычных обучающих видео докладов и лекций о Java. http://fetisovvs.blogspot.com/2015/12/java-5-java-java.html
Абстрактные классы и методы. http://fetisovvs.blogspot.com/2017/02/java.html
Полное руководство по Java Reflection API. Рефлексия на примерах. http://fetisovvs.blogspot.com/2017/02/java-reflection-api-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. http://fetisovvs.blogspot.com/2017/10/java-java.html
Микросервисы для Java программистов. Практическое введение во фреймворки и контейнеры. (Часть 3). http://fetisovvs.blogspot.com/2017/10/java-3-java.html
ТОП-3 способа конвертировать массив в ArrayList. Пример на Java. http://fetisovvs.blogspot.com/2016/09/3-arraylist-java-java.html
Ввод–вывод в Java. http://fetisovvs.blogspot.com/2016/05/java-java_28.html
Enum-Всемогущий. http://fetisovvs.blogspot.com/2017/02/enum-java.html
Массивы в Java. Создание и обработка. http://fetisovvs.blogspot.com/2017/10/java-java_18.html
Arrays, Collections: Алгоритмический минимум. http://fetisovvs.blogspot.com/2017/12/arrays-collections.html
Популярные методы для работы с Java массивами. http://fetisovvs.blogspot.com/2016/09/java-java_29.html
Пример использования метода replace в Java. Как заменить символ в строке? http://fetisovvs.blogspot.com/2017/01/replace-java-java.html
Класс Scanner в Java — описание и пример использования. http://fetisovvs.blogspot.com/2017/01/scanner-java-java.html
Пример использования метода trim в Java: как удалить пробелы в начале и конце строки? http://fetisovvs.blogspot.com/2017/01/trim-java-java.html
Spark — Потрясающий веб-микрофреймворк для Java. http://fetisovvs.blogspot.com/2017/10/spark-java-java.html
Чтение и запись CSV файла с помощью SuperCSV. http://fetisovvs.blogspot.com/2017/01/csv-supercsv-java-java.html
Конструкция try/catch/finally (исключения). http://fetisovvs.blogspot.com/2017/01/trycatchfinally-java.html
1000+ часов видео по Java на русском. http://fetisovvs.blogspot.nl/2017/06/1000-java-java.html
Шпаргалка Java программиста 7.1 Типовые задачи: Оптимальный путь преобразования InputStream в строку. http://fetisovvs.blogspot.com/2016/04/java-71-inputstream-java.html
Шпаргалки Java программиста 10: Lombok. http://fetisovvs.blogspot.nl/2017/12/java-10-lombok-java.html
Шпаргалки Java программиста 9: Java SE — Шпаргалка для собеседований и повторений. http://fetisovvs.blogspot.com/2017/12/java-9-java-se-java.html
Шпаргалка Java программиста 8. Библиотеки для работы с Json (Gson, Fastjson,
LoganSquare, Jackson, JsonPath и другие). http://fetisovvs.blogspot.com/2016/04/java-8-json-gson-fastjson-logansquare.html
Java 8 и паттерн Стратегия. http://fetisovvs.blogspot.com/2018/03/java-8-java.html
Реализация ООП-наследования в классах, работающих с SQL и MS Entity Framework. http://fetisovvs.blogspot.com/2017/02/sql-ms-entity-framework.html
Как установить соединение с СУБД MySQL в IntelliJ IDEA в редакции Community. http://fetisovvs.blogspot.com/2016/04/mysql-intellij-idea-community-java.html
Как с помощью maven работать с библиотеками, которых в maven нет. http://fetisovvs.blogspot.com/2017/03/maven-maven-java.html
Проекты по созданию компиляторов из Java в JavaScript и исполняемые файлы. http://fetisovvs.blogspot.com/2018/01/java-javascript-java.html
Диагностика утечек памяти в Java. http://fetisovvs.blogspot.com/2017/03/java-java_18.html
Spring AOP и JavaConfig в плагинах для Atlassian Jira. http://fetisovvs.blogspot.com/2018/04/spring-aop-javaconfig-atlassian-jira.html
Разбор задачек от Одноклассников на JPoint 2018. http://fetisovvs.blogspot.com/2018/04/jpoint-2018-java.html
Программируем… выход из лабиринта. http://fetisovvs.blogspot.com/2015/10/java.html
Основы работы с IntelliJ IDEA. Интерфейс программы. http://fetisovvs.blogspot.com/2016/09/intellij-idea-java.html
Ускоряем время сборки и доставки java web приложения. http://fetisovvs.blogspot.com/2018/03/java-web-java.html

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

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