пятница, 18 декабря 2009 г.

«Почему российские компании катастрофически отстают от западных?»

Зацепила меня статья про менеджмент http://habrahabr.ru/blogs/my_business/78576/. Зацепила тем, что вопросы в ней задаются правильные и неудобные. Надо задавать себе неудобные вопросы. И делать это постоянно.
Все больше убеждаюсь, что самая симпатичная мне компания - это Google. Хоть я и прекрасно понимаю какая это сейчас машина. И этой крупной машине будут свойственны те же изъяны, что и другим крупным машинам. Наверное, самое главное, что пропадает "дух стартапа", появляется задержка в принятии решений, боязнь ошибки. И это правильно, Google уже далеко не стартап. Мне нравится, что Брин пытается объяснить любое решение цифрами, найти какие-то алгоритмы и закономерности. Это правильный подход. Ну и надо быть немного "crazy":). Нравятся мне дерзкие компании.

среда, 16 декабря 2009 г.

Кэширование ресурсов в Eclipse

Проблема: изменил DTD и пытался перепроверить XML по новому DTD, но валидатор отрабатывал по старому DTD.
Решение: зайти в Window -> Preferences -> General -> Network Connections -> Cache и там удалить ресурсы, которые должны быть обновлены. После этого обновить XML документ, нажать кнопку "Reload Dependencies".

Комментарий:
Потратил уйму времени на выяснение того, почему новая версия DTD никак не может загрузиться. Казалось бы, логичная кнопка есть "Reload Dependencies", которая судя по описанию http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.wst.dtdeditor.doc.user/topics/tdtemplt.html должна перегружать DTD. Но по сути этого не происходило. Я знал, что у Eclipse есть кэш, куда он сохраняет DTD и XSD. Именно ковыряние по этой теме вывело на то, что нужно идти в настройки и там ковырять кэш. Вообще, интересно куда он кэш сохраняет в файловой системе, но сейчас некогда выяснять. "Тупо сделано"... что тут ещё скажешь.

вторник, 15 декабря 2009 г.

Многословная Java

Успеваю забывать то, что придумал пока кодирую. Java очень многословная. Тут дело именно в синтаксисе и всякие библиотечки не помогут. Java дает делать многие фишки, но слишком большой ценой. Муторно бывает по вложенным циклам ходить. Хочется это записывать в стиле современных языков. Надеюсь, что в Java 7 все-таки появятся замыкания. Хоть и синтаксис с ними станет ещё уродливее, но зато возможности вырастут. А вообще пора Scala изучать и не париться на эту тему. Как будет время свободное, то обязательно заюзаю и расскажу.

пятница, 4 декабря 2009 г.

Поставьте уже вашим сотрудникам большие мониторы

http://biz.cnews.ru/news/top/index.shtml?2009/02/20/338544
http://www.happy-pm.com/blog/?p=323

Управление ITшниками

По ссылке ниже можно прочитать перевод интересной статьи про управление ITшниками.
http://www.diggreader.ru/2009/09/13/neglasnyie-istinyi-upravleniya-gikami/

Самое главное в IT команде - это профессиональное уважение к тим-лиду и остальным участникам. Тут, как с врачами: главврачом всегда является врач высшей категории, который обладает реальным опытом и знаниями, а также практикует. Причем данное уважение никак не связано с общим обаянием человека или умением говорить красивые слова. Уважение связано с реальной работой. Айтишник готов работать до потери пульса не ради денег, а ради профессионального интереса, ради более изящного решения.


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

вторник, 24 ноября 2009 г.

Старое заблуждение о выносе локальной переменной за пределы цикла

Очень старое заблуждение, которое активно пропагандируется некоторыми некомпетентными преподавателями вузов. Заблуждение иллюстрируется следующим кодом:
    public void test1()
    {
        for (int i = 0; i < 20; i++)
        {
            int j = i;
            j++;
        }
    }

    public void test2()
    {
        int j;
        for (int i = 0; i < 20; i++)
        {
            j = i;
            j++;
        }
    }
Считается, что нужно самому выносить локальную переменную из цикла, иначе память под неё будет выделяться на каждой итерации. На самом деле это совсем не так. Компилятор без труда оптимизирует данный кусочек кода. Память будет выделена всего лишь один раз. Причем, это касается не только Java, но и других языков, таких как C, C++ и т.д. Это типичная оптимизация.
Для сомневающихся привожу байт-код обоих методов:
 // Stack: 2, Locals: 3
  public void test1();
     0  iconst_0
     1  istore_1 [i]
     2  goto 13
     5  iload_1 [i]
     6  istore_2 [j]
     7  iinc 2 1 [j]
    10  iinc 1 1 [i]
    13  iload_1 [i]
    14  bipush 20
    16  if_icmplt 5
    19  return
      Line numbers:
        [pc: 0, line: 14]
        [pc: 5, line: 16]
        [pc: 7, line: 17]
        [pc: 10, line: 14]
        [pc: 19, line: 19]
      Local variable table:
        [pc: 0, pc: 20] local: this index: 0 type: my.test.ByteCodeTest
        [pc: 2, pc: 19] local: i index: 1 type: int
        [pc: 7, pc: 10] local: j index: 2 type: int
      Stack map table: number of frames 2
        [pc: 5, append: {int}]
        [pc: 13, same]
  
  // Method descriptor #6 ()V
  // Stack: 2, Locals: 3
  public void test2();
     0  iconst_0
     1  istore_2 [i]
     2  goto 13
     5  iload_2 [i]
     6  istore_1 [j]
     7  iinc 1 1 [j]
    10  iinc 2 1 [i]
    13  iload_2 [i]
    14  bipush 20
    16  if_icmplt 5
    19  return
      Line numbers:
        [pc: 0, line: 24]
        [pc: 5, line: 26]
        [pc: 7, line: 27]
        [pc: 10, line: 24]
        [pc: 19, line: 29]
      Local variable table:
        [pc: 0, pc: 20] local: this index: 0 type: my.test.ByteCodeTest
        [pc: 7, pc: 13] local: j index: 1 type: int
        [pc: 2, pc: 19] local: i index: 2 type: int
      Stack map table: number of frames 2
        [pc: 5, full, stack: {}, locals: {my.test.ByteCodeTest, _, int}]
        [pc: 13, same]
Как мы видим, память выделяется под 2 переменные.

понедельник, 23 ноября 2009 г.

Подсчет временной разницы между двумя датами

Возникла такая задача: подсчитать разницу, прошедшую между двумя датами и уметь выводить её в годах, месяцах, днях и т.д., а также в такой форме "1 день 2 месяца 3 года".

При решении данной задачи нужно учитывать, что нельзя просто взять и вычесть количество миллисекунд одной даты из другой. Таким образом мы не можем в точности посчитать ничего, т.к. существует переход на летнее/зимнее время. Например, мы вычтем кол-во мс из даты, созданной на 30 марта 2009 года(установим также 0 часов, минут, секунд и миллисекунд) и 29 марта 2009 года(также обнулим лишние поля). Если перевести получившееся количество миллисекунд в часы, то мы получим 23 часа, а должно быть 24. Почему? Потому что именно в это время у нас переводят на зимнее время. Соответственно, необходимо учитывать данный факт.

То есть для вычисления мс, прошедших между двумя датами нужно использовать следующий метод:
public static long getDiffInMillis(Calendar c1, Calendar c2)
    {
        // учитываем перевод времени
        long time1 = c1.getTimeInMillis() + c1.getTimeZone().getOffset(c1.getTimeInMillis());
        long time2 = c2.getTimeInMillis() + c2.getTimeZone().getOffset(c2.getTimeInMillis());
        return Math.abs(time1 - time2);
    }

Таким образом мы легко получим кол-во прошедших часов, минут и секунд. Но если мы хотим получить кол-во прошедших дней, не учитывая часы, минуты и прочее, то нам необходим следующий метод:
public static int getDiffInDays(Calendar c1, Calendar c2)
    {
        Calendar gc1 = (Calendar)c1.clone();
        Calendar gc2 = (Calendar)c2.clone();

        // обнуляем часы, минуты и секунды
        gc1.set(Calendar.HOUR, 0);
        gc2.set(Calendar.HOUR, 0);
        gc1.set(Calendar.SECOND, 0);
        gc2.set(Calendar.SECOND, 0);
        gc1.set(Calendar.MILLISECOND, 0);
        gc2.set(Calendar.MILLISECOND, 0);

        return (int)(getDiffInMillis(c1, c2) / MILLISECONDS_IN_A_DAY);
    }

