Это не риторический вопрос. Я знаю, так исторически сложилось, но... почему мы продолжаем использовать текстовые файлы?
Вы можете сказать, что это очень простое решение: что видишь, то оно и есть. Но мы имеем дело с несколькими слоями абстракции, а все абстракции текут. Это приводит к ошибкам, запутанным диффам и проблемам с производительностью.
Давайте углубимся в искусство хранения кода в виде текстовых файлов.
Текст
Компьютеры оперируют бинарными данными, поэтому для представления текста им приходится использовать кодировки. Существует много вариантов: UTF-8 или UTF-16; с BOM или без него; CR, LF или CRLF; little-endian или big-endian — это лишь самые популярные варианты. К сожалению, мир не смог договориться об одном стандарте, поэтому то и дело приходится сталкиваться с проблемами: испорченные диффы, ошибки в тулзах, проблемы с копированием, нечитаемый текст на фронте.
Вы можете возразить, что текст дает нам свободу самовыражения: мы может записать код лесенкой или побаловаться ASCII art в комментариях. Это прекрасно, но имеет слабое отношение к программированию. Современные языки дают большую свободу для выражения сложных концепций в коде. Но если мы говорим о форматировании, для меня это выглядит странно: почему мы должны заботиться о пустых строках, табуляции или пробелах, ограничениях по длине строк и других несущественных деталях? Слава всем богам, мы не добавляем информацию о предпочитаемом шрифте и цвете в нашу кодовую базу, я точно не хочу читать код в Comic Sans.
Файловые системы
Еще один уровень абстракции между кодом и хранилищем. Зачем нам имена файлов и ограничения с ними связанные? Разве это удобно использовать двухбуквенные расширения для указания используемого языка? А ограничения на глубину вложенности каталогов или inotify watch limit? Или вот мы запускаем код в докере, а контейнер не видит изменения файлов на хосте, куда это годится?
А еще мы работаем на разных файловых системах, и они предоставляют нам разные функции. Чувствительность к регистру или нет? Жесткие и символические ссылки. Права доступа. Атрибуты. Все эти особенности не имеют отношения к нашему коду, по крайней мере, вы обычно не можете прочитать о них в спецификации вашего языка.
Я упомянул проблемы, с которыми сталкивался лично. Каждый раз мне приходилось тратить время на погружение в особенности файловых систем и поиск обходного пути. И далеко не всегда результат удовлетворял меня, чаще решение представляло собой костыль.
Парсинг
В спецификациях нашего языка задействовано много элементов форматирования: ключевые слова, скобки, разбиение строк, отступы. Возможно с ними проще читать код, но я уверен, что есть другой способ сделать код читабельным. Гораздо важнее эти элементы при парсинге кода компилятором и другими тулзами.
Обычно парсер разделяет ваш код на токены и строит Абстрактное Синтаксическое Дерево (AST). Затем он связывает идентификаторы, чтобы понять их назначение. Это очень быстрые операции, и ваш компьютер может разобрать множество файлов за секунды. Но не так много, как в вашем раздутом монорепозитории с миллионами строк кода. Поэтому иногда IDE тупит во время загрузки проекта.
Однако это еще не все, парсинг происходит много раз и после загрузки: при изменении кода, при переключении веток, при компиляции. В некоторых языках приходится парсить даже устанавливаемые зависимости (да, я про тебя, javascript). А еще у нас есть различные помощники для продуктивной работы: автодополнение, линтеры, статические анализаторы, форматтеры и AI-агенты. Все они читают наш код с диска и парсят его. Иногда используется один инструмент для всех этих задач, иногда разные. В таком случае их парсеры могут быть реализованы по-разному, что может привести к несогласованности: например, я иногда сталкивался с ситуацией, когда WebStorm сигнализирует об ошибках в импортах, но vite компилирует работающий JS без проблем.
Каким бы эффективным не был парсер, но он загружает ваш процессор и память. Сколько бы у вас не было ядер и планок памяти - они закончатся, когда вы откроете достаточно большой проект.
Диффы
Все становится намного хуже, когда вы работаете в команде. Мы используем специальное программное обеспечение для слияния изменений, но оно работает ужасно:
Когда вы перемещаете класс в другой файл — это новый класс.
Когда вы перемещаете функцию на несколько строк вверх или вниз — это новая функция.
Когда вы меняете имя любого идентификатора — у вас появляются изменения во всех файлах, которые его используют.
Когда два человека вносят изменения в один файл — возникают конфликты.
Основная проблема такого поведения заключается в том, что в наших текстовых файлах недостаточно информации о блоках кода — нет надежных идентификаторов, нет структуры. При сравнении двух файлов программное обеспечение может только распарсить оба файла и попробовать понять, какие блоки изменились, а какие нет. Но чаще сравнение происходит просто строчка за строчкой.
Итого
Итак, давайте представим, что мы разрабатываем систему для разработчиков, где они могут писать код, читать его и обмениваться изменениями. Должны ли мы использовать текстовые файлы в качестве основного источника истины? Очевидно, нет. Это неудобно, ненадежно и может привести к несогласованности.
Но что если мы распарсим код в AST, присвоим уникальные идентификаторы блокам кода, свяжем их и сохраним в графовую базу данных? Мы сможем сэкономить на размере данных если использовать enum для ключевых слов. Чтение из локальной БД будет сравнимо по скорости с чтением с диска. Форматирование AST должно быть быстрее парсинга. При слиянии веток надо будет сравнивать измененные блоки, а не файлы, что реже будет приводить к конфликтам. Статический анализ и автодополнение будут работать с блоками и связанными идентификаторами, что должно значительно уменьшить потребление памяти.
Система версионирования AST
Я работаю над PoC CVS, которая хранит AST кода TypeScript в распределенной графовой базе данных с коммитами и ветками.
Вот репозиторий: https://github.com/franzzua/ast
Текущий подход очень прост и прямолинеен. Код парсится с помощью oxc. В результате получается AST: функции, выражения, вызовы. Затем вычисляются области видимости для каждого блока: каждая функция создает область видимости, поэтому идентификаторы должны разрешаться от внутренней области к внешней.
Затем каждому узлу присваивается уникальный идентификатор и блоки связываются друг с другом, так что если есть вызов функции с именем sayHello, вместо ее имени ставится id вызываемой функции. После этого я сохраняю полученный граф в TerminusDB. Она требует схему данных, поэтому я попросил Gemini сгенерировать схему для AST oxc и подправил ее.
Сейчас эта штука может разбирать простой код в граф, сохранять его в базу данных, а затем загружать и форматировать как исходный текст. Дальше я собираюсь реализовать интерфейс для сравнения и слияния. Я представляю это как нечто вроде режима исправлений в Google Docs: некоторые части заменяются, другие перемещаются куда-то или удаляются. Надеюсь, получится сделать его интуитивным и понятным. После этого можно будет настроить автоимпорт проекта из git коммит за коммитом и посмотреть, где лучше и понятнее диффы.
Мечты о будущем
Никто не мешает расширить схему и добавить возможность привязать к блоку кода что-то вроде комментария, но с поддержкой Markdown - получится документация. А если добавить несколько полей и статусов, то можно реализовать менеджер задач. Конечно же нужно будет прикрутить CRDT для парного программирования. Небольшую доску для проектирования и чатик с войсами и стикерами. Why not?
Преимущества
Чистые диффы
Производительность и сокращение выбросов CO2
Согласованность между вашими инструментами
Комментарии (50)
kenomimi
17.06.2025 18:49А как его обратно декомипилить из разобранного и обработанного графа? Там же все метаданные убираются... Или я что-то не так понимаю?
fransua Автор
17.06.2025 18:49Сериализовать в текст? Этим постоянно все IDE занимаются, при форматировании кода, парсят в AST и рендерят в текст согласно выбранному code-style.
А какие метаданные, комментарии? Они тоже есть в ASTkamaz1
17.06.2025 18:49А если файл в данный момент синтаксически некорректен, исправлять нет времени, надо сохранить и идти по делам?
Jijiki
17.06.2025 18:49то что вы предлагаете делает визуалка на фоне(это не точно могу ошибаться), кидает внутрянку кв в таблицы по какой-то логике, но суть не меняется от этого, когда это всё вместе запускается, так кошмар начинается, как проверить и о чем я.
предположим мы на среднем ПК, откроем движок UE в визуалке!, и начнем писать в определенный момент проект самого всего двигла поттянется и начнётся веселье если это не пофиксилитут такая ситуация что эти ситуации надо минимизировать и конкретизировать операции прогонок(тоесть не чтоб оркестр запускался и на сессии ввода всё запускалось и считалось а как-то более тонко и продуманно)
мы пришли к проблеме которая не трвиальная даже на сегодняшний день, у этой проблемы 2 ситуации, цена за удобство в рантайме за оркестр, и цена за конкретную операцию и её ожидание, как найти баланс не знаю
вот на последнем абзаце и стоит проблема того как это достигается, гдето можно всё отключить, но реализация текстового редактора может не позволить всё отключить, хотя нам надо рисовать текст только по факту получается, и если углубляться в нюансы реализации текста она тоже нагрузная, поэтому всё это имеет цену в редакторах это в среднем так не везде, например какой-то блокнот может быть эффективнее визуалки, за счет того что просто рисует текст
тоесть это получается целый комплекс интерфейсов должен быть, чтобы можно было настраивать +-
Buharin
17.06.2025 18:49На хабре школьники пишут эссе на тему
"Кем я хочу стать?""Как я вижу будущее?"
VladimirFarshatov
17.06.2025 18:49Рекомендую ознакомиться с системами Графит-Флокс и Рапира+Школьница. Ещё можно погуглить Р-Технологии Глушкова. Такое ощущение, что Вы изобрели велосипед, но могу и ошибаться. )
fransua Автор
17.06.2025 18:49А с какими аспектами этих систем Вы предлагаете ознакомиться? Краем уха смотрел когда-то давно на дракона, ничего особенного не заметил.
CloudlyNosound
17.06.2025 18:49Хранить код можно в любом виде. Редактировать будете в текстовом виде, как ни крути.
В итоге, некоторые "слои абстракции" просто меняются местами. Только, вместо моментального открытия текста, придется ждать, пока по диффам соберётся требуемая версия.
fransua Автор
17.06.2025 18:49Хранить в CVS дельты или снепшоты - это перпендикулярный вопрос, я его не рассматривал.
Открытие текста в современных IDE не моментальное - он парсится в AST и потом рендерится на экран. Хотя бы для того чтобы раскрасить ключевые слова. Я предлагаю убрать первый шаг.CloudlyNosound
17.06.2025 18:49В продуманных IDE парсится фоном, а доступ к редактированию получаешь сразу.
Вам выше правильно написали. Подобные эксперименты уже были.
Если вас увлекает проект, продолжайте. Потом посмотрите на отклик сообщества.
Mishootk
17.06.2025 18:49То есть по сути разработчик вообще не заметит разницы, кроме случая, когда ему придется заглянуть в исходники не имея под рукой IDE? А не имея под рукой IDE как бы все.
Это типа что-то айфона? Вроде бы на устройстве музыки накачано, фильмов, фотографий, но вот просто так скинуть на произвольное соседнее устройство никак. И забрать тоже.
fransua Автор
17.06.2025 18:49Git тоже хранит код не в текстовом виде, если я не ошибаюсь. Но при checkout сериализует все в текст. При желании и тут можно так же. Но при редактирование текстового файла будут такие же плохие диффы, как и сейчас.
PerroSalchicha
Но... почему?
Почему именно текстовый файл, я легко отвечу: это естественный для меня формат, он хранит код именно так, как я его буду читать. И я его могу прочитать абсолютно любым инструментом, который у меня есть под рукой, вплоть до голой ОС.
В то же время преимущества каких-то других форматов для меня не очевидны. Удобство? Нет ничего удобнее нативного для меня формата. Надёжность? Текстовый файл надёжен настолько, насколько надёжен носитель, на котором он записан. Лучше этого и не придумаешь. Размер хранилища? Да, в этом плане текстовый файл ни разу не оптимален, но... на моём компьютере весь текстовый контент едва ли займёт несколько процентов от самого маленького накопителя на 256Гб. А остальное занимает отнюдь не код, а всякого рода бинарники и медиаконтент.
BobovorTheCommentBeast
Тут наоборот материшься на какого нибудь вендора IDE или тулзов, который хранит файлы не в текстовом формате (или в файлах, которые еще хранят кучу локальной\временной информации).
pnmv
мне, почему-то, вспомнились какие-то лекции, по программированию, кажется, на perl: весьма юный лектор показывает пример какого-то кода, весьма компактный, внятный и читаемый, а потом, такой - "ну, это муторошно!", после чего выдает такую простыню, которую прочтешь то не с первого раза.