Внедрить сложные, пересекающиеся ограничения на то, когда и когда не нужно регистрироваться [closed]

Это классическая проблема – более аккуратно обрабатывать постоянно меняющиеся требования без использования слишком большого количества вложенных операторов if. Вот мой текущий код на JavaScript.

fetchApiData(url){
//log before start
  Logger.logFetchStartedEvent();
  try {
    data = backendApi.get(url);
    Logger.logFetchSucceededEvent();
    return data;
  } catch (error) {
    Logger.logFetchFailedEvent();
  }
}

Все шло по счастливой дороге. Но я получил требование, чтобы для некоторых конкретных URL мы вообще не регистрировались.

Без проблем. Я добавил флаг и переключатель и положил конец.

fetchApiData(url, shouldLog){
//log before start
  if(shouldLog) {
    Logger.logFetchStartedEvent();
  }
  try {
    data = backendApi.get(url);
    if(shouldLog) {
      Logger.logFetchSucceededEvent();
    }
    return data;
  } catch (error) {
    if(shouldLog) {
      Logger.logFetchFailedEvent();
    }
  }
}

И это еще не все. Появляется новое требование, и его просят изменить для соответствия следующим требованиям

  • какой-то URL будет записывать все
  • какой-то URL-адрес будет регистрировать только ошибку
  • какой-то URL-адрес будет регистрироваться только в том случае, если URL-адрес вызова API является внешним сайтом
  • в некоторых случаях требуется регистрация события fetchSucceeded, в некоторых случаях это не нужно.

Я думаю, вы поняли. Я могу добавить бесчисленное количество вложенных условных выражений if / else и выполнить это, но теперь я уверен, что должен быть лучший способ решения этой проблемы. Теперь я чувствую, что один метод станет целым методом бога конечного автомата if / else.

Вот что я придумал

fetchApiData(url,logOnStart, logOnSuccess, logOnFailure, logOnlyExternalLink){
  //log on start
  if(logOnStart) {
    if(logOnlyExternalLink) {
      if(isExternalLink(url)) {
        Logger.logFetchStartedEvent();
      }
    } else {
      Logger.logFetchStartedEvent();
    } 
  }
  try {
    data = backendApi.get(url);
    //log on success
    if(logOnSuccess) {
      // may need external url check again
      Logger.logFetchSucceededEvent();
    }
    return data;
  } catch (error) {
    if(logOnFailure) {
      if(errorType(error) === TimeOut)
      {
        Logger.logFetchFailedTimeOutEvent();
      } else if (errorType(error) === 404) {
        Logger.logFetchFailed404Event();
      } else {
        Logger.logFetchFailedEvent();
      }
    }
  }
}

Я прочитал много вопросов о вложенной проблеме if / else, но большинство из них заканчиваются примерами типа foo / bar и расплывчатыми объяснениями, которые не имеют для меня практического смысла из-за отсутствия опыта.

Пожалуйста, укажите мне правильное направление.

2 ответа
2

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

import fetch from 'node-fetch'                                                  
                                                                                
const log = (url,eventName) => console.log(`${url}: ${eventName}`)              
const makeLogger = shouldLog => url => eventName => {                           
    if (shouldLog(url,eventName)) log(url,eventName)                            
}                                                                               
                                                                                
const isExternalLink = url => !url.includes('localhost')                        
                                                                                
const neverLog = (url,eventName) => false                                       
const alwaysLog = (url,eventName) => true                                       
const logError = (url,eventName) => eventName === 'error'                       
const logExternalOrError = (url,eventName) =>                                   
    eventName === 'error' || isExternalLink(url)                                
                                                                                
const errorType = error => 'error'                                              
                                                                                
async function fetchApiData(url, shouldLog) {                                   
    const logger = makeLogger(shouldLog)(url)                                   
    logger('start')                                                             
    try {                                                                       
        const response = await fetch(url)                                       
        logger('success')                                                       
        return response                                                         
    }                                                                           
    catch (error) {                                                             
        logger(errorType(error))                                                
    }                                                                           
}                                                                               
                                                                                
async function main() {                                                         
    await fetchApiData('http://localhost:8080', neverLog) // no log             
    await fetchApiData('http://www.google.ca', alwaysLog) // full log           
    await fetchApiData('http://localhost:8080', logError) // log error only     
    await fetchApiData('http://localhost:8080', logExternalOrError)             
}                                                                               
                                                                                
main()

  • Спасибо, Тед, это круто. Глядя на комментарии модераторов к вопросу, я действительно ждал, когда он будет удален. Вы спасли мою жизнь. Спасибо.

    – некслин

Минимизируйте роль функции.

Это Logger это должно фильтровать события журнала, а не fetchApiData.

Однако я подозреваю, что это проблема дизайна, поскольку я не вижу, как регистратор знает URL. НАПРИМЕР Logger.logFetchStartedEvent() не передан URL

Что необходимо сделать, так это чтобы регистратор знал, какой URL-адрес регистрирует, и что он фильтрует события журнала в соответствии с текущими правилами. Таким образом, ваш первый фрагмент будет правильным кодом, и это также означает, что любой другой код, который регистрирует события, может делать это без необходимости отслеживать набор правил ведения журнала.

    Добавить комментарий

    Ваш адрес email не будет опубликован. Обязательные поля помечены *