среда, 14 января 2015 г.

О важности базовых примитивов

Часто в спорах о языках программирования и технологиях оппоненты приводят со своей стороны аргументы вроде:

  • "X - не гавно, ты просто не умеешь этим пользоваться."
  • "Эта фича в Y есть, просто нужно её включить/заимпортировать."
  • "Язык Z этого не умеет, но есть библиотека W, которое делает то же самое."
В процессе спора дальше выясняется, что:
  • Правильно пользоваться то научиться можно, но это довольно сложно и нужно постоянно следить за тем, как бы случайно не наступить на грабли и не отстрелить себе ногу.
  • Подключение фичи идёт через жопу, включенное работает криво и неудобно.
  • Библиотека W оказывается дерьмовой поделкой, которая даже близко не умеет того, что есть в нормальных языках.
Дабы не быть голословным, вот примеры:
  • В Java почти всё стандартное API - блокирующее. "Но у нас же есть асинхронные каналы!" - возразят некоторые упоровшиеся по Java разработчики. Во-первых, оно появилось только в Java 1.7, во-вторых лично я не видел более худшего API, чем java.nio.channels. Вообще любая работа с сетью в Java - это боль и страдание. Ни один человек в здравом уме для работы с сетью не будет использовать стандартные примитивы Java, а возьмёт нормальную библиотеку вроде Netty.
  • В Java отсутствует синтаксис для value object'ов (2015 год на носу). "Но у нас же есть Lombok/AutoValue!". Ну что ж, я рад за вас, только AutoValue всё равно требует написания десятка строк на каждый класс. Да и смотрится оно по-уродски (напишите аналог data Maybe a = Nothing | Just a и убедитесь).
  • В Java всё по-умолчанию изменяемое. Поля классов, коллекции, локальные переменные. "Ну так поставь final, подключи Functional Java". Ну final я и так везде ставлю, а вот подключать библиотеки с другой парадигмой в проект не собираюсь. Просто коллеги не поймут. Будут материться, упрутся рогом, использовать фичи не будут. А будут по старинке клепать ArrayList'ы.
Вместо Java можете подставить C+, Go, C# и любой другой императивный язык. Там всё плохо практически в такой же степени (в C++ значительно хуже).

Так в чём причина плохого качества этих языков? Почему мы имеем в Java сотни тысяч готовых библиотек (среди которых есть очень много хороших, кстати), но продолжаем клепать неработоспособный и неподдерживаемый софт?

Дело в примитивах, которые есть из коробки. Если эти примитивы спроектированы дерьмово, то всё программирование на этом языке будет таким же. И не спасут вас никакие супер-пупер библиотеки. Вы можете написать супермодную библиотеку для работы с сетью, классную либу для реактивного программирования, сделать крутой препроцессор аннотаций для убирания boilerplate-кода, но все эти библиотеки будут жить в стороне, а базовые примитивы не изменятся. Люди будут продолжать наступать на те же грабли годами и десятилетиями, просто потому что примитивы, доступные из коробки, неправильны. ArrayList есть из коробки, а ImmutableList - нету, вот и будут они пихать этот ArrayList везде, даже там где по смыслу нужен неизменяемый список, а это процентов 80 случаев. По умолчанию все поля в классах изменяемы, а чтобы сделать их неизменяемыми, нужно написать final, а это долго и лень. Вот и будут большинство программистов херачить проекты с тоннами изменяемых классов. А потом вся команда уволится, и наймут студента, который этот проект будут поддерживать. Он в свою очередь допишет ещё пару тысяч классов с null'ами и synchronized-блоками, и тоже уволится. А следующий программист будет 90% времени отлавливать баги с NPE и стараться хоть как-то повысить производительность тормозящего приложения.

Да, я ни в коем случае не утверждаю, что на Java или Python нельзя написать хорошее и качественное приложение. Но чтобы это сделать, программист должен быть очень опытным и хорошо разбираться в архитектурных недостатках своей платформы.

Да, я считаю, что чтобы писать поистине качественные и при этом сложные приложения, не обязательно быть программистом с 10-летним стажем, который собаку съел на косяках своего языка программирования. Можно просто выбрать правильный язык с правильными базовыми примитивами. Если бы в Java всё по умолчанию было final и не было null, то мы бы сейчас имели совсем другую индустрию разработки.

В общем, изучайте новые языки и новые парадигмы. Смотрите на Kotlin, Rust, Swift, Haskell, Clojure, Scala. Только помните, что переход нужно осуществлять в комплексе. Не нужно использовать на Scala ArrayList'ы и Thread'ы. В Scala свои примитивы, которые требуют других подходов.