Wednesday, October 12, 2011

Git and Continuous Delivery


I wonder, how to establish development process with git or other distributed source control system and Continious Delivery pattern.
I've seen a presentation by Linus Torvalds, where he explained how are they use git for Linux development. So it's an hierarchical structure of commiters based on trust with Linus on the top. Linus trusts to some people and can pull code from them. These people have their own teams which they trust and pull changes and so on.
As a result Linus has fork of Linux source code which can be released. I know that Linux was migrated on GiHub. I suspect that only Linus can push changes there (or few people including Linus)
So GitHub remote repository can be treated as a mainline. Continuous Delivery pipelines use it for releases.
So i can see two ways to establish the process of commits.
1st as i described earlier with Linux
2nd - everybody can push to mainline (GitHub) and no hierarchy. I cannot see any benefits of distributed source control system in this case.

What do you think? What is best approach to build delivery process in this case? Or distributed source control systems are not the best choice for continuous delivery, and you'd better use centralized?

Wednesday, August 24, 2011

Functional testing Grails app with Geb. User story 1

User Story Description.
As a head of Sales department, i would like to see all orders from PreSellers and VanSellers.
I would like to see following info on the Orders Grid

  • Order Number
  • Seller
  • Customer
  • Sum
  • Customer Address
  • Status
  • Type
  • Order Date
  • Discount
  • Discount %
  • Payment type
  • Price
  • if Credit Limit Passed
  • is Stock Limit Passed
  • Shipped Date
  • Description
I also would like to be able to expand each row and see detailed description of each order, including Order Details

Architecture and Design
So, let's describe brief architecture of this solution. It's quite easy. 
We already have database solution of Orders data structure, which is on production. I prefer to provide read only access to Web Application using views.
We will use Grails Web framework as underlying technology for web application.
We will use GWT to implement views for Orders Enquiry (because i have Java background but not Java Script, unfortunately)

What about testing?
Ok. I prefer to be test driven as match as possible. But it's challenged task for UI tests. Unfortunately it's difficult to provide TDD for UI unless you have implemented it.
Imagine we will have simple grid, each row can be expanded and form appears. Form consists of 3 tabs:
  • Order Information
  • Customer Information
  • Order details with grid on it
Let's describe possible UI tests using mmm... Spock?

def "lets open order page and vlidate if 4 orders are seen"(){
when:
to OrdersPage
then:
assert ordersGrid.size == 4
}

More tests?


def "i would like to expand rows to see order info"(){
when:
to OrdersPage
and:
ordersGrid.expandRow(0).click()
then:
def now = new Date()
def df = new SimpleDateFormat('yyyy-MM-dd')
ordersGrid.expandedForm.orderInfoTab.nomNumber.value() == '000-00000-00'
ordersGrid.expandedForm.orderInfoTab.orderedDate.value() == df.format(now)
ordersGrid.expandedForm.orderInfoTab.shippedDate.value() == df.format(now)
ordersGrid.expandedForm.orderInfoTab.description.attr('value') == 'description'
ordersGrid.expandedForm.orderInfoTab.summ.value() == '10.30'
ordersGrid.expandedForm.orderInfoTab.seller.value() == 'PreSeller Ivanov'
}

def "i would like to expand rows to see customer info"(){
when:
to OrdersPage
and:
ordersGrid.expandRow(0).click()
then:
ordersGrid.expandedForm.customerInfoTab.customer.value() == 'Some test customer'
ordersGrid.expandedForm.customerInfoTab.salesOutlet.value() == 'Sales outlet'
ordersGrid.expandedForm.customerInfoTab.dept.value() == '0.00'
ordersGrid.expandedForm.customerInfoTab.creditLimit.value() == '1000.00'
}

def "i would like to expand rows to see order rows"(){
when:
to OrdersPage
and:
ordersGrid.expandRow(0).click()
then:
ordersGrid.expandedForm.orderDetailsTab.details.size() == '3'
}



What are to OrdersPage and ordersGrid.expandedForm.orderDetailsTab.details.size() == '3' you would ask. This is Geb and it's page objects.
I think that i should not explain what all these tests are doing. I think the main question is how are they doing their stuff.

Here are top level steps that you should do in order to lunch your UI tests using grails.
  • add geb grails plugin
  • add spock-groovy grails plugin
  • add build-test-data grails plugin in order to generate your data for tests
  • Place your tests in test/functional source directory
  • use grails command test-app -functional
