В сети живёт огромное количество материалов по JavaFX (OpenJFX), однако мало статей с разбором экономической стороны проектов на этом тулките. Его использование часто ограничивается решением внутрикорпоративных задач или же написанием клиентских приложений, что не требует особенной аналитики.

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

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

Начнем с самого простого SWOT-анализа для оценки сильных и слабых сторон JavaFX, как и влияния различных факторов внешней среды. Данный анализ представляет собой матрицу положительного и отрицательного влияния:

Положительное влияниеОтрицательное влияние
Внутренняя средаСильные стороны (Strengths)Слабые стороны (Weaknesses)
Внешняя средаВозможности (Opportunities)Угрозы (Threats)

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

Для увязывания двух столбцов между собой можно рассмотреть каждый фактор с точки зрения диалектического принципа борьбы противоположностей: как имеющий положительное и отрицательное влияние одновременно, так и наоборот - каждое отрицательное влияние будет сопровождаться положительным. Обратной стороной такого подхода будет увеличение количества описаний факторов, часть из которых будет иметь незначительное влияние в силу известного закона Парето 80\20. С другой стороны, SWOT-анализ ничего не говорит о приоритетности факторов или же важности их, как и не рассматривает изменение их в динамике, а значит какой-нибудь незначительный на первый взгляд фактор запросто может оказаться значительным.

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

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

Для систематизации факторов вполне можно использовать модель FURPS:

  • Functionality — Функциональные требования.
  • Usability — Удобство использования (самого тулкита и программы).
  • Reliability — Надежность.
  • Performance — Производительность.
  • Supportability — Поддержка (ремонтопригодность, гибкость, модифицируемость, модульность, расширяемость).

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

Внутренняя среда

Функциональные требования

Кроссплатформенность: тулкит запускается под Windows, MacOS, Linux, заявлены arm64 и arm32, возможен запуск на raspberry pi, для разработки под мобильные платформы есть плагин от Gluon, но нет достаточных данных об успешных проектах на мобильных платформах, за исключением нескольких. Есть мнения, что в промышленной мобильной разработке тулкит используется редко. Хотя существуют небольшие проекты разных лет, например, TiltMaze или Monastery Disentis.

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

В Java много самых разных готовых библиотек, есть стабильные проекты Apache Commons, но большая часть библиотек - общего назначения, поддерживают старые версии Java, что может осложнить их интеграцию в современные модульные приложения. В случае более специализированных библиотек могут быть проблемы, как с поиском их самих, так и с интеграцией. Например, ORMLite имела проблемы с модульностью, причем достаточно долго. Да и сама по себе удобная работа с SQLite может внезапно оказаться проблемной в Java-приложениях, которые более нацелены на клиент-серверные базы данных.

JavaFX можно использовать вместе с Groovy (как и Kotlin), как для реализации системы плагинов, DSL, так и для написания самого приложения, но такая интеграция может осложняться ограничениями доступа модулей друг к другу, сильным проседанием в производительности, реиспользованием кода в других Java-проектах.

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

В тулките есть WebView, который можно использовать как часть интерфейса с логикой работы на JavaScript, но потребление ресурсов может сильно возрасти, часть современных сайтов (сервисов) могут плохо его поддерживать. Например, из-за ограничений логина в менее популярных браузерах могут не работать различные сервисы, тот же Google и т.п.

Присутствует 3D, апи для работы с векторами (скалярное, векторное произведение, нормализация и т.п.) в пакете javafx.geometry, что облегчает работу с графикой и позволяет добавлять в приложения различную визуализацию, но в зависимости от задачи могут быть возникать и разные проблемы - производительность, импорт моделей разных форматов и т.д. Можно использовать OpenGL напрямую через JOGL, но это сложнее.

Возможно взаимодействие со Swing, но в зависимости от задачи оно может быть неполным, работать не так или никак.

Есть богатое апи для работы с датами и временем, но часть кода и библиотек завязано на устаревшее апи из java.util. Как и своеобразный конфликт между java.io и java.nio

Удобство использования

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

В Java много IDE - Netbeans, Eclipse, IntelliJ IDEA и другие, обширные возможности рефакторинга и отладки ускоряют разработку в разы, но за счет своей монструозности их сложнее настроить, как и есть шанс получить проблемы с проектом при обновлении самой IDE или библиотек. Например, разработчики Gradle склонны постоянно ломать апи, что для динамического DSL-языка может приводить к долгим и мучительным переделкам.

JVM снимает проблемы использования системных библиотек и адаптации логики кода к разным операционным системам, но может усложниться доступ к операционной системе, как и сохраняются проблемы корректной работы платформозависимых библиотек самого JavaFX (например, для работы с медиа) и появляются платформоспецифичные недоделки и баги. Так, могут быть проблемы с удобной идентификацией запущенных процессов приложения в системе, как и работа с различными правами доступа в т.ч. с root-привилегиями.

