Показаны сообщения с ярлыком Design. Показать все сообщения
Показаны сообщения с ярлыком Design. Показать все сообщения

пятница, 20 марта 2015 г.

О разработке ПО и книге Крега Лармана “Applying UML and Patterns”

DISCLAIMER: это моя типичная рецензия, в ней больше рассуждений на тему книги, чем информации о самой книге! Так что, не проходите мимо!

У стандартного процесса обучения есть интересная особенность. Как только мы решили узнать что-то новое, мы садимся за учебники, идем на курсы и получаем новые знания всеми доступными способами. Через время мы говорим себе «Фффатит!», забиваем на обучение и переходим к практике (на ранних этапах теория переплетается простыми практическими задачами, но они не оказывают существенного значения). После чего, мы начинаем применять наши новые знания на практике, и через время они практически полностью выветриваются из нашей славной головешки и их место занимает опыт.

Итак, что мы имеем? А имеем мы водопадную модель развития, когда на ранних этапах идет обучения, после которого начинается практика. И в чем проблема? А проблема здесь аналогична водопадной модели разработке ПО. Мы просто не в состоянии без должного опыта осознать все прелести сакральных знаний, которые нам пытаются вбить в голову на этапе обучения. У нас еще нет собственных набитых шишек, чтобы оценить эти советы по достоинству.

четверг, 26 февраля 2015 г.

О сложности

Фред Брукс в своем «Мифическом человеко-месяце» еще 30 лет назад описал пару понятий, которые я считаю ключевыми в проектировании. Это понятия случайной (accidental) и естественной (essential) сложности.

Разница между ними в том, что естественная сложность является частью самой задачи и от нее невозможно избавиться. Случайная сложность привносится в процессе решения и обусловлена ошибками проектирования, плохим выбором языка программирования или базы данных, неудачной декомпозицией системы и просто грязным кодом. Все эти иерархии наследования, принципы проектирования, cohesion & coupling, все это направлено на уменьшение случайной сложности. На то, чтобы обуздать естественную сложность задачи и сделать ее максимально очевидной.

Мне кажется, очень важно осознавать разницу между этими понятиями.

Сколько раз вы ловили себя на мысли, что совершенно не можете понять, что же делает некоторый код? Вы видите кучу блоков if-else, switch, foreach, перехват и логирование исключений. Все это хорошо. Но, какую же задачу этот код решает на самом деле? Затем вы начинаете распутывать этот клубок, добавляете комментарии, выделяете новые методы, переносите обработку исключений на более высокий уровень, и оказывается, что решается очень простая задача, которую можно описать парой предложений.

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

Шпаргалка по SOLID принципам

S – The Single Responsibility Principle

Название: Принцип единственной ответственности.

Определение: У класса/модуля должна быть лишь одна причина для изменения.

Смысл принципа: Борьба со сложностью, важность которой резко возрастает при развитии логики приложения.

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

Типовые примеры нарушения: 1) смешивание логики и инфраструктуры: бизнес-логика смешана с представлением, слоем персистентности, находится внутри WCF или windows-сервисов и т.п. 2) класс/модуль решает задачи разных уровней абстракции: вычисляет CRC и отправляет уведомления по электронной почте; разбирает json-объект и анализирует его содержимое и т.п.

Anti-SRP – Принцип размытой ответственности. Чрезмерная любовь к SRP ведет к обилию мелких классов/методов и размазыванию логики между ними.

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

О принципах проектирования

Цикл статей о SOLID принципах

--------------------------------------------------

Для чего выдумывать все эти паттерны проектирования, принципы и методики? Разве не было бы проще обойтись без всего этого, а просто научить разработчиков хорошему дизайну? Или почему бы не формализовать этот процесс и ввести четкие количественные метрики, которые бы говорили, что одно решение однозначно лучше другого?

«Правильный дизайн» - это святой Грааль молодых разработчиков и молодых менеджеров. И те, и другие мечтают найти ответ на главный вопрос жизни, вселенной и всего такого разработки ПО – как добиться качественного дизайна, в сжатые сроки и с минимумом усилий.

