Яндекс и суббота

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

Сначала было выступление, посвященное верстке в Idea от JetBrains. Возможно, в будущем сделаю шаг в сторону от эклипса и навстречу Идее.

Потом рассказывали про нарезку картинок. Узнал про гамму 2.2 и оптимизаторы картинок. Полезный доклад.

Далее Виталий Харисов говорил про верстку независимыми блоками. К слову, мы в студии используем его подход (и вообще многим вещам научились из докладов яндексовцев). Еще я узнал, что подняли клуб, посвященный этому делу.

Bind-функция для jQuery

Как разработчик привыкший к использованию библиотеки prototype.js, я не смог понять причину отсутствия в библиотеке jQuery отсутсвия метода bind, который позволяет в обработчик передать контекст (scope). А я часто пишу слабо связанные классы, которые связываются посредством событий. Поэтому, взяв за основу код из prototype.js я его адаптировал к полной независимости от библиотек. Теперь можно так обрабатывать события (ну или коллбеки, кто как назовет): В отличие от распространенной практики в jQuery: Еще сторонники jQuery часто пишут код обработчика прямо в анонимной функции. Замечу, что постоянно вижу у jQuery-разработчиков очень грязный код, в котором одна функция может быть на весь экран и более. Следует всегда в независимости от принятых подходов в фреймворке оформлять код руководствуясь книгой «Рефакторинг» Фаулера. Мне лично нравится продуманность и чистота кода библиотеки Ext.js

Алгоритм эффективного выполнения любого задания

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

Вам поставили локальную задачу в рамках проекта. Алгоритм решения:

1. Понять для чего проект и каким целям служит. Если не понятно, спросить.

2. Узнать все, что требуется для того чтоб ваша задача считалась завершенной.

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

4. Сказать тому кто поставил задачу прогнозируемое время выполнения и прогнозируемую дату. В тоже время мозг получит ограничение по времени и в фоновом режиме начнет корректировать действия чтоб уложиться в срок.

5. Последовательно выполнить каждый пункт плана.
По себе знаю, что с большой неохотой сажусь за выполнение непонятных мне задач, делаю их медленно. Если же проанализировать вначале задачу и сделать ее ясной — выполнение пойдет плавно и приятно.

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

Значение поля формы в Django шаблоне

Порой мелкие и простые ситуации отнимают лишнее время. Сегодня я встретился с ситуацией, что мне нужно было получить в шаблоне значение поля формы. Можно было бы передать значение в контексте, но это было бы уже дублированием.
Есть простой способ получить значение поля формы:
{{form.initial.field_name}}

Python yield — простым языком

Надеюсь, теперь понятно, что делает это команда. Фактически в функции встроен скрытый массив result, в который мы добавляем значения при вызове yield. При вызове next мы делаем pop из возвращенного значения. Можно также бежать по результату вызова функции (итератору) a как по обычному массиву 

Решение криптоарифметической задачи

Начал читать книгу «Экспертные системы: принципы разработки и программирование». Книга массивная, много букв. В конце первой главы дается криптоарифметическая задачка donald+gerald = robert при условии, что d = 5. Взял листик бумаги и ручку, минут 5–10 ушло на решение. В книге дают задание написать программу, решающую эту задачу. Начал придумывать как бы я написал эту программу. В голову пришло решение «в лоб», используя перебор.

Собрал в кулак свою лень, создал питоновский файл и начал писать. Далее будет код с краткими вкраплениями моих комментариев:

Результаты:
donald+gerald = robert если известно, что d = 5 :
result found on 103487 iteration: 526485 + 197485 = 723970
resolve took 9.399 s

если ничего не известно — подольше:
result found on 1917887 iteration: 526485 + 197485 = 723970
resolve took 183.831 s

Нашел еще задачку: send+more = money
result found on 2787378 iteration: 9567 + 1085 = 10652
resolve took 265.016 s

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

Сlonedigger — инструмент нахождения дубликатов в Python коде

Нашел отличный инструмент для нахождения дублирования в питоновском коде. Давно искал что-то подобное. Качественный инструмент. В результате прогона по коду, инструмент генерирует удобный html-отчет.
http://clonedigger.sourceforge.net/index.html

Динамические запросы (фильтры) в django

