Показаны сообщения с ярлыком job. Показать все сообщения
Показаны сообщения с ярлыком job. Показать все сообщения

The Navigame

1 коммент. | добавить комментарий
Just a week remains until the New Year 2012 comes. The last year was the first one we at Luxoft have been able to make the maximum contribution to the development of the next-generation car navigation system which we are working on since 2008. The most prominent thing is the complete responsibility for the production chain, of course. At the same time the software products we are developing have matured a lot - thanks to all my colleagues, past and present.

As I really appreciate what our guys have done and are doing and at the same time I want to remember and cherish the good time we had in 2011, I decided to write a simple computer game on how we work. So, meet The Navigame:


After some trials and errors I decided to make it looking like a paper sketch (most likely soon I'll assemble a new version with enhanced graphics which I've asked my friend for). The good thing is that here I've finally found an application for the TTF-font I created two years ago.

The goal of the game is to develop the navigation system and to compile digital maps - as much as possible. For this you have a pool of skilled developers and map production engineers which can be assigned different tasks. There are developers who create the navigation software and production engineers who build the maps using the map compiler which is a part of navigation. The more the navigation system is feature-complete, the bigger maps can be handled with it. There are also some athmospheric features like customer PM or developers' curses. You basically should (a) finish the navigation development, (b) fulfil the map production plan and (c) earn as much money as possible.

To all people we worked with during the last 2-3 years: there are good chances that you find yourself inside the game - so give it a try :)


The source code, readme and binary download are available on Github at https://github.com/sborodavkin/navigame. It is required to have JRE installed as the game is developed in Java using Slick and LWJGL.

All contributions and feedback are warmly welcome.

Проблемы документирования software design

0 коммент. | добавить комментарий
Сегодня на постмортеме решали, как менять существующий процесс документирования дизайна. Проблемы очевидны:
  • дизайн-документы хранятся в морально устаревшем формате Word, низкая прозрачность
  • сложный шаблон документа как результат стремления покрыть все требования к дизайну из ASPICE L3 HIS scope
  • непонятно, актуально ли описание дизайна, или уже устарело - к коду доверия больше.
Как перестать писать дизайн "из-под палки" и что вообще делать - мне пока непонятно. Нашел вот цитату из David Parnas and Paul Clements. "A Rational Design Process: How and Why to Fake It" in Software State-of-the-Art: Selected Papers. Dorset House, 1990, pg. 353-355:


It should be clear that documentation plays a major role in the design process that we are describing. Most programmers regard documentation as necessary evil, written as an afterthought only because some bureaucrat requires it. They do not expect it to be useful.
This is a self-fulfilling prophesy; documentation that has not been used before it is published, documentation that is not important to its author, will always be poor documentation.
Most of that documentation is incomplete and inaccurate, but those are not the main problems. If those were the main problems, the documents could be easily corrected by adding or correcting information. In fact, there are underlying organizational problems that lead to incompleteness and incorrectness and those problems, which are listed below, are not easily repaired.
1) Poor Organization: Most documentation today can be characterized as "stream of consciousness" and "stream of execution." "Stream of consciousness" writing puts information at the point in the text that the author was writing when the thought occurred to him. "Stream of execution" writing describes the system in the order things will happen when it runs. The problem with both of these documentation styles is that subsequent readers cannot find the information they seek. It will therefore not be easy to determine that facts are missing, or to correct them when they are wrong. It will not be easy to find all the parts of the document that should be changed when the software is changed. The documentation will be expensive to maintain and, in most cases, will not be maintained.
2) Boring Prose: Lots of words are used to say what could be said by a single programming language statement, a formula, or a diagram. Certain facts are repeated in many different sections. This increases the cost of the documentation and its maintenance. More importantly it leads to inattentive reading and undiscovered errors.
3) Confusing and Inconsistent Terminology: Any complex system requires the invention and definition of new terminology. Without it the documentation would be far too long. However, the writers of software documentation often fail to provide precise definitions for the terms they use. As a result, there are many terms used for the same concept and many similar but distinct concepts described with the same term.
4) Myopia: Documentation that is written when the project is nearing completion is written by people ho have lived with the system for so long that they take major decisions for granted. They document the small details that they think they will forget. Unfortunately, the result is a document useful to people who know the system well, but impenetrable for newcomers.
Documentation in the ideal design process meets the needs of the initial developers as well as the needs of the programmers who come later. Each of the documents mentioned above records requirements or design decisions and is used as a reference document for the rest of the design. However, they also provide the information that the maintainers will need. Because the documents are used as reference manuals throughout the building of the software, they will be mature and ready to use in later work. The documentation in this design process is not an afterthought; it is viewed as one of the primary products of the project. Some systematic checks can be applied to increase completeness and consistency. [...]
"Stream of consciousness" and "stream of execution" documentation is avoided by designing the structure of each document. Each document is designed by stating the questions that it must answer and refining the questions until each defines the content of an individual section. There must be one, and only one, place for every fact that will be in the document. The questions are answered, i.e., the document is written, only after the structure of the document has been defined. When there are several documents of a certain kind, a standard organization is written for those documents. Every document is designed in accordance with the same principle that guides our software design: separation of concerns. Each aspect of the system is described in exactly one section and nothing else is described in that section. When documents are reviewed, they are reviewed for adherence to the documentation rules as well as for accuracy.
The resulting documentation is not easy or relaxing reading, but it is not boring. It makes use of tables, formulas, and other formal notation to increase the density of information. The organizational rules prevent the duplication of information. The result is documentation that must be read very attentively, but rewards its reader with detailed and precise information. [...]
No matter how often we stumble on our way, the final documentation will be rational and accurate. Even mathematics, the discipline that many of us regard as the most rational of all follows this procedure. [...] Analogous reasoning applies to software. Those who read the software documentation want to understand the programs, not relive their discovery. By presenting rationalized documentation we provide what they need.
Our documentation differs from the ideal documentation in one important way. We make a policy of recording all of the design alternatives that we considered and rejected. For each, we explain why it was considered and why it was finally rejected. Months, weeks, or even hours later, when we wonder why we did what we did, we can find out. Years from now, the maintainer will have many of the same questions and will find his answers in our documents.

