Thursday, December 22, 2011

Зачетный пример на TDD - Prime Factors

Недавно мне посчастливилось попрактиковаться в парном программировании с Johannes Brodwall во время его визита в Киев на конференцию XP Days. Мы, играючи в ТДД пинг понг, за пару часов реализовали 2 довольно сложных примерчика, так называемых kata для его coding dojo сессии на XP Days. Причем успели один из примеров реализовать не только на Java, но еще на CoffeScript.

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

Если ты еще не знаком с правилами ТДД пинг понг, то рекомендую посмотреть как это делается здесь или попрактиковаться на нашем треннинге по ТДД.

"Prime Factors" (не знаю как по-русски).
Разложить целое число на множители из простых чисел:
2 -> [2]
3 -> [3]
4 -> [2,2]
6 -> [2,3]
9 -> [3,3]
12 -> [2,2,3]
15 -> [3,5]
и так далее...

Итак, начали...
Johannes. Естественно с теста:

public class PrimeTest {
@Test
public void primeFactorOfOne() {
assertEquals("[]", Prime.factorsOf(1).toString());
}
Я. А че тут думать? Самая простая реализация - вот:
Тесты прошли, пишу следующий тест:
junit.framework.ComparisonFailure:
Expected  :[2]
Actual    :[]

Johannes. Тоже не особо думая
и, после запуска тестов - пытается отдать мне это:
Oops... тест зеленый, сори, мне идет эта подача:
junit.framework.ComparisonFailure:
Expected  :[2, 2]
Actual    :[4]

Я. Лень что-то придумывать сложное. Первая мысль - добавить тупой if и разделить на 2
как ни странно, но прошло. Тихо радуюсь про себя, что не мне реализовывать следующий тест:
junit.framework.ComparisonFailure:
Expected  :[5]
Actual    :[2, 2]

Johannes. Видимо, почувствовал мое злорадство и тоже долгими раздумьями над идеальным решением себя не утрудил:
и, как говорится, "получите, распишитесь" - забираю клавиатуру с таким красным тестом:
junit.framework.ComparisonFailure:
Expected  :[2, 3]
Actual    :[3, 3]

Я. Тут я немного подвис. Смотрю на то, как падает тест и не без помощи напарника понимаю, что для того, чтобы в списке появилась 2, а потом 3, нужно организовать цикл:
Ура! Работает! Все тесты зеленые. Пробую добавить тест на семерку - проходит. Поправляю на 8 и отдаю клавиатуру
junit.framework.ComparisonFailure:
Expected  :[2, 2, 2]
Actual    :[2, 4]

Johannes. Все, что надо сделать - это заменить if на while:

Все тесты зеленые! Я пытаюсь добавить тест на двухзнчные числа, потом думаю подловить, предав что-то вроде такого 2*3*5*7*11*13*17*19*23, потом отнимаю от этого выражения 1, затем 2 но поломать код не получается - тесты зеленые! Все, сдаюсь и соглашаюсь: РАБОТАЕТ!

На этом бы и поставить точку, но в вообще существуют еще нефункциональные требования, которые зачастую не так легко проверить при помощи TDD.
Этот алгоритм еще можно оптимизировать по скорости, но чтобы это почувствовать мы добавили такой тест, который выполнялся около 23 секунд:

И "пофиксили" его вот таким изменением:

Все, теперь не только РАБОТАЕТ, но и работает БЫСТРО!

Tuesday, December 06, 2011

Как мигрировать локальный репозиторий SVN на Git/Github

Git предоставляет мост через который можно работать с SVN как с удаленным репозиторием, при этом пользуясь практически всеми возможностями, которые предоставляет Git. Все, что нужно сделать - это научиться пользоваться командой git svn которая идет вместе с инсталляцией клиентской версии git. С миграцей репозитория на Git\Github тоже ничего не должно быть сложного. Достаточно добавить удаленный репозиторий после импорта SVN в локальный проект и набрать команду git push. Эх, если бы все было так просто...Расскажу как у меня это получилось с обходом одной грабли, на которую пришлось наступить.

Для начала устанавливаем клиентскую версиою Git. Я использовал msysgit версии 1.7.8-preview.

Предположим, что наш локальный SVN репозиторий находится в папке C:\workspace\Repository и свн установлен на машине.

Открываем командное окошко (cmd) и набираем команду

svnserve --daemon --root C:\workspace\Repository

Этим мы запустили сервер SVN, который дает нам возможность удаленного доступа к нашему репозиторию по протоколу svn, что даст возможность Git его скачать. Теоретически и документация говорит, что git svn должен понимать протокол file://, но если бы все было так просто... на StackOverflow нашел свою проблему с решением

Далее создаем новую папку в которой будет создан локальный слепок SVN репозитория в GIT формате (в моем случае C:\workspace\git-repository)

Запускаем Git-bash в этой папке из контекстного меню Windows Explorer. И запускаем команду
$ git svn clone svn://localhost --no-metadata

Чем больше репозиторий, тем дольше она будет выполняться. В моем случае на 100 комитов она выполнялась минут 5. После чего у меня появилась папка localhost с содержимым svn репозитория и отображением всего SVN репозитория в локальном репозитории GIT.
Перехожу в эту папку
$ cd localhost/

и связываю локальный репозиторий с удаленным репозиторием Github, который я заблаговременно создал:
$ git remote add origin git@github.com:tdd-elevator-training/elevator.git

после чего мне осталось залить (пушнуть) изменения на сервер, что я с радостью и делаю вот таким способом:
$ git push -u origin master

Все, мой SVN репозиторий полностью со всей историей и даже с сохраненными авторами начальных комитов в Github.

Monday, December 05, 2011

Как быстро настроить Github в Intellij IDEA

Недавно вышел релиз кандидат Intellij IDEA 11. В числе многих украшательств и фишечек JetBrains расширил поддержку популярного вершн контрола Git/Github. Мне очень захотелось попробовать поработать с Git, но помня нашу неудачную с Сашей попытку настроить Github проект из Intellij IDEA, я предварительно вооружился документацией на русском языке после чего начал настраивать Git репозиторий. Здесь я расскажу как у меня это получилось и на какие грабли наступил.

Шаг 1. Установка Git клиента.

Следуем инструкциям по инсталляции с Github. Скачиваю msysgit (версия Windows здесь http://code.google.com/p/msysgit/downloads/list). Дальше все как по картинкам в инструкции.
Затем добавил переменную среды GIT_HOME, которая указывает куда установил Git:


после чего добавил в Path:
Шаг 2. Создаем репозиторий и публичный ключ

У нас уже есть учетная запись на Github, я использую ее и создаю репозиторий под названием "test".
Для того, чтобы сервер Git смог меня аутентифицировать (узнать) мне нужно сгенерировать rsa ключ. Делается это так:
Запускаю Git-bash из контекстного меню Windows Explorer (откуда запустил 0 не важно)
Знакомлю git клиента с параметрами пользователя, которые он будет использовать в поле Author для чего ввожу команды:
Затем генерирую файл ключа:
После того как я ввел пароль мне генератор сказал где лежит файл ключей:
Мне нужен публичный ключ, который находится в ./ssh/id_rsa.pub. Открываю этот файлик и копирую содержимое в буфер обмена (Ctrl+C).

Открываю страничку настроек моего акаунта в Github (Account Settings) и добавляю новый ключ в секции SSH Public Keys:

Все, теперь сервер должен меня узнать.

Шаг 3. Создаем проект и начинам комитить

Открываю скачанную недавно Intellij IDEA 11 RC, кликаю на Check out from Version Control и выбираю Git в выпадающем меню:

в окне Clone Repository ввожу Git Repository URL, Parent directory и Directory name:
Узнать Git Repository URL можно настройках репозитория, но я просто скопировал со страницы с инструктажем по настройке локального репозитория:
После того, как склонировался репозиторий создал проект и добавил в него README.txt файлик. Я готов комититься. Жимаю и выбираю комит с пушем (Commit and Push...) из окошка Commit changes:
Важный момент: окне просмотра Git push IDEA показывает, что master - это не "tracked" бранч. Т.е. он не связан с удаленным репозиторием. Почему так получилось - не понятно, но когда я экспериментировал с другим сервером Git хостинга unfuddle, все заработало сразу. В общем для того, чтобы это "полечить" достаточно выбрать галочку "Push current branch to alternative branch":
Все, мои изменения на сервере. Могу в этом убедиться просмотрев логи:
не верю своему счастью, меняю README.txt и делаю комит в идее (без пуша). После чего меняю еще раз и комичу с пушем:
Master теперь связан с удаленным репозиторием, о чем красноречиво говорит надпись master -> origin/master. Origin - это псевдоним удаленного репозитория. Git дает этот ему этот псевдоним по умолчанию. Это удобно, если работать с несколькими репозиториями одновременно - но это уже совсем другая история :)

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


Если не работает 

При попытке сделать update выдает ошибку идентификации или просто долго висит

Запусти git-bash и посмотри где он думает находится HOME директория пользователя (команда cd ~, затем pwd). Затем убедись что в этой директории находится папка с ключами .ssh



Добавь переменную окружения HOME, которая указывает на home директорию из git-bash. В моем случае уже были установлены переменные HOMEDRIVE и HOMEPATH, которые указывали на Z:\
Перезапусти IDEA