пятница, 6 ноября 2009 г.

[comp.prog.flame] Почему мне не нравятся соревнования на длину программы

В комментарии к одной из предыдущих заметок ув.тов.Ctapmex поделился ссылкой на отбор задачи для очередного сравнения Haskell vs C (да и вообще все против всех). Ну не подходит тов._adept_-у The Computer Language Benchmark Game (равно как и WideFinder, и Raytracer), ну что поделать – нужно придумать свой конкурс ;)

Я к такого рода соревнованиям отношусь скептически. Хотя и положительные стороны у них так же есть. Если не брать в расчет замеры скоростей на микробенчмарках (чем и является Benchmark Game), то самое важное достоинство таких соревнований – это демонстрация более-менее обычного кода на конкретном языке программирования. Поскольку примеры типа ping-pong на Erlang и QuickSort на Haskell, равно как и числа Фибоначчи на OCaml уже всех забабахали. А тут можно увидеть “живую” программу на языке, о котором ты раньше только слышал. Ну и впечатлиться. Или в очередной раз сказать: “ну нах”.

На этом достоинства, пожалуй, заканчиваются. А начинаются расхождения с реальной жизнью. Главное из которых – это несоответствие масштабов. Подобные соревнования обречены на микроскопический масштаб: делается все это just for fun, в свободное время, которое мало кто хочет тратить на написание большой и ненужной ему программы. Что плохо, поскольку:

  • программирование ради удовольствия сильно отличается от программирования за едуденьги. Ведь когда все делается с интересом, с удовольствием, с соревновательным азартом, возможности конкретного программиста значительно возрастают. Кроме того, программист может не замечать каких-то отрицательных моментов. Тогда как в обычной жизни очень многим приходится решать задачи, которые бы мы с радостью не решали. В таких условиях какой-то мелкий недостаток языка будет восприниматься как большая проблема и будет регулярно отнимать время и вызывать фразы, вроде “вот бл*, как меня это все заеб*ло!” (в качестве примера – в C/C++ после объявления типа структуры/класса нужно ставить точку с запятой, что я временами забываю делать). Поэтому, на мой взгляд, высоки шансы того, что разработчик с удовольствием решает соревновательные задачки на Ruby, но потом плюется от необходимости сопровождения 30K строк собственного Ruby-кода в mission critical приложении;
  • написание больших и маленьких программ очень сильно отличается по трудозатратам. И некоторые качества языка непосредственно сказываются на возможностях писать программы большого объема. Например, наличие пространств имен или модульности, наличие сборки мусора, наличие/отсутствие статической типизации и т.д. Поэтому, например, на маленьких задачках Ruby и Python по лаконичности будут рвать C++/Java/C# в клочья. Но на объемах свыше 100KLoc ситуация сильно изменится, а на объемах свыше 1MLoc станет совершенно другой;
  • программы редко пишутся в одиночку. Обычно это командный процесс. Но даже если над программой изначально работает один-два человека, то успешная программа, как правило, переживает не одну серьезную переделку разными людьми. Маленькие программки не позволят оценить удобство языка в условиях командной разработки. Так, один-два хороших C++ника способны наваять отличную, быструю и безглючную программу на C++. Но, стоит увеличить команду разработчиков в 10-20 раз, как вероятность успешного создания очень большой программы на C++ окажется сильно ниже, чем аналогичной на Java. Точно так же, пока над Lisp-евским кодом корпит один человек – это одно, но когда этот код будет передан второму разработчику на сопровождение, затем третьему, затем четвертому – насколько удобно каждому следующему программисту будет разбираться с творчеством предыдущих разработчиков?
  • в мелких соревновательных программах внешние библиотеки играют совсем незначительную роль. По определению. Ведь задача изначально ставится так, чтобы показать возможности языка – это предполагает, что все решение придется писать с нуля и полностью, с минимальным использованием внешних библиотек. Тогда как в обыденном, повседневном программировании приходится комбинировать обращения к сторонним компонентам/библиотекам;
  • не учитывается, что принцип “для каждой задачи свой язык” применим далеко не всегда. Например, есть группа C++ программистов, работающих над С++ проектом. Один из них сталкивается со вспомогательной задачкой, которую проще решить на Ruby (Python, OCaml, Haskell), а ее решение на C++ обойдется на 30-50% дороже. Имеет ли смысл брать Ruby? Зачастую нет. Поскольку кто это решение дальше будет сопровождать? Ведь это команда C++ников, отношение которых к Ruby может быть самым разнообразным. И если вы думаете, что выгодно научить кого-то языку Ruby, то задумайтесь, хотите ли вы, чтобы вас учили какому-нибудь Perl или Rebol?

