воскресенье, 12 октября 2014 г.

Про поиск в одном отдельно взятом проекте

Тема обработки данных в общем и поиска чего-то осмысленного в них, в частности, мне уже очень давно была интересна. С неструктурированными данными сложнее, там всякий ML, так что пока говорим про простой случай - полнотекстовый поиск. На некоторых больших проектах мы лишь обрабатывали и готовили данные, но потом я попал на небольшой проект, где надо было делать полный цикл, от подготовки данных до интерфейса поиска. Там я увидел, что поисковый движок может быть центральным элементом системы и точкой входа для пользователей. За ElasticSearch наблюдаю с тех пор. Мы использовали Solr, но уже тогда ES, ещё не дошедший до 1.0, выглядел гораздо интереснее. Мне интересно делать не абстрактные вещи, а приближенные к реальности, так что давно хотел и вот решил вкрутит его в Targetprocess. Данная статья фактически введение в основные фичи ES. Так что знатоки могут проходить мимо. Во-вторых, они будут рассказываться применительно к полнотекстовому поиску в Targetprocess, поэтому если для кого-то это реклама, писать комментарии об этом не надо, просто не читайте.

суббота, 28 декабря 2013 г.

Субботний вечер пропаганды маргинальных технологий: Go! Go! Go!

Практически сразу после предыдущего поста хотел написать про Go. За ним я следил с самого его объявление, всё таки делает его небезызвестная "Корпорация Добра", но в этом году несколько раз использовал и много какие проекты на нём плотно изучал. Хотел разобраться сильнее, чтобы более объективно/полно описать и поэтому откладывал. Но всё таки пришёл к тому, что основным, хотя даже и в топ 5 моих языков он не войдёт. Будет вспомогательным. Для чего, чуть ниже, но вначале небольшой дисклаймер. На Go суммарно я написал наверно максимум пару сотен банальных строк кода, поэтому этот пост будет очень небольшой и чтобы его дополнить расскажу про интересные проекты написанные на нём (не много будет пересекаться с предыдущим постом), так что профи - проходите мимо, но может заинтересует тех кто об этом языке не знал.

суббота, 9 ноября 2013 г.

Краткий сказ о неудавшемся администраторе

И снова долго не писал, в этот раз больше двух лет получается. Вроде даже мыслей и клёвых штук вокруг много, но как-то не мог себя заставить, но надо, иначе совсем зачахну. Решил начать с простого, рассказа о последних полутора годах моей работы. А работал я системным админимстратором, вернее оперейшен (в бывшем и могучем - это называлось оператор ЭВМ), вообщем автоматизировал и поддерживал инфраструктуру для hosted/ondemand/saas версии Targetprocess. Под катом краткая история с рассказом/перечислением интересных тулов с которыми пришлось поработать или просто читать.

пятница, 9 сентября 2011 г.

Akka actors: Первое неоднозначное впечатление

Давно я ничего не писал, хотя в draft лежит много чего, в том числе интересного. Но эта статья носит немного другой, как мне кажется, не технический, а больше эмоциональный характер, поэтому решил её долго не пилить и выложить, тем более в twitter обещал отписаться о моём опыте.

Ситуация такая. Есть у нас маленький, как считалось не слишком важный, кусочек кода, который переносит данные из oracle в mongo с небольшими преобразованиями. Через некоторое время, как обычно, оказалось, что он не такой уж и неважный, поэтому возникла задач быстро его немножко ускорить. Особо оптимизировать в коде нечего было, поэтому ускорение можно было предать параллелизацией некоторых его частей, благо код был разделен на достаточно независимые части. Для этого я решил в порядке эксперимента воспользоваться интересно библиотекой Akka, написанной на Scala, но разработчики поддерживают удобное api и документацию и для Java. Это мой первый опыт с данной библиотекой, так что никаких откровений тут не будет, да и в целом, как я ранее написал, статья больше эмоциональная, нежели техническая.

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

JQuery: Slider + Table или я в роли доктора Франкенштейна

Для тех, кто меня не очень хорошо знает, этот пост может показаться несколько бессмысленным (слишком он в духе К.О.), поэтому объясню. Уже пару лет я занимаюсь по большей части backend приложениями (как в рабочее, так и в свободное время). Тут предоставилась возможность поработать над прототипом с web интерфейсом. Вот и хотел поделится своими ощущениями, что сейчас это уже выглядит не так страшно, вроде бы.

