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

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

Оффициальная документация расположена тут и тут. При этом сложилось впечатление, что на github’е она более актуальная и полная. По ним можно собрать все, при условии, что у вас уже стоят нужные пакеты. Мне понадобились:

$ sudo apt-get install autoconf automake libtool libcurl4-openssl-dev

Тажке, не забыть выполнить “./autogen.sh” перед “./configure”. Почему-то, в секции “Installation for NGINX” документации написаны только общие сведения. Мне, например, не хотелось и не нужно было собирать mod_security для apache, устанавливать пакет apache2-dev и т.д. Поэтому выполнил configure со следующими параметами:

$ ./configure --prefix=/usr --disable-apache2-module --enable-standalone-module

Далее сборка, установка и настройка у меня прошла без проблем.



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

Безусловно, всем, ну ладно, почти всем, хочется писать только на самых последний версиях фреймворков, использовать самые новые технологии и навсегда забыть о так называемом legacy code. Но мало кто из разработчиков думает о том, когда и зачем это нужно, а когда - невозможно. Разберем пример выбора фреймворка Х на примере нескольких случаев.

Случай #1. Работает - не трожь!

Очень распространенный и нелюбимый мною случай. Проекту N лет, заказчика он устраивает, клиенты довольны. Но проект еще развивается, нужно не только фиксить баги, но и улучшать текущую, добавлять нувою функциональность. Но что бы добавить одну простую новую функцию, нужно написать “много” кода, который уже есть в новой версии фрреймворка X, который используется. А новая версия может быть несовместима со старой. А если и совместима - нет гарантии что все быстро и хорошо заработает. Часто бывает что проще и дешевле переписать с нуля. И вот тут должен выключаться режим разработчика и включаться режим владельца бизнеса. На основе естимейтов по переходу на новый фреймворк, можно посчитать что дешевле: дописать старое или написать, частично или полностью, новое. Наверняка, в каких-то правильных книжках по менеджменту (возможно, не только для ИТ) и/или економики уже есть готовые формулы для этого, но я не встречал такого. Самое сложное здесь то, что формула будет не такой простой, как может показаться изначально.

Например:

Функция А будет сделана(разработанна, протестированна, задеплоенная - вообщем, готова для использования) за 30 часов на старом фреймворке и за 20 на новом. Умножая кол-во часов на n денег легко посчитать как дешевле. Но тут нужно учитывать всевозможные риски с новым фреймворком - его баги, баги после миграции, стоимость изучения и т.д.

Пример выше сильно упрощен и я не сталкивался с таким в работе. Обычно, все выглядит так (цифры придуманы):

Функция А будет сделана(разработанна, протестированна, задеплоенная - вообщем, готова для использования) за 10 часов на старом фреймворке и за 50 на новом. Разница по деньгам и времени - в 5 раз. Тажело будет уговорить менеджера и/или заказчика. Но тут на решение должны влиять другие факторы, а именно:

 

  • каждая новая фича будет стоить дешевле из-за того, что разработчики уже выучат матчасть, набьют новые шишшки с новым фреймворком и т.д., в последствии чего - в идеальных условиях, время разработки будет стремится к времени на разработку этой же фичи на старом фремйворке - n часов.
  • во время миграции на новый фреймворк, пользователи продукта не будут видеть новых версий, что сильно влияет на time to market (TTM), может пказаться, что продукт больше не развивается.
  • на протяжении этого всего времени, нужно будет поддерживать старую/текущую версию продукта, что тоже стоит денег.
  • переписанный продукт на новый фреймворк X - часто является скорее новым продуктом, чем новой версией старого, со всемы вытикающими последствиями.

 

 

Случай #2. “Теперь мы используем фреймворк X версии Y” или “у нас новый проект на фреймворке X версии Y”.

Казалось бы все хорошо, фреймворк X версии Y - самая последняя версия самого крутого фреймворка, использующего самые новые технологии. Все хотят это испльзовать и работать с этим. Но пройдет сколько-то времени (месяц, два, год), а мы пишем все тот же проект, на все тех же технологиях, которые были актуальны и популярны полгода-год-два назад. И все сводится к вышеописанному сценарию #1.

 

Случай #3. Идеальный процесс разработки продукта.

Раз это описание идеального процесса, пусть это будет что-то типа continuous development. Все лучшее от разнообразных Agile методологий, Kaizen и т.д. и заказчик готов платить достаточно денег при соблюдении таких условий:

 

  • продукт будет выпущен в оговоренные сроки
  • дена дальшейшей разработки будет снижаться
  • цена поддержки будет низкой

 

