06 мая 2014

О зависимостях

Чем мне не нравится зависимость контрола от контрола.

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

Наша задача - максимально облегчить работу с компонентами, чтобы с ними можно было работать по отдельности, чтобы можно было легко подменять реализации компонентов на другой стороне зависимости. Мы используем разделение обязанностей, чтобы упростить работу. Вот, например, MVC - это разделение обязанностей на model, view и controller. Ведь раньше то ничего не мешало напихать все это в одно место. Но разделение обязанностей облегчает работу, делит код на части, определяет взаимодействие между частями. Чем меньше код тем проще с ним работать, меньше ошибок допускается, легче понять. Тоже самое происходит и с зависимостями. Зависимость - это один из аспектов ответственности компонента. В случае с контролами, контрол может отвечать за генерацию представления (HTML), binding к данным, обработку взаимодействия с пользователем, валидацию. Если мы заставим его отвечать еще и за взаимодействие - контрол проще не станет, и работать с ним проще не будет.

Это Inversion of Control - мы конечно можем управлять зависимостью изнутри компонента, но выделение границ между зависимостями помогает нам видеть эти границы, их сложнее случайно нарушить, меньше соблазнов добавить костылей к коду - нужно задекларировать костыль в интерфейсе. Это особенно важно когда мы работаем с JavaScript - ведь в нем намного меньше средств ограничить возможные методы использования объектов.

Выход из этого положения – это возложить ответственность за взаимодействие на того, кто создает взаимодействующие компоненты. В случае с контролами – на view, их использующую. Как это сделать – договориться что происходит в случае когда сообщение от одного компонента должно попасть к другому. Например опубликовать событие и генерировать его вместо прямого вызова метода зависимого компонента, обрабатывая событие на уровне view. В случае с JavaScript – использовать publish-subscribe pattern.