Мой open source велосипед

    “Воин не бросит начатое.”
    Мастер Шифу, м.ф. Кунг-фу Панда


    Можно рассматривать этот топик не как технический, а как художественный. Тут не будет кусков кода, диаграмм классов и прочей ерунды. Будет история одного java open source проекта, который я разрабатываю уже около года.

    Начало


    Все началось, когда я был на четвертом курсе одного провинциального российского университета. С семестра, о котором ходили легенды на моей специальности, как о “семестре-убийце“ с его 55-ю лабораторными работами по графике, компиляторам и вычислительной математике (далее ВМ).

    Когда в начале семестра думаешь о предстоящей большой и скучной (а в университетах как правило, все скучно) работе, не редко начинают опускаться руки. К счастью, у меня уже был проверенный временем рецепт “бесконечного энутизиазма”. Смысл его заключался в “бесконечном познании неизвестного” (с) Стругацкие, Понедельник начинается в субботу. Проще говоря, я каждый раз старался хоть как то извратить стандартный учебный процесс, чтобы он стал хоть немного интереснее для меня. Было испробовано большое количество способов — Linux на рабочей машине (с драйверами от ATI), непопулярные в университетских кругах языки (читай не С# и C++) и среды разработки (читай не VS2008), баг-трекеры для заданий, локальные репозитории кода для лабораторных и т.д.

    Тогда я и решил начать писать свой open source проект, представляющий собой агрегацию лабораторных работ по курсу ВМ в виде java библиотеки c прозрачным и привычными для java-программистов API.

    Я создал проект на Google Code, придумал название библиоткеи и работа началась. Каждая следующая лабораторная по курсу ВМ представляла собой пачку коммитов в репозиторий библиотеки. Это было что-то новое для меня и помогало мне поддерживать энтузиазм на протяжении всего курса.

    По окончанию курса la4j (Linear Algebra for Java) доросла до версии 0.0.7 и уже умела работать с векторами и матрицами, решать системы линейных уравнений 6-ю различными способами и находить собственные числа и вектора матриц.

    Середина


    После окончания курса ВМ я почти не занимался проектом, курс кончился — энтузиазм иссяк. Все изменилось, когда начался новый курс — Шаблоны проектирования.

    Этот курс меня невероятно заинтересовал, я даже начал писать об этом цикл статей на Хабрахабре. Но главное тут то, что я осознал все ошибки, которые когда-то совершил в la4j. Терпеть этого я не мог и вооружившись удобными инструментами рефакторинга Eclipse я начал кромсать код. Так получилась версия 0.1.0. Версия, которую уже не стыдно было кому-то показать. Она имела приятный ООП дизайн, небольшой но достаточный функционал. А самое главное — это был результат достаточно большой работы от которой я чувствовал удовлетворение.

    Не могу сказать, что до этого этапа я позиционировал la4j как open source проект. Я воспринимал это как свое хобби, как площадку для оттачивания своих знаний и умений. Я просто делал это just for fun.

    Потом на какое-то время я снова позабыл про la4j и начал усиленно заниматься рабочими делами, совмещая учебу и работу. Волею судьбы я стал заниматься производительность Java платформы на работе и этот факт заставил меня по-новому взглянуть на вычислительные алгоритмы внутри la4j.

    Я попытался применить полученный опыт performance анализа и оптимизаций в la4j. Так родилась статья “История одной оптимизации”, которая вызвала у хабрапользователей большой интерес к моему проекту. В тот момент я получил большое количество отзывов, а самое главное — предложений помощи. Несколько человек изъявили желание помочь мне дальше развивать проект.

    Тогда мне казалось, что сейчас все изменится. Люди начнут писать код и полетит куча коммитов в мой репозиторий. Но этого не произошло.

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

    Потом, я закончил университет и устроился на постоянную работу. Скажу лишь, что работать мне нравилось намного больше чем учиться. У меня была куча свободного времени, которое я тратил впустую, пытаясь отдохнуть от защиты диплома и марафона длиною в 5 лет.

    В сентябре, все студенты начинаю учиться и у меня как у собаки Павлова сработал условный рефлекс — нужно писать лабораторные, учить функциональный анализ и т.п. Тогда я вспомнил про la4j и решил, что должен ее закончить. Закончить не потому, что «решение систем ЛУ — очень важная и актуальная проблема современности», а просто потому что, я когда то это начал и не довел до конца.

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

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

    И …

    Почти конец


    Несколько дней назад, я закончил работу над версией 0.2.0. Было проделано очень много работы, принято много технических и не-очень решений, спроектировано и реализовано 55 классов, написано 6700 строк кода и около 80 jUnit тестов. Надеюсь мой труд не пропадет зря, и станет еще одним удобным инструментом в портфеле любого java-разработчика.

    Конец


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

    В: “На Java никто вычисления не пишет, закопать!”
    О: “Пишут. Более того, еще и не хотят использовать обертки над BLAS из за привязки к нативной платформе”.

    В: “Есть же JAMA, зачем еще один велосипед?”
    О: а) Потому что он свой. б) JAMA не поддерживает разреженые матрицы. в) JAMA не поддерживает ввод/выввод. в) у JAMA ужасный API. г) у JAMA ужасная производительность.

    Ресурсы



    UPD: На днях стала доступна версия 0.4.0 (03.06.2013)

    UPD: Тихо и незаметно вышла версия 0.4.5 (02.10.2013)
    Метки:
    Поделиться публикацией
    Комментарии 30
    • +3
      Спасибо. Отличная статья и отличная библиотека. Добавлю в закладки.
    • +4
      Рефлекс как у собаки Павлова — хорошо сказано. Который год думаю «выйду в отпуск, появится время, допишу свой проект». И вот наступает долгожданный, какой там проект — отдыхать!
      • +8
        Отличная история, спасибо.
        Однако это замечание

        > Кроме того, любая критика без ссылки на собственный open source проект восприниматься не будет

        весьма подпортило впечатление. Критика, сопровождаемая аргументами и обоснованиями, очень ценна, и не важно, от кого она исходит. Лучше получить к ней в нагрузку необоснованные нападки и проигнорировать их, чем не получить ничего.
        • +1
          Может быть зря перестраховался от агресивно-настроенной публики Хабра. Может быть вы и правы, сейчас уберу.
          • 0
            И сразу вопрос:
            зачем класс объявляется аж так: public class Complex extends Object?
            extends Object явно лишнее и не способствует быстрому чтению и пониманию
            • 0
              Этот класс — открытый проект, я просто его включил в la4j.

              Вот хедер же:

              /**
              * Complex implements a complex number and defines complex
              * arithmetic and mathematical functions
              * Last Updated February 27, 2001
              * Copyright 1997-2001
              * @version 1.0
              * @author Andrew G. Bennett
              */
              • 0
                имя автора мне ничего не сказало, так как Вашего не знаю :) может это и Вы :) вот ссылка на проект было бы хорошо…
                • 0
                  Ссылки никакой нет, этот человек просто где-то выложил свой клласс. Я даже не помню где его скачал. Гдето в google «java complex class».
              • +3
                посмотрел глубже — видимо один такой попался и я сразу на него наткнулся :)
                а вообще код чистый, С КОММЕНТАРИЯМИ! :)
                • +4
                  Кстати сначала писал их, потом даже специально стал вырезать. Не нужны они. Нужна документация, в данном случе javadoc с сылками к теории, например в википедию.

                  А любой коментарий устаревает сразу после того, как вы напишите "//".
                  • +1
                    лучше код с документацией, чем такой же но без оной. Особенно когда видишь что-то типа:

                    public void updatePrios(final MultiMap<Pair<Lang,String>,Triple<Source,Integer,Boolean>> newPrios, final int type) {

                    :)
                    • +3
                      Ну что нужна документация я написал.

                      Только напишите, что это не мой код :) А то щас пост заминусуют :)
                      • 0
                        не Ваш не Ваш ))
                        просто знаю места, где искать 8-)
                    • +2
                      Поддерживаю: код изменяется, а комментарий остается.
            • 0
              Спасибо.
              > непопулярные в университетских кругах языки
              А какие?

              У вас хорошая обстановка на кафедре по сравнению с моей, даже несмотря на
              «непопулярные в университетских кругах языки (читай не С# и C++) и среды разработки (читай не VS2008)».
              У нас не давали практически ничего из того, что нужно давать. Шаблоны проектирования? Ну что вы… Их даже не упоминали. Функциональное программирование? Только в виде галочки в учебном плане… Приходилось многое, очень многое изучать самому, а многие преподаватели даже тематику подсказать не могли, — некомпетентность была и остается удручающая.

              P.S. У меня тоже есть свой open-source проект. ;)
              • 0
                Я бы сказал, в моем вузе отличная обстановка на кафедре, отличные преподаватели, умные ребята. Из-за объемов материала правда учиться невсегда приятно, но это мелочи.

                А по поводу изучать самому — уж извольте. Вы высшее образование получаете, вас никто ничему не обязан учить. Ест даже фразеологизм «Научить — невозможно, можно только научиться.» Вас этому и учат на самом деле, учать не матану, вычмату и компиляторам, а учат — учиться и в сжатые сроки, в новой среде предоставлять результат. Инженерия чо уж там :)
                • 0
                  > А по поводу изучать самому — уж извольте. Вы высшее образование получаете, вас никто ничему не обязан учить.

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

                  А так, безотностиельно себя, — да со всем согласен.
                  • +1
                    Никого не хотел обидеть и из комментария подумал что вы — студент. Прошу прощения если что.
                    • 0
                      Никаких обид, что вы. :)

                      Так какие еще языки вы использовали в своей учебной деятельности? Java? Может, еще что-нибудь?
                      • +1
                        Университетская программа мягко говоря заточена на С++ (даже тот что managed C++/CLI) и С# и конечно все это добро должно было писаться в VS2005 а потом и 2008 + Лисп и Пролог как части курсов по ФП. Все остальное — на усмотрение студента.

                        У меня это было, что-то вроде Java, Python + PyQT + numpy, Perl, совсем чуть-чуть PHP. Были эксперименты писать на GTK/QT (на Linux) ну и конечно Mono :)
                        • 0
                          Список достоин уважения. Сейчас не все мои бывшие сокурсники-то готовы изучать что-то помимо стандартных C#/С++, что уж говорить о студентах… Кстати, не знаю, что вы имеете в виду под «заточкой на С++», — сейчас я жалею, что ФП у нас толком не было, потому что для многих своих университетских программ я бы выбрал Haskell. Впрочем, и на «плюсах» неплохо все получалось, но считаю, что изучать новые языки, средства и технологии, надо. Раз в год осваивать новый язык, — очень хорошо, но можно и раз в полгода, не повредит. С другой стороны, кроме языков программирования есть еще огромный пласт знаний, — та же автоматизация (сборка, системы контроля версий), те же шаблоны проектирования, то же ФП…

                          • 0
                            > Раз в год осваивать новый язык, — очень хорошо, но можно и раз в полгода, не повредит.

                            В одной чудесной книге — «Программист-прагматик» именно так и написано. Еще написано, что нужно одну книгу (техническую) хотябы раз в три месяца чиать. Тогда портфель знаний будет на уровне :)

                            А заточка на С++ — это просто когда тебе читают курс ООП и фиктивный (управляемый) указательна С++/СLI называют «крышечкой» без объяснения что это и зачем. Был у нас грешок на кафедре. Преподаватель ООП, до сих пор обидно, что такой отличный курс, так погано было преподнесен.
                            • +1
                              С ООП не только у вас плохо, у нас тоже было, стыдно сказать, изучение Delphi / Builder'a со словами «а вот это — класс». Хотя это далеко не ООП, — это самые-самые начала ООП. В общем, этого курса тоже, можно сказать, не было.

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

                              Сейчас я преподаю не на своей кафедре (ИВТ), но на родственной к ней (ПИМ). Если все сложится хорошо, на следующий год попробую забрать себе функциональное программирование у своего бывшего преподавателя. К сожалению, все его предметы были «спустя рукава», — потому что он хоть и профессор, а выпить горазд. В итоге его держат ради его звания, — есть негласные показатели, когда на кафедрах должно быть столько-то кандидатов, столько-то докторов. И с каждым годом эти цифры выдерживать труднее, потому что аспирантов очень мало, докторантов еще меньше. В этой статье написано правильно: чувствуется разрыв поколений.
                  • –1
                    Вы высшее образование получаете, вас никто ничему не обязан учить.
                    Тогда следует переименовать его в «высшее самообразование», чтобы не смущать людей. И, конечно, ни дай бог вам когда-нибудь воспользоваться услугами проктолога-самоучки.
                • +1
                  Пару мелких замечаний по коду.

                  1. класс AbstractVector и интерфейс Vector: во-первых, из объявления интерфейса неясно, какую фабрику векторов будут использовать методы без аргумента `factory`. Нужно выбрать либо вариант, когда фабрика передаётся в конструторе, либо в каждом методе. На мой взгляд, первый вариант лучше. во-вторых, почему одни методы могут выкидывать эксепшен, а другие нет — хотя имя у них одно (это касается интерфейса)?

                  2. интерфейс IOConstants: очень плохая практика использовать интерфейс в качестве хранения констант, а потом его имплементить. Основное предназначение интерфейса — описание методов объекта. Константы — это уже конкретика реализации и для них есть простые классы либо перечисления (enum). Тем более IOConstants не объявляет ни одного метода.

                  3. имплементации интерфейсов и относящиеся к ним классы лучше выносить в отдельный под-пекедж `impl`, если вы хотите отделить абстракцию от конкретики (и так удобней будет иметь один api и несколько реализайций)

                  4. Поля, которые не предполагается менять, лучше делать `final`. Например в LinearSystem поля a, b не переопределяются (пусть даже сами поля изменяемы (mutable), но ссылки на них постоянны) — их можно сделать final.

                  • 0
                    Спасибо за замечания!

                    1) Я думал над тем, чтобы передовать фабрику в конструкторе, но на мой взляд это лишняя операция. По умолчанию просто создается ассоциированная с типом вектора фабрика. Это была большая проблема: понять какой именно вектор нужно создавать например при сложении двух: плотный + разреженый = плотный, а плотный * разреженый = разреженый. Я решил использовать фабрики и сделать так чтобы пользователь мог просто умножать вектора не думая о том какой будет результат, для этого и нужна фабрика, которая инстанциируется по-умолчанию. Если пользователь знает что ему нужно — передает фабрику.

                    2) Идея взята из download.oracle.com/javase/1.4.2/docs/api/java/io/ObjectStreamConstants.html Я знаю что практика плохая, Effective Java читал. Просто хотел сделать что-то очень похожее на классы из java.io.

                    3) Хорошее замечание, но я не хотел сильно перегружать API. Все должно было быть просто. Хотя я тут согласен, практика хорошая.

                    4) Согласен.
                  • 0
                    Решил сообщить для неравнодушных. Версия la4j-0.3.0 доступна для загрузки.

                    Новый официальный сайт: la4j.org
                    Relase notes: la4j.blogspot.com/2012/12/la4j-030-is-out.html
                    la4j @ GitHub: github.com/vkostyukov/la4j

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.