Допустим, дата релиза запланированна на весну (сейчас декабрь). К тому времени должна выйти новая версия хорошо известного фреймворка X, а сейчас доступна совсем не production ready alpha. Т.к. авторы этого фреймворка всегда выпускают релизы вовремя(у нас же идеальная ситуация:) ), то можно начать писать на нем. Но т.к. у нас в руках очень сырая и нестабильная alpha версия, то нам нужно обезопасить себя от всяческих рисков и проблем, связанных с багами и недоработками фреймворка. Я вижу только один действительно рабочий способ - внедрение continuous integration процесса в полной его мере: покрытие всяческими тестами и постоянный их запуск. Таким образом, особенно при хорошем покрытии кода unit-тестами, мы можем отделить ошибки которые связаны с нашим кодом, от тех, что зависят от фреймворка и/или сторонних библиотек.

Таким образом мы берем на себя технологический риски, связанные с “сырым” фреймворком и возможные потери денег как на разработку продукта, так и на возможную недополученную прибыль от его использования и/или продажи. Но если все будет хорошо, и проект успешно выйдет в production, то мы получим следующие плюсы от этого:

 

  • малое значение TTM - продукт выходит на рынок как только пояляется новая технология/фреймворк
  • вы становитесь early adopters выбранного вами фреймворка
  • качество продукта будет достаточно высоким (см. о continuous integration)
  • счастливые разработчики, использующие самые последние технологии и фрейморки
  • разработка следующей версии продукта стартует быстрее (есть наборы тестов, CI) и так же может быть на еще более новой версии фреймворка

 

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

 

Ссылки по теме:



Вот так неожиданно для себя узнал что Selenium Webdriver работает без Java. До этого всегда был уверен, что такого не может быть. Возможно, это произошло с релизом Selenium 2, возможно нет. Но мой мир уже не будет таким как прежде. 

Не поверил, пока сам не убедился в этом. Пришлось ставить виртуалку без Java и проверять следующий код:


Build succeeded, 156 warnings

Published 11/18/2013 by e0ne in Offtopic

Запустил “make build” и получил 156 ворнингов:(... Хотя, достаточно быстро получил более радужное число - 69, что тоже не мало. Нужно фиксить дальше, а пока - немного очень IMHO на эту тему.

Отключать или нет параметр “mark warnings as errors” (название может отличаться, но суть остается той же) - часто решают для конкретного проекта и/или команды. Иногда это не мешает работы продукта. Я бы сказал что в 98% случаев это не мешает, зато остаются 2%. И баги, попавшие в те самые 2%, часто являются самыми трудновоспроизводимимы и затратными по времени на исправления.

Итак, из-за чего появляются warnings? Самые частиы причины - это:

  • использование deprecated и/или недокументированного API.
  • несоответствие кода гайдлайнам (guidelines) и/или принятым стандартам языка программирования, фреймворка и т.д.
  • проблемы с настройкой окружения (environment).

Что плохого в использовании deprecated API? Ничего, если приложение будет удалено не посже, чем сразу после перговго запуска. В противном случае, рано или поздно, после очередного обновления используемой платформы и/или фреймворка что-то перестанет работать, т.к. deprecated код будет удален. Таким образом, ваш код, который использует устаревший API фреймворка, автоматически становится deprecated :). Готовы ли вы писать заведомо legacy код?

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

