понедельник, августа 11, 2008

ICFP '08 Results

Опубликованы результыты первых восьми заездов. Для удобства фаллометрии свел все в одну табличку. Get it and use it well.

Score — сумма по всем восьми заездам.

Команды не допущенные до девятого заезда в табличку не включены.

UPD: Добавил восьмой заезд. Плюс организаторы вернули еще 16 команд, дисквалифицированных по техническим причинам.

TeamScore
1UBE327090
2td329520
3Celestial Dire Badger330350
4Hands Solo330560
5Blue Iris331800
6Team Meh332900
7shinh333270
8NMSU333390
9team_bruno333590
10Team Smartass334470
11CNaml334680
12Error 404334770
13cw336130
14HackerDom_1336740
15Actua337670
16ILL martians337870
17Yeahbut338630
18fireinthedisco2340290
19ais523340450
20Arekuma341070
21TC2341190
22elbereth@utmc341290
23Spore Sept 7th, only $49.99! Play Bejeweled @ popcap.com!341510
24Apathy Kings342900
25LazyBear347940
26SzM348090
27Wile E.352650
28Sir Bedevere the Wise353750
29TeamDJ353980
30Kee355170
31jabber.ru356170
32frank324356270
33Urxae358030
34Malfunctional Programmer358770
35Heklers359580
36PurelyFunctionalInfrastructure361340
37Cup<'t>362370
38Side Effects May Include...362960
39Purple Pointer Eaters363780
40intelliarts365870
41Slow366260
42EdFred367150
4342367510
44The B-Team: 25/26ths as good as the A-Team371520
45a1k0n373610
46RHZ373950
47souris aveugle374140
48LUHPI374310
49little lemon375620
50kstm.org376070
51m1-speedygonzalez377810
52Team Sampou378210
53Five of Six378920
54Mosquito381240
55Eger a Marson381530
56ur 67P385050
57tidder385790
5812a0389440
59Giantslalom390270
60epriestley408520
61Om Nom Nom Nom409070
62Bobry412030

вторник, июля 29, 2008

Nomen est omen

Представим себе гипотетическую ситуацию: некий юноша-с-косичкой подрядился писать программу. Ну хотя бы учет посетителей в библиотеке. (Ещё ни одной приличной не видел) И вот доходят у него руки до учета пользователей и он радостно создает в базе табличку visitors {firstName, lastName, middleName}. А что, у всех буквально есть фамилия, имя и отчество. Вот у его знакомых в родном Крыжополе точно у всех. Да и девочка-библиотекарь, которая заместо аналитика, говорит что так правильно. И вот поступает такая система в эксплуатацию. А там кого только нет: и Александров-Погорельский, Ли Син Цин, и Хосе Луис Мария Педро Фернандос. И вот мучаются библиотекари, стараясь всунуть чуждые имена в прокрустово ложе программы, сыплются проклятья и летят в сторону незадачливого юноши лучики поноса.

Произошло это потому, что незадачливый программист не разобрался в сути моделируемых явлений. На больших объемах данных такой подход очень редко сходит с рук — всегда найдутся выпадающие данные, даже если на первый взгляд их быть не должно. Хороший пример: тройные фамилии вроде бы как запрещены законодательно, по крайней мере просто так её взять не получится. Возникает соблазн добавить проверку, и соблазн довольно опасный. Вероятность того, что системе попадется человек с тройной фамилией довольно велика на большой выборке. Аллах знает, как у них это получается, но сменить человеку фамилию можно только через суд.

Ещё одна распространенная ошибка — трактовать отчество как middle-name. Мне попадался даже один декан, который подписывался Boris A. Gladkih, видимо, не подозревая, что читается это как Борис Афанасий Гладких, что суть нонсенс. Второе имя это именно самостоятельное имя, которое можно использовать отдельно, пусть даже оно и дается в честь отца или деда. Отчество же без имени употребляется исключительно в качестве прозвища и только отдельно от фамилии: «Кузмич — за пивом пойдет». На эти грабли качественно наступили создатели формата fb2.

В наш век всеобщей глобализации правильнее не задумываться над традициями присвоения имен, а признать, что человек может сам выбрать как ему называться. Технологически, ничего сложного в этом нет, если только вы не хотите поддерживать все возможные традиции именования. Зато, если завтра к вам придет посетитель, у которого в паспорте написано «БОЧ рВФ 260602 Вячеславович Воронин-Фролов» вы будете к этому готовы.

среда, июля 16, 2008

ICFP '08 Contest

Контест завершился, завалы на работе разобраны, настало время небольшого отчета, куда-ж без него.

Preambula

Про ICFP contest я узнал начитавшись отчетов и сразуже захотел попробовать. Этот контест выгодно отличается от ненавистных мне «академических» олимпиад и их идиотскими заданиями, не имеющими ни малейшего отношения к реальности. Поскольку по одним субъективными отчетам трудно достоверно оценить явление было решено потрогать воду лапкой прежде чем готовиться к участвовать всерьез. Что и было проделано с величайшим удовольствием. Однако, некоторую подготовку я все же провел: настроил NetBeans с Ruby, создал необходимую структуру папок для проекта, поднял на всякий случай Linux под виртуальной машиной, скачал и запустил LiveCD

Day 0. Landing

За час до начала вылезаю на канал #icfp-contest и наблюдаю там больше 200 человек. С трудом дожидаюсь публикации задания. Большого смысла в этом нет, но хочется уже прочесть его, составить план штурма и отправится спать. Время из-за разницы во времени довольно позднее. В час «X» вся эта толпа, коей набралось уже за 300 человек радостно тянется качать задание и на несколько минут роняет сервер. Наконец я добираюсь до нужного документа и погружаюсь в чтение. Итак, задача этого года, в моем кратком изложении

