10 кроків до YAML-дзену

Ми всі любимо Ansible, але Ansible – це YAML. Для конфігураційних файлів існує маса форматів: списки значень, пари "параметр-значення", INI-файли, YAML, JSON, XML та багато інших. Однак з кількох причин з них YAML часто вважається особливо важким. Зокрема, незважаючи на його освіжаючий мінімалізм та вражаючі можливості для роботи з ієрархічними значеннями, синтаксис YAML може дратувати своїм Python-подібним підходом до відступів.

10 кроків до YAML-дзену

Якщо вас дратує YAML, ви можете – і маєте! - зробити 10 наступних кроків, щоб знизити своє роздратування до прийнятного рівня та полюбити YAML. Як і належить справжньому списку, наша десятка порад нумеруватиметься з нуля, медитацію та духовні практики додаємо за бажанням 😉

0. Примусіть ваш редактор працювати

Неважливо, який у вас текстовий редактор - для нього, напевно, існує хоча б один плагін для роботи з YAML. Якщо у вас такого немає, негайно знайдіть та встановіть. Витрачений на пошук та налаштування час буде багаторазово окупатися щоразу, коли вам доведеться редагувати YAML.

Наприклад, редактор Atom підтримує YAML за умовчанням, а ось для GNU Emacs доведеться встановити додаткові пакети, наприклад, yaml-mode.

10 кроків до YAML-дзену

Emacs у режимі YAML та відображення пробілів.

Якщо у вашому улюбленому редакторі немає режиму YAML, то частину проблем можна вирішити, попрацювавши з налаштуваннями. Наприклад, штатний для GNOME текстовий редактор Gedit не має режиму YAML, але за умовчанням підсвічує синтаксис YAML і дозволяє налаштувати роботу з відступами:

10 кроків до YAML-дзену

Налаштування відступів у Gedit.

А плагін drawspaces для Gedit відображає прогалини у вигляді точок, усуваючи неясності з рівнями відступу.

Іншими словами, згаяйте час на вивчення свого улюбленого редактора. З'ясуйте, що він сам або його спільнота розробки пропонують для роботи з YAML, та використовуйте ці можливості. Ви точно про це не пошкодуєте.

1. Використовуйте лінтер (linter)

В ідеалі мови програмування та мови розмітки використовують передбачуваний синтаксис. Комп'ютери добре справляються з передбачуваністю, тому ще 1978 року виникла концепція лінтера. Якщо за 40 років свого існування вона пройшла повз вас і ви досі не користуєтеся YAML-лінтером, то саме час спробувати yamllint.

встановити ямлінт можна за допомогою штатного менеджера пакетів Linux. Наприклад, в Red Hat Enterprise Linux 8 або Fedora це робиться так:

$ sudo dnf install yamllint

Потім ви просто запускаєте yamllint, передаючи йому YAML файл для перевірки. Ось як це виглядає, якщо передати лінтеру файл з помилкою:

$ yamllint errorprone.yaml
errorprone.yaml
23:10     error    syntax error: mapping values are not allowed here
23:11     error    trailing spaces  (trailing-spaces)

Цифри ліворуч – це не час, а координати помилки: номер рядка та стовпця. Опис помилки може вам ні про що не говорити, зате ви знаєте, де вона знаходиться. Просто подивіться на це місце в коді, і, швидше за все, все стане зрозумілим.

Коли yamllint не знаходить помилок у файлі, екран нічого не виводиться. Якщо вас лякає така тиша і хочеться трохи більше зворотного зв'язку, можна запускати лінтер з умовною командою echo через подвійний амперсанд (&&), ось так:

$ yamllint perfect.yaml && echo "OK"
OK

У POSIX подвійний амперсанд спрацьовує тоді і лише тоді, коли попередня команда повертає 0. А yamllint якраз повертає кількість знайдених помилок, тому вся ця умовна конструкція працює.

2. Пишіть на Python, а не на YAML

Якщо вас реально дратує YAML, просто не пишіть на ньому буквально. Буває, що YAML – це єдиний формат, який сприймається програмою. Але й у цьому випадку необов'язково створювати файл YAML. Пишіть на тому, що вам подобається, а потім конвертуйте. Наприклад, для Python є чудова бібліотека pyyaml і два способи конвертування: самоконвертування і конвертування через скрипти.

Самоконвертування

У цьому випадку файл з даними заразом є і Python-скриптом, який генерує YAML. Цей спосіб найкраще підходить для невеликих наборів даних. Ви просто пишіть JSON-дані в змінну Python, випереджаєте це директивою import, а в кінці файлу додаєте три рядки для реалізації висновку.

#!/usr/bin/python3	
import yaml 

