<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4802694757293965538</id><updated>2012-02-12T13:11:59.929-08:00</updated><category term='qa-club'/><category term='logging'/><category term='zookeeper'/><category term='scala'/><category term='introduction'/><category term='java'/><category term='talk'/><category term='programming'/><category term='caliper'/><category term='junit'/><category term='devtime'/><category term='gwt'/><category term='code'/><category term='microbenchmarking'/><category term='distributed systems'/><category term='automation testing'/><title type='text'>Чудеса на виражах.. Плавно</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-3062328048639867499</id><published>2012-02-12T13:11:00.001-08:00</published><updated>2012-02-12T13:11:59.934-08:00</updated><title type='text'>Blog Relocated</title><content type='html'>Oops,Блог переехал. &lt;a href="http://mairbek.github.com/blog.html"&gt;http://mairbek.github.com/blog.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-3062328048639867499?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/3062328048639867499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2012/02/blog-relocated.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/3062328048639867499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/3062328048639867499'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2012/02/blog-relocated.html' title='Blog Relocated'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-9221052128291895692</id><published>2012-01-21T06:57:00.000-08:00</published><updated>2012-01-22T02:31:48.131-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><title type='text'>Logging Gotcha</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;Любое мало-мальски уважающее себя приложение не обходится без логгирования. Конечно, ведь иначе работа аппликухи в продакшне превращается в черный ящик.&lt;br /&gt;&lt;br /&gt;Современные библиотеки позволяют сохранять информацию на различных уровнях логгирования. В проектах, в которых я участвовал, обычно используется четыре уровня логгирования:&lt;br /&gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;i&gt;ERROR&lt;/i&gt; -- сюда выводится информация о критичных ошибках в системе.&lt;br /&gt;&lt;i&gt;WARN&lt;/i&gt; -- используется для вывода не критичных, но все же некорректных сиптомов неправльной работы приложения&lt;br /&gt;&lt;i&gt;INFO&lt;/i&gt; -- используется для вывода интересных событий происходлящих в системе&lt;br /&gt;&lt;i&gt;DEBUG&lt;/i&gt; -- детальныая информация о том, что происходит с системой. обычно используется при разработке либо при отладке.&lt;br /&gt;&lt;br /&gt;Обычно запись в лог выглядит довольно просто:&lt;br /&gt;&lt;script src="https://gist.github.com/1652978.js?file=logging.java"&gt;&lt;/script&gt;&lt;br /&gt;Уровни логгирования легко конфигурируются, так что мы можем наблюдать debug информацию при разработке и видеть чистый лог в продакшне.&lt;br /&gt;&lt;br /&gt;До сих пор, строки кода в open source библиотеках вида:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1652985.js?file=logging.java"&gt;&lt;/script&gt;&lt;br /&gt;вызывали недоумения: зачем это нужно, ведь запись в лог будет лишь при включенном дебаге, соответсвенно проверка влюченности дебага попахивает излишеством.&lt;br /&gt;&lt;br /&gt;Однако, недавно я обнаружил, что подход без использования проверки влюченности уровня логгирования несет недостатки о которых мне раньше не приходилось задумываться.&lt;br /&gt;&lt;br /&gt;Очень часто во время вывода в debug строки конкатенируются. И конкатенируются они независимо от того влючен дебаг или нет. Это во-первых приводит к тому, что создаются лишние строки что приводит к большим вызовам GC.&lt;br /&gt;Во-вторых, операция &lt;i&gt;toString&lt;/i&gt; может занимать продолжительное количество времени, и как показала недавняя история до 15% времени тормозящего метода.&lt;br /&gt;&lt;br /&gt;Получается писать проверку влюченности уровня необходимо. Но не удонбно. Количество строчек кода для записи в лог увеличивается в три раза.&lt;br /&gt;&lt;br /&gt;Однако, если в проекте используется библиотека логирования &lt;i&gt;slf4j&lt;/i&gt;, можно обойтись малой кровью используя шаблоны в строках. Как это работает:&lt;br /&gt;&lt;br /&gt;Вместо конкатенации строк при логировании&lt;br /&gt;&lt;script src="https://gist.github.com/1652985.js?file=oldstyle.java"&gt;&lt;/script&gt;&lt;br /&gt;писать&lt;br /&gt;&lt;script src="https://gist.github.com/1652985.js?file=newstyle.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-9221052128291895692?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/9221052128291895692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2012/01/logging-gotcha.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/9221052128291895692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/9221052128291895692'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2012/01/logging-gotcha.html' title='Logging Gotcha'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-5785471074471915501</id><published>2012-01-09T12:49:00.000-08:00</published><updated>2012-01-09T13:02:25.749-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='microbenchmarking'/><category scheme='http://www.blogger.com/atom/ns#' term='caliper'/><title type='text'>Microbenchmarking with Caliper</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;&lt;div class="p1"&gt;Бывает, что перед нами, разработчиками, возникает проблема выбора той или иной реализации алгоритма или структуры данных подходящей для решения текущей задачи.&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;div class="p1"&gt;Чаще всего, конечно, можно воспользоваться &lt;a href="http://google.com/"&gt;гуглом&lt;/a&gt;, задать вопрос на &lt;a href="http://stackoverflow.com/"&gt;stackoverflow&lt;/a&gt;, но в некоторых ситуациях ничего&amp;nbsp;не остается,&amp;nbsp;кроме как провести эксперименты самому.&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;div class="p1"&gt;Такая&amp;nbsp;инженерная практика именуется&amp;nbsp;&lt;i&gt;microbenchmarking&lt;/i&gt;. Суть микробенчмаркинга в измерении производительности (загрузки процессора, памяти или операций с сетью, диском) небольших кусков кода для того, чтобы понять какой код лучше подходит для текущего сценария.&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;div class="p1"&gt;Стоит заметить, что микробенчмаркинг и профайлинг -- это не одно и то же. Различия между ними напоминают различия между unit тестированием и интеграционным тестированием. Профайлинг подразумевает исследование производительности всего приложения в целом, тогда как микробенчмаркинг -- это, в свою очередь, исследование актуальной в данный момент функциональности.&amp;nbsp;&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;div class="p1"&gt;Зная что нужно измерять, написать бенчмарк довольно тривиально, и, часто, вполне можно обойтись одним единственным статическим методом main. Однако, используя фреймверк &lt;a href="http://code.google.com/p/caliper/"&gt;Caliper&lt;/a&gt; от компании Google, бенчмарки можно писать быстро и с удовольствием, выкинув при этом кучу boilerplate кода.&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;div class="p1"&gt;API &lt;i&gt;Caliper&lt;/i&gt;&amp;nbsp;в чем то напоминает старую версию &lt;i&gt;JUnit&lt;/i&gt;. Для того чтобы написать простой бенчмарк нужно:&lt;/div&gt;&lt;div class="p2"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Отнаследоваться от класса&amp;nbsp;&lt;i&gt;com.google.caliper.SimpleBenchmark&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Написать тестовые методы, название которых начинается со слова &lt;i&gt;time&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Подготовка данных и очистка ресурсов происходит в методах &lt;i&gt;setUp&lt;/i&gt; и &lt;i&gt;tearDown&lt;/i&gt; соответственно.&lt;/li&gt;&lt;/ol&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;div class="p1"&gt;Caliper изначально поставляется с большим количеством примеров. Один из интересных&amp;nbsp;&lt;i&gt;LoopingBackwardsBenchmark&lt;/i&gt;, который сравнивает скорость итерирования вперед и назад.&lt;/div&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1584321.js?file=gistfile1.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;div class="p1"&gt;Запустив тест мы убедимся, что разницы в производительности нет.&lt;/div&gt;&lt;div class="p2"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;Еще один пример. Допустим, мы разрабатываем функциональность которая предполагает огромное количество операций над дробными числами, и мы думаем стоит ли использовать&amp;nbsp;&lt;i&gt;BigDecimal &lt;/i&gt;или лучше остановить свой выбор на старом добром быстром &lt;i&gt;double&lt;/i&gt;. Сравнить насколько медленней будет работать &lt;i&gt;BigDecimal&lt;/i&gt; для такой операции как умножение не сложно.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;script src="https://gist.github.com/1584324.js?file=gistfile1.java"&gt;&lt;/script&gt;&lt;div class="p1"&gt;Прогнав тест, становится видно, что для небольших чисел и чисел с небольшой дробной частью &lt;i&gt;BigDecimal&lt;/i&gt; работает в &lt;i&gt;5&lt;/i&gt; раз медленней, а для больших чисел либо чисел с большим количеством символов после запятой в &lt;i&gt;20&lt;/i&gt; раз. &lt;/div&gt;&lt;br/&gt;&lt;div class="p1"&gt;Следует заметить, что &lt;i&gt;JVM&lt;/i&gt; хитрая штука, и постоянно занимается оптимизацией кода, что сказывается на результатах бенчмарка, по-этому иногда надо выкручиваться. Например, в бенчмарке &lt;i&gt;DoubleVsBigDecimalBenchmark&lt;/i&gt; используется массив и странный способ инициализации переменной &lt;i&gt;v&lt;/i&gt; нулем.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-5785471074471915501?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/5785471074471915501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2012/01/microbenchmarking-with-caliper.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/5785471074471915501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/5785471074471915501'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2012/01/microbenchmarking-with-caliper.html' title='Microbenchmarking with Caliper'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>1</thr:total><georss:featurename>Kharkiv, Kharkivs&amp;#39;ka oblast, Ukraine, 61000</georss:featurename><georss:point>49.9935 36.230383</georss:point><georss:box>49.830175499999996 35.914526 50.1568245 36.546240000000004</georss:box></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-1455885112463603762</id><published>2011-12-27T11:02:00.000-08:00</published><updated>2011-12-27T11:03:00.500-08:00</updated><title type='text'>Читая Practical Clojure</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;br /&gt;&lt;div class="p1"&gt;Объектно-ориентированный подход несомненно лучше процедурного, однако не лишен недостатков.&amp;nbsp;Цитата из &lt;a href="http://www.amazon.com/Practical-Clojure-Experts-Voice-Source/dp/1430272317"&gt;Practical Clojure&lt;/a&gt;:&lt;/div&gt;&lt;div class="p2"&gt;&lt;br /&gt;&lt;/div&gt;&lt;blockquote class="tr_bq"&gt;For the last decade, at least, the object-oriented style has dominated computer programming through its promises of data abstraction, code reuse, encapsulation, and modularity. It has delivered on these with varying levels of success, and is no doubt an improvement over the sequential or procedural styles that preceded it. But a number of problems have also become apparent:&lt;br /&gt;&lt;ul class="ul1"&gt;&lt;li class="li5"&gt;An object’s mutable state is unmanageable and dangerous in a highly concurrent environment.&lt;/li&gt;&lt;/ul&gt;&lt;ul class="ul1"&gt;&lt;li class="li5"&gt;It doesn't really solve the problems of code abstraction and modularization. It is just as easy to write over-dependent “spaghetti” code in an object-oriented language as any other. It still takes skill and special effort to write code that can truly be used without problems in a variety of environments.&lt;/li&gt;&lt;/ul&gt;&lt;ul class="ul1"&gt;&lt;li class="li5"&gt;Inheritance is fragile and can be dangerous. Increasingly, even experts in object- oriented languages are discouraging its use.&lt;/li&gt;&lt;/ul&gt;&lt;ul class="ul1"&gt;&lt;li class="li5"&gt;It encourages a high degree of ceremony and code bloat. Simple functionality in Java can require several interdependent classes. Efforts to reduce close coupling through techniques like dependency injection involve even more unnecessary interfaces, configuration files, and code generation. Most of the bulk of a program is not actual program code, but defining elaborate structures to support it.&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-1455885112463603762?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/1455885112463603762/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/12/practical-clojure.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/1455885112463603762'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/1455885112463603762'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/12/practical-clojure.html' title='Читая Practical Clojure'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-5865258594040472498</id><published>2011-10-24T08:47:00.000-07:00</published><updated>2011-10-24T08:47:35.950-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='zookeeper'/><category scheme='http://www.blogger.com/atom/ns#' term='devtime'/><category scheme='http://www.blogger.com/atom/ns#' term='talk'/><title type='text'>Hadoop Day at Dev Time</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;25 октября состоится &lt;b&gt;Hadoop Day&lt;/b&gt;&amp;nbsp;в рамках &lt;a href="http://dev-time.org/"&gt;Dev Time&lt;/a&gt;, где я буду выступать с докладом о &lt;a href="http://zookeeper.apache.org/"&gt;Apache Zookeeper&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-5865258594040472498?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/5865258594040472498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/10/hadoop-day-at-dev-time.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/5865258594040472498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/5865258594040472498'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/10/hadoop-day-at-dev-time.html' title='Hadoop Day at Dev Time'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-6832158509424467887</id><published>2011-05-27T02:17:00.000-07:00</published><updated>2011-05-27T02:36:12.980-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation testing'/><category scheme='http://www.blogger.com/atom/ns#' term='qa-club'/><title type='text'>QA-Club</title><content type='html'>Вчера прошел мой доклад в рамках QA-club. Спасибо организаторам за предоставленную возможность выступить. Итак все материалы по докладу:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Презентация&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.slideshare.net/mairbek/ss-7079843"&gt;slideshare&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Пример&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="https://github.com/mairbek/qa-club-demo"&gt;qa-club-demo&lt;/a&gt;&lt;/div&gt;&lt;div&gt;Для работы проекта необходима подтянуть следующие библиотеки &lt;a href="https://github.com/mairbek/ScalaMate"&gt;ScalaMate&lt;/a&gt; (позволяет использовать dependency injection в scala test), &lt;a href="https://github.com/mairbek/webelement-wrappers"&gt;webelement-wrappers&lt;/a&gt; (позволяет убодно работать с html элементами).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Ссылки для дальнейшего ознакомления&lt;/b&gt;&lt;/div&gt;&lt;div&gt;BDD:&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/Behavior_Driven_Development"&gt;wikipedia&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.scalatest.org/"&gt;scalatest&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://rspec.info/"&gt;rspec&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Dependency Injection:&lt;/div&gt;&lt;div&gt;Рекомендую посмотреть &lt;a href="http://www.youtube.com/watch?v=4E4672CS58Q"&gt;видео&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://code.google.com/p/guiceberry/"&gt;guiceberry&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Code Review&lt;/div&gt;&lt;div&gt;Удобная система для Code Review &lt;a href="http://code.google.com/p/rietveld/"&gt;rietveld&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://video.google.com/videoplay?docid=-8502904076440714866#"&gt;Видео&lt;/a&gt; от разработчика&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;DVCS&lt;/div&gt;&lt;div&gt;&lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&gt;http://nvie.com/posts/a-successful-git-branching-model/&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-6832158509424467887?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/6832158509424467887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/05/qa-club_27.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/6832158509424467887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/6832158509424467887'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/05/qa-club_27.html' title='QA-Club'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-8622827745383574159</id><published>2011-05-22T12:01:00.001-07:00</published><updated>2011-05-22T12:01:57.728-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='qa-club'/><category scheme='http://www.blogger.com/atom/ns#' term='talk'/><title type='text'>Мой доклад на qa-club</title><content type='html'>&lt;a href="http://www.qaclub.com.ua/node/126"&gt;http://www.qaclub.com.ua/node/126&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Приходите&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-8622827745383574159?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/8622827745383574159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/05/qa-club.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/8622827745383574159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/8622827745383574159'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/05/qa-club.html' title='Мой доклад на qa-club'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-452474583819590617</id><published>2011-05-14T08:57:00.000-07:00</published><updated>2011-05-27T02:14:40.267-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='gwt'/><title type='text'>To GWT or not to GWT</title><content type='html'>&lt;div&gt;Прошло время, когда web-разработка заключалась в обработке HTTP запросов и рендеринге соответсвующей html странички. Сейчас, куда не плюнь, везде требуется Rich UI. У java разработчика есть выбор: либо писать rich ui на javascript'e, либо воспользоватся GWT платформой, и писать на родимой жаве.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;В последнее время мне удалось поработать с GWT, итак за и против.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;За GWT:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. &lt;b&gt;Не нужно учить javascript.&lt;/b&gt; Если вы гуру и не одну собаку съели педаля на жабе и принципиально не хотите учить javascript, то gwt в самый раз.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2. &lt;b&gt;Все приимущества java.&lt;/b&gt; Статическая типизация, IDE, дебаггер, рефакторинги, анализаторы кода -- все к вашим услугам.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3. &lt;b&gt;Один код на сервере и на клиенте.&lt;/b&gt; Код написанный для сервера может быть скомпилирован в javascript и работать на клиенте.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;4. &lt;b&gt;Google.&lt;/b&gt; GWT разрабатывается, не командой волосатых программистов из гаража, а корпорацией google и используется в проектах компании.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;5. &lt;b&gt;Кросс-браузерность.&lt;/b&gt; Разрабатывая с помощью GWT можно не беспокоится про кросс-браузерность, клиент компилируется в поддерживаемый современными браузерами код.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Против GWT:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1. &lt;b&gt;Java == No fun.&lt;/b&gt; Писать на жаве UI неудобно. Количество строк кода в результате -- огромно.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;2. &lt;b&gt;Медленно.&lt;/b&gt; Скорость разработки на GWT на порядок меньше чем с помощью javascript'a. В большинстве из-за количества кода, которое приходится писать. Скорость работы GWT-овского компилятора уничтожает желание использовать GWT.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;3. &lt;b&gt;Отсутсвие подходов к написанию программ с помощью GWT.&lt;/b&gt; Best practices и подходы по написанию программ с помощью GWT постоянно меняются. RequestFactory и Activity Framework до сих пор сырые.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-452474583819590617?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/452474583819590617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/05/to-gwt-or-not-to-gwt.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/452474583819590617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/452474583819590617'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/05/to-gwt-or-not-to-gwt.html' title='To GWT or not to GWT'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-617668402206599003</id><published>2011-05-11T09:00:00.000-07:00</published><updated>2011-12-27T11:09:28.962-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='introduction'/><category scheme='http://www.blogger.com/atom/ns#' term='distributed systems'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='zookeeper'/><title type='text'>ZooKeeper Intro</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;Любое распределенное приложение не может обойтись без центрального сервиса, который координирует процессы в нем. Реализовывать координацию можно, однако разработка отказоустйчивой системы координации без deadlock'ов и race conditions -- задача не из тревиальных. Проект &lt;i&gt;Apache ZooKeeper&lt;/i&gt; призван избавить нас от решения этой проблемы.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;i&gt;ZooKeeper&lt;/i&gt; -- это распределенный, open-source сервис координнации для расспределенных приложений. Он предоставляет низкоуровневый API, с помощью которого приложения могут реализовать высокоуровневые сервисы для координации и синхронизации процессов в расспредеелнной системе. &lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;API &lt;i&gt;ZooKeeper'a&lt;/i&gt; черезвычайно прост. Распределенные процессы могут координироваться между собой с помощью расшаренной на всех клиентов иерархии znode'ов, организация которых по структуре похожа на файловую систему. Как и в файловой системе каждый &lt;i&gt;znode&lt;/i&gt; идентифицируется своим уникальным путем, вида &lt;i&gt;/node1/stuff/logs&lt;/i&gt;. В отличии от привычной файловой системы, каждый &lt;i&gt;znode&lt;/i&gt; может быть корневым узлом для других&lt;i&gt; znode'ов&lt;/i&gt;. Если говорить в терминах файловой системы: файл может выступать в роли директории. &lt;i&gt;Znode'ы&lt;/i&gt; версионируются и &lt;i&gt;ZooKeeper&lt;/i&gt; позволяет "смотреть"(&lt;i&gt;watch&lt;/i&gt;) за изменениями в ноде. Как только &lt;i&gt;znode'a&lt;/i&gt; изменяется, клиент, смотрящий за нодой, получает пакет, который говорит что в ноде произошло измение.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;i&gt;&lt;br class="Apple-interchange-newline" /&gt;ZooKeeper&lt;/i&gt;&amp;nbsp;реплицируемый и обрабатывает команды в строгой последовательности. Первое намного повышает его надежность, второе дает возможность пользователям разрабатывать примитивы синхронизации для распределенных систем. Все данные&amp;nbsp;&lt;i&gt;ZooKeeper&lt;/i&gt;&amp;nbsp;держит в памяти, что позволяет ему работать черезвычайно быстро.&amp;nbsp;Разработчики дауют нам следующие гарантии:&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;Sequential Consistency&lt;/i&gt; - Обновления от клиента будут применены в порядке в котором они были отправены&lt;/li&gt;&lt;li&gt;&lt;i&gt;Atomicity&lt;/i&gt; - Изменения от клиента атомарны, они либо исполняются либо нет&lt;/li&gt;&lt;li&gt;&lt;i&gt;Single System Image&lt;/i&gt; - Клиент получет одинаковый набор &lt;i&gt;znode&lt;/i&gt;'ов вне зависимости от того к какому серверу он подключен&lt;/li&gt;&lt;li&gt;&lt;i&gt;Reliability&lt;/i&gt; - Как только измение было применено, состояние будет неизменно до тех пор пока клиент не перетрет его&lt;/li&gt;&lt;li&gt;&lt;i&gt;Timeliness&lt;/i&gt; - Состояние системы для клиент гарантированно up-to-date с некоторой погрешностью по времени&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-617668402206599003?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/617668402206599003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/05/zookeeper.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/617668402206599003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/617668402206599003'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/05/zookeeper.html' title='ZooKeeper Intro'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-4679262901296866170</id><published>2011-05-04T14:26:00.000-07:00</published><updated>2011-05-04T14:31:25.058-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='scala'/><title type='text'>Почему Scala?</title><content type='html'>&lt;b&gt;Выразительный синтаксис&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Скала позволяет писать код без избыточных символов и дает возможность создавать DSL-подобный код: &lt;div&gt;&lt;ul&gt;&lt;li&gt;Необязательно ставить точки с запятой в конце строки&lt;/li&gt;&lt;li&gt;&lt;i&gt;object.doSomething()&lt;/i&gt; равнозначен &lt;i&gt;object doSomething()&lt;/i&gt; &lt;/li&gt;&lt;li&gt;Инфиксные операторы&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;Поддержка функционального программирования&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Scala предоставляет мощь объектно-ориентированного программирования, добавляя к нему изящные подходы из функционального&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Поддержка функций высокого порядка&lt;/li&gt;&lt;li&gt;Поддержка замыканий&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Улучшенное ООП&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Скала добовляет поддерживает ОО парадигму Java-мира, расширяя ее систему типов&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Trait (mixin) -- интерфейсы, которые могут включать логику и позволяют реализовать множественное наследование&lt;img src="http://www.blogger.com/img/blank.gif" alt="Bulleted List" border="0" class="gl_list_bullet" /&gt;&lt;/li&gt;&lt;li&gt;Case классы для быстрого создания value object'ов. В скале можно не писать getter'ов, setter'ов, equals и hashCode&lt;/li&gt;&lt;li&gt;Duck typing со статической типизацией&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-4679262901296866170?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/4679262901296866170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/05/why-scala.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/4679262901296866170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/4679262901296866170'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/05/why-scala.html' title='Почему Scala?'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-757257900326710464</id><published>2011-04-03T11:23:00.000-07:00</published><updated>2011-06-07T05:34:08.465-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation testing'/><title type='text'>Не бойтесть автомаизировать</title><content type='html'>Использование автоматизированных тестов на &lt;a href="http://seleniumhq.org/"&gt;selenium&lt;/a&gt; в качестве приемочных тестов становится распространненой тенденцией в индустрии разработки программного обеспечения. Об этом свидельствует успех прошедшей недавно конференции &lt;a href="http://seleniumcamp.com/"&gt;Selenium Camp&lt;/a&gt;, на которой Ваш покорный слуга выступал докладчиком. Отчасти этому способствует активная пропоганда от agile сообщества, отчасти наличием success stories от гигантов индустрии, таких как, например, &lt;a href="http://googletesting.blogspot.com/"&gt;Google&lt;/a&gt;, который является главным конрибьютером в новую, вторую, версию селениума.&lt;br /&gt;&lt;br /&gt;Однако, нужны ли нам автоматизированные тесты, если у нас в команде есть группа тестировщиков или QA-инженеров, способных обеспечить качество проекта на должном уровне? Я считаю, что автоматизированные тесты дополняют QA-инжеров, избавляя их от ненужной рутинной работы. Зачем тратить время на регрессию, если ее может сделать за тебя компьютер?&lt;br /&gt;&lt;br /&gt;К тому же тесты гарантируют, что ошибка не повторится вновь, а если и повторится, команда узнает о ней в скором времени. При этом разрабочики могут безболезненно вносить изменения в существующий код и добавлять новые фичи, зная что поломка может быть выявлена на этапе разработки. В то же время QA-инженер может занятся более интересными вещами, такими как usability, security тестирование, и поиск хитрых, заковыристых багов.&lt;br /&gt;&lt;br /&gt;Однако у тестов есть свои недостатки. Прежде всего, их нужно кому-то писать. Т.е. если у нас в команде нет людей, знакомых с автоматизацией, то нужно либо дать им возможность ошибаться и научиться, либо искать экспертов на стороне. Так же тесты требуют настройки инфраструктуры. Настройка билд конфигурации, развертывание серверов для запуска тестов и параллельный запуск тестов могут оказаться нетривиальными и потребовать времени и усилий.&lt;br /&gt;&lt;br /&gt;Нужно понимать, что тесты, как и любой код другой код требуют поддержки. Если у нас в приложении изменилась функциональность, то в тесты на эту функциональность придется вносить изменения, а возможно даже и переписывать.&lt;br /&gt;&lt;br /&gt;Несмотря на недостатки тестов, если удастся взрастить команду, которая может успешно автоматизировать приемочное тестирование, это будет выгодно всем. Бизнес получает более качественный продукт в меньшие сроки, сотрудники же занимаются интересными вещами, траятя свое время эффективно.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-757257900326710464?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/757257900326710464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/04/blog-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/757257900326710464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/757257900326710464'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/04/blog-post.html' title='Не бойтесть автомаизировать'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4802694757293965538.post-2810370113431005523</id><published>2011-03-23T04:38:00.000-07:00</published><updated>2011-05-05T03:07:43.525-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='automation testing'/><category scheme='http://www.blogger.com/atom/ns#' term='junit'/><title type='text'>Новинки JUnit. Категории</title><content type='html'>&lt;div&gt;&lt;div&gt;В последнее время во всех проектах где я принимаю участие не обходится без автоматизированного тестирования. Везде есть unit тесты, плюс разработку часто сопровождают попытки покрыть код тестами на Selenium.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Первый вопрос который стоит перед командой при написании автоматизированных тестов -- как мы будем запускать тесты? Точнее -- какой фреймворк для тестирования нам выбрать? Если мы программируем на Java, выбор не велик. JUnit или TestNG.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Помню, когда мы начинали заниматься функциональными тестами на нашем последнем проекте, мы долго решали что же выбрать. Победил TestNG. Легкость создания test suit'a, возможность группировать тесты и запускать их параллельно -- вот что определило наш выбор. В тот момент я подписался на интересные блоги и рассылки связанные с тестированием, и через некоторое время обнаружил, что JUnit активно развивается и догоняет TestNG по функциональности, при этом превосходит его в продуманности API.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Так, в JUnit начиная с версии 4.8 появился механизм для метки и группировки тестов, под названием Categories. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Процесс группировки тестов в JUnit до появления категорий можно стравнить с организацией писем в Microsoft Outlook. Мы можем группировать тест методы в классы, а классы в пакеты.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Теперь, с помощью категорий, группировка тестов похожа на группировку писем в GMail.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Представляются категории в виде java интерфейсов, что дает приемущества по сравнению с группами в TestNG. В отличии от строковых констант коими являются группы, мы можем переименовывать категории в IDE, &lt;/span&gt; плюс есть возможность построить йерархии категорий, что дает нам гибкость в организации тестов.&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Предположим, что у нас есть 4 категории: SmokeTest говорит что наш тест - смоук тест, BrokenTest показывает, что тест тестирует поломанный функционал, а с помощью FastTest и SlowTest мы помечаем тесты по времени выполнения.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;public interface SmokeTest {}&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;public interface BrokenTest {}&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;public interface FastTest {}&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;public interface SlowTest {}&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Допустим у нас есть два тест класса с помеченными методами:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;@Category(SmokeTest.class)&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;public class SomeSmokeTests {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;@Test&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;@Category(FastTest.class)&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;public void someFastTest() {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;  &lt;/span&gt;// test something&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;    &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Category(SlowTest.class)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public void someReallySlowTest() {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;    &lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// test something    &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;public class SomeTestCase {&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Test&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Category({SmokeTest.class, FastTest.class})&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public void fastSmokeTest() {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;span class="Apple-tab-span"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt;  &lt;/span&gt;&lt;/span&gt;// test something&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Test&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Category({SmokeTest.class, FastTest.class, BrokenTest.class})&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public void fastBrokenSmokeTest() {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;// test something&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;i&gt; &lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;/span&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Test&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;@Category({SmokeTest.class, SlowTest.class})&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public void slowSmokeTest() {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;    &lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;// test something&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;С помощью категорий мы можем построить test suite, который будет запускать быстрые smoke тесты с работающим функционалом:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;@RunWith(Categories.class)&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;@IncludeCategory(SmokeTest.class, FastTest.class)&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;@ExcludeCategory(BrokenTest.class)&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;@SuiteClasses(SomeSmokeTests.class, SomeTestCase.class)&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;public class RunFastSmokeTestCases {}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Правда, с увеличением количества классов в suite, конфигурация получаеться громоздкой, а куча аннотаций никак не добавляет читабельности коду.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;К счастью эта проблема решается с помощью библиотеки &lt;a href="http://github.com/mairbek/junit-suite-configurator"&gt;junit-suite-configurator&lt;/a&gt;. Так выглядит конфигурация эта же конфигурация написанная с ее помощью:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;@RunWith(Suite.Configuration.class)&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;public class Suite {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;public static class Configuration extends AbstractConfiguration {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt; &lt;/span&gt;public Configuration(Class&lt;!--?--&gt; testClass) {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;super(testClass);&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt; &lt;/span&gt;@Override&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;protected void configure() {&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;run(classes(SomeSmokeTests.class, SomeTestCase.class))&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;.filter(includeCategories(SmokeTest.class, FastTest.class))&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;    &lt;/span&gt;.filter(excludeCategories(BrokenTest.class))&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;&lt;span class="Apple-tab-span" style="white-space: pre; "&gt; &lt;/span&gt;   &lt;/span&gt;.applyRule(new Rule1())&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;   &lt;/span&gt;).invokeIn(singleThread());&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;i&gt;}&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4802694757293965538-2810370113431005523?l=khadikov.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://khadikov.blogspot.com/feeds/2810370113431005523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://khadikov.blogspot.com/2011/03/junit.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/2810370113431005523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4802694757293965538/posts/default/2810370113431005523'/><link rel='alternate' type='text/html' href='http://khadikov.blogspot.com/2011/03/junit.html' title='Новинки JUnit. Категории'/><author><name>Mairbek Khadikov</name><uri>http://www.blogger.com/profile/03268698527520280016</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://farm2.static.flickr.com/1338/1477336373_157bac9f62.jpg?v=0'/></author><thr:total>2</thr:total></entry></feed>
