Если нельзя, но очень хочется, то нужно обязательно и ничего в мире не стоит того, чтобы делать из этого проблему!


Интересна Java? Кликай по ссылке и регистрируйся!
Если тебе полезно что-то из того, чем я делюсь в своем блоге - можешь поделиться своими деньгами со мной.
с пожеланием
столько времени читатели провели на блоге - 
сейчас онлайн - 

понедельник, 23 мая 2011 г.

Рефакторинг: Замена рекурсии делегированием. Часть 1

Часто сталкиваюсь с проблемой, когда процедурный стиль программирования тянется в OOP код. Вот интерфейс бинарного дерева: добавили ноды, померяли глубину самого глубокого листика, напечатали на экране - все просто.



package com.binarytree;

public interface Node {

    int getMaxLeafDepth();

    void addValue(int value);

    String toString();

}

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

package com.binarytree.procedure;

import com.binarytree.Node;

public class ProcedureRecursionTree implements Node {

    private NodeElement root;

    public ProcedureRecursionTree(int rootValue) {
        root = new NodeElement(rootValue);
    }

    @Override
    public void addValue(int newValue) {
        addValue(root, newValue);
    }

    private void addValue(NodeElement node, int newValue) {
        if (newValue < node.value) {
            node.left = addTo(node.left, newValue);
        } else if (node.value < newValue) {
            node.right = addTo(node.right, newValue);
        }
    }

    private NodeElement addTo(NodeElement node, int newValue) {
        if (node != null) {
            addValue(node, newValue);
            return node;
        } else {
            return new NodeElement(newValue);
        }
    }

    @Override
    public int getMaxLeafDepth() {
        return getMaxLeafDepthFrom(0, root);
    }

    private int getMaxLeafDepthFrom(int depth, NodeElement node) {
        if (node == null) {
            return depth;
        }

        return 1 + Math.max(getMaxLeafDepthFrom(depth, node.left), 
                getMaxLeafDepthFrom(depth, node.right));
    }

    @Override
    public String toString() {
        return toString(root);
    }

    private String toStringSubnode(NodeElement node) {
        if (node != null) {
            return toString(node);
        }
        return null;
    }

    private String toString(NodeElement node) {
        return String.format("(%s, %s, %s)", 
            node.value, 
            toStringSubnode(node.left), 
            toStringSubnode(node.right));
    }

}
Это класс, в котором хранятся данные
package com.binarytree.procedure;

public class NodeElement {

    int value;
    int parentNodeValue;
    NodeElement left;
    NodeElement right;

    public NodeElement(int value) {
        this.value = value; 
    }

}
Ну и? Все нормально на первый взгляд. Методы маленькие, дублирования нет, все вполне читабельно. Да, но тут код пахнет другим - класс ProcedureRecursionTree инкапсулируя NodeElement root рекурсивно проходится по всем дочерним узлам/листьям root ноды. Это удобно - все ноды одного типа. Но это не по OOP. Правило простое.

Метод объекта должен работать только с полями своего объекта, иначе метод должен быть перемещен в тот объект, чьи данные использует интенсивнее всего. Если же данные не возможно расширить новым методом, тогда создается новый класс, их инкапсулирующий (или наследующий - что применимее), с последующим переносом в него исходного метода.

Вот этой задачкой я и предлагаю заняться. Рефакторинг, как оказалось недавно, в более широком виде, Фаулеровский и называется "Преобразования процедурного проекта в объекты (Convert Procedural Design to Objects)", я же его раньше называл "замена рекурсии делегированием".

Вывод пока напрашивается громкий - там где OOP там не должно быть рекурсии с передачей данных.

Вот кстати тест:
package com.binarytree;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import com.binarytree.Node;

public  class TreeTest {
    
    Node createNode(int rootValue) {
        return new ProcedureRecursionTree(rootValue);
 }
    
    @Test
    public void testAddLeftToRoot() {
        Node node = createNode(5);
        node.addValue(4);
        
        assertEquals("(5, (4, null, null), null)", node.toString());
    }
    