Со временем и молодой разработчик, и молодой менеджер придут к пониманию того, что это невозможно. Невозможно найти идеальный абстрактный дизайн, поскольку слова «идеальный» и «абстрактный» противоречат друг другу. Дизайн – это постоянный поиск компромисса между противоречивыми требованиями: производительностью и читабельностью, простотой и расширяемостью, тестируемостью и цельностью решения.

четверг, 25 сентября 2014 г.

The Dependency Inversion Principle

Цикл статей о SOLID принципах

--------------------------------------------------

clip_image001

Принцип инверсии зависимости (Dependency Inversion Principle – DIP):

  • Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те и другие должны зависеть от абстракций.
  • Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.

Роберт Мартин «Принципы, паттерны и методики гибкой разработки» ([Martin2006]).

Принцип инверсии зависимостей – один из самых известных сегодня принципов проектирования, который лежит в основе популярных техник внедрения зависимостей (Dependency Injection). Однако, если посмотреть лишь на его название и описание, то будет довольно сложно понять, что же он означает. Поэтому, если спросить простых обывателей о том, что означает этот принцип, то они начнут что-то говорить о пользе интерфейсов и абстракций, и, вообще, будут путаться в показаниях.

четверг, 18 сентября 2014 г.

LSP Часть 2. О сложностях наследования

Цикл статей о SOLID принципах

--------------------------------------------------

Бытует мнение, что генерация исключений InvalidOperationException или NotSupportedException методами наследника означает нарушение этим классом принципа замещения Лисков. И хотя в некоторых случаях это действительно так, судить так однозначно нельзя.

Является ли нарушением LSP, что ImmutableList<T> и ReadOnlyCollection<T> реализует IList<T>, поскольку попытка добавления элемента в такую коллекцию приводит к генерации NotSupportedException? Может показаться, что нарушают, однако в «контракте» интерфейса IList<T> четко сказано, что метод Add будет добавлять элемент, только в случае выполнения «предусловия» – коллекция должна быть изменяемой! Аналогично дела обстоят с потоками ввода вывода, методы Read/Write которых могут генерировать исключения, если свойствами CanRead/CanWrite возвращают false. Во всех этих случаях мы можем говорить о неудачном дизайне, но не можем говорить о нарушении принципа подстановки Лисков!

вторник, 2 сентября 2014 г.

Open/Closed Principle. ФП vs. ООП

Цикл статей о SOLID принципах

--------------------------------------------------

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

Давайте рассмотрим вопрос расширяемости в рамках семейства типов более подробно.

Большинство примеров, показывающих пользу «открытости» модулей обычно сводятся к демонстрации мощи полиморфизма над старым структурным подходом: «Смотрите, как здорово, когда мы избавляемся от конструкции switch в функции Draw и переносим всю логику в класс Shape и его наследники! Теперь наше решение является расширяемым и соответствует принципу Открыт/Закрыт, поскольку мы легко можем к квадрату и треугольнику добавить еще ромб с кругом!».

Да, действительно, добавить новый класс в существующую иерархию довольно легко, но что если мы хотим добавить в существующую иерархию новую операцию, например, метод GetArea в иерархию Shapes?

вторник, 26 августа 2014 г.

Open/Closed Principle

Цикл статей о SOLID принципах

--------------------------------------------------

Принцип открыт/закрыт (Open-Closed Principle, OCP): Программные сущности (классы, модули, функции и т.п.) должны быть открытыми для расширения, но закрытыми для модификации.
Роберт Мартин. Принципы, паттерны и практики гибкой разработки, 2010

Из всех «цельных» (SOLID) принципов, принцип Открыт/Закрыт является самым неоднозначным. Его неоднозначность кроется в противоречивости его определения (как что-то может быть одновременно «открытым» и «закрытым»?), а подкрепляется неоднозначными и разнообразными формулировками этого принципа в разных источниках. Не удивительно, что даже такие монстры, типа Эрика Липперта или Джона Скита относятся к этому принципу неоднозначно и признаются в его непонимании.

среда, 13 августа 2014 г.

Single Responsibility Principle

Цикл статей о SOLID принципах

--------------------------------------------------

Принцип единственной обязанности (Single-Responsibility Principle, SRP): У класса должна быть только одна причина для изменения.
Роберт Мартин. Принципы, паттерны и практики гибкой разработки

