• Телеграм

    Ох уж этот Телеграм. Все чаще разыгрывается сцена:

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

    – У меня нет телеграма.

    – А че так, у всех же есть?

    – Не хочу.

    – Почему?

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

    Меседжер отвлекает нотификациями. Каждая программа считает долгом уведомить о новом сообщении. У меня почти все нотификации выключены. Знаю людей, у которых пачка алертов загораживает половину экрана, а им нормально. Из динамика постоянное квакание, пикание. Такой расклад снижает продуктивность вдвое.

    В хороших фирмах, например, Студии Лебедева или Мосигре меседжеры запрещены. Нужно спросить – пиши письмо или двигай булками в соседний кабинет. Совсем срочно – звони.

    Устанавливая новый месаджер, мы не удаляем старые. Я бы с радостью снес Скайп, но не могу, потому что кое-кто мне еще в него пишет. Зачем ставить еще что-то новое? Была проблема, стало две проблемы.

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

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

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

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

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

    Давайте на минуту представим, что только одна фирма в мире имеет право производить телевизоры и что-то транслировать. И еще одна фирма, чтобы делать телефоны и передавать голос по проводам. А третья фирма владеет патентом на супер-секретный протокол обмена почтой, и все почтовые сервера в мире – ее.

    Меседжеры так и работают. Ты можешь написать сообщение другу используя только наше тормозное ПО, только по нашему бинарному протоколу, только через наш дата-центр. Бред же.

    Отдельно про Телеграм, чтоб еще раз не вставать.

    Телеграм – очередной меседжер, и только. Да, он работает лучше, быстрее, и в целом учел некоторые ошибки предшественников.

    Но.

    Это единый центр передачи сообщений. В случае сбоя вы не сможете ни с кем общаться. Я пишу это в то время, когда Слак не работает в России уже часа 3. А как Скайп на сутки ложился, помните?

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

    Телеграм зависит от операторов сотовой связи, потому что делает ставку на телефон. Опсосы без проблем сливают данные абонентов органам.

    Этот Дуровский пафос! Еще будучи в ВК, Павел любил рассказы о свободе слова и честных судах. А в это время аккаунты оппозиционеров ломали пачками с привлечением администраторов.

    Примеры хороших распределенных систем – электронная почта, Тор, Биткоин, торренты, Эрланг. Возможно, люди, стоявшие у их истоков, не стали богачами, но точно продвинули прогресс вперед.

    Они, а не дирекция еще одной программы коротких сообщений.

  • Подтвеждение кук

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

    Интернет существует лет эдак 30, и все это время сервера спокойно отправляли куки. Поздно вы, ребята, спохватились! Уведомление об отправке кук выглядит так же дико, как уведомление о загрузке изображений.

    Понятие кук носит технический характер и не имеет отношения к потребителю. Зашел американец на новостной сайт почитать о выходках Трампа – а ему плашка на весь экран. Подтверди прием кук. Это же свинство. Куки совершенно не в мире потребителя.

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

    Если я нажму “не принимать”, то как удаленный сервер запомнит мой выбор? Правильно – положит мне куку со значеним “не принимать”. То есть нарушит обещание! Или запишет флаг в localStorage, что одно и то же.

    Несколько выводов из абзацев выше:

    • Не нужно грузить людей ложной заботой о безопасности.
    • Не стоит влезать в чужую зону ответственности.
    • Нарушение этих правил приводит ко лжи.
  • Рассказ о Емаксе

    В прошлый четверг я рассказывал аудитории Хекслета про Емакс. Представляю читателям блога скомпилированную версию выступления. Рассказ пересекается с прошлой заметкой о Емаксе.

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

    throne

    Кадр из фильма Трон: наследие. Хакер взламывает кого-то при помощи Емакса. Ему помогают запущенный тетрис и игра-головоломка о перестановке пирамиды.

    Содержание

    Историческая часть

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

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

    В Емаксе используется собственный диалект Лиспа, называемый Elisp (не путать с EMACS Lisp – это совсем другой диалект). Столлман отверг Common Lisp как излишне усложненный диалект, а Scheme – как недостаточно мощный. Так появилась своя реализация.

    Технически Elisp имеет серьезные ограничения – никакой многопоточности, нет хвостовой рекурсии, трудности с замыканиями. Производительность его очень невысока, примерно как Питон или Руби старых версий. Однако, даже при всех недостатках языка в нем можно творить потрясные вещи – редактировать код, управлять процессами, читать новости, RSS, играть в игры и так далее.

    Известная шутка о том, что емакс – это операционная система, в которой нет нормального редактора, косвенно права. Емакс можно рассматривать как рантайм программ, написанных на ELisp. Примерно как Хром – среда исполнения Джаваскрипта.

    Емакс обязан успехом исключительно Лиспу. Многие пакеты были написаны 10-20 лет назад, но по-прежнему разрабатываются, проходят рефакторинг.

    Подобно Лиспу, у Емакса есть форки и ответвления. Так, в девяностых годах обанкротилась компания Lucid, программисты которой использовали Емакс. Они взрастили внутри компании независимую версию редактора. Случилось так, что разработчики не договорились о правах и лицензиях. Так появился XEmacs – своего рода улучшенный Емакс. О форках я расскажу ниже.

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

    Отличие от Вима

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

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

    В Емаксе нет режимов из коробки, поэтому комбинации нуждаются в дополнительных клавишах (Комманд и Мета), чтобы различать ввод текста и команды. Это делает комбинации не такими быстрыми в наборе.

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

    Субъективно, Емакс пребывает в более вменяемом состоянии, чем Вим. В сообществе последнего сильны настроения в духе “взять все и переписать”. В Емаксе такого нет. Существуют Емакс-пакеты, которые очень точно воспроизводят принципы работы Вима – режимы, комбинации, исполнение Вим-скриптов.

    Философия Емакса

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

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

    Недостатки. Когда не следует использовать Емакс

    Емакс не идеален. Вот в каких случаях я не рекомендую его использовать.

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

    • Вы пишете на языке-платформе, неотделимой от ИДЕ. Например, C# или Java. Пытаться доработать любой другой редактор бессмысленно.

    • Порог входа выше, чем у стандартных редакторов.

    • Для комфортной работы редактор нужно настроить. Настройка может длиться годами. Главное – не увлекаться.

    Достоинства

    • Работает в разной степени со всеми известными языками и технологиями.

    • Очень гибкая система обработки текста

    • Мощная поддержка процессов. Простота интеграции с любым системным процессом или утилитой, например, git, docker, psql, grep, ls и т.д.

    • Конфигурирование всего и вся

    • Встроенный терминал, ssh-клиент, почтовик, браузер и масса других утилит

    • Золотые хиты детства – змейка, тетрис! M-x snake и M-x tetris

    • Единообразие. Каждый буфер, неважно, файл это или список процессов, подчиняется основным правилам навигации и поиска. Например, вы выполнили поиск в файле, открылся новый буфер с результатами. Теперь вы можете искать в буфере результатов, словно в файле! В любом буфере, неважно, файл это или что-то другое, можно настроить правила подсветки строк. Везде одинаковая навигация, копирование и вставка. Это дико удобно. Напротив, в стандартных ИДЕ каждое окно живет по своим особым правилам.

    Как я переходил на Емакс. Трудности, мотивация

    Я работаю в Емаксе третий год. Расскажу, как как пришел в него и с какими трудностями столкнулся.

    emacs

    Мой Емакс сегодня. По клику большая версия. Слева – дерево файлов, посередине – эта статья в процессе подготовки, справа – код на Схеме.

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

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

    В случае с Саблаймом выяснилось, что для комфортной работы достаточно 5-6 модулей для нескольких языков, интеграции с SVN и Git. Саблайм я до сих пор считаю программой высочайшего уровня и рекомендую как легкую замену ИДЕ.

    Но вот что беспокоило – все авторитетные для меня инженеры работали либо в Виме, либо в Емаксе. Причем вообще без вариантов (чаще – в Емаксе, но не суть). Это легко выяснить из интервью, статей, или просто посмотреть dotfiles на Гитхабе. Так, Емаксом пользуются Гвидо ван Россум (создатель Питона), Джо Армстронг (Эрланга) , Линус Торвальдс (линукса и Гита), Тед Дзюба (предприниматель из Долины). Армин Ронахер, чей вклад в Питон неоценим, используем Вим.

    Полагаю, у названных людей есть деньги чтобы купить лицензии на нужные ИДЕ, но они этого не делают. Линус как-то сказал, что готов купить любую ИДЕ, но его пальцы уже нельзя переучить после 20 лет Емакса. Гвидо положительно отзывался о Пайчарме, но добавил, что опять пришел к связке Емакс + pdb (самый базовый отладчик).

    Я пришел к нескольким выводам. Во-первых, ИДЕ действительно помогает на раннем этапе карьеры. Но на уровне упомянутых программистов это уже не играет особой роли. Они создали языки и компиляторы без коммерческих средств с месячной подпиской.

    Во-вторых, ИДЕ – это прежде всего бизнес. Адепты Джет-Брейнс расскажут, что без ИДЕ код пишется плохо, нарушаются бизнес-процессы и страдает бизнес. Их позиция ясна.

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

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

    Я решил переходить на Вим или Емакс, чтобы повысить уровень.

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

    Напротив, с Емаксом пошло проще. Возможно, благодаря cua-mode. Это такой режим для новичков, когда основные команды вроде копирования и вставки работают как в классический редакторах. Долгое время я, за годы привыкший к Ctrl-X/C/V, использовал эти же комбинации. Потом перешел на общепринятые в Емаксе.

    Установка

    • Для Мака. Либо скачать графическую версию, либо поставить консольную версию из brew, предварительно обновив формулы.

    • Для линукса. Из пакетов: apt-get, yum.

    • Для Винды. Скачать бинарники. На винде осложнения в том, что Емакс нуждается в стандартных Юникс-утилитах ps, grep, find. Понадобится какой-нибудь Cygwin или аналог.

    Пакет для интеграции с Гитом под названием magit требует Емакс не ниже 24.4. Это не очень хорошо, так как в старых Убунтах в пакетах указан 24.3. Приходится заморачиваться со сторонними репозиториями. Для начинающих это неважно.

    Основные положения

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

    Буфер может и не быть связан с файлом. Например, это список процессов, результат поиска в текущем буфере, греп по директории, список файлов, JSON из какого-то урла, интерактивная справка и так далее.

    В момент старта Емакса появляются три стандартных буфера. Это приветствие со ссылками на документацию. Потом буфер сообщений, своего рода лог. И буфер scratch для копипасты.

    Этот последний буфер особый – в нем можно выполнить любой код на Лиспе и сразу проверить, какой эффект имеет этот код.

    В Емаксе используют особые сокращения для клавиш. C (командная клавиша) означает Контрол, M (мета-клавиша) означает Альт. Дефис означает одновременное нажатие. Важно помнить, что 40 лет назад клавиатуры были другие, и клавиша Command располагалась рядом с пробелом, как сегодня на Маке. Так что Столлман не виноват!

    keyboard

    Клавиатура тех дней. Обратите внимание на расположение служебных клавиш.

    Примеры:

    • C-x b – нажать вместе Контрол и x, потом b – сменить буфер.
    • C-x C-f – нажать одновременно Контрол и x, потом одновременно Контрол и f – открыть файл.
    • M-g g – нажать вместе Альт и g, потом еще раз g – переход на нужную строку текущего буфера (система спросит номер).

    Нажатие C-g прерывает ввод текущей команды.

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

    Не нужно стараться запомнить все сразу, это придет постепенно.

    Чтобы эффективно работать в Емаксе, желательно освоить две вещи, о которых упоминал Кирилл в вебинаре по Виму. Первое – перенести клавишу Контрол на Капс. Это необходимо и вообще не обсуждается. Если нажимать ее в стандартном положении, рука отвалится из-за сильного напряжения в кисти.

    Как сделать это в Маке, я уже писал раньше.

    Второе – займитесь слепой печатью. Зайдите на сайт онлайн-тренажера. Зарегистрируйтесь через соц.сеть, чтобы накапливалась статистика. Каждый день утром 15 минут печатайте вслепую. Сначала будет бесить, но статистика покажет медленное продвижение, и это классно. Вы должны как можно скорее избавиться от стрелочек и пользоваться только центральной частью клавиатуры.

    chart

    Один из графиков моего профиля. Он показывает, что скорость набора медленно, но растет.

    В Емаксе нет табов для открытых файлов. Это шокирует тех, кто только начал с ним работать. Дело в том, что табы не нужны. Когда вы долго работаете, сами по себе накапливаются открытые буферы (как мы уже знаем, в Емаксе это не только файлы). Я никогда не выключаю ноут, а только погружаю в сон. К концу второго месяца в Емаксе примерно 400 буферов. Представьте, что для каждого был бы таб. Я бы просто ничего не видел из-за них.

    Кстати, любителям ИДЕ посвящается – откройте 400 файлов и проверьте, как поведет себя система. У моего коллеги ноут грелся так, что обжигало руку. А Емакс потребляет 100 Мб памяти и 10% процессора.

    Удивительно, но основные комбинации для перемещения по тексту работают много где за пределами Емакса – например, в Хроме, почтовом агенте Мака. В Баше по умолчанию включена раскладка Емакса.

    Конфигурирование

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

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

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

    При старте Емакс ищет файл ~/.emacs . Затем – ~/.emacs.d/init.el. .el – расширение файлов на Elisp. Обратите внимание, что первый файл не содержит расширения в имени.

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

    Вот как ставится моя конфигурация:

    # Скачать репозиторий куда-то себе
    git clone https://github.com/igrishaev/dotfiles.git ~/somewhere
    
    # скопировать папку .emacs.d в домашнюю директорию
    cp -r ~/somewhere/.emacs.d ~/
    
    # перейти внутрь
    cd ~/.emacs.d
    
    # поставить утилиту Cask
    make install-cask
    
    # установить пакеты, перечисленные в cask-файле.
    # переменную EMACS нужно задать, если у вас в системе несколько емаксов
    EMACS=/path/to/bin/emacs make install-packages
    

    Я терпеть не могу длинных навороченных конфигураций со многими файлами. При малейших обновлениях они ломаются. Конфигурация должна быть максимально декларативной. Только список необходимых пакетов и установка переменных.

    Коротко о пакетах

    Для емакса написаны тысячи пакетов, некоторые из которых тянут на полноценные приложения, исполняемые внутри Лисп-машины.

    Пакеты хостятся в репозиториях, у которых следующие имена – GNU, Melpa, Marmelade. Как правило, в конфиге указывают их все. Стандартный менеджер пакетов из поставки Емакса может устанавливать из репозиториев, но не умеет разруливать зависимости. Поэтому используют либо пакет el-get, либо утилиту Cask, как в моем случае. Это утилита на Питоне для сопровождения проектов на ELisp. В ней много всего, в том числе установка зависимостей. Она переопределяет стандартный менеджер пакетов. Вы пользуетесь как будто стандартным.

    Основные пакеты для Емакса без привязки к конкретным языкам:

    • magit – Интеграция с Гитом
    • nav – Панель файловой навигации
    • auto-complete – Автодополнение из разных источников
    • flycheck – проверка синтаксиса для разных языков. Обычно нужен сабмодуль для конкретного языка
    • markdown-mode – Маркдаун
    • nyan-mode – Нян-кот в твоем Емаксе!
    • simpleclip – Облегчает работу с системным буфером обмена
    • json-mode – Подсветка и валидация джейсона

    Сборки, форки

    Я не особо осведомлен насчет сторонних сборок Емакса. Почти все время я работал со своей конфигурацией на чистом Емаксе, чтобы понять, как все работает.

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

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

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

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

    Судя по репозиторию проекта, работа проделана внушительная, но я не проникся. Да и вообще, идея смешения мне не нравится. Она наивна по своей природе. Вот есть Руби и Питон, у них достоинства и недостатки. Давайте возьмем от каждого только достоинства и получим идеальный язык! Или давайте Мерседес с Ауди смешаем. Или Виндуз с Маком. Это не работает.

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

    Для чего я использую Емакс

    В емаксе можно делать почти все, что угодно, главное – знать меру и не стать упоротым фанатом.

    Надо понимать, что некоторые пакеты имеют скорее не практический, а спортивный интерес. Например, один тип написал модуль управления кофеваркой по USB. Это забавно, но не стоит воспринимать всерьез.

    xkcd

    В Емаксе на все найдется команда.

    Я использую Емакс для следующего:

    • Программирую в Емаксе на Питоне, Кложе, Джаваскрипте, Ракете, Коммон-Лиспе. В нем же ковыряю Хаскелл и Гоу. Под каждый язык – пакет или два для поддержки. Питон, надо сказать, поддерживается очень хорошо. Трудность скорее в том, какие пакеты для него выбрать из множества. Для Лиспов емакс – родная среда.

    • Редактирую структурированные файлы: Маркдаун, Json, Yaml, ini, html, css. Где не хватает коробочных средств, тоже ставлю пакеты.

    • Работаю с системами контроля версий, почти не вылезая в терминал. Смотрю диффы, блейм, логи. Делаю и мерджу ветки в Емаксе.

    • Изредка читаю онлайн-документацию во встроенном браузере EWW. Это полезно, когда не хочешь постоянно переключаться из браузера в редактор. Делишь экран пополам, в слева страничка с доками,справа код – удобно. Емакс умеет проматывать соседний буфер, не переключаясь из основного.

    • Планирую делать резолв конфликтов при мердже веток встроенным пакетом emerge. Пока что использую kdiff3.

    • Некоторое время, когда в команде пользовались джаббером, сидел из Емакса. Тоже удобно, особенно когда обсуждаешь код.

    • Пытался пользоваться почтой с помощью встроенного пакета Gnus – не пошло в силу однопоточности Лисп-машины. На проверку почты уходит до 10 секунд (у меня куча папок), за это время ничего нельзя сделать.

    • Запускаю и контролирую процессы с помощью пакета prodigy. Был проект на микросервисной архитектуре. Чтобы завести его, нужны были штук 6 фейковых рест-сервисов. Эти заглушки было удобно поднимать и гасить прямо в Емаксе.

    • Порой пользуюсь встроенным терминалом, когда лень открывать основной.

    • Иногда делаю презентации в емаксе: пишу структурированный файл в разметке ORG, который экспортируется в HTML + reveal.js. Например, вот слайды для доклада о юнит-тестах: исходник, результат.

    • Рисую ascii-таблицы в org-mode. Параметры таблицы задаются командой. Таблица ведет себя как лист в Экселе – можно перемещаться по ячейкам, добавлять и удалять строки и столбцы, сортировать, вставлять формулы. Таблица автоматом растягивается под данные в ячейках. И при этом копируется как текст. Очень удобно для документации. Руками вы ее будете рисовать час.

    Пример по шагам:

    • M-x org-table-create – система спрашивает размер таблицы, ввожу число строк и колонок, получаю
    |   |   |   |   |   |
    |---+---+---+---+---|
    |   |   |   |   |   |
    
    • Ввожу данные:
    |Python   |Ruby   |Perl   |Java   |Common Lisp   |
    |---+---+---+---+---|
    |1   |2   |  3 | 4  |5   |
    
    • Нужен еще ряд? Набираю M-x org-table-insert-row:
    |Python   |Ruby   |Perl   |Java   |Common Lisp   |
    |---+---+---+---+---|
    |1   |2   |  3 | 4  |5   |
    |  Some long test  | 42   | foo   | bar     |    Another long text|
    
    • Все съехало, некрасиво. Набираю M-x org-table-align:
    | Python         | Ruby | Perl | Java | Common Lisp       |
    |----------------+------+------+------+-------------------|
    | 1              |    2 | 3    | 4    | 5                 |
    | Some long test |   42 | foo  | bar  | Another long text |
    

    Тадам. И это даже не верхушка айсберга, а самая мелочь из того, что можно делать в org-mode.

    • Возвращаюсь к нашему списку. Веду GDT – учет личных и рабочих дел. Давно хочу написать на эту тему в блог, но пока что отдельным абзацем.

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

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

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

    Перенес все задачи в такой файл и храню его в приватном репозитории. Каждое утро смотрю, какие задачи меня ждут и стараюсь их выполнять. Задачи можно архивировать. Емакс вырезает их из файла и переносит в архивный файл с похожим названием.

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

    ** DONE Sign Contract
    CLOSED: [2016-03-30 Wed 12:36] SCHEDULED: <2016-03-30 Wed>
    - CLOSING NOTE [2016-03-30 Wed 12:36] \\
      signed
    ** TODO Get Reports
    DEADLINE: <2016-06-20 Mon +3m>
    - CLOSING NOTE [2016-03-28 Mon 10:52] \\
      got and paid
    :PROPERTIES:
    :LAST_REPEAT: [2016-03-28 Mon 10:52]
    :END:
    ** DONE IP USN
    CLOSED: [2016-04-25 Mon 10:00] DEADLINE: <2016-04-18 Mon>
    - CLOSING NOTE [2016-04-25 Mon 10:00] \\
      done
    ** TODO Visit some secret place
    DEADLINE: <2016-03-31 Thu>
    ** DONE Sber get new card
    CLOSED: [2016-04-06 Wed 15:42] SCHEDULED: <2016-04-04 Mon>
    - CLOSING NOTE [2016-04-06 Wed 15:42] \\
      got it!
    ** DONE Add bank account to Paypal
    CLOSED: [2016-03-25 Fri 15:39] SCHEDULED: <2016-03-24 Thu>
    - CLOSING NOTE [2016-03-25 Fri 15:39] \\
      added
    ** TODO Sber Deposit
    SCHEDULED: <2017-02-06 Mon>
    ** DONE Phone to Office
    SCHEDULED: <2016-03-01 Tue>
    - CLOSING NOTE [2016-03-01 Tue 15:02] \\
      phoned
    - CLOSING NOTE [2016-02-24 Wed 22:52] \\
      phoned
    

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

    На временной линии задачи выглядят так:

    Friday     10 June 2016
    Saturday   11 June 2016
      Scheduled:  TODO Practice Typing                                    :learning:
      Scheduled:  TODO Listen english                                     :learning:
      Scheduled:  TODO Do some secret stuff
      Scheduled:  TODO Pay for one thing
    Sunday     12 June 2016
    Monday     13 June 2016 W24
    Tuesday    14 June 2016
      Scheduled:  TODO Another important task
      Scheduled:  TODO Listen english                                     :learning:
      Deadline:   TODO Publish announce
    

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

    Ресурсы

  • Сегодня рассказываю про Емакс

    Сегодня, в четверг 9 июня, в 17:00 по Москве я расскажу про Емакс в Слак-канале образовательного проекта Хекслет.

    Затрону следующие темы:

    • краткая история Емакса
    • основные отличия от Вима
    • как я переходил на Емакс, причины и мотивация
    • советы новичкам
    • плюсы и недостатки
    • базовые приемы работы с Емаксом
    • расширенные возможности
    • для чего использую Емакс
    • ресурсы, книги, статьи
    • заключение и вопросы

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

    Заходите, будет интересно.

  • Доклады с шестой встречи глубокого рефакторинга

    Провели шестую встречу!

    meetup

    Юра Хрусталев рассказал, как мы в проекте внедряли Ансибл:

    Слайды

    Миша Вьюков дал советы как продвигать продукты и сообщества в социальных сетях.

    Слайды

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

  • Размышления о Питоне

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

    Ниже – попытка обозначить слабые и сильные стороны Питона. Постараюсь, чтоб не было банальщины в духе “много библиотек и широкое комьюнити”. Все сказанное – исключительно личное мнение, которое не навязываю никому.

    Итак, преимущества:

    Питон – коммерчески успешный язык

    Приятно осознавать, что Питон используют не только в академических и любительских кругах, но и в бизнесе. Компании доверяют ему деньги. Много фирм используют Питон – Гугл, Пейпал, Инстаграм, НАСА.

    Питон создает рабочие места. Вакансий много, в том числе и в России. Питон – промышленный язык. Он стоит в одном ряду с Плюсами и Джавой по востребованности. Разработчик на Питоне имеет шанс попасть в настоящую разработку продукта. Это не суррогат местного потребления вроде 1С.

    Питон – очень легкий язык

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

    В Питоне мало сложных тем. Так я называю разелы языка, на изучении которых останавливаешься отдельно. В Лиспе один сложный момент – макросы. В Скале больше – трейты, импликты, составные объекты. В Питоне два – декораторы и метаклассы. В повседневной работе метаклассы не нужны, пожтому остатется только одна сложность. Разобравшись с декораторами, вы не встретите в языке других препятствий.

    Питон сильно приблизил програмирование к людям

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

    Появились специальные проекты и книги, например, Python For Engineers, A Primer on Scientific Programming with Python и другие. На работе я видел скрипты на Питоне, написанные людьми, у которых все знание программирования сводилось к школьной программе. Но скрипты работали, автоматизировали труд, а значит, экономили время и деньги.

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

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

    Питон – легкий способ попасть в промышленную разработку

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

    Абзацем выше я фактически рассказал свою историю. До знакомства с Питоном я занимался сайтами на CMS, Дельфями и 1С. Конечно, и с этим можно найти работу. Однако, именно за счет Питона я продвинулся на старой работе, потом переехал в другой город за 6000 км и попал в Датаарт. Позже нашел удаленку в Европе.

    Питон поддерживает все парадигмы программирования

    Питон удивидельно гибок. Его дизайн и синтаксис в равной степени поддерживают большинство парадигм. Стандартное ООП, императивный подход, процедурно-модульный, функциональный.

    Каждая парадигма реализована в неполной манере. Так, в ООП нет приватных переменных и интерфейсов. Двойное подчеркивание – хак и обходится на раз. Интерфейсы пишут миксинами, но точное следование интерфейсу отследить невозможно.

    Для полноценного ФП не хватает полноценных лямбд и неизменяемых коллекций. В тройке функцию reduce запрятали в недра стандартной библиотеки.

    Ленивые вычисления, декораторы и перегрузка операторов открывают пространство для интересных маневров. Питон мимикрирует под самые разные языки, например:

    • Fake Lisp – псевдо-Лисп, забавная попытка писать питонячий код S-выражениями.

    • Hask – закос под синтаксис Хаскела. Питонщикам очень полезно посмотреть, на какие ухищрения пошел автор, чтобы добиться столь точного сходства.

    • fn.py – функциональные ништяки из Скалы. Аналогично, очень интересно взглянуть, что под капотом.

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

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

    Закончим с преимуществами. Питон не идеален. Вижу следующие недостатки:

    Мелкие огрехи с синтаксисом

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

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

    foo = 1, 2  # it's tuple
    bar = 1,    # it's tuple
    baz = 1     # it's int!
    

    Забыл запятую – получил не кортеж, а число. Оставил на хвосте запятую – не число, а кортеж. Не страшно, код упадет из-за разных типов. Начнется боль, когда кортеж строк. Строка и кортеж поддаются общим операциям: итерации, доступу по индексу, срезу. Код отрабатывает без падений, но выдает неверный результат. Из-за одной запятой.

    Следующий пример. Две строки подряд без запятой сливаются в одну. Это значит, кортеж

    statuses = (
        'success',
        'error'
        'timeout',
        'denied',
    )
    

    вырождается в

    ('success', 'errortimeout', 'denied')
    

    потому что нет запятой после 'error'. Проверка 'error' in statuses вернет False, что есть прямое нарушение бизнес-логики.

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

    Главенство ООП

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

    Вы когда-нибудь дебажили Джанго? Я да. Это был кастомный бекенд авторизации. Дебаг длился больше часа и напоминал БСДМ-сессию.

    Объекты Request, Response, User, Session устраивают свальный грех. Устанавливают ссылки друга несколько раз. Лезут в кэш непонятно зачем.

    Очень странные требования к бекенду авторизации. Метод .get_user() отдает объект пользователя. Потом этот пользователь где-то теряется, на него не остается ссылки. Система запрашивает метод .get_user_by_id(). Я ведь уже отдал пользователя, дубина! Значит, нужно или снова лезть в базу или сеть, либо хранить в классе словарик, что не тред-сейф.

    Почему-то в Кложе с ее неизменяемыми коллекциями мне ни разу не приходилось лазить в сессию, реквест или респонс задним числом и что-то там править. Изменения в коллекции прокидываются только вперед.

    Я не призываю программировать в сплошном ФП-стиле. Признаться, все эти статьи в духе “Программирование на Питоне в функциональном стиле” выглядят жалко. Совершенно за уши притянуты редьюсы и трехэтажные лямбды. Такой код не уживается в рамках проекта и будет выпилен, даже если его удастся как-то протащить.

    Это наносит урон функциональному программированию. Распространяется заблуждение, что ФП – это мапы и лямбды.

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

    Впрочем, это был бы уже совсем другой язык.

    Низкая скорость

    Еще год назад говорил, что это не недостаток вовсе. Память дешевая, хостинг недорогой и прочие отмазки. Сегодня считаю такой ответ уделом дилетанта.

    Скорость исполнения важна. Представьте, весь ваш софт на компе написан на Питоне. Он бы работал раз в 20-30 медленней, об играх и фотошопах пришлось забыть. Это не просто шаг назад, а откат на несколько поколений.

    Недавно мне нужно было парсить лог Nginx, Гугл выдал утилиту ngxtop. Я не посмотрел, на чем она написана, поставил из пакетов. Лог в несколько гигабайт она обрабатывала час. Оказался Питон. Утилита на Си распарсила за 5 минут. Неверный выбор стоил потери времени.

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

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

    В моем личном проекте долго жил Питон, нагрузка постоянно росла. Сервер задыхался, я не успевал поднимать тарифный план. Затем плюнул и переписал на Кложе. Не забуду это чувство, когда график CPU упал с 80 до 20 процентов.

    ГИЛ

    На упрек в адрес ГИЛа отвечают в духе “он вам не нужен”, “используй процессы”. Так говорил и я до тех пор, пока не познал, как работает многопоточность в функциональных языках.

    Мы запускаем веб-приложение на Питоне под uWSGI так. Стартует мастер-процесс. Он управляет воркерами – процессами, в каждом из которых веб-приложение. Единовременно запущены 16 Джанг, каждая из которых отвечает, когда другая занята.

    Мастер-процесс следит, чтобы все были равны. Убивает тех, кто не отвечает, выжрал слишком памяти или перетрудился – выработал лимит запросов.

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

    Распараллеливание на процессах лишает общего доступа к памяти, вынуждая использовать суррогаты вроде Memcache или Redis, в то время как самый эффективный кеш – общая память.

    Мастер-процессы вроде uWSGI и Green Unicorn – дополнительная прокладка в цепи, по которой проходит запрос. Лишний I/O, точка логирования и падения.

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

    Трудности распространения

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

    Несколько лет назад я пробовал различные упаковщики: Py2Exe, PyInstaller, CxFreeze. Собрать без ошибок приложение под Винду смог только последний. Сделал это очень хорошо: выдал *.msi-инсталлятор, зарегистрировал системную службу. Но времени на сборку и чтение доков ушло немало. Почему разработчики Питона не озаботятся тем, чтобы включить в коробку систему распространения конечного продукта?

    Чтобы написал скрипт, запустил сборку и получил архив с исполняемым файлом. Почему функциональные языки это умеют, а Питон – нет?

    Кложа выдает uberjar. Собираю его на Маке, загружаю на хостинг, где кроме Джавы ничего нет – работает без проблем. Хаскель компилируется в бинарь. Ракет, Раст – тоже. Коммон Лисп, которому тридцать лет, Карл, делает дамп Лисп-машины в бинарный файл!

    Фактически, чтобы запустить веб-приложение на Питоне, нужно иметь примерно 10.000 *.py-файлов. Если не будет одного, система не заведется. Изолировать это многообразие можно Докером, но здесь мы кривим душой.

    Листая документацию к третьему Питону, обнаружил занятный модуль zipapp. В первую минуту подумал, что напрасно упрекал язык, дело сдвинулось с мертвой точки. Оказалось, модуль не поддерживает виртуальное окружение и сишные библиотеки. Собрать простое приложение с драйвером Постгреса я не смог.

    Заключение

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

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

  • Комментарии к статье о Лиспе

    Прочитал статью Лисп – философия разработки от 2010 года. Решил законспектировать заключительынй раздел с выводами – очень уж понравились.

    Если рассмотреть каждый отдельный язык, то, как правило, можно найти его объединяющую идею. […] Для Common Lisp объединяющей идеей на данный момент является как раз расширяемость.

    Не могу с точностью судить о CL, но расширяемость в Кложе(скрипте) сделана на высоте. Пожалуй, это единственная экосистема, где любой разработчик может внести свой контриб в чужой тип или протокол без обезьяних патчей, как в Руби и Питоне. Напоминает перегрузку операторов, но в масштабах всей Лисп-машины. Это надо просто попробовать.

    В то же время у нее [Джавы] есть и сильная сторона, а именно пронизывающая весь язык модель семантической расширяемости через интерфейсы. Так что в общем-то не удивительно, что язык Clojure появился именно на Java-платформе…

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

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

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

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

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

    В этом смысле показателен пример Python, известного своим девизом «Батарейки в комплекте», который подразумевает наличие в стандартной библиотеке (почти) всего, что нужно для разработки. […] Обратная сторона медали тут отмечена в другой цитате: «Пакет, который попадает в стандартную библиотеку, стоит одной ногой в могиле»

    Меткое замечание. Не случайно автор библиотеки requests, ставшей де-факто для HTTP-запросов, заключил с Гвидо неформальное соглашение. Согласно ему, requests НЕ включается в стандартную библиотеку (чего так хотелось Гвидо), но рекомендуется к использованию на страницах официальной документации. Хитрый мужик! Знал, чем чревато.

    В Common Lisp для этого [построения расширяемых систем] используются следующие технологии: макросы для создания мини-языков для декларативного описания систем, дистрибутивов (в отличие от использования для этих целей внешних языков, таких как XML)…

    Да, достоинство Лиспов – всегда можно написать доменный язык под любую задачу благодаря системе макросов. В Лиспе построение XML, HTML, SQL вырождается в декларативное дерево с одноименными узлами (cdata, div, select).

    Кому интересно, загляните и в другие статьи Практики функционального программирования. Актуальность они не потеряли и еще долго ее сохранят.

  • Полезные практики

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

    Первое. Указываю тип переменной в имени

    Задаю переменным имена по правилу <entity>_<type>. Открыв код месячной давности, сразу вижу, где и какие типы. Даже самая коммерческая ИДЕ порой не может понять, с чем имеет дело. А с моим правилом именования работать одно удовольствие.

    Применяю его не слепо, а выборочно. Скалярным типам, например, строкам и числам, не указываю тип, если он ясен из контекста. Выражения name_str = 'test' или age_int = 42 избыточны, поскольку имя и возраст вряд ли могут быть чем-то отличным от строки и целого.

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

    permisson = response['data']['item']['permisson']
    # wtf is permisson?
    

    А ведь достаточно назвать переменную perm_int, и все станет ясно – это же числовой код!

    Указывать тип стоит везде, где кроется неожиданность. Айдишка объекта может быть передана строкой, поэтому назову переменную user_id_str, а дальше преобразую в инт. Поле может называться item, а внутри – гуид сущности, а не словарь. И так далее.

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

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

    Если работаю со словарем с данными о пользователе, называю user_dict. Список пользователей – user_list, множество – ..._set и так далее, принцип, думаю, понятен. Для кортежей и итераторов окончания tupl, iter.

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

    Смотрит коллега в монитор и не понимает, отчего Pytest падает и выводит следующее:

    assert [1L, 2L, 3L] == [1, 2, 3]
    >>> long trace...
    

    Потому что справа список, а слева – квери-сет. Он выводится как список, но не равен ему.

    Отдельным абзацем замечу, что не приемлю лексемы data в именах переменных. user_data, response_data – ужасные имена. Любая переменная, даже ноль, уже несет данные. Понятней не стало. Это словарь, список или что?

    Добавлять на конце s тоже нет смысла. Коллекция подразумевает больше одного элемента. Если не указан тип, я опять в беде: users – это сет, словарь или кортеж? Можно ли брать слайс? Подставить в ключ словаря?

    Падение на None (он же nil, null, undefined, etc) – особая история. В программировании до сих пор нет понимания, что делать с пустыми типами. Чтобы обезопасить код, полезно явно задать имя вроде user_or_none или, для краткости, user_none. Это вынудит программиста выполнить проверку перед тем, как что-то делать с данными.

    Второе. Избегаю циклов

    О вреде циклов я уже писал, и не раз. Если коротко, то:

    • ручное накопление списка или словаря чревато багами
    • со временем цикл разрастается, обрастает вложенными for, if
    • из-за отступов плохо видно бизнес-логику
    • цикл поощрает плохую практику – впендюрить continue вместо того, чтобы отфильтровать данные до входа в цикл
    • цикл плохо поддается рефакторингу, поскольку затягивает контекст – коллекцию-результат, локальные переменные, вложенные циклы.

    Решение – использовать функции высшего порядка map, filter. Я отрицательно отношусь к трехэтажным лямбдам. Использую обычные функции, объявленные через def/func/defn.

    def get_item_list(user_id):
    
        def get_item(product):
            ...
    
    item_qs = models.Item.objects.filter(user_id=user_id)
    return map(get_item, item_qs)
    

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

    Добавить новое бизнес-правило в такой код очень легко. Это будет или еще один фильтр, или изменится действие над элементом. В любом случае не съедет весь код, как в примере ниже:

    items = users.get_items()
    res = []
    for item in items:
        if items.color = 'red':
            continue
        res.append(item.id)
    

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

    
    res = []
    users = get_all_users()
    for users in users:
        items = users.get_items()
        for item in items:
            if items.color = 'red':
                continue
            res.append(item.id)
    

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

    Простое правило “дейтвие, коллекция, мап, свертка” работает без нареканий и легко адаптируется под новые требования.

    Третье. Отлавливаю ошибки как можно раньше

    Почти любая операция небезопасна и может кинуть исключение. Проблема в том, что одновременно писать бизнес-логику и следить за ошибками трудно. Каждая ошибка – это блок try-catch и запись в лог, за которыми не видно главную мысль.

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

    Мне не нравится эта ситуация, потому что она ненадержна. Язык не может внятно сказать, какие исключения возникают при конкретной операции. Это может быть описано в документации, но чаще всего выясняется эмпирически.

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

    Заворачивать весь код в try-catch – не выход. Поможет возврат пары, как в Golang. С небольшим отличием – не (ok, result_or_error), как принято в последнем, а (err_or_null, result_or_null), как в Node.js. Второй вариант логическии правильней.

    Заворачиваю функцию в простой декоратор:

    def err_result(f):
        def wrapper(*args, **kwargs):
            try:
                return None, f(*args, **kwargs)
            except Exception as e:
                return e, None
        return wrapper
    

    Или вызываю just-in-place:

    def some_func(foo):
        ...
    
    err, result = err_result(some_func)(42)
    

    Вариант с мапом. Функция-обработчик раскладывает пару на составные части с помощью деструктивного синтаксиса:

    
    item_queryset = models.Item.filter(...)
    
    def process_item(item):
        ...
    
    pair_list = map(err_result(process_item), item_queryset)
    
    def process_pair((err, result)):
        if result:
            # positive brunch
        if err:
            # negative brunch
    
    map(process_pair, pair_list)
    

    Или отделяю котлеты от мух: разбиваю список пар на плоские списки ошибок и результатов. Отдельно логирую ошибки. Передаю результаты на дальнейшую обработку. Так в коде появляется порядок.

    Конечно, в случае с одноразовым скриптом я могу завернуть все в глобальный try-catch. Но прекрасно отдаю себе отчет в том, какие последствия это имеет в боевом коде.

    Заключение

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

    Повторюсь, описанные принципы не идеальны, но с ними возникает чувство порядка. Словно код становится на рельсы, а вместе с ним и процесс. Возникает линейность, предсказуемость действий.

    Кто-то скажет, что это не питоник-вэй, что диктатор не велел. Но кому это интересно? Мы пишем код не для Гвидо или Торвальдса, а для начальников, которые в гробу видали все паттерны, главное, чтобы код работал.

    Допускаю, что прочту этот пост через 2 года и подумаю, каким чудаком я был, но пока что так.

  • Полезный сервис Requestb.in

    Наткнулся на полезный сервис Request Bin.

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

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

    Поможет Request Bin. Идея сервиса гениальна. Вам дают уникальный урл, например, http://requestb.in/1j2bq6r1. На все обращения сервис отвечает 200 ОК, а сам записывает входящий запрос в память. По адресу http://requestb.in/1j2bq6r1?inspect сервис покажет последние 20 запросов: дату, метод, заголовки, параметры.

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

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

    Request Bin поддерживает соединение по протоколу HTTPS, правда, с самоподписанным сертификатом. Это помогло при интеграции с Пейпалом. Последний требует, чтобы урл начинался с https://, но не проверяет сертификат.

    Сервису есть, что улучшить. Если в теле запроса был json, парсить и показывать красиво. Сейчас выводит как пришло – в одну строчку. Добавить экспорт запросов в любой формат. Показывать сырой запрос (т.н. raw HTTP).

  • Доклады с пятой встречи любителей рефакторить

    Провели пятую встречу!

    Я рассказал про тесты с фикстурами:

    Слайды

    Михаил Хорпяков объяснил, какие вопросы задать работодателю на собеседовании:

    Слайды

    Напомню, сообщество тусит в группе Фейсбука. Скоро анонс шестой встречи. Принимаем заявки на доклады.

Страница 53 из 73