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

[prog.flame] Пару слов об let-it-crash

Данная заметка является развернутым комментарием к одному моменту в споре об исключениях, завязавшемся в обсуждении моей предыдущей заметки о языках D и Go.

Вкратце напомню, в чем дело. Ув.тов.Left и Gaperton высказывались в том ключе, что раз в Go нет исключений, то и ничего плохого в этом нет. Что можно выделять действия, которые могут завершаться ошибкой (например, делением на ноль или попыткой вычислить квадратный корень из отрицательного числа), в отдельные goroutine. Тогда при возникновении проблемы прибивается только эта goroutine, а запустивший ее код сможет понять, что произошел сбой и что-либо предпримет.

В защиту этой точки зрения приводился подход к разработке ПО на языке Erlang. Там операции распределяются по легковесным Erlang-овским процессам, а сами процессы выстраиваются в деревья, где процесс-родитель информируется о сбоях в дочерних процессах и может либо перезапустить дочерний процесс, либо завершиться самому, либо сделать что-нибудь еще (коротко прочитать об этом можно здесь). При этом сами процессы в Erlang принято разрабатывать в соответствии с принципом let-it-crash. Тут я лучше процитирую ув.тов.Gaperton:

Там рулит подход let-it-crash, при котором ты вообще не пишешь обработки ошибок, и закладываешься только на успешный случай. А когда оно упадет - как бы ни упало - обрабатывается падение процесса, и все.

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

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

Но в ряде случаев этот подход почему-то не нравится пользователям софта. А когда пользователям не нравится и они настоятельно просят сделать что-то, что мне, как программисту не нравится и кажется странным и абсолютно не нужным, то приходится наступать на горло своей песни. Т.е. забивать на let-it-crash, чтобы воплотить в жизнь принцип let-it-live :/

Ну, например. Есть программулина, которая время от времени лезет в БД за каким-то значением. Поскольку программулина работает долго, а БД лежит на другом сервере, то неизбежно возникают ситуации, когда связь с БД рвется. И обнаруживается это как раз при очередном обращении к БД.

Казалось бы, все просто – мы в БД с select-ом, а нам вместо ответа exception. Ну мы, как приверженцы let-it-crash, описание проблемы в log, а сами зовем abort. После чего нас рестартуют, мы заново подключаемся к БД, выполняем select и продолжаем работать как будто этого сбоя и не было.

Но вот пользователям эта простота не нравится. А у нас, говорят, в логах слишком много таких ошибок появляется, временами. С ними разбираться приходиться. А у нас, говорят, системы мониторинга начинаю кричать, когда какой-то процесс аварийно завершается. А еще у нас, признаются, временами супервизоры “подвисают” и забывают упавшие процессы поднимать на автомате. Поэтому не могли бы вы, программисты вы наши всесильные, сделать так, чтобы при возникновении ошибки “нет связи с сервером БД” при select-е вы не звали abort, а просто пытались заново к БД подключиться? Раза эдак два, три. А еще лучше, чтобы параметры восстановления подключения мы бы сами в конфиге прописывали. И только если все попытки обломились, либо же если на эти попытки было затрачено слишком много времени, то тогда уже abort. Ну очень надо!

Так что let-it-crash – это очень хорошо для программиста, гораздо лучше, чем let-it-live. Только не всегда допустимо. А там где недопустимо, нужны какие-то средства, которые не позволят прозевать неожиданную проблему (вроде забытой проверки кода возврата функции). И которые позволяют проблему вовремя диагностировать и исправить. Исключения, например.

PS. Для C++ных программ, работающих в режиме 24x7, подход let-it-crash, наверное, еще более важен, чем для Erlang-а. Поскольку уронить C++ную программу очень просто. Иногда для этого достаточно просто на новую версию Visual C++ перейти :)

четверг, 14 октября 2010 г.

[prog.flame] Почему я не использую языки D и Go

В комментарии к одной из предыдущих заметок ув.тов.Quaker задал мне непростой вопрос:

Евгений, хотелось бы Вас спросить: а у Вас какое мнение относительно D vs Go? Есть у кого-то из них реальный шанс?

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

Итак, почему же я не использую языки D и Go? Да все очень просто: они еще сырые. Ни один из них не был официально объявлен стабильным.

И если по поводу Go здесь все более-менее ясно, то с языком D ситуация сложнее. У языка D есть две ветки: D1, который официально вышел где-то в 2007-м, и D2, который не совместим с D1, который описан в книге Александреску “The D Programming Language”, но который еще не дошел до официального релиза.