Существует ряд патологических случаев нарушения принципа единственной обязанности, которые будут очевидны сегодня практически любому. Классы бизнес-логики, которые знают о пользовательском интерфейсе или о базе данных; класс windows-сервиса c кучей бизнес-логики; статические утилитные классы, изменяющие глобальное состояние и т.п.

При этом нарушение SRP бывают как на уровне классов/модулей, так и на уровне подсистем и приложений. Классическим примером из моей практики являются два вопиющих нарушения SRP на уровне приложений: использование Windows Forms приложения в качестве WCF сервиса, и необходимость взаимодействия виндового сервиса с пользователем через Message Box-ы.

вторник, 5 августа 2014 г.

Interface Segregation Principle

Цикл статей о SOLID принципах

--------------------------------------------------

Вы никогда не ловили себя на мысли, что Принцип разделения интерфейса (ISP, Interface Segregation Principle) вам не вполне понятен или, что он является лишь разновидностью принципа единой ответственности (SRP, Single Responsibility Principle)? До недавнего времени у меня было подобное отношение, но оно несколько изменилось, после того, как я посмотрел на него с другой точки зрения.

Причина некоторого недопонимания принципа ISP, как мне кажется, кроется вот в чем. Во-первых, ISP отличается от других принципов SOLID тем, с какой стороны он применяется (об этом позднее), а во-вторых, у него далеко не самое лучшее определение.

Давайте начнем с определения. Вот формулировка принципа ISP из любимой мною книги Боба Мартина «Принципы, паттерны и методики гибкой разработки»:

"Этот принцип относится к недостаткам "жирных" интерфейсов. Говорят, что класс имеет жирный интерфейс, если функции этого интерфейса недостаточно сцепленные (not cohesive). Иными словами, интерфейс класса можно разбить на группу методов. Каждая группа предназначена для обслуживания разных клиентов. Одним клиентам нужна одна группа методов, другим – другая."

понедельник, 14 июля 2014 г.

Книги по дизайну и ООП

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

Невозможно стать хорошим архитектором прочитав несколько книг, поскольку нужно четко понимать, как конкретное теоретическое решение отражается в реальных системах. Я никак не могу помочь вам с практикой, но могу посоветовать хорошую литературу в области ООП/ООД/ФП.

воскресенье, 8 июня 2014 г.

Is TDD Dead. Часть 5

В то время, как в Виларибо спорят жив ли TDD или мертв, в Вилабаджо думают, а стоит ли компилировать код перед коммитом.

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

Is TDD Dead. Part V on Youtube. В целом, получилось более затянуто чем обычно (ведь выступление длилось в двое дольше), но, как всегда, весьма любопытно.

Проблема обсуждения вопросов дизайна

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

Обсуждение вопросов дизайна является довольно сложным вопросом и у этого есть как минимум несколько причин. Во-первых, дизайн любой системы постоянно развивается, при этом результат зависит не только от способностей членов команды, но и от исторического контекста (злосчастное, «исторически сложилось»). Это значит, что мы не можем судить о существующем дизайне в вакууме, нам нужно еще и понимать, как мы к нему пришли и какие проблемы считали наиболее приоритетными. Во-вторых, не существует достаточно объективной меры качества дизайна, которая бы четко доказывала, что одно решение действительно лучше другого. В-третьих, при обсуждении вопросов дизайна автор статьи или книги сталкивается с вопросом выбора размера и сложности примера. С одной стороны, нет смысла рассматривать продвинутые техники проектирования на примитивных примерах, ведь примитивные задачи можно решить любым способом. С другой стороны, автор не может давать слишком сложные примеры, поскольку 90% читателей просто не захотят тратить свое время и с ними разбираться.

среда, 7 мая 2014 г.

Паттерн Итератор

Пред. паттерн: Паттерн Посредник

Назначение: представляет доступ ко всем элементам составного объекта, не раскрывая его внутреннего представления.

Подробнее – Iterator on Wiki

Мотивация

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

четверг, 10 апреля 2014 г.

Об автоматизированном тестировании

и книге Стива Фримана "Growing Object-Oriented Software Guided by Tests"

DISCLAIMER: как и многие ревью, в этот раз будет гораздо больше обсуждений темы дизайна и автоматического тестирования, чем непосредственно рецензии книги. Так что, не проходите мимо!

