Думаю многие знают про интересную библиотеку Bootstrap от разработчиков twitter. Для тех кто не в курсе: это набор готовых элементов интерфейса, типографики, форм и layout-ов. С помощью набора стилей можно легко верстать достаточно сложные интерфейсы, мало что понимая в многообразии бразуеров, блочной верстке и прочем колдовстве.
Недавно увидел магазин http://wrapbootstrap.com/, в котором по типу templatemonsters продаются различные стили для Bootstrap. Похоже, что инструмент набирает популярность и становится массовым.
Особая польза видится мне в том, что Bootstrap задает некий язык, на котором можно общаться с «фронтендерами». В библиотеке покрыто множество аспектов, которые при разработке интерфейсов часто оказываются за кадром, забывается дизайнерами, делается абы как верстальщиками. Это единый внешний вид элементов форм, списков, сообщений об ошибках.
Формулировка задачи разработчикам интерфейсов в формате «нужен дизайн как кастомизация Bootstrap» позволяет не потерять из виду мелочи, и как следствие, получить более качественный продукт, который легко использовать и поддерживать.
Про именование булевых переменных
22.04.2011
Сегодня по дороге на обед мой коллега Алексей Пыченков высказал отличную мысль про именование булевых переменных (как правило различных флажков) в тексте программы, которой мне очень захотелось поделиться.
Именовать флажки лучше в «положительном» ключе. Такое именование улучшит читаемость логических выражений в условных операторах.
К примеру $isAllowed лучше, чем $isDisallowed. Например выражение:
if (something && !$isAllowed) { ... }
сильно понятнее
if (something && !$isDisallowed) { ... }
где, нужно затратить дополнительные усилия, чтобы провести в уме двойное отрицание.
Интересное сообщение об ошибке «attempt to run compile-and-go script on a cleared scope» стало появляться в нашем проекте в новом Firefox 4.
Ошибка происходила в компоненте, который с помощью объекта xmlHttpRequest делал long polling на предмет новых событий. Компонент слушал событие window.onunload и вызывал метод abort() у xmlHttpRequest, дабы избежать подвисших соединений. Проблема решилась сбросом обработчика onreadystatechange перед вызовом abort().
Причина, похоже, крылась в том, что метод abort() вызывал обработчик onreadystatechange в момент, когда контекст окна уже перестал существовать.
Решил на досуге набросать ассоциативную карту МоегоКруга. В качестве инструмента выбрал mindmeister.com и начал работу.
В процессе, оказалось, что мне очень нужны ссылки между узлами дерева, а mindmeister задавать такие отказался. Решил сменить инструмент на бесплатную программу FreeMind.
Для сохранения карты в формате FreeMind mindmeister хочет, чтобы пользователь перешел на платный аккаунт. Из того, что предлагается за $45 мне нужна была только выгрузка одного файла.
Форматы файлов очень простые (jsonp и xml), поэтому я соорудил конвертер на питоне: https://github.com/xfox/mind2mm. Конвертер очень простой – он не сохраняет форматирования, переносит только структуру.
Disclaimer: Я не призываю обманывать mindmeister.com и не пользоваться его платными сервисами. В premium очень много полезных функций, для тех, кому они нужны.
Прокси-сервер с задержкой пакетов на twisted
18.02.2011
На работе возникла необходимость потестировать как наш код работает с задержкой репликации.
Долго искал в интернете подходящий инструмент, который бы проксировал соединения slave->master и создавал бы задержку, но ничего достойного не нашел. Поэтому набросал простенький прокси на питоне, благо в Twisted был готовый модуль portforward.
Для рабочих задач мы нашли другое решение, а код мб кому-нибудь пригодится https://github.com/xfox/tcpdelay
Проблема
Разрабатывая приложение с использованием js openapi столкнулся с проблемой: при совместном использовании с
prototype.js в браузерах IE6/7 возникает js-ошибка Function expected.
Покопавшись пару часов в исходниках api выяснил, что ошибка возникает при инициализации вспомогательного модуля XDM, который, судя по всему, помогает выполнять кросс-доменные запросы.
Проблема проявляется только в IE6/7 и, возможно она когда размер запроса > 1500 символов. Именно в этих случаях запрос производится через XDM.
Решение
Для обхода конкретно проблемы я использовал хак – перед вызовами openapi я удалял метод toJSON у Array.prototype, дабы для json-сериализации не использовался prototype.js
// ...
var _hackStore = Array.prototype.toJSON;
delete Array.prototype.toJSON;
// do smth with openapi
Array.prototype.toJSON = _hackStore;
Технические подробности
Объект, подготовленный для передачи в XDM proxy, имеет метод each, появившееся после того, как библиотека prototype.js расширила стандартный массив Array дополнительными методами. Перед вызовом XDM функция openapi.js:applyMethod заменяет все методы передаваемого объекта на хеши.
Далее, в функции xdmHelper.js:str() делается проверка на наличие метода toJSON у передаваемого объекта, и его вызов. В методе prototype.js:Enumerable.toJSON объек рекурсивно обходится с помощью each, и как только дело доходит до ветки, обработанной applyMethod – возникает ошибка, т.к вместо метода each у объекта – хеш.
Чтобы обойти проблему оказалось достаточно перебить метод toJSON, чтобы openapi не предпринимала попыток сериализации через prototype, а пользовалась только внутренними методами.
Пример кода, демонстрирующий проблему – http://ilazarev.ru/vkapi/index.html
– нажать login + поехали.
Несмотря на то, что таскменеджеры наши друзья и помогают не забывать ни одной мелочи, очень часто работа с ними превращается в поиск иголки в стоге сена. Во многих проектах задачи валятся как из рога изобилия: саппорт фиксирует десятки жалоб от пользователей, заказчики жаждут новых новых сочных функций, тестировщики находят изощренные ошибки и тщательно их документируют.
Через пару месяцев число открытых задач переваливает за 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»