Но используя данную методику нельзя сказать сколько прошло месяцев и лет. Для этого мы будем использовать следующий метод:
/**
     * 

Высчитывает разницу между двумя временами, в зависимости от значения field. * field - это константное значение из java.util.Calendar, обозначающее * конкретную временную метрику(год, месяц и т.д.).

* *

Устанавливает поля, заданные в массиве clearFields равными 0.

* * @param field * константное значение из java.util.Calendar(YEAR, MONTH...) * @param c1 * первая дата * @param c2 * вторая дата * @param clearFields * поля даты, которые не учитываются при сравнении. Задаются массивом констант из из java.util.Calendar. * Например, можно не учитывать миллисекунды, секунды и часы. Данные поля будут обнулены. * @return * разницу между c1 и c2 в метрике, заданной field */ public static int getTimeDifference(int field, Calendar c1, Calendar c2, int... clearFields) { Calendar gc1, gc2; if (c2.after(c1)) { gc1 = (Calendar)c1.clone(); gc2 = (Calendar)c2.clone(); } else { gc1 = (Calendar)c2.clone(); gc2 = (Calendar)c1.clone(); } if (clearFields != null) { // очищаем поля, которые мы не будем учитывать при сравнении дат for (int clearField : clearFields) { gc1.clear(clearField); gc2.clear(clearField); } } int count = 0; for (gc1.add(field, 1); gc1.compareTo(gc2) <= 0; gc1.add(field, 1)) { count++; } return count; }
Как мы видим, данный метод просто пытается прибавить 1 к заданному временному промежутку. В clearFields мы задаем поля, которые необходимо обнулить. Таким образом мы можем найти разницу не только в годах и месяцах, но и в чем угодно, но это будет неэффективно. Следующей задачей является вывод нужного слова для временной единицы. Например, мы говорим прошло "5 лет", "2 месяца", "1 год", "11 секунд" и т.д. Оказывается, что все названия временных промежутков подчиняются единому закону. Достаточно всего лишь трех слов :). Этот закон выражен данным кодом:
/**
     * Возвращает слово, добавляющееся к временной единице, когда указывается сколько прошло
     * временных единиц.
     * В русском языке для временных единиц достаточно трех слов.
     * Значение time берется по модулю.
     * 
     * @param time
     *            количество временной единицы
     * @param timeUnitName1
     *            Название временной единицы, которое используется с 1. Например, 1 "минута".
     * @param timeUnitName2
     *            Название временной единицы, которое используется с 2. Например, 2 "минуты".
     * @param timeUnitName5
     *            Название временной единицы, которое используется с 5. Например, 5 "минут".
     * @return
     *         слово для единицы времени
     */
    public static String getTimeUnitPeriodName(long time, String timeUnitName1, String timeUnitName2, String timeUnitName5)
    {
        String result;
        time = Math.abs(time); // для отрицательных чисел
        int small = (int)(time % 10);
        int middle = (int)(time % 100);

        // если заканчивается на 11, то всегда оформляется словом timeUnitName5
        if (small == 1 && middle != 11)
        {
            result = timeUnitName1;
        }
        // если оканчиваются на 2, 3, 4, за исключением 12, 13 и 14
        else if (small >= 2 && small <= 4 && (middle < 12 || middle > 14))
        {
            result = timeUnitName2;
        }
        else
        {
            result = timeUnitName5;
        }

        return result;
    }
Оказалось, что так устроен наш язык, что особыми временными единицами являются 11, 12, 13 и 14(точнее оканчивающимся на эти числа). Остальное подчиняется общим правилам. То ли дело в английском языке. Теперь мы можем считать промежуток между двумя датами в любой временной единице и находить для данной единицы нужное слово. Осталась ещё одна нерешенная задача: как выводить временной промежуток в формате "X дней Y месяцев Z лет", но делать это так, чтобы у нас не было ситуации "12 дней 13 месяцев 1 год", а было например так "12 дней 1 месяц 2 года". Т.е. у нас не может быть больше 12 месяцев или больше 31 дня. Данную задачу мы решим следующим образом. Будем находить разницу в годах и затем вычитать данную разницу из конца промежутка. Дальше поступим также для месяца. Оставшиеся дни же просто выведем. Вот кусок кода(from и to - экземпляры Calendar):
// если конечная дата больше, то меняем их местами
        if (from.after(to))
        {
            to = from;
        }

        int diffInYears = DateUtils.getDiffInYears(from, to);
        to.add(Calendar.YEAR, -diffInYears); // вычитаем учтенные года

        int diffInMonths = DateUtils.getDiffInMonths(from, to);
        to.add(Calendar.MONTH, -diffInMonths); // вычитаем учтенные месяцы

        int diffInDays = DateUtils.getDiffInDays(from, to);
Не забудьте, что вы вычитаете из даты, поэтому нужно клонировать переданный экземпляр Calendar. Ну а далее форматируем полученные числа по своему желанию.

p.s. также не забывайте указывать первый день недели на понедельник(в России) - calendar.setFirstDayOfWeek(Calendar.MONDAY)

пятница, 20 ноября 2009 г.

Успех

Есть люди, которые работают быстро и качественно. Результаты таких людей просто потрясают. Фактически пара людей может написать достаточно большую и сложную систему. Пара! Причем сделать это, например, за полгода или меньше. Пример перед глазами. Это круто. Конечно же речь идет не о написании бизнес-лапши. Ибо бизнес лапша на моих весах находится где-то в соотношении 100:1. 100 классов бизнес-лапши равны одному утилитарному(системному) классу.
Вообще рекомендую ввести метрики для подсчета своей эффективности. А также для интереса подсчитать коллег. Соответственно следовать своей метрике и улучшать её.
Мне очень кажется, что увольняться с работы стоит тогда, когда ты в принципе достиг на ней хороших результатов. Дальше уже или скучно или некуда. То есть пока не уволился, достигай результатов. Ставь цель и достигай её. Иначе будешь отвечать на тупые вопросы на знание Java вместо того, чтобы рассказывать о своих успехах на предыдущей работе. Например, одной из метрик может быть кол-во комментариев до и после тебя. Или ты сделал так, что делать некоторую рутинную задачу стало в 2 раза быстрее. Либо ты увеличил скорость некоторого участка в 3 раза. Разница должна выражаться в разах. Возможно ты так отрефакторил класс, что он стал в 2 раза короче, а его использование стало в 4 раза проще. Может быть ты наладил систему тестирования и обеспечил этим в 3 раза меньшее кол-во багов.

пятница, 30 октября 2009 г.

Старая ошибка в бинарном поиске в Java

Случайно наткнулся на статью Joshua Bloch о любопытной ошибке в реализации бинарного поиска в старой версии Java. Вот ссылка http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html. Суть проблемы в том, что на массивах из очень большого количества элементов(примерно миллиард элементов) данный поиск бы ломался. Причина этого, неочевидна, но проста. А именно при сложении двух чисел типа int можно получить число, больше максимально возможного для int. А, как мы знаем, в бинарном поиске позиция текущего элемента вычисляется, как среднее между двумя числами:

int mid =(low + high) / 2;

Джош переписывает эту строчку кода на:

int mid = low + ((high - low) / 2);

или что лучше по производительности:
int mid = (low + high) >>> 1;

Последняя строка сейчас и используется в Arrays и в Collections. Вот такая забавная история.

воскресенье, 18 октября 2009 г.

666 евро в месяц

Предлагают нам учиться во Франции и получить единоразовую стипендию в размере 8000 евро на год. А это получается по 666,6(6) евро в месяц. Неплохо. У нас в ЮУрГУ стипендия равна примерно 50$ в месяц. А зарплата сотрудников института что-то около 120-150$.
Как же тут учиться и одновременно не работать?

пятница, 16 октября 2009 г.

Интересные заметки по Java

Пишет некто  Dr. Heinz M. Kabutz. Довольно интересные заметки http://www.javaspecialists.eu/archive/archive.jsp

вторник, 13 октября 2009 г.

Пара вопрос к программистам-практикам на C/C++

Подскажите пожалуйста хорошие книги, статьи на тему "дизайна", конструирования программ на языке Си. Интересует, как пишутся "средней руки" системные программы на Си и желательно под Unix системы.
Общие принципы видятся такими:

  1. Выделяются относительно обособленные куски. Они раскидываются по разным файлам
  2. Для них пишутся свои структуры("замены классам") и функции.
  3. В файле(ах) "main" это все собирается воедино
Слишком уж абстрактно...
Также интересно, какими инструментами пользуются для статического анализа кода на предмет ошибок и возможных утечек памяти. В качестве IDE думаю взять Eclipse CDT. 

суббота, 10 октября 2009 г.

Программа для быстрого перевода

Использую сам уже более двух месяцев и рекомендую другим попробовать программу-обертку для перевода от Google Translate http://translateclient.com/. Выделяете любой текст и появляется иконка с кнопкой. Нажимаете и получаете перевод. Можно настроить перевод с любого на любой язык. Также, можно легко отключить работу программы в некоторых приложениях, например в Eclipse, чтобы она не выводила подсказку при выделении текста. Программа стабильна и не глючит.
Автору данной программы большое спасибо!
p.s.: забыл добавить, что работает это только для windows :(

среда, 7 октября 2009 г.

Как сделать в svn уведомления о коммитах

Теперь я понимаю *nix'ые HOW-TO и пошаговые инструкции, где и что нужно вводить :). Вот моё HOW-TO. Сам я устанавливал это на Linux сервере.
1) http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/mailer/mailer.py- сам скрипт для рассылки
http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/mailer/mailer.conf.example настройки для этого скрипта
2) Кладете mailer.py в вашу любимую директорию со скриптами. Не забудьте сделать chmod 755.
3) Переименуйте mailer.conf.example в mailer.conf. Положите его в директорию /home/username/svn/yourproject/conf/. Сделайте chmod 755.
4) Правьте mailer.conf. Тут все зависит от ваших настроек сервера. В моем случае я раскомментировал строчку с mail_command и smtp_hostname.
Запишите в to_addr адреса членов комманды, которые будут получать уведомления. Адреса разделяйте через пробел.
Добавьте в reply_to почтовый адрес сервера(для красоты и фильтрации:)).
Там ещё много всяких настроек. Они уже на усмотрение остаются.
5) Заключительный шаг.
Идем в svn директорию проекта и находим там папку hooks. Переименовываем файл post-commit.tmpl в post-commit. Делаем chmod 755.
Там комментируем лишние линии, кроме REPOS и REV.
Добавляем следующую линию, описывающую путь до скрипта:
/home/username/script/mailer.py commit "$REPOS" "$REV"