What is grails test-app -functional
Actually this is command for triggering functional test against grails web application. The life-cycle of grails functional test is straightforward:
  • Build grails application
  • deploy it in servlet container instance (Tomcat is used)
  • start web application in tomcat
  • run functional test against running grails application
  • shutdown web application and tomcat instance
You can configure grails functional test in Continuous Integration system.

TDD
 So tests are written and it's time for coding. But it's not really true. We need to generate data for our test and do it automatically for each test run and clean previous tests results.

Test data generation
Lets create grails controller which will be responsible for data generation. And thus we will be available to trigger it from browser to generate test data.
All controllers are placed in grails-app/controllers source folder. Also there is naming convention about controllers. Their class names should have Controller tail. For instance TestController. This class will be treated as controller class. Grails has a spring MVC under the hood.
So here is our controller with two closures for generating and deleting test data for our tests

class TestController {

def generateOrders = {
OrdersBuilder.build{
orders '000-00000-00', '000-00000-01', '000-00000-02', '000-00000-03'

Date now = new Date()
order('000-00000-00').hasType('Local Storage').and().hasOrderDate(now)
order('000-00000-01').hasType('Main Stoarage ').and().hasOrderDate(DateGroovyMethods.previous(now))
order('000-00000-02').hasType('Direct Move').and().hasOrderDate(DateGroovyMethods.previous(DateGroovyMethods.previous(now)))
order('000-00000-03').hasType('indirrect Move').and().hasOrderDate(DateGroovyMethods.previous(DateGroovyMethods.previous(DateGroovyMethods.previous(now))))
}.each {
it.value.save(flush:true)
}

render 'orders generated succesfully'
}

def deleteOrders = {

Orders.findAll().each { it.delete()  }
render 'orders deleted succesfully'
}
}

And it's available through URLs
and

I've used DSL technique (which i'll describe in my future posts) for generation data in order to be more readable by user. As a result of this DSL execution we will have 4 Orders with 000-00000-00 01 02 03 order numbers. Now the only thing we should do is to visit these URLs from our test to delete previous data and generate a new one. I will explain it later

Grails application can be run against several configured environments.  Functional Tests are run against grails executed with test env. You can configure several things under environments, but one of the main things is db configuration. Test env uses embedded in-memory hsql db by default. So all generated data will not affect your production data and will live in scope of running grails server for testing propose.


Coding
Now let's implement out inquiry page using grails and GWT. I won't explain how to do it. Just provide screenshots















































Geb
Geb is Groovy based web testing framework. It uses JQuery syntax, Page Objects pattern and groovy under the hood. All these 3 elements makes Geb extremely powerful DSL for web testing and even scraping web scripts.

