Thursday, September 22, 2011

Google: Don't be evil

Тема, которая навеяла на написание данного поста это гугловский слоган "Don't be evil", который пытаются впутать в различные события, которые происходят с Google, например последний radio-t говорит нам о том, что мол какой же "не делай зла", когда они убили Яндекс. Ну и то, что мне ещё попалось на глаза новость о том, что гугл завышает цены на рекламу для майкрософта.

Сейчас я расскажу почему это не противоречит мантре "Don't be evil".

Давайте разберёмся откуда вообще появился этот слоган. Если верить википедии то появился он в формулировке того, что компании, которым достаются какие-то данные о пользователях (а их у гугла тонны), начинают злоупотреблять этим положением. То есть когда пользователь доверяет вводить в поисковую строчку "геморрой" он доверяет гуглу и это при том, что гугл может сам найти сейчас все клиники по-близости к твоему ip, позвонить им и мягким синтетическим голосом сказать "Сергей Петрович Иванов, который проживает на улице такой-то, а сейчас проходит с телефоном Andriod мимо Вашей клиники и испытывает острую необходимость в Ваших услугах, позвоните ему по вот этому номеру (или напишите ему в Google Talk), денег на его google checkout хватит на несколько приёмов, не переживайте. Кстати не предлагайте ему чай или кофе, в последнее время он подсел на натуральные соки.". Вот это, блин, я называю "be evil".

Ещё раз: мантра относится к тому, как пользоваться пользовательской информацией, а именно она означает "не делай быстрых больших денег, потому что это отпугнёт клиентов". Читнём опять википедию и выделим там нужные слова: "exploiting the users" "short term gains" "best interests of the public".

Теперь возьмем ситуацию с Яндексом. Есть ли тут использование пользователей? Конечно нет, данные о том, каким поисковиком ты пользуешься совершенно не компрометируют тебя, то есть если человек не стесняется сидеть в одноклассниках зачем ему стесняться того, что он ищет в яндексе? Есть ли тут краткосрочные доходы? Казалось бы да, но нет, они долгосрочные, суть в том, что мысль записанная между строк "don't be evil" звучит так "мы играем в долгую, сейчас мы и так зарабатываем достаточно, способ зарабатывать больше в будущем --- только доверие пользователей", а значит желание получить прибыль в долгосрочной перспективе фактически синоним слогану "don't be evil". Ну и наконец да, переход с поиска яндекса на поиск гугла это и есть служение в лучших интересах публики, потому что яндекс.паравозики можно найти и в гугле, а вот ничего полезного в яндексе найти уже не удастся. Те, кто до сих пор считают что яндекс ищет лучше чем гугл (просто проверьте, лол), можете прочитать это так "гугл хочет чтобы больше пользователей искали в нём, чтобы улучшить качество поиска в долгосрочной перспективе". Короче вы поняли да? Отсутствие выбора поисковиков в хроме есть прямое следствие мантры "don't be evil" никак ни наоборот.

Теперь Microsoft. Использует ли google данные пользователей? Опять же, пользоваться виндой считается постыдным делом только у очень малого количества людей, то есть нет, данный пункт совершенно боком. Есть ли в повышении цен краткосрочная прибыль? Нет, как раз наоборот: реклама винды приносит прибыль здесь и сейчас, но в долгосрочной перспективе предлагает развитие сервисов майкрософта в ущерб сервисам гугла, то есть завышает цены (если он это конечно делает) гугл не для того, чтобы получить с этого прибыль, а для того, чтобы прекратить сотрудничать с майкрософтами, ну или по крайней мере сбалансировать убытки в долгосрочной перспективе. Ну и конечно же да, по мнению гугла пользоваться сервисами гугла это лучше удовлетворяет интересам публики чем использовать сервисы майкрософта, думаю что даже многие с этим согласятся.

Ну вы поняли? Если гугл не обижает пользователей и заботится о здоровье и процветании своей компании в долгосрочной перспективе (а и как следствие своих пользователей), то он не нарушает свою мантру "Don't be evil".

Wednesday, May 4, 2011

golang prof pprof

В общем задался тут задачей понять как можно профилировать проги на Go, в итоге сначала попался мне prof причём если там пишут, что чтобы выполнить профайлинг нужно выполнить 6prof, то верьте им. В общем-то печалит то, что вывод, который генерирует эта прога довольно бессмысленный:

$ 6prof -p `pidof your_program`
72 samples (avg 5 threads)
400.00% runtime.futex
 91.67% syscall.Syscall6
 12.50% runtime.clone
  6.94% syscall.Syscall
  1.39% scanblock

Ну а дальше в интернетах говорят про гугловский pprof, собственно для начала нужно поставить его с их сайта (я лично ставил из deb пакета, так же там есть и rpm сборка). Дальше возникает вопрос, а как же подружить свою свежую прогу с этим произведением человечества. Я гуглил долго в гугле и просто "golang pprof" и "golang profiling", долго мне это не давалось, пока я не попал на вот это сообщение в рассылке go-nuts. То есть разгадка оказалось очень простой, нужно сделать ровно 2 вещи:
1) подключить пакет http/pprof
import _ "http/pprof"
если символ _ кажется для вас удивительным, то это нормально, я тоже не знал что это такое :) судя по спекам это специальная декларация, которая с одной стороны как бы не включает пакет в область видимости (то есть не будет ругани про то, что пакет не используется внутри программы), но при этом запускает некую "инициализацию", в общем-то просто функцию init(), но суть, что эту функцию нельзя вызвать как pprof.init() потому что она не экспортирована (пишется с маленькой буквы).
2) запустить http-сервер. В целом для меня это кажется немного не очевидным, что для простого профилирования нам приходится городить http-сервер, но суть что пакет http/pprof вешает обработчики url'ов (это видно из исходного кода той самой функции init): /debug/pprof/cmdline /debug/pprof/profile /debug/pprof/heap /debug/pprof/symbol. Собственно я пока ещё думаю над тем, как именно включить сервер, но пока обхожусь примерно таким способом:
        go func() {
                err := http.ListenAndServe(":6060", nil)
                if err != nil {
                        panic("ListenAndServe: " + err.String())
                }
        }()
добавляю этот код прямо таки в начало функции main(). Ну соответственно в production этот код (и подключение http/pprof тоже) нужно или вовсе выкидывать или хотя бы запускать только если запустили приложение с каким-нибудь флагом, ну и опять же возможно стоит позволить задавать порт произвольным, но это уже в каждом случае решается конкретно. Ну и сейчас если что-то запустится не так, то приложение сразу же весело падает, а возможно стоит сделать всё по правилам defer, panic, recover.

Но самое-то главное! Теперь мы можем помучить наше приложение и посмотреть где оно мучилось больше всего. Делается это очень просто:
$ pprof --web http://localhost:6060/debug/pprof/heap

И в браузере появится svg-схема того что откуда куда, например такая.

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

Friday, February 18, 2011

Мои git alias'ы

Решил тут написать алиасы, которые я использую в гите:

$ cat ~/.gitconfig
...
[alias]
di = diff --no-prefix
ll = status
fast-fix = !"git diff && read -p \"ready to commit?\" i && git commit -a && git push"


Итак по порядку:
git diff --no-prefix заменяет вывод с
--- a/path/to/file
+++ b/path/to/file

на
--- path/to/file
+++ path/to/file

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

git ll это просто аналог башевского alias ll='ls -l'

Ну и наконец самое сложное: git fast-fix
сначала делается git diff && read -p "ready to commit?" эта штука выводит текущие изменения и ждёт когда я что-нибудь нажму или же нажму ctrl+c для отмены дальнейших действий. А действия дальше какие: git commit -a который понятно что делает: просит ввести коммит мессидж, если его ввести, то произойдёт git push, если нет, то коммита не будет и как следствие пуша :)

Во-первых почему называется fast-fix? потому, что на букву f начинается не так много команд, а на fa и вовсе ниодной, таким образом я набираю git fa[TAB][ENTER], можно было бы тогда и назвать git fa, но имхо это уже не такое очевидное сокращение, как di или ll.
Во-вторых зачем так сложно? Данная команда очень удачна в случае, когда изменений минимальное количество: скажем нужно просто исправить опечатку. Тогда чтобы сделать это нужно выполнить всего 3 действия: git pull; edit somefile; git fast-fix. Ну причём первое не всегда обязательно, если вы забыли стянуть изменения, то при git push вам об этом скажут и можно будет отдельно сделать git pull; git push; Самое главное, что происходит проверка того, что вы собираетесь закоммитить: во время git diff (изменения по сравнению с working tree) и во время git commit (список файлов, по сравнению с HEAD). Во время которой может обнаружиться что-то, чего вы не ожидали :) и главное, можно будет исправить (ctrl+c в diff и пустое сообщение в git commit).
В-третьих зачем так просто? Да, когда изменений больше чем на пару строчек, то этот скрипт немного слабоват, и тут я открыт для предложений :)