Слайды к статье про фунциональное программирование в Java

Многие, наверное, читали следующую статью http://antilamer.livejournal.com/245962.html. Но я думаю, что далеко не все видели слайды к данной статье http://spbhug.folding-maps.org/wiki/EugeneKirpichov?action=AttachFile&do=get&target=JavaFP_ru.ppt. В презентации больше информации, примеров и вообще лучше усваивается.

p.s.: хотя в Google на запрос "Функциональное программирование Java" данные слайды вылезают первыми.

Проглядел комментарии

Извиняюсь перед всеми, что не выводил комментарии. Надеялся, что мне по почте будут выводиться уведомления и попросту не смотрел.
p.s.: Там есть комментарии, оставленные несколько месяцев назад...

пятница, 2 октября 2009 г.

Наука
Выбрал темой для научных исследований тему №3:"координатор параллельной СУБД на базе СУБД PostgreSQL". Буду постргеc ковырять, а также MPI. Все это дело, между прочим, пишется на чистых Сях. Прощай JVM и сборка мусора! Привет, Access Denied и free!

ФП
Стало доходить "промышленное понимание" основ функционального программирования(ФП). К сожалению, не читал ни одной книги по ФП, поэтому называю это понимание промышленным. Оно ничем фундаментальным не подкреплено. Однако, теперь лень писать циклы, а однотипные действия очень хочется запихать в некие "объектики-функции"(скажем так:)). В Java для этого очень могут помочь доп. библиотеки. Но увлекаться всем этим не стоит. Нужно держать code-style. Однако, приходит смутное понимание, что 1000 строк кода можно уместить в 500 и даже меньше и все будет читабельно. Хочется иметь не 100 методов, а 10 объектов-функций и просто комбинировать их :)

Универ
Очень хочется сюда попасть. Посмотрим, насколько это окажется реальностью.

четверг, 1 октября 2009 г.

Ссылки на подкасты и научная работа

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

Подкасты, которые я регулярно слушаю:
http://ruby.rpod.ru/
http://maxim.podfm.ru/runetologia/
http://taop.rpod.ru/


Также предложили следующие темы для научной работы:
- оптимизация обменов данными в параллельной СУБД для многопроцессорных
иерархий.
- динамическая реконфигурация параллельной СУБД.
- координатор параллельной СУБД на базе СУБД PostgreSQL


Проект на RoR развивается и скоро уже будет в продакшн :-) Ждите...

вторник, 22 сентября 2009 г.

TDD подход

Занимаюсь задачей по построению отчета. Было пару интересных моментов в этой задаче, связанных с оптимизацией и самим построением. Удалось время построения отчета довести примерно до 1,5 минут, что очень даже приемлемо. В остальном же задача унылая, преунылая.
Почему же она такая преунылая и я занимаюсь ей уже 78 часов..? Потому что отчет строится не совсем правильно. Проблема в том, что автоматизированных тестов нет вообще. Соответсвенно протестировать мне же свою работу почти что невозможно. Вот тут я сразу вспомнил TDD и разработку через тестирование. По сути надо было в начале написать тесты, моделирующие различные состояния бизнес-объектов, а после этого браться за сам отчет. Теперь же ни я ни кто-либо другой не уверен, что данный отчет будет работать корректно. Никогда ранее я не ощущал такой острой необходимости в TDD. Мне кажется, что эта задача будет вечно теребить мой мозг. Самое же страшное - это когда ты не уверен в работоспособности собственного кода и все понимают, что протестировать это вручную крайне утомительно(а значит оно так и остается на твоей совести).

воскресенье, 2 августа 2009 г.

Ruby Design

Понравилось недавнее высказывание на Ruby Talk: "Ruby, thankfully, is designed to be nice to humans, not to parsers."

четверг, 30 июля 2009 г.

Narrowing proxy

Если у вас Hibernate вдруг стал писать в логгере следующие строчки:
"WARN org.hibernate.engine.StatefulPersistenceContext.ProxyWarnLog - Narrowing proxy to class имя_класса - this operation breaks == "
То есть хорошее объяснение вот здесь https://forum.hibernate.org/viewtopic.php?p=2404391

Ужасный маппинг (Crazy Mapping)

Вчера отрефакторил одну "мега-фичу". Она заключалась в том, что маппинг для сущностей создавался автоматически и подключался при каждом старте системы. Это было очень плохо по следующим причинам:
  1. Нет зафиксированного состояния БД. Непонятно, какие сейчас названия у колонок, внешних ключей, индексов и даже таблиц. Для нас это очень важно т.к. мы мигрируем БД из одного состояния в другое и нам обязательно нужно знать, как сейчас называются объекты в БД.
  2. Смена логики формирования влечет смену всех имен объектов в БД.
  3. У нас так не принято делать. Можете не считать это аргументом, но для меня это аргумент.
Я уже обрадовался, что больше такой "фичи" у нас нет, но не тут-то было. Начала вылезать ошибка, что сущности "ru.naumen.unids.archive.StudentArchive" нет в hibernate. Оказалось, что автор данной "фичи" маппил два класса в одну таблицу, а я вынес только один маппинг. То есть у него это выглядело вот так:
1) <class name="ru.naumen.unids.archive.StudentArchive" table="AR_STUDENT" lazy="false">
2) <class name="ru.naumen.unistudent.bobjects.student.StudentArchive" table="AR_STUDENT" lazy="false">
В остальном же весь маппинг полностью аналогичен. Вот так... Сейчас разгребаем.