Хороший заголовок, информации в гугле по этому поводу не найдено. Стоит задача сделать фильтр. Возьмем, к примеру, таблицу, первая строка которой содержит фильтры для колонок. Усложненный вариант фильтра позволяет выбирать сразу несколько значений. Реализовать такой механизм средствами ORM django довольно просто.

Создаем метод, получающий на вход имя поля и массив значений: Вызывать можно таким образом: Обращаю внимание на одну очень замечательную особенность ORM django — city__country__name. Эта запись означает, что мы фильтруем по имени страны, к которой принадлежит город нашей целевой модели. Работу по созданию джоинов джанго берет на себя.

Основываясь на коде, приведенном выше можно построить универсальную систему фильтрации.

Анализируя JavaScript код

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

Спрятать и показать

Типичный код, — абсолютно симметричная пара методов для сокрытия и показа чего-то. Но решение не самое лучшее из-за дублирования:

Рефакторим:

Вполне резонно заметить, что получившегося кода стало больше на один метод и не ясно, стоит ли увеличивать комплексность кода. В данном случае экономия весьма не очевидна, как и затраты. Я за то чтобы делать рефакторинг, начиная с самого незначительного — все дело в стиле мышления (не говоря о гибкости, которая появилась). Поддерживая порядок, будешь жить в чистоте. Иначе — известно в чем.

Массивы

Часто можно встретить такой вид создания:

Более короткая версия:

Удаление элемента из массива. Интуитивно-понятного метода remove у массива нет, к сожалению. Поэтому можно встретить код: Тут происходит простое копирование всего в новый массив, за исключением ненужного элемента. Не самый быстрый способ, особенно в случае большого массива. Пользователи библиотеки Prototype.js для этой часто используют метод — arr.without(el), который работает по той же самой схеме (все же замечу, что у прототайпа великолепные методы для расширения класса Array). Тривиально, но многие не знают, что удаление из массива выполняет встроенная операция — arr.splice(номер элемента, количество удаляемых элементов) — еще метод позволяет делать замену.

Создание элементов

Часто можно увидеть большое количество кода создающего DOM-структуру. Пишутся обертки для удобного создания DOM-елементов. А ведь решение — не самое производительное.

По производительности innerHTML — лучший. Исходя из этого, в большинстве случаев методы DOM отбрасываем (есть исключения, такие как тег — table в IE, он не дает ничего записать в свой innerHTML). Мне очень нравится класс Template в библиотеке Prototype, позволяющий создавать штмл подобным образом: Для остальных пользователей легко придумать решение используя стандартный replace. Еще на один момент следует обратить внимание. Временным контейнером штмл является массив строк и в конце происходит this.cbCity.innerHTML = options.join(""); — это дает лучшую производительность.

В заключение

Мне еще попадались различные стандартные ситуации. По мере возможности, в будущем соберу их еще в одну часть.

Симметрия кода

Прочитал книгу Кента Бека «Implementation Patterns», у нас почему-то названную «Шаблоны интеграции корпоративных приложений». Коэффициент полезного содержания в этой книге, по какой-то причине, оказался меньшим чем я рассчитывал (возможно, прочитанное будет вылазить из недр сознания позже).

Тем не менее, мысль о симметрии в коде, мне понравилась. Возможно, термин «однородность кода» ходит где-то рядом.

Симметричный код читать легче. Например, зная один метод, можно предположить, что ему есть пара: enable, disable; add, remove; undo, redo и так далее. Симметричность может проявляться не только в именах-антонимах, но и в логике кода.

Возьму книжный пример (вдобавок мое вольное изложение на основе воспринятого): Код не симметричен: count++ дает слишком много детализации по сравнению с input и output. Теперь более симметрично. Но ввод, увеличить количество, вывод — не самые симметричные вещи. Куда однороднее звучит — ввод, счет, вывод.

Теперь попробую применить к своему коду (внимание, эксперементальный юмор):

Джаваскриптовый метод, создающий штмл для вывода городов в выпадающем списке.

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

Промежуточная версия кода была бы куда менее близка к симметрии:

А вот финальная версия, с точки зрения детализации, является симметричной:

Юнит-тестирование — плохо

Для не знающих

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

Но