Стоит задача сделать что-то похожее на Google Finance StockScreener. В первом приближении необходима приятная табличка (с сортировкой и разбитием на страницы) и слайдер, с помощью которого можно отфильтровать данные, отображаемые в этой таблице. Слайдер уже есть практически из коробки: JQuery UI Slider. В качестве таблицы выбор пал на Data Tables. Осталось только их соединить так сказать вместе и об этом и будет этот небольшой пост.

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

Мир вверх тормашками или код как данные

Я тут в очередной раз пытаюсь перечитать (но уже печатную) SICP. Вторая глава там: Построение абстракций с помощью данных. Действительно, чтобы мы делали, если бы нельзя было из примитивных типов строить что-то побольше. И мне там очень понравился один примерчик. Про его и хочу рассказать. Если выключить машину времени и вернуться в реальность без скобочек, то в мейнстримных сейчас в наших палестинах C#/Java обычно для этих целей мы используем классы. Книжный пример рассказывал о паре. В C# для этих целей есть класс Tuple (там правда не только пара, но нам сойдёт). Так вот, а давайте представим, что в C# не было бы специальной конструкции языка class (ну и struct заодно). Как же теперь нам сделать пару или любую другую сложную структуру данных из примитивов языка? Я уже в статье раньше рассуждал немного о философской проблеме ООП языков: кто должен быть this'ом. Так вот под катом пример на C# (переделанный из SICP) демонстрирующий ненужность this :)

среда, 20 апреля 2011 г.

JLine: Интерактивная Java Console в стиле Quake

Каждому программисту в жизни приходилось писать небольшие консольные утилитки. Обычно это выглядит как бесконечный цикл чтения строки, парсинга её и выполнение. Но визуально это всегда выглядит не очень, да и пользоваться трудно. Но мне как-то пришлось писать такую консольную утилитку, с которой должны работать нормальные люди :) поэтому задумался (после соответсвующего пинка :))) над её усовершенствованием в стиле Quake, т.е. сделать такую консольку более интерактивной. Конечно же писать самостоятельно в 2011 году наверно глупо. Немного поискав, остановился на наилучшем, на мой взгляд, варианте: JLine. Перечислю те вещи, за которые она мне больше всего приглянулась:

  • История команд, по которой можно легко перемещаться с помощью стрелочек.
  • Редактирование строки. В стандартном java console приложении невозможно отредактировать символ внутри уже набранной строки, приходится удалять весь хвост.
  • Автодополнение команд с помощью tab. Легко настраиваемое, но при этом с хорошим стандартным набором

В этом посте я набросаю простенькую консоль, поддерживающую команды, которые можно легко будет добавлять (для этого задействуем Google Guice).

суббота, 26 марта 2011 г.

Субботний вечер пропаганды маргинальных технологий: Статистический анализ с помощью clojure и incanter

Начну из далека. Все прекрасно знают, что Java код компилируется в платформа независимый java bytecode. Sun'ики этого не планировали, но, так же как и для CLR, появились альтернативные языки, компилируемые под JVM. Зачастую это порты других известных языков: Jython (Python), JRuby (Ruby), Kawa (Scheme). Они пользуются небольшой популярностью по очевидной причине, люди предпочитают использовать не порт, а настоящий язык. Но есть языки разработанные специально для JVM. Например Groovy, солянка Ruby и Java, заполучил своё место под солнцем как скриптовый язык, часто используется, как основа более гибких конфигураций, нежели статический xml и вроде веб на нём тоже делают. Ещё есть Scala, мельтипарадигменный язык, который совмещает в себе огромную кучу фич из ООП и ФП. Мне он не очень нравится перегруженностью синтаксиса, но он набирает популярность как замена Java. Но сегодня я хотел бы поговорить о Clojure - это функциональный язык, диалект великого Lisp'а. Ах, нет, я хотел обмануть, про замечательный язык clojure я не стану рассказывать детально в этой статье, лучший способ с ним познакомиться это одноименный раздел на сайте Алекса Отта. Там же есть постоянно обновляющаяся вводная статья написанная Алексом для журнала fprog.

