Почему JSON и YAML мешают вам писать нормальные конфиги (и чем их заменить)
- вторник, 11 ноября 2025 г. в 00:00:22
JSON, YAML, TOML, HCL - за последние годы человечество успело изобрести десяток языков для конфигурации.
Каждый обещал быть "простым", "удобным" и "читаемым человеком".
Но по факту - все они страдают от одних и тех же проблем: шумный синтаксис, хрупкие отступы, бесконечные кавычки и отсутствие элементарных возможностей вроде модульности и слияния конфигов.
Пора перестать с этим мириться и сделать конфигурации наконец человеческими.
утомлять глаза, пытаясь разобраться в тонне бесполезных кавычек
утомлять глаза, пытаясь распознать в каком месте есть проблема с отступом
писать велосипед, когда в очередной раз нужно мержить конфиги для разных окружений
писать велосипед, когда нужно парсить env переменные в структуру конфига
забивать мозг, пытаясь разобраться в огромной конфигурации из-за отсутствия модульности
Использовать адекватный язык для конфигурации 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
}
}
📄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