Как стать ПМом

6 коммент. | добавить комментарий
За последние месяцы меня несколько раз спрашивали, что нужно для того, чтобы стать руководителем проекта (ПМ). Что примечательно, этот вопрос исходит в основном от джуниоров, молодых и амбициозных. Опуская сантименты "оно вам не надо" и т.д., попробую высказать свое субъективное и неправильное мнение на этот счет.

1. ПРИЧИНА

Главная причина того, что люди задаются таким вопросом - стремление к власти. Ничего плохого в этом нет - как известно, главных испытаний в жизни всего 4: деньги, слава, власть и любовь. Для точки внутри пространства такого ортогонального базиса, например, жажда любви ничем не лучше жажды власти. К тому же, сравните:
  • "я зарабатываю пять тысяч в месяц" (деньги),
  • "меня знают и уважают в Одессе" (слава),
  • "я руковожу тремя проектами и сорока людьми" (власть).
Что звучит убедительней? Власть, только она наиболее полно позволяет человеку ощутить степень своего карьерного роста и практически количественно (в подчиненных) измерить его.

2. СРЕДСТВА

Теперь о средствах достижения вожделенного ПМства. В дополнение к очевидному - желанию стать ПМом - более-менее внятно озвучить я могу пять:

2.1. Опыт. Я придерживаюсь мнения, что стать хорошим ПМом, не отработав N лет в инжиниринге, нельзя. Плохим - можно, но мы не рассматриваем этот вариант по причине того, что все риски, связанные с плохим ПМом, разделяет его руководитель, а значит вряд ли назначит его на эту должность. Только через годы работы разработчиком, старшим разработчиком, техлидом и тимлидом можно приблизиться к креслу ПМа, поскольку:
  • позиция разработчика даст вам прочувствовать то, как управлять собой и своим временем
  • позиция старшего разработчика поможет вам глубже разобраться в областях, непосредственно не относящихся к кодингу: анализ и управление требованиями, оценка трудозатрат, ревью архитектуры и дизайна и т.д. Кроме того, обычной практикой является курирование старшим разработчиком одного или нескольких программистов.
  • на позиции тим/тех-лида в первую очередь приходит понимание того, что такое ответственность за команду. Это очень важный пункт, который нельзя пропускать, поскольку через него мы приходим к умению нести ответственность за технические решения (свои и команды), организационные решения (свои и компании), ну и в целом за проект. Кроме этого, здесь вам придется научиться управлению рисками и проблемами, грамотному общению с заказчиком, а также основам того, как быть интерфейсом между командой, компанией (рекрутерами, HR, руководством, администрацией) и заказчиком.
К сожалению или к счастью, опыт здесь нельзя заменить знаниями. Разработчик, прослушавший курсы по управлению проектами, - это еще не ПМ. В системном анализе программные проекты относятся к классу сложных систем (СС) с неформализуемыми компонентами (в первую очередь - людьми). Управление ожиданиями подчиненных, понимание культурных и личностных особенностей разных заказчиков, понимание и принятие правил, по которым функционирует ваша организация (а также их выполнение) - все это нельзя получить из книг. Более того, даже формализуемые компоненты СС (собственно ПО) также требуют опыта. Например: никому не нужен в качестве архитектора вчерашний студент, пусть и очень знающий, но не спроектировавший N реальных систем с учетом требований производительности, масштабируемости, устойчивости к изменениям требований и т.д. - а ПМ должен выполнять ревью требований, архитектуры, тест-плана, поэтому и спрос с него соответствующий.

2.2. Процессная дисциплина. Только понимая процессные активности той или иной процессной модели, принимая их для себя и выполняя их, можно внедрять и контролировать их выполнение в проекте. Сюда я отношу создание технических требований, оценку трудозатрат, управление рисками, своевременную эскалацию проблем, управление изменениями, аккуратную и регулярную, как чистка зубов, отчетность. Из относящихся к кодированию: код-ревью и создание юнит-тестов. На всем этом нужно набить шишки, находясь на позиции старшего разработчика, поскольку те же шишки на позиции ПМа будут стоить гораздо дороже - как вам, так и компании. См. также пункт 2.1.

2.3. Инициатива (или "делайте больше"). Покажите своему руководителю (от которого зависит ваше повышение), что вы можете больше. Вам дали задачу? Найдите способ сделать ее лучше, чем указано в требованиях! Заложите больше масштабируемости, проведите рефакторинг, напишите больше тестов, оптимизируйте алгоритм. Однако, не бросайтесь с места в карьер: отсутствие опыта приведет только к тому, что вы будете предлагать нереализуемые, ненужные или ранее отвергнутые сценарии и тем самым злить начальство. См. также пункт 2.1.

