• Емакс в терминале

    Долгое время я пользовался Емаксом с графическим интерфейсом. Для Мака такой Емакс качается с сайта Emacs For Mac OS X и ставится как обычное приложение в папке Applications.

    Два месяца назад перешел на версию для терминала. Ниже короткие заметки о том, как это сделать и что изменилось.

    Установка из пакетов. Для Мака ставится из brew: brew install emacs. На момент написания статьи скачивается версия 25.1. Важно: бинарник находится по пути /usr/local/Cellar/emacs/25.1/bin/emacs! Если вы введете в терминале просто emacs, то запустится /usr/bin/emacs, у меня это какое-то старье.

    Внешний вид. Я использую стандартную цветовую схему light-blue из коробки. Включается командой (load-theme 'light-blue t). В терминальной версии цвета немного другие. Сравните графическую версию:

    gui

    и терминал:

    terminal

    Размер текста. Для комфортной работы я нашел полезным ставить шрифт покрупнее. Глаза нам даны одни на всю жизнь, так что лучше их поберечь. В графической версии высота шрифта меняется командой (set-face-attribute 'default nil :height 140) (140 – моя метрика, подобранная эмпирически). В терминале, конечно, это не прокатит. Поэтому я просто жму три раза Cmd + =. Получается как на рисунке ниже (картинка специально обрезана, чтобы вошла в колонку без масштабирования):

    font

    Курсор. Больше недели не мог настроить цвет курсора в терминале. В графической версии был красный, а в терминале серый. Сливается в голубым фоном, глазам трудно найти. Команды вроде (set-cursor-color "#ffffff") не помогают. Оказывается, в маковском терминале Iterm2 цвет курсора и текста под ним регулируется силами самого терминала. Пришлось поправить настройки:

    iterm2

    Вместе с цветом курсора (Cursor) можно включить легкое цветовое выделение текущей строки (Cursor Guide).

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

    Напомню, мой конфиг Емакса с комментариями лежит в Гитхабе.

  • Что почитать на выходных №2

    В этом выпуске:

    • История одного тестового задания (русский) – забавный пост о том, как кандидаты справляются с практическим заданием при трудоустройстве. Каждый абзац прекрасен. С юмором, тонко и по делу.

    • Simple Made Easy (видео, слайды, английский) – ТОТ САМЫЙ доклад Рича Хики, что делит жизнь пополам. Серьезно: очень мощное выступление Рича. Без привязки к конкретному языку.

    • Культ женской глупости (русский) – Арина Холина о женщинах и интеллекте.

    Что, мало про технологии? Да забейте. Дайте мозгу отдохнуть.

  • Отказ

    Дональд Трамп отказался от президентской зарплаты в $400.000. Вместо этого он будет получать один доллар. На меня это произвело большое впечатление. Когда я упоминаю об этом, слышу гнилой базар что у Трампа денег много, и он чуть ли не был обязан так поступить.

    Те, кто так рассуждают, мещане. Давайте-ка я объясню.

    Во-первых, считать чужие деньги некрасиво. Да, Трамп богат, но мещанин всегда видит только одну сторону медали. То, что богатый человек выплачивает по 25 миллионов долларов в судах, его не интересует.

    Далее, нет установленной суммы, после которой считается, что ты получаешь “много” и можно отказываться от денег. У каждого человека эта планка своя, но в среднем стремится к бесконечности.

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

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

    Легко обещать, зная, что никогда не понесешь ответственность за сказанное.

    Вот вы зарабатываете 50 тысяч рублей, на жизнь хватает. Откажетесь ли вы от халявных 100 тысяч? Нет же. Вы скажете: будь у меня миллион, я бы не взял. А будь миллион, скажете, что все равно на квартиру не хватит, так что возьму.

    Вам вообще приходилось от чего-то отказываться? Например, от денег, на которые вы морально не претендуете. Или от вещей, которые в прекрасном состоянии, но просто вы ими не пользуетесь?

    Вот вам на размышление: под Новый Год дают премию в размере одной зарплаты. Вы знаете, что работали хреново, без конца срались в чатиках и смотрели смешные картинки. Откажетесь от денег?

    Дома у вас компьютер и ноутбук, пользуетесь чем-то одним. Отнесете лишнюю технику в школу? Подарите малообеспеченным соседям?

    Сделайте что-то подобное, а потом говорите.

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

  • БиБиСи говно

    Я не знаю, кто решил, что БиБиСи делает хорошие обучающие фильмы. Да, наснимали их кучу, заполонили ТВ и Ютубы. А вы их видели? Пытались посмотреть целиком? Я не вынес и 15 минут. Что интересно, сын – тоже.

    Подозреваю, что когда-то фильмы БиБиСи были действительно качественными и несли крупицы образования. В тот момент руководство почуяло, что пипл хавает. Начали масштабное производство, продали каналам, подсадили школы. Конечно, качество просело.

    Чтобы вы знали, что представляет собой типичный “образовательный” фильм БиБиСи, представьте вечерний НТВ. Резкий, агрессивный монтаж. Попытка навязать значимость лишним деталям. Строй повествования скачет. В кадре без конца появляются люди, которые говорят 10 секунд, а затем пропадают навсегда. Кто это был – эксперт или уборщица?

    Нет логических пауз. Фильм гонят, как боевик, не дают переварить информацию. Русский перевод ниже всех санитарных норм, наложен поверх оригинальной дорожки. Это и есть типичный фильм, который, по мнению БиБиСи, обучает и развивает.

    Показывают ядовитого паука. Резкие кадры, челюсти, мы все умрем. Внезапно, ученый: этот паук поразил меня! Снова резкие кадры. Какая-то баба: паук до сих пор представляет загадку для всего человечества! Диктор говорит за дикие пальмы. И так два часа.

    На Ютубе крайне трудно найти что-то на тему космоса или природы, чтобы это было не БиБиСи. Поиск выплевывает бесконечный список халтуры. Везде одно и то же – никакое повествование и говно-перевод.

    Такое видео отупляет. Ребенка не обманешь – после хороших, годных фильмов халтура не катит. И не рассказывай, что это БиБиСи. Мне искренне жаль американских и европейских детей, что им впаривают это говно в школах.

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

  • Что почитать на выходных. Выпуск 1, пробный шар

    Некоторые блоггеры ведут полезную рубрику – в конце недели публикуют интересные ссылки, посты, видео. Обычно материалы объемные и в будни с ними возиться некогда. А поваляться на диване на выходных с ноутом, почитывая интересный бложег – самое оно. Вот и я тоже решил поделиться тем, что нарыл за неделю.

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

  • Стоп-спор

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

    На то есть причины. Ответьте, зачем вы участвуете в спорах? Чтобы прийти к истине или исправить чужие ошибки? Ага, конечно. Спорят только для того, чтобы поднять ЧСВ. Если спор разгорается при свидетелях, победить в нем – приоритетная задача на сегодняшнее утро.

    Мы пытаемся оправдать низменные чувства стремлением к истине и справедливости. Знакомый доказывает мне, что я покупаю не то молоко и наношу вред здоровью. Он, такой молодец, покупает правильное молоко, а я – неправильное. При этом знакомый курит и почему-то игнорирует факт, что сигареты потенциально скосят ему 10 лет жизни, а бутылка “неправильного” молока безвредна.

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

    – Вот ссылка на Википедию… – Вики – не авторитетный источник данных.

    – В книге написано… – Выпущена 10 лет назад, устарела, сейчас так не делают.

    – Этот метод практикуют в Яндексе… – Яндекс ни о чем, оттуда все ушли.

    – Так сказал Джоэль Спольски… – Да он же гей!

    Согласен, временами выходит смешно, но тогда не делайте вид, что спорите о чем-то важном.

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

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

    Что действительно важно, так это оказаться правым в долгосрочной перспективе. Я считаю, что поступил правильно, когда сменил современный редактор на Емакс, занялся Лиспом и ушел из крупной фирмы на удаленку. Потому что жизнь стала лучше по всем показателям: профессиональном, финансовом.

    За спорами я теперь вижу проявление нужды. Спорящий нуждается во внешнем внимании, ему важно осозновать, что его замечают. По этой же причине мы часто ищем подтверждение своих мыслей у известных людей или компаний. Например, на Питоне пишут в Гугле, а на вашем Хаскеле – где? Реакт используют в Фейсбуке, а ваш фреймфорк – кому он сдался?

    Раньше я тоже ревностно собирал информацию о том, кто использует те же средства, что и я. Кидался именами – Гугл, Яндекс. Но затем понял, что это неважно. Если мне нравится Кложа, значит, буду писать на ней даже когда вообще не будет вакансий.

    Избегать споров помогает отличный прием. Нет вопроса – нет ответной реплики. Например, в чат набрасывают ссылку, где язык А по тестам уделывает язык Б. Начинается срач. Правильно будет отвечать только на открытые вопросы, когда спрашивают именно ваше мнение.

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

  • Без ORM. Вдогонку

    В предыдущем посте я поделился мыслями насчет преимуществ сырого SQL перед ORM. Забыл привести два следующих аргумента.

    Миграции

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

    Пример типичной миграции:

    -- change column types
    alter table users
        alter column username type text,
        alter column username set not null;
    

    Здесь я просто меняю тип поля на text с varchar и добавляю ограничение на обязательное заполнение. Чтобы проверить миграцию, просто запускаю ее вручную:

    psql --user foo foo-dbm < resources/migrations/20161107112942-change-username.up.sql
    

    Если у вас база в Докере, то выигрыш в том, что при старте образа запускается специальный скрипт. Он автоматом прогоняет .sql-файлы из особой папки. Достаточно накидать в эту папку файлы миграций, и они выполнятся! Вот как это делается в compose-файле:

    version: '2'
    services:
      ...
      postgres:
        image: postgres
        volumes:
          - <папка с миграциями>:/docker-entrypoint-initdb.d:ro
    

    Сравните теперь с типичной Django-миграцией:

    from django.db import migrations, models
    
    class Migration(migrations.Migration):
    
        dependencies = [("migrations", "0001_initial")]
    
        operations = [
            migrations.DeleteModel("Tribble"),
            migrations.AddField("Author", "rating", models.IntegerField(default=0)),
        ]
    

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

    Далее, этот код может быть запущен только на Питоне и только в особом окружении. Нужна Джанга, вирутальное окружение, верные переменные среды. Просто запустить его я не могу.

    По Ричу Хики, SQL-миграция – просто, Джанго-миграция – легко. Я за простоту.

    Рекурсивные запросы

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

    При этом самые частые операции в коде были перемещение от элемента на самый вверх или на самый низ. Что сделал разработчик? Понятно, лезть в базу поштучно очень дорого, в цепочке может быть 20 узлов. Решил проблему радикально – вынимает из базы ВСЕ узлы, потом стоит иерархический словарь в памяти и перемещается по нему. Это работало, потому что в базе было мало узлов, около тысячи. Ради забавы я написал юнит-тест с 10000 узлами, код подвис секунд на пять.

    А ведь достаточно было использовать рекурсивные запросы! Они не только в Постгресе есть, но даже в SQLite! Запрос разбивается на две подчасти. Первая – инициализирующая часть, вторая – накопительная. Пример с Хабра:

    WITH RECURSIVE r AS (
       SELECT id, parent_id, name, 1 AS level
       FROM geo
       WHERE id = 4
    
       UNION ALL
    
       SELECT geo.id, geo.parent_id, geo.name, r.level + 1 AS level
       FROM geo
          JOIN r
              ON geo.parent_id = r.id
    )
    
    SELECT * FROM r;
    
     id | parent_id |      name       | level
    ----+-----------+-----------------+-------
      4 |         2 | Европа          |     1
      5 |         4 | Россия          |     2
      6 |         4 | Германия        |     2
      7 |         5 | Москва          |     3
      8 |         5 | Санкт-Петербург |     3
      9 |         6 | Берлин          |     3
    (6 rows)
    

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

    Любите SQL – прекрасный, понятный язык запросов к данным!

  • Без ORM

    UPD Продолжение

    sql

    В текущем проекте мы используем SQL. Запросы, миграции, триггеры – все это чистый скуль, написанный нами. Сперва было непривычно, за годы работы с Джангой я напрочь забыл язык запросов. Теперь, напротив, меня дико прет. Рассказываю плюсы и минусы такого подхода.

    Прежде всего, мы используем библиотеку HugSQL. Работает она любопытным образом. Вы пишете обычный .sql файл с запросами. Перед каждым запросом размещаете структурированный комментарий. В нем указываете имя функции и дополнительные директивы. Затем библиотека парсит файл и динамически создает в модуле функции с аналогичными названиями.

    Пример:

    -- :name create-user! :<!
    -- :doc creates a new user record
    INSERT INTO users
    (first_name, last_name, email, username, password, phone)
    VALUES (:first_name, :last_name, :email, :username, :password, :phone)
    RETURNING *
    
    
    (let [user (db/create-user! {:username "ivan"
                                 :email "test@test.com"
                                 :password "123"
                                 :phone "223-322"
                                 :first_name "test"
                                 :last_name "test"})])
    

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

    Во-вторых, приходется потратить время на повторное изучение SQL и конкретной базы данных, в нашем случе – Постгреса. Потому что все ORM-системы превращают базу в хранилище, то есть черный ящик. Есть модели, пользуйся, а внутрь не лезь. И вообще, объекты предлагают больше синтаксического сахара.

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

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

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

    Мы активно используем расширения Постгреса и специальные типы данных. JSON, геолокация, генерация токенов и случайных величин. Не приходится писать это в коде. Например, если из двух разных мест выполнить вставку в эту таблицу, будет сгенерирован случайый токен на уровне БД. А если делать это в коде, придется копипастить.

    В логах Постргреса я вижу написанные в своем стиле запросы. ORM, как правило, генерит адский поток, который невозможно прочесть. Если ORM-запрос содержит что-то посложней чтения или вставки, например, group by, having, join, union, приходится его дебажить. Потому что далеко не факт, что результат будет таким, как вы хотите. Например, Алхимия в Питоне не может правильно сделать union, хоть убей. А как указать, что тебе нужен именно левый джоин, а не внутренний?

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

    Выражаясь терминами Рича Хики, ORM это легко (easy), а SQL – просто (simple). Это не синонимы. Легко значит – быстро, а просто – прозрачно. Здесь я не буду умничать, а просто советую послушать доклад.

  • Поменьше о себе, пожалуйста

    Бывает, делишься с кем-то впечатлениями о книге, статье или фильме и получаешь примерно такой ответ:

    – Я не смотрю аниме.

    – Я не посещаю этот сайт.

    – Я не читаю книги.

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

    Это нелогично

    – Зацени, какая интересная статья.

    – Я не читаю Хабр.

    Минуточку. Тебя никто не спрашивал, читаешь ты Хабр или нет. Зачем ломать линию разговора? Очевидно, полное сообщение ответной реплики звучит так: я не буду читать, потому что не посещаю этот ресурс. Но в исходном сообщении уже содержится контр-аргумент. Он звучит так: даже если ты не открываешь этот сайт, сделай это ради полезного материала! Ответ “я не делаю Х” в ответ на призыв – нелепый.

    Что отвечать, если вам советуют что-то, что вы еще не пробовали, не читали, не смотрели? Задавать открытые вопросы. Напомню, открытые – это те, что начинаются со слов что, когда, где и т.д. Если предмет беседы того стоит, собеседник внятно опишет его преимущества.

    – Чем привлекает этот фильм?

    – Какие особенности в этом языке программирования?

    – Какая главная мысль автора?

    Если слышите в ответ “да там вообще ништяк зацени”, вежливо заканчивайте разговор.

    Это эгоистично

    – В этой книге подробно описано…

    – Я не читаю книги.

    Что движит тем, кто делится информацией? Положительные чувства, эмпатия. Если это не смишные картинки, конечно. Что содержится в ответе? Ничего кроме эгоизма. Смотри какой я крутой. Я не читаю, не смотрю, это для лохов. Даже высказанный вежливым тоном, ответ содержит презрение.

    Это предубедительно

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

    Вывод

    Если вам что-то предлагают, не спешите рассказывать какой вы крутой, и что вы делаете, а что нет. Задавайте вопросы, чтобы быстро узнать суть. Вежливо отвечайте “спасибо”, чтобы не продолжать дальше. И поменьше о себе, я прошу.

  • Перенесли чат в Телеграм

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

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

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

    А пока что прошу зайти в канал Телеграма DeepRefactoring. В нем раньше появятся анонсы и обсуждение докладов и встреч. В Фейсубке мы стараемся теперь не общаться, будем только кросспостить анонсы.

Страница 50 из 75