Есть квадратное поле заданных размеров, представляющее поверхность Марса. На поверхности имеются:
  1. кратеры, в которые можно упасть, насмерть, много;
  2. валуны, о которые можно стукнуться, больно, тоже много;
  3. марсиане, которые норовят сожрать, самоходные, много;
  4. база, дружественная, одна;
  5. марсоход, свой, один.
На поверхность в произвольной точке высаживают марсоход (с довольно реалистичной физической моделью) для которого нужно написать программу управления (общающуюся с сервером по TCP/IP), приводящую его к базе в обход кратеров, валунов и марсиан. Соревноваться в итоге будут программы между собой, у кого лучше, тот и победитель. В деталях, оригинал на 12 страницах.

Прочитав задание, понимаю, что Ruby тут не при делах. Марсоход — железка глупая, не станет ждать пока досчитается, укатится к черту на рога. Решаю применить запасной вариант и использовать Java. Пока разворачивается IDE, лезу качать симулятор, но его ещё не выложили. Основных проблем в задании видится три: 1) Сетевой протокол; 2) Алгоритм управления; 3) Визуализатор для отладки. За пару часов реализую сетевой протокол, описываю необходимые структуры данных и с чистой совестью отправляюсь спать

Day 1. Doctrine: Mobility

Пока я спал, организаторы выложили симулятор, а участники в чате и рассылке развели невообразимый флейм. Быстро скачав симулятор, проверяю свой код. Сетевой протокол работает без отладки. В симуляторе оказывается встроенный визуализатор, так что от одной задачи я на некоторое время избавлен. Несколько часов уходит на то, чтобы научить марсоход ехать в заданную точку. Дело продвигается медленно, потому как тригонометрию я напрочь забыл, уж слишком давно не делал ничего подобного. Когда первая карта проходит отправляюсь кататься на велосипеде, а вечером принимаюсь за объезд препятствий. Лобовое решение, отворачивать от препятствия расположенного в опасном угле по курсу работает плохо. Объехав первый кратер, марсоход сослепу ухает во второй. Мне подкидывают идею, предсказывать положение марсохода на несколько ходов. Решаю заняться этим завтра и отправляюсь спать.

Day 2. Doctrine: Flexibility

Со вчерашнего дня обнаружилась ещё одна проблема: перерегуляция, приводящая к том, что марсоход пролетает мимо базы. Решил сперва побороть её и ввел эвристики, запрещающие крутые повороты вдали от базы для наведения на цель. С предсказанием все плохо, марсоход едет довольно паршиво, часто падает в кратеры и стукается о валуны. Приседания с параметрами дают немного. Это продолжается до тех пор, пока я не начинаю проверять точность предсказаний в реальном времени. Сперва обнаруживается, что я забыл учесть трение и предсказания скорости не слишком точны. Добавив систему оценки трения и ускорения, получаю точность предсказания скорости до четвертого знака. Выглядит хорошо, но точность предсказания расстояния не изменилась. Проверяю расчеты калькулятором и обнаруживаю, что java.lang.Math принимает аргументы синусов и косинусов в радианах, а я считаю углы в градусах. Правлю и точность hgtlcrfpfybq достигает требуемой. Поскольку нет необходимости в играх с параметрами, устанавливаю предсказания на 5 секунд вперед. Все три тестовые карты проходятся, так что я начинаю искать, на чем бы ещё протестировать. Поскольку возможности достать и померяться прямо в процессе организаторы не предусмотрели народ во всю обсуждает результаты и выкладывает собственные карты. Пытаюсь протестировать на чужих картах и обнаруживаю два факта: а) на рандомных картах сходных с тесовыми все работает идеально; б) стенки, «рюмки», «бутылки», лабиринты и прочие непрерывности вводят марсоход в ступор. На этой прекрасной ноте отправляюсь спать.

Day 3. Doctrine: Initiative

Пенедельник — день рабочий, поэтому за марсоход удается приняться только к вечеру. Проверять на каждом шаге полноценное дерево решений чтобы выбрать оптимальное мне влом. Судя по отзывам не меньше половины участников этим не заморачивались, уповая на отсутствие в реальных тестах стенок. Так что я решаю посвятить оставшееся время отладке и доводке. На марсинан также решено забить. Мой марсоход едет быстро и непредсказуемо, так, что даже я не всегда могу предполагать куда он свернет. Перехватить его марсианином, задача гораздо менее тривиальная, чем объезд препятствий, так что с марсианином он может столкнуться только по чистой случайности. Вычисление радиуса поворота в эвристиках для определения необходимого положения руля значительно помогло. Теперь марсоход едет быстро, оптимально и опасно. Решаю оставить как есть в надежде, что он не свалится в кратер больше двух раз. Пробую ещё пару идей, но они не работают. Сперва пытаюсь объединить пересекающиеся препятствия в одно большое, но точности это не увеличивает, зато существенно замедляет работу. Затем пытаюсь настроить москитный маневр (вместо движения прямо, рулить попеременно влево-вправо для затруднения перехвата), но это ухудшает точность предсказаний, которые на него не рассчитаны. Допиливать предсказания не хочется, поэтому сабмичу, как есть. Выложат результаты, будет видно насколько мои предположения оправдались. 

Conclusions

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

четверг, июля 03, 2008

Date, Time, Interval, and Duration

С представлением времени в большинстве систем творится полный бардак. Ладно, RDF с OWL’ем, там и без этого все плохо, но даже в стандартных библиотеках самых что ни на есть мейнстримных языков полный бардак. Ну что нужно курить чтобы в стандартный класс Date добавить преобразование к Юлианскому календарю? Ни разу не встречал человека, которому бы это потребовалось. Зато вычислять интервал между двумя событиями приходится вручную. Давайте попробуем спроектировать библиотеку для работы со временем правильно. Может хоть кому-нибудь живой пример вправит мозги.