пятница, 24 июля 2009 г.

О новом, старом и общем

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

Понравилось недавнее высказывание Google, о том, что их система масштабируется горизонтально. Вся их система держится на нескольких основных технологиях, таких как Map-Reduce, Big Table, GFS и т.д. И оптимизация каждой из них ведет к оптимизации всей системы. Это замечательно.
Как такая идея может пригодиться нам, обывателям? Например, когда мы делаем систему кэширования, то она должна быть универсальной, единой для системы. Вообще же надо стремиться к универсализации и использовании open-source решений. Ресурсов не хватает все это поддерживать, не то что развивать.

четверг, 23 июля 2009 г.

Изобретатели велосипедов хуже идиотов

Настроение сегодня ни к черту из-за того, что целый день ковыряюсь в идиотском модуле, написанным одним "программистом". Этот хренов модуль, как и его автор ничего не слышали о MVC. Также они считают, что когда все понапихано в одном месте - это признак хорошего кода. Как же надо было хотеть изобретать велосипеды, чтобы заменить все стандартные компоненты на компоненты собственного производства ("@author FullIdiot"). Его уже давно не волнует, что теперь штук 300 выписок создано на основе его "наработок". И теперь от этого идиотизма никуда уже не деться, не помогут никакие книги про рефакторинг.
Да и ещё этот горе-программер решил похвастаться знанием шаблонов разработки. Применил "паттерны" Visitor, Adapter, AdapterProvider. Тошнит уже... Кому разгребать эту конюшню..?

p.s.: Изобретатели велосипедов хуже идиотов. идиоты хотя бы пользуются готовыми наработками.

среда, 22 июля 2009 г.

Проблемы с кодировкой в патчах Eclipse

Проблема была с русскими символами при накате Eclipse патча (Apply Patch). Собственно выводилась "абракадабра". Наконец-то потратил немного времени, чтобы побороть эту проблему . У нас почти все файлы кодируются в UTF8. Я думал, что возможно патчи кодируются в ANSI и при перекодировке из UTF8 с ними что-то случается. Но оказалось, что патчи сохраняются в UTF8 (видимо тут учитываются настройки кодировки проекта), а вот накатываются, как ANSI. Решением здесь будет перекодировать патч в ANSI. Например, в NotePad++ это делается в один клик "Кодировки -> Преобразовать в ANSI". После этого патч накатывается без проблем.

update(добавлено позже): оказывается данная проблема очень легко решается установкой параметра "-Dfile.encoding=UTF-8" в настройках Eclipse (добавить эту строчку в файл eclipse.ini).

(Eclipse patch encoding problem, проблемы с кодировкой патча в Eclipse)

суббота, 18 июля 2009 г.

Признание ошибок

Недавно на работе создал один классик, выполняющий кое-какую функцию. Думал, что данная функция не реализована. Недели через 2 понял, что данную функцию можно реализовать, используя стандартные механизмы. После этого, без страданий и мучений удалил свой классик, переписав на стандартную реализацию. Также стал теперь отмечать флагами "TODO:" те участки своего кода, где я недоволен им. Бывает, времени нет, либо ты чего-то не понял, а задачу нужно доделывать. Раньше тратил много времени, гоняясь за красотой, сейчас же ставлю "TODO:" комментарий и продолжаю работу. Данный "TODO:" бывает исправляю сам же, в течение пары дней. В любом случае, видя "TODO:" комментарий, сразу понимаешь, что здесь что-то может быть не так, либо есть решение красивее.
Нужно признавать свои просчеты или ошибки, не замалчивать их. Если ты чего-то не знаешь, нужно говорить об этом открыто.

четверг, 16 июля 2009 г.

PHP

Ужасаюсь всему известному и написанному на PHP: Joomla, phpBB, OSCommerce. Это популярно, но невероятно уродливо. От этого такое отторжение к самому PHP. Сам когда-то начинал именно с него. Ничего не понимал про ООП, да вообще ничего не понимал тогда. Отторжение такое, что кажется проще написать все своё с нуля на любимом языке. Все эти php-детища живут, дышат и даже "развиваются". Ими пользуются по причине отсутствия бесплатных аналогов. Тем более php-хостинг очень распространен.

Сам "язык" PHP я никогда не полюблю...

понедельник, 13 июля 2009 г.

Простые советы

  1. Методы, возвращающие булево значение, называйте "is" + проверяемое условие. Без всяких отрицаний в названии метода. Никаких "isNotNull()" или "isWithoutValidation()" не может быть. Иначе при вызове "!isNotNull()" или "!isWithoutValidation()" получаем отрицание отрицания. А это плохо при чтении кода. Сравните: "!isEmpty()" и "!isNotEmpty()". Что проще понять?
  2. Избегайте регулярных выражений, где возможно. Конкретный пример из практики: "String.format("%s %s %s", last, first, middle)". В данном простом случае, косвенно используются регулярные выражения. Вариант "last + ' ' + first + ' ' + middle" работает в 3-5 раз быстрее и жрет намного меньше памяти.

четверг, 9 июля 2009 г.

О плохих вещах в программировании

Есть несколько вещей, которые меня доводят (отсортировано в произвольном порядке):
  1. Суровость. Программер пишет новый модуль/класс, которым должны пользоваться другие программеры и не оставляет ни единой строчки комментариев. Встречал мнение, что написание комментов означает нечто плохое, якобы ты "снижаешь свой уровень программирования" тем самым. Возможно, твой код действительно лучший и читаемый, но поверь, что это сразу не поймешь. Моё мнение, что такого быть не должно. Сам столкнулся с кучей недокументированного кода. Ну а смысл? Там, где я разобрался бы за 1 минуту, мне приходится разбираться 15. А если я лезу в новые дебри, то несколько часов разбирательств гарантированны.
  2. Изобретательство велосипедов. Ну это вообще бред.
  3. Нешаблонное мышление в плохом смысле этого слова. Когда ты делаешь некий компонент или класс, то должен понимать "ага, тут мы следуем MVC модели, а это значит, что в вид нельзя запихивать получение данных". Это серьезный вопрос. Старшие товарищи должны объяснять младшим "как надо".
  4. Отсутствие контроля со стороны старших программистов. К сожалению, code-review для меня несбыточная мечта. Плохо.
  5. Присутствие "индуса" в команде. Это вообще тихий ужас. К счастью, такого сейчас нет.
  6. Отсутствие амбиций у команды... это когда просто кодят, выполняют свою работу и ничего больше. Скучно работать становится.
  7. Отсутствие автоматических тестов. Это просто большая ошибка. Твои заказчики будут тебя ненавидеть за то, что они являются твоими тестерами. Хоть часто и говорят "все не протестируешь", "у нас тут gui", "сложная логика", но мое мнение, что надо разрабатывать соответствующие механизмы, инструменты и такие проблемы решатся. Да это затраты, да это время. Может я просто никогда не был тим-лидом, поэтому так и считаю...?
  8. Нарушение DRY (Don't repeat yourself) принципа. Очень тоскливо, но зачастую, как мне кажется, невероятно сложно избегать DRY. Нужно видимо быть по-настоящему крутым прогером, чтобы такие вещи в твоем продукте не допускались.
  9. Отсутствие общей "багзиллы". Это провоцирует такие вещи, как "да это же известный баг!". Да, конечно он очень известный и был в рассылке аж полгода назад. Глупо. Тем более зачастую если я нашел баг, то мне не хочется или не хватает квалификации его исправить. Так бы я занес его в багзиллу и кто-то "постарше" исправил. Действия по принципу "сам нашел - сам и исправляй" на мой взгляд неуместны.

четверг, 11 июня 2009 г.

Подборка забавных комментариев

Подборка смешных комментов из исходников:
  1. "//if you want to refactor: please, attend!";
  2. "//todo: BUILT or NOT_BUILT - that is a question...";
  3. "//TODO:Temporary hack" - висит уже больше года;
  4. "//TODO or not TODO: implement this as OSGi service...";
  5. "//TODO: Зачем увеличивать диффузию слоя данных в слой представления ?";
  6. "//TODO: "одноногий компонент".";
  7. "// FIXME Это нормально что переформирование ведомости для каждой группы проходит в свой транзакции с одной стороны в этом нет ничего плохого, но как-то не по принятым правилам :)";
  8. "//TODO & FIXME this code is buggy. Should be a bridge between MetaClasses & CoreClasses. Don't say I didn't warn you! ;)";
  9. "// FIXME! Теоретически запрос может вернуть более чем один объект в результате чего произойдет исключение. В общем не понятна логика когда будет возвращено более одного объекта";
  10. "//Исчадье копипаста".
p.s.: автором одного из данных комментов являюсь я сам :)