Вы, скорее всего, не умеете писать тесты и, очень вероятно, что в вашем коде присутствует большинство признаков плохого кода. Это лечится при желании. Лекарства:

  • Рефакторинг. Улучшение существующего кода
  • Экстремальное программирование: разработка через тестирование
  • Шаблоны тестирования xUnit. Рефакторинг кода тестов — эта книга мега-лекарство.

Для знающих много пользы

А знать надо вот что:

  • Юнит-тест — тестирует лишь небольшой кусочек функционала.
    В идеале протестировать метод на то, что он правильно делает вызовы других методов
  • Юнит-тест невероятно быстр.
    Поскольку тестируется лишь маленький кусочек функционала без обращений к бд или файлам — все довольно таки быстро.
  • Для большого метода юнит-тест написать очень сложно.
    Сложно, потому что много логики. Приходится слишком много заглушек делать для одного метода.
  • Тестируемый функционал не обращается к базе данных, не отправляет запросов, не считывает файлы с диска.
    Это долго и тестируемый функционал становится незащищенным от сбоев внешнего функционала.
  • Юнит-тест не зависит не от порядка выполнения теста, не от сбоев в остальном функционале.
    Тесты должны быть независимы — это упрощает локализацию ошибок.
  • Все юнит-тесты вместе взятые выполняются не более 10 секунд в любом проекте.
    Иначе слишком часто запускать их будет не удобно.
  • Юнит-тесты как и код требуют рефакторинга.
    Постоянно делая рефакторинг, получите свой тестовый язык (или апи) для тестов.
  • 100% покрытие юнит-тестами не даст 100% гарантии работоспособности проекта.
    Всего не учтешь и не протестируешь.
    Тесты дадут возможность:

  • избежать сценариев — кто похерил мой функционал? (разработчик); как же так, оно ведь уже работало? (заказчик)
  • смело делать рефакторинг кода, который используется во всем проекте
  • быстро находить ошибки
  • получать удовольствие от разработки (когда знаешь, что все работает — очень хорошее чувство)

Еще мысли

Юнит-тесты писать сложно. Лень, незнание, самообман — очень веские помехи.
Разработка через тестирование? — В идеале.
Легко тестировать функционал для рассчетов чего-либо — это сплошное удовольствие.
Являются ли тесты гарантией успеха проекта? — Нет, также как и хороший код. Но приятнее работать с хорошим кодом и с протестированным функционалом.
Если проект не большой и его не надо будет сопровождать в будущем — можно и без тестов обойтись, используя копи-паст для ускорения разработки.

Кроме юнит-тестов нужно писать интеграционные тесты — те же юнит-тесты только без заглушек функционала. Выполняются долго, зато позволяют проверить, что механизм в собранном виде функционирует нормально.

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

И обязательно прочтите книги из списка, если еще этого не сделали.

Автоматизация простой операции

Довольно таки полезно автоматизировать повторяющиеся операции.
Например:
original_save_photo = views.save_photo
original_all = Album.objects.all
original_get_sizes = views.get_sizes
original_filter = Photo.objects.filter
original_send_json = Ajax.send_json

Потом надо вернуть данные свойства на место — довольно таки назойливая ручная операция:
views.save_photo = original_save_photo
Album.objects.all = original_all
views.get_sizes = original_get_sizes
Photo.objects.filter = original_filter
Ajax.send_json = original_send_json
Я такую операцию в эклипсе провожу с помощью замены
Ищу: ^\s*(.+)?\s=\s (.+)?$
Меняю на: $2 = $1

Continuous Integration в django проекте

Предпосылки

Проект относительно небольшой с командой из 4 разработчиков. Хотелось процесс разработки максимально приблизить к описанному в книге Continuous Integration: Improving Software Quality and Reducing Risk Были поставлены требования:

  • юнит-тестинг
  • проверка кода на соответствие стандартам
  • автоматизированный подъем проекта на сервере для тестирования
  • быстрый прогон тестов (до 10 секунд)

Юнит-тестинг

Доктест сразу отпал (с тдд маловато общего). В юнит-тестинге сразу столкнулся со сложностью:

  • The models.py file. The test runner looks for any subclass of unittest.TestCase in this module.
  • A file called tests.py in the application directory — i.e., the directory that holds models.py. Again, the test runner looks for any subclass of unittest.TestCase in this module