Вроде бы D1 уже давно стабилен, последние изменения самого языка D1 (вроде бы это были текстовые mixin-ы), если мне не отшибает склероз, относились к весне 2007. С тех пор выходят только bugfix-релизы D1.

На тот момент язык D1 был очень даже ничего. Гораздо лучше C++03 и, наверное, даже получше C++0x. Но, библиотеками и инструментами он не был снабжен никак. Стандартная библиотека Phobos там была ущербная, более качественная и удобная Tango находилась в каком-то промежуточном состоянии – новые релизы тогда выходили более-менее регулярно, но не были достаточно стабильными. Других библиотек или D-шных оберток вокруг C-шных или C++ных библиотек было крайне мало (да и сейчас не густо). В общем, начать какой-нибудь proof-of-concept проектик можно было (что я и пытался сделать с помощью студента-практиканта), но было понятно, что до production-применений нужно ждать еще года 1.5-2 (в лучшем случае).

И вот тут Брайт с Александреску прошлись серпом по моим светлым мечтам :( Было заявлено о начале разработки D2 с принципиально другими подходами к обеспечению константности и иммутабельности данных. Поскольку константность и иммутабельность я люблю (наличие константности в C++ сильно компенсирует мне другие недостатки этого языка), то стало понятно, что какой бы код на D1 я не написал сейчас, после выхода D2 меня ждет big rewriting. Что сразу же поставило крест на желании делать что-либо серьезное на D1. А D2 так до сих пор и не вышел.

Теперь можно перейти к рассуждениям о том, при каких условиях я бы решился на применение D и/или Go.

При пропихивании нового продукта в массы различают следующие категории потенциальных покупателей: Innovators (которые любят все новое и любят рисковать), Early Adopters (которые менее рискованные, чем Innovator-ы, но готовы пойти на риск, если видят, что новая технология может дать им преимущество), Early Majority (которые готовы к изменениям, но только если видят, что эти изменения уже себя зарекомендовали), Late Majority (которые пойдут на изменения, если увидят, что большинство вокруг уже сделало этот шаг и не жалеет об этом), Laggards (это самая консервативная часть, которая решается на перемены только когда необходимость перемен становится очевидна всем).

Так вот, сейчас языками D и Go, на мой взгляд, интересуются только Innovator-ы и, может быть, Early Adopter-ы. Себя же я причисляю к Early Majority. Поэтому внимательно на D и Go я буду смотреть только после того, как Early Adopter-ы докажут всему миру, что данные языки вышли из состояния детских игрушек. А для этого нужно, как минимум:

  • наличие стабильных реализаций на большом количестве платформ. Может быть даже разных реализаций от разных производителей;
  • наличие инструментария (как минимум: отладчики, профайлеры) для большого количества платформ;
  • наличие достаточного количества бесплатных и легкодоступных библиотек общего назначения (самых разных: работа с командной строкой, обертки вокруг zlib, поддержка UUID, генераторов случайных чисел, средств работы с файловой системой, с сетью, биндинги к графическим библиотекам или собственные графические библиотеки, криптография, XML и пр.). А так же явно выраженная тенденция к их увеличению;
  • наличие заметных и знаковых success stories, причем, в разных областях.

Это необходимые, но не достаточные условия. Сюда же еще нужно добавить удобство самого языка. А здесь я могу сказать, что у D больше шансов войти в мой арсенал, чем у Go. Объясню почему.

Язык D рассматривается как улучшенный C++. И, наверное, таковым является. Тогда как я слышал мнение, что Go – это улучшенный C. И с этим мнением я согласен.

Но вот мне нужен именно язык класса C++, а не C. Ну не любитель я чистого процедурного подхода, не нравятся мне C и Pascal. Наверняка многие более комфортно программируют сложные системы на C, чем на C++, но у меня все наоборот. Поэтому, когда я посмотрел на Go, то не понял, как он сможет заменить мне C++ с классами, шаблонами и исключениями. Я понимаю, как заменой может стать D. А вот для Go у меня такого понимания нет.

Поэтому на данный момент язык Go меня не интересует.

Язык D интересует чуть больше, но это, скорее, просто чисто исторический интерес. Я считаю, что язык D переусложнен, что есть в нем вещи, которые будут мешать на нем нормально программировать. В частности, когда я пытался его использовать, меня раздражало наличие value и reference типов, но при этом наличие указателей. В D2 появилась транзитивная константность (и только она), что так же не есть хорошо с моей точки зрения. В общем, как язык D немногим лучше C++ – мегагуру будут на нем писать нормально, а простые смертные плодить баги, как и на C++.

Поэтому и к будущему D я отношусь скептически.

А вот будет ли у этих языков будущее – это интересный вопрос. Я думаю так: у Go оно выглядит более радужным, чем у D. Ведь D все эти годы развивался с какой-то непонятной целью. Т.е. авторы хотели создать хороший практический язык, но где та практика, на которой обкатывались их решения? Тогда как у Go, насколько я могу судить, ситуация совсем другая – язык развивается по мере реализации реальных систем внутри Google. И если Google-овцы объявят, что Gо официально считается стабильным, да еще расскажут и покажут, что на нем было сделано, то это будет очень весомая заявка. Хотя бы на то, чтобы стать нишевым языком (вроде Erlang). А вот будет ли Go успешным в других прикладных областях – тут я даже судить сейчас не возьмусь.

среда, 13 октября 2010 г.

[prog.flame] В LinkedIn Signal используются Scala и JRuby

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

11 октября на InfoQ.com опубликовали небольшой рассказ об архитектуре LinkedIn Signal и ответы ключевых разработчиков этого сервиса на вопросы InfoQ. Может быть, кому-то будет это интересно. Мне же понравились примеры кода на Scalatra – вэб-фреймворке для Scala (оказывается, не Lift-ом единым…). Не часто увидишь к месту использованную родную поддержку XML-я в языке Scala:

package org.scalatra

class ScalatraExample extends ScalatraServlet {

  // send a text/html content type back each time
  before {
    contentType = "text/html"
  }

  // parse matching requests, saving things prefixed with ':' as params
  get("/date/:year/:month/:day") {
    <ul>
      <li>Year: {params("year")}</li>
      <li>Month: {params("month")}</li>
      <li>Day: {params("day")}</li>
    </ul>
  }

Но больше всего меня вставила вот эта фраза от одного из разработчиков (это Chris Conrad рассказывал о своих впечатлениях от Scala):

Regarding pitfalls, I think that the most common has to do with the mixed object oriented/functional nature of Scala.  Programmers will need to spend the time and learn when to model the program using objects and when to model their program using functions and how to mix the two together.  Personally, while writing Norbert, I had to go back and revisit some pieces of code multiple times as I became more comfortable with using Scala.

Что в моем вольном переводе (с помощью ув.тов.alexey-rom) звучит как:

Если касаться проблем, то я думаю, чаще всего они связаны со смешанной объектно-ориентированной/функциональной природой Scala. Программистам приходится приходится тратить время на то, чтобы учиться определять, когда программы нужно строить посредством объектов, а когда посредством функций, и как все это смешивать друг с другом. Лично я, когда писал Norbert, был вынужден возвращаться назад и переделывать куски кода по несколько раз по мере того, как я все больше привыкал к Scala.

По началу для меня, как для замшелого C++ника, такое высказывание было диким. С++никам же постоянно приходится выбирать – ООП ли использовать, обычное процедурное программирование, обобщенное программирование или еще что-то. Что в этом сложного? ;)

А потом вспомнилось, что на Scala переходят Java-исты, которые измучены нарзаном были воспитаны дятлами чистым и ущербным Java ООП. У них же кроме классов и интерфейсов ничего не было. И, более того, многим именно это и нравилось. А тут на тебе! И функции, и объекты, и трайты, и паттерн-матчинг… Конечно, так сразу все это счастье не переживешь :)