В общем, если резюмировать, то подобные соревнования так же объективны, как соревнования между аккумуляторной дрелью и перфоратором. Дрелью вы сможете сделать маленькие и аккуратненькие отверстия в деревянном ящике, но не сделаете ни одной дырки в бетоне. А с перфоратором наоборот. Поэтому сравнивать языки нужно на больших задачах (например, пусть бы кто-нибудь реализовал gold не на C++, а на своем любимом языке – это было бы более адекватным сравнением).

Реализация простой задачи на разных языках имеет большой смысл в одном случае: когда вы сами хотите получить впечатление от работы на каком-то языке. Ведь почему мы пробуем новые языки? Потому, что нас в них что-то цепляет. Скажем, я когда-то давно перешел на C++ потому, что там можно было создать класс “множество” и этот класс не отличался бы от встроенного в язык типа. Этого мне в C/Pascal очень не хватало.

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

Для себя такую задачу я уже нашел. Но, думаю, у каждого она должна быть своей.

10 комментариев:

Quaker комментирует...

Поскольку примеры типа ping-pong на Erlang и QuickSort на Haskell, равно как и числа Фибоначчи на OCaml уже всех забабахали.
У меня такое ощущение, что кроме математических задач и синтаксических анализаторов функциональщикам пока больше нечем похвастаться.
Точно так же, пока над Lisp-евским кодом корпит один человек – это одно, но когда этот код будет передан второму разработчику на сопровождение, затем третьему, затем четвертому – насколько удобно каждому следующему программисту будет разбираться с творчеством предыдущих разработчиков?
В конторе должен быть корпоративный стандарт на стиль написания программ.

eao197 комментирует...

>У меня такое ощущение, что кроме математических задач и синтаксических анализаторов функциональщикам пока больше нечем похвастаться.

Да, есть такое дело.

>В конторе должен быть корпоративный стандарт на стиль написания программ.

С этим не так все просто. Попозже попробую развернуть эту мысль.

Miroslav комментирует...

мне кажется что эта затея с тестами не выгорит. 2 цитаты: "даром поют только птицы", "Рабинович напел".
С точки зрения альтернатив тут все тем более грустно тк голд является частью большого легаси со старыми проблемами. С помощью nih там нельзя ничего сделать. По дискуссии в мейл листе шансы голда 1-5%.
По поводу декодирования смс - возник вопрос где с++ решение? Впрочем риторический тк понятно что оно работает в продакшене :)

eao197 комментирует...

2Rubanets Myroslav: я привел в пример gold потому, что человек его (вроде бы) пилил с 2006-го года. И проект в 50K строк -- это уже вполне достойная задача. Если его кто-нибудь перепишет на другом языке за гораздо более короткий срок и получит такую же скорость работы (а скорость была главной задачей gold-а), то это хорошая демонстрация, имхо.

Про декодирование SMS -- варианта на C++ и не было никогда :) Несколько лет назад, когда я серьезно занимался языком D (вскоре после выхода D 1.0, но до появления сведений о D 2.0) вдруг возникла срочная потребность разобраться в одном неприятном инциденте. Для чего пришлось перелопачивать несколько десятков гигабайт логов. Поскольку задача была одноразовая, то я решил ее сделать на D. На реализацию ушло несколько часов, основное время было потрачено на поиски нужных функций в библиотеке Tango. Но сама задачка мне понравилась. Поэтому я ее повторял и на Eiffel, и на Nice. К счастью, такие штуки в продакшен не идут.

Rustam комментирует...


У меня такое ощущение, что кроме математических задач и синтаксических анализаторов функциональщикам пока больше нечем похвастаться.


http://groups.google.com/group/fa.caml/browse_thread/thread/b19555a7e09f063c#

Пример системного программирования на OCaml. Притом не поделки типа экспериментальных OS, а вполне промышленный код.

eao197 комментирует...

2Rustam: а как там скачать исходники без установки Mercurial?

Rustam комментирует...

Тут есть http://xenbits.xen.org/xapi/install.html iso'шки, сейчас сам качаю, вроде должны быть исходники.

Rustam комментирует...

Еще тут http://cufp.galois.com/2008/slides/MadhavapeddyAnil.pdf презенташка от разработчиков.

eao197 комментирует...

2Rustam: когда скачаешь, дай знать, что там есть. А то в лом 300Mb качать просто так.

Rustam комментирует...

Я первую исошку http://www.xen.org/files/XenCloud/Software/20719c/main.iso скачал, исходников там не нашел, и начал скачивать меркуриалом все подряд с верха страницы http://xenbits.xen.org/xapi/install.html там исходники есть.