Про телеметрию
TLDR: следить за пользователями — это обычно плохая идея.
Вроде бы это должно быть очевидно (с точки зрения пользователя), но у всяких там продактов иногда возникает соблазн “собрать немного данных”. Поэтому некоторое время назад я решил поисследовать эту тему поглубже, чтобы иметь более аргументированную позицию.
Источники
Есть отличная серия постов от разработчика Go, в которой разобраны плюсы телеметрии, аргументы за нее и обозначены лучшие практики по ее внедрению. Вкратце:
- Баг-репорты содержат недостаточно информации.
- Опросы пользователей содержат недостаточно информации и нерепрезентативны.
- Многие негативно относятся к телеметрии из-за в основном предубеждений и стереотипного мышления (“они собирают каждый наш клик!”), но в некоторых случаях это вовсе не преувеличение.
- Без статистики использования непонятно, какие функции используются/нужны, а какие нет, и время разработчиков может быть потрачено впустую.
- Пользователи не знают, как должно вести себя ПО, поэтому не дают достаточно хорошие баг-репорты, а некоторые проблемы могут остаться незамеченными несколько релизов.
- Телеметрия должна быть прозрачной: надо собирать как можно меньше данных, показывать пользователю, что собирается, не содержать идентификаторов, ее должно быть легко отключить, данные должны быть текстовыми.
- Решение о внедрении телеметрии должно быть публичным.
- Собирать со всех все не нужно, достаточно сравнительно небольшой выборки для репрезентативных данных.
- С каждой установки данные собираются не постоянно, а изредка.
- Все собранные данные должны быть публичны.
- Телеметрия должна быть включена по умолчанию, но ее отключение должно быть простым.
Последний пункт был отредактирован, потому что после обратной связи от сообщества разработчики решили отключить телеметрию по умолчанию, т.е. пользователь должен осознанно ее включить. Вообще, opt-in (телеметрия по умолчанию выключена) против opt-out (включена по умолчанию) — один из ключевых вопросов в этой теме. В этой же серии постов можно прочитать про это подробнее: тяжелее получить данные, надо пиарить подключение, согласившимся нужно будет чаще посылать данные, будет перекос в собранных данных и т.п.
А есть мнение, что замена на opt-in сделает телеметрию бесполезной. Т.е. по сути opt-out — плохо для пользователей, а opt-in — бесполезно для разработчиков. Но в той же статье есть и аргументы за телеметрию, причем в оригинальном видении из цикла статей. При этом отмечается, что не последнюю роль в негативной реакции сообщества сыграло то, что автор предложения работает в Гугле (а он уже давно не “don’t be evil”).
Разработчики Audacity хотели внедрить телеметрию, но в итоге после негативной реакции пользователей пришли к более скромному варианту, который покрывает только вопрос более подробных баг-репортов.
Некоторые аргументируют, что телеметрия бывает разной, и не вся телеметрия — это слежка, а стоит думать о ней как о голосовании, мол, ваш “голос” будет учтен. И вообще, open source разработчикам тяжелее получать данные о пользователях, чем разработчикам проприетарного ПО.
Если почитать статьи про телеметрию с более пользовательской точки зрения, то там будут в основном негативные или язвительные комментарии. Примеры:
- Telemetry is definitely your enemy
- The Telemetry Fallacy
- Fedora Project mulls ‘privacy preserving’ usage telemetry
Отдельно можно отметить комментарии на HackerNews, тысячи их:
Там есть мнения как с точки зрения пользователя, так и с точки зрения разработчика.
Я постарался как-то это все агрегировать ниже.
Аргументы “за”
Вкратце: Больше данных хорошо, проще получать инсайты, проще приоритизировать задачи и развивать продукт.
- Без телеметрии невозможно собрать статистику об использовании продукта.
- Статистика использования позволяет приоритизировать разработку функциональности.
- Статистика позволяет удалить ненужную функциональность без негативных последствий.
- Люди лгут, телеметрия — нет. Опросы пользователей содержат недостаточно информации и нерепрезентативны.
- Телеметрия позволяет обнаруживать проблемы, о которых люди и не задумывались.
- С телеметрией предоставляется больше данных чем в обычных баг-репортах.
- Баг-репорты требуют усилий и не все пользователи их отправляют/могут отправить, телеметрия экономит усилия пользователя по отправке данных.
- Телеметрия позволяет делать более надежные продуктовые решения. Без данных принимаются плохие решения.
- Телеметрия — это способ “голосования” людей за улучшения в продукте.
- Обратную связь разработчики получают только от самых “говорливых” пользователей, а с телеметрией — от всех.
- Понять сценария использования системы и интегрировать эту информацию в процесс разработки и тестирования весьма тяжело без метрик.
- Тяжело тестировать оптимизации ПО без метрик с пользовательских машин, держать парк своих серверов для тестирования производительности — дорого.
- Телеметрия может помочь создать более прибыльный продукт.
- Все веб сервисы и так собирают данные при каждом обращении к сервису, чем телеметрия хуже?
- Большинству пофигу на “приватность”.
Аргументы “против”
Вкратце: данных и так полно, качество данных от телеметрии сомнительно по многим причинам и не даст всей картины, на основе телеметрии можно сделать неверные выводы, надо думать о ИБ.
- У вас и так полно данных о платформах, которые вы получаете от статистики установок, User-agent и т.п. Интернет так работает и всех это устраивает, т.к. большинство понимает, что посылается и когда. Активная отсылка данных с клиента — плохо, потому что это вторжение на пользовательский клиент, которое пересекает границу, созданную браузером/протоколами.
- Обложите бекэнд трейсингом, и получите дофига данных.
- Если у вас не веб-приложение, то вместо телеметрии можно добавить функциональность по отправке ошибок.
- Если у вас не веб-приложение, то возможно ваши пользователи достаточно умны, чтобы написать нормальный баг-репорт.
- Если вы не знаете, как работает ваш продукт или что нужно пользователям, то телеметрия не решит проблемы вашей разработки. Наймите нормального продакта и нормально делайте исследование своих пользователей, прежде чем внедрять телеметрию. Желание внедрить телеметрию может быть сигналом о том, что продукт стал таким сложным и/или хрупким, что пользователи не напрягаются давать обратную связь. Или отправить баг так сложно, что никто этим не заморачивается.
- Просто данных недостаточно для того, чтобы делать какие-то выводы. Нужно строить гипотезы и подтверждать их, иначе это будут просто догадки. Легко “переоптимизировать”. Любая метрика перестает быть хорошей когда она становится самоцелью. Для оценки качества есть соблазн использовать эту же метрику. Телеметрия не покажет ни намерений, ни эмоций пользователя.
- Если фича редко используется, это не значит, что ее можно удалить (аргумент про огнетушитель и бэкапы).
- Телеметрия может быть формой дискриминации: “только 5% пользователей пользуется фичей, давайте ее удалим” или “если ты не шлешь телеметрию, то твое мнение не учитывается”.
- Разработчики опенсорса не должны заботиться о том, как используют их бесплатное ПО пользователями, которые ничего не дают им взамен. А ответственные пользователи помогают проектам, открывая пулл-реквесты и баг-репорты.
- Телеметрию нельзя использовать на удаленной фиче или на желаемой фиче, для этого надо использовать другие источники информации и знать своего пользователя.
- С телеметрией легко скатиться к “среднему пользователю” и “среднему по больнице”, что обычно плохо.
- Для новой фичи данные будут искажены из-за ранних пользователей и не дадут хорошей картины.
- У вас и без данных от телеметрии полно работы (кто-нибудь работал в успешном продукте, где не было большого бэклога?). Если у вас есть четкое видение продукта и вы нормально исследуете пользователей, то у вас достаточно и работы и приоритетов.
- Многие продукты больших компаний (Google, Facebook и т.п.) обложены телеметрией — становятся ли они со временем лучше? Точно ли телеметрия дает выгоду пользователю?
- Анонимизация снижает качество собираемых данных, но при этом способы деанонимизации совершенствуются. Т.е. если данные нормально анонимизировать, то они станут бесполезны, а если это не делать — то это нарушит приватность пользователей. Некоторые еще переживают, что с ИИ анонимность вообще недостижима, а пользователей с уникальными (странными) окружениями легко сдеанонить фингерпринтингом.
- Если продукт с открытым исходным кодом, то легко его модифицировать, чтобы посылать мусор вместо данных.
- Компании плохо заботятся о ИБ, данные пользователей рано или поздно утекут. Даже если собираемые данные надежно защищены, не факт, что это не поменяется в будущем или что они не будут слиты по первому запросу госорганам.
- Opt-out — плохо для пользователей, а opt-in — бесполезно для разработчиков.
- Opt-out — в серой зоне с точки зрения легальности (с точки зрения GDPR и конвенций ООН).
- Телеметрия выгодна только разработчикам и нужна, чтобы сократить расходы.
- Телеметрия может быть первым шагом к агрессивной монетизации и сместит фокус разработчиков на платных пользователей. Будут внедрятся только те фичи, которые прибыльны, а не те, которые полезны пользователям.
- Телеметрия должна быть прозрачной, но публичные данные о статистике пользователей могут быть использованы против вашей компании.
- Если продукт был успешен X лет без телеметрии, то действительно ли она необходима? Как-то же справлялись разрабы раньше без нее.
- Всегда будут люди, которые откажутся от телеметрии, и это чаще продвинутые пользователи. А еще телеметрию может быть заблокирована блокировщиком рекламы, если у вас веб-приложение.
- Телеметрия — потенциальная брешь в системе, как со стороны клиента, так и сервера, и увеличивает поверхность атаки.
- Телеметрия — это доп. расход ресурсов, как пользователя, так и компании. Если все программы будут собирать телеметрию, приведет ли это к чему-то хорошему? Чем ваше приложение такое особенное, чтобы делать это?
- Если решение принимается децентрализовано, сообществом, то будет достаточно мнений, чтобы обойтись без телеметрии.
Итого
В основном телеметрию хотят разработчики, а пользователи (которые высказывают свое мнение) в целом против нее.
Большинству пользователей на все выше скорее всего насрать. Приложения на телефоне и какой-нибудь поиск гугла или хром собирают о вас столько данных, что вас можно будет заменить роботом и никто не заметит. Ну и, увы, как-то странно верить, что в мире осталась какая-то приватность, когда каждое устройство и программа что-нибудь собирают, улицы обвешаны камерами, а товар в бесплатных сервисах — это вы.
Доверие очень тяжело заслужить и легко потерять (“и невозможно забыть”:) ). Если прям надо-надо телеметрию, то лучше быть максимально прозрачными и следовать советам от разработчиков Go, а насчет opt-in или opt-out — думать, что лучше подходит. Но в первую очередь стоит подумать, а точно ли она нужна вообще (скорее всего нет). С ее помощью можно получить какие-то данные, но у них может быть сомнительное качество.
The more these things are happening and the more I read about it, the more I understand and agree with Richard Stallman.
Автоматический рефакторинг кода с помощью OpenRewrite
Попробовал применить OpenRewrite к репозиторию Gradle и если вкратце, то все очень плохо.
В официальной документации очень солидные заявления — утилита позволяет делать автоматический рефакторинг на основе рецептов, при этом код преобразуется в семантические деревья, к ним применяются трансформации и результат “минимально инвазивно” записывается обратно. Основная фишка инструмента, как я понял, заключается в том, что вы пишете правила для рефакторинга (или используете готовые), а потом применяете скопом к своей большой кодовой базе (возможно из нескольких репозиториев), экономя время на ручной труд.
Но реальность полна разочарований.
Подключение к проекту и запуск
Довольно быстро обнаружилось, что плагин для Gradle не поддерживает современные фишки: кэш настроек, параллельное выполнение (с весьма странным багом) и т.п.
Вдобавок к этому, парсер давился на Groovy файлах (у нас большинство тестов написаны на нем), что довольно странно, ведь вроде инструмент поддерживает Groovy.
Но это еще цветочки, эта приблуда еще пыталась обработать jsp
из ресурсов!
Т.е. она даже не понимает, где исходники и на каком языке, и видимо молотит все текстовые файлы подряд.
Через час (sic!) после запуска я получил… OOM. Возможно где-то есть утечка памяти, либо в самом Gradle, либо в плагине. Я в итоге плюнул и написал скрипт, который применяет утилиту к одному подпроекту за раз. Память пришлось поднять только для одного большого подпроекта.
Работает утилита, мягко говоря, не быстро: чтобы весь код прошерстить, ей понадобилось больше 2 часов (и это на топовом маке). Впрочем, насчет производительности разработчики вряд ли парятся — платный вариант как раз обещает ускорение за счет своей БД, чтобы не перестраивать семантические деревья каждый раз с нуля.
Сами изменения
Сначала я попробовал применить рецепт по миграции на Java 8 — первая версия Gradle была написана аж 2008, кода довольно много, и что-то могло остаться в “старом стиле”. Но этот рецепт никаких изменений не внес.
Далее я попробовал миграцию на Java 17 — там уже была куча правок, но не стал углубляться, т.к. ее обновление пока только запланировано.
Пока я ждал первого прогона, почитал документацию в целом и поискал, какие есть интересные готовые рецепты.
Инструмент очень сильно сфокусирован на Java (даже не JVM).
Кроме обновления версии Java я нашел только 2 интересных рецепта: CodeCleanup
и CommonStaticAnalysis
.
Там были и другие, например для обновления билд-скриптов, миграции на новую версию Hibernate и т.п., но большинство из них были довольно узко применимыми.
Сами изменения были не без ошибок:
- добавлялся
final
к свойствам, которые потом изменялись, и к классам, у которых были наследники; - удалялись/добавлялись параметры типов там где не надо;
- была добавлена куча пустых конструкторов (видимо, чтобы сузить область видимости), но ценности я в этом не увидел;
- пока не добавил исключения, Groovy файлы были обновлены по непонятным правилам: например,
as SomeClass
превратилось вasSomeClass
.
Отдельно отмечу упрощение условий: оно было настолько тупое, что заменило
!(methodName != null ? !methodName.equals(that.methodName) : that.methodName != null);
на
methodName == null ? !methodName.equals(that.methodName) : that.methodName != null;
что буквально вызовет NPE.
Тут у меня начались вьетнамские флешбеки от кривых #define
в Си, где надо было огораживать все скобками, иначе получится шляпа.
При этом IntelliJ через пару Alt+Enter заменит этот код на человеческий
Objects.equals(methodName, that.methodName)
Другой показательный пример:
public boolean isEmpty() {
return size() == 0;
}
был заменен на
public boolean isEmpty() {
return isEmpty();
}
Да-да, это классическая реализация StackOverflowError
.
Все вышеперечисленное приводило к ошибкам компиляции и к ошибкам от существующих средств проверки качества кода (-Werror
, ErrorProne, CodeNarc и т.п.).
Из-за этого я переписал скрипт, чтобы после применения рецептов к подпроекту запускалась компиляция.
Разумеется, это еще больше замедлило и без того небыстрый процесс.
И ошибки компиляции править приходилось вручную, так что продуктивность полетела прямиком в помойку.
Самое отстойное, что некоторые рецепты проще всего было бы отключить совсем, но такой опции у инструмента нет. *звуки грустного тромбона*
Вывод
Я был довольно упертым и все-таки применил рецепты ко всем проектам. В итоге было обновлено 1700+ файлов. Было ли там что-то такое, ради чего стоило проходить через эти пляски? Если кратко, то нет.
Были изменения в форматировании (местами сомнительные, типа Йода-условий или порядка модификаторов), манипуляции с импортами, упрощение условий (см. пример выше), везде была добавлена куча final
(даже там где не надо), лямбды были заменены на ссылки на методы, убраны ненужные параметры типов, мелкие изменения типа замены .size == 0
на .isEmpty()
или страшной восьмеричной системы с 0777
на понятную десятеричную с 511
.
Если ваша кодовая база маленькая, то вы вряд ли будете будете писать новые рецепты — проще руками через IDE все мигрировать. Если кодовая база большая, и есть платформенная команда, то скорее всего код и так уже будет довольно однородный и кучу вещей можно будет решить скриптом/простыми текстовыми преобразованиями. Кажется, рецепты имеет смысл писать только для чего-то специфичного. Самая потенциально полезная часть инструмента — общеприменимые рецепты (типа миграции Java), но их не очень много и покрывают они на удивление мало.
Но все это просто уничтожается качеством инструмента.
От чего-то, основанного на семантическом представлении, которое строится тыщу лет, я ожидаю, что итоговый код будет хотя бы компилироваться и не содержать очевидных ошибок.
А по факту все это не сильно лучше текстовых замен или #define
в Си со всеми их недостатками.
IntelliJ гораздо лучше понимает код и его контекст.
И такое ощущение, что с ней сделать те же операции было бы быстрее.
В общем, great idea, does not work.
P.S. Затеял я это все для того, чтобы посмотреть, какие есть инструменты для миграции кодовой базы с одного языка на другой. ChatGPT и прочие AI штуки сразу отмел, т.к. хотя с маленькими кусочками он и хорошо справлялся, но я думал, что недостаточно надежно будет его применять для большого количества кода. Но кажется для этой задачи он явно лучше этого изделия. Еще находил Txl, но он показался слишком сложным. Планирую попробовать его в будущем.
Сапер для вымышленной консоли на Nim
На выходных запилил игрулю, вариацию Сапёра.
Поиграть можно тут (с компа стрелочками удобнее, но на мобилах тоже работает), а исходники почитать — тут.
Про саму игру
Идея пришла в голову не слишком случайно. Недавно поставил себе классического сапера на планшет и залипал в него. Но с “аккордеонами” (которые рекурсивно открывают соседние ячейки если все однозначно) игра превращается в тупейший кликер на скорость. Прям думать-думать надо раза 2-3 за игру на “Профессионале”, и обычно после этого приходится делать случайный выбор.
“Ездить” по полю было намеренным решением. Кликать скучно, а так себя можно представить роботом, который уволился из доставки и пошел в саперы. В голове у меня застряла прочная ассоциация с Bomberman, в который тоже недавно играл, — там тоже кто-то ходит и связано со взрывами, но общего тут только ходьба по большому счету.
Получившаяся игра чисто случайно (потому что консоль 160x160 пикселей) получилась с такими же параметрами как у “Любителя”, однако она тяжелее. Тут надо думать чаще, да еще и помнить, где мины стоят (отсутствие флажков тоже было намеренным). И следить за тем, чтобы случайно не уехать дальше, чем нужно: чаще всего я проигрываю как раз из-за этого.
Вообще я заметил, что и в обычной жизни некоторые вещи хочу делать побыстрее и без особых раздумий. В результате делаю тупейшие ошибки и выходит дольше и хуже:) Все как в поговорке. Возможно, эта игра потренирует мою усидчивость.
Консоль и ее ограничения
На платформу я наткнулся, когда что-то искал для Zig в рамках своего предыдущего приключения:
там есть еще и другие языки, чтобы на них пострадать
В целом, программировать под нее оказалось довольно просто. При этом она не идеальна (я нашел пару багов, придумал фичу и даже сделал мини-пуллреквест), но компенсирует это “ламповостью”.
И наличие ограничений тут сыграло на руку: я очень быстро выкинул несколько идей (некоторые, правда были неплохие), которые могли бы затянуть разработку на недельку, и смог быстро получить что-то рабочее.
Nim
Nim я выбрал по принципу “что-то новое, но при этом хотя бы слышал” (оказывается, для этого баззворд даже есть). Про него до этого я знал только, что да, вот есть такой язык, похож на питон чем-то, но при этом системный, и вроде хвалят.
Писать на Nim было легко. Я опять поленился и не почитал даже простейшие туториалы (1, 2), но первую играбельную версию написал без проблем, просто используя те конструкции, которые казались логичными для питона/сей и при взгляде на код рядышком из шаблона. Углубиться в язык понадобилось только когда проверку решаемости добавлял.
С точки зрения синтаксиса — да, напоминает питон с его значимыми пробелами и некоторыми особенностями синтаксиса, и еще в чем-то есть сходство с F#.
Есть непривычные вещи, например, конкатенация строк через &
вместо +
или перевод в строку с помощью доллара ($someInt
).
Забавно, что лямбды — это сахар, и для x => x + 1
надо буквально импортировать std/sugar
.
Немного расстроили структуры, там обязательно надо указывать имена полей при создании, Cell(x: p.x + 1, y: y)
мне не очень понравилось и я в итоге оставил просто две переменных во многих местах.
Switch не такой мощный, как хотелось бы (даже Kotlin’овский when
поинтереснее), но это я по скаловскому скучаю.
Впрочем, это все скорее вкусовщина.
Одна из крутых фич — все методы это по сути расширения.
Т.е. x.pos(y)
это сахар для pos(x, y)
.
С точки зрения программиста на Cях со структурами, да и с точки зрения ФП-шника с ворохом DTO — очень удобно.
Еще крутая фишка — оптимизированные множества.
Стандартный set
— это битовый массив.
Итераторы с yield
— мое почтение, тоже очень удобно.
Есть и всякие плюшки для времени компиляции, например when
или static: assert
, но чтобы их по настоящему оценить, нужно видимо что-то мультиплатформенное делать.
Не понравилось, что объявление функции должно быть обязательно раньше его использования: не очень дружелюбно к косвенной рекурсии, да и организовать код в файле чуть-чуть тяжелее. Возможно, надо было разбивать код на модули, но я решил, что оно того не особо стоит: весь код занимает меньше 300 строк.
Прям неожиданно споткнулся об интервалы: они паскалевские/котлиновские, т.е. вместо привычного for i in 0..n
надо писать for i in 0..<n
.
С одной стороны, более явно, чем “в устоявшемся” стиле, с другой — тяжело обнаружить классическую ошибку на единицу.
В этом плане отстойно, что не было никакой проверки на выход за границы массива.
И еще один бесючий момент — жесткая сегрегация численных типов без неявной конверсии между ними, т.е. int
, uint8
, uint32
и т.п.
Подобное было уже с Rust и Zig, и вроде в Nim чуть лучше, но все равно не нравится.
Справедливости ради, один потенциальный баг может быть за счет этого был обнаружен.
С точки зрения инструментов, видимо, это модный тренд: делать менеджер пакетов, совмещенный с инструментом сборки. Да еще чтобы скрипты сборки были на этом языке (хотя по факту это мало отличается от Make с набором альясов для баш-команд).
В целом в Nim есть интересные фичи (но и сомнительные тоже), и ощущения после него остались приятные.
Разработка
На все-про-все у меня ушло часов 10-11, и большую часть времени я потратил на установку рабочего окружения. Причем дважды: локально, чтобы не curl-sh (сесурити!) и в GitHub Actions (благословлен пусть будет act, без него было бы еще дольше).
Первую играбельную версию я получил всего через 2-3 часа после настройки окружения.
Потерял немного времени на диагностику проблемы с рандомом, чтобы в итоге использовать трюк со счетчиком фреймов.
Обнаружил еще, что функция обновления фрейма не блокирует последующий вызов, но это тоже стоило времени — для меня блокировка была как что-то само собой разумеющееся. А неправильная обработка этой ситуации вызывала проблемы с обработкой нажатий клавиш.
Наконец, подобрать более-менее пристойную картинку для логотипа тоже заняло время: найти AI-сервис генерации без регистрации и смс, выяснить, что с текстом все еще есть проблемы у старых моделей, а потом еще отмасштабировать картинку и с помощью ImageMagick снизить количество цветов до 4. Ну и поиграться с цветами, разумеется.
Из собственно алгоритмических вещей самой трудозатратной задачей было обеспечение того, что в игру можно выиграть. В ранних версиях этой проверки не было, и была возможна ситуация, когда пустое место в углу было перегорожено двумя минами. Я пытался придумать что-нибудь умное, чтобы влезть в “почти” константную память, но в итоге забил и оставил простой BFS. И была еще пара экспериментов, от которых я отказался.
Был еще забавный момент, когда я тестировал небольшое изменение, связанное с обновлением состояния игры. Я спешил пройти уровень и постоянно делал мелкие ошибки, и в итоге долго не мог отладить поведение просто потому, что не мог выиграть :)
Итого
В целом у меня остались вполне позитивные впечатления от платформы и от Nim. Игрулей я доволен, и особенно я доволен тем, что очень быстро получилось что-то сделать и поиграть.
Ограничения и предохранители
Зацепились языками с одним из коллег на тему удобства языка для разработки без IDE. Он заявил, что код на Kotlin невозможно читать без IDE. Вполне органично дискуссия перешла в плоскость того, полезны ли ограничения языка или нет.
Началось все с тезиса про то, что структура файлов в Java (1 файл на 1 класс, 1 папка часть пакета) это полезно и позволяет находить нужный класс быстрее. А вот в Kotlin можно как угодно делать. Поэтому ограничения — это хорошо, они приводят к порядку и простоте. В качестве дополнительных примеров были модификаторы видимости (C против Java), владение (C vs Rust) и т.п. Да и вообще, ограничения формируют/способствуют культуре разработки.
Когда я пытался аргументировать, что ограничение на структуру файлов — весьма дурацкое и особо не помогает, мой оппонент подумал, что я его троллю:) Так-то класс может быть в разных модулях, может быть вложенным и т.п., т.е. это не просто “иди по этому пути”, и хоть какой-то поиск придется рано или поздно использовать.
Весь спор пересказывать не буду, а перейду сразу к выводам.
Я понял, что есть 2 принципиально разных аспекта в языке: ограничения и предохранители. Предохранители — это обычно просто замечательно, они позволяют избегать тупых ошибок. Например, явная проверка на null в Kotlin или владение памятью в Rust — это предохранители. Ограничения — это противоположность выразительности, т.е. что-то, что мешает сделать программисту то, что он хочет. “Я ограничен технологиями своего времени”.
Соответственно, ограничение и предохранитель легко спутать друг с другом (или дебатировать, что хорошо и что плохо). И вот тут-то и зарыт корень наших разногласий: мой коллега искренне считал, что структура папок в Java — это предохранитель и это хорошо, а для меня это еще одно ограничение. В этом плане мне гораздо важнее разложить код по модулям, по ролям и/или по шаблону какой-нибудь трехбуквенной архитектуры. Обычно языку на это плевать, но в Java будет привет от com.company.name.package.folder
.
Мне нравятся выразительные языки. На мой взгляд, хреново и непонятно можно написать на любом языке. Да, в более выразительном языке возможностей может быть больше, но человеческая тупость вообще бесконечна. В свою очередь, выразительный язык предоставляет больше возможностей написать код хорошо. А предохранители должны этому способствовать.
И разумеется, опыт в более выразительных языках влияет на то, как разработчик пишет код. Однако говорить о том, что язык формирует культуру разработки — очень странно. Это как сказать, что ножницы формируют культуру парикмахерской, или молоток формирует культуру стройки. Если у вас инструмент формирует процессы и/или подходы — у меня для вас плохие новости…
Комменты телеграма на сайте и похвала роботам
На выходных удалил комментарии от телеги с сайта (которые comments.app). API и возможности администрирования с 2020 года совсем не изменились: например, до сих пор нельзя посмотреть все комменты на сайте. Да и не пользовался ими никто — ровно один комментарий был не от меня. Старые комменты спарсил краулером, написанным ChatGPT.
Нашел как подключить комментарии из канала. Повспоминал свои боли с Jekyll. С точки зрения самой телеги оказалось довольно нетривиально понять, как сделать так, чтобы была ссылка вела сразу на дискуссию с комментариями, а не тупо на пост. В итоге тупо вставил ссылку в конце поста, на компе работает, но на планшете — нет (не открывает комментарии, только пост). ¯\_(ツ)_/¯
Увы, нельзя комментировать старые посты, потому что для них нет соответствующего поста в группе обсуждений. Ну и фиг с ними, все равно их никто не читает :) Паравозиком приехала ссылка на комменты с Хабра (тоже не знаю зачем, даже я уже Хабр практически перестал читать).
Осталось дело за малым — добавить везде ID поста в телеге. Это около 250 файлов, и там не просто подряд числа. Тут очень хорошо повкалывал ChatGPT, прям аж похвалить его захотелось: всего за 3-4 итерации генерировал рабочие решения на питоне, причем мне даже особо не нужно было читать код.
В итоге все посты из телеги сохранил через экспорт канала (с доступом через API нахвался уже), потом сопоставил их с постами с сайта по заголовку. Часть файлов обновил руками — там заголовки не совпадали или были проблемы из-за кавычек. На все-про-все ушло минут 10, и это классно.
Немного напортачил с переносом строк. Хотел поправить башем, но ChatGPT внезапно отупел и его предложения не работали. Оказалось, что кончились токены на 4 версию. Т.е. если предыдущие версии я в основном ругал, то от четвертой в основном положительные впечатления остались.
Еще я сделал тупую опечатку, которую нашел не сразу. В итоге больше всего потратил на обработку крайних случаев, тупую опечатку и приколы с экранированием. Иронично, что первый пост, к которому можно оставить коммент — “Самые сложные проблемы в разработке” (ладно, для душнил есть еще пост про открытие комментариев). Но в целом результатом я доволен, наконец-то почувствовал продуктивность с ChatGPT. Сам подход напомнил скачивание архива — тоже из говна и палок, “лишь бы работало”.