Spock
Spock is groovy based highly expressive specification language. It allows you describe specifications by example very quickly using given when then (and it's modifications such as expect - where) notation.


Geb Spock Grails functional tests examples



Specification provided above will open page which is represented by OrdersPage Page Object. Static variable url in OrdersPage class is used for to method in specification. As a result orders page will be opened in configured browser.
The contents of the page is described with static content closure property. The notation of defining content is following:
"name" {"defenition"}
name is a reference to the content definition which can be used in specification.
If your pages are too complicated you should use Modules. So i decided to isolate Grid object in separate ExpandableGrid Module.
As a result we will have:

when:
to OrdersPage - opens http://localhost:8080/mcell-gui/ordersControl/orders url in configured browser
then:
assert ordersGrid.size == 4 Refers to ordersGrid content definition of OrdersPage and then to size definition of ExpandableGrid Module

As you can see from ExpandableGrid i defined all needed content for my tests using css selectors. Actually Geb uses css selectors for retrieving data from the DOM tree of the page.

Also you can inherit Modules and Pages. For example i have ExpandableGrid which contains simple Grid definitions plus expandable rows functionality. Let's refactor it:


class Grid extends Module{
def debugId
static content = {
grid {
$('div', id: "gwt-debug-${debugId}").find('.x-grid3-body')
}
rows{ grid.find('table[class*=row-table]') }
size{ rows.size() }
row{row-> rows[row] }
}
}


and 


class ExpandableGrid extends Grid{
static content = {
expandRow { row ->
grid.find('.x-grid3-row-expander')[row]
}
expandedForm{ module OrderForm}
}
}

Content information will be merged with Grid Module for ExpandableGrid


One more test description




I've added more Modules to represent Order Form and all tabs on it. Now i can straightforward DSL for my specifications


Driver configuration
More detailed driver configuration you can find on geb site. I've chosen ConfigSlurper mechanism:

waiting = { timeout = 2 }
driver = {
def driver = new FirefoxDriver()
}


Now my geb scenarios will work with firefox WebDrivers


That's all so far. i think it's time to deploy may app.







Thursday, August 11, 2011

Почему feature branches плохо.

читаю статью на http://habrahabr.ru/blogs/android/126082/ , вот выдержка

В прошлом году Google столкнулся с серьезной проблемой. Они хотели выпустить планшетную версию Android как можно быстрее, чтобы соревноваться с iPad от Apple, поэтому и разделили разработчиков на две группы. Одна часть занималась разработкой Gingerbread для смартфонов, а вторая разрабатывала Honeycomb для планшетов.

«Для того, чтобы успеть вовремя, мы пошли на компромиссы» — сказал Энди Рубин. «Мы даже не хотели задумываться, как запусть ту же самую версию (Honeycomb) на смартфонах. Это потребовало бы дополнительных ресурсов и задержало срок сверх разумного».

Поэтому Google и продолжил в том же стиле — дебютировал с Gingerbread на Nexus S в декабре, а версия Honeycomb появилась на Motorola Xoom в феврале. И с тех пор команда разработчиков Android прикладывает все возможные усилия для того, чтобы объединить эти ветви обратно в единое целое.
Goole пошел на компромиссы, я понимаю компромиссом тут является создание отдельной ветки для планшетов и все что из этого вытекает. Теперь нужно потратить много усилий чтобы все это смержить.  

Рассуждение о релизных циклах и методологиях ведения проектов


Если вы хотите быстро получить информацию о том какая методология используется в той или иной компании для ведения проектов спросите, "сколько у вас длиться релизный цикл?" ответом на этот вопрос может быть фраза от "1 день или неделя" до "1 год".
Так вот если ответом был первый то это скорее Agile методология, если второй то скорее всего традиционный подход.
Теперь подумаем что плохого в той или иной продолжительности циклов и стоит ли сразу переходить от одного к другому.
Сначала я встану на защиту традиционного подхода, хотя сразу оговорюсь - я не являюсь его поклонником. Итак релизный цикл 6 - 12 месяцев. Скорее всего процессы компании настроены таким образом, что требования подготавливаются перед началом цикла и заказчик ожидает получить новые фичи к концу. Заказчик готов к тому, что у него раз в год или полгода происходит обновления программного обеспечения и это его полностью удовлетворяет. Учитывая что релиз достаточно болезненное мероприятие как для компании разработчика так и для заказчика то, чем меньше их тем лучше для обоих :) поэтому некоторые стараются увеличить релизные циклы, однако с увеличением они становятся все сложнее и болезненней. Сокращение же релизного цикла приведет ко многим изменениям организации процессов начиная от IT департаментов заканчивая Sales и к этому нужно быть готовым. Кроме того Agile методология с её короткими релизными циклами лучше всего подходит к Software as a Service (SaaS), когда заказчик даже не подозревает, что на продакшен серверах происходит обновление программного обеспечения. Хотя вам ничего не мешает делать Private Releases.
Теперь поговорим о всем том плохом, что сопровождает длинные релизные циклы. Как правило при таком подходе 2/3 времени занимает разработка фичи, а остальное на её тестирование. Итак представьте что вы взяли в очередное релиз цикл 20 фич, при этом цикл у вас занимает 6 месяцев. 4 месяца разработка и 2 тестирование (автоматизированное, UAT и т.д.) Итак посчитаем сколько времени необходимо потратить чтобы фича прошла все стадии и была готова к релизу. 6 мес (24 недели) / 20 = 1.2 недели. округлим в большую сторону и получим 2 недели на одну фичу (это разработка и тестирование и выпуск её в релиз). Вместо этого заказчик её увидит через 6 месяцев эффективность можно посчитать 2/24 = 0.08 что составляет примерно 8 процентов.
Итак возникает вопрос, а стоит ли увеличивать релизные циклы и вечно бегать от страшного наказания под названием "релиз"? Что если наоборот уменьшать их? от полугодового перейти к поквартальному. От поквартального к ежемесячному и наконец к еженедельному и ежедневному, когда фичи поставляются как пирожки на конвейере. Да вам скорее придется обратиться в веру Agile, но подумайте над этим, стоит ли противиться этой новой вере?