отсюда

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

С базой данной проблема решалась путем замены MySql на Sqlite (: memory: — она в оперативной памяти) во время тестинга (решение отсюда).

Для того чтоб тесты лежали в отдельной директории, в этой же директории был создан файлик suite.py, в котором приблизительно в таком виде все происходит Вот две функции из кода выше:

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

Проверка кода на соответствие стандартам

Для проверки кода используется утилита pep8 Внедрялось с некоторым недовольством со стороны разработчиков. Но довольно таки полезная вещь для поддержания порядка в коде.

Билд-сервер

Можно сказать, что какой там билд сервер может быть в питоне и что там билдить. Я не знаю как его назвать иначе. В моем случае это сервер с Windows, на котором стоит TeamCity. Очень удобная штука в работе, с отличным веб интерфейсом. Конфигурить очень просто и быстро. Позволяет делать Pre-tested Commit (в моем случае не очень хорошо работало). Он периодично проверяет SVN (мы его используем) на наличие изменений и запускает билд скрипт- в моем случае это обычный build.bat файл, который делает апдейт из свн, выполняет тесты и рестартует Apache, который у нас на сервере. С этого момента проект можно открывать и тестировать на билд сервере. Участники проекта, в зависимости от конфигурации оповещений узнают об успешности или провале билда.

Реалии проекта и планы

Для команды это первый проект с использованием Contineous Integration. Как и первый серьезный django проект. Дедлайн как всегда очень рядом. Вероятно, не все звенья процесса разработки близки к идеалу, но процесс есть и работает. В планах внедрить Selenium тесты, cделать автоматизированный деплой проекта в продакшн.

Типограф (тупо-пу)

http://www.kigorw.com/typo-py/

Я написал типограф на питоне. Это был переколбас существующего PHP типографа с открытым исходным кодом. На все ушло около 16 рабочих часов.

Пришлось понять как правильно работать с юникодом и регулярками в питоне.

Пришлось придумать альтернативу Lookahead, Lookaround, которые выглядят иначе в питоновских регулярках.

Код получился некрасивым, но рабочим. С юнит-тестами.

Рассчитываю на то, что кому то еще пригодится.

Совет изучающим новую технологию

Когда, к примеру осваиваешь Django, полезно первым делом прочитать книгу по Python и книжку по Django. Многие детали хоть и не закрепятся, но будет создан рабочий поисковый индекс. Вы будете знать возможности и знать где посмотреть детали реализации.

Думаю, что этот подход хорош для освоения почти (подстраховался) любой области знаний.

Обучение. JavaScript

2. JavaScript. Синтаксис языка, понимание DOM модели, понимание того для чего и как работают джс фреймворки (к примеру прототайпджс, джквери). Способность писать многофункциональные клиентские приложения, виджеты.

На сверстанной страничке из первой части (там такое задание) есть диаложек (его тоже верстают). Потом я даю задание подключить диложек с помощью джаваскрипта. Говорю использовать библиотеку prototype.js и на ее основе строить классы.
Еще настоятельно рекоммендую книги:

Далее приведу список наиболее частых ошибок при написании джаваскрипт кода.

  • Множество классов в одном файле. Примите за правило — в одном файле один класс. Потом все джаваскрипты сжимаются в один файл, и компрессятся.
  • Хаотичное использование в каждом методе document.getElementById (в прототайпе $ или $$, что еще хуже). Надо по возможности записать ссылки на дом элементы на поля класса в инициализации один раз и потом уже использовать.
  • Отсутствие понимания, что такое контекст. И зачем в прототайпе bind и bindAsEventListener
  • Много глобальных переменных
  • Тянучка связей между классами, все классы знают про всех остальных. Дом элементы модифицируются и тоже хранят ссылки на другие обьекты. Надо же делать связи на основе событий.
  • Обьект создается прямо в джаваскрипт файле (еще лучше ситуация когда там код window.onload = function (){ new MyClass ()}). Подключая этот джс на страницу получаешь кота в мешке -речи о том что потом можно будет сбилдить все джсы в один файл уже не идет.
  • Весь код прямо в штмле, код должен быть в отдельных файлах

Пока все, буду дописывать постепенно.

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

Джанго

Нравится 

  • Наследование темплейтов
  • Middlewarе и template processors
  • forms
  • orm

