Re: Передача контекста через множество уровней абстракции приложения
От: Sinix  
Дата: 30.05.16 11:46
Оценка: 16 (3) +1
Здравствуйте, LWhisper, Вы писали:

LW>Всем привет.


Для начала вот что надо сделать:

1. Выделить чисто утилитарные классы, которые сами по себе с зависимостями не работают и всё нужное явно декларируют в API, через свойства / параметры.
Этот слой вы скорее всего захотите тестировать и заморачиваться с "вспомни, какие зависимости забыл положить" вам вряд ли понравится.

2. Выделить штуки, которые вы хотите предоставлять в виде зависимостей, по возможности оформить их в виде интерфейсов (разумеется, без фанатизма).

3. Внедрить immutable класс-контекст, который будет отвечать за передачу / подмену зависимостей. Что-то очень легковесное, типа ServiceContainer.

ВАЖНО: Никогда, ни при каких обстоятельствах не повторяйте вот эту ошибку в дизайне (метод по умолчанию возвращает null, если сервис не найден). Довелось поработать на проекте с таким решением, если коротко — выстреливало постоянно.
Методы, которые в случае "нунишмогла" возвращают null, надо обзывать с префиксом Try. Иначе ловить вам null reference в самых внезапных местах до конца жизни проекта.

4. Задокументировать типовые сервисы в виде extension-методов. Т.е. большинство вызовов должны выглядеть как context.GetLogger(), а не как context.GetService<ILogger>(). Без этого различить "используем стандартное API" от "протаскиваем экзотичную фигню" невозможно и код превращается в мешанинуиз зависимостей.

5. Для свежего фреймворка (читай, для 4.6): рассмотрите возможность передавать контекст неявно, через AsyncLocal<T>. Упрощает передачу контекста до
var logger = Context.CurrentContext.Logger(); // Context - static class

а с using static — до
var logger = CurrentContext.Logger();

без необходимости протаскивать контекст через параметры.


Вот после того как всё это сделано, большинство проблем с зависимостями рассосётся и оставшееся можно будет обсуждать предметно. Конкретно:


LW>Происходит аутентификация пользователя. Теперь лог пишется уже в каталог этого горемычного юзера.

В момент аутентификации происходит подмена контекста, в новом контексте переопределяется логгер.

LW>Юзер выполняет некоторую команду, лог пишется всё в ту же папку, но уже в файл с именем выполняемой команды.

Снова подмена контекста.

Оффтоп: Вас саппорт случаем не убивает за необходимость собирать лог из десятка файлов?


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

Нувыпоняли

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

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

DI — это уже нашлёпка поверх протаскиваемого контекста. Если с ним бардак, то DI только замаскирует проблему, а не поможет её вылечить.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.