вторник, 9 июня 2009 г.

Баг Java компилятора

Удивительные вещи. На работе случайно написал код, который вызывает ошибку компилятора java. Этот пример можно проиллюстрировать таким вот кодом, который компилится при помощи Eclipse и не компилится при помощи javac:
public class X
{
<T extends X> T f1() throws Exception
{
return null;
}

<U extends X> U f2() throws Exception
{
return f1();
}
}

javac выдает следующую ошибку:
X.java:6: type parameters of <T>T cannot be determined; no unique maximal instance exists for type variable T 
with upper bounds U,X
return f1();
^


Если заменить "return f1()" на "return this.<U>f1()", то javac проглатывает. Этот баг также известен здесь http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6302954. И судя по комментам не исправлен в 1.6.13 и исправлен в 1.7. Только я вот одного не понимаю, как же оно в Eclipse компилится...

воскресенье, 7 июня 2009 г.

MS SQL "Немедленно"... но что немедленно..?

Что произойдет в MS SQL, если в процессе восстановления БД из дампа нажать на ссылку "Немедленно":
Ответ белым шрифтом внизу... это что же логично?

Восстановление БД немедленно прервется

пятница, 5 июня 2009 г.

Метки в Java (Java Labels)

Метки в Java могут использоваться для выхода из вложенных циклов. Это по сути GOTO в Java. В данном случае не нужно создавать дополнительных "индикаторных" переменных и тем самым усложнять код. Стандартный пример в данном случае:

int i, j = 0;
label: for (i = 0; i < 10; i++)
{
for (j = 0; j < 10; j++)
{
if (i == 5 && j == 5)
{
break label;
}
}
}
System.out.println(i + " " + j);


Также одним из полезных применений меток будет переход на следующую итерацию внешнего цикла:
label: for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
if(i == 5)
continue label;
}
System.out.println(i);
}


Прикол в тему меток. Скомпилируется ли данный код?
public static void main(String args[])
{
http://dr-magic.blogspot.com/
System.out.println("Hello World!");
}

четверг, 4 июня 2009 г.

Google Squared

Java != JavaScript. Google Squared пока не в курсе

.

Опрос: лучшая книга по Java

Мне вдруг стало очень интересно услышать, какую же книгу по Java вы считаете самой лучшей и интересной. А также вообще какие книги по данной теме вы читали. Можете ли что-то посоветовать?

понедельник, 25 мая 2009 г.

Научная теория принятия решений и бизнес

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

А неопределенность в работе этой самой фирмы оказывается настолько высокой, что статического ip-адреса приходится ждать месяц, из-за того, что "не щелкнули вовремя на нужную галочку в форме". А также неопределенности периодически возникают и исчезают. Длительность таких неопределенностей колеблется от 30 минут до нескольких дней...
Оказывается можно писать такие статьи в умных журналах и при этом не видеть очевидных прорехов в работе своей фирмы. А может и не хотеть их видеть...
Разве нужны хоть какие-то математические выкладки, чтобы не брать на работу "по блату" или не нанимать неквалифицированных рабочих..? Это и так всем понятно. Оказывается, что менеджмент - это не так уж и сложно, во всяком случае в теории и по книгам.

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

Конечно, экономика России во многом теневая, много коррупции и прочих "неопределенностей", но тогда зачем создавать нерабочие теории? Это как в задачке "если вы закажете анализ рынка у профессора, то он окажется прав с вероятностью 0,9". Да вы никогда не узнаете с какой вероятностью он окажется прав, а лишние деньги наверняка потратите. А между прочем, некоторым удаётся предсказать экономическое будущее на основании математического подхода, как например Виктору Маслову. Думать надо... думать!

p.s.: разговор идет в первую очередь про теории принятия решений, теории управления и т.п.

пятница, 22 мая 2009 г.

Интересное инстанцирование

Скажите кто хоть раз встречался с таким инстанцированием класса:

public class Example {

public class MemberOfExample {
public void test() {
System.out.println("Hello, my dear friend!");
}
}

}


public class Main {
public static void main(String[] args) {
Example example = new Example();
MemberOfExample member = example.new MemberOfExample();
member.test();
}
}


Любопытно...

вторник, 19 мая 2009 г.

Мнемоническое правило для запоминания, что нужно вернуть в compare методе

Наверное, каждый программист знает про метод compare, который есть в том или ином виде во многих языках программирования. В Java этот метод определяется в интерфейсе Comparator:
int compare(T o1, T o2);

Но зачастую забывается, что же там надо вернуть - минус или плюс один. Я придумал мнемоническое правило, по которому легко запомнить, какое значение вам необходимо возвращать. Итак:
Если o1 меньше o2, то возвращаете минус один(-1). Обратите внимание на букву "м" в слове "меньше" и ту же букву в слове "минус". По этой самой букве "м" легко запомнить, что нужно возвращать. меньше => минус

Остальное же легко:
-если o1 равно o2, возвращается 0(это помнят все).
-остался один случай, когда o1 больше o2. Тут уже вспоминаете методом исключения, что надо вернуть "1".

Возможно, это было уже кому-то известно, однако, я такого нигде не читал.

p.s.: вообще необязательно возвращать +1 или -1. Просто должно быть отрицательное и положительное число. Часто делают +1 или -1, если не нужно знать насколько одно "больше" или "меньше" другого (в кавычках, потому что понятие больше или меньше условно). Но можно возвращать насколько одно "больше" или "меньше" другого. Например, пять больше трех на два. Эта информация может пригодиться в работе некоторых алгоритмов.

"Hello world". Java vs Python

Предположим, вы создали две программы на языках Java и Python, которые просто выводят строчку "Hello world". Программу на java вы скомпилировали и сделали jar-ник. А на Python'е вы просто создали файл с расширением ".py". Теперь вы выполняете получившиеся программы.

Внимание вопрос: какая из программ выполнится быстрее?

p.s.: об этом было в докладе про Java 7 на Sun Tech Days.

ORM. Введение и основные концепции

Привыкли мы, что знания приходят "извне" в уже разжеванном виде. Но это скучно до жути, хотя и продуктивно. Предлагаю тем, кто не знаком с аббревиатурой ORM самим придумать этот самый ORM! Зачем же нужен ORM..?

Итак, мои наводящие вопросы:
  1. У вас есть класс с переменными. Вам нужно этот класс сохранить в БД для дальнейшего считываения. Ваши действия, как это можно сделать?
  2. Допустим, вы додумались, как вам его сохранять. Теперь подумайте вот над чем: каким образом вы узнаете, что сохраненная запись относится именно к определенному классу? Какую информацию нужно знать, чтобы определить "вот эта запись относится точно к такому классу"?
  3. Так... неужели вы и до этого додумались? Тогда вопрос хитрее: у вас есть иерархия классов, каким образом вы будете её сохранять в БД?
  4. Вопрос ещё хитрее! У вас есть разветвленная иерархия классов. Это когда от одного класса наследуется несколько других классов, как вы будете их сохранять в БД? Каким образом вы отличите один подкласс от другого в БД? А сможете ли вы распознать класс-предок?
  5. Предложите несколько вариантов хранения иерархии классов в БД. Подумайте какие у них достоинства и недостатки. Скажу, что есть 3 основных, которые уже могут комбинироваться.
  6. Так, если вы до этого на все вопросы ответили и считаете, что правы, то подумайте каким образом вы бы сохранили коллекцию типа Set в БД? То есть у каждого класса есть переменная, типа Set. И у каждого она может быть своя.
  7. А типа List? Учтите, что в листе важен порядок следования элементов!
  8. Додумались..? Хм... Не верю! :) Хорошо, тогда ещё вопрос: подумайте, как можно сохранить в БД коллекцию типа Map.
  9. А теперь идите скачивайте Hibernate и мануал к нему... там ничего нового :)