Итак, что такое время для программиста? Это одна координатная прямая, на которой определена выделенная точка «сейчас», делящая прямую на «прошлое» и «будущее». Примитивные племена на этом и останавливаются, оперируя тремя понятиями: «было», «есть» и «будет». Современному человеку требуется больше: время должно быть измеримо. Это позволит производить вычисления (до сеанса осталось полчаса) и учитывать порядок событий ([сначала]он мне в глаз, а [затем] я ему в ухо) от которого и до причинно-следственной связи недалеко. Для того чтобы сделать время измеримым на прямую произвольным образом добавляют фиксированную выделенную точку «0». Исторически сложилось так, что в разных культурах эту точку добавляли по-своему. Это мог быть день коронования императора, начало определенного года, произвольно выбранный момент времени и даже время «сотворения мира». В мире UNIX, например, это полночь 1 января 1970 года.

С другой стороны люди привыкли к довольно неудобной для вычислений системе предстваления времени, связанной с циклами вращения Земли. Опять же, в разных культурах к этой проблеме подходили по разному. В результате год начинается в разное время и по разному делится на месяцы в зависимости от культуры. Более того, в разных культурах привычные способы записи времени сильно отличаются, даже если системы счисления времени совпадают. Та же американская ММ/ДД/ГГ и русская ДД.ММ.ГГ.

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

Поскольку продолжительность суток растет, каждые несколько лет к UTC добавляют секунду, чтобы компенсировать замедление. Это тоже усложняет точные расчеты, однако, пока не вызывает проблем, поскольку единой системы точного времени затрагивающую все — от GPS приемников до кофеварок не создано.

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

Первое, что нам требуется, это момент времени (Timestamp) заданный с максимальной возможной точностью в некоторой системе отсчета, хоть UNIX time. Этот класс является платформозависимым, поскольку умеет работать с системным таймером. Никаких преобразований или вычислений этот класс делать не должен. Очень часто требуется работать с моментами времени с точностью до минуты, дня или года, в этом случае максимальное разрешение тут только мешает. Для некоторой частых случаев можно определить классы Date и DateTime и точностью, соответственно, до дня и до секунды. Timestamp должен корректно поддерживать сравнение отметок времени с максимальной и ограниченной точностью.

Второе — интервал между двумя моментами времени (Interval) Интервал можно представить двумя моментами времени: начало интервала и конец интервала. Интервал должен уметь вычислять свою продолжительность. Кроме того, нужна возможность зная начало или конец интервала и продолжительность, получить интервал.

Третье — продолжительносить (Duration) Внутри продолжительность хранится в максимально возможной системной точностью.

Для каждой из трех сущностей потребуется два интерфейса: *Parser и *Formatter имплементации которых служат для преобразования сущностей из строки и к строке (или прочим типам). Кроме форматирования, их зона ответственности — преобразование к другим системам представления времени, например к тому же юлианскому календарю.

В основном, этого достаточно. Естественно, в некоторых языках можно добавить собственные удобности, например профайлинг в Ruby:

duration = Duration.measure do
...
end

вторник, июня 24, 2008

RuPyRu 2008. Конференция

Пару слов о самой конференции. В целом RuPyRu оправдала мои ожидания: хорошая, добротная провинциальная конференция.

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

Качество докладов оставляет желать лучшего. Было очень много рассказов своими словами об использовании чужих технологий, разбавленных собственным опытом. По большому счету такие доклады бесполезны, поскольку такую информацию легко почерпнуть в мануале, а все, кто «в контексте» давно прочитали обзорные статьи в блогах и форумах. Вопросы в стиле «Почему это сделано именно так?» таким докладчикам тоже задавать бессмысленно, не они технологию разрабатывали, откуда им знать.

Познать механизм деления докладов на «общий» и «специальный» потоки мне не удалось. Интересные доклады были и там и там. Я бы предложил деление на «пользовательский» и «авторский» потоки. В первом — краткие обзорные доклады, посвященные чужим технологиями, во втором — доклады авторов о собственных разработках и доклады экспертов. Понравилось, что Ruby и Python не были разнесены на отдельные потоки, что позволило познакомиться с конкурентными технологиями.

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

Идея круглых столов с едой, хороша, но реализация не слишком хорошо удалась. Стоило составить физические столы так, чтобы народ сидел лицом друг к другу, обозначить вопросы на обсуждение и как-то организовать дискуссию. Темы круглых столов тоже не слишком удались. Здесь бы стоило разнести Ruby и Python на разные столы, поскольку в таком формате обычно обсуждаются довольно тонкие вопросы, пользователям конкурентной технологии не интересные.

Из интересного для меня оказались совершенно не раскрыты темы развертывания Rails и Django приложений, использования динамических языков для кодогенерации, использования Ruby и Python в качестве скриптовых языков внутри приложения и создания DSL на базе динамических языков.

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

RuPyRu 2008. Омск

памятник Ленину

Дожидаясь начала конференции удалось прогуляться по Омску. Увы, было ранее субботнее утро, поэтому оценить вид города в час пик не удалось. Утром выходного дня все города выглядят одинаково хорошо. На вокзале нас встретил традиционный бронзовый Ленин, твердой рукой указующий почему-то на здание вокзала. Видимо, это должно означать: "Убирайтесь, откуда пришли".

памятник Оленям

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

памятник Сантехнику

В центре города нам встретился памятник Говночерпию Сантехнику, из вечно актуальной серии памятников рабочему классу (памятники Электрику и Дворнику в Томске) Расположенный прямо на тротуаре, он символизирует близость рыцаря труб и задвижек к народу, а умиротворенное выражение лица убеждает в чистоте его намерений.

граффити

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

мотоцикл

Омские байкеры настолько суровы, что способны ездить даже на таком странном звере. К сожалению застать его едущим нам не удалось.

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

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