Код, который не соответствует стандартным гайдлайнам, как минимум, - странный. IMHO. Нет, я понимаю, что при использовании StyleCop (для C#) практически невозможно писать код, соответствующий всем его требованиям, но для того же Python’а, держать код в соответствии с PEP-8 достаточно просто. Трудности бывают только с 80-ю символами в строке. С PyLint все немного сложнее. Но никто не заставляет выполнять все требования. Главное - здравый смысл и правильная настройка инструментов, которые используются.

Проблемы с настройкой окружения. Тут не буду много писать, т.к. эта тема тянет на отдельный пост в блоге, который уже давно хочется написать. Скажу только то, что один и тот же код (id коммита, tag, и т.д.) должен, по возможности, собираться одинаково на всех используемых окружениях. Это, как правило, рабочий ПК разработчиков и тестировщиков и билд-серверы. Иначе где-то что-то пойдет не так.

Не попал в мой классификацию еще один случай - содержимое stderr. Бывает, что только туда пишуться какие-либо предупреждения, которые остаются непрочитанными. Давно уже руки тянуться помечать все билды как failed, если что-то есть в stderr, но пока это сделать не получается, т.к. “хороший продукт !== работающий и/или безбажный продукт”, а “хороший продукт == радующий пользователя/заказчика продукт”. Как-то так.



Разберем ситуацию, ставшую достаточно распространенной в наше время. Есть распределенная команда, допустим в двух городах (А и Б), которая работает над одним крупным проектом. Сборка проекта происходит на Jenkins’е в городе А и длится, например 3 минут. Скачать готовый продукт из города А в город Б можно в среднем за 30 минут (в зависимости от времени суток, загрузки канала, фазы луны и т.д.). Итого: команде из города Б нужно ждать час(60 минут) чтобы запустить/протестировать свежий билд. Очевидно, это достаточно много. Нужно ускорять.

Рассматривать вопросы вынесения этого всего (CI) в облако и прочее я не буду по двум причинам:

 

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

 

Также я пропущу вопросы синхронизации репозиториев с исходниками и прочие инфраструктурные вещи, не относящиеся к данной теме.

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

Делается это, примерно, так:

 

  1. Заходим на наш Jenkins и устанавливаем нужные плагины (Jenkins => Manage Jenkins =>  Manage Plugins => Available). Нам нужен “Throttle Concurrent Builds Plugin” (https://wiki.jenkins-ci.org/display/JENKINS/Throttle+Concurrent+Builds+Plugin) и NodeLabel Parameter Plugin (https://wiki.jenkins-ci.org/display/JENKINS/NodeLabel+Parameter+Plugin).
  2. Настраиваем Slave node. Документация лежит тут: https://wiki.jenkins-ci.org/display/JENKINS/Step+by+step+guide+to+set+up+master+and+slave+machines.
  3. Настраиваем нашу Job’у для параллельного выполнения на двух нодах. Я для примера создал Fake-long-job, которая выполняет простой bash-скрипт “sleep 20;”.
    • Отмечаем флаг “This build is parameterized”
    • Добавляем параметр Node

    • Выбираем на каких нодах можно выполнять билд

    • Настраиваем одновременные билды. В моем случае их может быть 2, по одному на каждой ноде

      .
    • Нажимаем кнопку Save.
  4. Проверяем, что все работает, запустив два билда на разных нодах.

 

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


Скорее заметка для себя. Постоянно забываю об этом ключе.

Иногда нужно очень быстро поднять HTTP-сервер с минимальным функционалом. Например, нужно проверить HTML+JavaScript, который работает только через веб-сервер. Я, конечно понимаю, что у меня под рукой всегда есть, как минимум nginx, и поднять на нем сайт, который будет раздавать статические фалы, делов на 5-10 минут. Но, во-первых, это долго, а во-вторых, этот самый nginx у меня находится на виртуалке, пусть и включенной в 90% времени на ноутбуке. А тут прийдется не только веб-сервер настроить, но и расшаренные папки в VirtualBox-е, и так далее...

Единственное, что у меня действительно всегда есть под рукой, это Python (уже несколько лет не пользуюсь ОС Windows, а на всех *nix он есть из коробки). Поднять простой тестовый веб-сервер на питоне можно всего одной командой:

$ python -m SimpleHTTPServer 8100

После этой команды, у вас локально запустится веб-сервер на 8100-м порту, который покажет содержимое текущей папки.

Работает это благодаря ключу -m, который указывает интерпритатору о том, что необходимо выполнить модуль как скрипт. Это идентично команде "$ python /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SimpleHTTPServer.py", но писать значительно проще. Единственное ограничение, что этот модуль должен быть доступен в sys.path


Или мне так не везет, или для всех это совершенно очевидные вещи, но я, при выполнении простой fabric task'и копирования содержимого директорий, столкнулся на ряд проблем, которые хоть и казались простыми и распростаренными, но были описаны в найденных мной блогах и мануалах в плной мере.

Проблема #1 - неправильный пользователь

Не всегда бывает что имя локального пользователя совпадает с удаленным. Ситуация распространенная и описанная всеми, кому не лень. Решение простое - указывем нужного пользователя в переменной env.user:

from fabric.api import *
env.user = 'e0ne'

Проблема #2 - аутентификация

Самый простой способ аутентификации по SSH - имя пользователя и пароль. Самая распространенная проблема - нужно как-то безопасно хранить пароль. А так, как я предпочитаю все скрипты для развертывания хранить в VCS (читать как в git’е), то возникает проблема: нехорошо хранить пароль в репозитории, особенно в открытом на GitHub’е. Решение простое - использование пары public/private RSA ключей. Процесс генерации и настройки (ключевые слова: ssh-keygen, ~/.ssh/known_hosts) описывать сейчас не буду, только то, что касается Jenkins’а.

В моем случае, Jenkins был установлен на Ubuntu server 13.04 командой  “apt-get install jenkins”, поэтому пользователь jenkins в системе создался таким образом, что без подоплнительной настройки под ним не залогинишься. Поэтому использем sudo и генерируем ключи для подключения по SSH, примерно, так:

$ sudo -u jenkins -i ssh-keyget -t rsa

После чего в домашнем каталоге jenkins’а будет лежать пара ключей, публичный из которых нужно положить на наш сервер, на который fabric будет копировать файлы. Достатьid_rsa.pub можно так:

$ sudo -u jenkins -i cat ~/.ssh/id_rsa.pub

И положить этот ключ на сервер, в моем случае в файл /home/e0ne/.ssh/known_hosts.

Этот способ так же решает проблему того, что не нужно передавать в fabric путь к ключу, он будет браться из пути по умолчанию.

Проблема # 3 - не загружаются файлы

Ошибка тут у меня была совсем непонятной (привет paramiko и протоколу ssh), откатывать настройки или делать это с другим сервером сейчас нет возможности. Да и точно не помню как я пришел к решению. Наверное, после медитации на вывод команды “ls -al”. Задача jenkins job’ы была в том, что нужно было апдейтить простое веб-приложение, а у пользователя, под которым jenkins/fabric подключался к серверу не было прав на запись в нужную директорию. Решилось добавлением пользователя в группу www-data, в которой у меня находится пользователь nginx’а.

Пока все. Эти три проблемы были при попытке “простого копирования” файлов. Дальше будет должно быть интереснее. Или проще. Как повезет:).



Иногда приходится делать удивительные и неожиданные для себя вещи. Например, писать что-то на PHP. Но написать мало - надо еще проверить что написанный код работает. В моем случае приложение было немного сложнее классического "hello, world", но все-равно требовалось проверить его работоспособность.

Т.к. это всего-лишь тестовая версия/PoC или что-то такое, интересовала самая простая схема его запуска. Apache не виртуалке c Ubuntu не стоял, под руку попал Nginx. Далее все происходило так:

  • установка необходимого пакета (PHP уже стоял):
    $ sudo apt-get install php5-fpm
    Не знаю насколько FastCGI хорош и применим в мире PHP, но мне подошел
  • выключаем работу с unix socket и вешаем FastCGI процесс на локальный порт 9000; для этого правим конфигурационный файл "/etc/php5/fpm/pool.d/www.conf" следующим образом:
    ;listen = /var/run/php5-fpm.sock
    listen = 127.0.0.1:9000
  • настраиваем Nginx ("/etc/nginx/sites-available/default"):
    location ~ \.php$ {
                    try_files $uri =404;
                    fastcgi_split_path_info ^(.+\.php)(/.+)$;
                    fastcgi_pass 127.0.0.1:9000;
                    fastcgi_index index.php;
                    include fastcgi_params;
            }
  • копируем нужный PHP-скрипт в директорию, на которую смотрит веб-сервер
  • проверяем работу скрипта
Все. Решение не претендует на правильность и полноту. Просто иногда надо.


MacOS Case-Sensitive FIle System

Published 1/13/2013 by e0ne
Tags:

Какое-то время назад, для меня было удивительно, что в Mac OS X, в отличии от Linux, стоит Case-Insensitive файловая система. Т.е. файловая система не чувствительная к регистру файлов и директорий. В большинстве случаев, это не причиняет вреда, но иногда приносит достаточно досадные проблемы. Что бы избавиться от этого можно либо создать раздел с Case-Sensitive файловой системой, либо создать временный (или не очень) виртуальный диск. Плюс второго способа в том, что этот диск будет храниться одним файлом и, при необходимости, если легко будет удалить.

В Mac OS это делается с помощью встроенной программы Disk Utility:

 

Такой небольшой диск прост в создании и использовании и дает возможность проверить работу приложения в более приблеженном к linux окружении (имеется в виду ошибки в путях к файлах и реозиториям).


Суббота, вечер, пишу очень IMHO. Мнение атора может не совпадать с мнениями других и действительностью.

С моей точки зрения, как разработчика проекты делятся на:

 

  • Outsourcing - вроде все понятно, самый популярный вид разработки в наших краях, но бывает разный
    • product development - когда вся разработка происходит тут, у нас, менеджмент тоже свой, но заказчик кто-то из вне. Собственно заказчик, со всемы вытикающими отсюда плюсами и минусами, единственное, что отличает этот пункт, от пункта "own product
    • "классический аутсорс" (не знаю как правильно называется) - когда заказчик возводится чуть ли не до уровня Бога, а мы для него становимся просто дешовой рабочей силой, которая должна молча, быстро и хорошо выполнять задачи, которые меняются по срокам, целям и приоритетам по неизвестной для нас причине.
  • Outstuffing - когда продают команду, фактически, команда тут становится равноправной командой заказчика, просто удаленной.
  • Own Product - разработка своего продукта. Не все так радужно и классно, как может показаться на первый взгляд. Если это первая версия - то да, драйв, код и рок-н-ролл: мы выбираем технологии, фичи, делаем эстимейты, никакого легаси кода. Но как только продукт может случиться такое: начинает использоваться, появляется легаси код, архитектура становится не такой классной и т.д.
  • Startup - модно, стильно, быстро. Иногда много денег, иногда - нет. Сложность и интересность проектов (с точки зрения разработчиков) зависит только от фантазии основателя и наличие энтузиазма/денег на еду у программистов. Риски тут 50/50 - или повезет, или нет.