Рефакторинг исключений для рабочего процесса - PullRequest
0 голосов
/ 03 декабря 2009

В настоящее время я выполняю рефакторинг приложения, которое использует исключения для логического потока. Код трудно читать и поддерживать, и он заставляет фаната S.O.L.I.D, такого как я, плакать при его чтении (не говоря уже о самом длинном блоке уловов, который я когда-либо видел в своей карьере).

У меня вопрос: какие шаблоны вы могли бы использовать для упрощения поддержки или как бы вы провели рефакторинг?

public void CallExternalServices(ICriteria criteria)
{
    try
    {
        someResult = ExternalService1.SomeMethod(criteria);
    }
    catch (Service1Exception service1Exception)
    {
        if (criteria.SomeValue == "1")
        {
            if (service1Exception.InnerException != null 
                && service1Exception.InnerException.InnerException != null
                && service1Exception.InnerException.InnerException is TargetSystemException)
            {
                TargetSystemException targetSystemException = (TargetSystemException)service1Exception.InnerException.InnerException;
                if (targetSystemException.ErrorStatus.IsServiceDownForMaintenance())
                {
                    // Call internal method to perform some action
                    SendNotification("Service down for maintenance.")
                }
            }
        }
        else if (criteria.SomeValue == "2")
        {
            if (service1Exception.InnerException != null 
                && service1Exception.InnerException.InnerException != null
                && service1Exception.InnerException.InnerException is TargetSystemException)
            {
                TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
                if (targetSystemException.ErrorStatus.IsBusy())
                {
                    // Call to some internal method to perform an action
                    SendDifferentNotification()

                    criteria.SetSomeFlagToBe = true;

                    try
                    {
                        someResult = ExternalService2.SomeOtherMethod(criteria);
                    }
                    catch (Service2Exception service2Exception)
                    {
                        if (service2Exception.InnerException != null 
                            && service2Exception.InnerException.InnerException != null
                            && service2Exception.InnerException.InnerException is TargetSystemException)
                        {
                            TargetSystemException tx = (TargetSystemException)service1Exception.InnerException.InnerException;
                            if (targetSystemException.ErrorStatus.HasNumberOfDailyTransactionsBeenExceeded())
                            {
                                // Call internal method to perform some action
                                SendNotification("Number of daily transactions exceeded.")
                            }
                        }
                        else if (service2Exception.InnerException != null
                            && service2Exception.InnerException.InnerException != null
                            && service2Exception.InnerException.InnerException is FaultException)
                        {
                            FaultException faultException = service2Exception.InnerException.InnerException as FaultException;

                            if (faultException.Detail != null
                                && faultException.Detail.FaultMessage.Equals("SomeValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
                            {
                                return someResult;
                            }
                            else
                            {
                                throw service2Exception;
                            }
                        }
                        else
                        {
                            throw service2Exception;
                        }
                    }

                    if (someResult != null)
                    {
                        // perform another action
                        SomeActionInvoker.ExecuteAcitonAgainst(someResult);
                    }
                }
            }
            else if (service1Exception.InnerException != null
                     && service1Exception.InnerException.InnerException != null
                     && service1Exception.InnerException.InnerException is FaultException)
            {
                FaultException faultException = service1Exception.InnerException.InnerException as FaultException;

                if (faultException.Detail != null
                    && faultException.Detail.FaultMessage.Equals("SomeOtherValueToCheckAgainst", StringComparison.OrdinalIgnoreCase))
                {
                    return someResult;
                }
                else
                {
                    throw service1Exception;
                }
            }
            else
            {
                throw service1Exception;
            }
        }
    }
}

Ответы [ 3 ]

1 голос
/ 03 декабря 2009

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

if (<exception-instance>.InnerException != null && 
    <exception-instance>.InnerException.InnerException != null && 
    <exception-instance>.InnerException.InnerException is <exception-type>)

в логический метод; мой краткий взгляд ты называешь код таким как минимум 3 раза.

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

1 голос
/ 03 декабря 2009

Check Эффективная работа с устаревшим кодом от Michael Feathers, особенно в главе 22 («Мне нужно изменить метод монстров, и я не могу написать для него тесты»). Есть много отличных техник для таких ситуаций, как ваша. Лично в таких случаях я обычно заканчиваю тем, что извлекал методы из разделов более длинных методов и избавлялся от локальных переменных, которые используются в методе; это почти всегда неприятности.

0 голосов
/ 03 декабря 2009

Начните с рефакторинга метода на несколько методов. У тебя слишком много уровней отступа.

После этого подумайте, можно ли извлечь некоторые из новых методов в другие объекты, и используйте подход в стиле IoC, а не процедурный.

Это ответ высокого уровня, но я устал и у меня нет сил, чтобы фактически переделать код сам:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...