2.4. Язык. Как правило - английский. ПМ, пишущий письма заказчику на плохом английском, с ошибками в словах и грамматике, отвратителен. С другой стороны, вполне можно писать простыми предложениями, употреблять в основном часто используемые слова - но ради Бога, грамотно! Оценить свою степень владения языком можно на курсах, у преподавателя, у более знающего коллеги, а также, частично, с высоты своего языкового опыта. См. также пункт 2.1.

2.5. Способности к руководству. Это что-то из области "можно вам доверить людей" или нет. Оценивать вас по этому пункту будет ваш руководитель, скорее всего, чисто субъективно, в связи с чем ограничусь примерами:
  • "человек-фюрер", как правило, отлично справляется со всеми задачами, возложенными на него, и при этом (простите мой французский) аж ссытся, так хочет кем-нибудь поруководить. Обычно не упускает возможности дать коллегам понять, что главный здесь - он, а также зарисоваться перед начальством. Такому человеку доверять руководство людьми опасно - у него нет к этому природных способностей, и частично помочь здесь сможет специализированное обучение, опыт и внутренняя дисциплина.
  • "человек-рыба" также хорошо выполняет все поставленные задачи, но другими людьми склонен не интересоваться, не заинтересовывать, не развивать. Обычно стремится большой объем работы выполнить сам, мотивируя тем, что у команды мало опыта. Такому человеку доверить руководство также можно только после предварительных упражнений.
Я бы мог перечислить еще много смешных типажей, но это - тема отдельного поста. Хорошее упражнение - попробовать посмотреть на свое поведение в офисном ареале со стороны, непредубежденным взглядом. Очень важно понимать свои недостатки в этой области, иногда они - причина того, почему вас не повышают. Как правило, с ними вам придется бороться на протяжении всей карьеры, поскольку они (в отличие от предыдущих четырех пунктов) - часть вашей личности. Вы хотите руководить людьми до судорог в коленках? Скрывайте силу вашего желания, не дайте никому догадаться! Вы уверены, что знаете все лучше всех? Превозмогите себя, дайте вашим коллегам шанс - пусть они сделают не так идеально, но зато приобретут опыт, и т.д.


3. ОТКЛОНЕНИЯ

Иногда на ПМских позициях оказываются люди, не соответствующие написанному выше. Причин у этого может быть несколько:
  • повышение произвел некомпетентный руководитель. Либо он (руководитель) пострадает из-за этого и отменит такое повышение, либо ПМ "натыркается" и будет сносно выполнять свои ежедневные обязанности, тем не менее лажаясь каждый раз, когда от него потребуется что-то, что выходит за круг его привычных задач (написать proposal для нового заказчика, выступить с презентацией на ежегодном собрании и т.д.)
  • повышение произвел компетентный руководитель. В этом случае он (руководитель) принимает все риски, связанные с таким назначением, и возможно выполняет часть работ за своего ПМа. Такая ситуация возможна, когда:
    • руководитель держит бразды правления в своих руках, отдавая ПМу рутинные технические задачи (распределение тасков между людьми, сбор индивидуальных отчетов и подготовка проектного отчета, написание / ревью технических требований и т.д.) О реальной власти ПМа в такой ситуации речь не идет - однако это может быть ловко замаскировано более опытным руководителем и подано молодому ПМу под правильным для него соусом из манипулятивных утверждений и обещаний.
    • Другой вариант развития событий: руководителю нужен реальный ПМ, нанимать "готового" с рынка для компании экономически нецелесообразно, поэтому новый ПМ целенаправленно взращивается в реальных условиях. Это возможно при соблюдении требований 2.2, 2.3, [2.4], 2.5 из списка выше. При этому руководитель ПМа все так же несет ответственность за проект, готов придти ему на помощь в случае необходимости и в целом верит в него.
  • компания понимает под ПМом что-то принципиально другое, чем то, что понимаю я. Мне встречались случаи, когда ПМами называли себя фактические продакт-менеджеры, сейлзы или аналитики. Скорее всего, ПМ в таком случае будет бесконечно далек от PMBOK.

4. ВЫВОДЫ

Чтобы стать ПМом, обязательно нужен инженерный опыт. Софт-скиллы (управление людьми, конфликтами, изменениями, ведение переговоров, навыки проведения презентаций и т.д.), как правило, приобретаются уже на новой должности (либо на должности тим/тех-лида при более дальновидной политике компании). В дополнение к опыту обязательна инициатива в смысле желания делать больше. Очень важны процессы (и да, agile - это процесс). Кроме того, важно знать свои недостатки, которые могут помешать вам в управлении людьми, и вести с ними постоянную борьбу.

Иногда можно увидеть в кресле ПМа дятла. Несмотря на то, что этому, как правило, можно найти объяснение, ответьте себе на вопрос: а вы - дятел? При желании можно придумать, как нацепить на себя лейбу ПМа, что будет служить формальным подтверждением вашей власти. Однако власть - это всего лишь одна из мер карьерного роста, и лейба ПМа не заменит содержания ПМа. Быть хорошим ПМом в средне- и долгосрочной перспективе гораздо выгодней, чем плохим:
  • вы не теряете связи с инжинирингом, который развивается очень быстро
  • вы сможете больше делать, брать на себя больше ответственности, ваша работа будет интересней
  • вы не теряете возможности повышения зп. Хороший ПМ развивается на своей должности, плохой - держится за нее и за свой узкий круг обязанностей, внутри которого он чувствует себя комфортно, а снаружи - нет
  • хороший ПМ пользуется уважением коллег, плохой - нет, его обсуждают за глаза, из-за него достается на орехи начальству
  • у плохого ПМа нет перспективы роста (количества подчиненных, получения новых проектов и т.д.).