Monday, February 14, 2011

gitolite+gitweb on ubuntu

В общем сейчас расскажу что у меня получилось сделать :)
Сервер git с авторизацией по ключу, с гибкой системой прав, то есть gitolite.
Закрытый по паролю доступ к веб-морде с проектами (история, просмотр кода), то есть gitweb.

Ставим

Имелась у меня убунта, сначала я поставил в неё апач и gitweb
$ sudo aptitude install gitweb apache2

Дальше ставил gitolite не из репозитория, а из исходников. Инструкция тут, но вкратце:
на своей машине
$ scp .ssh/id_rsa.pub server:/tmp/YourName.pub
на машине, где будет сервер
$ sudo -i
# adduser --disabled-password git
# git clone git://github.com/sitaramc/gitolite gitolite-source
# cd gitolite-source
# mkdir -p /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks
# src/gl-system-install /usr/local/bin /usr/local/share/gitolite/conf /usr/local/share/gitolite/hooks
# su - git
$ gl-setup /tmp/YourName.pub

Только не забываем заменять YourName на ваше имя, а server на адрес сервера.

Настраиваем gitolite

Дальше конфигурим (локальная машина):
$ git clone git@server:gitolite-admin
$ cd gitolite-admin
$ editor conf/gitolite.conf
$ git add .
$ git commit
$ git push


Собственно, что же надо было написать в конфиг:

repo testing
RW+ = @all
R = gitweb daemon

Ну в целом добавляем права на чтение для любого репа, который хотите, чтобы появился в веб-морде. Подробнее тут.
На этом наше конфигурирование не заканчивается :) нужно сменить маску для новых репов (файл .gitolite.rc)
$REPO_UMASK = 0022;
и указать пусть к .htaccess (об этом чуть позже)
$HTPASSWD_FILE = "/home/git/.htpasswd";

Настраиваем gitweb

Теперь нужно отредактировать /etc/gitweb.conf. Всего пара строчек:
$projectroot = "/home/git/repositories";
$projects_list = '/home/git/projects.list';


Правим права

Сейчас на сайте http://server/gitweb ваши репозитории не будут показываться из-за проблем с доступом. Дело в том, что хоть мы и написали маску $REPO_UMASK = 0022;, но сработает она только для новых репозиториев. Хотите доступ, нужно сделать
$ sudo chmod a+r /home/git/projects.list
$ sudo chmod a+rX /home/git/repositories/

И для репов, в которые вы хотите дать доступ (в нашем случае testing) нужно сделать
$ sudo chmod -R a+rX /home/git/repositories/testing.git, я не советую делать всё одним махом, чтобы не давать лишних прав на gitolite-admin.git

Настраиваем apache

Теперь мы вдруг понимаем, что полного доступа для всех нам не надо (в противном случае можно давно было завести аккаунт на github.com). С этим бороться будем вот так.
Для начала скажем, что доступ будут иметь только люди, у которых стоит пароль в .htaccess
для этого отредактируем /etc/apache2/conf.d/gitweb, чтобы получилось типа так:

Alias /gitweb /usr/share/gitweb
<Directory /usr/share/gitweb>
  Options FollowSymLinks +ExecCGI
  AddHandler cgi-script .cgi
  Options ExecCGI FollowSymLinks Indexes
  AuthName "git repo"
  AuthType Basic
  AuthUserFile /home/git/.htpasswd
  <Limit GET POST PUT>
    Require valid-user
  </Limit>
</Directory>
Ну и перезапускаем апач:
$ sudo service apache2 restart

Даём доступ

Права на файл /home/git/.htpasswd у меня выглядят так:
-rw-r--r-- 1 git git 21 2011-02-14 16:35 /home/git/.htpasswd, чтобы добавить какому-то юзеру доступ по паролю делаем так
$ sudo htpasswd /home/git/.htpasswd YorName, но есть более иной способ, так как на сервер пользователи уже могут попасть по ключу, то все, кто имеют такой доступ могут выполнить ssh git@server htpasswd, который определить по ключу ник и предложит установить пароль. Выглядит примерно так:
$ ssh git@server htpasswd
Please type in your new htpasswd at the prompt. You only have to type it once.

