Несмотря на то, что таскменеджеры наши друзья и помогают не забывать ни одной мелочи, очень часто работа с ними превращается в поиск иголки в стоге сена. Во многих проектах задачи валятся как из рога изобилия: саппорт фиксирует десятки жалоб от пользователей, заказчики жаждут новых новых сочных функций, тестировщики находят изощренные ошибки и тщательно их документируют.
Через пару месяцев число открытых задач переваливает за 5 – 6 сотен и таскменеджер перестает выполнять свою функцию – управление задачами, и становится просто свалкой. Задачи ни получается не приоритезировать, ни просто отыскать.
Чтобы работа с таскменеджером не приносила невыносимых страданий, хорошо бы настроить эффективную с ним работу.
Некоторое время назад на работе возникла необходимость оценить время ответа одной из функций сервиса. Получить время ответа можно, например, из логов nginx или логов apache. Как воспользоваться этими цифрами, чтобы понять, быстр наш веб-сервис, или требуется оптимизация?
Для анализа цифр я решил воспользоваться python. В интернее нашлось несколько удобных библиотек для вычисления статистик и построения графиков:
- numpy и scipy – пара очень удобных математических библиотек
- matplotlib – очень мощная библиотека для визуализации вычислений
Сегодня я решил разобрать коробку с книгами, оставшуюся после последнего переезда, и наткнулся на эту книгу.
Очень рекомендую её всем, кто интересуется методологиями разработки ПО, коммуникацией внутри команды и задумывается о применимости того или иного подхода к своему проекту.
Автор описывает 7 принципов построения методологий, вот некоторые из них:
- Общение лицом к лицу – самый дешевый и быстрый способ обмена информацией.
- Избыточная «тяжесть» методологии стоит дорого.
- Более многочисленные команды требуют более «тяжелых» методологий.
- БОльшая формальность подходит для проектов с бОльшей критичностью.
- Возрастание обратной связи и коммуникации сокращает потребность в промежуточных конечных продуктах.
Также в книге подробно рассмотрены различные виды обмена информацией между участниками проекта. Особенно интересными мне показались мысли автора об «осмотической коммуникации» – косвенном получении информации из разговоров коллег (как фактической информации, так и информации вида «ага, Коля знает про А, нужно спросит его при случае»).
Ну, думаю я достаточно рассказал, чтобы вас заинтересовать
P.S: Последнее время я испытываю острый недостаток интересного чтива. Интересуют как технические книги о подходах, паттернах и технологиях, так и бизнес-литература и книги по менеджменту. Интересуют подборки must-have книг. Можно ссылками на соц.сервисах, как например на http://moikrug.ru/profile/books/.
Выделяем поля из логов nginx на python
01.01.2010
Для анализа логов nginx мне понадобилось регулярное выражение, которое бы корректно разделяло запись на отдельные поля. Немного по-колдовав над логом, я понял, что наилучший способ разобраться в формате лога – это выцепить его из конфигурации сервера.
Кроме очевидного плюса – выделение полей с учетом всех разделителей и кавычек, использование формата позволяет получить именованные поля.
Вот код, который у меня получился, возможно пригодится.
import re
# формат из конфигурации nginx
FORMAT = '$remote_addr - $remote_user [$time_local] "$request" $status' + \
' $bytes_sent "$http_referer"' + \
' "$http_user_agent" "$gzip_ratio" "$cookie" $hostname'
# выражение, описывающее переменную в конфигурации логов nginx
TOKEN = '\$([a-z\_]+)'
# возможные скобки и кавычки вокруг переменных в конфигурации логов nginx
POSSIBLE_QUOTES = ('[]', '"', '\'')
def get_matcher(format):
quotes = re.escape(''.join(POSSIBLE_QUOTES))
pat = format
for token in re.findall(TOKEN, format):
res = re.search('([%s]?)(\$%s)([%s]?)' % \
(quotes, token, quotes), format).groups()
if not res:
continue
elif res[0] <> res[2]:
tq = res[0] + res[2]
tq_escaped = '\%s|\%s' % (res[0], res[2])
else:
tq = res[0]
tq_escaped = '\%s' % res[0]
tq = re.escape(tq)
tq_escaped = re.escape(tq_escaped)
if not tq:
ftoken = '\$%s' % (token)
ptoken = '(?P<' + token + '>[^\ ]*)'
else:
ftoken = '[%s]\$%s[%s]' % (tq, token, tq)
ptoken = '[%s](?P<%s>(?:%s|[^%s])*)[%s]' % (tq, token, tq_escaped, tq, tq)
pat = re.sub(ftoken, ptoken, pat)
patc = re.compile(pat)
def matcher(line):
return patc.match(line)
return matcher
def main():
f = file('access_log')
matcher = get_matcher(FORMAT)
for line in f:
print matcher(line).groupdict()
Возможно кому-нибудь будет полезным
UPD: Немного поправил код, чтобы он корректно работал с записями, в которых встречаются поля вида: «some text with escaped \» qoute»
К примеру, хочется иметь в объекте модели поле, дата которого будет задаваться при сохранении объекта.
Казалось бы, вот такой код будет логичным:
class MyModel(models.Model):
time = models.DateTimeField(default = datetime.now())
Однако, в приведенном выше примере – все создаваемые объекты будут иметь дату создания в памяти класса MyModel.
Правильным будет указать в качестве значения по-молчанию функцию, которая будет вызываться каждый раз, при сохранении объекта:
class MyModel(models.Model):
time = models.DateTimeField(default = datetime.now)
upd:
Как подсказывает товарищ overplumbum, можно добавить в конструктор models.DateTimeField() auto_now=True – http://ff.im/bQyQO
Ошибка при работе с pycurl
17.10.2009
Сегодня мне окончательно надоело пользоваться кривейшим сайтом локальной сети моего провайдера. Основное назначение сайта – публикация ftp-ссылок на фильмы, которые заливаются на несколько локальных серверов. Я задумал написать небольшой индексатор, который обойдет папки у ftp и соберет мне имена файлов.
Для решения этой задачи наиболее адекватным инструментом мне показался CURL. За двадцать минут я написал 70 строк кода на питоне, и отправил сканер гулять по серверам. Информация начала литься в индекс, но счастья не случилось. Сканер начал намертво зависать после нескольких минут работы.
Ошибка оказалась дурацкой и слегка неожиданной. В цикле обхода я для каждого запроса создавал новый объект PyCURL, и потом чистил его. Конечно, это все накладные расходы, но в моей задаче мне на них был наплевать. Но не тут то было. После создания многих экземпляров, при их чистке CURL вешает процесс.
Решение простое – создает один объект PyCURL, и работаем только с ним, через pycurl.setopt меняя параметры и много раз вызывая метод perform().
Пусть у нас есть несколько условий, которые могут выполнятся одновременно. И есть несколько ветвей алгоритма, которые нужно выполнить в зависимости от результатов проверок.