d={
"glossary": {
  "title": "example glossary",
  "GlossDiv": {
	"title": "S",
	"GlossList": {
	  "GlossEntry": {
		"ID": "SGML",
		"SortAs": "SGML",
		"GlossTerm": "Standard Generalized Markup Language",
		"Acronym": "SGML",
		"Abbrev": "ISO 8879:1986",
		"GlossDef": {
		  "para": "A meta-markup language, used to create markup languages such as DocBook.",
		  "GlossSeeAlso": ["GML", "XML"]
		  },
		"GlossSee": "markup"
		}
	  }
	}
  }
}

f=open('output.yaml','w')
f.write(yaml.dump(d))
f.close

Тепер запускаємо цей файл на Python і на виході отримуємо файл output.yaml:

$ python3 ./example.json
$ cat output.yaml
glossary:
  GlossDiv:
	GlossList:
	  GlossEntry:
		Abbrev: ISO 8879:1986
		Acronym: SGML
		GlossDef:
		  GlossSeeAlso: [GML, XML]
		  para: A meta-markup language, used to create markup languages such as DocBook.
		GlossSee: markup
		GlossTerm: Standard Generalized Markup Language
		ID: SGML
		SortAs: SGML
	title: S
  title: example glossary

Це абсолютно коректний YAML, але yamllint видасть попередження, що він не починається з. Що ж, це можна легко виправити вручну або злегка доопрацювати Python-скрипт.

Конвертування через скрипти

У цьому випадку спочатку пишемо на JSON-і, а потім запускаємо конвертор у вигляді окремого Python-скрипта, який на виході дає YAML. Порівняно з попереднім, цей спосіб краще масштабується, оскільки конвертування відокремлено даних.

Для початку створимо JSON-файл example.json, наприклад, його можна взяти на json.org:

{
	"glossary": {
	  "title": "example glossary",
	  "GlossDiv": {
		"title": "S",
		"GlossList": {
		  "GlossEntry": {
			"ID": "SGML",
			"SortAs": "SGML",
			"GlossTerm": "Standard Generalized Markup Language",
			"Acronym": "SGML",
			"Abbrev": "ISO 8879:1986",
			"GlossDef": {
			  "para": "A meta-markup language, used to create markup languages such as DocBook.",
			  "GlossSeeAlso": ["GML", "XML"]
			  },
			"GlossSee": "markup"
			}
		  }
		}
	  }
	}

Потім створимо простий скрипт-конвертор та збережемо його під ім'ям json2yaml.py. Цей скрипт імпортує обидва модулі - YAML і JSON Python, а також завантажує вказаний користувачем файл JSON, виконує конвертування і пише дані у файл output.yaml.

#!/usr/bin/python3
import yaml
import sys
import json

OUT=open('output.yaml','w')
IN=open(sys.argv[1], 'r')

JSON = json.load(IN)
IN.close()
yaml.dump(JSON, OUT)
OUT.close()

Збережіть цей скрипт у system path і запускайте при необхідності:

$ ~/bin/json2yaml.py example.json

3. Парсіте багато і часто

Іноді на проблему корисно поглянути під іншим кутом. Якщо вам важко уявити взаємозв'язки між даними в YAML, можна тимчасово перетворити їх на щось звичніше.

Наприклад, якщо вам зручно працювати зі словниковими списками або з JSON, то YAML можна перетворити на JSON лише двома командами в інтерактивній оболонці Python. Допустимо, у вас є YAML-файл mydata.yaml, тоді ось як це буде виглядати:

$ python3
>>> f=open('mydata.yaml','r')
>>> yaml.load(f)
{'document': 34843, 'date': datetime.date(2019, 5, 23), 'bill-to': {'given': 'Seth', 'family': 'Kenlon', 'address': {'street': '51b Mornington Roadn', 'city': 'Brooklyn', 'state': 'Wellington', 'postal': 6021, 'country': 'NZ'}}, 'words': 938, 'comments': 'Good article. Could be better.'}

На цю тему можна знайти безліч інших прикладів. Крім того, є безліч онлайн-конвертерів і локальних парсерів. Тож не соромтеся переформатувати дані, коли бачите в них лише незрозумілу мішанину.

4. Читайте спіки

Повертаючись до YAML після тривалої перерви, корисно зайти на yaml.org та перечитати специфікації (спіки). Якщо у вас проблеми з YAML, але до специфікації руки так і не дійшли, то настав час цю ситуацію виправляти. Спеки напрочуд легко написані, а вимоги до синтаксису ілюструються великою кількістю прикладів у Розділ 6.

5. Псевдоконфіги

При написанні книги або статті завжди корисно спершу накидати попередній план, хоча б у вигляді змісту. Так само і з YAML. Швидше за все, ви уявляєте, які дані треба записати у файл YAML, але не дуже розумієте, як зв'язати їх один з одним. Тому перш ніж ваяти YAML, намалюйте псевдоконфіг.

