Где мы свернули не туда? Как получилось, что современный десктопный GUI по умолчанию использует платформу HTML/CSS/JavaScript, которая изначально не предназначена для нативной работы на десктопе? Она создана конкретно для браузера и веба. Зачем из нативного софта делать веб-страницы в браузерной оболочке?
Джефф Этвуд (автор Stack Overflow) предсказал этот феномен ещё в 2007 году. Он тогда сформулировал так называемый закон Этвуда:
Любое приложение, которое можно написать на JavaScript, будет в итоге написано на JavaScript.
Так и вышло.
А если серьёзно, то это явный тренд в софтверной разработке, который наблюдается уже два десятилетия. Сейчас большинство GUI-приложений разрабатываются на платформе HTML/CSS/JavaScript.
Для разработки кросс-браузерных приложений на веб-стеке чаще всего используется платформа Electron, которая стала своеобразным стандартом.
В наше время на «Электроне» сделано практически всё:
- 1Password
- Asana
- Discord
- Figma
- GitHub Desktop
- Microsoft Teams
- Skype
- Slack
- Trello
- Twitch
- Visual Studio Code (на скриншоте вверху)
… и десятки других популярных десктопных программ.
Люди смирились и просто смотрят, как одна за другим нативные программы переходят на Electron со всеми вытекающими последствиями. Дело даже не в общей тормознутости и излишнем пожирании памяти (хотя это неизбежно в браузерной оболочке). В реальности производительность JS-кода по части UI даже обогнала типичный .NET за счёт многолетней тщательной оптимизации выполнения JS в браузерах. Нормально спроектированные JS-приложения сейчас гораздо быстрее, чем раньше. Но они по определению не могут сравниться с нативным софтом. Поэтому раздувание софта идёт полным ходом.
▍ Коммодитизация разработки
Почему так происходит? Логика абсолютно понятна. Фирме выгоднее разрабатывать и поддерживать одну платформу (веб) вместо N (веб+разные десктопные и мобильные ОС). Это чисто экономический вопрос: банально требуется меньше программистов.
Преимущества нативных приложений совершенно не очевидны для компании. Да, они могут быть быстрее. Но для этого нужно приложить усилия по оптимизации. И разница в скорости не так велика, чтобы обращать на неё внимание.
JavaScript проще, чем C++, так что и с этой точки зрения веб-платформа кажется привлекательнее. Происходит своеобразная коммодитизация разработки, когда создание приложений ставится на конвейер. Все они становятся похожи друг на друга, и производятся в «фабричном» стиле с помощью фреймворков типа Angular JS и Vue.JS. Правда, со временем становятся видны недостатки такого подхода:
- несовместимость разных версий фреймворков (приходится частично переписывать код);
- браузеры, стандарты и экосистема HTML/CSS/JS слишком быстро изменяются (гораздо быстрее, чем это нужно для коммерческих приложений);
- трудности в поддержке.
В итоге большие кодовые базы оказываются заблокированы в рамках определённой архитектуры/реализации. В некоторых ситуациях остаётся единственный вариант — переписать всё с нуля. С годами кодовая база начинает так пахнуть, что уже никто не хочет к ней прикасаться.
▍ Лучший консольный софт
Программисты старой школы не поддаются на новые веяния. Если посмотреть на творения лучших разработчиков, то там код максимально оптимизирован, GUI зачастую отсутствует, а производительность — наивысший приоритет. Вот список крутых опенсорсных программ, которые выбиваются из общего ряда. Это принципиально другой, «антипотребительский» подход к разработке. К сожалению, таких образцов становится всё меньше. Последние могикане. Упомянем некоторые из них:
▍ Аудиоплееры
- moc — консольный аудиоплеер для Linux/UNIX
- mpd — клиент-серверный плеер с консольным и графическим интерфейсом
- mus — модульный демон/клиент с консольным интерфейсом, который принимает плейлисты в текстовом виде
- vorbis-tools — плеер Ogg/FLAC
▍ Торрент-клиенты
- btpd (The BitTorrent Protocol Daemon) — торрент-клиент, реализованный в виде демона
▍ RSS-ридеры
- newsraft — фид-ридер с интерфейсом ncurses
- sfeed — парсер RSS и Atom с интерфейсом sfeed_curses UI
- snownews — текстовый RSS-ридер для Linux и Unix
- zs — Zeitungsschau, конвертер RSS/email
▍ Файл-менеджеры
- lf — файл-менеджер в стиле
ranger
, написанный на Go - mc — Midnight Commander, кросс-платформенный классический файл-менеджер
- nnn — Nnn's Not Noice, форк
noice
с большим количеством функций - noice — маленький и портативный файл-браузер
- ranger — файл-менеджер с привязкой сочетаний клавиш на текстовый редактор
vi
, написанный на Python, с очень приятным интерфейсомranger
- rover — простой консольный файл-браузер
- sfm (simple file manager) — простой файл-менеджер для unix-подобных систем
▍ Git
- stagit — генератор статических HTML-страниц для репозитория git
- stagit-gopher — генератор страниц в формате .gph (gopher)
- stagit-gemini — генератор страниц в формате .gmi (gemtext) для Gemini.
▍ Вьюеры картинок
- feh — продвинутый вьюер с функцией установки обоев для рабочего стола
- imv — простой вьюер X11/Wayland, зависимости: SDL2 и FreeImage
- lel — простой вьюер для X11, читает изображения в формате Farbfeld
- meh — вьюер, который напрямую использует XLib, libjpeg, libpng and libgif
- qiv — Quick Image Viewer
- sxiv — simple/small/suckless X Image Viewer, зависимости: xlib и imlib2. В данный момент осиротел (нет мейнтейнера)
- nsxiv — Neo Simple X Image Viewer, форк осиротевшего
sxiv
, зависимости: xlib и imlib2 - xli
- xwallpaper — минималистичная утилита для обоев рабочего стола
- xzgv
▍ Медиаплееры
- ffplay — простой и портативный медиаплеер, поставляется с
ffmpeg
, которому нужен для работыmplayer
- mplayer
- mpv — свободный, кросс-платформенный медиаплеер
▍ Уведомления
- herbe — уведомления без демонов и D-Bus. Минималистичный, легковесный, написан на C. Для вызова можно использовать tiramisu
- tiramisu — демон уведомлений на базе
dunst
, который передаёт нотификации в STDOUT, так что пользователь может обрабатывать их на своё усмотрение, как в панелиdwm
▍ Парольные менеджеры
- oathtool — Open AuTHentication (OATH) для одноразовых паролей
- pinentry-dmenu — программа для ввода паролей pinentry с добавлением динамических менюшек dmenu. Подходящий интерфейс для pass
- pass — «стандартный парольный менеджер UNIX»
- spm (simple password manager) — активно поддерживаемый форк
tpm
- tpm (tiny password manager)
▍ PDF-вьюеры
- mupdf — легковесный PDF-вьюер, написанный на C. Поддерживает PDF, XPS, EPUB, XHTML, CBZ, PNG, JPEG, GIF и TIFF
- zathura — расширяемый вьюер/оболочка, поддерживает CBZ, DJVU, PS, EPUB (с
mupdf
) и PDF (сmupdf
илиpoppler
)
▍ Оболочки
- dash — POSIX-совместимая реализация
/bin/sh
, оптимизированная на минимально возможный размер - mksh (MirBSD Korn Shell) — активно разрабатываемая свободная реализация языка программирования оболочки Korn Shell, наследник Public Domain Korn Shell (pdksh)
- oksh — портативная версия
ksh
из OpenBSD - yash (yet another shell) — задуман как POSIX-совместимая оболочка, которая в то же время поддерживает функции для ежедневного интерактивного и скриптового использования
▍ Текстовые редакторы
- acme — текстовый редактор Роба Пайка для Plan 9. Включён в состав plan9port
- ed — «стандартный текстовый редактор»
- ired — минималистичный hex-редактор и биндиффер для p9, w32 и *nix
- mg — портативная версия
mg
, поддерживается командой OpenBSD - mle — маленький, гибкий консольный текстовый редактор
- nano — клон
pico
, маленький и простой в использовании - neatvi — минималистичная реализация vi с поддержкой двунаправленного UTF-8 (LTR/RTL)
- nextvi — продолжение разработки
neatvi
с дополнительными функциями - nvi — маленький редактор в стиле
vi
- micro — консольный текстовый редактор со стандартными сочетаниями клавиш типа ctrl-c/v
- sam — редактор от Роба Пайка, написанный под вдохновением от
ed
- sim — текстовый редактор на основе
vim
иsam
- traditional vi — исправленная версия оригинального
vi
- vim (в GUI рекомендуется
:set go+=c
для блокировки всех всплывающих окон) может быть скомпилирован в предельно минималистичном стиле, какvim-tiny
в репозиториях Debian - vis — современный и эффективный редактор в стиле
vim
- wily — клон
acme
для POSIX
▍ Обработка текста
- csvquote — инструмент для кодирования проблемных символов CSV, чтобы unix-инструменты могли корректно их обрабатывать. Оптимизация SIMD по умолчанию, при сборке можно активировать откат на портативную версию C
- json2tsv — конвертер из JSON в TAB-Separated Value (TSV) и отдельный JSON-парсер
- md4c — конвертер из Markdown в HTML, быстрый, совместимый с CommonMark, поддерживает расширения, которые можно включать/отключать из консоли
▍ Утилиты/другое
- abduco — подключение/отключение сессий
- dvtm — динамический менеджер виртуальных терминалов
- entr — запуск произвольных команд по факту изменения файлов
- mrandr — простой и легковесный менеджер профилей мониторов (дисплеев), написанный на языке POSIX Shell
- mtm (Micro Terminal Multiplexer) — мультиплексор консолей, на скриншоте внизу три инстанса tine
- nq — утилита очереди командной строки UNIX
- pv — инструмент для мониторинга прохождения данных по конвейеру
- smenu — мощный и универсальный инструмент выделения в консоли для использования в интерактивном режиме или в скриптах
- snore — пауза с визуальным фидбеком
- yt-dlp — форк
youtube-dl
для скачивания видео и звука с YouTube и других платформ - zbar — пакет для распознавания штрихкодов из разных источников (видео, фото)
Полный список см. на сайте Stuff That Rocks.
▍ Оптимизация приложений. Примеры
Практически любое стандартное приложение можно оптимизировать. Например, для мобильных аппликаций критический параметр — время первоначального запуска, то есть промежуток между нажатием кнопки и загрузкой интерактивного интерфейса. Это тем более важно, поскольку первый запуск создаёт первое впечатление о приложении. Даже небольшая оптимизация будет заметна.
Люди очень чувствительны к задержке интерфейса. Пятнадцать лет назад Amazon выяснила, что каждые 100 мс задержки веб-сайта уменьшают продажи на 1%. С тех пор требования публики значительно ужесточились.
В 2017 году Akamai констатировала, что каждые 100 мс задержки снижают конверсию уже на 7%.
В 2018 году Google опубликовала статистику по загрузке мобильных страниц. Выяснилось, что пользователи на мобильных устройствах менее терпимы к задержкам. Так, при росте задержки с одной до трёх секунд количество отказов от загрузки возрастает на 32%, при росте до пяти секунд количество отказов увеличивается на 90%, и так далее.
- Рост задержки с 1 до 3 с → количество отказов возрастает на 32%
- … с 1 до 5 с → на 90%
- … до 6 с → на 106%
- … до 10 с → на 123%
Поэтому так важно оптимизировать мобильные сайты и приложения. И есть стандартные способы оптимизации, доступные каждому. Например, разработчики DoorDash рассказали, как ускорили первоначальную загрузку iOS-приложения на 60%:
- Профилирование для выявления узких мест (они использовали Xcode, а также Performance Analysis от Emerge Tools).
Трассировка стека, показывающая три возможности оптимизации
- Исправление трёх основных проблем, на которые тратится время в основном потоке:
- Проверка соответствия протоколу Swift — никто даже не знал, что стандартный String(describing:) занимается такими дорогими операциями.
Трассировка стека String(describing:) API
Замена идентификации типов
String(describing:)
на простой указатель типаObjectIdentifier
сразу ускорила загрузку приложения на 11%, а это всего одна строчка кода! - Отказ от тотального хеширования AnyHashable абсолютно всех действий и команд для хранения их уникальных значений. Переосмысление архитектуры привело к пониманию, что необязательно идентифицировать все команды по их хешу, а зачастую достаточно просто указателя на тип.
Эта простая оптимизация (опять одна строчка кода) ускорила запуск приложения ещё на 29%, а выполнение команд — на 55%.
- Аудит инициализации сторонних фреймворков показал, что эти ненужные вызовы замедляют запуск приложения примерно на 200 мс (конкретно в этом случае виноват фреймворк ServiceCore от Salesforce).
Разработчики подкрутили динамический линкер (dyld), чтобы он пропускал эти вызовы при запуске.
- Проверка соответствия протоколу Swift — никто даже не знал, что стандартный String(describing:) занимается такими дорогими операциями.
Все сделанные оптимизации в целом ускорили запуск приложения DoorDash примерно на 60%.
Эта история наталкивает на мысль, что большинство мобильных приложений абсолютно не оптимизированы. Они включают в код внешние библиотеки, которые 90% времени выполняют ненужные операции, как String(describing:) выше, добавляя задержку на пустом месте.
В результате даже самая простая программа типа hello, world!
с внешними модулями и зависимостями начинает неизбежно лагать на любом, даже самом быстром устройстве.
Есть мнение, что пользователям не нужен быстрый софт, потому что они якобы «ленивы и туповаты». Мол, пипл «схавает» всё, что дадут. Даже ужасной прилагой с задержкой десять секунд на каждое нажатие будет кто-то пользоваться. Люди привыкают к ужасу — и начинают считать его нормой. Однако адаптивный механизм психики — не оправдание для создания плохих продуктов.
Так или иначе, но фронтенд на HTML/CSS/JavaScript стал стандартом на всех платформах: и на десктопных, и на мобильных. Даже инструменты для разработчиков выпускаются в том же стиле. Например, Visual Studio Code на КДПВ — это браузер (Chromium) с сервером Node.js и файлами HTML/CSS, скомпилированными в исполняемый бинарник. Все переходят на веб-платформу. Ничего не поделаешь, таков путь.
Автор: Анатолий Ализар