...сегодня утро начал с интересного видео, показывающего какие мы все таки микробики в этой игре жизни:
Тем не менее многие из нас (по умолчанию) думают, что являются центром вселенной (я не исключение)...Читать дальше...
...Java Sun для настоящих мужчин.
Интересно? Идем сюда...
...
- Я забыл как тот график называется....
- Burn Down Chart. Горящий вниз график. Сразу ничего не получится, красная линия - это идеальный случай. Думаешь у меня все получается гладко?
- Ну если ты про меня - то нет)
- Хотя бы это. Я вообще-то имел ввиду свой основной проект, пленнинг, баги, эстимейты, фичи, заказчики...
- Там много того что от тебя не всегда зависит.
- Но чем больше опыта, тем легче с этим управляться. Если от тебя не зависит, упадет ли рядом стоящий тополь на машину, оставленную на парковке или нет, то со временем понимаешь, что именно от тебя зависит будет ли стоять твоя машина на этой парковке под тополем в грозу. Чья-то машина все равно пострадает.
- Да это опыт.
- Радуйся каждой шишке. Чем больше таких шишек будет на твоем теле, тем более ценный ты сотрудник.
...а вот какие каракули да Винчи я сегодня намалевал.
Они мне помогли в решении одной задачи, правда пришлось втыкать в них минут 15. Кто не в курсе, идем сюда...
...иногда на собеседованиях предлагают откомпилировать на бумажке код ("посмотрите на этот код - он откомпилируется или нет?"), на что так и хочется спросить "а вы часто имеете дело с J2EE в блокноте?". Как ни крути IDE ускоряет но деградирует.
А еще на множество вопросов просто не знаешь ответа, и говоришь ведь "я бы написал красный тест; после методом try-error + google driven development заставил бы его позеленеть; ну а после был бы рефакторинг или пометка TODO, с добавлением issue в issue tracking system; а спустя некоторое время либо нашлось бы решение, либо появился бы в поле зрения техлид" Кто-то ведет разработку иначе?
И ведь, спрашивают постоянно про потоки! Хоть бы кто-то потом дал возможность с этими самыми потоками на практике поиметь дело. Потому я уже прочно говорю - потоков не знаю, дела не имел. Надо будет - разберусь.
А еще любимый вопрос: какова корреляция между hashcode и методом equals. Во какая. А можно ответить "я знаю ответ, но мы никогда не использовали свои объекты в качестве ключей, и все же я бы использовал HashCodeBuilder и EqualsBuilder от ApacheCommons". Этого более чем достаточно. Но если любопытно, можно узнать как реализован HashMap и понять на кой ему hashCode объекта. Вообще-то поиск вначале проводится по хеш-значению (которое формируется на основе hashCode), а потом уже из отобранных объектов - по equals. В итоге, без правильной реализации hashCode более вероятно, что он (метод get) просто ничего не найдет (но может и найти, это уже как повезет с хеш-значением)....
... а тут можно почерпнуть информации на тему Apache Commons утилит, приятно избегающих NullPointerException...
...я тут погляжу SUNовцы немного забили на читабельность кода. Вот кусок их HashMap, причем не самый худший:
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); for (Entryповбивав би...e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
...любопытный рефакторинг придумал. Исходный метод:
public boolean isSafelyChanges(DateInterval intervalBefore, DateInterval intervalAfter) { return (intervalBefore.getStrat() <= intervalAfter.getStart() && (intervalBefore.getEnd() == 0 || (intervalAfter.getEnd() != 0 && intervalAfter.getEnd() <= intervalBefore.getEnd()))); }Задача была такая. Есть интервал дат - он может меняться. Если end в интервале = 0, то это означает, что дата окончания где-то возле бесконечности. Интервал может перекрываться с другим интервалом. Но если исходный интервал поменялся так, что перекрытия не будет хоть ты тресни (т.е. сузился), то метод должен вернуть true. Исходный метод используется для оптимизации, чтобы не включать тяжеловесные алгоритмы поиска перекрытий. А я немного пошалил:
public static final boolean IS_SAFELY = true; public static final boolean IS_NO_SAFELY = false; public boolean isSafelyChanges(DateInterval intervalBefore, DateInterval intervalAfter) { if (intervalBefore.getStrat() > intervalAfter.getStart()) { return IS_NOT_SAFELY; } return (intervalBefore.getEnd() == 0 || (intervalAfter.getEnd() != 0 && intervalAfter.getEnd() <= intervalBefore.getEnd()))); }потом так:
public static final boolean IS_SAFELY = true; public static final boolean IS_NO_SAFELY = false; public boolean isSafelyChanges(DateInterval intervalBefore, DateInterval intervalAfter) { if (intervalBefore.getStrat() > intervalAfter.getStart()) { return IS_NOT_SAFELY; } if (intervalBefore.getEnd() == 0) { return IS_SAFELY; } return (intervalAfter.getEnd() != 0 && intervalAfter.getEnd() <= intervalBefore.getEnd())); }дальше так:
public static final boolean IS_SAFELY = true; public static final boolean IS_NO_SAFELY = false; public boolean isSafelyChanges(DateInterval intervalBefore, DateInterval intervalAfter) { if (intervalBefore.getStrat() > intervalAfter.getStart()) { return IS_NOT_SAFELY; } if (intervalBefore.getEnd() == 0) { return IS_SAFELY; } if (intervalAfter.getEnd() == 0) { return IS_NOT_SAFELY; } return (intervalAfter.getEnd() <= intervalBefore.getEnd())); }ну и напоследок так:
public static final boolean IS_SAFELY = true; public static final boolean IS_NO_SAFELY = false; public boolean isSafelyChanges(DateInterval intervalBefore, DateInterval intervalAfter) { if (intervalBefore.getStrat() > intervalAfter.getStart()) { return IS_NOT_SAFELY; } if (intervalBefore.getEnd() == 0) { return IS_SAFELY; } if (intervalAfter.getEnd() == 0) { return IS_NOT_SAFELY; } if (intervalAfter.getEnd() > intervalBefore.getEnd()) { return IS_NOT_SAFELY; } return IS_SAFELY; }Позже пришлось добавить комментарий типа "не меняйте порядок проверок иначе будет капец" :) Стало читабельнее? Как бы то ни было, любую, N-этажную булевскую конструкцию, при условии, что она Extract'нута в отдельный метод, можно превратить в последовательность простых проверок с return'ами.
Правило "простое":
(0) Запомним где-то в голове переменную с начальным значением true - назовем ее ЧТО_ВЕРНУТЬ.После того как рефакторинг проведен - можно аннигилировать двойные НЕ ("!") операторы в результирующих проверках, или изменить условие (по типу с > на <=) с удалением/добавлением оператора НЕ ("!").
(1) Условие с отрицанием? Если да - тогда инвертируем нашу переменную ЧТО_ВЕРНУТЬ и проделаем еще раз операцию (1), если нет - идем дальше.
(2) Условие сложное (т.е. работает бинарный оператор ИЛИ ("||") или И ("&&"))?
(3) Если нет - выделяем простое условие в if и возвращаем значение ЧТО_ВЕРНУТЬ из метода, а в конце метода всегда возвращаем инвертированное значение ЧТО_ВЕРНУТЬ. На этом конец.
(4) Если да - находим самый приоритетный бинарный оператор (с учетом скобок меняющих приоритеты + так же помним, что оператор И ("&&") имеет больший приоритет нежели оператор ИЛИ ("||")).
(5) Смотрим на левый операнд бинарного оператора:
(6) Если левый операнд сложный (т.е. в скобках так же используется операторы ИЛИ ("||") или И ("&&") а правый операнд простой (т.е. проверка на равенство/неравенство/больше/меньше/вызов метода + с возможной инверсией НЕ ("!")), то мы меняем операнды местами (чтобы слева стоял простой операнд) и делаем операцию (8).
(7) Если и левый и правый операнд сложные (т.е. в скобках так же используется операторы ИЛИ ("||") или И ("&&")) тогда выбираем наиболее простой операнд, ставим его слева от оператора (а сложный справа) и выполняем операцию (8), считая левый операнд простым. Это единственное исключение, когда разобрать выражение типа ((a || b) && (с || d)) или ((a && b) || (с && d)) просто не получится.
(8) Если же левый операнд простой, то мы смотрим на его оператор:
(9) Если оператор ИЛИ ("||"), то мы выделяем левый операнд в if и возвращаем текущее значение переменной ЧТО_ВЕРНУТЬ из метода.
(10) Если оператор И ("&&"), то мы выделяем левый операнд в if, инвертируем его и возвращаем инвертированное значение ЧТО_ВЕРНУТЬ из метода.
(11) Удаляем отработанный оператор, лишнюю пару скобок и проделываем с оставшимся правым операндом операцию (1).
Так же можно поиздеваться над одним свойством булевских операторов:
!(a && b) = !a || !b
и
!(a || b) = !a && !b
Возможно оно поможет на каком-то этапе избавиться от мешающего оператора НЕ ("!").
Назову ка я этот шаблон refactoring "Избавление от очень умного булевского выражения" или "Getting rid of a very intelligent boolean expression" (если с инглышем что-то не так, прошу поправьте).
Послать что-ли его Фаулеру? Помню, в книге своей он просил отправлять ему все замечания и новые идеи...
...3:55 ночи! Ого! Саня, пора бы пойти спать...
Комментариев нет:
Отправить комментарий