Как скрыть управление конфигурацией от основной функции?

У меня есть точка входа, как это:

def main(args: Array[String]): Unit = {
  pureconfig.loadConfig[Conf] match {
    case Right(conf) => doStuff(conf)
    case Left(fail) => lectureUserAboutStuff(fail)
  }
}

Похоже, что основная цель моей программы - загрузить конфигурацию, что не соответствует действительности, ядро ​​моей программы - doStuff,

Как выразительно представить это и скрыть скрытую конфигурацию?

Я хотел бы что-то вроде этого:

def main(args: Array[String]): Unit = {
  doStuff(conf)(failHandler)
}

В котором ясно, что обработка сбоев и загрузка конфигурации является лишь аксессуаром.

1 ответ

Решение

Один из наиболее распространенных способов использования PureConfig из main метод вашей программы заключается в быстром сбое в случае ошибки. API обеспечивает loadConfigOrThrow который возвращает конфигурацию, если загрузка прошла успешно, и выдает ConfigReaderException иначе:

import pureconfig.loadConfigOrThrow

def main(args: Array[String]): Unit = {
  val conf = loadConfigOrThrow[Conf] // will throw if Conf cannot be loaded
  doStuff(conf)
}

Причина по которой pureconfig.loadConfig возвращает Either это потому, что загрузка конфигурации может быть неудачной. Either моделирует случай отказа, с Leftи случай успеха, с Right, Это хорошо для библиотеки, потому что вы никогда не знаете, где loadConfigбудет вызван, и, следовательно, вы не хотите бросать исключение. Хотя это в целом верно, когда loadConfig используется из "поверхностного" метода, например mainВыдача исключения или просто выход в случае сбоя загрузки конфигурации имеет смысл, и именно поэтому pureconfig предоставляет loadConfigOrThrow,

Если вам не нравится выбрасывать исключение или вы предпочитаете собственный обработчик ошибок, например lectureUserAboutStuffВы можете создать помощника:

def loadConfig(): Option[Conf] = {
  val errorOrConf = pureconfig.loadConfig[Conf]
  errorOrConf.left.foreach(lectureUserAboutStuff)
  errorOrConf.toOption
}

def main(args: Array[String]): Unit =
  loadConfig().foreach(doStuff)

И последнее, что следует иметь в виду, это то, что небольшая проблема с этим кодом заключается в том, что на код завершения приложения не влияют сбои конфигурации. Если вы хотите установить код выхода, когда конфигурация не может быть загружена, измените main в

val configReaderFailureErrorCode = 42

private def configFailureExit() =
  sys.exit(configReaderFailureErrorCode)

def main(args: Array[String]): Unit =
  loadConfig().fold(configFailureExit())(doStuff)
Другие вопросы по тегам