Для примера рассмотрим такую задачу. Мы разрабатываем веб-приложение с графическим интерфейсом, в котором можно рисовать прямоугольники. Размер прямоугольника можно менять «потянув» за край или угол. Нужно, в зависимости от положения мыши относительно прямоугольника, изменить курсор мыши так, чтобы пользователю было понятно, как можно изменить размер прямоугольника.
Борьба с порно-спамом
24.12.2008
За последние несколько месяцев поток порно-спама перешел все мыслимые и не мыслимые границы. Akismet с ним не плохо справляется, но количество комментариев так велико, что мне уже лень очищать от них очередь спама.
В Wordpress есть вполне действенный механизм «черных списков», но, к сожалению, по-умолчанию комментарий, не прошедший через проверку, помечается как «спам». Поэтому я быстренько соорудил небольшой плагин, который сразу отклоняет такие комментарии и не засоряет базу.
Сделал небольшое дополнение для firefox, которое форматирует rss + дополнительные поля из jira в виде небольших карточек, удобных для печати.
Буду рад предложениям и замечаниям.
Задачка для собеседования программиста, 2
17.10.2008
Задачка про базы данных, старая и не моя.
Имеется таблица, один из столбцов которой – уникальный целочисленный идентификатор. Каждый новый идентификатор получается инкрементом предыдущего значения (проще говоря – auto_increment в MySQL).
Иногда строки из этой таблицы удаляются и в последовательности идентификаторов возникает пробел. Требуется найти идентификатор, находящийся до или после первого пробела.
Небольшая иллюстрация:
| id | ... | 1 | ... | 2 | ... | 3 | ... | 5 | ... | 7 | ...