В общем-то, можно быть и дятлом в кресле ПМа. Главное - не обманывать себя. Удачи!

Project Management Plan Hell

4 коммент. | добавить комментарий
В нашем центре разработки существует обязательная практика написания Project Management Plan'а (PMP) для каждого проекта. Под РМР у нас понимают документ объемом около 20-30 страниц следующего содержания:
- Scope проекта (milestones, deliverables, assumptions, constraints и т.д.)
- организационные диаграммы: внутренняя + интерфейсы на стороне заказчика
- планы по управлению рисками, требованиями, изменениями, схема эскалации проблем
- методики оценки проекта, планы верификации и тестирования, процедуры приемки задач и пр.
- план-график проекта
- цели качества и контролирующие их метрики
- план обучения персонала
- и т.д.

От каждого (условно) project manager'а в обязательном порядке требуется:
- составить такой документ (с учетом проектных задач, которые никто не снимает - 2-3 недели)
- провести ревью внутри команды с привлечением инженера по качеству, учесть замечания (если в команде человек 10-15 - 1 неделя)
- провести еще одно ревью с участием руководителя группы качества и сайт-менеджера и утвердить РМР на нашей стороне (с учетом занятости таковых - 2 недели)
- утвердить документ с ПМ'ом на стороне заказчика (с учетом занятости такового - 2 недели)

В общем итоге, составление и утверждение РМР занимает около 2 месяцев. За это время, разумеется:
- изменяется scope проекта, появляются новые задания и активности
- изменяется состав команды (кто-то приходит, кто-то, возможно, уходит)
- сдвигается план-график
- уточняются цели качества, изменяется набор метрик
- люди обучаются, план обучения также эволюционирует.

Все эти изменения требуют обязательного переутверждения РМР с проведением внутрикомандного ревью, что занимает около 6 недель. Таким образом, имеем:
- постоянно отстающий от реальности РМР
- постоянный цейтнот в связи с необходимостью его переутверждения (многие на это забивают, получая в результате другие проблемы: либо необходимость обманывать группу качества, декларируя соответствие реальности фактические устаревшего РМР, либо необходимость отбиваться от руководства, требующего переутверждения РМР).

Пути решения могут быть, например, такими:
- упрощение процедуры переутверждения РМР
- упрощение содержания РМР
- отказ от РМР.

Ага?

"Толстые" дороги в SLD

0 коммент. | добавить комментарий
Для отрисовки карт в нащих плагинах к uDig, мы используем Styled Layer Decorator (SLD).

На прошлой неделе я решал проблему отрисовки дорог шириной более 1 пикселя. Вот как оно выглядело изначально:



Очевидные проблемы:

  1. Отрисовка перекрестков. На перекрестках дорог видно не соединенные между собой окончания сегментов.
  2. Взаимное наложение дорог. При слишком близком расположении, дороги хаотически взаимно перекрываются. Особенно это заметно, опять же, на перекрестках. Кроме того, в левом верхнем углу заметно, что сегменты двух дорог (со стрелочками) также поочередно перекрываются.


SLD обеспечивает настройку правил для отрисовки дорог с помощью LineSymbolizer:

<sld:LineSymbolizer>
<sld:Stroke>
<sld:CssParameter name="stroke">#00ff00</sld:CssParameter>
<sld:CssParameter name="stroke-opacity">1</sld:CssParameter>
<sld:CssParameter name="stroke-width">1</sld:CssParameter>
<sld:CssParameter name="stroke-linejoin">round</sld:CssParameter>
<sld:CssParameter name="stroke-linecap">round</sld:CssParameter>
</sld:Stroke>
</sld:LineSymbolizer>


Предполагается, что, управляя параметрами linejoin (miter, round, bevel) и linecap (butt, square, round), можно добиться желаемого эффекта. Например, в статье "GeoServer render OpenStreetMap" приводится реальный SLD-стиль, использующийся для отрисовки OSM. Как видно из примеров, хороших результатов удалось добиться только для мелких масштабов; при приближении становятся видны артефакты перекрестков и назойливые "сосисочные" окончания дорожных сегментов.

Продолжив поиски и поэкспериментировав с параметрами LineSymbolizer, я сделал вывод, что возможностей SLD для отрисовки таких "толстых" дорог, какие у нас были изначально (8-14 пикс.) попросту недостаточно. Уменьшив ширину до 2-6 пикселей и выставив linecap = butt, linejoin = miter, я получил такой результат:



Цвета я поменял на более близкие к Google Maps, но это не принципиально.

Кроме этого, заметил следующее:

  1. Для отрисовки направлений движения GeoServer в стиле tiger.sld использует TextSymbolizer, печатающий "стрелочку":

    <sld:Label>
    <ogc:Literal>←</ogc:Literal>
    </sld:Label>

    Однако, я столкнулся с тем, что стрелочка у меня непредсказуемо переворачивается (очевидно, это зависит от направления вектора, представляющего дорогу, относительно базовой точки). Поэтому направление движения я задаю с помощью LineSymbolizer, отрисовывающего стрелочку попиксельно.
  2. Управлять порядком отрисовки дорог с помощью разных Rule внутри одного FeatureTypeStyle толком нельзя, поскольку GeoTools применяет эти правила в непредсказуемом порядке. Я вынес правило для отрисовки каждого из типа дорог в отдельный FeatureTypeStyle, после чего они стали отрисовываться в порядке, указанном в моем SLD.


