Как стать автором
Обновить

Комментарии 33

Это, конечно, правильно, выносить логгер в абстракцию. Но таким образом любые абстракции, предоставляемые сторонними библиотеками и фреймворками, обрастают обёртками. Зато можно легко поменять фреймворк/библиотеку (наверное).

А вот насчёт внесения ReportShapesSize в классы — это не нарушение SRP?
Вот я, как математик, сижу описываю прекрасные классы кубов, шаров, призм. А потом какой-нибудь продажник из соседнего отдела понавтыкает мне в код свои *$%е методы для одному ему нужного отчёта (да ещё и зависимости притащит от какого-нибудь, пусть не конкретного жирного CrystalReports, но даже абстрактного IReport). Мне было бы неприятно.
Но таким образом любые абстракции, предоставляемые сторонними библиотеками и фреймворками, обрастают обёртками.

Хм.
Фреймворки и так представляют абстракции.
Если так хочется городить огород над его абстракциями, то зачем вообще фреймворк?
Может, автор статьи пояснит.
Вот был у меня код с log4net:
var logger = log4net.LogManager.GetLogger(typeof(ProductManager));
logger.Info("The product is purchased.");

(собственно, чем это отличается от FileLogger в примере?)

Нет, обязательно надо избавить свой код от зависимости от log4net, написать обёртку и интерфейс ILogger, чтобы было по феншую.

Если нужно сделать код юнит тестируемым (подставить моки) относительно уровня и контента логируемых сообщений, то да. Иначе, как хотите. Тут нет единой рекомендации. Прямое использование лог фор нет является имхо жестковатым, если хотите проверять в юнит тестах то, что Вы логируете.

но это же не цель?

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

Жизненный пример: требуется внедрить софт в корпоративную структуру, которая предоставляет свой сервис логгирования. Без жесткой привязки к log4net вы легко напишите адаптер, который поможет внедриться.
Так-то можно закостылить кастомный Appender для log4net, который пишет не в файл, а в другой логгер )))
Можно и так :)

Так и правда стоит делать в общих библиотеках — ведь их пользователь может использовать любой способ ведение логов. А вот в своих программах, я считаю, делать абстракции над абстракциями не стоит.

То есть, каждая библиотека должна предоставить свой интерфейс логирования ILibraryLogger, а ещё должен быть интерфейс логгера на уровне приложения (IMyAppLogger), который передаётся как зависимость в классы приложения, и куча конверторов во все логгеры из интерфейсов конечных библиотек логирования.

Тут непонятно, где подвести «общий знаменатель». У кажого логера свои фичи, а каждая библиотека может выставить свои требования к логгеру. Конверторам придётся либо что-то игнорить, либо реализовывать недостающее.

В таких ситуациях надо идти не от общего знаменателя, а от задачи. Нужно залогировать событие X? Значит, один из методов в интерфейсе должен быть способен залогировать X.

На каждое событие отдельный метод?

На каждый класс схожих событий.

НЛО прилетело и опубликовало эту надпись здесь
Хорошее замечание про ReportShapesSize. В некоторых языках это красиво решается при помощи тайпклассов. Будет круто, если в шарпах появится такой функционал.
Думаю, что для фигуры метод Report(), отвественный за вывод консоль, нарушает SRP.
С другой стороны наличие метода или свойства, возвращающего площадь, будет оправданно для геометрической фигуры. Хелпер бы уже можно было завязать на него.

Принцип SRP как показывает опыт довольно спорный. Это предмет отдельной дискуссии. Вспомните ООП. Там не брезгуют хранить состояние объекта и в то же время наделяют его методами. В нашем случае фигура сознательно наделена способностью себя рисовать. В нашем случае считаю это достаточным.

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

У меня был случай когда из-за проблем с лицензией приходилось менять Unity IoC контейнер на кастомный. В случаем с логгерами, в принципе log4net с его аппендерами бывает достаточным. Но мало ли что? Вдруг придется… Кроме того, абстракция логгера поможет при юнит тестировании, если есть требования на логирование. Например, в таком-то случае нужно логировать то-то с таким-то уровнем. В моем проекте такое встречается довольно часто.

Необходимости менять не было, но желание было.
Например, было желание переехать с NLog на Serilog. И, кстати, переехали в итоге.
Правда в абстракции для логгера я тоже не вижу смысла, как для IoC контейнера.
Переехать с одного логгера на другой оказалось несложно без всяких абстракций.
Кто-нибудь когда-нибудь имел необходимость менять логгер в существующем проекте?

Да регулярно. Заменить самописный логгер на что-то более функциональное.

В первом примере в разделе "Хрупкость" похоже опечатка: "roleId == 1 && roleId == 2", или это так задумано? Условие всегда ложно, там скорее всего "или" должно быть..

Да, это опечатка. Поправлю, спасибо!

Мне кажется, или «жесткость» и «неподвижность» можно объединить под общий пункт «сильная связанность»? Использование абстракций, а вместе с ними IoC и DI практически толкает на разделение кода на модули. Другое дело, сможет ли разработчик правильно поделить ответственность между модулями.
Я ожидал в «ненужной сложности» прочитать о лишних слоях, типа менеджеры адаптеров фасадов менеджеров и тому подобное.

Вы правы, возможно я дополню эту главу чем-то подобным, спасибо.

В этом случае класс A перестает зависеть от конкретного класса B, а зависит лишь от интерфейса IComponent.

А если интерфейс нужно поменять? Еще больше правок придется сделать.

Все может поменяться. Обычно интерфейсы меняются реже чем их реализации. Закрыть все от изменений не получится.

В чем тогда проблема поменять реализацию класса B?

Хотя бы в том, что прямая ссылка на класс B может сделать класс A трудно тестируемым юнит тестами, которые требуют использование мока для тестирования логики класса A. Получается реализация меняется, а абстракция остается неизменной.

Да, с тестами согласен.

Зарегистрируйтесь на Хабре , чтобы оставить комментарий

Публикации

Истории