Я участвую в проекте по обработке данных. Предыдущая версия использовала MS Sql Server для своей работы, поэтому анализ работы системы сделать было достаточно просто, можно было обойтись и простым t-sql скриптом или, если нужно было графическое представление, то можно было использовать Reporting services. Сейчас же, для того компонента, которым я занимаюсь, никакие СУБД не используются, поэтому какие-то выводы можно делать исключительно по логам. Поэтому даже был сделан отдельный структурированный лог в csv формате обо всех важных событиях, произошедших в системе. К примеру, к нам приходит много файлов, поэтому для каждого из этих фалов, этот лог содержит упрощённо 3 записи: файл найден, файл отправлен на обработку, файл обработан. Как то у Ярослава возникла идея попробовать язык R, чтобы нарисовать какие-нибудь интересные аналитические графики. Меня идея заинтересовала, я скачал книгу и впал в ступор. В общем и целом, язык этот мне не понравился (можно сказать не осилил:)). Но месяц назад в очередном порыве изучения clojure, у Алекса наткнулся на упоминания о проекте incanter. Лучше всего его описали сами авторы:

Incanter is a Clojure-based, R-like platform for statistical computing and graphics.

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

понедельник, 7 марта 2011 г.

Две стороны одной медали: удобство разработки

Хотел немного подробнее раскрыть упомянутый в предыдущем посте антипаттерн "Immutable Class", изобретение которого принадлежит моей клавиатуре. В данном конкретном случая, это была попытка в Java реализовать Immutable object. И тут возникла проблема, которая всегда актуальна в спорах "динамическая типизация vs статическая типизация". Т.е. с одной стороны можно сделать конечный код (который использует этот класс) более простым, с другой стороны мы получаем ошибки, которые, как правильно в исходном посте заметил Андрей не находятся компилятором. И это действительно произошло, у людей были проблемы с модификацией этого класса, из за чего он и был наречён immutable. Хотел бы более развёрнуто описать почему я так решил, вернее почему мне кажется, что ответ на это вопрос не так однозначен. В самом исходном посте одну из причин я уже указывал, это наследования с огромным количеством переопределенных методов. Тут хотел рассмотреть вопрос удобства изменения только этого класса. Комментарии и в особенности критика приветствуются.

воскресенье, 6 марта 2011 г.

О поиске простого решения или как я писал JobStore для Quartz

Java очень хорошо известна своим разнообразием различных Open Source frameworks, одни ребята из Apache наверно несколько десятков сгенерировали. Причём всегда есть много альтернатив (к сожалению, зачастую все равно выбрать нечего :))). Но есть планировщик задач Quartz, которому нет альтернативы, почти стандарт, так сказать. Причём с архитектурной точки зрения он довольно прост и хорош. У нас есть Scheduler в котором мы регистрируем Trigger'ы и Job'ы и связи между ними, таким образом каждый триггер может активировать одну или несколько работ.

Данная библиотека одна из ключевых в одном из наших подпроектов. Важный вопрос как всегда это persistence. Т.е. возможны следующие случаи к примеру:

  • Если триггер должен сработать только несколько раз. То после рестарта приложения Scheduler должен знать об этом и не активировать его.
  • Если у нас есть триггер, который должен срабатывать каждый час, но спустя, например, 59 минут наше приложение упало. То когда его перезапустили, этот триггер должен сработать через минуту, а не через час.

Это вопрос в Quartz так же решён. Есть интерфейс JobStore, к которому обращается Scheduler за всеми нужными данными и он должен обеспечивать сохранность данных. По умолчанию существуют две реализации RAM и JDBC. Как нетрудно догадаться, RAM никакой сохранности не обеспечивает, но JDBC по сути должно хватить всем, так как почти любая СУБД к вашим услугам. К сожалению для нас это не так, мы не используем СУБД. Поэтому пришлось реализовывать JobStore самостоятельно. И вот тут, тот, кто также успел сходить по ссылке на api JobStore, мог ужаснуться, так как JobStore - это интерфейс наверно на полсотни методов. Поэтому под катом, моя история, как я пытался малой кровью реализовать этого бегемота для наших нужд :)

суббота, 19 февраля 2011 г.

Субботний вечер пропаганды маргинальных технологий: Анемичная модель

Ох, эта статья будет ещё более сумбурная, чем они бывают обычно у меня. Просто есть какие-то мысли и надо их немного устаканить.

Есть такой человечище, зовут Мартином. Когда я ещё только играл в HoMM 3, он уже написал статью про анти-паттерн AnemicDomainModel. И не смотря на то, что я запоем читал некоторые его книги и статьи, с этим я совершенно не согласен.

java.lang.Process баги

