Как спорить о языках программирования

топ 100 блогов tonsky22.11.2014

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

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

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

У нас же, в программировании, удовольствие сильно переоценено. Очень много заморочек на гладкий и бесшовный «экспириенс», на «красивый» и «лаконичный» код. Как будто красота определяется языком. То есть я не против, но это не может быть единственной selling point и не должно идти в ущерб важным качествам: композируемости, читаемости (даже самоочевидности), устойчивости к внесению ошибок, универсальности. Скажем, столь популярные DSL, когда одна, обычно очень конкретная задача решается очень хорошо, но чуть выйдешь за рамки и вся структура оборачивается очень закостенелой (пример: midje). В Clojure очень хорошо с DSL, но по перечисленным причинам я не привожу это как преимущество. Вообще, бойтесь вещей, которые продают только лаконичную запись и ничего больше. Обычно это достигается серьезными уступками, и как правило в целом того не стоит.

То же самое касается простоты освоения, она сильно переоценена. Глупо игнорировать что-то только потому, что оно выглядит непривычно. Что такое две недели изучения языка, если вы потом будете год делать на нем проект? Лучше день потерять… Многие вещи настолько хорошо подходят под определенные задачи, что стоят того, чтобы с ними разобраться (R, Erlang, Lua). Смешно, но непривычность — одно из сильнейших препятствий к освоению Clojure (lisp-синтаксис, ФП). Кстати, ровно так же глупо думать, что что-то понянто, если оно выглядит привычно. Любой язык или технологию нужно учить, потому что они привносят что-то новое (если не привносят, то они и не нужны). Иллюзия привычности — плохой индикатор, привычки вообще очень мешают развитию.

По этой же причине мне кажутся вредными статьи «как я поставил Go и Rust и что узнал за первые два дня» с выводами. Подобные тексты создают иллюзию понимания, хотя все описанные ощущения и факты, совершенно непонятно, как они сыграют in the long run. Удобные мелочи могут превратиться в катастрофу (например, github-зависимости в Go или сложность Scala, которая не уменьшается со временем), а страшные проблемы могут просто не встречаться в реальной жизни (или окажется, что пытаешься делать неправильно, надо дать организму привыкнуть). Разница как между первым знакомством и браком — какие-то вещи чувствуешь сразу, какие-то понимаешь через год, и скорее всего во всем, что пытался просчитать, ошибся.

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

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

Одно из важнейших достижений здесь — REPL и интерактивная разработка. В мозгу человека есть несколько пределов, они достаточно небольшие, что-то порядка 100 мс — человек замечает задержку, 1 секунда — теряет внимание, 10 секунд — переключается на другую задачу (цифры примерные, по памяти). Чтобы не разрывать состояние потока, паузы в цикле обратной связи не должны превышать пары секунд. На границе этих порогов происходит качественный скачок. Скажем, разница в скорости между Java-разработкой (перекомпиляция) и Clojure-разработкой (вычисление прямо в редакторе inline) может составлять больше порядка. Не потому что суммарное время компиляции java-проекта большое (не такое большое), а потому что программист успевает отвлечься. Как живут C++ программисты, у которых проект собирается часами, я не знаю.

Наличие готовых библиотек, по идее, тоже качественно ускоряет работу программиста. Open source иногда называют той самой серебрянной пулей, которая есть. Я лишь хочу дополнить, в контексте оценки годности языков, что огромным плюсом является возможность самому построить нужные библиотеки за короткий срок, за несколько дней. Современные языки, кроме низкоуровневых, обычно неплохо с этим справляются. То есть гнаться можно не только за платформами с кучей кем-то написанного удобрения (nodejs, ruby), но и за языками, где написание нужных вещей — умеренно-тривиальная задача. Я вообще гораздо больше ценю идеи, чем их реализации. У некоторых важных вещей нет реализации — wsgi, REST, CRDT.

