СтрижПИ

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

Во-первых, то, что Эппл выпустило нормальный реактивный data-driven UI фреймворк, заслуживает исключительно всяческих похвал. Правильный тренд, правильный подход, _почти_ интерактивное превью, все вовремя и к месту. Нам, iOS-программистам, чего-то такого сильно не хватало.

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

VStack(
    Image(uiImage: image),
    Text(title),
    Text(subtitle)

можно было писать

VStack {
    Image(uiImage: image)
    Text(title)
    Text(subtitle)

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

Работает это благодаря вот такому вот прекрасному интерфейсу:

То есть не только не очень понятно зачем так усложнять себе жизнь, но еще и больше 10 элементов не засунешь. Может быть создатели руководствовались правилом 7±2 и решили, что пользователи айфона не смогут всерьез осознать более 10 одновременных элеметов на экране.

То что в этом интерфейсе пропилена специальная дырка для if напрягает если честно еще больше:

Не самим фактом дырки, а вопросом, где же собственно дырки под все остальное?

(на самом деле, если хочется больше 10 элементов, есть целый специальный компонент — ForEach, который — уберите детей от экрана! — принимает список)

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

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

VStack(alignment: .leading) {
  Text("abc")
    .font(.subheadline)
    .padding(.all)

.font() устанавливает свойство (шрифт), а .padding() заворачивает Text view в Padding view, возвращая новый тип view. То есть почему не сделать однообразно? Свойства — методами, контейнеры замыканиями?

VStack {
   Padding {
       Text("abc")
           .font(.subheadline)
   }
}.alignment(.leading) 

Есть и совсем странные места, например, NavigationView берет заголовок не из собственного property, а из первого лежащего в нем ребенка!

NavigationView {
   List {...}
       .navigationBarTitle(Text("Rooms"))

Но это все конечно цветочки. Главный консерн у меня по поводу того, сколько всего SwiftUI делает сам, «магически». Например, можно написать:

Text("abc").padding() 

и все. Какой именно паддинг? А какой-то дефолтный. Еще и зависящий от ситуации. Хуже того, можно вообще ничего не писать:

HStack {
   Text("★★★★★")
   Text("Avocado Toast).font(.title)
   ...

И все равно обнаружить дырку вот тут:

Процитирую чувака со сцены:

SwiftUI didn’t slam all of the stack’s children against each other. It left some space between these two because Adaptive Spacing™ is in effect.

То есть SwiftUI сам решил что в этом месте нужна дырка и добавил ее. Как он это решил? На основании чего? Вы скажете «просто дефолт», но все сложнее! Насколько я понимаю, SwiftUI не чурается залезть внутрь ваших вьюх и если он узнает лежащие там компоненты, он может принимать разные решения в разных ситуациях. Например, отступить не от bounding box, а от text baseline, если он у вас где-то в глубине есть: 

Или если написать

List {
   Button { Text("Add room") }

То кнопка будет черненькая:

А если теперь поменять стиль списка (не кнопки!):

List {
   Button { Text("Add room") }
}.listStyle(.grouped) 

То уже синенькая!

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

Во-первых, на дефолты нельзя полагаться, потому что они будут меняться. Пока ты изловчился сделать на сегодняшних, Эппл выкатывает завтрашние и они становятся еще умнее и перекрашивают кнопки, втыкают больше паддингов, ставят контролы с другой стороны и т.п. Помните CSS reset? Может показаться, что в случае с браузерами это проблема исключительно потому, что браузеров много и они не могли договориться. SwiftUI же один, чего тут волноваться? Очень просто: во-первых, устройств у Эппла много и на всех дефолты разные. А во-вторых, через два года Эппл решит что пора обновлять свой design language и выкатит другие дефолты и все приложения поплывуууут в дальнее плавание. 

Вторая причина в том, что с умным поведением нужно бороться, что тоже очень неприятное занятие. Я прекрасно помню бессонные ночи, когда я (в вебе) изо всех сил пытался убрать какие-то левые зазоры под картинками, выровнять текст с иконкой ровно как тебе нужно, пытался убить непойми откуда взявшийся вложенный скролл, победить наезжающие друг на друга float: left иллюстрации и подобное. Потому что ситуация ровно такая же: веб предлагает набор высокоуровневых дефолтов и «умной» логики лайаута, которые иногда работают, а иногда как кость поперек горла, вытаскиваются только хирургическим путем.

И третья причина в том, что с таким подходом разработка никогда не завершится. Ты не знаешь, сколько еще «умных» дефолтов ты пропустил и как они могут потенциально испортить тебе жизнь, сейчас или в будущем. Обнаружить, что у Васи на древнем третьем айпаде и вчера вышедшей новой iOS (и только на такой комбинации) «умный» SwiftUI показывает дырку в 30 пикселей вместо 20 и из-за этого едет половина верстки, бегать за такими проблемами — занятие для молодых и сильных.

Так что с тех под я предпочитаю вещи явные, прямые и тупые, как кусок водопроводной трубы: если я забыл воткнуть зазор между картинкой и текстом, то я сам дурак и не будет никакого зазора. Если я воткнул зазор в 20 пикселей, он и останется в 20 пикселей, что бы ни случилось. Более того, об этом в коде будет явно написано буквами.

Да, такой код не будет выглядеть так красиво со сцены Steve Jobs Theater. Зато он будет делать ровно то, что в нем написано, его можно понять, предсказать, найти, разобраться и поменять. Потому что ДОБАВЛЯТЬ простые и предсказуемые компоненты просто. А вот ОТМЕНЯТЬ чужую умную непрозрачную логику тяжело. Потому что она чужая, умная и непрозрачная.

P.S. Disclaimer: People being people, многим важно не только ЧТО написано, но и кто это пишет. Некоторые не готовы слушать аргументацию человека, который не программирует на Swift минимум пять лет без отпуска. Некоторые игнорируют любую критику, автор которой не может похвастаться собственноручно задизайненым языком или (хотя бы) полноценным UI-фреймворком. Поэтому во вступлении я немножко слукавил. Конечно я никой не iOS разработчик, я даже на Swift (языке) никогда не писал и слабо представляю, что там стоит за атмосфера. Swift UI изучал только то статьям и презентациям. Я даже попробовать его не могу, потому что он требует Каталины, а на ней не работают никакие программы. Но зато я давно и плотно интересуюсь темой UI фреймворков, да и программирую не первый день, так что верить мне можно.

P.P.S. Верить никому нельзя.

Кто бреет брадобрея?

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

Один из примеров был в игре Portal 2:

Does a set of all sets contain itself?

И вот буквально сегодня попалось в Вечной жизни смерти:

– У нас есть веревка, толщина которой неодинакова. На то, чтобы она сгорела от одного конца до другого, требуется час. Как, используя эту веревку, отмерить пятнадцать минут? Помните – толщина у веревки разная!

На этот раз дети не торопились отвечать – они глубоко задумались. Вскоре поднял руку мальчик:

– Надо сложить веревку пополам и поджечь ее одновременно с двух концов.

АА кивнула:

– Иди сюда, – и поставила мальчика позади себя рядом с первой девочкой.

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

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

В примерах выше слова пересказаны по памяти почти абсолютно точно, с мельчайшими ошибками (в первом ВСЕГО ЛИШЬ частицу «не» забыли! — мелочь для обычного литературного текста в обычных обстоятельствах), но эта мельчайшая ошибка разрушает самую суть. Остается как бы пустая скорлупа без смысла, соломенный самолет, приманивающий миротворческие грузы.

Good times create weak men

Есть такой очень важный доклад Jonathan Blow - Preventing the Collapse of Civilization. Смотреть прям обязательно. Это такой Software Disenchantment только с анализом причин и выводом.

Так вот, в нем утверждается что современные программисты, стоя на плечах гигантов, утратили способность писать фундаментальные вещи и вообще простой, быстрый, надежный софт. Good times create weak men:

Ну а логика очень проста: предыдущее поколение сделало X, следующее пишет Y на X и ему не очень нужно и вообще не интересно, как X внутри устроено и как сделать такое же с нуля. Повторить N раз.

При этом тревогу никто не бьет: всем кажется, если мы умели делать X, а научились делать Y, то теперь мы умеем делать и X, и Y. Что не совсем верно, потому что знания (экспертиза!) сами по себе вообще говоря не передаются (это одна из самых важных и новых для меня мыслей доклада), а необходимости практиковать X нет, соответственно он благополучно забывается. Docker и Electron — самые популярные технологии сегодняшнего дня. Обе не про что-то новое или фундаментальное, а про то, чтобы тихонько спрятать сложность под ковер, понять, разобраться или изменить которую у нашего поколения уже не получается.

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

Все это немножко отдает дедовским ворчанием, и вообще как-то не ощущалось без хороших наглядных примеров. Пока я не набрел на annoying.technology, клон нашего grumpy.website. Ребята не побоялись поставить себе macOS Catalina, и вот где, оказывается, цирк!

Переключение чатов тормозит: https://annoying.technology/posts/e500c236b5e2853a/

Вместо следующего трека показывается через-один-следующий https://annoying.technology/posts/ee91b37183818d7b/

Песни показываются по два раза https://annoying.technology/posts/991e8babac1f6dc4/

Рендеринг разъезжается https://annoying.technology/posts/802dfae3517d4419/

Элементы списка не выделяются https://annoying.technology/posts/da8e5b3f56d9f767/

Клик на элементе выбирает другой элемент https://annoying.technology/posts/04769fafdac16826/

Программа конфликтует сама с собой https://annoying.technology/posts/c1f50e78a65d2ce3/

Программа рандомно отписывает от подкастов https://annoying.technology/posts/5c942a7b43a4a8b4/

Скачка не завершается https://annoying.technology/posts/50a5965493785fdb/

И это только первые две страницы!

Что показательно, это не какие-то случайные заскоки или ушлые маркетинговые решения. И не то чтобы они пытались что-то инновационное сделать. Нет, это самые простые и банальные вещи, какие только могут быть, вещи, которые компьютеры делали 30 лет без особых проблем, которые ipod с ЖК экраном и мощностью в 1/10 наручных часов успешно решал, и они их фейлят. Ты просишь человека открыть шкаф, а он обосрался. Не в смысле не смог, а буквально наложил в штаны вместо этого. Примерно такой уровень сложности задачи.

Вот как программируют современные программисты. Как думаете, сколько этот код продержится? https://twitter.com/argentumko/status/1210532125637611521
Вот как программируют современные программисты. Как думаете, сколько этот код продержится? https://twitter.com/argentumko/status/1210532125637611521

Причем, как правильно замечено в одном из постов, это не какие-то маргинальные программы непойми кого. Это флагманские Эппловые продукты, с помощью которых вообще-то в первую очередь рекламировалась эта самая новая ось. То есть не применим аргумент недосмотрели, не было времени, занимались чем-то другим — нет, можно быть уверенным, что огромное количество ресурсов было потрачено и огромное количество глаз смотрело именно на эти самые приложения. И ВСЕ РАВНО НЕ СМОГЛИ!

Понимаете? Понимаете, насколько все плохо? Одна из самых влиятельных технологических компаний в мире, которая может нанять кого угодно и в каких угодно количествах, бренд которой построен на супер качественном и вылизанном софте, компания, которая не выпускает «бета продуктов», которая МОГЛА в прошлом (документальный факт), НЕ СМОГЛА! Не «не захотела», не «выбрала неверное направление», не «переоценила свои силы», не «промахнулась с первого раза» а тупо, банально хотела, очень хотела, но не смогла.

И такое, ну, вообще вокруг нас. Новый Gmail работает хуже старого. Новый Твиттер медленнее и косячнее старого. Новый Youtube рисует меньше, а тормозит больше. Про macOS и iOS мы уже поговорили. Даже когда ситуация и задача фиксирована, а качество все падает и падает. Это даже не worse is better, потому что ничего нового не производится, место на рынке не делится, компания, принципы, приоритеты, пользователи не меняются. Буквально, те же самые люди делают тот же самый продукт. И выходит хуже и хуже.

Вот что печально.

Будущее программирование-2

Интересно, что хоть я в своем предыдущем посте явно и написал, что работа в облаке и работа в браузере — две совершенно перпендикулярных оси, я все равно получил пару комментариев от людей, которым кажется, что ЕСЛИ ты хочешь чтобы IDE работала в облаке, НЕОБХОДИМО, чтобы она работала в браузере.

если у тебя браузер лишь отвечает за фронт, то ресуркоёмкие вещи (индексация всякая, подсказочки, рефакторинг, компеляция) можно отдать серваку (по-моему пока ms додумались до language server, не?).
Не секрет, что многие считают идею очень прожорливой, поэтому мне кажется это было бы отличным выходом запихнуть иде в браузер где все сложные и ресурсоемкие операции выполнются на сервере, а тебе предоставляется только окошко терминал.

Поэтому я на всякий случай повторю еще раз:

Можно сделать локальную, прожорливую ИДЕ нативно. Классика: IDEA, Eclipse, Visual Studio. Подход прост и понятен всем.

Можно сделать облачную ИДЕ в браузере: Cloud9, Jupyter. Это то, что считалось будущим программирования, но пока стало очень нишевой штукой. Но это НЕ единственный возможный вариант.

Можно сделать локальную, прожорливую ИДЕ в браузере. Это то, что сделали VS Code и Atom. Не очень понятно, что они от этого выиграли, кроме того, что попали в волну, когда всем показалось, что будущее за JavaScript.

Можно сделать облачную ИДЕ с нативным приложением. Примеров ИДЕ пока нет, но самому подходу сто лет, называется тонкий клиент, отлично себя зарекомендовал.

Никто не мешает отгружать вычисления, ворочать облачными ресурсами и делать все остальное, НЕ будучи засунутым в браузер. Еще раз: браузер это довольно странная, во многом ограниченная и компромиссная платформа, которая дает leverage простым веб-страницам, но стоит начать делать что-то чуть более сложное (да, приложения, причем ЛЮБЫЕ приложения, даже самые элементарные), как она тут же начинает путаться под ногами и мешать.

Ну серьезно, подумайте, вот начали вы облачную ИДЕ делать, чем браузер вам поможет? HTTP-клиентом? Серьезно, там больше НИЧЕГО нет, одни ограничения.

Да, у веб-страниц есть ОЩУЩЕНИЕ что они легковеснее, чем нативные ИДЕ. Но это только ощущение. Если нужна максимальная производительность, то внезапно оказывается, что JS очень медленный язык, грузит он не так уж и мало, интерпретирует долго и КАЖДЫЙ РАЗ.

Единственное, почему, как мне кажется, в умах облачное == браузерное это репутация нативных ИДЕ как прожорливых монстров. Но это просто XCode или там Idea так написаны, как супер-комбайны «все и сразу». Они портят репутацию нативных ИДЕ, но это не значит что любые нативные ИДЕ должны быть такими. Нативные приложения могут быть легкими, шустрыми, простыми. Так мало кто делает, но это возможно и гораздо проще, чем заставить быстро работать браузер.

Будущее программирование

Я тут сделал доклад в JetBrains (внутренний, сорян) про будущее IDE. И после доклада было много вопросов из серии “Но ведь будущее определенно за Х, а вы его даже не рассматриваете”. Отвечаю.

— Почему вы не делаете IDE для браузера?

Visual Studio Code Online
Visual Studio Code Online

Делать IDE в браузере особого смысла нет. Да, лет десять назад, на волне успеха Google Docs всем казалось, что сейчас вообще все переедет в веб: и фотошоп, и обработка музыки, и монтаж видео, даже игры пытались. И, разумеется, программирование. Оказалось (внезапно, да) что браузер это довольно неудобная и ограниченная фигня и сидеть в нем добровольно никто не хочет. То есть это и так было понятно, просто лет десять назад казалось, что щас гугл с майкрософтом напрягутся и подтянут веб до нужного уровня. Тогда думать так было нормально. Сегодня это уже наивно, потому что мы видим, что по факту никто ничего никуда не подтянул, наоборот, закручивают гайки и делают из веба платформу для документов. 

Ну и десять лет назад, может быть, кому-то и казалось, что веб это дивный новый мир, но сегодня уже совсем не так ясно, зачем вообще лезть в браузер? От попадания туда у приложений не возникает магически каких-то волшебных свойств, которые невозможно было бы организовать на десктопе. Наоборот, многие полезные свойства гарантированно теряются: шорткаты сильно ограничены, drag-n-drop, файлы, интеграция в систему, перформанс. Зачем, мистер Андерсон, зачем? Если будущее приложений (вообще любых, кстати) и лежит где-то, то точно не в браузере.

— Но ведь есть WebAssembly!

Естественно, в таких дискуссиях неизбежно всплывает веб-ассемблер. Что тоже мне не очень понятно: веб ассемблер это такой способ запустить C++ в браузере. Но тут мы приходим опять же к вопросу: а зачем вообще запускаться в браузере? Что там есть такого, чтобы сначала усложнять себе жизнь, а затем эти проблемы героически решать?

— Но ведь если IDE написать для браузера, ты сразу сможешь запуститься на любом устройстве?

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

Нет, ребята, запинать код — не такая уж и проблема. Проблема — это чтобы продукт выглядел уместно в той среде, где запускается. Чтобы вел себя адекватно. Чтобы интегрировался. Поэтому write once, run anywhere это довольно наивная утопия, посмотрите хотя бы на кошмар UI-библиотек на Java. Гораздо здравомысленнее выглядит подход Flutter, которые сразу говорят: под каждую платформу виджеты свои, пишите дважды. Да, это тяжеловато разработчикам, зато прекрасно для тех, кто будет приложением пользоваться. Оптимизировать разработку продукта под время/удобство разработчика вообще путь в никуда. А если писать UI-код под каждую платформу заново звучит страшновато, то посмотрите на разработчиков игр — они под каждую консоль просто всю игру заново пишут, иногда это даже разные команды. И ничего, живут как-то, игры выходят, оптимизируются под особенности железа, используют фичи платформы. Игроки довольны.

— Ноутбуки говно, будущее за планшетами, ультимативной мобильностью и работой из купе поезда Москва-Владивосток. А что, разве нет?

Да, раз в год в интернете очередной персонаж объявляет год отказа от ноутбуков и программирования на айпаде. Да, так можно сделать. Можно найти способ, придумать, извернуться. Вопрос только: зачем?

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

Но время прошло. Айпаду уже почти 10 лет, и за это время стало понятно, что у каждого из устройств есть свой sweet spot. Для телефона это приложения, доступ к которым нужен на бегу. Для ноутбука — серьезная офисная работа. Для планшета — чтение и рисование? Так или иначе, у каждой задачи есть свой максимально удобный форм-фактор, максимально подходящий набор приложений, максимально подходящая обстановка. Скажем, для рисования это действительно экран с пером, а не ноутбук, не аудиоколонка и не телефон. Для прослушивания музыки — умная колонка, а айпад с ноутбуком будут overkill. А вот для программирования — десктоп с большим монитором, настоящей клавиатурой и мышкой/трекпадом. Все остальное — компромисс.

Да, можно программировать и на ноутбуке, почти ничего не потеряв. Можно программировать и на айпаде. Можно и на телефоне, наверное, и даже на часах. Вопрос же не в том, как может извернуться человек. А в том, что вот перед вами программист, решивший остаток своих дней посвятить созданию программ. Предположим, чисто гипотетически, что например IntelliJ IDEA УЖЕ существует для всех на свете возможных платформ, включая MiFit. Так вот, зачем, какая сила даже чисто теоретически может этого человека заставить выбрать устройством работы с кодом айпад, а не нормальную рабочую станцию? Даже при прочих равных. Ну не сможет он, бедняга, поехав в отпуск и оставив ноутбук на работе, поправить десять строчек кода. Сможет только (и будет) смотреть мультики с детьми. Настолько ли это большая проблема? Настолько ли частая? И та ли эта ситуация, вокруг которой мы должны строить будущее для всех остальных?

Спасибо, кстати, что хотя бы никто не спросил, почему мы ничего не планируем для VR-а.

— За чем же тогда будущее? На что ориентироваться?

(окей, это я уже сам себе вопрос задаю, хочется какой-то позитивный месседж в конце оставить)

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

Во-первых, компьютеры никуда не денутся именно для программистов. Может быть, часть каких-то приложений будет постепенно уходить с них на другие форм-факторы (телефон, планшет, часы), но не IDE.

Кросс-платформенная разработка важна как минимум для трех главных платформ: macOS, Windows, Linux. Пользуясь случаем, хочу напомнить, что настоящий язык по-настоящему кросс-платформенной разработки — никакая не Java, и все еще не JavaScript и уж конечно не WebAssembly, а C++. Вот уж что-то, что действительно runs anywhere.

Скорость всегда будет одной из главных фич любой программы, и уж конечно IDE. Взлет Sublime Text, Atom и VS Code связан не с успехом JavaScript, а с тем, что ждать, пока запустится Visual Studio/XCode/Eclipse/IDEA нет ну никаких сил. Если хотите расширить доступность вашей IDE — надо не выпускать ее под iPad, а лучше снизить потребление памяти вдвое. Пользуясь случаем, напомню, что по части скорости обскакать Atom/VS Code все еще есть куда (с Sublime Text уже сложнее).

Наравне со скоростью всегда будет цениться хороший UX. Буквально, если вам нужно ворваться на рынок IDE — просто берете и делаете нормально. Тут как-то даже и конкуренции особой нет.

Вот, например, я потихоньку собираю скриншоты проблем в Idea и VS Code (для отдельного поста):

Пользуясь случаем, напомню, что количество фич ≠ хороший UX. Мало сделать правильные фичи, нужно еще удержаться и не делать неправильные/ненужные/бесполезные. Feature bloat — анти-фича, и это как раз та дыра, куда сейчас летит VS Code. У них слишком много рук и слишком много свободного времени, поэтому на запуске она уже выглядит как зведолет. А значит, это еще одна возможность обскакать лидера рынка.

В общем, если будете вдруг делать IDE — успехов!

Облака и коробки

Я с Дропбоксом чуть ли не с самого открытия. Посмотрите какую милоту они рассылали в 2009:

Вышло приложение под айфон 3! Уииии!

Великая вещь, революция, без него не было бы ни Google Drive, ни iCloud Drive, ни OneDrive, ни Yandex Drive, ой, простите, Yandex Disk.

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

Потом пошли звоночки. В 2016 Дропбокс выпустил Paper — свой редактор документов, типа Google Docs (на самом деле hackpad, конечно). Ну окей. При чем тут Дропбокс, синхронизация файлов? А ни при чем, просто сделали вот. Ладно. Не помогает, но вроде как и не мешает.

Ага-ага, как-то так и проходят все наши рабочие совещания. Собираемся вокруг стола и коллаборативно редактируем документ, каждый со своего телефона/планшета/ноута. Разговаривать тоже не разговариваем, прям в комментах переписываемся. Зачем покидать интерфейс, если он такой секси? (выглядел он и правда не так старперски, как Google Docs)

И вот в 2017 Дропбокс делает редизайн. Прикольно, свежо, но... При чем тут Дропбокс, опять же?

Поясню. Гений дизайна Дропбокса в том, что это абсолютно утилитарная штука, которая очень-очень нужна и которой почему-то не было. Тот редкий случай, когда вещь продает ТОЛЬКО ее функция. Ну типа как соль, или картошка — сколько ее не рекламируй, купят ее ровно столько, сколько нужно дома. Поэтому хороший дизайн облачного диска — максимально невидимый дизайн. У него не должно быть интерфейса, иконки, сплеш-скрина, емейл-рассылок, попапов, нотификаций. Ты не должен про него вспоминать в принципе. Пока он выполняет свою фунцкию, это просто часть компьютера, чем невидимее, тем лучше.

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

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

А вот и линеечка продуктов на 2019. Скупай-поглощай!
А вот и линеечка продуктов на 2019. Скупай-поглощай!

И вот в начале года покупаю я себе новенький телефон. Ставлю привычно Dropbox. И что вижу? Дропбокс теперь может работать только на 3-х устройствах!!! А у меня УЖЕ девять, и это я не особо старался. По мелочи в основном.

Тут надо упомянуть про бизнес-модель того самого Дропбокса. Я, при всей моей гигантской к нему любви денег ни разу не заносил. Потому что у них совсем дебильная сегментация — либо сиди на бесплатных 2 Gb, что конечно преступно мало, либо покупай сразу 2 Tb за 120 Eur/year, что как бы чуть больше чашки кофе. А посередине ничего нет. Так что я сидел с бесплатным.

Помню, в какой-то момент я даже табличку составлял, в которой считал, какой хостинг эффективнее. Кроме Google Drive, конечно, им в принципе нельзя пользоваться, его как будто студенты писали. Сейчас не знаю, но пару лет назад у него на Маке иконка была кривая и не-ретиновая!

Это на 2015 год
Это на 2015 год

Короче, надо мемуар этот сворачивать. Выбрал Эппл. Типа, у меня и так все устройства Эппл, последним как раз новый телефон стал, плюс у них 50 Gb всего за 59 руб./мес, типа, в 10 раз дешевле. Я, как человек, десять лет умещавшийся в 7 Gb Дропбокса, больше и не прошу!

Это был stupidly good deal, и план был безупречен. Уж Эппл-то не будет пихать фичи в синхронизатор файлов! Уж Эппл-то сделает его настолько ненавязчивым, насколько это возможно.

Сделал. Блин. Я в него все перенес. Рабочие проекты, документы, поездки — все, как я привык, тока теперь в Эппле. И что?

Во-первых, если Дропбокс находился в ~/Dropbox, то где находится iCloud Drive? Конечно же в ~/Library/Mobile Documents/com~apple~CloudDocs. Мало того что это хрен напечатаешь, хрен изменишь, мало того что это чисто эстетически некрасиво, в пути есть еще и пробелы! А что у нас происходит, если какой-нибудь bash-скрипт обнаруживает себя в папке с пробелами? Правильно, он обсирается! Что предсказуемо со мной и случилось.

Ладно, но мы же умные. Хардлинков в APFS нет, но есть Soft links. Линкуем ~/Library/Mobile Documents/com~apple~CloudDocs в ~/iCloud и вуаля! Теперь это можно хотя бы набрать в терминале. Но! Особо умные скрипты делают что? Сначала резолвят себя до канонического пути, а потом уже обсираются!

Смешно? Мне не очень. Раньше я хранил Fira Code (которая билдится через venv) и tonsky.me (bundler) в ~/Dropbox/ws, с iCloud я теперь так не могу. И ничего, ничегошеньки сука с этим не сделаешь!!! Как бы мне ни хотелось сказать, что фиксить эти проблемы должны разработчики тех скриптов, а не Эппл, какого-то конкретно виноватого здесь нет, а до всех не достучишься. Увы, это уже просто факт жизни — папки с пробелами в шелле не работают. Привет изобретателям shell command language. Текст победит!

Но и Эппл тоже молодцы. Что мешало положить iCloud Drive в нормальное место? Да ничего не мешало! Но мы же умные, думаем outside of the box. Поэтому положим его хрен знает куда, чтобы ты не мог найти свой диск ни в каком файндере или терминале, а потом, осознав что людям может все-таки понадобиться в него заходить, потому что нахрена мне диск в который я ничего не могу положить/достать, накодим еще миллион строк кода чтобы в файндере была специальная иконка, в диалогах iCloud рисовался тоже отдельно, типа это что-то специальное. Ау, это просто папка!

Кстати, знаете, что будет, если попросить macOS синкать содержимое вашего рабочего стола через iCloud? Нет, она не начнет его синхронизировать. Как говорили в великом Generation Kill, “That would be not retarded enough”. Она ваш десктоп тоже спрячет в свой говнопуть так, что никак кроме опять же специально обученного файндера вы его не найдете. То есть это ломает все, абсолютно все альтернативные способы навигации по ФС, начиная от терминала, конечно, продолжая альтернативными файл-менеджерами, не-нативными диалогами, кросс-платформенным софтом. Просто потому что fuck you, that’s why.

Ладно. Во-вторых. У него реально нет интерфейса. Ну то есть прикольно, конечно, все максимально прозрачно, но если например сейчас не очень подходящий момент для синхронизации (слабый wifi или раздаешь с мобилы), то нет кнопки, чтобы поставить iCloud на паузу. Положил гигабайт на другом компе неделю назад — будь добр выкачать! На слабых ноутах это еще и ставит систему раком. Терпи.

В третьих, я же тут не один живу! С Дропбоксом у нас в семье выработалась система, когда мы шарим все документы и билеты через общие папки. Удобно, всегда под рукой, всегда знаешь где смотреть.

Ну и с iCloud хотелось бы устроить так же. Иду я значит шарить папки. Низя. Не желает ли милорд проапгрейдиться до Семейного плана за жалкие 200 rub/month. Ну ладно, не совсем то что я хотел, но уже как бы ввязался до определенной степени. Че уж, раскошелимся. Раскошелился. Создал семью. Стал организатором.

Иду в Files. Жму Share (потому что у Эппл традиционно все функции прячутся в Share, это типа More). Ну как бы ничего не вижу. Ладно. Читаю. Пишут, а Share-то и нет! Вселенский фейспалм. Не сделали. Эппл. Не сделали. Ололо. Вся моя схема разом рухнула. Два iCloud Drive-а не подключишь. Под одним аккаунтом не зайдешь, потому что: ИНТЕГРАЦИЯ! ЭКОСИСТЕМА! Если ты не хочешь одновременно с этим также читать чужие сообщения и пароли, лучше все-таки логиниться каждому под своим аккаунтом.

И вот о чудо. В какой-то статье читаю, что это ПОКА нет шаринга. Но типа будет. В iOS 13. Которая как раз выходит через неделю! Это конечно идеальный тайминг, потому что если бы я этого не прочитал, я бы точно что-нибудь разбил поблизости.

Ладно. Жду iOS 13. Выходит. Обновляю в тот же вечер. Иду в Share наутро. Не вижу никакого общего доступа. Но можно поделиться папкой через iMessage. Ладно, думаю, это же Эппл. Наверняка они как-то хитро это интегрировали, что все настолько самоочевидно и simply works (tm) что пока не загуглишь не поймешь. Шарю папку по iMessage. И что получаю?

ZIP, блядь, архив. Охуеть синхронизация, так я тоже могу. Спасибо что не письмом.

Пора идти в Гугл для тупых. Оказывается. Оказывается. Оказалось, что планы на фичу были. Даже в бетах она вроде как была. Но Эппл передумал и убрал. До iOS 13.1. А я сижу у разбитого корыта. От Дропбокса ушел, а в Эппл не пришел.

Самое обидное знаете что? Что для шаринга папок и делать-то ничего не нужно. Точнее, все уже сделано. У вас уже полноценная синхронизация между N устройствами. Добавить еще одно, независимо от того, кому оно принадлежит, ТЕХНИЧЕСКИ не представляет никакой проблемы. Технически это просто еще один клиент, точно такой же, как все остальные.

Но мне кажется я знаю почему эта фича так долго откладывается. Дело в том, что инженеры—наберите сейчас праведного гнева в грудь—инженеры Эппла решают, куда бы еще хитрее запрятать шареные папки. А то ~/Library/Mobile Documents/com~apple~CloudDocs слишком уж быстро вычислили.

UPD: 13.1 вышел, шаринг не добавили, отправку папок zip-архивом отключили обратно. Удивляться не приходится :(

UPD2: С момента написания поста iCloud отказался в критически важный момент загружать документы на телефоне (при прекрасном LTE коннекте). Просто крутил ползунок как дебил битый час и все. Apple Photos, как оказалось, не умеют шарить фотки. Так что моя логика «все равно за iCloud платить, т.к. там фотки с айфона хранятся» разлетелась в щепки. Ну что же, пора снова составлять табличку и выбирать провайдера, походу.

pub mod fiasco

Лучший язык, в котором правильно сделаны модули (ну или неймспейсы) — Кложа. Один файл === один неймспейс. Неймспейс может называться только так, как называется файл, и никак иначе. И лежать он должен тоже ровно по пути пакета. То есть (ns me.tonsky.hello) может и должен лежать в me/tonsky/hello.clj и нигде иначе. Сначала меня это почему-то напрягло — эй! свободу ограничивают! а как же самовыражение??? Это при том что в остальном Кложа — довольно либеральный язык и позволяет любую другую дичь творить спокойно и вообще говоря это чуть ли не единственное место, где абстракция «как организовать свой проект на файловой системе» протекла в язык, который, вообще говоря, весь такой интерпретируемый, динамичный, код может есть с руки и про файлы ничего не знает.

Но потом я проникся и оценил, особенно когда в других языках поработал. Кайф в том, что это не позволяет разводить бардака. Потому что в жизни, даже если все люди хорошие, рукопожатные и намерения у всех без исключения самые добрые, если бардак физически что-то не мешает развести — его разведут. Ну вот Кложа мешает. Живите с этим. И живут! И как живут!

Тут-то судьба забросила меня в Балтийское море, на остров Котлин. У Котлина какой основополагающий принцип? Если где-то что-то запрещают, у нас разрешают! Все обиженные, обездоленные приходите к нам и творите что хотите. Этот же принцип применен и к файловой системе. В Джаве ведь как? Один файл == один класс. Какое расточительство! В Котлине один файл == сколько угодно классов, объектов, функций, констант и чего угодно еще. Более того, файл может объявлять объекты в пакете, в котором он даже не находится. То есть какой-нибудь src/main/kotlin/me/tonsky/hello.kt может спокойно объявлять package go.fuck.yourself; и никому за это ничего не будет!

Что же тут не так? Помимо самоочевидного бардака, становится довольно сложно понять, где что находится. Скажем, ищу я класс me.tonsky.Draggable. Смотрю в me/tonsky/ папку а там layout.kt, main.kt и scene.kt. Ну офигеть! Класс может быть в любом. То есть на самом деле это не один файл содержит множество объектов. Это один модуль размазан на несколько файлов с ничего не говорящими названиями. Разница тонкая, но существенная.

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

Все это, конечно стимулирует продажу IDE от одноименной компании, но почувствуйте разницу! Язык, разработанный на деньги IDE вендора, и язык, который при разработке не предполагал, что у вас вообще будет какой-то редактор (а судя по форматированию классов в clojure.lang писал его Рич в блокноте и пропорциональным шрифтом).

А потом вскрывается еще одна беда — разные файлы-то, получается, срут в общее пространство имен! То есть если ты в oops.kt написал val default = 1, то у тебя вдруг перестал работать wtf.kt про который ты даже не слышал, просто потому что он тоже определил val default = 0 когда-то а в алфавите W идет после O. Никакой изоляции. Не будешь же, в самом деле, по папке с одним файлом заводить на каждый класс. Сомнительное, короче, удобство.

А потом я пришел в Раст. Его систему с модулями я настолько не понял, что специально сейчас сидел перечитывал. Итак:

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

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

Как следствие, Раст позволяет ссылаться на над/под-модули с помощью относительных путей. Я тоже думал, что это давно пройденный урок и уже все без исключения на планете знают, насколько это хреновая идея: относительные пути не ищутся, легко путаются, плохо рефакторятся, плохо копи-пастятся и вообще слишком хрупки и зависимы от контекста, чтобы экономия пары-тройки букв оправдывала их существование. Просто сразу нет.

Раст позволяет импортить как модули, так и отдельные типы. Причем синтаксис общий. Что создает еще больше путаницы. Модуль — это неймспейс, средство изоляции имен, не больше. Тип — это уже что-то полезное. Давайте уже как-то разделять.

Видимо, по старой доброй C-традиции, в Расте сделали include вместо import. То есть когда ты говоришь use module, ты не просто создаешь некий синтаксический псевдоним, действующий исключительно до конца файла для разрешения имен. Нет, ты буквально добавляешь все что было в module в текущий файл. Не сослался, а скопировал и вставил себе. Это плохо, потому что вместо понятной модели «есть штука, она одна и существует там, где написана, плюс есть способы сослаться на штуку, псевдонимы, они могут быть любыми» мы получаем «одна и та же штука, размноженная N раз в N местах». А я еще удивлялся, почему одни и те же функции и из std::, и из core:: торчат. Вот почему!

Ну и на вишенку, модуль определяется не в том файле, где он написан, а в его родителе! Скажем, если вы сделали govno.rs, и написали в нем код, вы потом идете в lib.rs и в нем уже пишете mod govno;. Или, если хотите, определить его публично, pub mod govno;. То есть понимаете, да? Если вам интересно, торчит ли govno.rs наружу, вы не можете зайти в него и посмотреть. Вам нужно сообразить, кто его родитель, найти в этом родителе (в произвольном достаточно месте) надпись mod govno; и там узнать, есть ли префикс pub у него. Если вы хотите создать какой-то достаточно глубокий модуль, скажем, kak::zhe::vse::zaebalo, вам нужно пойти и создать всех промежуточных родителей и в каждом написать ровно по одной строчке:

lib.rs:
pub mod kak;

kak.rs:
pub mod zhe;

kak/zhe.rs:
pub mod vse;

kak/zhe/vse.rs:
pub mod zaebalo;

kak/zhe/vse/zaebalo.rs:
<your code here> 

В каком-то смысле это все следствие относительности имен и «удобства» их использования. В каком-то — следствие концепции вложенности. Этот пример прекрасно ее иллюстрирует: слишком много возни, слишком много вопросов, а в чем профит не ясно. Скажем, если модуль kak будет публичным, zhe — нет, vse — тоже нет, и наконец zaebalo — публичным. Смогу я его в конце концов заимпортить? Если нет, то в чем смысл pub в pub mod zaebalo;? Если да, то в чем смысл того, что промежуточные модули — приватные? И сколько файлов мне придется посетить, чтобы вычислить, доступен ли zaebalo для импорта?

Короче. Я не очень понимаю, как тут можно запутаться, но опыт показывает что путаются все и постоянно. Модули — плоские. Пути — абсолютные. Один файл === один модуль. Все, что надо знать про модуль, написано в нем самом. Будете делать свой язык — смотрите не объебитесь.


Депрессия год спустя

Ровно год назад я написал «Историю одной депрессии». Самое время подвести итоги.

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

И что вы думаете? Он конечно поугарал над самостоятельно поставленными диагнозами в ЖЖ, но согласился что они не неправы — это депрессия. Нормальная, неиллюзорная, медицинская.

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

Первые три месяца я тупо лежал на диване. С трудом поигрывал в одолженный у друга плейстейшн. Это совсем не такое райское времяпрепровождение как может показаться, просто ничего другого делать не можешь все равно. Ты просто терпишь и убиваешь время, ждешь, когда же уже станет наконец лучше. Фотографии периода пика болезни до сих пор вызывают во мне внутреннее содрогание, кстати. То есть на них ничего такого нет, но вот ощущения запомнились. Do not recommend.

Через три месяца деньги подошли к концу, я начал брать какие-то небольшие контракты. Работалось конечно с трудом. Особенно угнетал страх, что ты с кем-то договорился, пообещал, а организм подведет тебя и у тебя не будет сил работать. Короче худо-бедно я что-то сделал, хотя в фактическая работа была очень далеко от моего идеального представления о себе.

Одна из вещей, которые я изменил — начал ходить в коворкинг. Все-таки когда вокруг тебя какие-то люди, живые, энергичные, и периодически тебе надо выходить на улицу — организм это замечает. А вот сидеть днями напролет дома на кухне за ноутом, одному, когда максимальное перемещение которое ты можешь сделать — до туалета и обратно (а это не так много в однокомнатной квартире) — это на чисто физиологическом уровне что-то в организме убивает. Я до сих пор немного внутри пугаюсь когда пытаюсь присесть на кухне поработать. Не надо так. 

Тогда же примерно я запустил Патреон, который существенно помог мне продержаться до конца моего импровизированного саббатикала — спасибо еще раз всем подключившимся! Работать над своими проектами кстати гораздо веселее, может быть потому что они уже состоялись и там все сделано именно так, как мне нравится. А может быть, потому что приятно видеть что это именно мои идеи. Так или иначе, до сих пор это единственное, что вызывает во мне эмоциональный отклик и живой интерес. Когда мне на работе совсем грустно, я вспоминаю, что можно что-то небольшое пофиксить, приладить, кому-то ответить, помочь. И все у себя. Ни с кем не согласовывая, не консультируясь, без всякой ответственности. Ровно и только так, как я хочу. Рекомендую.

Что с интересом к программированию, то он так до конца и не вернулся. Весной я пытался искать работу, пособеседовался в несколько стартапов, в несколько больших компаний, и везде меня охватывало отвращение при одной мысли, что это опять все то же самое, опять это скучное унылое программирование, веб проекты, опять те же тормоза, глюки и люди, которым на это глубоко пофиг, лишь бы продукт вышел поскорее и похуже. Рефлексируя над причинами, которые заставили меня написать Software Disenchantment, я понял что всего этого не хочу. Что просто физически не могу писать очередной медленный отстойный электрон-или-прости-господи-браузер-апп, который к тому же ничего не значит и ничего не изменит. Как бы ни хотелось каждому основателю стартапа, его супер-уникальный-свежий-современный-вылизанный продукт — просто унылое, никому не нужное, высосанное из пальца говно (не пытайтесь это представить), а все эпитеты ничем не подкреплены. Может это конечно со мной что-то не так, или я не там ищу, но ощущение что никто даже не думает пытаться сделать хорошо и качественно конкурентым преимуществом, хотя попиздеть про это любят за милую душу. Устроился, кстати, я пока в JetBrains, но не над самой IDEA работать конечно, а на research-проект, где мы пытаемся научиться делать редакторы быстрыми и легкими. Посмотрим, как пойдет.

Ну и самый главный результат: мне больше не хуево. Те самые таблетки произвели вполне неиллюзорный эффект: депрессия ушла, симптомы ушли, мне больше не хочется лежать на диване и забиваться в угол, не нужно изображать энтузиазм или интерес, когда их нет, зато хочется постоянно улыбаться. Нет, серьезно, самое странное, на чем я себя ловил — когда никакого повода нет, ты идешь/сидишь сам с собой, и уголки рта самопроизвольно чуть приподняты. Не то чтобы мне вдруг внезапно все вокруг стало нравиться (см. выше), но общий депрессивный фон, который, скажем, автоматически добавлял ко всем ощущениям -10, теперь добавляет +0. Это самое лучшее, наверное, как я могу произошедшее описать.

Ой, простите, это старая фотка. Вот:

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

На что я хочу заметить:

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

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

“Have you ever tried not having a diarrhea?”

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

Все это я пишу, чтобы заметить, нет, депрессия не в головах. Это не пресловутое «нет настроения», а вполне конкретный физическо-химический процесс, с которым никакое количество «думай позитивно» и «не грусти» так просто не справятся. Если ты проснулся без энергии — сколько не старайся думать позитивно, энергия ниоткуда не возьмется. Советы вроде «Хватит выгорать. Перестаньте это делать. Не выгорайте» вот реально бесят. Тебе мало того что хуево 24/7, тебе нужно это еще кому-то там доказывать, чтобы к твоим словам отнеслись серьезно? Идите в лес с такими советами.

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

Так что, как говорит мой терапевт, не болейте!

С высоты-3

Пост вызвал некоторую дискуссию, в связи с чем я не перестаю удивляться, насколько людям кажется что мир устроен так как им хочется а не так как он устроен на самом деле. Многие живут мыслью что то что они (ну или я) пишу это не настоящая Кложа, а где-то там далеко есть настоящая, и если сильно припрет то взял type hints и поправил и так-то и пишут настоящие джедаи. У них все всегда сразу достигает JVM-уровня скорости потому что они сразу везде указывают примитивные лонги и вообще все специфицируют и раскладывают сразу оптимально. Ну или разложат если будет нужно.

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

Так вот. Я сам не то чтобы чужд оптимизациям и натягиванию ужа на ежа. Я потратил достаточно много времени, пытаясь делать разные вещи быстрее, чем они есть. Придумывал какие-то оптимизированные defrecords в DataScript. Менял функции на макросы для инлайнинга. Городил макро-DSL для работы с массивами. Писал макросы, которые эмитят сразу оптимальный JS. AOT-прекомпилял Кложу в классы для быстрого стартапа. Видел тоже разного: всякие библиотеки для быстрой математики, патченные исходники с отложенной инициализацией var-ов, фоновые «прогретые» JVM для быстрого старта. Даже мантра «держи репл всегда запущенным» в общем-то про то, как бороться со тормозами на старте Кложи. Про все это можно сказать одно: это очень изнурительно, и удовольствия в этом никакого нет, только сложность и постоянное разочарование.

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

Но если уж ввязался, то просто делай как все — будет проще, приятнее и честнее. Если язык предлагает records, бери и используй records, а не городи свой хитрый макрос на deftypes. Если нужно позвать функцию — значит, нужно позвать функцию. Если компилятор при этом продалбывает arity в метаданных, чтож — значит, продалбывает, такова цена. Так устроен язык. Хорошо, если это просто по недосмотру и можно отправить патч в компилятор. Если нет, что ж. Все равно нормальный, обычный код, собранный из того, что дают, в конечном счете, на длинной дистанции, выигрывает именно своей простотой и нормальностью. Потому что локальные оптимизации всегда останутся локальными и будут только мешаться под ногами непредвиденным образом; чем дальше, тем больше.

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

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

Как верно подметил древнегреческий поэт Архилох (да, я тоже только что его нагуглил и тоже только что офигел), в критической ситуации ты не вырастаешь до уровня своих ожиданий, а падаешь до уровня своей подготовки. Ваша программа не будет написана из тысячи выдроченных микроциклов, она будет написана из тысячи самых обычных, рядовых функций, на многие из которых никто даже второй раз никогда не посмотрит, не то что оптимизации начнет расставлять. Поэтому глупо жить мечтами, что если быстрый код в принципе, теоретически, как-то где-то можно написать, то он везде почему-то будет написан. Не будет. Потому что это неудобно, противоестественно, не нужно. Из «на Кложе можно писать быстро» не следует «код на Кложе будет быстрый». Не будет.

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

[...] при разработке на Кложе удобно думать в математических понятиях (а хешмэп это пожалуй самая близкая к функции структура данных). При разработке на Расте это кажется прямо-таки немного противоестственным, и хочется уже взять плоский кусок памяти, и как-то там его расчерчивать.

Язык определяет мышление, best tool for the job, вот это все. Банально, но на конкретном примере оно всегда как-то доходчивее.

С высоты-2

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

Ну и что я сделал. Я пошел учить Rust. Не, ну интересно же, как компьютеры сегодня могут, если их правильно попросить.

Чтобы потренироваться я портировал на Раст наше решение из ICFPC. Причем портировал точь-в-точь: все те же структуры данных, те же алгоритмы, те же константы. Ну разве что не персистентные: там, где в Clojure update, в Rust у меня clone() и только потом push/insert, потому что в комплекте персистентные структуры не идут, да и так идиоматичнее. Важно: я не пытался что-то улучшить, срезать углы, реализовать покрасивее, нет: я написал ровно то, что мы и на Clojure написали. Ну, чтобы сравнение было честным.

Как только мой решатель начал что-то решать, я сразу же побежал сравнивать производительность. Rust ожидаемо вырывался вперед, но не на безумные цифры. Типа, вместо 4-5 секунд на задачу решал за три. Я даже собрался уже разоблачающий пост писать, что мол язык не важен, важны структуры данных и алгоритмы, в них весь перформанс, а не в том, на каком языке вы их записали. Потом, правда, коллеги подсказали, что я забыл снять с ручника, то есть запускал Rust в debug-билде. Ну и конечно, стоило поставить --release, как скорость выросла раз в двадцать. Впечатляет, да?

Самое печальное тут в том, что это все время на одну и ту же работу. Чистый оверхед. Программа на Clojure не выдает какой-то более умный или точный или качественный ответ. Она приходит к тому же финишу, только к ногам привязаны огромные 20-кратные гири. Раст на одном ядре обгоняет Кложу на двенадцати ядрах в 3,5 раза!

Можно было бы сказать «но это же низкоуровневый язык, как на нем можно что-то писать»? Писать было непривычно, потому что язык новый, но по ощущениям ничего особенно сложного, когда научишься. Приходится внимательно следить, что в каком порядке выделяется и кто куда что передает, но в нормальной программе оно обычно и так нормально разложено. Скажем так, Раст не дает тебе развести беспорядок там, где другие языки даже бы не обратили внимания. Да, это еще одна забота, но не ужас-ужас что прям программировать невозможно. Кода кстати сравнимо, 800-900 строк.

Зато 17 раз!!!

Исходник и голые цифры. Выводы делайте сами.