Scala IRL. Часть 1: конфиги.

Для Scala, как для языка довольно молодого, пока ещё нет (а может уже и не будет) единого стандарта для такой обыденной вещи как конфиг-файлы. Вариантов не так уж много и в этом посте я хочу сделать небольшой обзор тех, которые мне так или иначе довелось использовать.

.properties

Текстовые и XML файлы, хранящие пары “ключ-значение”. Вполне подходят для конфигурирования большинства проектов, а в стандартной библиотеке JRE, есть средства для работы с ними. Что касается поддержки со стороны Scala, в пакете scala.collection есть объекты JavaConverters и JavaConversions, предоставляющие implicit методы для конвертации объектов класса Properties в mutable.Map[String, String].

Эти файлы часто используются не столько для хранения конфигов, сколько для локализации. Тут нельзя промолчать об одной их особенности, о которой, наверное, знает каждый Java-программист, но которая всегда меня изумляла: в платформе, где Unicode является основной кодировкой для работы со строками, для хранения локализованных строк предлагается формат, не поддерживаюший unicode. Файлы предлагается сначала писать в unicode, а потом конвертировать в странный и уродливый формат утилитой native2ascii. Ну не отвратительно ли?

Эти же файлы использует фреймворк Lift (с расширением .props), добавляя к ним замысловатый механизм выбора нужного файла в зависимости от режима работы (run mode) и окружения.

XML и JSON

Здесь всё понятно: стандартных библиотек целая куча, и старые явовские, и специально сделанные для Scala с вкусностями типа XPath-подобных DSL. Такие конфиги имеют привычку разрастаться до неприличных размеров, а JSON ещё и не умеет удобно работать с длинными и многострочными значениями и не имеет констукции для комментариев. Впрочем, можно просто использовать для этой цели обычные поля, которые при чтении конфига будут игнорироваться.

configgy

configgy - замечательная Scala-библиотека, выполняющая сразу две задачи: работа с конфиг-файлами и удобный логгинг. Эти задачи практически никак не связаны между собой (за исключением того, что логгинг тоже надо конфигурировать), но это именно те две задачи, которые требуется решать в практически любом проекте больше сотни строк.

Configgy поддерживает несколько форматов для конфигов, как линейный, так и со вложенными блоками, типа такого:

# JDBC parameters
jdbc {
    driver = "com.mysql.jdbc.Driver"
    uri = "jdbc:mysql://localhost:3306/test?characterEncoding=UTF8"
    limit = 5000 # Batch size for selects
}

#logging parameters, see configgy readme for details
log {
    filename = "debug.log"
    level = "debug"
    utc = false
    console = false
}

Логгинг автоматически подхватывает параметры из секции log при чтении конфига, что очень удобно - вся обычная рутина с конфигурированием сводится практически к одной строчке.

Ostrich

Когда мы собрались прицепить configgy к одному из очередных наших проектов, то обнаружили (на страничке проекта на github), что проект теперь deprecated (хотя и будет пока поддерживаться в каком-то виде) и вместо него предлагается использовать Scala-библиотеки от twitter. Для логгинга - util-logging из набора Util, который помимо лог-файлов поддерживает Scribe и Syslog, для конфигурирования - ostrich.

Ostrich - это довольно развесистая библиотека, предназначенная для

  • конфигурирования
  • сбора статистики
  • запуска/остановки приложения и его сервисов
  • предоставления админского интерфейса через HTTP или просто сокет

Главная особенность конфиг-файлов ostrich - они являются обычными Scala-классами, со всемы вытекающими: они типизированы и могут наследоваться от абстрактного класса или трейта. В тех местах, где конфигурация используется, отпадает необходимость извлечения значений из конфига, проверки на то что они присутствуют, предоставления дефолтных значений и приведения к нужному типу. Обратной стороной медали можно было бы назвать необходимость компиляции конфига в рантайме, но поскольку делать это нужно не так уж часто (обычно при старте приложения), то ради красивых type-safe конфигов можно и потерпеть.

Также, ostrich предоставляет готовую заготовку ServerConfig, включающую в себя настройку логгинга и поднятие http/socket интерфейса при загрузке.

Несмотря на фичастость, мне кажется что автор configgy совершенно зря остановил развитие библиотеки: она очень проста в использовании и идеально подходит для большого диапазона проектов. Ostrich же относится к совершенно другой категории и для многих задач его навороченность выглядит излишней. Кроме того, в его использовании есть несколько подводных камней, о которых я постараюсь рассказать поподробнее в следующий раз.

Comments