вторник, 12 октября 2010 г.

[life.sport.darts] Прошел третий турнир в офисе

В прошлую пятницу прошел очередной турнир для новичков в нашем офисе. Под катом небольшой рассказ об этом с фотографиями-иллюстрациями (огромная благодарность за которые Дмитрию Косточко).

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

[prog] Описание нововведений Scala 2.8: Named and Default Parameters и Type Constructor Polymorphism

Продолжается серия статей о нововведениях в Scala 2.8. На сей раз две статьи, которые опубликованы вне scala-lang.org:

Ранее были опубликованы:

Пару слов от себя. Сегодня пытался прочитать про Type Constructor Polymorphism. Сумел воспринять только какие-то отрывки из обрывков. Главным образом потому, что статья представляет из себя набор общих фраз и абстрактных примеров. Тогда как язык программирования (тем более претендующий на мейнстримность) предназначен для решения конкретных проблем. Посему пользователям языка нововведения нужно объяснять в буквальном смысле на пальцах. Вроде такого: вот у нас контейнер с апельсинами, а вот с яблоками. Мы хотим сделать сортировку по привлекательности внешнего вида, но беда в том, что типы разные, хоть и производные от какой-то базы… И бла-бла-бла с большим количеством примеров нормального, читабельного кода. До тех пор, пока этого не будет, Scala останется привлекательной для небольшого количества гиков, способных придти в восторг от конструкции:

