D:\sideБлогТекст или не текст

⚠️ Обращайте внимание на даты.
Этот блог больше не ведётся с 17 января 2023, и на тот момент с написания этой страницы (24.09.2015) прошло 7 лет.

Я хочу поговорить о нескольких больных темах. Во-первых, о Clojure, в котором я так толком и не продвинулся, но которым я по-прежнему восхищён, даже несмотря на полное отсутствие вакансий на него. Во-вторых, о редакторах и IDE, потому что существенной разницы между ними так и не появилось, а самое важное остаётся уделом хипстеров из мира программирования. В-третьих, я затрону такие вещи, как GameMaker и Scratch, идеи которых по сей день презираются, развиваются мелкими шажками и с большой осторожностью.

Все эти три пункта довольно грустные. Если утрировать, то это:

Эти три вещи кое-что объединяет.

Язык, которым никто не пользуется

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

Кложуристы при этом почти всегда умалчивают о такой мощной вещи, как Paredit: это изначально плагин для emacs, который даёт возможность поддерживать баланс (открыть-закрыть) скобочек механически. Подобная штука встречается сейчас во многих редакторах, даже в Atom, в котором я сейчас это пишу: я открываю скобку, редактор за курсором ставит закрывающую, и всё, что я напишу далее, оказывается внутри них, я открываю скобку с выделенным словом и это слово оказывается в скобках. И… это удобно.

Paredit, конечно, не так прост. Он не только “дозакрывает” скобки, но и предоставляет средства по перемещению по окрестностям, выделению и раскрытию целых S-выражений (любое правильное скобочное выражение). Выражения можно менять местами, быстро выделять и раскрывать наружу.

Существует Paredit давно. Разработан он, предположительно, для Common Lisp, но больше всего применялся, похоже, для Emacs Lisp – диалекте Lisp, используемом в редакторе Emacs для расширений. У него было достаточно времени “созреть”. В Clojure синтаксис чуть сложнее, но идея в целом та же, и практически никто сейчас всерьёз не работает с Clojure без Paredit. Он просто вызывает страшное привыкание.

Спор, в котором нет смысла

А что долго говорить о бессмысленном? Среда разработки сильнее заточена под конкретную технологию, имеет больше инструментов для неё. В чём это выливается? В лучшем умении анализировать язык этой технологии. И… постойте-ка, всё. То есть, добавив/разработав в редактор достаточно вспомогательных инструментов, о границе IDE/редакторы можно забыть.

Это не новость и не размышления, это скорее напоминание.

Из чего сейчас состоят наши инструменты разработки? В основном это редактор для ввода кода. Иногда ещё и интерактивная консолька для ввода кода, чаще ради запуска программ. Иногда бывает такая роскошь, как визуальный редактор интерфейсов.

Дело, которым никто не занимается

“А теперь я расскажу вам свою биографию”. Точнее, ту её часть, что относится к теме.

Я некогда нашёл Game Maker 6. Он меня, конечно, удивил – оказалось, игра это всего лишь кучка объектов, в которых при определённых событиях что-то происходит!.. Но уже до этого я по школьному учебнику копался в среде “ЛогоМиры”, где программы писались из несложных текстовых инструкций и выполнялись либо единоразово (по щелчку на объект), либо каждый шаг среды. В этом смысле GM привёл в некоторое замешательство “что, всё так просто?” Разумеется, вкапываясь глубже и перейдя на GM7 (просто чтобы вы понимали, сколько времени прошло), я начал встречать определённые проблемы и ограничения, которые возникают без использования встроенного скриптового языка GML, и… жизнь отвлекла меня на переход в другую школу и изучение языка С. Потом я снова вернулся к GML и понял, что язык мне понятен и нужно только понять, как работает то, чем мы с помощью этого языка управляем.

В самом Game Maker, если не трогать GML, система написания алгоритмов очень несложная, но документация по ней была не очень понятной без предварительного опыта написания кода. На тот момент у меня его не было настолько, что читая раздел “GML Reference” и справку на русском языке я около года пытался вникнуть в то, что означает “возвращает значение” почти под каждым пунктом. Но мы отвлеклись. При составлении алгоритмов из “кнопочек” в GM важных принципов надо знать всего три:

Оглядываясь назад, я понимаю, что это “инструкции” (statement), “конструкции” (clause) и “составные инструкции” (compound statement). Т. е. это просто инструкции (присваивания, вызовы), это команды циклов/ветвления и аналогичные (for/while/repeat/if/with), а также фигурные скобки ({}). Упущена важная часть – выражения. Их мы вынуждены вводить прямым текстом.

Экспрессия? Выражение? Эм, что?

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

Интересно то, что я в последнее время работаю в основном с языками, где выражениями является практически всё. Первые подобные приёмы я видел в С – там, например, присваивание возращает присвоенное значение, что позволяет его (а) использовать в местах вроде условий у while, где инструкции писать нельзя и (б) позволяет присваивать по цепочке, а-ля a = b = 5. В GML, впрочем, даже этого нет – присваивание является инструкцией и в выражении фигурировать не может (a = b = 5 в GML больше похоже на a = (b == 5)). Но если погружаться глубже – в Ruby определения классов и методов, циклы и условные операторы (даже так!) возвращают какие-то значения. Похожее происходит в CoffeeScript (но не в JavaScript, который в этом отношении ближе к С) и даже в Clojure (скорее особенно в Clojure, там выражениями после разворачивания макросов является вообще всё).

Так что GM – не лучший пример среды, делающей программирование проще, хотя в нём есть интересные моменты. Чуть дальше зашёл Scratch, по следам которого спешил Stencyl. Чуть более похожий на IDE – TouchDevelop, но он всё ещё является скорее экспериментом и обучающей игрушкой, нежели рабочим инструментом.

Работа с текстом… или нет

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

К примеру, форматирование. Код можно писать по-разному, в том числе и вовсе в одну строку (в большинстве языков…). Чтобы люди писали код понятно, принимаются разные меры. Считается хорошей практикой завести “свод правил” для стиля кода, т. н. “styleguide”. Это решает сразу две задачи: учит писать понятнее (тех, кто ещё этому не обучался) и делает код проекта более однородным. Но у этого есть и проблемы.

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

Думаю, достаточно… для начала? По большинству правил из списка есть какое-то общепринятое мнение. Но не всегда. В некоторых случаях аргументы есть в обе стороны. В лучшем случае стороны договорятся и где-то зафиксируют свою договорённость. В худшем – “война правок” и коммиты из “синтаксиса покрасивее”.

Видите проблему? Человек может смириться с чужой нормой, но ему всё равно будет не очень удобно. Как можно решить эту проблему? Можно формально определить оба стиля (проектный и личный), при редактировании автоформатировать в личный, при сохранении форматировать в проектный. Костыль? Ещё какой.

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

Может, стоит задуматься о том, чтобы перестать редактировать код как текст и начать редактировать синтаксическое дерево, в которое он всё равно будет преобразован?