На этом я пока что и остановился.

Мультатор

2 коммент. | добавить комментарий
Нарисовал "альтернативную" заставку для одного из наших проектов.
84 кадра, 300 КБ:

Смешной код

2 коммент. | добавить комментарий
Несколько смешных участков кода из нескольких проектов:

1. Магический скрипт

private final String magicScript = "\nif(8==8)return;";


2. Глубокая иерархия

public void dragEnter(DropTargetDragEvent arg0) {
((DropTargetListener)getParent().getParent().getParent()
.getParent().getParent()).dragEnter(arg0);
}

public void dragExit(DropTargetEvent arg0) {
((DropTargetListener)getParent().getParent().getParent()
.getParent().getParent()).dragExit(arg0);

}

public void dragOver(DropTargetDragEvent arg0) {
((DropTargetListener)getParent().getParent().getParent()
.getParent().getParent()).dragOver(arg0);

}

public void drop(DropTargetDropEvent arg0) {
((DropTargetListener)getParent().getParent().getParent()
.getParent().getParent()).drop(arg0);
}

public void dropActionChanged(DropTargetDragEvent arg0) {
((DropTargetListener)getParent().getParent().getParent()
.getParent().getParent()).dropActionChanged(arg0);
}


3. Магические вычисления

int ww0 = getWidth() ;//- 40;
int hh0 = getHeight();// - 40;
int sz = Math.min(ww0, hh0);

sz = sz/4*3;


int y0 = (hh0 - sz) / 2;



int x0 = 0;
int h = sz / 2;
int dh = sz / 4;

int y = y0 + h;

int hh = (int)Math.sqrt(h*h - h*h/4);
y0 = y - hh;


Rectangle rect = new Rectangle(x0, y0 , sz, hh + hh );

int arrX[] = {x0 + dh, x0 + 3*dh, x0 + sz,
x0 + 3*dh , x0 + dh, x0};
int arrY[] = {y0 , y0 , y ,
y0 + hh + hh, y0 + hh + hh, y};

Polygon poly = new Polygon(arrX, arrY, 6);

return poly;

Баг в JTable: теряется множественный selection при начале DnD

0 коммент. | добавить комментарий
Пишу класс, перегружающий JTable, и снова вижу баг, который видел еще под JRE 1.4.2 году в 2006-м.

Ссылка на баг: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6195469.

Ошибка заключается в том, что, если в JTable выделить несколько ячеек и попытаться их перетащить (drag & drop), то, сразу же после нажатия кнопки мыши, selection сбрасывается со всех ячеек, кроме той, на которую непосредстенно нажали.

Воркараунд, приведенный по ссылке выше, по крайней мере в 1.6 не работает. Поэтому выкладываю свой класс FixedTableUI, которым можно подменить тот класс, который предлагается в воркараунде. Работает с 1.4 по 1.6 включительно:

/**
* This internal helper class helps to solve two bugs:
* The first is disable row selection with mouse drag
* The second is allow handling of multiple selected rows without need to
* hold a Shift key.
*/
private class FixedTableUI extends BasicTableUI {
private MouseInputHandler handler = new MouseInputHandler() {

private boolean isShiftDownInMousePressed = false;


public void mouseDragged(MouseEvent e) {
// Do nothing here!
}

public void mousePressed(MouseEvent e) {
isShiftDownInMousePressed = e.isShiftDown();
int row = rowAtPoint(e.getPoint());
if (!getSelectionModel().isSelectedIndex(row)) {
super.mousePressed(e);
} else {
if (e.isControlDown()) {
if (getSelectionModel().isSelectedIndex(row)) {
getSelectionModel().removeSelectionInterval(row, row);
}
}
}
}

public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
int row = rowAtPoint(e.getPoint());
int col = columnAtPoint(e.getPoint());
int[] selRows = getSelectedRows();
if (selRows.length > 0) {
if (!e.isControlDown() && !e.isShiftDown() &&
!isShiftDownInMousePressed) {
getSelectionModel().setSelectionInterval(row, row);
}
}
}
};

protected MouseInputListener createMouseInputListener() {
return handler;
}
}

JTabbedPane и фокус в ней

0 коммент. | добавить комментарий

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

Вот неработающий код:


tabPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
txtName.requestFocusInWindow();
}
});

Баг #5089436 (а ему уже около 5 лет) предлагает воркэраунд, связанный с обрамлением вызова requestFocusInWindow() в  invokeLater():

tabPane.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
EventQueue.invokeLater(new Runnable() {
public void run() {
txtName.requestFocusInWindow();
});
}
});

А в остальном Свинг по-прежнему хорош.

На пути к оптимизации

2 коммент. | добавить комментарий
Только что наткнулся на такой вот участок кода в нашем приложении:



// This method produces a HUGE overhead
//TreeNodesUpdater.updateComponentTreeUI(this);

// This works, but cuts end part of lines in bold (produces "...")
/*this.invalidate();
this.validate();
this.repaint();*/

// So, we just switch the renderer to null and back to the original one,
// which revalidates the sizes

setCellRenderer(null);
TreeCellRenderer renderer = createCellRenderer();

setCellRenderer(renderer);



А за каждой из этих строчек - целая история...

Война подчеркивания и дефиса: разные стандарты именования в Maven и Eclipse PDE

0 коммент. | добавить комментарий
В одном из наших Eclipse-проектов сборка происходит следующим образом:

1. Сначала мы собираем target-платформу для системы uDig (user-friendly Internet GIS) - набор OSGi-bundles. Состоит она из:
  • GeoAPI и ее зависимостей
  • GeoTools и ее зависимостей
Сборка GeoAPI и GeoTools выпоняется с помощью Apache Maven, который автоматически скачивает нужные зависимости с прописанных репозиториев, запускает компилятор, генерирует MANIFEST.MF для OSGi-бандлов - короче, делает все. В результате мы имеем папку с набором JAR-файлов примерно следующего содержания:
...
java3d.osgi.vecmath-1.3.1.jar
javax.media.jai.osgi.jai_imageio-1.1.0.jar
net.opengis.ows-2.6.0-SNAPSHOT.jar
...

Эта папка - не что иное, как target platform для компиляции uDig, которая делается через PDE.

2. Мы запускаем Eclispe PDE batch build и компилируем uDig. В результате мы получаем продукт uDig, в папке plugins которого, среди прочих, оказываются уже такие файлы:
...
java3d.osgi.vecmath_1.3.1.jar
javax.media.jai.osgi.jai_imageio_1.1.0.jar
net.opengis.ows_2.6.0_SNAPSHOT.jar
...

Первый вывод уже очевиден:
Maven использует "-" (дефис) для отделения номера версии от имени бандла, в то время как PDE использует для этого "_" (подчеркивание)
3. Для того, чтобы собрать наш проект, нам нужна платформа в составе:
  • OSGi-бандлы из папки plugins системы uDig
  • наши проприетарные модули и их зависимости
Причем сборка второго пункта также выполняется с помощью Maven. Соответственно, нам очень удобно использовать модули, уже находящиеся в локальном m2-репозитории - такие, как, например, java3d.osgi.vecmath-1.3.1.jar. Однако, когда мы пытаемся добавить к нашим плагинам плагины из uDig, начинаются проблемы, поскольку в uDig, как мы помним, соответствующая библиотека называется уже java3d.osgi.vecmath_1.3.1.jar (подчеркивание вместо дефиса). Поэтому в результате простого копирования файлов получаем следующую картину:
...
java3d.osgi.vecmath_1.3.1.jar
java3d.osgi.vecmath-1.3.1.jar
javax.media.jai.osgi.jai_imageio_1.1.0.jar
javax.media.jai.osgi.jai_imageio-1.1.0.jar
net.opengis.ows_2.6.0_SNAPSHOT.jar
net.opengis.ows_2.6.0-SNAPSHOT.jar
...
Т.е. набор идентичных по смылу OSGi-бандлов, но продублированных в файлах с разными именами.

Пока что, чтобы решить эту проблему, я стал используюVBS-скрипт, который переименовывает файлы по заданному регулярному выражению с тем, чтобы заменить подчеркивание на дефис. Хотя, наверное, нужно делать это прямо в PDE-сборке и заменять наоборот - дефис на подчеркивание...

А война дефиса и подчеркивания, между прочим, разгорелась нешуточная. В мейл-листах Maven утверждают, что единственно верный разделитель - это дефис. Эклипс пока что понимает только подчеркивание, хотя в 3.5 обещают это исправить (в 3.5 М4, вроде, уже вставили соответствующий патч).

Системы управления требованиями: ReqHeap и OSRMT