Это шутка конечно, что "там ничего нового". Там действительно много нового и интересного, порой совсем непонятного...

Ответы на вопросы для собеседования по Java SE (Часть 3)

Предыдущая серия ответов: Ответы на вопросы для собеседования по Java SE (Часть 2)
Теперь помимо ответов на вопросы предоставляю ещё дополнительные вопросики для четкости полученных знаний.

11. Какие модификаторы доступа в Java вы знаете?
Java, как наследник C++ наследует и модификатор доступа с этого языка: public, private, protected и модификатор доступа по умолчанию - это когда модификатор не указывается.

-Можно ли объявить класс с модификатором protected?

12. Какой из модификаторов более строгий: protected или package-private?
Для начала надо разобраться, что такое package-private модификатор. Он ограничивает видимость до пределов пэкэджа, в котором лежит класс. И только до него! То есть, если класс лежит в пэкэдже "ru.myprog", то из пэкэджа "ru.myprog.base" он виден не будет(тоже самое для методов).
Protected модификатор, как все знают(кто хотя бы немного изучал ООП), раскрывает область видимости только для классов-наследников и для классов определенных в том же пэкэдже. Здесь мы видим отличие от C++, в котором только наследники видят protected.
Здесь можно почитать более подробно про модификаторы, а также увидеть сводную табличку http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

Из всего этого следует, что package-private модификатор более строгий.

-Объявляем класс с модификатором public, в котором создадим метод с default модификатором. Будет ли виден этот метод из других пэкэджей?
-Скомпилируется ли данная программа:
package ru.test;
class DefaultPackage {
void test()
{
;
}
}
----
package ru.test;

public class Public extends DefaultPackage {

}
----
package ru.test.base;

import ru.test.Public;

public class Main {
public static void main(String[] args) {
Public pub = new Public();
pub.test();
}
}

-Возможно ли перегружать default методы?

13. Если у класса-родителя есть метод, объявленный как private, может ли наследник расширить его видимость? А если protected? А сузить видимость?
private методы никто, кроме самого класса не видит. Поэтому их наличие/отсутствие никак не отражается на классах-наследниках. Они с легкостью могут объявлять методы с такой же сигнатурой и любыми модификаторами. Но это очень плохой тон! Антипаттерн.
Также клас наследник может расширить видимость protected-метода. Такой класс называется "Паблик-Морозов":). Из-за того, что как известный советсткий пионер, раскрывают информацию кому ни попадя! :)
Сузить видимость класс-наследник не может. Это будет ошибка компиляции.

14. Что означает ключевое слово final?
В случае класса - нельзя от него наследоваться.

В случае метода - нельзя его переопределять. Это используется, когда нужно явно указать "здесь не трогайте! оно так не задумано!". Обычно позволяет улучшить архитектуру системы. Но это нужно делать только если есть необходимость. Не надо все методы определять как final! Таких программистов называют "фаталисты". Раньше ещё было такое мнение, что final методы быстрее работают. Сейчас это абсолютная неправда. Работают они с такой же скоростью! Так что используйте их только при явной необходимости.

В члена класса final означает константу, которая после инициализации не поменяет своего значения. Но подумайте сами, что будет, если мы объявим, например, коллекцию как final:
Сработает ли следующий код?
public class Test {
final static List _list = new ArrayList();

public test() {
_list.add("Hello world!");
}
}

А этот ?
public class Test {
final List _list = new ArrayList();

public test() {
_list = new LinkedList();
}
}

15. Имеет ли смысл объявлять метод private final?
Только если вы отъявленный фаталист, финалист и пессимист! :)

16. Какие особенности инициализации final переменных?
Если они объявлена не как static, то они инициализируются в конструкторе, даже если не были объявлены не в нем. В этом случае код сгенерирует сам компилятор. Причем порядок их инициализации соответствует порядку их определения.
Если же она объявлена, как static, то либо при первом обращении к этой переменной, либо при первом создании объекта такого класса. То есть создание статических переменных происходит "по требованию" и только один раз. И это очень логично.

17. Что будет, если единственный конструктор класса объявлен как final?
Ошибочка компиляции. Почему - предлагаю подумать самим и написать в комментариях.

Django или Ruby on Rails

Вступление:
Для тех кто в раздумиях, что изучать Django или Ruby on Rails.

Мой ответ:
Ruby on Rails

Про языки:
Сами языки Ruby и Python сравнивать не буду. После Java и то и другое хорошо и лаконично :)

Раздумия:
Я сам думал над этим вопросом месяца 3-4 назад. Решил изучить Django после прочтения информации, что рельсы - это тормоза, а также, что Python - мега-язык программирования:).
Изучил базовый Python. Прочитал все базовые мануалы по Django на сайте(которые кстати активно сейчас пишутся). Создал своё приложение с нуля... и понял, что ну не хватает мне той модели работы с БД, которую они предлагают. Слишком она уж примитивная. Слишком мало хороших плагинов => долгая разработка проекта обеспечена. Да и как-то медленно у них всё развивается...
Модель рельс мне показалась очень симпатичной, нацеленной именно на продуктивную работу. Конфигурация БД под разработку, тестирование и продакшн чего стоит! Файлы для тестирования, которые генерируются сами(только файл, без тестов :)). Потом хелперы для вьюшек. Процесс разработки идет быстрее и проще, благодаря такой вот модели.

По пунктам:
  1. Гигантское количество действительно крутых плагинов для RoR. Это громаднейший плюс. Многие проблемы решаются установкой этих плагинов.
  2. Разработка "от ссылки" в Django. Это хорошо... для газетных сайтов. Если же ссылка не важна, то лишняя работа обеспечена, потому что без этой настройки ничего не заработает.
  3. Миграции в RoR против ручного обновления таблиц в Django. Это просто неудобно.
  4. Слабый и не всегда понятный ORM у Django. Наверное, blank=True, null=True многих вводит в легкий ступор. Но вообще это нормально. После Hibernate хочется и коллекции также мапить одним махом, однако увы... :)
  5. Django за 3 года обновился с версии 0.9.x до 1.0.x. Слабовато... Рельсы же скоро выйдут третьей версии;
  6. Встроенная возможность тестирования для RoR. Отдельная конфигурация БД для тестирования.
  7. Коммьюнити у RoR больше;
  8. Для RoR есть Aptana, на основе моего любимого тормознутого Eclipse :). Для тех кто не понял - есть удобнейшая IDE для работы именно с RoR. Для Python на эту тему есть только PyDev плагин;
  9. Хостинг для RoR найти проще, хотя вообщем-то всё равно такие проекты нацелены на виртуальные или dedicated сервера;
  10. Админка в django по-моему весьма сомнительный плюс. Её тоже надо пилить, причем весьма и весьма. Хотя да, она красивая. Для тех же рельс наверняка можно найти пару хороших плагинов.

Яндекс выбрал Django!"
Теперь попытаюсь объяснить почему Яндекс выбрал именно Django для пары своих проектов. Мне кажется, что Django при хорошей квалификации программиста предпочтительнее RoR. Он не такой груженный. А то, что нужно - программист допилит... тем более программист Яндекса. Ну и нагрузка тоже решает.

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

(update 22.05.2009)
Disclaimer:
Всегда хорошо изучить всё самому и принять собственное решение. Самый лучший вариант скачать и то и другое, потратить 2-3 недели на освоение обоих фреймворков и принимать решение хотя бы из интуитивных предпочтений(нравится/не нравится).

воскресенье, 17 мая 2009 г.

Принципиально новый научный поисковик

Спешу поделиться очень крутой новостью!