Содержание

В мире разработки ПО нет более неоднозначной темы, чем тестирование. Нет, я не о тестировании ПО в целом, тут все ясно, оно нужно, без него никак. А вот отношение к автоматическим тестам и особенно к юнит-тестам весьма неоднозначное.

четверг, 20 марта 2014 г.

Паттерн Посредник

Пред. запись: RAII в C#. Локальный Метод Шаблона vs. IDisposable

Назначение: Определяет объект, инкапсулирующий способ взаимодействия множества объектов.

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

Описание: Посредник обеспечивает слабую связанность (low coupling) системы, избавляя объекты от необходимости явно ссылаться друг на друга, позволяя тем самым независимо изменять их и взаимодействия между ними.

Подробнее – Mediator on Wiki

Мотивация

В качестве примера, давайте отойдем от темы анализа паттернов проектирования и посмотрим на пример, приведенный Робертом Мартином в своей статье "Принцип инверсии зависимостей" (Robert Martin – Dependency Inversion Principle) и в своей книге "Принципы, паттерны и методики гибкой разработки на языке C#".

вторник, 4 марта 2014 г.

Паттерн Шаблонный Метод

Пред. запись: Паттерн Стратегия
След. запись: RAII в C#. Локальный Метод Шаблона vs. IDisposable

Назначение: Шаблонный Метод определяет основу алгоритма и позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом.

Другими словами: шаблонный метод – это каркас, в который наследники могут подставить свои реализации.

Подробнее – Template Method Pattern on Wiki

Общие сведения

На заре своего становления, наследование считалось ключевой концепцией ООП для расширения и повторного использования кода. Однако со временем, многим разработчикам стало очевидно, что наследование не такой уж и простой инструмент, использование которого приводит к сильной связности (tight coupling) между базовым классом и его наследником. Эта связность приводит к сложности понимания иерархии классов, а отсутствие формализации отношений между базовым классом и наследниками не позволяет четко понять, как именно разделены обязанности между классами Base и Derived, что можно делать наследнику, а что – нет.

среда, 26 февраля 2014 г.

Паттерн Стратегия

Пред. запись: GoF паттерны на платформе .NET
След. запись: Паттерн Шаблонный Метод

Назначение: определяет семейство алгоритмов, инкапсулирует каждый из них и делает их взаимозаменяемыми. Стратегия позволяет изменять алгоритмы независимо от клиентов, которые ими пользуются.

Другими словами: стратегия инкапсулирует некоторое поведение с возможностью его подмены.

Подробнее – Strategy Pattern on Wiki

Мотивация

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

пятница, 21 февраля 2014 г.

GoF паттерны на платформе .NET

След. запись: Паттерн Стратегия

Посты серии:

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

Так, когда в начале 90-х на арене программного мира появились паттерны проектирования, многие начали мечтать о том, что благодаря им даже бизнес-пользователи и 1С программисты смогут собирать приложение из готовых кирпичиков. Довольно быстро стало ясно, что этого не случится и начали искать другие подходы, включая программирование через конфигурацию, пламенно воспетую Хантом и Томасом в их «Программисте-прагматике». Затем появились IoC (или DI) контейнеры и начался новый этап создания «слабосвязанных приложений», разбираться с которыми стало еще сложнее, чем прежде благодаря замене «физической» (прямой) связи между компонентами на «логическую» (косвенную).

четверг, 9 января 2014 г.

О пользе выбора

Мы очень часто сталкиваемся с дилеммой при разработке проекта или одной из его фич: что выбрать, подход А или подход Б? Что лучше, использовать WCF или веб-сервисы; Entity Framework или NHibernate; читать конфигурацию из файла конфигурации или из базы данных?

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

Поскольку иногда бывает сложным убедить собеседника в своей правоте мы можем прийти к заключению, что нужно найти компромиссное решение. Здесь мы ступаем на очень тонкий лед. Может показаться, что лучшим решением этой дилеммы будет создание гибкого решения, которое будет удовлетворять обоим подходам одновременно. Очевидно, что в этом случае мы не просто сможем переключаться от одного решения к другому: мы поддерживаем два решения сразу! Разве не прекрасно?