четверг, 11 декабря 2014 г.

Интерфейсы vs. Абстрактные классы

DISCLAIMER: ниже речь идет об интерфейсах и абстрактных классах на платформе .NET. Большая часть рассуждений применима и к другим языкам, с разделением понятий интерфейсов и классов.

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

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

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

В языках с множественным наследованием, таких как С++ или Eiffel, понятие интерфейса отсутствует, в нем просто отпадает необходимость. Отсутствие полноценного множественного наследования влияет на то, как мы проектируем иерархию классов.

понедельник, 8 декабря 2014 г.

Для чего нужны интерфейсы?

В чем сила интерфейсов? Сила интерфейсов в правде слабости системы типов!

Принято считать, что интерфейсы предназначены для моделирования абстракций и обеспечения слабой связанности (loose coupling). Звучит умно, но что это значит?

Что дают интерфейсы?

Наследование моделирует семейство объектов с общим поведением. Интерфейс и абстрактный класс определяет «протокол» этого семейства, а наследники определяют конкретную реализацию. Разные виды предусловий можно спрятать за интерфейсом IPrecondition, разные виды стратегий сортировки – за ISorter, разные виды импортеров/экспортеров – за Importer/Exporter.

Наличие интерфейсов/абстрактных классов позволяет думать о задаче более абстрактно, не вдаваясь в подробности, какая конкретная разновидность используется. Абстрактность интерфейсов позволяет сосредоточиться на главном, игнорируя второстепенные детали. Отсюда вытекает распространенное убеждение, что интерфейс моделируют абстракцию.

четверг, 27 ноября 2014 г.

DI vs. DIP vs. IoC

Существует три схожих понятия, связанных передачей и управлением зависимостями, в каждом из которых есть слово “инверсия” (inversion) или “зависимость” (dependency):

  • IoC – Inversion of Control (Инверсия управления)
  • DI – Dependency Injection (Внедрение зависимостей)
  • DIP – Dependency Inversion Principle (Принцип инверсии зависимостей)

Подливает масло в огонь рассогласованность использования этих терминов. Так, например, контейнеры иногда называют DI-контейнерами, а иногда IoC-контейнерами. Большинство разработчиков не различает DI и DIP, хотя за каждой из этих аббревиатур скрываются разные понятия.

среда, 12 ноября 2014 г.

Когда предусловия не являются предусловиями

UPDATE: библиотека Code Contract знает о тонкостях реализации таких возможностей как async/await и блоков итераторов. Поэтому описанные ранее проблемы касаются лишь старых (legacy) предусловий, основанных на if-throw. Если вы зашли сюда первый раз, то просто не обращайте внимания на этот абзац!

Что такое предусловие? Это некоторое утверждение, которое должно быть истинным во время вызова метода, причем за его истинность отвечает вызывающая сторона. Предусловия включают в себя проверку аргументов или внутреннего состояния объекта, а его нарушение проявляется в генерации вызываемым кодом исключений ArgumentException для невалидных аргументов, и InvalidOperationException для вызова метода в невалидном состоянии объекта.

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

// class CustomStream
public Task<string> ReadString(int
position)
{
   
if (position < 0
)
       
throw new ArgumentOutOfRangeException("position"
);
   
if
(CanRead)
       
throw new InvalidOperationException("Stream is not readable"
);

   
return Task.FromResult("42");
}

среда, 5 ноября 2014 г.

О логировании исключений и Exception.ToString

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

Очень неприятно, когда тебе приходится разбираться с проблемой на боевом сервере в час ночи, когда все, что ты видишь в логе – загадочную строку “Exception has been thrown by the target of an invocation” или “The type initializer for ‘YourBestTypeInTheWorld’ threw an exception”. А все потому, что кто-то умудрился сохранять в лог не все исключение, а лишь его сообщение.

clip_image002

четверг, 30 октября 2014 г.

О книге “Writing High-Performance .NET Code”

Как-то давно не было рецензий умных книжек, так что пришло время это исправить. Недавно, уважаемый Sinix на rsdn.ru упомянул о книге, с любопытным названием “Writing High-Performance .NET Code”. Я вообще не собирался переключаться пока на литературу по .NET-у, но поскольку по работе мне нужно было пообщаться поближе с виндовыми счетчиками производительности (a.k.a. performance counters), а они были описаны в одной из глав этой книги, то меня как-то зацепило.

clip_image002

Ну, ок. Давайте поговорим о высокопроизводительном .NET коде. Что это такое и бывает ли вообще? Тут сказать сложно. Когда речь заходит о действительно высокой производительности, то практика показывает, что с управляемыми языками, несмотря на все заявления, добиться высокой производительности не всегда возможно. Мы можем создать эффективное управляемое приложение, но если наша цель – эффективно использовать каждый такт процессора, то неуправляемый код все равно будет впереди планеты всей. Достаточно вспомнить, что ядро виндофона ушло от управляемого кода на неуправлямый, да и Windows Runtime сложно назвать полностью «управляемой платформой».

вторник, 21 октября 2014 г.