    @Test
    public void testAddRightToRoot() {
        Node node = createNode(5);
        node.addValue(6);
        node.addValue(4);
        
        assertEquals("(5, (4, null, null), (6, null, null))", node.toString());
    }
    
    @Test
    public void testStartSecondLevel() {
        Node node = createNode(5);
        node.addValue(6);
        node.addValue(12);
        node.addValue(3);
        
        assertEquals("(5, (3, null, null), " +
                          "(6, null, (12, null, null)))", node.toString());
    }
    
    @Test
    public void testGetDepthFrom3LevelOnlyRightTree() {
        Node node = createNode(5);
        node.addValue(6);
        node.addValue(12);
        
        assertEquals(3, node.getMaxLeafDepth());
        assertEquals("(5, null, (6, null, (12, null, null)))", 
                node.toString());        
    }
    
    @Test
    public void testGetDepthFrom3LevelLeftRightTree() {
        Node node = createNode(5);
        node.addValue(1);
        node.addValue(2);
        
        assertEquals(3, node.getMaxLeafDepth());
        assertEquals("(5, (1, null, (2, null, null)), null)", 
                node.toString());        
    }
    
    @Test
    public void testGetDepthFrom4LevelleftRightTree() {
        Node node = createNode(5);
        node.addValue(6);
        node.addValue(12);
        node.addValue(16);
        node.addValue(3);
        node.addValue(1);
        node.addValue(0);    
        
        assertEquals(4, node.getMaxLeafDepth());
        assertEquals("(5, (3, (1, (0, null, null), null), null), " +
                         "(6, null, (12, null, (16, null, null))))", 
                node.toString());        
    }
    
    @Test
    public void testGetDepthFrom5LevelTree() {
        Node node = createNode(5);
        node.addValue(4);
        node.addValue(6);
        node.addValue(3);
        node.addValue(7);
        node.addValue(2);
        node.addValue(8);
        node.addValue(1);    
        node.addValue(9);
        
        assertEquals(5, node.getMaxLeafDepth());
        assertEquals("(5, (4, (3, (2, (1, null, null), null), null), null), " +
                         "(6, null, (7, null, (8, null, (9, null, null)))))", 
                node.toString());        
    }

}
Приятного аппетита. Продолжение следует.

воскресенье, 22 мая 2011 г.

Я и мой джин, или как было придумано название книги

"В соответствии с ГОСТ 7.60-2003 альманах — сборник, содержащий литературно-художественные и (или) научно-популярные произведения, объединенные по определенному признаку."

Когда я спросил себя, как я хочу назвать свою книгу мне вспомнился фильм "Назад в будущее", во второй части которого Марти приходит мысль немного подзаработать а ставках спортивных состязаний, и он покупает «Спортивный Альманах Грейс» — брошюру, в которой напечатаны все результаты спортивных состязаний с 1950 по 2000 годы.

Часто пользуюсь этой способностью своего мозга. Хоть мне не понятно, как это работает на самом деле - для себя и друзей я придумал одну байку. Звучит она так.

Мозг - это записывающее устройство, которое, подробнейшим образом, пишет все то, что когда либо с тобой случалось от момента его появления. Если тебе сейчас 25 лет, то это 220 000 часов записи мастер класса "Моя Жизнь". Этот опыт доступен одновременно и уже незамедлительно может быть использован. Прямо сейчас. Вопрос в том, как это сделать и чем это может помочь?

Все просто - задай себе прямо сейчас вопрос, любой вопрос. Для верности задай его вслух или напиши на бумаге. Задал? Ничего не произошло? Произошло, но ты не не обратил внимание, потому как то, на что надо было обратить внимание настолько привычно, что не воспринимается всерьез.

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

Ну что? Задал? Наверное, ничего особенного не произошло. Все как-то обычно. Поток мыслей такой же, как и в любое другое время - только я перестаю думать что-то одно в голове появляется что-то другое. Достаточно сложно сознательно остановить мысль и потому чаще всего этим никто не занимается. Посмотри на людей в метро, троллейбусе, когда они едут с работы домой - они либо слушают свое внутреннее радио либо сами там вещают. Обычный процесс.