http://www.wolframalpha.com/

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


Примеры запросов:
Интеграл от корня икс на косинус икс:
http://www69.wolframalpha.com/input/?i=integrate+sqrt+x+cos+x
Ноты:
http://www68.wolframalpha.com/input/?i=C+E+G+Bb+D+F%23+A
Икосаэдр:
http://www68.wolframalpha.com/input/?i=+icosahedron%2C+truncated+icosahedron
Биология аспирин против кофеина:
http://www69.wolframalpha.com/input/?i=caffeine+vs.+aspirin

Статистика по имени Анна:
http://www69.wolframalpha.com/input/?i=Anna
Россия:
http://www69.wolframalpha.com/input/?i=Russia
Оттуда же:
"religions | Russian Orthodox (17.5%) | Muslim (12.5%) | Christian (2%)
literacy fraction | 99.4% "
"Russian Orthodox" и "literacy fraction". Откуда такие данные?? :))

Простые числа между 100,000 и 1,000,000
http://www69.wolframalpha.com/input/?i=primes+between+100%2C000+and+1%2C000%2C000

Решение рекуррентных соотношений:
http://www69.wolframalpha.com/input/?i=fibonacci(n)+recurrence
http://www69.wolframalpha.com/input/?i=f(n)%3Df(n-1)%2Bf(n-2)%2C+f(1)%3D1%2C+f(2)%3D2

Теория графов:
Красивый граф:
http://www69.wolframalpha.com/input/?i=12-wheel+graph
Сравнение двух графов:
http://www69.wolframalpha.com/input/?i=Petersen+graph%2C+icosahedral+graph
Некий непонятный граф:
http://www69.wolframalpha.com/input/?i=(10%2C8)+cage+graph

Звездное небо города, в котором вы находитесь:
http://www69.wolframalpha.com/input/?i=star+chart

Общие корни для русского, латинского, испанского и французского языков:
http://www69.wolframalpha.com/input/?i=Spanish%2C+French%2C+Latin%2C+Russian

Сравнение IBM и Apple:
http://www69.wolframalpha.com/input/?i=IBM+Apple

Сравните льва,пуму, лису и человека, особенно интересно генетическое дерево в конце:
http://www69.wolframalpha.com/input/?i=puma%2C+lion%2C+red+fox%2C+human

Короче, новый поисковик уже позволяет реально извлекать знания. Я в восторге :))
p.s.: всё же раз в 10 лет появляется нечто новое :))

четверг, 12 марта 2009 г.

"Абстракция"

public abstract class AbstractClass
{

public abstract String getValue();

public static class RealClass extends AbstractClass
{

@Override
public String getValue()
{
return "Внутренний класс";
}
}

private static final AbstractClass CLAZZ = new AbstractClass()
{
@Override
public String getValue()
{
return "Анонимный класс";
}
};

public static AbstractClass getClazz()
{
return CLAZZ;
}

public static void main(String[] args)
{
AbstractClass clazz = new RealClass();

System.out.println(AbstractClass.getClazz().getValue());
System.out.println(clazz.getValue());
}
}

пятница, 6 февраля 2009 г.

MS SQL 2005. Работа из консоли (sqlcmd)

В MS SQL 2005 появилась(заменила другие) консольная утилитка sqlcmd. Она предназначена для работы с MS SQL 2005 при помощи консоли.
Формат вызова у неё такой:
Использование: Sqlcmd    [-U идентификатор_входа]  [-P пароль]
[-S сервер] [-H имя_узла] [-E доверенное_соединение]
[-d имя_используемой_БД] [-l время_ожидания_входа] [-t время_ожидания_запроса]
[-h заголовки] [-s разделитель_столбцов] [-w ширина_экрана]
[-a размер_пакета] [-e отображать_ввод] [-I идентиф.в_кавычках]
[-c конец_команды] [-L[c] вывести список серверов[очистить_вывод]]
[-q "запрос_ком.строки"] [-Q "запрос_ком. строки" и выйти]
[-m код_ошибки] [-V уровень_серьезности] [-W удал.конечные пробелы]
[-u вывод_в_юникоде] [-r[0|1] вывод на STDERR]
[-i входной_файл] [-o выходной_файл] [-z новый_пароль]
[-f <кодовая_страница> | i:<кодовая_страница>[,o:<кодовая_страница>]]
[-Z создать пароль и выйти]
[-k[1|2] удалить[заменить] управляющие символы]
[-y ширина_экрана_переменного_типа]
[-Y ширина_экрана_фиксированного_типа]
[-p[1] печатать статистику [формат столбцов]]
[-R использовать региональные настройки клиента]
[-b завершить выполнение командного файла при ошибке]
[-v переменная = "значение"...] [-A выделенное административное соединение]
[-X[1] отключить команды, сценарии запуска, переменные среды [и выйти]]
[-x отключить подстановку переменных]
[-? показать сводку по синтаксису]

Это значит, что можно создать файл скрипта, например для восстановление БД и
не лезть в тормознутую SQL Management Studio.
Файл restore.sql:

RESTORE DATABASE my_database FROM DISK = 'D:/DB/Backups/my_db.bak'
WITH REPLACE
[можно ещё добавить действий по смене владельца таблиц, обработке, добавлению данных т.д.]

Тогда этот скрипт можно выполнить следующей командой:

>sqlcmd -d my_database -i "C:/scripts/restore.sql" -o result_restore.txt

Результат восстановления БД будет выведен в файл result_restore.txt.
Также можно непосредственно выполнять команды при помощи этой утилиты:
>sqlcmd -d my_database
1>:out result.txt //выведет результаты в файл
1>exit(select * from TBL_SAMPLE) //выполнит запрос и выйдет

Можно заюзать так:
>sqlcmd -d my_database -q "select * from TBL_SAMPLE"
Выведет результаты выполнения скрипта на экран.

Вообщем консоль способствует повышению эффективности труда :)

четверг, 5 февраля 2009 г.

Hibernate. Атрибут inverse

При работе с Hibernate часто ли вы задумываетесь зачем и для чего нужен атрибут inverse и что означает inverse = "true"? В данной заметке будут раскрыта эта тема.


По существу, "inverse" обозначает какой конец отношения должен игнорироваться. Когда вы сохраняете предка, имеющего коллекцию потомков, должны ли вы спрашивать предка о его потомках, или же спрашивать потомков, кто является их предком?

Итак взгляните на код:
Parent parentA = new Parent();
Parent parentB = new Parent();
Child child = new Child();
parentA.getChildren().add(child); // с помощью самого предка
child.setParent(parentB); // с помощью установления предка у потока

как hibernate сохранит эту ситуацию? Для однонаправленной связи one-to-many это очевидно; только один конец отношения создаётся (это только parent.addChild(), не child.setParent()), но когда связь является двунаправленной (parent.getChild и child.getChildren), то вы должны указать, является ли one-to-many обратным(inverse) или нет.

Что значит быть обратным? Это информирует hibernate, что нужно игнорировать конец отношения. Если отношение one-to-many отмечено, как обратное, hibernate будет создавать child-> parentB отношение (child.getParent). Если one–to–many отношение не было помечено, как обратное, тогда child->parentA отношение будет создано.


Просто запомните следующую вещь:
  • если inverse = "true" на one–to–many, тогда child.getParent будет вызван.
  • если inverse = "false" на one–to–many, тогда parent.getChildren будет вызван.

вторник, 27 января 2009 г.

Сюрприз C/C++ структуры (Data structure alignment)

Казалось бы, что размер структуры в C/C++ элементарно равен сумме её частей(прим. лично я так думал).

struct Vector {
int x;
int y;
int z;
};


Большинство скажет: sizeof(Vector) == 3 * sizeof(int) . int как правило равен 4 байтам, т.е. данная структура по идее должна занимать 12 байт. Теоретически - это так. Но (!) практически - как выставите опции компилятора.

Данная "фича" называется "Выравнивание" или "Data Structure Alignment". Она выравнивает размер структуры данных до кратного некоторому числу(естесственно степени 2), например 2, 4, 8. Располагает данные в нужном порядке, а между ними размещает "заполнитель" :) пустоту вобщем.