Не нравится 

  • Стандартная админка. Лучше писать свою — дешевле.
  • Юнит тестинг. Слишком много манипуляций надо сделать, чтоб нормально начать писать тесты. Тестирование вьюзов сложновато. Питоновская либа pymock, после работы с дотнетовскими моками выглядит ущербной.
  • Скудный язык темплейтов (можно спорить)

Обучение. Верстка

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

Первый пункт из моей программы

1. HTML, CSS. Разработчик должен без проблем уметь верстать, быть в курсе большого числа аспектов (семантическая верстка, спрайты, кроссбраузерность, фаербаг итд).
1.1. Понимание основ типографики, юзабилити, дизайна (ководства для начала хватит)

Я даю ученику сверстать простую страничку, он мне ее присылает и я говорю, что неправильно. Уже сейчас могу сказать типичные ошибки учеников при верстке:

1. Не видят расстояний, размеров шрифтов, цветов. Детали, которые для тренированного глаза сразу видны.
Бороться с этим очень легко. Ставим Фаербаг, PixelPerfect и плагин линейка

2. Семантичность. Для списков надо использовать тег

  • . Для заголовков тег h. Для позиционирования элементов не использовать тег br. Для надписи над инпутом использовать тег label.
    Короче говоря, надо знать для чего какой тег использовать.

    3. Селекторы делаем class, а не по id. Возможно тут и поспорить. Но такое решение гораздо более масштабируемо.

    4. Забывают посмотреть в ИЕ или ФФ.

    5. CSS инлайн, а надо в отдельном файле.

    6. Не знают ничего о свойствах margin и padding, которые управляют расстояними между элементами.

    7. Используют в цсс свойства, о назначении которых не знают.

    То, что может помочь.

Linq to SQL и DDD

В данной статье описывается создание инфраструктуры, позволяющей использовать технологию Linq to SQL и методику DDD. Сразу же даю ссылку на исходники, для тех кому надо по быстрому получить рабочее решение.

Замечательная книга Джимми Нильсена  Applying Domain-Driven Design and Patterns: With Examples in C# and .NET хороший материал о разработке комплексных проектов через тестирование. Книга была написана еще до выхода технологии LINQ. Майкрософт сделал многое для того, чтоб ORM стал простым в .NET разработке.

Некоторые принципы DDD: Обьекты – POCO – они не знают про ORM, являясь наследниками Object. Репозитории – классы отвечающие за извлечение и сохранение обьектов. Архитектура, базируется на модели.

В блоге Скота Гу, много материала по LINQ, но там ни слова про DDD.

Класс DataContext, идущий рядом с паттерном UnitOfWork, имеет серьезный недостаток – не реализует интерфейса. Что сильно затрудняет юнит тестинг (нельзя подделать реализацию с помощью Mock objects) Здорово, что проблема уже решена: Using Mock Objects When Testing LINQ Code — вполне рабочее решение, но мне ближе другая реализация. Trying Out Persistence Ignorance with LINQ  — эту реализацию я и взял за основу решения, использованного в моем проекте.

Способ состоит в том, чтоб сделать интерфейс UnitOfWork, который инкапсулирует в себе все взаимодействие с хранилищем. Так что, будет очень легко подставить в классы для тестирования поодельную реализацию.

Сама реализация кратко ниже:

Настоящий источник данных делегирует все родному классу DataContext.

Настоящий UnitOfWork создает PersistentDataSource и считывает маппинг классов из хмл файла, дизайнер классов я не использую и вам не советую.

Поддельная реализация IDataSource весьма проста – она все делегирует классу List

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

Пример

Есть таблица со странами. Для демонстрации связи с другой таблицей я указал Это означает, что в стране могут быть привязанны пользователи.

Класс страны Простой класс, практически POCO. Практически, потому что связь описывается при помощи коллекции EntitySet. Линк использует этот класс для автоматической загрузки графа обьектов.

Так выглядит ссылка в классе User на класс страны. Так в хмл

Сохраняемые в БД классы я храню в одном проекте с ифраструктурой сохраняемости. Иначе у меня не получалось корректно инициализировать UnitOfWork. Далее все как по книге Нильсена.

Репозитории

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

Так выглядит NUnit тест