среда, июня 18, 2008

Just few photos

Вернулись со сплава по Средней Катуни. Выяснилось несколько забавных вещей:
  • Камера µ 770 SW + запасной аккумулятор + 2Гб флешка категорически рулят. Мочить камеру водой не страшно, поэтому вдохновившись радостно наснимали 1.5Гб фотографий, из которых, правда, половина — чье-то весло или каска.
  • С каждым годом количество крупных вещей уменьшается, а мелких — растет приближаясь к стандарту «все необходимое можно распихать по карманам»
  • В следующий раз в качестве полезной вещи нужно брать термос с горячим чаем. Правильно зафиксированный, он, скорее всего, не разобьется.
  • Свой котелок и горелку мы совершенно напрасно не взяли, понадеявшись на общественный. В результате, большую часть времени обходились без чая потому, как дождавщись когда он согреется, уже никакого чая не хочется.
  • После Алтая воняет даже Академгородок:-(
Несколько пейзажей без сюжета:

среда, июня 11, 2008

Declarative interface

Gineer, попросил меня описать, что я понимаю под декларативным интерфейсом. Признаться, идея пришла мне в голову прямо здесь, но я попытаюсь оформить ее в разумную форму. Любой прибой, по сути своей является черным ящиком для пользователя. Разговаривая по телефону, можно ничего не знать о модуляции, СВЧ технике или принципах маршрутизации голосового траффика. Декларативным я называю интерфейс, построенный в терминах потребностей пользователя, а не средств их достижения. По идее, любой интерфейс любого прибора может быть декларативным, однако, на практике это не так. Например, мой телефон требует для установки будильника следующей последовательности команд: Меню > Развлечения > Будильники > Выбор одного из трех возможных > Включение > Установка времени > Установка режима "повторять ежедневно/по будням/никогда" > Выбор мелодии > Подтверждение. Это идиотский интерфейс, потому что он заставляет меня думать не об исходной потребности, а о деталях реализации. Мне нужно, чтобы телефон разбудил меня в указанное время. Все остальное лишь опции. Для чего мне знать, сколько у телефона будильников (готов спорить, их три, только для того, чтобы влезли на один экран в интерфейсе), которые из них включены и как именно он меня собирается будить. Декларативным будет примерно такой интерфейс: разбуди_меня вермя|интервал [периодичность] [способ], где вермя может быть в любом формате от "в 1130" до "завтра в 8", а то и вовсе интервал: "через 2 часа". Конечно, это потребует продвинутого date/time picker, но изваять такой уже давно не проблема. Еще понадобятся две функции: покажи_список_будильников и отмени_будильник > выбор будильника Может показаться, что приведенный синтаксис относится только к CLI, однако это не так. Аргументы команды вполне могут выбираться самостоятельным диалогом. В GUI команду можно представить в качестве мастера, опциональные параметры которого легко пропустить или установить в любом порядке. Из идеи декларативного интерфейса есть одно интересное следствие, которое стоит обдумать. Если более строго описать синтаксис UNIX команд с учетом зависимостей, типов и связей параметров, возможно, удастся помирить GUI с CLI. Хотя бы посредством автогенерации интерфейсов.

четверг, мая 01, 2008

What do you need to know

Как вести проектную документацию? Оставим в стороне ГОСТы, RUP, фантазии некомпетентных и прочую фигню и сосредоточимся на одном вопросе: "Какая документация вам нужна в проекте, рассчитанном на несколько лет?" Проекты в стиле "Сделал и забыл" (а это большая часть аутсорсинга) в документации не нуждаются и останутся за скобками. Итак, поехали:

Первое, что нам нужно, это требования. У натуралистов есть такое правило: "Не записано ― не наблюдалось" Это именно то, чем стоит руководствоваться при работе с требованиями. Почему это важно? Да потому, что без требований "в бумаге" через три месяца вы не сможете отличить баг от реально затребованной кем-то фичи, через полгода у вас появятся "гуру" обладающие редким знанием о том, что именно и зачем вы делаете, через три года вы обзаведетесь прекрасными образцами устного фольклора, которые останутся единственным источником информации об истории проекта, а через пять лет, когда вы захотите все переписать с использованием современных технологий, вам придется нанять археолога.

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

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

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

четверг, апреля 24, 2008

Geoid

Земля имеет форму шара, Забавно видеть хуй омара. Азбука
А вот хрен — возвопят просвещенные — не шара, а геоида. Эта феерическая глупость передается из уст в уста. Не исключено, что она уже просочилась даже в школьные учебники. По крайней мере в русскую википедию просочилась:
Геоид- фигура, отражающая форму Земли, важное понятие в геодезии.
Помилуйте, геоид не имеет решительно никакого отношения к форме Земли. Более того, изобретать просто так фигуру «описывающую форму Земли» бессмысленно. Однако, математики давно прослыли чудаками и эта бессмысленность не бросается обывателю в глаза. Если вы приглядитесь к картинке, геоид довольно слабо напоминает форму Земли. Откуда же он взялся? На самом деле геоид имеет вполне практическое применение. Как вы все наверняка знаете, географические координаты (те которые широта и долгота) суть координаты сферические. Однако, поскольку земля не сфера и не эллипс, возникает вопрос: относительно какой сферы задаются географические координаты? Математики давно предложили работающее решение: использовать мнимый эллипсоид вращения как-то худо-бедно совпадающий с земной поверхностью. Для вычислений идеально, однако, стоя в чистом поле довольно трудно этот эллипсоид обнаружить. Он же математическая абстракция. Мудрые математики и тут не сплошали. Они расположили эллипсоид так, чтобы короткая ось его совпадала с осью вращения земли, в центр его совпадал с центром масс Земли или был смещен относительно него на какое-то расстояние. Из физики мы знаем, что ось вращения проходит через центр масс. Осталась малость, вычислить его положение относительно поверхности. Для это была проведена гравиразведка все поверхности земли и построен геоид — фигура на поверхности которой сила тяжести постоянна и совпадает со средней силой тяжести на поверхности моря. Этого достаточно чтобы определить центр масс геоида, который совпадает с центром масс Земли. Зная, где находится центр масс, мы можем поместить в центр земли эллипсоид (умозрительно, конечно) и использовать его для определения координат.

четверг, апреля 10, 2008

Half-life

Период полураспада для большинства нововведений составляет две недели. Вне зависимости от того в чем состоит идея: вести документацию в wiki или штрафовать за неположенное распитие пива. Каждый может припомнить несколько довольно хороших (или ужасных) идей, которые «не пошли». Связано ли это с тем, что идеи плохие? Нет, распадаются и вполне хорошие начинания. Со стороны видно, что внедрить что-то сложнее чем кажется. Любая система обладает некоторым запасом инерции и социальные системы не исключение. После того как программистам наказали указывать номер бага при коммите обязательно придется некоторое время следить чтобы это правило выполнялось. И лишь через какое-то время оно перейдет в разряд «здесь так принято». Никогда, ни одно правило не будет выполняться только потому, что оно есть. Время принятия зависит от того, насколько нововведение выгодно конкретным исполнителям. Дневные отчеты могут быть офигенно полезными для проекта и для компании в целом, но если программисты не видят в них смысла, они будут забрасываться при каждом удобном случае. В идеальном случае, когда все без исключения исполнители понимают, какую пользу им принесет нововведение, они способны сами его внедрить. На практике это случается довольно редко. Итак, несколько практических рекомендаций:
  • Продумывая любое изменение обязательно оцените ресурсы потребные на его внедрение;
  • Назначьте ответственных за внедрение;
  • Донесите до исполнителей выгоды, которые им сулит нововведение;
  • Если нововведение не сулит ничего хорошего исполнителям, обеспечьте им выгоду искусственно;

среда, апреля 09, 2008

Alone

Принято считать, что в современном мире для любой серьезной вещи нужна команда. Поговорки-пословицы всякие: «один в поле, волкам на потеху», «семеро одного не боятся», «команда — все, остальное — волшебные пузырьки». Вроде бы, как само собой разумеется, что производительности одного человека ни для каких серьезных задач недостаточно, а вот команда это сила. Ещё бы, на один только чай команда тратит в день больше времени, чем один человек может удалить работе в неделю. Доходит до того, что привычный к командной работе программист смотрит на индивидуальную задачу и изрекает: «да тут мне одному на полгода». И действительно, провозится с задачей 6 месяцев. В то же время, за стенкой может сидеть человек, стабильно решающий подобные задачи за месяц каждая. Производительность лучших и худших программистов отличается примерно на порядок. Всякий имеющий доступ к метрикам может получить эти данные самостоятельно. Вопрос в том, за счет чего так получается и какую выгоду можно извлечь, если работать в одиночку. Самое очевидное, это работа с постановкой задач. Любую задачу можно решать разными способами. К тому моменту, как задача доходит до программиста через кучу промежуточных звеньев, она обрастает коркой фантазий, зачастую не имеющих никакого отношения к исходной проблеме. Например, клиент хочет, чтобы работающие с программой менеджеры не забывали о назначенных встречах. Можно реализовать управление встречами в программе, а можно обратить внимание, что в компании уже используется для этого Outlook с которым довольно легко интегрироваться. Аналогичные ситуации возникают и при внутреннем взаимодействии. Быстродействующий программист не станет ничего делать пока не выяснит, какую именно проблему он должен решить. Второе, это правильное использование готовых средств. Если собственное решение занимает три недели, а применение готового — несколько часов на чтение документации и пару дней на исправление багов в чужом решении, это сэкономит две недели. В другом случае, частное решение пишется за неделю, а на использование существующего могут уйти недели. Умение верно оценить, сколько времени займет переиспользование, а с сколько собственное решение и есть искусство быстрой сборки из кубиков. У быстродействующего программиста нет времени изобретать все свои велосипеды самостоятельно. На третьем месте — острая пила. Инструмент должен быть адекватен решаемым задачам. Это касается как языков и библиотек, так и окружения. В эту бочку и владение инструментами (от IDE до shell) и DSL, и метапрограммирование с кодогенерацией. Отдельные аспекты «заточки пил» освещены изрядно. Пилы быстродействующего программиста всегда острые. Если хотите готового чеклиста:
  • Может ли исходная проблема быть решена более простым способом?
  • Можно ли изменить условия задачи так, чтобы она решлась существенно проще?
  • Есть ли для задачи готовое решение?
  • Существует ли инструмент, позволяющий решить данную задачу быстрее?

среда, марта 26, 2008

Meeting

-Пойдем с нами, помитингуем. -Надолго? -Да нет, часа на полтора.
Знакомо? Митинги — хороший способ осознать какова сила командной работы. За полтора часа разговоров команда тратит столько времени, сколько тебе в одиночку не потратить за неделю. На первый взгляд, кажется что время тратится с пользой. Люди говорят, спорят, обсуждают, но стоит поймать выходящего из комнаты для совещаний и спросить, что, собственно, обсуждалось, и что было решено, как будет получен ответ в стиле: «Ну взаимодействие системы, А с подсистемой B. Петро будет спеку на интерфейс писать." Помилуйте, что тут можно было обсуждать полтора часа? А ведь существуют компании где на подобные совещания тратится больше половины рабочего времени, а большая часть «митингующих» рисует чертиков. Между тем способ сделать собрания эффективными давно известен всем желающим. Нужно лишь соблюдать несколько простых правил:
  • Прежде чем назначить совещание нужно составить план, в котором будут перечислены вопросы вынесенные на обсуждение и предполагаемое время обсуждения каждого. Это позволит определить список заинтересованных лиц и оценить время необходимое на совещание. С планом необходимо ознакомить всех участников заранее, а не прямо на месте. Лучше, если участники будут пропускать несущественные для себя вопросы, чем рисовать чертиков.
  • Если в процессе обсуждения поднимается новый вопрос, план ни в коем случае не меняется на лету. Вместо этого назначается отдельное обсуждение с собственным планом и отдельными участниками. Если участники будут уверены в том, что план не изменят на лету, они смогут пропустить несущественные для них вопросы.
  • На любом совещании должен быть председатель. Его задача следить за соблюдением регламента, прерывать затянувшиеся обсуждения и вести протокол. По окончании совещания протокол выдается всем участникам или публикуется. Протокол нужен обязательно. Иначе уже через полчаса непонятно почему было принято какие-то решения, а на следующий день забываются и сами решения.
  • Любой участник может поручить любому другому участнику говорить от своего имени. Это позволит сэкономить время самым продуктивным сотрудникам, способным сделать за время совещания что-то более полезное.
  • Если кто-то из приглашенных счел возможным не придти, и не доверил свой голос другим участникам, это автоматически означает его согласие с любым принятым решением. 
Более подробно этот подход описан у ДеМарко в «Deadline». Там же есть и примеры удачно проведенных совещаний.

понедельник, марта 17, 2008

Code conventions

Через пару недель проекта, особенно если оный был расчитан на достаточно долгий срок, всегда находится гаврик, считающий, что для успешного существования проекта необходимо немедленно, пока не слишком поздно, написать code conventions. Не будучи вовремя остановленным, он за один присест порождает страниц, эдак, двадцать, заполненных беспорядочными правилами, вроде:
Имена переменных должны удовлетворять camelCase; Недопустимо обращение через две точки, во имя закона Деметры; Бинарные операторы должны быть отделены пробелами с обоих сторон; В сеттерах нужно использовать this; Забытая в микроволновке еда считается общей; и т.д.
Обычно такой документ живет ровно две недели, затем перемещается в архив, извлекаемый оттуда только для того чтобы продемонстрировать его новичкам. Поскольку документ изначально не соблюдался и разительно отличается от негласных соглашений принятых в коде, новички тоже откладывают его в сторону. От проекта к проекту такая ситуация повторяется с завидной регулярностью. Причина в том, что любая дополнительная активность, как написание комментариев, проверка кода на соответствие соглашениям, комментарии к коммиту в VCS требует дополнительных затрат. Если преимущества от этих действий неочевидны человек склонен «забывать» их делать. Поэтому введение в проекте code conventions автоматически означает появление роли следящего за их соблюдением. Для того чтобы решить проблему недостаточно опубликовать документ, каким бы хорошим он ни был. Нужна постоянная активность,  это везде так. Отлично, но следить за соблюдением правил, описанных на двадцати страницах, отнимает прорву времени. И это вторая причина, по которой затея с code conventions проваливается. Теперь, когда мы добрались до сути, мы можем сформулировать рекомендации для написания соглашений. Но, сперва, давайте обозначим проблему, которую мы собираемся решать. Разные программисты предпочитают разные стили написания кода. Если несколько разных стилей смешиваются в одном файле, этот файл становится трудным для чтения. Разнобой в стиле выглядит неряшливо и поощряет неряшливость уже в самом коде. Соглашения о коде призваны устранять неоднозначности в выборе несущественных деталей оформления, в идеале сужая пространство вариантов до одного. Как же писать code conventions? Определите кто ваши программисты. Кто сказал: «Они все здесь»? А как же библиотеки, которыми вы пользуетесь. Их интерфейсы должны вашим соглашениям. Естественно, вы не в силах заставить сторонних разработчиков соблюдать ваши стандарты, но вы всегда можете подогнать стандарты под них. В противном случае использование библиотек будет выбиваться из общего стиля и увеличивать энтропию проекта. Все соглашения можно разделить на две части: поддающиеся автоматическому переформатированию и не поддающиеся. Переформатированию поддаются такие вещи как количество пробелов, формирование отступов, расположение скобок, длина строк и т.п. Лучший способ их публикации, это положить в VCS файл настроек для IDE. Можно также настроить VCS сервер на вызов автоформаттера перед каждым коммитом и забыть о них навсегда. Описывать их в документе совершенно не обязательно. Не стоит поручать человеку делать то, что сумеет машина. Не поддаются переформатированию такие вещи, как имена файлов, переменных, пакетов и классов, стиль работы с исключениями, расположение файлов. Продвинутые автоформаттеры умеют отлавливать ошибки, но исправлять из автоматически невозможно. Поэтому все что не поддается автоформатированию придется описать в документе явно. Документ содержащий code conventions не должен быть большим. Четырех страниц более чем достаточно. По крайней мере ограничение объема избавит вас от соблазна включать в документ правила пользования микроволновкой. Если есть возможность, не изобретайте велосипедов. Почти всегда можно взять готовые документы у разработчиков языка или людей в нем авторитетных. Вот несколько таких примеров: Утилиты для автоформатирования кода:

вторник, марта 11, 2008

Как выбирать библиотеку

Каждый раз сталкиваясь с новой задачей мы задаем себе вопрос: Стоит ли ее решать? Возможно, удастся использовать готовое решение. В этом сила программирования, для большинства задач, таких как вывод суммы прописью или реализация протокола Z39.50 давно существуют готовые решения. Но, если решений несколько, как выбрать одно из них? Или может быть отказаться от всех них и реализовать задачу самому? Для многих такой выбор оказывается черезмерно сложным и они скатываются к одной из двух крайностей: предпочитают во всех случаях готовые средства или всегда изобретают велосипеды. Однако, разумные люди предпочитают объективно оценивать ресурсы. Я определил следующий набор критериев:
  • Большинство библиотек плохо работают на грани своей области применимости. Например, все известные мне попытки применить Hibernate или ActiveRecords из Ruby on Rail к сложной унаследованной базе, вдобавок денормализованной достигали цели только посредством тяжких ухищрений. Убедитесь, что вы собираетесь использовать библиотеку именно так, как это запланировано разработчиками. В противном случае, выбросьте ее сразу. Все равно она для вас не подходит.
  • Срок жизни кода в среднем составляет 5-10 лет до того момента как он морально устареет и будет выброшен. Это тот срок, когда кому-то нужно будет поддерживать код. Соответственно поддержка библиотеки должна быть расчитана на тот-же срок. Будет неприятно, если через пять лет в критичной библиотеке найдется критичный баг, который невозможно исправить, поскольку разработчики библиотеки давно испарились вместе с исходниками. Для коммерческих библиотек с закрытыми исходниками это может стать серьезной проблемой. Для Open Source такой гарантией может стать поддержка большого сообщества или серьезной конторы вроде IBM, Intel или Sun
  • Критичный для функционала проекта должен писаться только собственноручно хотя бы на один уровень вглубь. Например, если мы занимаемся разработкой GIS системы, мы можем взять набор классов с представлением географических координат из десятков библиотек. Но координаты расползутся по всему приложению и заменить библиотеку когда она перестанет удовлетворять будет практически невозможно. Модели предметной области, бизнес правила, уникальные для вашей предметной области элементы интерфейса должны разрабатывать только вы сами. В противном случае у вас есть все шансы при очередном изменении требований столкнуться с ограниченностью библиотеки. К сожалению разработчики библиотек этого не понимают и норовят запихнуть свои «фреймворки», «модели предметной области» и «наборы бизнес правил» во все подходящие, на их взгляд, проекты
  • Любая библиотека имеет склонность врастать в продукт и изменять его вокруг себя. Выбор, например, log4* навсегда определит вашу стратегию логгирования. Хорошая библиотека, изменит продукт в лучшую сторону, плохая только ухудшит. Стоит следить, чтобы архитектурные принципы используемых библиотек были сходны с вашими, code conventions не слишком отличались, а политика релизов была ясной и прозрачной. Плохое регрессионное тестирование библиотек или нарушение обратной совместимости приведет к шаманствам с зависимостями при сборке проекта и багам при обновлении библиотек. Важно понимать, что библиотека это не просто набор интерфейсов, а живой организм со своими особенностями.
Для того чтобы руководствоваться этими принципами на практике есть простой чеклист:
  • Функционал реализуемый библиотекой критичен для проекта?
  • Насколько сложно написать собственный код по сравнению с использованием библиотеки?
  • Является ли библиотека open source либо предоставляют ли производители какие-то осязаемые гарантии?
  • Насколько велико сообщество пользователей библиотеки?
  • Как часто выходят релизы и фиксятся баги?
  • Насколько хорош код библиотеки?
  • Насколько хороша документация?

понедельник, марта 03, 2008

Очередной пример "замечательного" перевода. Фильм Zodiac, фраза: "His ashes were scattered by his family in San Francisco Bay", перевод: "Его статьи и записи были проданы его семьей с аукциона E-Bay". Я нашел только два совпадающих слова. Интересно, что курил переводчик?

вторник, февраля 26, 2008

Ноль это бесконечность, а минус единица это ноль

В некотором отделе некоторой компании разрабатывали продукты, да не простой а коробочные. Целые отдел маркетинга днями и ночами продукты те толстым буржуям продавал, да лицензии для них генерировал. И были те лицензии не простые, а с ограниченным сроком годности. Кому на месяц, кому на полгода, а кому и год. Жили они так не тужили, пока отдел маркетинга не задумался, а что это мы продукты по одному продаем, несолидно. Cтали они продукты на части разбирать в ящики складывать и ящики продавать. А на ящиках тех златом, али серебром писать слова иностранные. Все бы ничего, да продукт-то программный, а значит ящики — фикция одна. Дело только в лицензиях, в которых для каждой части строчка отдельная добавилась. А в строчке той цифирь, означающая сколько частей в ящике. Тут бы им жить поживать, да встретился местный барин на какой-то конференции с барином иностранным, другом старым. Тот-то ему и пожаловался: «Мы, — говорит, — друзья старые, а твои архаровцы меня заставляют на каждую новую часть отдельную лицензию делать. А у меня этих лицензий уже два камаза с прицепом» Призвал барин программистов пред светлы очи и повелел бесконечную лицензию выдумать. Но поскольку призывал он всех по отдельности, разные продукты разное выдумали, потому как нет такой цифири «бесконечность». Один решил вместо бесконечности «0» писать, все равно на ноль штук лицензия не нужна. Другой решил, что ноль ему пригодится и «-1» под такое дело зарезервировал. Ну а третий долго не думая самое большое число, которое знал, использовал. Долго ли, коротко ли, придумал отдел маркетинга новую забаву. Теперь пока лицензия не кончилась, ее стало можно переоформить: частей добавить или изъять. Ну а раз изъять, то и нули в строках стали возможны. Пришлось программистам еще раз напрячься, да ноль выдумать. Ну а когда стали правила лицензирования в отдельный продукт собирать, запестрел он правилами вроде «если продукт один ноль это бесконечность, а минус единица это ноль, а ежели другой, то все наоборот». И набралась таких правил толстая книга. Мораль, прежде чем изобретать велосипед, посмотри уже изобретенные, да посоветуйся с коллегами.

вторник, февраля 19, 2008

У каждого бага есть имя, фамилия и отчество

Был такой замечательный человек, Лазарь Моисеевич Каганович. Сейчас как-то принято ругать всю сталинскую эпоху скопом, поэтому Лазаря Моисеевича чаще всего вспоминают как в связи со "сталинскими" репрессиями, коллективизацией сельского хозяйства на Украине и сносом старых зданий в Москве. Умер Каганович в 1991 году, в возрасте 97 лет, совсем немного недотянув до развала СССР. Так вот, в бытность свою наркомом путей сообщения, Каганович произнес замечательную фразу: "У каждой аварии есть имя, фамилия и отчество". Слово не разошлось с делом, начались служебные расследования и многие нерадивые, как тогда было заведено, были обвинены во вредительстве и отстранены. Результат: в начале Войны при эвакуации, несмотря на страшную перегрузку всей транспортной системы, не произошло ни одной серьезной аварии. На мой взгляд, это самый выдающийся результат, который вообще возможен. К сожалению эту замечательную фразу в последнее время забыли и уж тем более не принимают как руководство к действию. Сейчас принято считать, что бывают ситуации, в которых никто не виноват. Они как-бы происходят сами собой, безо всякого человеческого вмешательства либо считаются просчетом всего коллектива, всего общества. Рванула чернобыльская АЭС, виновата "некомпетентность". Застрелился новобранец, виноваты "деды". Выпустили релиз с блокером, виновата команда. И как-то так получается, что никто конкретно и не виноват. А раз никто не виноват, так действительно накосячивший никогда не осознает совей ошибки и обречен повторять ее снова и снова.

пятница, февраля 01, 2008

Primary keys in life

Те, кто изучал реляционные базы данных в теории обычно убеждены в том, что некоторые виды объектов по самой своей природе обладают некоторым привычным ключом. Обычно приводят такие примеры: человек — серия и номер паспорта или номер социального страхования или ИНН; книга — ISBN и так далее. На первый взгляд кажется, что эти поля подходят для первичного ключа. При некоторых допущениях так и есть. Однако так ли это на самом деле? Рассмотрим того же человека:
  • Серия и паспорт человека меняется как минимум трижды в течение жизни;
  • У книги может быть как несколько номеров ISBN, так и не быть ни одного;
  • Бывают люди без ИНН и номера социального страхования
Однако на этом проблему не заканчиваются. Что будет если нам придется импортировать данные из сторонних систем? Можем ли мы использовать первичные ключи для этого? Предположим, мы импортируем список людей содержащий имена, даты рождения, данные паспорта и СНИЛС. Совпадение каких полей может служить однозначной идентификации? Правильный ответ: только совпадение всех полей позволяет однозначно связать две записи. Рассмотрим пример подробнее. У нас есть несколько кластеров данных в каждой записи: 1. Тройка фамилия-имя-отчество 2. Дата рождения 3. Данные паспорта (серия-номер-дата выдачи-выдавший орган) 4. Номер социального страхования СНИЛС Я намеренно упустил из виду существование других документов удостоверяющих личность, лиц без гражданства, иностранных граждан и т.п. Будет достаточно одного простейшего случая. Из предметной области мы знаем:
  • У человека может измениться фамилия, что происходит довольно часто, имя или отчество, что происходит занчительно реже;
  • В особых случаях у человека может измениться дата рождения;
  • Смена фамилии, имени или даты рождения влечет смену документа удостоверяющего личность
  • Человек может получить новый паспорт с совершенно другими данными, никак не связанными с предыдущим;
  • Человек может получить другой номер ИНН, что происходит довольно редко, но происходит;
  • Человек может получить другой СНИЛС, что происходит довольно регулярно;
  • При внесении данных в базу возможны ошибки оператора;
  • На больших объемах данные проявляется "эффект больших чисел": разные люди с частично совпадающими данными.
Этого уже достаточно чтобы понять — никакого первичного ключа здесь нет. Более того, как только нам потребуется вносить данные в систему мы непременно столкнемся с проблемой идентификации, которую невозможно разрешить автоматически. Единственный выход — система синхронизации на основе правил и ручного анализ спорных случаев оператором. Любые попытки изобрести первичный ключ из любой комбинации полей приведут к отсечению части вполне законных use cases предметной области, как это произошло здесь

среда, января 16, 2008

Урочище

Термин "урочище" вводит большинство обывателей в ступор. Что же это на самом деле такое: "Горелое болото" — урочище, "Лысая гора" — урочище, "Проходная грива" тоже урочище, хотя там ни горы ни болота нет, зато течет ручей. Википедия тоже мало проясняет:
Урочище — в физической географии, одна из морфологических частей географического ландшафта, сопряженная система фаций, объединяемых общей направленностью физико-географических процессов и приуроченных к одной мезоформе рельефа на однородном субстрате. … Также урочищем называется участок, отличный от окружающей местности, например это может быть болото, лесной массив или нечто подобное, а также участок местности, являющийся естественной границей между чем-либо.
Как-то само собой разумеется, что "урочище" это какой-то особенный участок местности, неважно какой. Однако, это не так, например, поляна в лесу объективно отличается от окружающей местности, однако урочищем эта поляна является далеко не всегда. Суть урочища не в том, что этот участок отличается, а в том, что он именованый. Поляна в лесу станет урочищем только когда на нее начнут ссылаться люди, например, так: "Ведьмина поляна" или "Козий мох". Бессмысленно спрашивать аборигенов об "урочищах". Не знают они что такое урочище "Старый тракт", зато прекрасно осведомлены, что вот это место называется Старым трактом, а вон то — Сухим логом. Собственно, на картах урочища появились именно потому, что потребовалось наносить на карту местные топонимы, которые не укладываются в стройную систему географических наименований. Никакого иного сакрального смысла в урочищах нет. Хороший пример: урочище Перевал Дятлова. До того как дятловцы там гробанулись, никак это место не называлось. Зато потом это место стали называть назвали "перевал Дятлова" и оно просочилось на новые карты уже как урочище.