Разработка сильно ускоряется за счет SceneBuilder, но в нем есть недоделки и баги в т.ч. они могут проявляться в генерации самих FXML-файлов разметки.

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

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

Часть контролов может создаваться\заполняться рефлексивно, но для модульного приложения рефлексивная автоматизация со стороны тулкита может требовать открытия доступа, например, пакета контроллеров к модулям JavaFX.

За счет наличия реактивности в пакетах javafx.beans.binding, контролах через свойства javafx.beans.property, коллекциях (javafx.collections) часть логики можно сильно упростить, что не требует подключения реактивных библиотек, но это может ухудшить отладку и создать коварные баги в сложной логике.

За счет возможности в FXML напрямую использовать ключи языковых ресурсов сильно упрощается локализация приложения, но сложнее перехватить ошибочную ситуацию: отсутствие ключа, неверный ключ, пустое значение и т.п.

За счет поддержки HiDPI упрощается работа с разными экранами, но для изображений есть только 2x версия, на разных операционных системах с HiDPI могут возникать коварные баги.

javafx.concurrent, как и метод javafx.application.Platform.runLater, который позволяет запускать код в JavaFX потоке, сильно упрощают работу с многопоточностью, но они могут быть недостаточными для более сложных задач, как и для интеграции стороннего кода и библиотек.

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

В случае запуска .jar файла сохраняется удобная кроссплатформенность - запуск возможен через простую передачу в шелле пути к директории с библиотеками javafx, индивидуальной для каждой системы, но это потребует наличия JRE, установленной в систему или в портабельном виде.

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

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

javafx.animation позволяет создавать сложную анимацию, но может привести к потерям в производительности, как и нарваться на высокое использование процессора приложением.

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

Надежность

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

Для более ответственных и настраиваемых расчетов в Java есть BigDecimal, но при использовании все равно возможны ошибки (например, проблемный конструктор из double). В операциях с простыми типами возможны ошибки из-за целочисленного деления, переполнения, сужающего приведения типов, отрицательного результата деления с остатком и т.п.

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

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

Производительность

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

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

Поддержка

JavaFX постоянно обновляется с фиксом проблем и багов, но тулкит не включен в JDK как Swing, что требует отдельного подключения библиотек. Существуют различные поставки jdk (Liberica, у Azul Zulu есть FX-сборки) с включенным тулкитом, но это может быть менее универсальным в сравнении с всегда доступным Swing.

В тулкит вносится очень мало изменений апи, шанс получить неработоспособное состояние программы при обновлении очень небольшое, разве что это не сопровождается кардинальной поломкой апи или архитектуры (как было в случае перехода с java 8 на 9), но сохраняются проблемы при обновлении и настройке операционных систем и библиотек в них.

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

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

Можно настраивать как и самое простое (модуль java.util.Logging), так и более сложное (logback и т.п.) логирование, но его конфигурация может быть сложной задачей и упираться в различные конфликты между разными библиотеками.

Есть возможность снимков (скриншотов) узлов сцены (через javafx.scene.Node.snapshot), а также есть свой javafx.scene.robot (немного более удобное апи в сравнении с java.awt.Robot и пару удобств, например, определение позиции курсора), что можно использовать в целях тестирования, но апи очень простое и для более сложных случаев (как и, например, сравнение скриншотов) может потребоваться что-то другое.

Внешняя среда

В случае анализа внешней среды в игру вступают уже другие языки, технологии, участники рынка и прочее. Для выявления наиболее значимых факторов можно использовать PEST-анализ (STEP), а также его расширенные формы (PESTLE и т.п.). В самом простом виде принимаются в расчет следующие факторы:

  • Политические (P - political)
  • Экономические (E - Economic)
  • Социальные (S - Social)
  • Технологические (T - Technological)

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

С другой стороны, большая часть таких факторов очень сильно зависит от региона и особенностей самого проекта. Если же повышать уровень абстракции, то они становятся очень трудно прогнозируемыми. Можно, конечно, выделить несколько явных тенденций для разных факторов, что-то вроде:

  • Стимулирование развитие технологий и сервисов, создание льгот для проектов-резидентов.
  • Повышение требований к безопасности и работе с личными данными пользователей.
  • Подстройка образования под спрос на IT-специалистов.
  • Поиск удешевления разработки и кроссплатформенности из-за большого количества устройств и необходимости связывать их все в одной кодовой базе.
  • Постепенное увеличение акцента на IT в образовании и самообразовании.
  • Дальнейший рост IoT и появление новых операционных систем и платформ и т.п.

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