В какой-то момент я решил использовать это радио. Я вдруг осознал, что раз уж я генерирую этот весь эфир, значит там может быть что-то полезное. И стал экспериментировать. Было замечено, что переключение радиостанции происходит всякий раз, когда я сознательно что-то запускаю в эфир. Чаще всего это утверждение произнесенное "про себя". Но так же хорошо переключают каналы и внешние раздражители, полученные в любой форме: свет, звук, запах, тепло, прикосновения, удар, вкус, боль.

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

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

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

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

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

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

Этот джин отвечает не сразу а в течении дня, а может и недели. Иногда джин говорит не связно или вообще не говорит, а сразу после вопроса показывает картинки, включает музыку, напоминает о каком-то событии из прошлого. Если не проморгать и поймать этот ответ, то можно задаться вопросом "а чем мне может помочь ЭТО в поиске ответа на мой вопрос?". После наводящего вопроса картина проясняется (но опять же не всегда словесно и не всегда сразу).

Пример, как это было с названием книги. Задал вопрос "как мне назвать книгу?". Получил ответ в виде воспоминания об альманахе из фильма назад в будущее. Скажу честно, многие слова русского языка я использую интуитивно, но если стоит разобраться в значении того или иного слова - я пользуюсь Википедией. "Альманах" - это как раз тот случай. Вот я и решил узнать, что это слово значит. Википедия мне ответила, что это тематический сборник за определенный период времени (чаще год). Любопытно то, что формат моей книги (когда я с джином его придумал) - подборка всевозможных рецептов, которые собирались на протяжении 6 последних лет, пока я трудился в сфере разработки программного обеспечения. Вот так то.

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

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

А ты спроси.

вторник, 17 мая 2011 г.

Test Driven Development: TDD мантра

В TDD ты перестаешь быть причиной своим действиям - ты зависим от внешних сигналов.

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

Когда загорелся зеленый - ты думаешь как бы сохраниться и навести марафет.

Когда горят несколько красных - ты думаешь, как бы откатиться.

Все что по привычке придумывается в процессе - выносится в список "на как-нибудь потом".

Когда все готово - думаешь, что бы взять попроще из списка. Тут все начинается опять.

Период такой итерации - 15 минут. Никаких DEBUG по пути.

Страшно быть не должно. Не делай того, за что беспокоишься. А если беспокойство само собой возникло - пиши тесты.

Если тест мешает - подумай, как от него избавиться. Но если страшно - напиши другой тест.

суббота, 14 мая 2011 г.

Майский сплав на Черемоше

Фотик с собой в воду не брал, т.к. боялся утопить. Но фотки все же есть - первый день мы походничали в горы. Тут я хотел бы поделиться своими панорамками.

Это мой телефон как-то при зуме добавляет эффекту. Прикольно.








Верховина, вид сверху.













Закат





Наша команда








Красивые горы




А вот и "крутилка" (она большая, а потому для загрузки нажми тут...)

How to: Как скачать музыку из В контактах?

Пост актуален для тех, у кого есть Firebug под Firefox. На крайний случай его можно скачать и поставить за минуту. Качаем тут.

Для начала надо открыть firebug и активизировать в нем панельку "сеть"


Потом запустить песенку проигрываться (она тем временем начнет качаться) и проследить какой из запросов от твоего браузера получил самый жирный ответ - это и будет песенка. Остается только скопировать линк и закачать повторно.

Дело в том, что от этой тулзы очень сложно что либо скрыть - она тупо показывает что ушло от браузера и что пришло обратно как ответ.

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

Кто-то возразит - так есть же качалки и будет прав. Да есть. Но мне их качать надо, а firebug под боком. К тому же нет универсальной качалки. А firebug вроде как универсален.

Подборка #50

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