4 коммент. | добавить комментарий
Вчера попользовал две системы управления требованиями: Reqheap (http://reqheap.sourceforge.net/) и OSRMT (Open Source Requirement Management Tool, http://osrmt.com). Сказать имею следующее:

ReqHeap сделан на связке PHP+MySQL, поднимается легко, мыслит в терминах проектов, подпроектов, требований и тест-кейсов. Поддерживает много пользователей и разграничение прав. Однако, проследить traceability, скажем, от требований к тестам, построить матрицу и пр. не представляется возможным - нет средств. Короче, просто удобная хранилка всего вышеперечисленного.

OSRMT - могучая вещь, имеющая как Swing-интерфейс, так и веб-клиента. Сделана на Java. Ее словарь, вкратце, таков:
  • Requirement
  • Feature
  • Design
  • Implementation
  • Test
Система позволяет строить traceability matrix от всего ко всему, рисовать диаграммы зависимостей и пр. Из недостатков можно отметить убогость веб-клиента (например, вводишь текст требования в Swing-приложение, форматируешь его там, а потом смотришь в веб - а оно все сплошняком порет. Уж хотя бы <pre>-теги ставило... Кроме того, странным кажется то, что веб-клиент и Swing-клиент по умолчанию использую разные БД, находящиеся в разных папках.

И зачем было так делать?

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

Про аутсорсинг

0 коммент. | добавить комментарий
Даешь два поста в день!

Только что прочел интересную статью о пост-советском аутсорсинге вот здесь. Имхо, интересно. К сожалению, ничего из нее скопировать сюда не могу, т.к. автор впилякал в ее конец вот такую вот просьбу:

I am sorry, but I strictly prohibit reproducing anything from this material in any form and any type of media without my personal approval


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

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


Ну как, уважил я автора?

Как JComboBox всех зарулил

2 коммент. | добавить комментарий
И снова Swing, и снова баг - на этот раз в JComboBox. Состоит в следующем:


JComboBox box = new JComboBox();
box.addItem("x");
box.addItem("x");
box.setSelectedIndex(1);
System.out.println(box.getSelectedIndex())


Этот код напечатает в консоль не 1, как ожидалось, а 0. Баг состоит в том, что метод getSelectedIndex() возвращает индекс первого попавшегося элемента, равного селектированному, причем сравнение выполняется методом equals().

В развернувшейся бурной дискуссии сотрудники Sun пытаются доказать, что данное поведение корректно, поскольку оба элемента x равны. Лично я не согласен: так мог бы вести себя метод getSelectedItem(), но от getSelectedIndex() я бы ожидал возврат выбранного индекса , а не какого-нибудь другого.

Багу #4133743 уже более 10-ти лет. Интересно состояние данного тикета: "11-Closed, Not a Defect, bug". :))

pnuts drives me crazy

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

Короче, объявляю класс. Когда я для какого-то из его полей объявляю cеттер, а впоследствии вызываю его, то чудный пи-натсовый интерпретатор вываливается со StackOverflowError:

java.lang.StackOverflowError
at java.lang.String.indexOf(Unknown Source)
at java.lang.ClassLoader.checkName(Unknown Source)
at java.lang.ClassLoader.findLoadedClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClassInternal(Unknown Source)
at sun.reflect.GeneratedMethodAccessor63.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at pnuts.lang.Runtime.setBeanProperty(Runtime.java:3066)
at pnuts.lang.JavaBeansConfiguration.setBeanProperty(JavaBeansConfiguration.java:154)
at pnuts.lang.JavaBeansConfiguration.putField(JavaBeansConfiguration.java:136)
at pnuts.lang.Java2Configuration.putField(Java2Configuration.java:101)
at pnuts.lang.Runtime.putField(Runtime.java:547)
at _pnuts_$2.exec(Unknown Source)
at pnuts.lang.PnutsFunction.exec(PnutsFunction.java:294)
at pnuts.lang.PnutsFunction.call(PnutsFunction.java:232)
at SamePOI.setDistance(Unknown Source)
at sun.reflect.GeneratedMethodAccessor63.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at pnuts.lang.Runtime.setBeanProperty(Runtime.java:3066)
at pnuts.lang.JavaBeansConfiguration.setBeanProperty(JavaBeansConfiguration.java:154)
at pnuts.lang.JavaBeansConfiguration.putField(JavaBeansConfiguration.java:136)
at pnuts.lang.Java2Configuration.putField(Java2Configuration.java:101)
at pnuts.lang.Runtime.putField(Runtime.java:547)
at _pnuts_$2.exec(Unknown Source)
... и т.д.


А если присваивать полю значение непосредственно снаружи, то все работает!

Сеттер имеет вполне типичный вид:

void setDistance(int d) {
this.distance = d
}


В чем проблема - ума не приложу! И с геттером, кстати, та же фигня :(

UPD 18:12 А вот еще что раздражает: длинные заголовки методов класса можно разбивать только так:

void myMethod(int param1, String
param2, bool param3)


Т.е. перевод строки можно ставить ТОЛЬКО между типом и параметром. Так работать не будет:

void myMethod(int param1,
String param2, bool param3)


Я специально взял отсюда и расковырял грамматику языка, чтобы убедиться, что так оно и есть:

TypedParamList = "(" ( ")" | TypedParam ("," TypedParam )* ")" ) ;
TypedParam = Param | ClassName Param ;
Param = Eol IDENTIFIER Eol ;

Т.е., если указываем ClassName, то Eol может следовать только сразу после него, либо (что еще страннее), ПЕРЕД запятой. Но не после. Т.е. так тоже будет работать:

void myMethod(int param1
,String param2, bool param3)


Вот так и проходит рабочее время))

Гамбург - 01

0 коммент. | добавить комментарий
Уже неделю работаю я в Гамбурге на благо компании Харман/Бекер. Приятно все-таки приезжать в компанию в третий раз: за это время несколько человек сами подошли ко мне с подходом «а я тебя уже видел, ты откуда, и т.д.» Так что число моих шапочных знакомых все время растет.

Один из них – Мартин (это тот, который босиком ходит), не перестает удивлять меня своими странностями. В пятницу поймал меня за пуговицу в коридоре и начал рассказывать о том, какой он трудоголик, как трудно ему различать «рабочее» и «личное», и какой он молодец, что может говорить об этом открыто. На нем висит значок «I am not normal», что, безусловно, чистая правда. Третьего дня, например, слышал от него историю, как он обновил какую-то навигационную таблицу, записал ее в навигатор своего автомобиля и поехал к родственникам, и как оно все плохо работало, и длительность поездки предсказывало с ошибками, и не туда его заворачивало, и пр…
Другой из них – Stefan - кстати, скоро станет нашим главным контактом с немецкой стороной. Питер наконец-то созрел для того, чтобы выделить человека, для которого работа с нами будет основным занятием, а не «между прочим», как это происходит сейчас. Штефан, как сказал Питер, тысячу лет работал на проекте БМВ, и сейчас ему срочно нужно сменить род занятий, чтобы не загнуться от тоски. Жду хорошего. Поживем – увидим, как оно будет.
Здание нашей работы находится над одним из многочисленных каналов, и, если выйти во двор, то с него есть спуск на понтонный причал, где отдыхают уточки.



В четверг играли с Питером в Го. О многом поговорили. Кроме Питера, я сыграл партию в Го с одним новичком (разумеется, обыграв его). Интересен род его деятельности: он проверяет, насколько плотно закручены болты в самолете, перед его взлетом. В его распоряжении 5 болтов – за остальные отвечают другие. И так – от рейса к рейсу – 5 болтов. Впечатляет занятие!
В Го-клубе много разговоров было о чемпионате Европы по футболу, проходящем сейчас. В тот вечер играла Германия, и Питер все хотел, чтобы они проиграли, и это сумасшествие на улицах закончилось. Каждый день в 20:45 начинается очередной матч – и до этого времени важно успеть поужинать, т.к. все кафе и рестораны, где есть телевизор, заполняются толпами оголтелых болельщиков. Турки, кстати, коих здесь великое множество, ох сильные болельщики – от сигналов их машин я в пятницу вечером почти оглох, пока шел под мостом возле станции Berliner-Tor. А за Россию, которая вчера играла, соотечественники болели, в основном, по кабакам – почти из каждого доносились крики на родном языке, когда я возвращался домой из бассейна. В метро на электронных табло, где пишут, сколько времени осталось до прибытия следующего поезда, вечером выводят счет текущего матча. Короче говоря, народ болеет.

В эти дни в Гамбурге проходит еще одно мероприятие – т.н. Harley Davidson Days. Со всей Европы сюда съехались десятки тысяч волосатых байкеров на своих мотоциклах, чтобы как следует напиться и покрасоваться. Их парад был вчера в районе St.Pauli, но я не пошел – посмотрел фотографии с прошлогоднего события и, признаться, побоялся, что затопчут. В центре, однако, их тоже было много, народ их фотографировал, и т.д. Как по мне – мотоциклы как мотоциклы, хотя я тоже не удержался и сделал пару фотографий для истории.


Вместо байков я вчера сфокусировался на местах, где еще не был в прошлые разы – Altstadt (старый город) и Hafencity (гавань). В последней я был, но в этот раз я зашел с другой стороны (с какой? Не знаю, как объяснить – со стороны Altstadt :)) Центральная старая часть города непохожа на нашу. Гамбург – город портовый, и сооружения там, преимущественно, квадратные и утилитарные, построенные для портовых контор и первых офисов. Основная особенность – красный кирпич, из которого в том районе построено без исключения все.