NOTE THAT THE PASSWORD WILL BE ECHOED, so please make sure no one is
shoulder-surfing, and make sure you clear your screen as well as scrollback
history after you're done (or close your terminal instance).

new htpasswd:testpass
Updating password for user YourName



Заключение

Вот так вот можно получить хороший, закрытый git-хостинг своими руками. Есть конечно куда копать: не очень понятно что делать, если хочется давать через веб-морду доступ только туда, куда у юзеров есть доступ через git. Тут есть конечно способ лечить головную боль топором: руками вписывать тех, кому можно, а изменение .htaccess запретить (убрать права у юзера git на запись или же убрать опцию $HTPASSWD_FILE). В интернетах пишут о более иных способах, но я пока не осилил :)

П.С. Если я где-то что-то накосячил, то дайте знать и я всё исправлю.

Wednesday, February 9, 2011

Начинаю вводить GTD в свою жизнь :)

Меня как-то утомила фрустрация на счёт бесцельно пролетающего времени. Сейчас объясню, что я попытался с этим сделать.
Первое, что я понял уже давно, это то, что планы на день совершенно не помогают мне эти планы выполнить. То есть если я знаю что за день мне надо что-то сделать, я аккуратненько выписываю это в google tasks, но занимаюсь почему-то тем, что там не написано --- чуть-чуть поиграю в какую-нибудь игрушку, чуть-чуть почитаю/попишу в жуйк, чуть-чуть поовощу на ютубе и т.д. и т.п.
Я решил пойти другим путём. Я по рекомендации из Radio Grinch заюзал сайт cuoluo-diary.appspot.com, но каким образом --- я начал писать там отчёты о проведённом времени. Причём сначала я пишу примерно чем я собираюсь заняться на ближайшие полчаса, а потом корректирую, таким образом, чтобы о прошлом была всегда написана правда, а о будущем планы были не сильно заоблачными. Я когда-то пытался делать это в виде google calendar, но оказывается, что гораздо проще писать в плейнтексте "10.05-10.15 разбор почты" чем сделать это в гуглокалендаре (там привязки на полчаса, как следствие сложно ввести время некратное получасу, как в примере время начала и продолжительность).
Чего я добился --- я заметил, что время перестало неожиданно исчезать, то есть теперь, когда я открываю таб с CuoLuo то там написано время не сильно отличающееся от текущего (скажем время окончания того, что я запланировал может отличаться буквально на 5 минут).
В первый день у меня была проблема, что я ставил себе задачу на ближайшие полчаса пофиксить определённый баг, а через часа полтора оказывается, что я мало того, что в это время не фиксил баг, так ещё и забыл на час о том, что я веду отчёт. Сейчас (третий день) у меня теряется максимум минут 15.
То есть подытожу. Плюсы: видно куда уходит время и получается лучше оценить что и сколько времени я буду делать в будущем (имеется в виду ближайший час, а не дни или годы конечно). Минусы: нужно быть всегда у компа (что не для всех проблема), нужно быстро печатать таймстампы :) ну и касательно "видно куда уходит время" без системы тэгов или чего-то такого, видно только здесь и сейчас. То есть нет возможности посмотреть скажем сколько процентов времени я трачу на "игры", "сон", "чатики" и т.д.

Tuesday, January 18, 2011

Проблама с !username вместо [user:name] и прочими в drupal 7

При обновлении drupal 6 на drupal 7 выяснилось, что шаблоны типа !username, !site, !login_uri теперь не работают, а вместо них нужно вставлять [user:name], [site:name], [site:url] и так далее. Решил что руками я это менять не хочу. Пошёл писать скриптик. Ну в итоге даже написал его. Нужно его скачать, и сделать
drush php-script user_email_convert.php
где-нибудь в кишках сайта. Если не знаете, что такое drush, то самое время узнать.

Кстати вот пока разбирался и пытался понять что там вообще к чему, нашёл в модуле user скрипт обновления базы, но почему-то он не сработал... так что может только у меня такая бага?

п.с. замечания и исправления кода приветствуются :)
п.п.с. код в public domain можете делать с ним всё что угодно.