• Удаление слешей из урла в nginx by Ast

    Иногда требуется удалить множественные слеши из адреса, например:

    http://mysite.com//page//1.htm/ --> http://mysite.com/page/1.htm

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

    set $test_uri $scheme://$host$request_uri;
    if ($test_uri != $scheme://$host$uri$is_args$args) {
        rewrite ^ $scheme://$host$uri$is_args$args? permanent;
    }
    

    И с конца:

    rewrite ^/(.*)/$ /$1 permanent;
    
  • Событийная архитектура веб-приложения by Ast

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

    Приведу пример простейшего API корзины интернет-магазина, а для событий используем уже имеющуюся «шину» — элемент body.

    function add(item_id, quantity) {
        $.ajax({
            type: "POST",
            url: "/api/cart/add",
            dataType: 'json',
            data: {item_id: item_id, quantity: quantity}
        }).done(function (data) {
            $('body').trigger('QuantityChanged', [data.item_id, data.quantity]);
            $('body').trigger('PriceChanged', [data.item_id, data.sum]);
        });
    };
    

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

    /**
     * Обновить количество товара в корзине
     */
    $('body').on('QuantityChanged', function (e, item_id, quantity) {
        $('[data-item-quantity="' + item_id + '"]').html(quantity);
    });
    
    /**
     * Обновить цену товара в корзине
     */
    $('body').on('PriceChanged', function (e, item_id, sum) {
        $('[data-item-sum="' + item_id + '"]').html(sum);
    });
    

    Никто теперь не мешает нам расширить систему, добавив на какой-то отдельной странице дополнительное действие при добавлении товара в корзину. И это всё без изменения API, без изменения старых событий и без условных операторов.

  • Пакет для балансировки запросов к статическим файлам by Ast

    Url Balancer

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

    • Поддержка Composer (через packagist)
    • Поддержка Silex
    • Расширяемость стратегий балансировки

    Установка

    Рекомендуется установка через Composer:

    {
        "require": {
            "astartsky/url-balancer": "1.1.2"
        }
    }
    

    Пример использования

    $urlBalancer = new \Astartsky\UrlBalancer\UrlBalancer();
    $urlBalancer->setStrategy(new \Astartsky\UrlBalancer\Strategy\HashStrategy())
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s1.myawesomesite.com"));
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s2.myawesomesite.com"));
    $urlBalancer->addBucket(new \Astartsky\UrlBalancer\Domain("s3.myawesomesite.com"));
    
    $url = $urlBalancer->getUrl("/images/my_impressive_content.png");
    

    Ссылки

    На Packagist.org: пакет

    На Bitbucket.org: репозитарий

  • Как команда технарей свою студию создавала by Ast

    Интересная история о том, как мы внезапно создали с нуля студию в изложении andry:

    Команда

    Уверен, многих технарей посещала идея создания своего бизнеса. Вот и у нас в определенный момент все звёзды сложились так, что казалось — это беспроигрышный вариант: сильная техническая команда, откуда ни возьмись появились менеджеры, готовые продавать наши услуги, есть даже пара проектов на старт. Грех не попробовать. И мы рискнули. Фактически всё надо ставить с нуля. И в первый же месяц всё перевернулось с ног на голову.

    Читать дальше...

  • Minecraft by Ast

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

  • А вот и я, всем привет by Ast

    Dragon

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

    Что ж у меня нового?

    Я отпустил бороду. Борода это круто. Вы можете, конечно, со мной спорить, если хотите, но это факт. Она иногда немного мешает целоваться, зато в остальное время тепло и уютно, можно дергать её в задумчивости, поглаживать, даже расччесывать, словом, очень полезная штука. Гриву отпустил, но её приходится смирять резинкой в форме хвоста: мои волосы категорически отказываются слушаться меня по-хорошему, приходится так, по плохому. Но иногда я отпускаю их погулять.

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

    Еще я переехал в Москву, в Крылатское: и очень тому рад. С трех сторон тут зелень, до метро рукой подать, панорамный вид на лесопарк. Можно забыть о пробках на Можайке, о переполненных душных электричках и всяких вокзалах, о соседях-алкашах и всем таком родном, но надоевшем. Свой дом, пусть и условно свой -- это, все таки, уже крепость. На работу с апреля по конец ноября катался на своих двоих колесах, на велосипеде. В один конец около 15-20 километров, намотал тысячи километров за год. Ветер в лицо, хэви металл в уши: до этого никогда не радовался дороге так, как в этом году.

    В общем, я всегда где-то здесь. Может, еще что-то расскажу скоро.

  • Ветка git в командной строке by Ast

    Если активная работа над проектом идет над несколькими ветками сразу, всегда полезно знать, на какой ветке в текущий момент находится указатель HEAD репозитария. Чтобы не полагаться на память, можно добавить отображение названия ветки в приглашение командной строки. Для этого откроем на редактирование ~/.bashrc

    export PS1='\u@\h: \w\[\033[01;33m\]$(__git_ps1) \$\[\033[00m\] '
    

    Любуемся результатом:

    Но, по хорошему, лучше просто поставьте zsh — оно того стоит.

  • Добавление файла подкачки в Ubuntu by Ast

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

    Создание файла

    sudo dd if=/dev/zero of=/swap bs=1G count=4
    

    Выглядит как достаточно непонятная команда. Рассмотрим параметры подробно:

    • if, Input File: Источник данных для файла: а нашем случае он будет полностью заполнен нулевыми байтами (ASCII NUL, 0x00). Не то чтобы нам это было важно, просто это просто и быстро; 
    • of, Output File: Вывод данных. Здесь это простой файл;
    • bs, Bytes: Количество байт для одной операции записи;
    • count: Количество блоков заданного размера;

    Есть альтернативный вариант, если вы торопитесь:

    sudo fallocate -l 4G /swap
    

    Итого, мы получим 4 гигабайта чистого счастья (1024 раза по 524288 килобайт).

    Разметка файла подкачки

    Время подготовить заготовку файла для высокой миссии.

    mkswap /swap
    

    Установка прав доступа

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

    chown root:root /swap
    chmod 0600 /swap
    

    Активация файла подкачки

    Пришло время потянуть за главный рычаг и включить файл подкачки.

    swapon /swap
    

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

    nano /etc/fstab
    
    /swap swap swap defaults 0 0
    

    Теперь при загрузке системы виртуальная память включится сама.

    free -m
    

    Если все прошло хорошо, мы увидим эффект подключения файла подкачки.

  • Как вежливо попросить git напомнить о миграциях by Ast

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

    #!/bin/bash
    
    HAS_NEW_MIGRATIONS=0
    git diff HEAD@{1} HEAD@{0} --name-only --diff-filter=A | grep 'migration' | while read FILENAME; do
      if [ "$HAS_NEW_MIGRATIONS" == 0 ] ; then
        echo -en "\033[32mМиграции добавлены: \033[0m \n"
        HAS_NEW_MIGRATIONS=1
      fi
    
      echo -en "\033[32m — " $FILENAME "\033[0m \n"
    done
    
    HAS_MODIFIED_MIGRATIONS=0
    git diff HEAD@{1} HEAD@{0} --name-only --diff-filter=M | grep 'migration' | while read FILENAME; do
      if [ "$HAS_MODIFIED_MIGRATIONS" == 0 ] ; then
        echo -en "\033[31mМиграции изменены: \033[0m \n"
        HAS_MODIFIED_MIGRATIONS=1
      fi
    
      echo -en "\033[31m — " $FILENAME "\033[0m \n"
    done
    
    exit 0
    
    ~/project/.git/hooks/post-checkout
    ~/project/.git/hooks/post-merge
    ~/project/.git/hooks/post-rewrite
    

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

    На самом деле, лучше используйте какое-нибудь готовое решение для учета миграций, которое, в том числе, умеет их откатывать. А еще лучше — делайте это автоматически, используя Continious Delivery.