Минутка просвещения

Читать в телеге. Когда-то там были посты не только от меня.

Принцип наименьшего удивления

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

В более мягкой форме — это принцип наименьшего удивления. Даже Википедия говорит, что принцип хоть и формализован в ИТ, но использовался и раньше, да и люди находят ему применение в оффлайне. Одно из следствий принципа — существование шаблонов проектирования (чтобы архитектура была “привычной”). Другое — самодокументируемый код. Еще одна инкарнация этого принципа — анекдот про плохие интерфейсы: “Пользовательский интерфейс — как анекдот. Если его надо объяснять, то он плохой”.

Суть принципа очень проста: код, дизайн, UI, тесты и т.п. должны быть логичны, последовательны, соответствовать общепринятым (среди пользователей/команды) практикам и вообще не удивлять негативно. Например, строит проектировать код так, чтобы нельзя было написать “неправильно” или “неочевидно”. Если текущие инструменты не позволяют это сделать — обеспечить преодоление порога вхождения в контекст обучением, документацией и т.п., чтобы было хотя бы понятно, “как принято” писать. Другой пример: покрытие тестами не должно вызывать по причине “WTF, все сломал, а тесты еще зеленые”. А постановка задачи не должна вызывать “WTF, кому и нафиг это надо”. Даже на процессы это можно натянуть: новый сотрудник не должен в первые дни WTF’ить: что делать, как это работает, к кому идти, почему это так, кто это вообще такую дичь придумал, у кого это спросить и т.п.

СсылкаКомментировать

Статус-код ответа graphql

Если почитать рандомные статьи (раз, два) про работу с GraphQL, то получается, что обработка ошибок как в REST — это “неправильный” подход к использованию GraphQL. Потому что, во-первых, GraphQL не привязан к транспортному протоколу, а во-вторых, спецификация явно определяет, что для ошибок есть специальное поле. Кроме того, один запрос может содержать несколько подзапросов, и не понятно, что делать, если один обработался успешно (как вариант, предлагают 207), а другой — нет. И вроде как надо возвращать 200, если запрос выполнился успешно, и 500 — в любом другом случае.

Однако, когда тебе на невалидный запрос возвращается 200 с пустыми данными, это выглядит, как минимум, странно. Если копнуть глубже, то выяснится, что в официальной документации про статус-код не говорится ничего. В 2018 в рабочей группе GraphQL поднимался этот вопрос, и потом еще в 2019 и 2020. Но четкого результата у этих обсуждений нет, только черновик.

Я в итоге на текущем проекте решил группировать по убыванию. Если нет ошибок — 200, хотя бы один 5xx код — это 500, несколько 4xx = 400, один 4xx — его и вернуть, в любой непонятной ситуации — 500.

СсылкаКомментировать

Почему формальные методы редко используются

Интересная статья про доказательство корректности программ, точнее, почему оно редко применяется на практике. TLDR:

  • Чтобы что-то доказать, нужны четкие требования и спецификация. Их получить довольно тяжело, если вообще возможно.
  • Надо понимать, что хотим получить от верификации. В бизнесе всем насрать, правильно ли у тебя сортировка работает, если клиенты не приносят бабки.
  • Надо формализовать хотелки. Человеческие понятия тяжело формализовать. Кстати, эта же проблема — причина многих проблем с безопасностью ИИ.
  • Доказывать что то формально — тяжело. Например, доказать ассоциативность сложения — либо дорого, либо опасно (например, в C++ сложение не ассоциативно в районе INT_MAX).
  • Чем язык богаче фичами, тем тяжелее в нем доказать что-то.
  • В повседневной работе хороших тестов и документации достаточно для приемлемо хорошего качества. Каждый следующий “процент качества” обычно кратно дороже предыдущего.
  • Многие проблемы лежат на уровне проектирования. Но в него почти никто не вкладывается, потому что мало кто понимает его ценность. Большой вклад вносит культурный барьер.

СсылкаКомментировать

Ревью пулл-реквестов

Более-менее серьезные пулл-реквесты довольно неудобно смотреть в самом GitHub. Даже переключение diff на две колонки (split-view) не очень помогает: например, лично мне не хватало дерева файлов. Делать ревью через Intellij стало уныло с обновлением интерфейса — там есть просто позорные баги.

Но можно на странице PR нажать обычную точку ., и будет загружена веб-версия VS Сode, в которой делать ревью приятнее. Причем можно ставить плагины (хоть и не все работают полноценно).

СсылкаКомментировать

Проверка простоты числа с помощью регулярки

def is_prime(n):
    return re.match(r'^1?$|^(11+?)\1+$', '1' * n) is None

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

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

СсылкаКомментировать

Mercurial мертв?

С одной стороны, недавно был релиз, и он еще используется в Mozilla, nginx. Но, например, Facebook планирует отказываться от него.

Даже до прекращения поддержки на BitBucket, Mercurial’ом пользовалось около 3% людей. Доля пользователей Mercurial была мала даже в 2010х. Если посмотреть на тренды гугла или поискать вакансии, то у Mercurial все грустно.

Так что да, Mercurial скорее мертв, чем жив. Немного жаль, ведь команды Mercurial более интуитивны, да и сам он проще и логичнее. Хотя сейчас почти всю работу в этом плане делают среды разработки, которые поддерживают в основном только git, а остальное — по остаточному принципу.

СсылкаКомментировать

Производительность приложения и расположение в памяти

Интересный доклад про производительность и как ее правильно измерять. Доклад из введения и двух частей.

Суть первой части:

  • производительность приложения довольно сильно зависит от расположения кода и данных в памяти, разница может доходить до 40%;
  • почти любое изменение кода это расположение меняет;
  • оно еще зависит от порядка линковки, размера переменных окружения, версий библиотек, текущей директории и т.п.
  • чувак разработал инструмент, который рандомизирует расположение и позволяет понять лучше влияние изменений на производительность;
  • эксперименты показали, что -O2 и -O3 статистически неразличимы.

Суть второй части:

  • большинство профилировщиков подталкивают на оптимизацию узких мест;
  • этот подход плохо работает для многопоточных приложений;
  • вместо этого надо анализировать DAG вычислений/зависимостей, и искать места, оптимизация которых реально поможет — как будто они лежат на критическом пути в диаграмме Ганта;
  • а еще многие профилировщики измеряют время в контексте всей жизни приложения, а не функции (например, выполнения HTTP-запроса), и чувак сделал профилировщик, который позволяет измерять пропускную способность от точки до точки;
  • под конец результаты оптимизаций на основе анализа результата профилировщиков.
СсылкаКомментировать

Интерактивное обучение DNS

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

dig txt +short maybethiscould.work
СсылкаКомментировать

Частичная выгрузка данных в SQL

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

Но у обоих есть недостатки: COPY может выгрузить данные по запросу, но только в CSV формате. А pg_dump может выгрузить в формате sql-скрипта, но только всю таблицу целиком. Но если таблица не очень гигантская, то поможет grep:

pg_dump --table=table_name --data-only --column-inserts --dbname=postgresql://user:pass@ip:5432/dbname > dump.txt
cat dump.txt | grep some_id
СсылкаКомментировать