Хотел бы в очередной раз поругать Java'у. В этот раз по делу :)

Есть такой интерфейс java.lang.Process и класс Runtime, которые позволяют  запускать другие приложения, скажем так. У нас это достаточно частая штука. Скажем даже основная функция (:

Поэтому следующие два взаимодополняющих бага в JVM прочувствовали очень сильно на себе.

Process.waitFor() fails to return. Проблема заключается в том, что waitFor может упасть, если никто не вычитает stream'ы процесса. Я не зря употребил слово _может _, так как это например у нас первый раз появилось спустя несколько месяцев тестирования. Ладно, его типа закрыли, так как можно перед вызовом waitFor прочитать потоки процесса и всё будет хорошо. Ага, только в каком-либо другом, идеальном мире.

"IOException: Stream closed" if more data sent after Process.destroy. Тут мы приходим ко второму багу. Так как если применить выше указанный способ, т.е. запускать процесс, открывать потоки и читать их до завершения у работающего процесса, то в случае если его кто-нибудь kill'нёт, что для ряда процессов у нас нормальное явление, то мы получаем ещё один прекрасный exception при чтении. И этот баг не закрыт.

Да, варианты конечно всегда есть, даже несколько. Можно глотать exception, можно использовать цикл и exitValue, вместо waitFor. Но оба смотрятся по уродски.

Вот такая нелёгкая жизнь у Java программиста :) И я бы Sun Oracle всё бы простил, если бы это происходила на какой-нибудь Windows, так нет, тут всё хорошо, а происходят эти баги на той самой SunOS.

пятница, 7 января 2011 г.

Новогоднее обещание :)

Не привычный пост :) Обычно пишу всякий рабочий треш, куча которого скопилась ещё и в draft'ах :) Но тут другое дело. Некоторый поток сознания приведший к этому можно почитать в buzz'е. Но если кратко. Часто видел/читал про американскую традицию давать в новый год всякие обещания на следующий, типа бросить курить или похудеть. Я решил, что надо поумнеть. Не знаю как у кого, но у меня знания очень трудно усваиваются после прочтения книжки, даже если делать задания в конце глав (а в некоторых таких заданий и нет). Вообщем было решено написать проектик, конечно же open source. Ничего нового и никаких startup'ов, просто проект, в котором можно было бы попробовать немного того, что прочитал или увидел в книгах, конференциях, статьях, подкастах и пр. Как всегда часто возникает вопрос, почему бы не присоединиться к существующему проекту. Всё просто, я хочу учить, попробовать много фишек, вообщем это не для проектов, которые ставят цель создать продукт, в конце я конечно надеюсь к декабрю 2010 получить продукт, но всё же основная цель поиграться, понабивать шишек, которые недоступны в hello world приложениях.

Больше двух с половиной лет, я каким то образом занимаюсь ETL и обработкой данных. И знаете, мне это нравиться. Вот и решил написать свою ETL :) Их тыщи, ещё одна не повредит. Ах да, и спасибо Андрею и Вите, вместе проработали много, делали PoC такой ETL на .NET.  Да и вся с кем я работа(л/ю). Получил бесценный опыт и большинство, что я тут напишу я знаю благодаря им. И конечно Ване, который меня познакомил со всеми этими отличными людьми.

Под катом, немного подробностей, если кому интересно.

И конечно же всех с наступившим Новым годом и успехов вам в ваших проектах!

понедельник, 6 декабря 2010 г.

Java Generics vs Наследование

Вообщем по просьбе Viktor Davion объясняю (в 140 твиттеровских символов не уложился), отчасти, что побудило к посту ненависти. Под катом, т.к. содержит плоды работы воспалённого мозга.

пятница, 5 ноября 2010 г.

Code coverage для интеграционного тестирования

Итак, ситуация следующая. Есть у нас Integration Test Framework, написанный специально для нашего приложения. Но начался он писаться задолго после старта работы над приложением, поэтому накопилось большое количество кода, который тестируется в лучшем случае unit тестами. Как это всё вместе работает не совсем понятно :) Для это писался этот ITF, но он ещё в разработке и тесты пишутся достаточно медленно. Вот в процессе обсуждение этого факта, мне подумалось, а почему бы не считать каково покрытие тестами у нас. Вообще, было замечено, что многие программисты очень плохо относятся ко всяким таким характеристикам как сode coverage. Вот для unit тестов оно у нас не считается, но локально иногда запускаешь посмотреть, сейчас у нас больше 80%. Но, как мне сказали, о чём это говорит? Из за неправильного ответа на этот вопрос и возникает такая не любовь к этой величине. То, что сode coverage 100% это не значит, что вы достигли просветление, ваше приложение идеально и вы на пути к нирване. Но это говорит о том, что весь написанный код, действительно вызывается, т.е. это немного спасает от простых ошибок.

