JSON, YAML, TOML, HCL - за последние годы человечество успело изобрести десяток языков для конфигурации.
Каждый обещал быть "простым", "удобным" и "читаемым человеком".
Но по факту - все они страдают от одних и тех же проблем: шумный синтаксис, хрупкие отступы, бесконечные кавычки и отсутствие элементарных возможностей вроде модульности и слияния конфигов.
Пора перестать с этим мириться и сделать конфигурации наконец человеческими.
? Перестаньте
утомлять глаза, пытаясь разобраться в тонне бесполезных кавычек
утомлять глаза, пытаясь распознать в каком месте есть проблема с отступом
писать велосипед, когда в очередной раз нужно мержить конфиги для разных окружений
писать велосипед, когда нужно парсить env переменные в структуру конфига
забивать мозг, пытаясь разобраться в огромной конфигурации из-за отсутствия модульности
⁉️ Как перестать?
Использовать адекватный язык для конфигурации ATMC
ATMC - минималистичный, но мощный язык конфигурации, созданный для удобного описания системных настроек.
Он сочетает простоту синтаксиса, поддержку импортов, переопределений, гибкого слияния конфигов и переменные окружения.
? Почему ATMC?
-
топовый синтаксис
супер минималистичный
интуитивно понятный и простой
не перегружен конструкциями
не зависит от отступов, переносов, кавычек, запятых и прочей чепухи
очень простой и в то же время достаточно мощный
-
модульность
можно импортировать разные кусочки (модули) конфига
очень минималистичный синтаксис импорта
можно обращаться к вложенным полям импортированного конфига
-
слияние конфигов (киллер фича)
супер легко мерджить несколько конфигов (например, common + stg или prod)
есть возможность переопределять поля
умное слияние - рекурсивное - не перетирает поле полностью
-
встраивание
можно встраивать объекты и массивы с помощью spread (...) оператора
с помощью него же и происходит слияние
-
доступ к env переменным
$YOUR_ENV_VARIABLE
-
поддержка всех необходимых типов
int
float
string
bool
object
array
компиляция в структуру и мапу из коробки
поддержка комментариев
-
расширяемость:
можно получить итоговый AST со всеми резовленными значениями
можно сделать на этой основе компилятор во что угодно
в перспективе можно поддержать LSP
? Примеры использования
Простой пример
?File: config.atmc
{
logging: {
level: ["warn", "error"]
}
database: {
clickhouse: {
username: "username"
password: "password"
port: 9000
}
}
}
Пример с импортом
?File: config.atmc
db ./database.atmc // Супер минималистичный импорт
{
logging: {
level: ["warn", "error"]
}
database: db // Тут появится объект из импортированного файла
}
?File: database.atmc
{
clickhouse: {
username: "username"
password: "password"
port: 9000
}
}
Пример с spread + env
?File: config.atmc
db ./database.atmc
{
logging: {
level: ["warn", "error"]
}
database: {
postgres: {
username: $POSTGRES_USERNAME // Будет подставленно значение из env
password: $POSTGRES_PASSWORD
}
db... // Сюда встроится импортированный конфиг
}
}
?File: database.atmc
{
clickhouse: {
username: "username"
password: "password"
port: 9000
}
}
Пример с доступом к вложенному полю
?File: config.atmc
db ./database.atmc
{
logging: {
level: ["warn", "error"]
}
database: {
postgres: {
username: $POSTGRES_USERNAME // Будет подставленно значение из env
password: $POSTGRES_PASSWORD
}
clickhouse: db.clickhouse // Сюда будет встроен вложенный в db объект
}
}
?File: database.atmc
{
clickhouse: {
username: "username"
password: "password"
port: 9000
}
}
Пример со слиянием
?File: common.atmc
{
logging: {
level: ["error"]
}
database: {
postgres: {
username: $POSTGRES_USERNAME
password: $POSTGRES_PASSWORD
host: "localhost"
port: 5432
}
}
}
?File: prod.atmc - конфиг для prod окружения
common ./common.atmc
{
common... // Встраивается общий конфиг
// Далее добавляются новые параметры и переопределяются параметры из общего конфига
logging: {
level: ["warn", "error"] // Переопределяется
enable_tracing: true // Добавляется новое поле
}
database: {
postgres: {
port: 6432 // Переопределяется только порт, остальные поля не будут затронуты
}
}
}
?File: stage.atmc - конфиг для stage окружения
common ./common.atmc
{
common... // Встраивается общий конфиг
// Далее добавляются новые параметры и переопределяются параметры из общего конфига
logging: {
// Переопредел��ется - можно без запятых
level: [
"info"
"warn"
"error"
]
}
}
⚙️ Что под капотом?
Язык конфигурации работает благодаря множеству компонентов:
-
lexer
преобразует код в токены
-
parser
преобразует токены в AST
-
analyzer
проверяет семантику в рамках одного AST
проверяет наличие неиспользованных переменных
проверяет использование неопределенных переменных
-
linker
резолвит значения переменных из всех связанных AST
резолвит значения переменных среды
выдает один итоговый AST
-
processor
получает на вход путь до файла с конфигом
запускает все необходимые компоненты для обработки всех связанных файлов
отдает полученный итоговый AST после линковки
-
compiler
компилирует итоговый AST
компиляторы могут быть разными (в map, в struct и т.д.)
? Поддержка и интеграция
Язык написан пока только на Go, соответственно работает только для этого языка программирования.
В дальнейшем планируется поддержка других платформ
? В планах
-
компиляция в самого себя
будет удобно смотреть итоговый конфиг
можно будет выводить итоговый конфиг, как это делает, например,
nginx -T
-
кодогенерация структур на базе конфига
тогда описывать конфиг придется только в одном месте - в atmc файле
-
автоматическая загрузка env переменных из .env файла
сейчас такого нет - нужно будет самим загружать, чтобы они стали доступны в os.Getenv
но будет удобно, если добавить
подсветка синтаксиса
-
имплементация LSP
умная подсветка синтаксиса
подсказки
поиск определений и помощь в импортах
P.S. Знаю, что уже есть похожие языки, но у всех есть свои недостатки. Где-то приятный синтаксис, но нет модульности; где-то есть модульность, но нет слияния; а где-то есть всё, но язык излишне усложнён. В ATMC есть всё нужное - и ничего лишнего.
Моя цель - сделать конфигурации такими же простыми, как Go-код: предсказуемыми, читаемыми и расширяемыми.
? Репозиторий и примеры: https://github.com/atmxlab/atmc
Комментарии (8)