Часто переживают насчет наличия IDE к языку, мол, радикально улучшает производительность. Я бы сказал, зависит от того, какие фичи имеются в виду. За пределами IDE тоже можно жить, и отказ от удобств может положительно влиять на код. Вопрос сложный и даже контринтуитивный, завязан на устройство мозга; иногда, чтобы добиться от него максимальных результатов, полезно его немножко обманывать. Если коротко, то отсутствие IDE наказывает тяжестью за сложный код, а мозг интуитивно ищет более легких путей. Наверное, с очень большой кодебазой работать в IDE эффективнее. Но и писать большие программы — не единственный способ программировать. Мне кажется, что REPL гораздо важнее любых рефакторингов и анализов.

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

В этом смысле, в глобальном, основной критерий оценки, даже оправдания существования того или иного языка, платформы — это создание новых классов систем. Лучшее, что может оправдать почти все остальные недостатки языка, это возможность создавать вещи, которые до этого были принципиально невозможны или близки к невозможным. Примеры: go — сетевые сервисы, transit — быстрая коммуникация browser/server, erlang — неубиваемые сервисы. А вот загвоздка CoffeeScript, например, в том, что он не дает никаких новых качеств. Кстати, в этом разрезе у C# и у Objective-C как языков вполне есть смысл :)

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

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

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

Перейдем теперь к вещам, чуть менее часто обсуждаемым в спорах за языки.

Устойчивость к росту и дисциплина. Системы, которые мы строим, всегда меняются. Это больше похоже на управление муравейником, чем на возведение здания. Неправильно рассматривать исходники как что-то застывшее, это скорее динамическая система (даже если не брать в расчет эксплуатацию, только код). Неправильно также выносить за рамки ее авторов — программисты тоже важная часть уравнения. Кто они, какие они, сколько их. Как часто они меняются.

В этих смыслах одни языки могут подходить лучше, чем другие. Статическая типизация лучше ведет себя с ростом количества кода, избыточные языки лучше масштабируются на большие команды. На Clojure можно строить сложные системы очень быстро, но трудно масштабировать ее за пределы 8–10 человек.

Языки с большим количеством ограничений (например, Erlang) привносят больше дисциплины, помогают держать код в тонусе, он меньше «плывет». Мысленный эксперимент: представьте, что вы взяли некое ядро и отдали двадцати людям работать над ним в течение года. Что получится на выходе, если оно было написано на языке X? А если Y? К примеру, Ruby On Rails решает проблему разбродов и шатаний просто фактом наличия конвенций и соглашений.

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

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

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

Это транскрипт моего доклада на fby.by, который я делал по новой модели: сначала пост, потом доклад. Вроде удобно

Слайды :P

Оставить комментарий

Архив записей в блогах:
Сегодня ночью вслед за перебоями со светом у нас упал интернет нашего провайдера Ай Флэт. В чатах их костерят, это уже не первый случай, а я перешел на LTE, жалея о том, что у нас нет Старлинка, хотя Маск наш во всех отношениях. А в Подольске начались аресты саботажников, диверсантов и ...
Что будет, если в бочку мёда добавить ложку дегтя? Правильно, мёд станет несъедобен. Нечто подобное произошло и с глубоко научным исследованием капитала и капитализма К.Марксом. И произошло это в результате добавления им в свое учение ...
Кусочек лета Кипит в моей кастрюльке... Аромат компота. (вечернее зимнее хокку) Воспоминания о прошлом лете согревают душу! Варю компот: крошу яблоки, бананы, груши... А за окном метель, мороз - Москва в сугробах нежится - ей тоже лето грезится! Летний компот и гречневые ...
"В Екатеринбурге поезд насмерть сбил подростка, который шёл по путям в наушниках" Электричка ему дудела, но чувак наслаждался музоном. Я всегда говорил-наушники, сука, опасны. Ранее ночью грузовой состав почти там же протаранил Финик. Нормальные девки не ждут какого-то там паровоза, ...
Опять рукожопая подделка, рубеж XIX-XX веков, в "стиле" XVI века. Это пиздец конечно. Длина 515 мм. Ну и сравните это убожество с реальными историческими образцами Фотографические карточки CZERNY'S INTERNATIONAL AUCTION HOUSE S.r.l. и Wallace ...