scala> def foo[CC[x], El](xs: CC[El]): CC[El] = null.asInstanceOf[CC[El]]
foo: [CC[x],El](xs: CC[El])CC[El]

scala> foo(List(1,2,3))
res0: List[Int] = null

[life.sport.darts] Джеймс Уэйд таки уделал Адриана Льюиса в финале World Grand Prix!

Только что закончился финал World Grand Prix, в котором Джеймс Уэйд победил Адриана Льюиса со счетом 6:3. Болел я как раз за Уэйда, хотя как игрок он мне особо не нравится. Но на моих сегодняшних предпочтениях сказались результаты вчерашних полуфиналов.

Вчера молодые игроки – Уэйд и Льюис – забороли монстров Барневельда и Тейлора. И если игра Уэйда с Барневельдом особо не впечатлила, поскольку было видно, что Барневельд находится не в своей тарелке – видимо, недавние проблемы со спиной сказались, то матч Льюис против Тейлора был интересным и, в чем-то, выдающимся.

Примечательно, что в полуфиналах и Барневельду, и Тейлору удалось выдать по максимальному checkout-у – по 170 очков. Причем в случае с Тейлором это был вообще очень примечательный checkout. В том леге Льюис шел на завершение в 9 дротиков. В последнем подходе Льюису нужно было списать 161 (T20-T17-Bull), тогда как у Тейлора оставалось 170. Льюис споткнулся на T17 (т.е. на восьмом дротике) и смог оставить себе 24. Казалось, что Льюису можно беспокоиться только о том, что он не сделал nine darts finish, а лег у него в кармане по-любому. Но Тейлор – это Тейлор. Взял да и выбил 170.

Похоже, Фил Тейлор провоцирует своих соперников на “максимумы” (когда тремя дротиками выбивают 180 очков). Гари Андерсон в четвертьфинале против Тейлора сделал 10 максимумов. А Льюис вчера, в полуфинале, смог выбить 16 (шестнадцать!) максимумов!

Но я придерживаюсь мнения, что не только и не столько максимумы помогли выиграть Льюиса. А еще и зрители, которые в последних 2-3 сетах стали очень активно болеть против Тейлора. А Льюис это провоцировал. Стоило ему выбить максимум, сделать успешный double-in или взять лег, как он поворачивался к зрителям и начинал размахивать руками – мол, давайте, поддерживайте, кричите. И зрители кричали. Как только Тейлор выходил бросать, как аудитория начинала дружно скандировать “Lewis! Lewis! Lewis”. По-моему, в последнем сете именно это Тейлора и доканало. Но нужно отдать должное Тейлору, он не позволял себе апеллировать к зрительному залу.

Поэтому-то я болел не столько за Уэйда, сколько против Льюиса. Сегодня он пытался продолжать в том же духе – поворачивался к зрителям и делал призывные взмахи руками. Но сейчас это не сильно помогло. И максимумов Льюису удалось сделать всего восемь (хотя у Уэйда лишь три), и болельщиков Уэйда сегодня в зале было побольше. Поэтому скандирование “Lewis! Lewis! Lewis” хоть и начиналось иногда, но очень быстро затухало. Так что Уэйд сегодня был в более комфортной обстановке, чем Тейлор вчера. Наверняка это и сыграло свою роль.

В любом случае, матч получился интересным. Хотя до четвертьфинала Тейлор vs Андерсон, да и до полуфинала Тейлор vs Льюис, ему было далеко.

воскресенье, 10 октября 2010 г.

[life.photo] Горы на фотографиях Павла Белошицкого

Сегодня в рубрике “Знакомство с фотомастером” горные снимки Павла Белошицкого. На мой взгляд, они не такие красочные и мастерски сделанные, как, скажем, снимки Дмитрия Шатрова. Но зато они полны какого-то своего очарования. Видно, что делал эти фотографии влюбленный в горы человек.