Tuesday, July 26, 2011

Возрождение старого проекта

Давно я не писал.

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

И вот что пришло в мою светлую голову. Был когда то у меня проект на котором я собственно учился Java. Сейчас он даже в продакшене в конторе в которой я работал когда то. Я до сих пор с умилением и теплотой вспоминаю о том времени когда я над ним работал. И вот что собственно пришло мне в голову. А не восстановить ли в памяти все бизнес требования и переписать его под современный стэк технологий. В чем поинт спросят меня критики. Ну поинт первый - перестать сетям Мегамаркет делать кассу на бердичевском пиве, хоть оно и офигенно вкусное. Поинт второй - хоть проект на котором я работаю сейчас интересен с технологической точки зрения, но все как то дают нам задачи доделать, что то за ребятами из Лондона, а хочется с нуля, чтобы прочувствовать всю глубину глубин. Ну и наконец последнее хочется выкатить, что то свое и Open Source.

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

Теперь по стэку технологий
сейчас там используется J2SE 1.3, Swing, SWT (на клиентской части), hibernate, MS SQL, Maven

Хотелось бы
UI: GWT (JQuery) или какой то другой JS framework
Web framework: Grails и весь список фрэймворков под капотом
Server Side. Тут хочется использовать SOA архитектуру которая окутана чем то типа ServiceMix
DB layer: тут я уступаю достаточно в познаниях но я так понимаю, что или My SQL, или PostgreSQL, а может для производительности и NoSQL решение. Кроме того наверно какой нить распределенный кэшь хмм, может cassandra? пока незнаю

Tools
Git + GitHub
Maven, Ivy(для grails)
TeamCity а лучше Jenkins он open source
Sonar

Куда деплоиться? думаю на какой нить AWS или на какой нить кастомный сервачек.

Ну и наконец методологии буду(ем) если кто то присоединиться, придерживаться гибкой, это означает, что сейчас не будем делать архитектуру и дизайн, а потом как то перейдем к реализации. We will not build software we will grow it.

Ну вот как то так.

Monday, June 27, 2011

InfoQ: Collaboration Over Contracts in Agile “Offshore” Outsourced Development

Посмотрел давеча презентацию Craig Larman.
InfoQ: Collaboration Over Contracts in Agile “Offshore” Outsourced Development

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

Сюда вошли и общие принципы agile и сугубо технические вопросы и даже типы payment.
Передаю горячий привет своему Project Manager. Андрей судя по всему твоя роль весьма сомнительная. И даже страдает Transparency. Дело вот в чем, исходя из того что Feadback мы слышим от Customer не так часто, а если и слышим то в основном положительные отзывы, то у нас или все хорошо или не совсем так, но в это верится с трудом, потому что РМ иногда приходит и говорит, а что нужно сделать чтобы вы работали в 2 раза лучше :) Craig говорит, что РМа не должно быть как такового и налаживать отношение должен Product Owner (PO) непосредственно с командой.

Где то на 44 ой минуте Craig говорил о тестировании и Acceptance Tests. Тут мне вспомнилась полемика с моим предыдущим тимлидом. Он говорил о том, что acceptance tests слишком долгие и их тяжело поддерживать. Одним из аргументов было то, что они неправильно написаны, но как мне кажется все зависит от сложности flow и проекта в целом. Единственное в чем я твердо уверен, так это то, что они должны делаться и максимальное количество из них если не все должны быть автоматизированы. Spec by Example вам в помощь. В конце концов это подтверждение того что вы имплементировали именно то, что от вас хотел заказчик.

Хорошо что Craig затронул тему о передаче знаний (Knowlage transfer). Это очень важно для offshore teams. Следует взять на заметку Domain and Vision Workshops. Потому как офшорные команды должны разбираться в доменной области и видеть big picture, иначе они превращаются обезьянок за клавиатурой.

Очень понравилась рекомендация не навязывать дизайн и архитектуру со стороны onshore. Давать возможность офшорным командам самим принимать решения в этих вопросах, иначе это очень разочаровывает. Ведь на самом деле предотвратить проблемный дизайн можно всегда с помощью Code Review и Design Workshop.

Напоследок, хочу отметить что Craig Larman удивительно всесторонне развитый и терпеливый человек и действительно имеет право давать такого рода рекомендации и мастер классы. У него богатый опыт как в управлении процессами, так и в непосредственной разработке программного обеспечения. Я это могу утверждать на основании того, что сам с ним 2 дня сидел вместе в паре и TDDировал :)