Для чего это нужно? Здесь описано. Вкратце, это оптимизация данных для ускорения доступа. Как всегда, есть некая точка равновесия между размером данных и скоростью доступа к ним. Короче, должно быть использовано с умом и пониманием.

К каким последствиям это может привести? Последствием может быть неправильное чтение/запись структуры, если оно чётко определено стандартом. Это могут быть различные заголовки файлов, данные и т.д. Такое бы уже не прошло:
read(file, &my_struct, sizeof(my_struct));
write(file, &my_struct, sizeof(my_struct));


Для меня эта новость была неожиданной и привела к нескольким часам выяснения, почему заголовок BMP файла читается неправильно. Оказалось, что IDE Borland Turbo C++ по умолчанию выставлял опцию компилятора - выравнивание в 4 байта.
Вообще заголовок BMP файла должен был занимать 14 байт, но sizeof(BMPHeader) упорно возвращал 16! И из-за этого я никак не мог прочитать смещение до самих данных.
Выставить нужно смещение можно либо выставив опции компилятора, либо директивами:
#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1) /* set alignment to 1 byte boundary */

/** твоя структура */

#pragma pack(pop) /* restore original alignment from stack */

p.s.: компилятор borland и IDE Borland TurboC++ используются сугубо по требованию преподавателя.

понедельник, 19 января 2009 г.

Ответы на вопросы для собеседования по Java SE (Часть 2)

Продолжаю цикл статей, посвященных ответам на вопросы по Java Core.
Ответы на вопросы для собеседования по Java SE (Часть 1)
Ответы на вопросы для собеседования по Java SE (Часть 3)

Следующие 5 вопросов, тесно связаны с пятеркой предыдущих вопросов, поэтому повторяться не буду. Напишу краткие ответы:

6. Какая связь между hashCode и equals?
Объекты равны, когда equals и hashCode возвращает одни и те же значения. Но необязательно, чтобы два различных объекта возвращали различные хэш коды(такая ситуация называется коллизией).

7. Каким образом реализованы методы hashCode и equals в классе Object?
Реализация метода equals в классе Object сводится к проверке на равенство двух ссылок:

public boolean equals(Object obj) {
return (this == obj);
}


Реализация же метода hashCode класса Object сделана нативной, т.е. определенной не с помощью Java-кода:
public native int hashCode();
Он обычно возвращает адрес объекта в памяти.

8. Что будет, если переопределить equals не переопределяя hashCode? Какие могут возникнуть проблемы?
Они будут неправильно хранится в контейнерах, использующих хэш коды, таких как HashMap, HashSet.

9. Есть ли какие-либо рекомендации о том, какие поля следует использовать при подсчете hashCode?
Есть. Необходимо использовать уникальные, лучше примитивные поля, такие как id, uuid, например. Причем, если эти поля задействованы при вычислении hashCode, то нужно их задействовать при выполнении equals.
Общий совет: выбирать поля, которые с большой долью вероятности будут различаться.

10. Как вы думаете, будут ли какие-то проблемы, если у объекта, который используется в качестве ключа в hashMap изменится поле, которое участвует в определении hashCode?
Будут. Опять же будут проблемы связанные с хэш коллекциями. А именно, не сможем выбрать элемент из хэш-коллекции, его как будто и не будет.
----

Продолжение следует...

воскресенье, 18 января 2009 г.

Ответы на вопросы для собеседования по Java SE (Часть 1)

Добрый, предобрый день.
В сети распространены различные варианты вопросов на собеседование по Java SE6. Но ответов на эти вопросы нет. Подумав, я решил, что это очень интересная тема для поста и дальнейшего обсуждения. И поэтому начинается цикл статей, посвященный ответам на вопросы по Java Core. За основу я взял 50 вопросов для интервьюирования.
Итак первые 5 вопросов с моими вариантами ответов:

1. Что такое класс Object? Какие в нем есть методы?
Object это базовый класс для всех остальных объектов в Java. Каждый класс наследуется от Object. Соответственно все классы наследуют методы класса Object.
Методы класса Object:
  • public final native Class getClass()
  • public native int hashCode()
  • public boolean equals(Object obj)
  • protected native Object clone() throws CloneNotSupportedException
  • public String toString()
  • public final native void notify()
  • public final native void notifyAll()
  • public final native void wait(long timeout) throws InterruptedException
  • public final void wait(long timeout, int nanos) throws InterruptedException
  • public final void wait() throws InterruptedException
  • protected void finalize() throws Throwable
Замечание: Для полноты обзора можно сказать, что существует ещё один метод private static native void registerNatives() .

2. Что такое метод equals(). Чем он отличается от операции ==.
Метод equals() обозначает отношение эквивалентности объектов. Эквивалентным называется отношение, которое является симметричным, транзитивным и рефлексивным.
  • Рефлексивность: для любого ненулевого x, x.equals(x) вернет true;
  • Транзитивность: для любого ненулевого x, y и z, если x.equals(y) и y.eqals(z) вернет true, тогда и x.equals(z) вернет true;
  • Симметричность: для любого ненулевого x и y, x.equals(y) должно вернуть true, тогда и только тогда, когда y.equals(x) вернет true.
Также для любого ненулевого x, x.equals(null) должно вернуть false.
Отличия equals() от операции == в классе Object нет. Это видно, если взглянуть исходный код метода equals класса Object:

public boolean equals(Object obj) {
return (this == obj);
}Syhi-подсветка кода
Однако, нужно не забывать, что, если объект ни на что не ссылается(null), то вызов метода equals этого объекта приведет к NullPointerException. Также нужно помнить, что при сравнении объектов оба они могут быть null и операция obj1 == obj2 в данном случае будет true, а вызов equals приведет к исключению NullPointerException.
Как мы видим, при помощи операции == сравниваются ссылки на объекты. Но мы можем переопределять метод equals, тем самым задавая логику сравнения двух объектов. Например, рассмотрим сравнение двух одинаковых чисел, созданных при помощи класса Integer:

Integer a = new Integer(6);
Integer b = new Integer(6);
System.out.println(a == b); // false т.к. это разные объекты с разными ссылками
System.out.println(a.equals(b)); // true, здесь уже задействована логика сравненияSyhi-подсветка кода
Если взглянуть внутрь метода equals класса Integer, то мы увидим:

public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}Syhi-подсветка кода
Понятно, что тут уже нет сравнения ссылок, а сравниваются int значения.

3. Если вы хотите переопределить equals(), какие условия должны удовлетворяться для переопределенного метода?
Эти условия приведены в пункте 2.

4. Если equals() переопределен, есть ли какие-либо другие методы, которые следует переопределить?
Да, есть.Нужно переопределить метод hashCode(). Равные объекты должны возвращать одинаковые хэш коды. Например у класса Integer метод hashCode() переопределен следующим образом:

public int hashCode() {
return value;
}Syhi-подсветка кодаvalue это private значение, которое хранит объект класса Integer. Собственно это и есть число.

5. Для чего нужен метод hashCode()?
Для начала вспомним, что такое хэш и хэширование. Теперь вспоминаем такие известные классы, как HashMap, HashSet, Hashtable, в основе которых лежит вычисление хэш-функции. Именно за счет хэша мы можем вставлять и получать данные за O(1), то есть за время пропорциональное вычислению хэш-функции.
Например, рассмотрим вставку элементов в HashMap:

public V put(K key, V value) {
...
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
...
addEntry(hash, key, value, i);
...
}Syhi-подсветка кода
Как мы видим, i-е место вставки объекта вычисляется при помощи хэша. А для вычисления нам нужна хорошая хэш функция, чтобы давала равномерное распределение и поменьше коллизий.
То есть ответ на вопрос заключается в том, что существуют коллекции(HashMap, HashSet), которые используют хэш код, как основу при работе с объектами. А если хэш для равных объектов будет разным, то в HashMap будут два равных значения, что является ошибкой. Поэтому необходимо соответствующим образом переопределить метод hashCode().



Пока, что всё. Впереди нас ждет много интересных вопросов!
До встречи.

Продолжение:
Ответы на вопросы для собеседования по Java SE (Часть 2)