А, вот еще новость: я купил билеты в Брюссель! В пятницу, день своего рождения, после работы я сяду на поезд и чухну в Бельгию. Посмотрю на здания Евросоюза, писающих мальчика и девочку (да, есть и такая), поем бельгийского шоколаду да вафель, и вечером поеду обратно. Поезда в этот раз без пересадок – надеюсь, что дорога не будет такой утомительной, как была, к примеру, из Копенгагена в прошлом году. Туда-обратно – 110 евро – это вместе со скидкой, которую мне сделали как молодому, не достигшему 25 лет. Женю все равно наверняка потянет в Рим (дался ему этот Рим, блин!) – ну а я себе в Бельгию ))

Кстати о Жене – он прилетает в понедельник, но Тобик (наш ПМ) отказался его встречать. Поэтому ехать в аэропорт придется Михаэлю, который вообще к организационным вопросам никаким боком не относится (отвечает только за один из наших продуктов), да и машины у него нет. Так что, поскольку он мне симпатичен, я поеду вместе с ним, чтобы его поддержать. Интересно другое – меня Тобик встретил, т.к. я его contact person. А Женю, который работает над другим продуктом, он уже встречать не хочет, т.к., мол, «не его человек», и нечего на него тратить деньги на бензин. Смотрю я на этих немцев, и нарадоваться не могу их бесконечной бережливости!

Вот, вкратце, такие дела. О чем еще сказать? Ну, не знаю, меня, как всегда, много жизнеполагающих вопросов волнует. Например, вот елочка:

Так вот: горшочек у этой елочки просто разбился, или это такая художественная задумка?..

Еще один баг от Swing

0 коммент. | добавить комментарий
Только что еще один Свинговый баг побороли. На одной из ~10 машин, где работает наша программа, запуск диалога выбора файлов JFileChooser занимает примерно полминуты (ну о-о-очень долго, если честно). Кроме того, переход в любую папку также отбирает несколько секунд. Windows XP SP2 стоит, последние обновления, все дела... А на других машинах - все хорошо.

После непродолжительного копания, наткнулся на описание Java-Sun bug #5050516. Оказывается, на некоторых системах такое поведение вызывается поддержкой Windows Compressed Folders. После того, как отключили ее командой

regsvr32 /u %windir%\system32\zipfldr.dll,

все заработало быстро и правильно.

Багу больше 4х лет. В jdk 1.6 он еще живет. Вроде, исправили в седьмом, но я не проверял))

О стандартах на коды стран (оч.кратко)

0 коммент. | добавить комментарий
По работе столкнулся с проблемой кодов стран (сокращенных названий вроде RU, UA и т.д). Какая же это непростая проблема оказывается!

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

А, во! Еще у стандартов этих есть разные толкования - особенно у ISO-3. Сидим сейчас и гадаем, какой код у Румынии - ROL, ROM или ROU :)

Пароле-пароле-пароле

0 коммент. | добавить комментарий
А вы используете матерные слова в качестве паролей?

Помню красное лицо моего коллеги, когда ему пришлось по телефону диктовать по слогам слово "за-е-ба-ло", дабы его собеседник мог вытащить из его компа требуемый файл.

Сегодня тоже был прикол. Коллективно помогали другому коллеге вспомнить забытый пароль. У него фишка была в том, что в начале было слово, а в конце - номер месяца (март), в котором он его установил. Диалог был примерно такой:

- А, может, там был не март?
- Да нет, почему? Мат...

И дикий ржач. Без палива))

Побороли ошибку

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

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

А почему дергала, спросите вы? Такие уж это загадочные существа - женщины :)