Saturday, June 25, 2011

Ubuntu Natty Narwhal upgrade или как я провел сутки

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

Так вот, как видно из темы я решил заапгрейдится на более новую версию опреационки на Lenovo S12.

Сразу скажу, что у меня знаний в Linux администрировании на уровне пятиклассника.

Все шло хорошо, как по маслу пока не пришла пора перегружаться. Как оказалось после перезагрузки максимум что я увижу пустые обои на девственно чистом рабочем столе. Максимум что я мог делать это бездумно двигать курсором мыши елозя тачпад, менять рабочие зоны через Ctrl+Alt+PgDn|Up|Left|Right и наконец нажать на power увидеть чудо - диалог завершения работы ну собственно завершить работу или перегрузить это чудо.

Немного погуглив я напоролся на что то типа вот таких постов разочарованных пользователей :) Очень информативно. К сожалению дело уже было поздно вечером и я не мог четко сформировать запрос googлу, поэтому поиск затянулся, пока я не нашел вот этот пост. Это реально был кладезь информации по проблеме. В итоге я почти все перепробовал что предложил товарисч MAFoElffen.


Первое что меня обнадежило и не дало поднять белый флаг, это то что загрузка с LiveCD, происходит без потерь, кроме того мне удалось запуститься в recovery mode и увидеть Gnome Desktop (вместо Unity, которое в Ubuntu 11.04 по умолчанию).


Почитав дальше я понял что проблема с grub2 конфигурацией, и вообще с загрузчиком. Дело в том что когда-то давно когда я купил этот нетбук я поставил на него 3 операционки Ubuntu, Win7 и еще раз Ubuntu потому как не знал как вернуть загрузчик после того как его стерла Win7 :) (стыдно)


Загрузчик у меня был grub а не grub2, это я понял после того как начал применять инструкцию по восстановлению grub2 для своего grub. В итоге было решено сделать upgrade и загрузчику :) слава богу он прошел более не менее гладко благодаря вот этой статье, воспользовался я Boot-Repair тулзовиной.


Вернувшись к изначальной проблеме я начал пробовать разные варианты загрузки, манипулируя с linux boot line я пришел к выводу, работают 2 варианта
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash nomodeset"
и
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash i915.modeset=0 xforcevesa"
Прописав один из вариантов в /etc/default/grub, выполнив sudo grub-update, и перегрузившись я наконец увидел Gnome


Вот немного теории которую я вытянул по nomodeset из этого ресурса. Последние ядра взяли на себя ответственность за конфигурацию video, вместо того чтобы это делал драйвер X Server. Одной из причин по видимому является появившаяся возможность заранее инициировать видиокарту и тем самым обеспечить более представительный процесс загрузки.


Итак проблема пустого десктопа была решена и я уже было вздохнул с облегчением как обнаружил новую (_|_). Пропал Wireless. И снова google нам помог, правда не сразу. Материала по поводу проблем с wlan в Ubuntu Natty навалом, и опять же не все было применимо для моей конфигурации железа.


Вот ресурс и ресурс которые мне в итоге помогли.

Первое что нужно, так это избавиться от загрузки модуля acer_wmi. Для этого
sudo rmmod -f acer-wmi
sudo rfkill unblock all 
rfkill list all
при этом wireless LAN должен быть

Soft blocked: no
Hard blocked: no


к сожалению у меня этого не произошло. Я обнаружил что у меня загружено 2 Wireless модуля: первый ideapad-laptop, а второй собственно тот который нужен brcmwl. Дело в том что я этот драйвер предварительно установил из предложенных проприетарных драйверов от Broadcom. Грохаем ideapad-laptop
sudo rmmod -f ideapad-laptop
sudo rfkill unblock all 
rfkill list all 


после этого Network Manager магически ожил.

Теперь для того чтобы эти манипуляции не делать при каждой загрузке системы кладем все ненужные модули в blacklist
echo 'blacklist ideapad-laptop'  >> /etc/modprobe.d/blacklist.conf
echo 'blacklist acer-wmi'  >> /etc/modprobe.d/blacklist.conf

также добавим

rfkill unblock all в /etc/rc.conf перед exit 0

Если вы игрались с opensource драйверами то нужно их также выгрузить

sudo modprobe -r b43 ssb wl
sudo modprobe wl 

и убедиться что они в blacklist

вроде все.