Часами могу так брынчать. Правильно или нет вовсе не важно. Мне нравится процесс заучивания - сегодня еще ничего не получается, кажется, моцк дубовый, а уже завтра то же делать становится легче, после завтра еще легче, а через неделю и вовсе не задумываешься. Раньше я думал, а как это пианист может сесть и сыграть любую песенку? Ответ прост - он долго-долго ее заучивал...

...Бросаем курить с андроидом

...А вот и Библия для Android на русском языке...

...Манифест, блять!...

...Реверс-инжиниринг android приложений...

Мультик про эксгибиционизм




Прочитал такие статьи по тайменеджменту:
Как сократить рабочую неделю втрое?
Как распределить дела в течение дня?
Приоритеты в жизни
Как стать жаворонком
Как побороть лень?
Как найти время на себя?
Что крадет наше время
Так много нужно сделать и так мало времени (Брайан Трейси)
ну и конечно же еще раз перечитал про
Что делать, если тайм менеджмент вам не помогает?
Можно ли успешно жить и работать, не зная понятий тайм менеджмент и само мотивация?
На одном дыхании прочитал!

Представь, что существует банк, который каждое утро кладет на твой счет 86,400 руб. Он не хранит ежедневный остаток.
Каждую ночь он приравнивает к нулю весь остаток до последней копейки, который ты не использовал в течение дня.
Что ты сделаешь? Конечно, ты будешь снимать каждый день все до последней копейки!
Знайте: у каждого из нас есть счет в этом банке. Его название? ВРЕМЯ.
Каждое утро этот банк начисляет тебе 86.400 секунд.
Каждую ночь этот банк стирает данные, и смотрит, какую часть этого кредита ты не инвестировал в нужных целях.
Этот банк не хранит денег и не позволяет переводить их на другие счета. Каждый день открывается новый счет.
Каждую ночь аннулируется остаток за день. Если ты не используешь эти деньги — теряешь только ты.
Мы не можем вернуться назад или позаимствовать завтрашний кредит. Ты должен жить в настоящем на то, что тебе дано сегодня.
Инвестируй так, чтобы достигнуть большего в здоровье, в счастье, в успехе.
Часовая стрелка продолжает описывать дугу. Достигни максимума за день.
*** Чтобы оценить по достоинству год, спроси об этом у студента, который потерял год учебы.
*** Чтобы понять ценность месяца, спроси об этом у матери, которая родила преждевременно.
*** Чтобы понять ценность недели, спроси об этом издателя еженедельного журнала.
*** Чтобы понять ценность часа, спроси об этом у двух влюбленных, которые ждут встречи.
*** Чтобы понять ценность минуты, спроси об этом человека, только что опоздавшего на поезд.
*** Чтобы понять ценность секунды, спроси об этом человека, только что избежавшего автокатастрофы.
*** Чтобы оценить по достоинству тысячную долю секунды, спроси об этом у атлета, выигравшего серебро на Олимпийских играх.
Оценивай по достоинству каждый момент, которым ты живешь, и придай ему еще большую значимость,
разделив его с особенным человеком настолько особенным, чтобы посвятить ему твое ВРЕМЯ.
И помни: ВРЕМЯ никого не ждет!

...Крастота




...Полезен тот код, который делает счастливым заказчика. Лучший тот код, который делает заказчика счастливым с помощью меньшего числа строк. Идеальный тот код, который так и не написан (но заказчик при этом доволен)...

...Пару фидбеков мне от http://drimtim.ru

Интернет. Кто вы в сети?
Ваша роль в интернете— Интернет-инноватор.

Я любитель всего нового, что происходит в интернете. Мне нравится пробовать новые «фишки»: лет 8 назад я был фанатом «Живого журнала», в 2005-м – осваивал социальные сети, а сегодня – обожаю twitter, интернет-карты и мобильные сети.
Для меня важна не конкретная идея, а сам принцип новизны. Я в курсе самых свежих «движух» в интернете. Я отлично знаю смысл модных словечек, так что друзья всегда могут спросить меня, что такое микроблоггинг, геотэггинг или юзабилити. Мое призвание в интернете – «пионерить» новые сервисы...