Псевдоконфіг схожий на псевдокод, де не треба дбати про структуру або відступи, відносини «батько-нащадок», успадкування та вкладеності. Так і тут: ви малюєте ітерації даних у міру того, як вони з'являються у вас в голові.

10 кроків до YAML-дзену

Псевдоконфіг з перерахуванням програмістів (Martin та Tabitha) та їх навичок (мов програмування: Python, Perl, Pascal та Lisp, Fortran, Erlang, відповідно).

Намалювавши псевдоконфіг на аркуші паперу, уважно проаналізуйте його і, якщо все гаразд, оформіть у вигляді валідного YAML-файлу.

6. Дилема «табуляція чи прогалини»

Вам доведеться вирішити дилему «табуляція чи прогалини?». Не в глобальному сенсі, а лише на рівні вашої організації, чи хоча б проекту. Неважливо, чи буде при цьому використовуватися пост-обробка скриптом sed, налаштування текстових редакторів на машинах програмістів або ж поголовне взяття розписок про суворе дотримання вказівок літера під загрозою звільнення, але всі члени вашої команди, які так чи інакше стосуються YAML, обов'язково повинні використовувати лише прогалини (як потребує специфікація YAML).

У будь-якому нормальному текстовому редакторі можна налаштувати автозаміну табуляції на задану кількість пробілів, тому бунт прихильників клавіші таб можна не боятися.

Як добре відомо кожному ненависнику YAML, на екрані не видно різниці між табуляцією та пробілами. А коли чогось не видно, про це, як правило, згадують в останню чергу, після того, як перебрали, перевірили та усунули решту можливих проблем. Час часу, вбитий на пошук кривої табуляції або блоку пробілів, просто кричить про те, що вам над терміново створити політику використання того чи іншого, а потім реалізувати залізобетонну перевірку її дотримання (наприклад, через Git-хук для примусового прогону через лінтер).

7. Краще менше та краще (або більше – це менше)

Деякі люди люблять писати YAML, оскільки він підкреслює структуру. У цьому вони активно використовують відступи, щоб виділяти блоки даних. Це таке свого роду шахрайство для імітації мов розмітки, у яких використовуються явні роздільники.

Ось приклад такої структурованості з документації Ansible:

# Employee records
-  martin:
        name: Martin D'vloper
        job: Developer
        skills:
            - python
            - perl
            - pascal
-  tabitha:
        name: Tabitha Bitumen
        job: Developer
        skills:
            - lisp
            - fortran
            - erlang

Комусь такий варіант допомагає розкласти в голові структуру YAML, інших він, навпаки, дратує масою непотрібних, на їх погляд, відступів.

Але якщо ви власник YAML-документу і відповідаєте за його супровід, то ви і тільки ви повинні визначати, як використовувати відступи. Якщо вас дратують великі відступи, зведіть їх до мінімуму, який лише можливий згідно з специфікацією YAML. Наприклад, вищенаведений файл з документації Ansible без будь-яких втрат можна переписати ось так:

---
- martin:
   name: Martin D'vloper
   job: Developer
   skills:
   - python
   - perl
   - pascal
- tabitha:
   name: Tabitha Bitumen
   job: Developer
   skills:
   - lisp
   - fortran
   - erlang

8. Використовуйте заготовки

Якщо при заповненні файлу YAML ви постійно повторюєте одні й самі помилки, має сенс вставити в нього шаблон-заготівлю у вигляді коментаря. Тоді наступного разу можна буде просто скопіювати цю заготівлю та вписати туди реальні дані, наприклад:

---
# - <common name>:
#   name: Given Surname
#   job: JOB
#   skills:
#   - LANG
- martin:
  name: Martin D'vloper
  job: Developer
  skills:
  - python
  - perl
  - pascal
- tabitha:
  name: Tabitha Bitumen
  job: Developer
  skills:
  - lisp
  - fortran
  - erlang

9. Використовуйте щось інше

Якщо програма не тримає вас мертвою хваткою, можливо, варто змінити YAML на інший формат. Згодом конфігураційні файли можуть переростати себе і тоді краще перетворити їх на прості скрипти на Lua або Python.

YAML – чудова штука, яку багато хто любить за мінімалізм та простоту, але це далеко не єдиний інструмент у вашому арсеналі. Тож іноді від нього можна відмовитись. Для YAML легко знайти бібліотеки парсингу, тому якщо ви запропонуєте зручні варіанти міграції, ваші користувачі відносно безболісно переживуть таку відмову.

Якщо ж без YAML ніяк не обійтися, то візьміть на озброєння ці 10 порад і переможіть свою ворожість до YAML раз і назавжди!

Джерело: habr.com

Додати коментар або відгук