pilot114
10.11.2025 14:30Модульность и слияние нужно реализовать не как фичу самих конфигов, а в том месте где они подключаются, после декодирования - и при этом вообще не зависеть от формата - вот куда усилия приложить надо, а не в изобретение json диалекта

kez
10.11.2025 14:30Основная проблема всех "статичных" языков не в синтаксисе (хотя насчёт ямла можно поспорить), а в том, что в этих языках нет синтаксических конструкций для избежания копипасты.
HCL пытается с этим что-то делать, вводя модули, но не забывая вводить магические переменные для описания циклов — что, по мне, отвратительно, и начинает напоминать Ansible с его декларативными конструкциями, которые на практике оказываются просто нетипизируемым ямлом. Ямл тоже пытается избежать копипасты со своими anchors, и
<<, но, опять же, на практике это превращается в просто месиво.Итого, потребность в хорошем языке для конфигов действительно есть.
В статье отсутствует какое-либо сравнение с существующими языками, включая плюсы и минусы каждого из них. Понятно, что ATMC яыляется более "выразительным", и более абстрактным, нежели JSON, YAML etc. Поэтому также стоит сравнить с Pkl, dhall, CUE, jsonnet и другими.
По статье, не доконца понял
можно ли отрендерить/экспоритировать .atmc конфиг в другие форматы?
как сделать ключ с пробелом?
можно ли сделать циклы?
пофейлится ли конфиг с одинаковыми ключами или есть какое-то правило?
при рекурсивном мерже, мержатся ли списки или просто перезаписываются?
Ещё много вопросов можно задать, но думать лень

user-book
10.11.2025 14:30YAML как раз позволяет "копипастить" причем довольно гибко, можно указывать шаблон, а потом докидывать и перезаписывать конкретные параметры, это не Ansible-приколы а часть стандарта
вообще из опыта конфиг нужно строить универсальным:
хочешь пихай json
хочешь yml или что то вообще странное
хочешь запускай без конфига вообще
хочешь укажи всего пару через cli параметры
решать за клиента как ему лучше самая порочная практика. Автор статьи вообще создал уже существующее неоднократно, есть куча похожих json-подобных языков конфигурации
Landgraph
Шутка про n-стандартов…
ИМХО, когда конфиг становится сложнее, чем можно описать в ini файле - что-то пошло не так. И этот конфиг уже перестает быть человекочитаемым и лучше уже иметь какой-то гуй.
paramtamtam
В дополнение, крайние несколько лет являюсь адептом секты "config-less", когда все что нужно сконфигурировать - должно иметь cli/env ручки для этого, и знаете - этот подход более чем жизнеспособен! И строгие правила, и валидация, и генерация документации из этого кода - прям хорошо. Да что уж говорить - великий и могучий Traefik и тот умеет себя конфигурировать флагами без сильной боли ниже поясницы (если понимаешь что делаешь), а он тот еще комбаин.