Мой темперамент
— Шторм.

Я энергичный, активный, любящий соревноваться человек. Я получаю полноценное удовольствие от жизни, когда чувствую ее динамику, активно действую, направляю обстоятельства в нужное мне русло, достигаю результатов, успешен и нравлюсь окружающим.
развернуть скрыть
Для меня характерны:
* Высокая деловая активность, увлеченность работой, целеустремленность.
* Способность быстро принимать решения.
* Активный стиль отдыха.
* Эмоционально насыщенная жизнь, честолюбие, стремление к успеху и лидерству, постоянное желание улучшить результаты сделанной работы.
* Чувствительность к похвале и критике.
* Стремление к соперничеству, к конкуренции, соревнованию.
* Вспыльчивость, неуравновешенность в ситуациях с высоким уровнем стресса.

Моя гибкость и отзывчивость.
Филантроп.

Я верю, что отношения должны строиться на желании помогать другим, поддерживать их, и поэтому я охотно делюсь тем, что у меня есть. Благодаря признанию высокой ценности партнерских отношений я вкладываюсь в отношения первым. Я внимательно отношусь к партнеру и его потребностям. Мой стиль поведения и манеры изменяются в зависимости от ожиданий партнера. Моя удовлетворенность отношениями зависит от того, насколько достигается взаимопонимание и близость в партнерстве. При этом предметное содержание совместно проведенного времени отходит на второй план.
Сильные стороны моего стиля взаимоотношений в партнерстве:
* Мне свойственно подстраиваться под другого человека, разделять его интересы, следовать за своим партнером и при этом получать искреннюю радость от общения.
* Я умею чувствовать и предугадывать желания партнера, испытывать искреннюю радость, когда партнер благодарен мне за поддержку.
* Я умею поддержать партнера добрым словом и порой очень ценным советом, особенно в области человеческих взаимоотношений.
* Я умею обойти или сгладить шероховатости в отношениях с категорично настроенными людьми.
Слабые стороны моего стиля взаимоотношений:
* У меня есть склонность отодвигать свои интересы и потребности на второй план. Это может приводить к накоплению чувства неудовлетворенности и в итоге – к эмоциональным срывам и депрессивным состояниям.
* Если я не получаю одобрения со стороны партнера, то редко испытываю удовлетворение от того, что делаю.
* Предугадывая желания партнера, стремясь разделить с ним его интересы, я порой произвожу впечатление не в меру навязчивого человека, ограничивающего свободу своего партнера.
* В компании нескольких поспоривших друзей я могу «потеряться», не зная, какую позицию мне занять.

Особенности стиля общения.
— Панда.

Я с удовольствием вступаю в контакты с людьми и формирую партнерские отношения, не являясь при этом фанатом общения. Я умею общаться как с равными себе по положению и уровню развития людьми, так и с людьми более высокого или низкого социального статуса. Я стремлюсь подбирать подходящие для каждой конкретной ситуации формы общения и устанавливать комфортную для себя дистанцию.
Мои сильные стороны:
* Я умею как получать удовольствие от общения, так и дарить его другим.
* Я могу быть в равной степени и слушающим, и рассказывающим – все зависит от ситуации.
* Обычно я достаточно чутко отношусь как к себе, так и к партнеру для того, чтобы выбирать подходящий для каждой конкретной ситуации стиль общения. Я могу даже отказаться от общения, если настроение или обстановка к этому не располагают.
Мои слабые стороны:
* Я излишне строго отношусь к себе при завязывании новых знакомств, тем самым скрывая от потенциального партнера свои сильные стороны.
* Нередки ситуации, где я теряю инициативу в общении и больше рассчитываю на собеседника, чем на себя.

Нормальный сайтик...

...Вчера по телику решил посмотреть новости. Показывали пидпыздэсь. Это полный пидпыздэсь. Читаем, смотрим тут...

...Хорошая реклама...