Но вернёмся к ITF. Почему я считаю, что для интеграционных тестов сode coverage более полезен.

  1. Меньше возможностей для искусственной манипуляции результатами. Как иногда бывает с простыми численными характеристиками, за что их и не любят, люди увлекаются попыткой их достижения. И если мы говорим о unit тестах, то достаточно просто написать много, по своей сути бесполезных тестов, которые дадут требуемую цифру. Это ещё одна из причин, почему test first :) Но для интеграционных тестов это не так. Они не работают напрямую с методами или классами. Они используют исключительно пользовательское api, создание файла, нажатие на кнопку и т.п. Поэтому пытаться искусственно делать 100% покрытие очень трудоёмкая задача. Кроме того, даже для ручного тестирования, многие все равно прикручивают сode coverage, чтобы увидеть это заветное число, после того как тестировщики погоняют приложение. Это даёт много интересной информации для размышления.
  2. Мы оказались в ситуации, что интеграционные тесты приходится писать вдогонку. Уже есть большая часть приложения, команда разрослась почти до 10 человек и всего 2 тестировщика. Таким образом, отслеживая величину покрытия, можно делать выводы о том, мы догоняем или всё таки уже опоздали. Т.е. если на предыдущей недели было 20%, а на этой стало 23%, то мы на верном пути, но если стало 10%, то слишком увлеклись генерированием не проверенного кода и наверно стоит поднапрячь программистов, чтобы они побольше внимания уделяли написанию интеграционных тестов в помощь тестировщикам.

В результате всё таки создал такой таск и решил на досуге посмотреть, что может предложить open source java community поэтому поводу. Надо была попроще библиотека, которая позволяла посчитать покрытие кода, по результатам работы приложения. начал конечно же с Open Source Software in Java. В принципе, предложения есть. Я выбрал последнее с "оригинальным" названием CodeCover. Последняя версия можно считать 1.0.* оформленная ажно в 2009 году, но плагин под эклипс обновлялся в 2010, да и остальные тулы, тоже не сильно новее. Маленький проектик hoto можно увидеть под катом, если заинтересовало.

суббота, 30 октября 2010 г.

Субботний вечер пропаганды маргинальных технологий: hgsubversion

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

Сегодня хотел немного затронуть тему распределенных систем контроля версий. На самом деле, эта тема достаточно популярно, просто больших компаниях приживается очень плохо, некоторые, как я узнал, например в IBA, вообще cvs пользуются. Подробно рассказывать именно про DVCS не думаю, что есть смысл, материалов на всех языках мира хватает, как в общем про DVCS, так и про конкретные системы. Один из главных зачинатилей всего безобразия, это Линус, так что в качестве введения можно посмотреть его выступление в кампусе Google, где в его духе эмоционально рассказано кто не прав и почему :)

Я расскажу про немного другую проблему. Когда вы делаете не свой продукт, а под заказ или являетесь всего лишь небольшим подпроектом огромного проекта, часть технологий вы выбрать не можете и вынужденны использовать subversion. Но ведь хочется вкусненького, и это возможно. Почти все разработчики DVCS понимают, что все сейчас прям не бросятся переводить свои репозитории на новые рельсы. Поэтому присутствует интеграция с многими другими системами контроля версий. Например с subversion. Вот хотел бы рассказать про hgsubversion, проект, который позволяет интегрировать subversion и mercurial репозитории. Был опробован на реальном проекте и пока никаких проблем не возникло.

пятница, 29 октября 2010 г.

Требую больше immutability!

Вообщем тривиальная слоган, его можно прочитать даже в достаточно старой Joshua Bloch: Effective Java, Item 15: Minimize mutability.

Под катом чутка банальности, так как сегодня доделал и наболело.

пятница, 22 октября 2010 г.

Java сompile time annotations

