-
Без названия
-
Восьмая встреча
Провели восьмую встречу!
Я рассказал про монады. Читали Булгакова? “Оно, может, умно, да непонятно. Над вами потешаться будут.” Потешались надо мной где-то час:
Денис Ковалев рассказал про криптографию. Очень хороший доклад получился:
Напомню, сообщество тусит в группе Фейсбука.
Скоро анонс девятой встречи. Хотите выступить? Пишите в группу.
-
Докер
Последний месяц меня дико прет с Докера. Это настоящий прорыв в индустрии. Я подключаю Докер ко всем репозиториям. Решил поделиться впечатлениями, описать плюсы и рассмотреть реальный пример.
Про Докер написано очень много. Я не собираюсь досканально описывать как он работает. Расскажу лишь кратко о том, что вы, возможно, не слышали.
Докер – утилита для запуска процесса в изолированном окружении. Технически это работает поверх одной из фич ядра Линукса – 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 минут чтобы нагуглить рецепт, вспомнить забытую команду, поправить конфиг, перезагрузиться. Хотя вообще-то сел работать.
Мак не идеален, но как настольная система для повседневных задач гораздо стабильней. Именно настольная, я делаю акцент. Потому что в серверном плане у Линукса нет конкурентов. Десктоп пилить и пилить еще.
Убунтоводы, не спешите писать о недостатках Мака. Они есть, но о них в другом посте.
-
Книга "Цель"
Ох, какую книгу я прочитал – обзавидуетесь! Книга-праздник. Так я называю книги, удовольствие от которых почти физическое. Рад представить:
Цель. Процесс непрерывного улучшения
Это бизнес-роман. С таким жанром я столкнулся впервые и был приятно удивлен. Цель – это история об увлекательных тайнах бизнеса, оптимизации производства, финансовых делах. Все это проходит сквозь жизнь главного героя, который взвалил на себя нелегкую задачу в бизнесе. Одновременно он вынужден разобраться с личными и семейными проблемами.
Алекс Рого, прообраз автора – директор завода в небольшом американском городке. Дела на заводе идут плохо: заказы просрочены, процесс неясен, нехватка материалов, задержки во всех рабочих центрах. Особо важные заказы приходится “протаскивать”: в буквальном смысле сопровождать каждую партию деталей по станкам, требовать экстренной перенастройки оборудования, набирать внеурочные смены.
Из-за нервной обстановки нервы на пределе, рабочие допускают ошибки. Самый важный заказ не ушел в срок: механик неверно наладил станок. Много брака, станок уходит в ремонт. Счет за экстренный выезд наладчиков уводит прибыль от заказа в минус. Мастер, допустивший ошибку, увольняется из-за нервов и боязни вычета. У других рабочих нет квалификации для этого станка.
И так каждую неделю. Алекс фактически живет на заводе, пытаясь разрулить трудности. Начинаются проблемы в семье.
Дела идут плохо не только на заводе Алекса, но и во всем дивизионе. Алексу ставят ультиматум – если за 3 месяца не изменить ситуацию к лучшему, завод закроют.
Для Алекса это катастрофа, провал, карьерная смерть. На новом рабочем месте ему предложат низкую должность. Если остаться в текущей фирме, не будет уважения. Алекс – надежда города, потому что завод дает тысячу рабочих мест, а с бюджетом у городка не густо.
Главный герой пытается обратиться к книгам и учебным материалам, но ни времени, ни сил на обучение не остается. Попытки провести анализ ситуации не дают успеха. Помощь приходит с неожиданной стороны – от бывшего учителя по физике Ионы.
Ранее ученый-физик, Иона занимается оптимизацией процессов на производстве. Задав несколько вопросов, он быстрей Алекса понимает, в какой заднице завод. Иона дает несколько странных, с точки зрения Алекса, советов. Один из них звучит так – прежде чем мы начнем спасать завод, определи, в чем цель фирмы.
Что дальше – не описать. Три напряженных месяца. Жизнь в жутком стрессе в ожидании провала. Разрыв с женой. Первые проблески надежды. Снова проблемы. Очередные наставления Ионы, взрывающие мозг. Успех. Новые трудности, дело безнадежно. Потом…
Короче, надо читать самому. Книга рвет изрядное число шаблонов.
-
На предприятии обязательно есть то, что главный герой называет бутылочным горлышком. Это станок, сотрудник или узел, где мощность пропускного потока ограничена. Горлышко есть всегда. Нежелание его обнаружить – главная проблема на производстве.
-
Бутылочное горлышко отвечает за производительность предприятия в целом. Час, потерянный в горлышке, невозможно нагнать на следующих стадиях производства.
-
Горлышек может быть несколько. В общем случае, их наличие – норма и даже желаемый факт. Регулируя мощность горлышек, мы меняем производительность всего предприятия.
-
Обычный рабочий центр (или не-бутылочное горлышко) не должен работать свыше нормы, заданной рынком. Иначе бутылочное горлышко не сможет потребить потенциал не-горлышка, и возникнет избыточное производство.
-
Последний термин полностью звучит как “Материально-товарные ценности”. Это все, что было созданно в процесе производства. Высокое значение показателя говорит о проблемах со сбытом. Если ценности растут, значит, производство делает продукт, но его не покупают.
-
Предприятие, в котором все центры работают на полную мощность – неэффективно! Рано или поздно процесс упрется в бутылочные горлышки, которые не были заметны раньше.
-
Напротив, эффективно работает то предприятие, где всегда остается запас нереализованной мощности. Это значит, что не люди бездельники. Персонал и оборудование не обеспечили заказами. Нужно работать с рынком, искать новых заказчиков.
-
Вот почему вредно нагружать работой людей и технику только за тем, чтобы не было простоев. Сотрудники поймут, что с головой у руководства не в порядке. В случае с техникой нельзя забывать амортизацию и Мерфи.
-
Ритм важнее темпа. Размеренность производства в приоритете перед скоростью конкретного рабочего центра. Выигрыш в час рабочего времени на обычном узле не несет выигрыша в целом.
-
По этой же причине могут оказаться ложными показатели эффективности на отдельных рабочих местах. Да, каждый справился на ура, но продукт выпустили с опозданием. Работа на выходных съела часть прибыли. Кто виноват?
-
В цепи событий возможны колебания. Ошибочно считать, что они нейтрализуют друг друга. Напротив, погрешности накапливаются и двигаются волнами. Волна значит бессонную ночь, задержки, увольнения.
-
Пример: рабочие последовательно обрабатывают детали, передают их друг другу. Эмпирически определена средняя выработка рабочего:
N
деталей в час. По факту он делает от(N - 5)
до(N + 5)
деталей в час. Можем предположить, что если первый случайно сделал(N - 2)
деталей, то второй с такой же вероятностью сделает(N + 2)
, что сведет погрешность в ноль. На самом деле второй рабочий не сможет сделать(N + 2)
, потому что получит от первого только(N - 2)
. И все остальные сделают не больше(N - 2)
. Это значит, негативная погрешность распространяется до конца цепочки, а позитивная, даже если случится, будет поглащена негативной где-то внутри. -
Этому существует математическое обоснование. Алекс провел игру с одноклассниками сына. Мальчики кидали кости и передавали спички (детали). Количество очков (обработанных деталей) распределилось строго по убыванию очереди. Хотя среднее число очков на кости было одинаковым для каждого мальчика (3.5), чем дальше он был в цепи, тем меньше спичек (деталей) мог переложить из своей тарелки (рабочего центра) следующему.
-
Чтобы решить проблемы в фирме, нужно четко понять, в чем ее цель. Незнание цели ведет к растрате ресурсов и ложным ожиданиям.
-
Ограничения носят блуждающий характер. Устранив ограничение, наивный руководитель откидывается в кресло до наступления нового завала. Мудрый руководитель умеет предсказать, где возникнет новое.
-
Использование ресурса не всегда ведет к достижению цели. Например, заставить рабочих таскать мешки из угла в угол только потому, что у них простой. Это повысит показатели эффективности (8 рабочих часов вместо 6), но не приведет к достижению цели.
-
Новинки технического прогресса приносят пользу фирме лишь при правильном их использовании. Так, формально новый роботизированный станок улучшил эффективность фирмы по всем статьям, но на деле лишь быстрей потащил ее на финансовое дно.
-
Намереваясь сделать очередной шаг, спросите себя, как он приблизит вас к цели. Например: добавляя эту фичу, мы улучшаем продукт, что расширит базу клиентов и принесет прибыль. Контр-пример: мы хотим заменить устаревший фреймворк на современный. Клиенты не почувствуют разницу, но разработчикам будет интересно.
-
Смотрите на любую вещь так, словно видете ее впервые. Оспаривайте выводы, которые следуют из “здравого смысла” или “общеизвестных фактов”. Это главная мысль книги.
Самый классный эпизод – три главы про поход Алекса с сыном и одноклассниками в лес. Столько проблем и идей! Материал в этом месте особо плотный.
Книгу дополняют интервью с автором и руководителями крупных фирм, внедривших его практики. Директор одного из заводов Дженерал Моторс рассказывает, что у него ушло 5 лет на одни только бутылочные горлышки.
Теперь о том, какое отношение книга имеет к ай-ти. Я считаю, непосредственное. Группа программистов – не завод, но многие из идей автора верны для любой фирмы или просто группы людей. Что именно, полагаю, напишу отдельным постом.
Пока читал книгу, вспоминал один крупный проект. Компания – гигант, деньги гребет лопатой. Команда не маленькая. Но – мы не успевали. Каждый релиз был мрак и боль. Внезапные баги, патчи на прод. Задержки, перенос релизов. И когда я пытался сказать, что это неправильно, отвечали – так у всех. Поиск виноватых напоминал ситуацию с заводом. Каждый в отдельности отработал отлично, закрыл таски в Джире. А релиз хромой и с опозданием на неделю.
К счастью, я понял, что так не у всех. Нужно только пересмотреть ситуацию и пойти к цели маленькими шагами. Если у всех плохо, не значит, что должно быть и у вас. Герой автора это доказал. Ищите ограничения, смотрите на вещи под другим углом и не ведитесь на общепринятые догмы.
-
-
Как писать иностранные термины
В комментариях на Хабре мне пишут, что, оказывается, я неправильно пишу зарубежные термины – кириллицей, а надо латиницей. Это называют “в привычной манере”. И добавляют: imho.
С этой болезнью я борюсь давно и не удивляюсь прокаженным.
Нет смысла спорить с человеком, который полагает, что писать “Google” вместо Гугл или “iPhone” вместо Айфон – правильно. Это означает серьезную брешь в самообразовании. Доказывать что-то бесполезно. Человек должен сам прийти к тому, что правильно будет Гугл, Айфон, Айпад, Гит, Джаваскрипт и так далее.
Запомните следующий тезис:
Не бывает слов, которые не переводятся
То есть вообще не бывает. Понятно? Любое слово из английского, испанского или китайского можно взять и перевести.
Помните начало нулевых? Тогда многие всерьез писали Internet или Web-site. Они думали, что эти слова не переводятся. А сегодня разве кто-то пишет Internet? Только тот, кто не имеет к нему отношения.
Покажите мне человека, который пишет Pepsi вместо Пепси или Coca-Cola вместо Кока-Кола. Почему-то эти слова прекрасно переводятся.
По аналогии, переводятся технические слова: названия инструментов, языков, паттернов. Кстати, мы же не пишем pattern, а просто фигачим транслитом. Примеров этому тысячи.
Непривычно! – кричит хабраюзер, который всю жизнь довольствовался треш-переводами, где русских слов меньше, чем английских. Все сперва непривычно. Новый язык, браузер, телефон, переезд – непривычно. Секс в первый раз тоже непривычен.
Несколько лет назад я участвовал в мероприятии по переводу документации системы Друпал. Знаете, такой мамонт на пы-хы-пе. Мой перевод не приняли по той причине, что термин URL, оказывается, не переводится!
Админ с багом решил распространить баг на меня. В итоговой документации английских слов было поровну с русскими. Это назвали переводом и выбросили в сообщество.
Кто сегодня в трезвом уме пишет URL? Пишут “ссылка”, “адрес”. Представьте:
Миша, скинь URL на твой профиль в Skype?
Видно же, что у человека рак мозга: четые раза переключал раскладку, набирал капсом или с шифтом. Как можно позволить себе такую неэффективность? Это только секретарше в госконторе простительно.
Развитый человек смотрит на проблему перевода с недоумением. В математике, если нельзя вычислить значение функции от аргумента, должно быть этому обоснование. Например, нельзя посчитать
a / x
приx = 0
. А почему слово нельзя перевести? Кто-то может внятно объяснить, не ссылаясь на привычки и “здравый смысл”?Особо одаренные пишут термин латиницей, а на хвост сажают русское окончание. Получаюся уродцы в духе:
…расскажет о websocket-ах!
…опубликовать в Facebook-е.
…показать только свежие commit-ы?
Вот смотрите, американец пишет текст. Если попадется слово на русском, польском, китайском языках, он ни за что не напишет оригиналом. Вообще никогда. Потому что американский писатель уважает читателей. Как они прочтут незнакомое слово?
Кириллица для американца – все равно что иероглифы для русского. Как прочесть букву “р”? Это “эр” или “пэ”? Буква “м” – это наша, американская “эм” или что-то другое?
Вот идет гопник в майке с надписью “Russia”. Кто-нибудь хоть раз видел, чтобы американцы печатали на одежде “США”?
Разве бывает, чтобы слово “водка” американцы написали русскими буквами? Они пишут vodka. Если речь о машине “Камаз” – пишут Kamaz. Еще пишут Volga, matreshka, balalaika и так далее.
Если смысл слова не ясен, все равно пишут транслитом, а в скобках или под сноской – значение. Вот реальный пример из учебника по английскому. Текст про первую женщину-космонавтку:
Pilots named her Chaika (seagul in russian).
Не “Чайка”, а “Chaika”.
Я уж не говорю о том, что названия китайских или японских брендов никогда не пишут иероглифами.
Вернемся к нашим баранам. Очередной горе-перевод:
После раздумий он решил уйти из Google в Facebook.
Вот подумай, переводчик, как читать эту фразу тем, кто не знаком с английским? Из Гогле? Из Гоогл? Из Гугле? В Фасбук? Фесбоок? А если чел переехал Китай и устроился в национальный поисковик 百度? Закорючками писать будешь?
Поможем неуверенному переводчику. Google переводится и будет по-русски Гугл. Facebook, внезапно, тоже переводится и будет Фейсбук:
После раздумий он решил уйти из Гугла в Фейсбук.
Китайский вариант:
После раздумий он решил уйти из Гугла в Байду.
Еще раз: непереводимых слов нет. Да, вы не сможете написать “Фейсбук” на африканском наречии, где 3 звука и 2 жеста. Но по-русски сможете.
Если все плохо и доводы вас не убедили, ситуацию все еще можно спасти. Почитайте, что пишут достойные люди по этому поводу:
-
Публикация на Хабре
На главной Хабра висит моя статья о библиотеке
f
для функционального программирования в Питоне.Гитхаб проекта с документацией. Пакет в Pypi.
-
Плохая работа
Бывает, когда что-то сделано плохо или не работает, я злюсь. Окружающие удивляются: ну подумаешь, не работает! Можно открыть в другом браузере, зайти позже, воспользоваться услугами конкурента. Я злюсь еще сильнее, потому что меня не поняли.
Раздражает не факт того, что работа сделана плохо. Вот невидаль! Бесит, что плохая работа прошла полный цикл исполнения, согласования, приема и внедрения. И никто – ни один человек во всей цепочке – не сказал: ребят, мы же говно сделали, как этим пользоваться?
Плохая работа повсюду. Сделали сайт – не открывается на Айпаде из-за говно-скриптов. Сделали скат возле лестницы – невозможно катить коляску. Парковочное место стоит впритык с тротуаром, машина загораживает проход. В анкете не хватает места. Бордюры там, где их быть не должно.
И так далее.
Причина плохой работы кроется в следующем. Исполнитель либо не пользуется своим продуктом, либо имеет халявный доступ к продукции фирмы. Оба фактора одинаково плохи. В результате изделие или услуга не находят точек соприкосновения с действительностью. Оно как бы есть, но люди пользуются обходными способами.
Артемий Лебедев предложил оригинальный способ приема пандусов. Прораба сажают в инвалидную коляску и скатывают вниз. Скатился цел – работа принята. В противном случае прораб сам станет инвалидом. Но это предотвратит появление других опасных пандусов.
Ничто так не развращает, как халявный доступ к продукту. Получая бесплатно своими же руками сделанное говно, исполнитель вздыхает – да, не очень, зато бесплатно.
Максимальной привилегией, положенной сотруднику, должна быть обычная скидка в 10% от стоимости продукта. Ты делал – так купи! В фирмах, где действует это правило, производят классные вещи и услуги.
В реальности картина должна быть такой. Если ты дизайнер и сделал бланк анкеты – распечатай и заполни сам. Сразу станет ясно, где много места, где мало. Сделал сайт – открой на медленной машине или на Айпаде. Если тормозит – переделывай. Сделал пандус – сел в инвалидную коляску и попробовал съехать. Не вышло – все разобрать и переделать. Убытки вычесть из зарплаты проектировщика.
И так далее. Короткими словами – нужно только обязать исполнителя воспользоваться своим же продуктом.
Очень советую прочитать “Сказку О Криворуких Ебланах”. Это именно то, что я хотел передать.