• Реклама

    У меня очень простое отношение к рекламе: на сайте ее быть не должно.

    Я установил в Хроме Адблок и Гостери, два полезных расширения, которые вырезают до 90% рекламы. Оба периодические подтягивают с серверов информацию о новых рекламных сервисах.

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

    Если реклама пролазит не смотря на все ухищрения, с сайтом приходится расстаться. Что поделать, не судьба.

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

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

    Ребят, вы не охуели?

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

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

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

    Новостной сайт. На морде подписчику видно больше анонсов. И так далее.

    Мне несколько раз предлагали добавить рекламу на страницу личного проекта за деньги. Зачем? У меня платная подписка. Почему потребитель должен видеть какое-то говно? Он же целенаправленно зашел на мой сайт. Разве правильно показывать левую инфу по результатам вчерашнего гугления?

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

    Или Медуза. На морде обязательно висит несколько “партнерских материалов”. А что это другими словами? Реклама, Карл.

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

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

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

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

  • Правила работы с почтой

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

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

    Фильтры и правила. У меня масса правил, чтобы раскладывать почту по нужным папкам. Это позволяет не отвлекаться на рассылки или уведомления, которые не требуют мгновенной реакции. Мне достаточно окинуть взглядом папки, чтобы понять, что меня ожидает. Например, папки yandex (2) и facebook (1) говорят о том, что пришли уведомления, которые можно посмотреть потом.

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

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

    – “А вот уеду я в отпуск, – говорит коллега, – и не хочу видеть письма с работы”. Не вопрос! Скрой эту папку в настройках интерфейса, по возвращению опять верни.

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

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

    На десктопе плохо сделан поиск. В Гугле он просто охренеть какой классный и работает мгновенно.

    Только плоский текст. Никаких шрифтов, болдов, италиков. Только плейн-текст.

    Никаких подписей. Свое имя в конце письма я вписываю руками. Жирный абзац с должностью, телефонами и ссылками на соцсети – признак неадеквата. Огрызки типа “С ув, Алексей” – тоже.

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

    Банальности. Стараюсь писать без ошибок, проверять имена, не ставить пробелы перед знаками препинания.

    Не больше одного восклицательного знака на письмо.

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

  • JSON в 1С на Гитхабе

    Наконец-то дошли руки выложить полезную функцию 1С на Гитхаб. Речь о сериализации любого объекта в JSON. Ранее в блоге я публиковал ссылки на Pastebin, но теперь с этим покончено.

    Ссылка на репозиторий.

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

    Код не требует сторонних модулей и работает с версиями 8.1 и выше. Кажется, в 8.3 грозились добавить аналог в коробку, но я за этим не слежу.

    Пользуйтесь на здоровье.

  • Спорт

    Нет ничего отвратительней большого спорта.

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

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

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

    Спорт высасывает колоссальные деньги из стран в пользу спортивной мафии. Всякие ФИФА и МОК – обычный лохотрон, только разводят не отдельных лиц, а целые страны.

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

    Все состязания должны быть в одном месте. Летние – а какой-нибудь Греции, зимние – в странах северной Европы.

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

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

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

    Большой спорт – безумие. Он оттдает низостью, коррупцией и маргиналами. Брр.

  • Без названия

    bot

  • Восьмая встреча

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

    Я рассказал про монады. Читали Булгакова? “Оно, может, умно, да непонятно. Над вами потешаться будут.” Потешались надо мной где-то час:

    Слайды

    Денис Ковалев рассказал про криптографию. Очень хороший доклад получился:

    Слайды

    Напомню, сообщество тусит в группе Фейсбука.

    Скоро анонс девятой встречи. Хотите выступить? Пишите в группу.

  • Докер

    Последний месяц меня дико прет с Докера. Это настоящий прорыв в индустрии. Я подключаю Докер ко всем репозиториям. Решил поделиться впечатлениями, описать плюсы и рассмотреть реальный пример.

    Про Докер написано очень много. Я не собираюсь досканально описывать как он работает. Расскажу лишь кратко о том, что вы, возможно, не слышали.

    Докер – утилита для запуска процесса в изолированном окружении. Технически это работает поверх одной из фич ядра Линукса – Cgroups.

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

    Этот плюс я уже испытал на практике. Мне пришел из ремонта Мак. За время работы на Линуксе я успел перевести большую часть репозиториев на Докер. На Маке все завелось без проблем.

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

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

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

    В случае с Докером все файлы ложатся в образ – единый файл. Удалив его, мы достоверно вернем систему в то состояние, в котором она была до билда.

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

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

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

    По этой причине я смеюсь над Микрософтом, которые добавили ps и grep в 10 Виноуз. Кому это нужно? В сети тысячи версий юникс-утилит, скомпилированных под Винду. Скорей делайте нативный Докер!

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

    Докер – это отсутствие состояния. Контейнер может удалить все файлы внутри себя, нагадить в конфиги и аварийно завершиться. Но стоит запустить контейнер из образа, и мы вновь в прежнем состоянии: файлы, конфиги на месте. Иммутабельность – это круто.

    Докер отлично подходит для билдов всего и вся. Собрать проект, который требует миллион пакетов и библиотек – милое дело.

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

    Существует официальный хаб образов. Оттуда можно скачать образ ЛЮБОЙ версии Питона, Руби, Постгреса и т.д. Помните, какой это геморрой – на систему с Питоном 2.7 ставить 3.4? Или проверить баг на старой версии БД? Теперь c этим покончено.

    Хранить приватные образы в хабе Докера разрешено за деньги. Альтернативой может стать официальный сервис Амазона ECR, где все операции над образами бесплатны.

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

    Теперь рассмотрим реальный пример применения Докера.

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

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

    Установка Докера подробно описана на официальном сайте под каждую операционку в отдельности.

    В корне проекта создаем файлик Dockerfile с содержимым:

    FROM ubuntu:16.04
    
    RUN apt-get update
    RUN apt-get install -y jekyll bundler
    
    RUN mkdir /blog
    WORKDIR /blog
    COPY Gemfile* ./
    RUN bundle install
    RUN rm Gemfile*
    
    CMD ["jekyll", "serve"]
    

    Разберемся построчно:

    • Образ унаследован от официального образа Убунты версии 16.04.
    • При создании образа обновить информацию о пакетах.
    • Установить из пакетов jekyll (движок) и bundler (установщик пакетов для Руби).
    • Создать внутри образа папку blog в корне.
    • Перейти в нее.
    • Скопировать из хост-системы в образ файлы Gemfile и Gemfile.lock. Это аналог питонячьего pip.requirements.txt.
    • Поставить пакеты, специфичные для проекта.
    • Удалить Gem-файлы.
    • При запуске контейнера стартануть локальный сервер.

    Собираем образ Make-командой:

    docker-build:
    	docker build -t blog .
    

    Параметр -t <foo:bar> задает имя и тег для образа.

    Посмотрите, что показывает консоль при сборке:

    The following additional packages will be installed:
      ca-certificates cpp cpp-5 dbus file fontconfig-config fonts-dejavu-core
      fonts-lato ifupdown iproute2 isc-dhcp-client isc-dhcp-common
      javascript-common krb5-locales libasn1-8-heimdal libatm1 libauthen-sasl-perl
      libbsd0 libcap-ng0 libdbus-1-3 libdns-export162 libdrm-amdgpu1 libdrm-intel1
      libdrm-nouveau2 libdrm-radeon1 libdrm2 libedit2 libelf1
      libencode-locale-perl libexpat1 libffi6 libfile-basedir-perl
      libfile-desktopentry-perl libfile-listing-perl libfile-mimeinfo-perl
      libfont-afm-perl libfontconfig1 libfontenc1 libfreetype6 libgdbm3
      libgl1-mesa-dri libgl1-mesa-glx libglapi-mesa libglib2.0-0 libglib2.0-data
      libgmp10 libgnutls30 libgssapi-krb5-2 libgssapi3-heimdal libhcrypto4-heimdal
      libheimbase1-heimdal libheimntlm0-heimdal libhogweed4 libhtml-form-perl
      libhtml-format-perl libhtml-parser-perl libhtml-tagset-perl
      libhtml-tree-perl libhttp-cookies-perl libhttp-daemon-perl libhttp-date-perl
      libhttp-message-perl libhttp-negotiate-perl libhx509-5-heimdal libice6
      libicu55 libidn11 libio-html-perl libio-socket-ssl-perl
      libipc-system-simple-perl libisc-export160 libisl15 libjs-coffeescript
      libjs-jquery libk5crypto3 libkeyutils1 libkrb5-26-heimdal libkrb5-3
      libkrb5support0 libldap-2.4-2 libllvm3.8 liblwp-mediatypes-perl
      liblwp-protocol-https-perl libmagic1 libmailtools-perl libmnl0 libmpc3
      libmpfr4 libmysqlclient20 libnet-dbus-perl libnet-http-perl
      libnet-smtp-ssl-perl libnet-ssleay-perl libnettle6 libp11-kit0 libpciaccess0
      libperl5.22 libpng12-0 libpq5 libpython-stdlib libpython2.7-minimal
      libpython2.7-stdlib libroken18-heimdal libruby2.3 libsasl2-2
      libsasl2-modules libsasl2-modules-db libsm6 libsqlite3-0 libssl1.0.0
      libtasn1-6 libtext-iconv-perl libtie-ixhash-perl libtimedate-perl
      libtxc-dxtn-s2tc0 liburi-perl libuv1 libwind0-heimdal libwww-perl
      libwww-robotrules-perl libx11-6 libx11-data libx11-protocol-perl libx11-xcb1
      libxau6 libxaw7 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0
      libxcb-shape0 libxcb-sync1 libxcb1 libxcomposite1 libxcursor1 libxdamage1
      libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxml-parser-perl
      libxml-twig-perl libxml-xpathengine-perl libxml2 libxmu6 libxmuu1 libxpm4
      libxrandr2 libxrender1 libxshmfence1 libxt6 libxtables11 libxtst6 libxv1
      libxxf86dga1 libxxf86vm1 libyaml-0-2 mime-support mysql-common netbase
      nodejs openssl perl perl-modules-5.22 python python-chardet python-minimal
      python-pkg-resources python-pygments python2.7 python2.7-minimal rake rename
      ruby ruby-afm ruby-ascii85 ruby-blankslate ruby-classifier-reborn
      ruby-coderay ruby-coffee-script ruby-coffee-script-source ruby-colorator
      ruby-did-you-mean ruby-execjs ruby-fast-stemmer ruby-ffi ruby-hashery
      ruby-jekyll-coffeescript ruby-jekyll-feed ruby-jekyll-gist
      ruby-jekyll-paginate ruby-jekyll-sass-converter ruby-jekyll-watch ruby-json
      ruby-kramdown ruby-liquid ruby-listen ruby-mercenary ruby-mime-types
      ruby-minitest ruby-multi-json ruby-mysql ruby-net-telnet ruby-oj
      ruby-parslet ruby-pdf-core ruby-pdf-reader ruby-pg ruby-posix-spawn
      ruby-power-assert ruby-prawn ruby-prawn-table ruby-pygments.rb
      ruby-rb-inotify ruby-rc4 ruby-rdiscount ruby-redcarpet ruby-rouge
      ruby-safe-yaml ruby-sass ruby-sequel ruby-sequel-pg ruby-stringex
      ruby-test-unit ruby-toml ruby-ttfunk ruby-yajl ruby2.3 rubygems-integration
      sgml-base shared-mime-info ucf unzip x11-common x11-utils x11-xserver-utils
      xdg-user-dirs xdg-utils xml-core zip
    Suggested packages:
      cpp-doc gcc-5-locales dbus-user-session | dbus-x11 ppp rdnssd iproute2-doc
      resolvconf avahi-autoipd isc-dhcp-client-ddns apparmor apache2 | lighttpd
      | httpd libdigest-hmac-perl libgssapi-perl gnutls-bin krb5-doc krb5-user
      libdata-dump-perl coffeescript libcrypt-ssleay-perl pciutils
      libsasl2-modules-otp libsasl2-modules-ldap libsasl2-modules-sql
      libsasl2-modules-gssapi-mit | libsasl2-modules-gssapi-heimdal
      libauthen-ntlm-perl libunicode-map8-perl libunicode-string-perl
      xml-twig-tools perl-doc libterm-readline-gnu-perl
      | libterm-readline-perl-perl make python-doc python-tk python-setuptools
      ttf-bitstream-vera python2.7-doc binutils binfmt-support ri ruby-dev
      libjs-mathjax ruby-activesupport doc-base coderay fonts-arphic-gkai00mp
      ruby-pdf-inspector ruby-prawn-doc ttf-dejavu-core bundler sgml-base-doc
      mesa-utils nickle cairo-5c xorg-docs-core gvfs-bin debhelper
    The following NEW packages will be installed:
      ca-certificates cpp cpp-5 dbus file fontconfig-config fonts-dejavu-core
      fonts-lato ifupdown iproute2 isc-dhcp-client isc-dhcp-common
      javascript-common jekyll krb5-locales libasn1-8-heimdal libatm1
      libauthen-sasl-perl libbsd0 libcap-ng0 libdbus-1-3 libdns-export162
      libdrm-amdgpu1 libdrm-intel1 libdrm-nouveau2 libdrm-radeon1 libdrm2 libedit2
      libelf1 libencode-locale-perl libexpat1 libffi6 libfile-basedir-perl
      libfile-desktopentry-perl libfile-listing-perl libfile-mimeinfo-perl
      libfont-afm-perl libfontconfig1 libfontenc1 libfreetype6 libgdbm3
      libgl1-mesa-dri libgl1-mesa-glx libglapi-mesa libglib2.0-0 libglib2.0-data
      libgmp10 libgnutls30 libgssapi-krb5-2 libgssapi3-heimdal libhcrypto4-heimdal
      libheimbase1-heimdal libheimntlm0-heimdal libhogweed4 libhtml-form-perl
      libhtml-format-perl libhtml-parser-perl libhtml-tagset-perl
      libhtml-tree-perl libhttp-cookies-perl libhttp-daemon-perl libhttp-date-perl
      libhttp-message-perl libhttp-negotiate-perl libhx509-5-heimdal libice6
      libicu55 libidn11 libio-html-perl libio-socket-ssl-perl
      libipc-system-simple-perl libisc-export160 libisl15 libjs-coffeescript
      libjs-jquery libk5crypto3 libkeyutils1 libkrb5-26-heimdal libkrb5-3
      libkrb5support0 libldap-2.4-2 libllvm3.8 liblwp-mediatypes-perl
      liblwp-protocol-https-perl libmagic1 libmailtools-perl libmnl0 libmpc3
      libmpfr4 libmysqlclient20 libnet-dbus-perl libnet-http-perl
      libnet-smtp-ssl-perl libnet-ssleay-perl libnettle6 libp11-kit0 libpciaccess0
      libperl5.22 libpng12-0 libpq5 libpython-stdlib libpython2.7-minimal
      libpython2.7-stdlib libroken18-heimdal libruby2.3 libsasl2-2
      libsasl2-modules libsasl2-modules-db libsm6 libsqlite3-0 libssl1.0.0
      libtasn1-6 libtext-iconv-perl libtie-ixhash-perl libtimedate-perl
      libtxc-dxtn-s2tc0 liburi-perl libuv1 libwind0-heimdal libwww-perl
      libwww-robotrules-perl libx11-6 libx11-data libx11-protocol-perl libx11-xcb1
      libxau6 libxaw7 libxcb-dri2-0 libxcb-dri3-0 libxcb-glx0 libxcb-present0
      libxcb-shape0 libxcb-sync1 libxcb1 libxcomposite1 libxcursor1 libxdamage1
      libxdmcp6 libxext6 libxfixes3 libxft2 libxi6 libxinerama1 libxml-parser-perl
      libxml-twig-perl libxml-xpathengine-perl libxml2 libxmu6 libxmuu1 libxpm4
      libxrandr2 libxrender1 libxshmfence1 libxt6 libxtables11 libxtst6 libxv1
      libxxf86dga1 libxxf86vm1 libyaml-0-2 mime-support mysql-common netbase
      nodejs openssl perl perl-modules-5.22 python python-chardet python-minimal
      python-pkg-resources python-pygments python2.7 python2.7-minimal rake rename
      ruby ruby-afm ruby-ascii85 ruby-blankslate ruby-classifier-reborn
      ruby-coderay ruby-coffee-script ruby-coffee-script-source ruby-colorator
      ruby-did-you-mean ruby-execjs ruby-fast-stemmer ruby-ffi ruby-hashery
      ruby-jekyll-coffeescript ruby-jekyll-feed ruby-jekyll-gist
      ruby-jekyll-paginate ruby-jekyll-sass-converter ruby-jekyll-watch ruby-json
      ruby-kramdown ruby-liquid ruby-listen ruby-mercenary ruby-mime-types
      ruby-minitest ruby-multi-json ruby-mysql ruby-net-telnet ruby-oj
      ruby-parslet ruby-pdf-core ruby-pdf-reader ruby-pg ruby-posix-spawn
      ruby-power-assert ruby-prawn ruby-prawn-table ruby-pygments.rb
      ruby-rb-inotify ruby-rc4 ruby-rdiscount ruby-redcarpet ruby-rouge
      ruby-safe-yaml ruby-sass ruby-sequel ruby-sequel-pg ruby-stringex
      ruby-test-unit ruby-toml ruby-ttfunk ruby-yajl ruby2.3 rubygems-integration
      sgml-base shared-mime-info ucf unzip x11-common x11-utils x11-xserver-utils
      xdg-user-dirs xdg-utils xml-core zip
    

    А ю факин сириес? Миллион пакетов на установку одной тулзы! Представьте теперь, что ставите ее нативно, без Докера. Колоссальное захламление системы. Вы не сможете потом удалить эти пакеты. Не записывать же их на бумажку.

    Это точка невозврата. Без Докера вы не сможете сделать систему такой, какой она была до установки.

    Ок, образ собрался. Запускаем через Make:

    docker-run:
    	docker run -it --rm -p 4000:4000 -v $(CURDIR):/blog blog
    

    Параметры:

    • -it значит прикрепить STDIN хост-системы к контейнеру. Иначе говоря, считывать пайпы или ввод с клавиатуры.
    • --rm – удалить контейнер по завершении процесса.
    • -p 4000:4000 – пробросить 4000 порт хост-системы на аналогичный порт контейнера.
    • -v $(CURDIR):/blog – смонтировать текущую папку хост-системы в папку /blog образа.

    Make-переменная $(CURDIR) означает текущую папку. К сожалению, при пробросе томов нельзя указать относительный путь, а хардкодить в Гите – моветон.

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

    При старте образа автоматом запустится сборка блога и сервер. Мне останется открыть в браузере http://127.0.0.1:4000/ и посмотреть на результат. При изменении маркдаун-файлов – не важно где, в образе или на хосте – блог автоматом себя перестроит.

    Посмотреть исходники для Make и Докера можно в репозитории блога. Возможно, в следующий раз я расскажу об инструменте Docker Compose. С помощью него мы создадим три контейнера – приложение, база и Редис – и заставим идти в одной упряжке как единое целое.

    Используете ли вы Докер, и если да, то как?

  • Антитеизм

    Оказывается, мое отношение к религии называется “Антитеизм”. Вот и хорошо, теперь можно просто ссылку кидать.

    ТЫЦ

    Цитата:

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

  • Питонячьи хитрости

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

    Многоточие

    Неожиданно, при определенных условиях многоточие ... становится правильной лексемой! Внутри оператора [] многоточие вырождается в объект Ellipsis:

    >>> d = {(1, Ellipsis, 2): 42}
    >>> d[1, ..., 2]
    42
    

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

    # бесконечный ленивый список от единицы
    List[1, ...]
    
    # ленивый список от 1 до 100
    List[1, ..., 100]
    
    # аналогично, но с шагом в 2
    List[1, 3, ...]
    

    В другом месте многоточие вызовет ошибку синтаксиса.

    Срезы в аргументах

    В оператор индекса [] можно передать синтаксис словаря: key: value, .... Тогда в методе __getitem__ мы получим кортеж объектов slice. Ключ и значение хранятся в полях .start и .stop. Выглядит так:

        def __getitem__(cls, slices):
    
            if isinstance(slices, tuple):
                slice_tuple = slices
            else:
                slice_tuple = (slices, )
    
            keys = (sl.start for sl in slice_tuple)
            vals = (sl.stop for sl in slice_tuple)
    
            return dict(zip(keys, vals))
    
    YourClass["foo": 42, "bar": "test"]
    >>> {"foo": 42, "bar": "test"}
    

    Деструктивный синтаксис

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

    Это объективный минус третьего Питона. Зачем лишать разработчиков удобной возможности? Я постоянно работаю с парами. Синтаксиса def action((key, val)): теперь будет не хватать.

    Погружение в словарь

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

    data.get('result', {}).get('user', {}).get('name', 'unknown')
    

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

    Неочевидный минус, из-за которого придется чинить прод в пятницу, кроется в методе .get. Он возвращает дефолт только если ключа нет. А если ключ есть и равен None, то вернется None вне зависимости от того, что передано в дефолт.

    data = {"result": {"user": None}}
    data.get('result', {}).get('user', {}).get('name', 'unknown')
    >>> AttributeError: 'NoneType' object has no attribute 'get'
    

    В библиотеке f я предложил нормальный способ работы со вложенными словарями:

    f.ichain(data, 'result', 'user', 'name')
    >>> None
    

    Конечное приведение типов

    Приводить типы в конце каждой операции – здравая мысль. Идея в том, чтобы добавлять к концу вычислений кусочек ... or <default>, например:

    get_users_count() or 0
    >>> 0
    
    get_account_list(id) or []
    >>> []
    
    f.ichain(data, 'result', 'user', 'name') or 'dunno'
    >>> dunno
    

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

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

    data = {"user": None}
    (data.get("user") or {}).get("name") or "dunno"
    >>> "dunno"
    

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

    Правые методы

    Еще одна особенность классов в Питоне – правые волшебные методы. Они начинаются с префикса r: __radd__, __rsub__ и т.д. Как следует из названия, эти методы вызываются для правого операнда в тех случаях, когда для левого операнда метод не определен.

    Другими словами, рассмотрим выражение a + b. Сперва Питон попытается сделать так: a.__add__(b). Если для a метод __add__ неопределен, будет предпринята другая попытка: b.__radd__(a). И если __radd__ тоже не определен для b, вылезет ошибка.

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

    class List(list):
    
        def __add__(self, other):
            if isinstance(other, list):
                return super(List, self).__add__(other)
            else:
                return self + [other]
    
        def __radd__(self, other):
            if isinstance(other, list):
                return other.__add__(self)
            else:
                return [other].__add__(self)
    
    >>> 99 + List([1, 2, 3])
    [99, 1, 2, 3]
    
    >>> List([1, 2, 3]) + 99
    [1, 2, 3, 99]
    

    Особенности среза в тройке

    Во втором Питоне у классов был особый метод __getslice__ для получения среза. В тройке его объединили с __getitem__. Теперь интерпретатор проверяет, что передано в __getitem__. Если написать foo[1:2], будет передан экземпляр класса slice, а если foo[1, 2] – кортеж.

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

        def __getitem__(self, item):
            if isinstance(item, slice):
                return super(MyClass, self).__getitem__(item)
            else:
                ...
    
  • Настольный Линукс

    Пока Макбук на ремонте, вынужденно работаю в Убунте. Достал с антресолей старенький Леново x220i, скачал образ 16.04, поставил с флешки. I’m using Linux, woo-hoo!

    Возвращаться в эту среду было интересно по двум причинам. Во-первых, испытать прошлый опыт. До Мака я довольно долго сидел на Убунте с оконным менеджером i3. Во-вторых, оценить, что изменилось за 2 года c Маком, и в какую сторону.

    Ожидаемо, настольный Линкус по-прежнему уступает Маку. Удивляет, что многие из претензий могли бы быть исправлены уже сейчас. Разработчикам Убунты не нужно, как Джобсу, брить голову и идти в монахи. Достаточно поработать недельку в Маке, а потом сесть за собственное поделие.

    Первая претензия – ошибки при старте системы. Стоило поставить из пакетов стандартные утилиты вроде Гита, Емакса, dev-библиотек, как при загрузке вылазят диалоги “System Program Error”. Что случилось, как починить – не понятно. Число ошибок со временем растет. Была одна, стало две. У знакомого штук 12 выскакивало.

    Убунта не вывозит без частой перезагрузки. Работая на Маке, я не выключал его месяцами. 2-3 месяца непрерывной работы – обычное дело. Рекод был 5 месяцев, и все без перебоев.

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

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

    Разработчики Убунты не имеют базовых понятий об интерфейсе. Тыкая на балон с нотификацией, я ожидаю увидеть окно с полной информацией. Но в Убунте принято просто показать балон, а как добраться до цели – твои проблемы.

    Наример, всплывает нотификашка – “Your software needs to be updated”. Ну, ок, обновляйся. Тыкаю в пузырь, он бледнеет, ничего не происходит. Я сам должен идти в дебри настроек и запускать апдейт. Заняться мне больше нечем, ага.

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

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

    Установщик пакетов – беда. Поставить пакет без трудностей можно только в терминале.

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

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

    Убунтоводы, не спешите писать о недостатках Мака. Они есть, но о них в другом посте.

Страница 57 из 79