Ох.. тут давече затеяли большой рефакторинг проекта в рамках которого я решил сделать пару классов immutable. Казалось бы, делаем все поля private + final и всё ок. Но нет, для ссылочных типов это не работает. Так как в этом случае мы не можем изменить ссылку на этот объект, которая храниться в поле, но за то можем изменить сам этот объект, например добавить в коллекцию ещё пару объектов. Тут есть два подхода, оба приводят к равно ценном результату (immutable классу):

  1. Требовать, чтобы все ссылочные типы также были immutable, как String например. Для коллекций можно использовать Collections.unmodifiableCollection метод.
  2. Второй способ заключается в основе ООП: инкапсуляции. Ни один метод не возвращает объект по ссылке, только его копию, например вместо возврата коллекции можно вернуть её неизменяемую копию с помощью описанного выше метода.
Вообщем то всё достаточно очевидно. Ввиду ряда особенностей и уменьшения последствий рефаторинга, посоветовавшись, я решил воспользоваться вторым способом. Но пока рассматривал первый метод, захотелось аннотацию, которая бы сигнализировала, что объект не изменяем и корректность класса проверялась на этапе компиляции. Если кого-то заинтересовала, краткое описание под катом.

четверг, 16 сентября 2010 г.

Log4j file header

Давно не писал, но тут накипело. Читал буквально позавчера статью Модульный дизайн, или «что такое DIP, SRP, IoC, DI и т.п.». Вот там говориться про великий Log4j, какой он распрекрасный. И вот понадобилось мне сделать header для файлов. Такой вот конфиг:
  1. <appender name="eventhistoryfile" class=" org.apache.log4j.RollingFileAppender">  
  2.     <param name="LogFileName" value="${log4j.file.name}"/>  
  3.   
  4.     <layout class="org.apache.log4j.PatternLayout">  
  5.         <param name="ConversionPattern" value="${log4j.pattern}"/>  
  6.     </layout>  
  7. </appender>  
Очень простой.. Как добавить хедер? Оказывается PatternLayout содержит пустую реализацию метода getHeader. Ну и как это называется??? Ладно, сделал свой, который добавляет эту функциональность, не сложно. Идём дальше. Запустил, работает. Вырубил приложение, запустил ещё раз появился ещё один header в файле О_о я нахожусь в шоке. Пришлось ещё наследоваться от RollingFileAppender и переопределять у него метод writeHeader, чтобы header в файл писался один раз (код взят в исходном FileAppender  только добавлена последняя проверка).
  1. @Override  
  2. protected void writeHeader() {  
  3.     if (this.layout == null) {  
  4.         return;  
  5.     }  
  6.     String header = layout.getHeader();  
  7.     if (header == null && this.qw == null) {  
  8.         return;  
  9.     }  
  10.     File f = new File(this.getFile());  
  11.     if (!f.exists() || (f.exists() && f.length() == 0)) {  
  12.         this.qw.write(header);  
  13.     }  
  14. }  
Вообщем, негодую.

вторник, 22 июня 2010 г.

Crash Racing

Для получения Диплома осталось только подписать обходной лист. Вот разбирал архивы, чтобы всё накопленное записать на dvd и сдать в архив, и наткнулся на прикольный проект. На втором курсе у нас Java вёл очень хороший преподаватель Гафуров Сергей Владимирович. И в конце курса  мы разбились на команды и где-то недели две писали сетевую игру на Java. Мы выбрали гоночки и как видно из заголовка поста - разрушительные гоночки. Это был невероятный проект и очень полезный, заставил по другому взглянуть на программирование. Всё таки работа в команде, это работа в команде :) Где-то в середине проекта стало понятно, что мы не успеваем и пришлось перебороть юношеский максимализм и волевым усилием отказаться от оружия. Зато к сроку у нас был работающий проект, хоть и разрушать ничего нельзя было. Вот на память записал видео сражения 4х ботов на моей любимой карте, за ними наблюдать иногда веселее чем самому играть, а благодаря Диме Гончарову выиграть у них практически не возможно =DD это удавалось только Диме Хоревичу. Кстати да, о лицах :) Первый Дима как не сложно догадаться работал над физикой и ИИ, второй над UI, Катя Цвирко сделала потрясающие карты и работала с панелью игрового поля. А я скромно писал сетевое взаимодействие. Играть можно было по сети. Так как ботов было трудно победить - сражались между собой :) Игра не поражает воображение, но это всё таки учебный проект второкурсников, причём в жатые сроки, мне нравиться ^__^



Код не покажу, стыдно :)

Upd: Видео уже лень делать, вот скриншоты :)