Полезнее может оказаться Анализ пяти сил Портера, который оценивает:

  • Анализ рыночной власти поставщиков.
  • Анализ рыночной власти потребителей.
  • Угрозы появления продуктов-заменителей.
  • Угрозы появления новых компаний-игроков на рынке.
  • Анализ уровня конкурентной борьбы.

Что вполне укладывается в возможности и угрозы SWOT.

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

В Java повсеместно распространена финализация и ограничение доступа private\package, что сильно уменьшает гибкость и настраиваемость библиотек. Любое изменение в рефлексивном доступе, как и конфликты модулей друг с другом наиболее критичны для мелких проектов, не имеющих больших команд программистов и решающие задачи в сжатые сроки. Если задача предполагает подключение крупной легаси-библиотеки со множеством зависимостей, которые давно (или никогда) не обновлялись, то стоит ожидать проблем и есть шанс потратить очень много времени на их решение, вместо решения задач самого проекта. В таком случае альтернативные тулкиты выглядят более привлекательно, разве что альтернативные библиотеки могут быть хуже по качеству или вообще отсутствовать.

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

"Потребителями" будут являться не только непосредственные клиенты, но и промежуточные фирмы по внедрению, сопровождению и т.п. поскольку проект может быть как B2C так и B2B. Поскольку кроссплатформенность и дополнительная прослойка в виде JVM создает неудобства в установке, запуске и использовании, то возможности здесь полнее раскрываются на проектах, где требования контролируется, как и внедрение.

С другой стороны, появление в Java 9 системы модулей вместе с jlink решает большинство проблем деплоя, кроме проблем от легаси-библиотек, ещё не перешедших на модульную системы.

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

Конкурентные технологии уже рассматривались в старой статье, но к ним следует добавить Blazor, но еще не совсем понятно, насколько он может конкурировать с десктопными тулкитами на других языках, поскольку сам по себе является еще и конкурентом уже существующим C#-тулкитам, а это может оказывать влияние на количество и качество библиотек. А также угроза может быть со стороны Go, хотя за счет упрощения языка построение сложной логики может оказаться немного более сложным в сравнении с классическими объектными языками и уже выверенными паттернами и приемами. Но тем не менее, это возможно, а учитывая, что Go очень популярный язык, то вполне закономерно желание какую-то часть десктопных (и не только) задач решать на нем.

Вероятно, одна из наибольших десктопных угроз - это Flutter из-за высокой универсальности фреймворка и вполне удобного Dart. Намечаются тенденции интеграции его в экосистему Linux, например, пакеты для взаимодействия с D-Bus, NetworkManager и т.п. лежат в репозиториях Canonical, что может создать для Flutter удобную интеграцию с популярными дистрибутивами, повысив популярность и удобство разработки. Ну а поскольку JavaFX часто используется на Linux из-за нежелания использовать системные языки для разработки сложной логики, то это наличие очень сильного конкурента.

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

Очень большая часть задач могут быть решены с использованием веб-стека, что универсально, относительно дёшево и гибко. Если отбросить различные нетехнические факторы и учесть анализ выше, то можно смоделировать следующую ситуацию: в регионе между двумя фирмами разворачивается конкурентная борьба, одна фирма использует веб-стек, другая - JavaFX клиент. У второй может быть больше издержек за счет найма более дорогих Java-программистов, а также из-за сложностей поддержки продуктов, какую конкурентную стратегию должна может выбрать вторая фирма?

Есть различные классификации конкурентных стратегий (Портер, Раменский-Грайм и т.п.), но определяющим фактором скорее всего будет являться сама предметная область. Например, функционал сложного редактирования документов проблематично построить на мобильных платформах и он в любом случае будет менее удобен для тех, кому важна скорость работы. Следовательно, если, выбирая JavaFX двигаться в направлении юзабилити и повышения скорости работы, то кроме самой гонки это может создать конкуренту множество проблем после определенного этапа сложности и заставит расходовать дополнительные средства на разработку и тестирование, хотя опять-таки зависит от множества факторов, начиная от квалификации команды и заканчивая её управлением.

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

Важным фактором будет и сама целевая аудитория. Например, лояльность части технических специалистов можно получить дистанцируясь от веб-стека и Electron, хотя с Flutter это сделать уже не получится.

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

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

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

Если вспомнить "звериные" стратегии конкурентного поведения (Фризевинкель, Раменский), то использование JavaFX, вероятно, ближе к стратегии патиентов (лисы) с приспособленностью к узкому рынку, тем более, что на фоне огромного количества курсов количество Java-программистов, вероятно, сильно увеличится в ближайшие годы, что уменьшит проблемы с поиском специалистов.

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