Рубрики
Без рубрики

Результат: композиция и ошибка умение обращаться

Мы можем улучшить нашу обработку и композицию ошибок, используя класс результатов и несколько других инструментов из мира функционального программирования. Tagged с помощью JavaScript, TypeScript, ROP, функциональный.

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

Вместо того, чтобы бросать ошибки, мы обертываем наши результаты. Либо результатом является значение ошибки, либо значение успеха, в процессе, документируя возможные ошибки. Абоненты должны сначала исследовать и развернуть результат, обрабатывая либо успех, либо сбой. Проложить путь для более функционального программирования и композиции.

Для более полного знакомства с классом результата и ориентированным на железную дорогу программирование:

Для проверки реализаций Github #Железнодорожный ориентированное программирование ; ROP во многих языках программирования ( Python/go/java/c#/f# так далее)

В этих сериях я поделюсь своими выводами во время моего (захватывающего) путешествия.

Императивная выборка

const r = doSomeAction() // Result
if (r.isErr()) { // r: Error
  if (r.error instanceof SomeVariableIsInvalid) {
    ctx.body = r.error.message
    ctx.statusCode = 400
  } else {
    ctx.statusCode = 500
  }
  return
}
// r: Ok
ctx.body = r.value
ctx.statusCode = 200

Доосомеакция может быть реализовано как:

function doSomeAction(): Result {
  if (!someVariableIsValid) {
    return err(new SomeVariableIsInvalid("some variable is not valid")
  }
  if (!isServiceAvailable()) {
    return err(new ServiceUnavailableError("The service is currently unavailable")
  }

  return ok("success response")
}

Функциональный образец

doSomeAction() // Result
  .map(value => {
    ctx.body = value
    ctx.statusCode = 200
  })
  .mapErr(error => {
    if (error instanceof SomeVariableIsInvalid) {
      ctx.body = error.message
      ctx.statusCode = 400
    } else {
      ctx.statusCode = 500
    }
  })

Все «операторы» должны жить на объекте результата, и, следовательно, расширение сложнее. (Это похоже на то, как, например, rxjs начал)

Функциональная композиция

doSomeAction() // Result
  .pipe(
    map(value => {
      ctx.body = value
      ctx.statusCode = 200
    }),
    mapErr(error => {
      if (error instanceof SomeVariableIsInvalid) {
        ctx.body = error.message
        ctx.statusCode = 400
      } else {
        ctx.statusCode = 500
      }
    })
  )

Операторы теперь просто функционируют, легко расширять и катить наши собственные 😉 ( Rxjs v5.5 Пользователи могут увидеть здесь некоторые сходства)

Данные в последний раз

const pipeline = pipe(
  map(value => {
    ctx.body = value
    ctx.statusCode = 200
  }),
  mapErr(error => {
    if (error instanceof SomeVariableIsInvalid) {
      ctx.body = error.message
      ctx.statusCode = 400
    } else {
      ctx.statusCode = 500
    }
  })
)

pipeline(doSomeAction())

Так трубопровод теперь многоразовый. Если только TC39 Предложение-Pipeline-Operator Скоро приземлится, чтобы мы получили синтаксический сахар, который скрывает котелную пластину и синтаксический шум:)

Здание на вершине

Дальнейшее разложение на отдельные функции, так что они становятся повторными или разделять уровни абстракции, чтобы трубопровод становился легче читать.

const writeSuccessResponse = value => {
  ctx.body = value
  ctx.statusCode = 200
}

const writeErrorResponse = error => {
  if (error instanceof SomeVariableIsInvalid) {
    ctx.body = error.message
    ctx.statusCode = 400
  } else {
    ctx.statusCode = 500
  }
}

const pipeline = pipe(
  map(writeSuccessResponse),
  mapErr(writeErrorResponse)
)

Дальнейшее разложение:

const writeSuccessResponse = value => {
  ctx.body = value
  ctx.statusCode = 200
}

const writeDefaultErrorResponse = error => {
  ctx.statusCode = 500
}

const writeSomeVariableIsInvalidErrorResponse = error => {
  if (error instanceof SomeVariableIsInvalid) {
    ctx.body = error.message
    ctx.statusCode = 400
  }
}

const pipeline = pipe(
  map(writeSuccessResponse),
  mapErr(writeDefaultErrorResponse),
  mapErr(writeSomeVariableIsInvalidErrorResponse),
)

Возможно, другой вариант:

const mapErrIf = (errorHandler: error => void, predicate: error => boolean) => 
  error => {
    if (!predicate(error)) { return }
    errorHandler(error)
  }
}
// usage
mapErrIf(_ => ctx.statusCode = 400, error => error instanceOf SomeVariableIsInvalid)

И, конечно, есть много других вариантов и форм композиции, пусть это будет учет читателя 😉

Структура и пример кода

Я работаю над структурой приложений, изучая эти темы, которые широко используют композицию трубопровода, в комплекте приложением примеров!

Исходный код:

Что дальше

Далее в серии я планирую представить более продвинутые концепции, как плоская карта , totup , футболка и другие:)

дальнейшее чтение

Обязательно также проверьте gcanti/fp-ts ; Ориентированная на программировавшая библиотека, особенно V2, выглядит очень многообещающей из -за аналогичной композиции трубы!

Оригинал: “https://dev.to/patroza/result-composition-and-error-handling-m8i”