Какие слои должны регистрироваться для исключений? - PullRequest
5 голосов
/ 12 января 2020

У меня есть одно большое монолитное c приложение с четырьмя слоями для определенных c функциональных требований.

UI Layer -> Presentation Logic Layer -> Business Logic Layer -> Persistent Layer

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

class ProductViewController {
    func showProduct(list){
        // populate list in view
    }
}

class ProductPresenter {
    func sanitiseProduct(list){
        // apply presentation logic to list
        viewController.showProduct(list)
    }
}

class ProductService {
    func filerProducts(list){
        // apply filtering logic to list
        productPresenter.sanitiseProduct(list)
    }
}


class ProductDatabase {
    func retrieveProducts(){
        // retrieve raw product list
        productService.filerProducts(getAllProduct())
    }
}

Теперь, если какое-либо исключение произойдет в каком-либо слое потока (например, query exception in Database layer), я решил зарегистрировать его в каждом слое с соответствующими TAG и info и отбросить на верхние уровни для распространяется так, что при отладке каждый уровень может фильтровать свои собственные журналы, используя соответствующую метку, не заглядывая в другие уровни (например, especially when different teams are responsible for different layers).

Во время проверки один из моих коллег отметил, что в моем проекте будет дублирование журналов для одного исключения / ошибки, что может привести к снижению производительности и памяти. Он предлагает применить регистрацию в одном из слоев для определенных c исключений (то есть query exception in Persistent Layer only). Однако он предложил продолжить выдавать исключение на верхние уровни.

Следует ли изменить мой подход к ведению журналов, который обеспечивает лучшую ремонтопригодность, ради производительности и памяти? Каковы общие предложения по решению этой ситуации?

Ответы [ 6 ]

4 голосов
/ 14 января 2020

Ответ, скорее всего, страшен .. Это зависит. Я имею в виду, если у вас есть проблемы с производительностью или памятью, конечно, каждый немного помогает. Кроме того, наличие дублированных записей в журнале может вызвать другие проблемы (как и у каждой команды, просматривающей запись / ошибку журнала, даже если она не имеет к ним отношения. Потратить время на просмотр несущественных записей журнала может быть пустой тратой времени для команд, даже если они могут увидеть теги довольно быстро). Ведение журнала только в источнике может быть полезно, если это является проблемой.

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

Поэтому я предлагаю, если в настоящее время нет проблем с памятью, производительностью или чем-то подобным, ремонтопригодность выигрывает для долгоживущих монолитных c приложений. Но я думаю, что это ответ, вероятно, отличается от разработчика к разработчику.

2 голосов
/ 21 января 2020

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

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

Из моего опыта исключение должно обрабатываться ответственным уровнем, а результат должен возвращаться в соответствии с 'контрактом' с вызывающими уровнями. Это делает очень плотный интерфейс между уровнями, и исключение генерируется нижним уровнем, когда согласованный интерфейс не соблюдается (например, IllegalArgument)

В случае, если обработка исключения не может привести к правильному возвращенному результату (например, База данных соединение потеряно), тогда generi c 'Layer Exception' может быть сгенерировано уровнем, обрабатывающим исключение (например, 'DataAccessError', сгенерированный Data Layer) Это исключение должно быть поймано только тем уровнем, который может вернуть результат верхним уровням в соответствии с контрактом, иначе не должен обрабатываться. В конечном счете, в этом случае слой Presentation будет корректно обрабатывать исключение.

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

[PRESENTATION] Error displaying Product Info: DataAccessLayerError - Error fetching Product info for ID 123.
...
...
[DATA] Error fetching Product info for ID 123:
/stack trace of caught DB Connection Error/

Это в сочетании с печатью Контекст потока (или эквивалент в вашей структуре ведения журнала) упростит отслеживание ошибок в ваших лог-файлах.

1 голос
/ 21 января 2020

Вы можете попытаться следовать этому шаблону домена https://martinfowler.com/articles/domain-oriented-observability.html Кроме того, код, который не поддерживается, обычно не может привести к хорошему увеличению производительности.

1 голос
/ 20 января 2020

Если вы не можете восстановить, просто повторно выбросьте свое исключение и поймайте его в слое перехватчика (промежуточное ПО).

В противном случае вы можете следовать этому интересному шаблону домена: https://martinfowler.com/articles/domain-oriented-observability.html

0 голосов
/ 21 января 2020

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

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

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

                  +----------------------+
                  |                      |
        +---------+   LoggableException  +----------+
        |         |                      |          |
        |         +-----------+----------+          |
        |                     |                     |
        |                     |                     |
        |                     |                     |
        |                     |                     |
+-------v--------+    +-------v--------+   +--------v--------+
|                |    |                |   |                 |
|  Exception1    |    |   Exception2   |   |   Exception3    |
+----------------+    +----------------+   +-----------------+

0 голосов
/ 21 января 2020

В идеале ответом будет Business Logic Layer. Что касается Persistence Layer, исключения могут быть пойманы на Business Logic Layer.

Кроме того, работа Presentation Layer состоит в том, чтобы взять данные из UI Layer, десериализовать их и отправить их в Business Logic Layer, затем взять данные из Business Logic Layer, сериализовать их и отправить в UI Layer.

ИЛИ

Это также зависит от архитектуры программного обеспечения. Вы также можете регистрировать ошибку в каждом слое и использовать уникальный идентификатор для поиска указанной операции c. Например, программное обеспечение, использующее запросы HTTP, должно использовать уникальный requestId в каждом операторе журнала, чтобы идентифицировать все операции для запроса и для системы обмена сообщениями (очередей). messageId может использоваться аналогично для идентификации журналов для операции.

...