SlideShare a Scribd company logo
О принципах 
проектирования 
Сергей Тепляков
Обо мне 
• Microsoft C# MVP 2011-2014 
• MSFT Employee 2014- (VS Team) 
• Blogger: SergeyTeplyakov.blogspot.com 
• Контакты 
• Sergey.Teplyakov [sobak] gmail.com 
• @STeplyakov
О чем будем говорить? 
• О принципах проектирования в целом 
• О SOLID принципах
Нужны ли нам принципы проектирования?
Дизайн – штука сложная!
Поиск серебряной пули 
• Ответ на вопрос жизни вселенной и всего такого?
Мы хотим использовать опыт и знания 
повторно!
Классические подходы 
• Low coupling 
• High cohesion 
• Design by Contract
SOLID принципы 
• S – Single Responsibility Principle 
• O – Open-Closed Principle 
• L – Liskov Substitution Principle 
• I – Interface Segregation Principle 
• D – Dependency Inversion Principle
Опасности принципов 
• Что «сильнее» композиция или 
наследование? 
• Остерегайтесь культа карго
В чем проблема с текущим описанием? 
• Принципы слишком неформальны 
• Берут свое начало в 90-х (С++) 
• Не ясно, когда им следовать, а когда - 
нет
Как следовать этим принципам? 
Принципы существуют для того, чтобы помогать в 
устранении дурных запахов в дизайне. Это не духи, 
которыми надо обильно поливать всю систему. 
Чрезмерная приверженность принципам ведет к пороку 
ненужной сложности.
Single Responsibility Principle 
• Исходное определение: 
У класса должна быть только одна причина для изменения 
• Смысл принципа SRP: 
Борьба со сложностью 
• SRP violation means low cohesion! 
http://bit.ly/SingleResponsibilityPrinciple
Любой класс из реального мира будет 
нарушать SRP
Типичные примеры нарушения SRP
Смешивание логики и инфраструктуры 
• Windows сервис ходит в базу 
• WCF-сервис сам содержит логику обработки 
запросов 
• Azure Role содержит логику по 
перекладыванию данных из одного места в 
другое. 
• Смешивание логики и «сохраняемости» 
(persistence)
Смешивание логики и представления
Выделяйте каждому сложному аспекту 
системы свой класс/модуль
Я хочу иметь возможность сосредоточиться на 
сложных аспектах системы по отдельности, 
поэтому когда мне становится сложно это 
делать, я начинаю разбивать классы и выделять 
новые.
Дизайн – это эволюционный процесс
Актуальность SRP возрастает вместе с 
увеличением сложности!
Пример увеличения сложности: добавление 
предусловий
Интерфейс ContextActionBase 
public abstract class ContextActionBase 
{ 
public abstract void Execute(); 
public abstract bool IsAvailable(); 
public abstract string Text { get; } 
}
SOLID Principles in the real world
Эволюция дизайна
SRP – это способ поиска скрытых абстракций, 
достаточно сложных, чтобы им отвели 
отдельную именованную сущность и спрятали в 
их недрах все детали.
Open-Closed Principle 
Классы, модули, функции и т.п.) должны быть 
открытыми для расширения, но закрытыми для 
модификации 
http://bit.ly/OpenClosedPrinciple
Как вы понимаете OCP?
Объяснение Боба Мартина 
• Они открыты для расширения. Это означает, что поведение модуля можно 
расширить. Когда требования к приложению изменяются, мы добавляем в 
модуль новое поведение, отвечающее изменившимся требованиям. Иными 
словами, мы можем изменить состав функций модуля. 
• Они закрыты для модификации. Расширение поведения модуля не 
сопряжено с изменениями в исходном или двоичном коде модуля. Двоичное 
исполняемое представление модуля, будь то компонуемая библиотека, DLL 
или EXE-файл, остается неизменным (выделено мною).
Нарушает ли фабрика OCP? 
abstract class Importer 
{ 
public abstract void ImportData(); 
} 
static class ImporterFactory 
{ 
public static Importer Create(string fileName) 
{ 
var extension = Path.GetExtension(fileName); 
switch (extension) 
{ 
case "json": 
return new JsonImporter(); 
case "xls": 
case "xlsx": 
return new XlsImporter(); 
default: 
throw new InvalidOperationException("Extension is not supported"); 
} 
} 
}
Принцип единственного выбора 
Всякий раз, когда система программного обеспечения 
должна поддерживать множество альтернатив, их 
полный список должен быть известен только одному 
модулю системы. 
Бербран Мейер
OCP != Расширяемость
Определение от Бертрана Мейера 
• Модуль называют открытым, если он еще доступен для расширения. 
Например, имеется возможность расширить множество операций в нем или 
добавить поля к его структурам данных. 
• Модуль называют закрытым, если он доступен для использования другими 
модулями. Это означает, что модуль (его интерфейс – с точки зрения скрытия 
информации) уже имеет строго определенное окончательное описание. На 
уровне реализации закрытое состояние модуля означает, что модуль можно 
компилировать, сохранять в библиотеке и делать его доступным для 
использования другими модулями (его клиентами).
Open-Closed Principle 
• Что такое OCP? Это фиксация интерфейса класса/модуля, и 
возможность изменения или подмены реализации/поведения. 
• Цели OCP: борьба со сложностью и ограничение изменений 
минимальным числом модулей. 
• Как мы реализуем OCP? С помощью инкапсуляции, которая позволяет 
изменять реализацию без изменения интерфейса и с помощью 
наследования, что позволяет заменить реализацию, которая не 
затронет существующих клиентов базового класса.
Типичный пример нарушения 
расширяемости (OCP) 
public static int Count<TSource>(this IEnumerable<TSource> source) 
{ 
var collectionoft = source as ICollection<TSource>; 
if (collectionoft != null) return collectionoft.Count; 
var collection = source as ICollection; 
if (collection != null) return collection.Count; 
int count = 0; 
using (IEnumerator<TSource> e = source.GetEnumerator()) 
{ 
while (e.MoveNext()) count++; 
} 
return count; 
}
Расширяемость: OOP vs. FP 
• В ООП: легко добавлять новый тип, сложно – новую операцию 
• В ФП: легко добавлять новую операцию, сложно – новый тип 
Expression Problem!
Расширяемость в ООП
Иногда мы хотим вынести логику за пределы 
иерархии! 
Решение: Посетитель!
Пример
public interface IValidationResultVisitor 
{ 
void Visit(NoErrorValidationResult vr); 
void Visit(ContractErrorValidationResult vr); 
void Visit(ContractWarningValidationResult vr); 
void Visit(CustomWarningValidationResult vr); 
} 
public abstract class ValidationResult 
{ 
private ICSharpStatement _statement; 
protected ValidationResult(ICSharpStatement statement) 
{ 
Contract.Requires(statement != null); 
_statement = statement; 
} 
public abstract void Accept(IValidationResultVisitor visitor); 
}
class IsIssueFixableVisitor : IValidationResultVisitor 
{ 
public bool IsIssueFixable { get; private set; } 
public void Visit(NoErrorValidationResult vr) 
{ 
IsIssueFixable = false; 
} 
public void Visit(ContractErrorValidationResult vr) 
{ 
IsIssueFixable = 
vr.Error == MalformedContractError.VoidReturnMethodCall; 
} 
public void Visit(ContractWarningValidationResult vr) 
{ 
IsIssueFixable = 
vr.Warning == MalformedContractWarning.NonVoidReturnMethodCall; 
} 
public void Visit(CustomWarningValidationResult vr) 
{ 
IsIssueFixable = false; 
} 
}
ФП подход: сопоставление с образцом 
public T Match<T>( 
Func<CodeContractErrorValidationResult, T> errorMatch, 
Func<CodeContractWarningValidationResult, T> warningMatch, 
Func<ValidationResult, T> defaultMatch) 
{ 
var errorResult = this as CodeContractErrorValidationResult; 
if (errorResult != null) 
return errorMatch(errorResult); 
var warningResult = this as CodeContractWarningValidationResult; 
if (warningResult != null) 
return warningMatch(warningResult); 
return defaultMatch(this); 
}
Пример использования 
ValidationResult vr = GetValidationResult(); 
bool isFixable = vr.Match( 
error => error.Error == 
MalformedContractError.VoidReturnMethodCall, 
warning => warning.Warning == 
MalformedContractWarning.NonVoidReturnMethodCall, 
@default => false);
Как пользуюсь принципами? 
• Принципы – не самоцель! 
• Дизайн постоянно эволюционирует. Валидируйте его согласно этим 
принципам на каждой итерации.
Цикл постов о SOLID-принципах 
• http://bit.ly/SingleResponsibilityPrinciple 
• http://bit.ly/OpenClosedPrinciple 
• http://bit.ly/LiskovSubstitutionPrinciple 
• http://bit.ly/InterfaceSegregationPrinciple 
• http://bit.ly/DependencyInversionPrinciple
Чего почитать по теме 
• О культе карго в программировании 
sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html 
• Критика книги Боба Мартина «Принципы, паттерны и методики гибкой 
разработки на языке C#» 
sergeyteplyakov.blogspot.com/2013/12/about-agile-principles-patterns-and.html 
• Цикл постов об управлении зависимостями 
http://sergeyteplyakov.blogspot.com/2013/10/articles.html#dependency_manage 
ment 
• Лучшая книга по ООП эвар! – Бертран Мейер «Объектно-ориентированное 
конструирование программных систем» 
http://sergeyteplyakov.blogspot.com/2012/03/blog-post_19.html

More Related Content

PPT
Шаблоны разработки ПО. Рефакторинг
PPT
Шаблоны разработки ПО. Часть 1. Введние
PPT
Парадигма объектно-ориентированного программирования.
PPT
Java. Инкапсуляция.
DOC
Конспект лекций по курсу "Шаблоны разработки ПО"
PPTX
GRASP – паттерны Объектно-Ориентированного Проектирования
PPT
Принципы SOLID
PPTX
Как писать красивый код или основы SOLID
Шаблоны разработки ПО. Рефакторинг
Шаблоны разработки ПО. Часть 1. Введние
Парадигма объектно-ориентированного программирования.
Java. Инкапсуляция.
Конспект лекций по курсу "Шаблоны разработки ПО"
GRASP – паттерны Объектно-Ориентированного Проектирования
Принципы SOLID
Как писать красивый код или основы SOLID

What's hot (20)

PPTX
Большие проекты, архитектура и фреймворки.
PPTX
Принципы объектно-ориентированного дизайна
PPT
Шаблоны разработки ПО. Шаблоны GRASP
PPT
Step 3.1
PPTX
Составные части объектного подхода
PDF
Шаблоны проектирования GoF
PDF
SOLID & GRASP
ODP
Refactoring
PPTX
Java core-lect6-part3-annotation.ppt
PPT
Шаблоны разработки ПО. Часть 2. ООП и UML
PPTX
Java Core. Lecture# 2. Classes & objects.
PPT
Msu.Center.Lectures.J03 Oop And Uml
PPT
Java. Lecture 03. OOP and UML
PDF
JUnit, дай пять!
PPTX
Наследование и полиморфизм
PDF
C++ осень 2013 лекция 5
Большие проекты, архитектура и фреймворки.
Принципы объектно-ориентированного дизайна
Шаблоны разработки ПО. Шаблоны GRASP
Step 3.1
Составные части объектного подхода
Шаблоны проектирования GoF
SOLID & GRASP
Refactoring
Java core-lect6-part3-annotation.ppt
Шаблоны разработки ПО. Часть 2. ООП и UML
Java Core. Lecture# 2. Classes & objects.
Msu.Center.Lectures.J03 Oop And Uml
Java. Lecture 03. OOP and UML
JUnit, дай пять!
Наследование и полиморфизм
C++ осень 2013 лекция 5
Ad

Viewers also liked (6)

PPTX
Solid code via tdd
PPTX
Android architecture
PPT
Android Architecture
PPTX
Сергей Калинец "Не SQL-ом единым..."
PPTX
android architecture
Solid code via tdd
Android architecture
Android Architecture
Сергей Калинец "Не SQL-ом единым..."
android architecture
Ad

Similar to SOLID Principles in the real world (20)

PPT
Design Principles
PPTX
Yuri Trukhin - Software developement best practices
PPTX
SOLID
PDF
Лекция 4. Принципы SOLID
PDF
ук 03.001.02 2011
PPTX
SOLID. Принципы объектно ориентированного дизайна
PPTX
07 Архитектура информационных систем. Принципы GRASP
PPT
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
PPT
Design Rules And Principles
PPTX
SOLID – принципы объектно-ориентированного дизайна
PPTX
Coding like a sex
PPTX
Design by Contract
KEY
Объектно ориентированный дизайн
PDF
Принципы программирования [NoBugs WTF PRO уровень].pdf
PPTX
AOP and Design Patterns (GoF)
PPTX
Aspect Oriented Programming and Design Patterns
PPTX
Фофанов Илья - Лучшие практики проектирования и реализации API на C#
PDF
Общие темы. Тема 02.
PPTX
Андрей Кирпичев "Гибкая модульность инструментами АОП"
PPTX
разработка бизнес приложений (7)
Design Principles
Yuri Trukhin - Software developement best practices
SOLID
Лекция 4. Принципы SOLID
ук 03.001.02 2011
SOLID. Принципы объектно ориентированного дизайна
07 Архитектура информационных систем. Принципы GRASP
Евгений Кривошеев: Фундаментальные правила и принципы проектирования ПО
Design Rules And Principles
SOLID – принципы объектно-ориентированного дизайна
Coding like a sex
Design by Contract
Объектно ориентированный дизайн
Принципы программирования [NoBugs WTF PRO уровень].pdf
AOP and Design Patterns (GoF)
Aspect Oriented Programming and Design Patterns
Фофанов Илья - Лучшие практики проектирования и реализации API на C#
Общие темы. Тема 02.
Андрей Кирпичев "Гибкая модульность инструментами АОП"
разработка бизнес приложений (7)

More from EPAM (9)

PDF
JavaScript. Code Quality.
PDF
Continuous integration for JavaScript projects
PDF
Visualization of Big Data in Web Apps
PDF
Object Oriented Concepts in Real Projects
PDF
Modern web applications infrastructure
PPTX
Reactive Extensions: classic Observer in .NET
PDF
Future of the Future of E-Commerce
PDF
Bootify Yyour App from Zero to Hero
PDF
Responsive Web in Brief
JavaScript. Code Quality.
Continuous integration for JavaScript projects
Visualization of Big Data in Web Apps
Object Oriented Concepts in Real Projects
Modern web applications infrastructure
Reactive Extensions: classic Observer in .NET
Future of the Future of E-Commerce
Bootify Yyour App from Zero to Hero
Responsive Web in Brief

SOLID Principles in the real world

  • 2. Обо мне • Microsoft C# MVP 2011-2014 • MSFT Employee 2014- (VS Team) • Blogger: SergeyTeplyakov.blogspot.com • Контакты • Sergey.Teplyakov [sobak] gmail.com • @STeplyakov
  • 3. О чем будем говорить? • О принципах проектирования в целом • О SOLID принципах
  • 4. Нужны ли нам принципы проектирования?
  • 5. Дизайн – штука сложная!
  • 6. Поиск серебряной пули • Ответ на вопрос жизни вселенной и всего такого?
  • 7. Мы хотим использовать опыт и знания повторно!
  • 8. Классические подходы • Low coupling • High cohesion • Design by Contract
  • 9. SOLID принципы • S – Single Responsibility Principle • O – Open-Closed Principle • L – Liskov Substitution Principle • I – Interface Segregation Principle • D – Dependency Inversion Principle
  • 10. Опасности принципов • Что «сильнее» композиция или наследование? • Остерегайтесь культа карго
  • 11. В чем проблема с текущим описанием? • Принципы слишком неформальны • Берут свое начало в 90-х (С++) • Не ясно, когда им следовать, а когда - нет
  • 12. Как следовать этим принципам? Принципы существуют для того, чтобы помогать в устранении дурных запахов в дизайне. Это не духи, которыми надо обильно поливать всю систему. Чрезмерная приверженность принципам ведет к пороку ненужной сложности.
  • 13. Single Responsibility Principle • Исходное определение: У класса должна быть только одна причина для изменения • Смысл принципа SRP: Борьба со сложностью • SRP violation means low cohesion! http://bit.ly/SingleResponsibilityPrinciple
  • 14. Любой класс из реального мира будет нарушать SRP
  • 16. Смешивание логики и инфраструктуры • Windows сервис ходит в базу • WCF-сервис сам содержит логику обработки запросов • Azure Role содержит логику по перекладыванию данных из одного места в другое. • Смешивание логики и «сохраняемости» (persistence)
  • 17. Смешивание логики и представления
  • 18. Выделяйте каждому сложному аспекту системы свой класс/модуль
  • 19. Я хочу иметь возможность сосредоточиться на сложных аспектах системы по отдельности, поэтому когда мне становится сложно это делать, я начинаю разбивать классы и выделять новые.
  • 20. Дизайн – это эволюционный процесс
  • 21. Актуальность SRP возрастает вместе с увеличением сложности!
  • 22. Пример увеличения сложности: добавление предусловий
  • 23. Интерфейс ContextActionBase public abstract class ContextActionBase { public abstract void Execute(); public abstract bool IsAvailable(); public abstract string Text { get; } }
  • 26. SRP – это способ поиска скрытых абстракций, достаточно сложных, чтобы им отвели отдельную именованную сущность и спрятали в их недрах все детали.
  • 27. Open-Closed Principle Классы, модули, функции и т.п.) должны быть открытыми для расширения, но закрытыми для модификации http://bit.ly/OpenClosedPrinciple
  • 29. Объяснение Боба Мартина • Они открыты для расширения. Это означает, что поведение модуля можно расширить. Когда требования к приложению изменяются, мы добавляем в модуль новое поведение, отвечающее изменившимся требованиям. Иными словами, мы можем изменить состав функций модуля. • Они закрыты для модификации. Расширение поведения модуля не сопряжено с изменениями в исходном или двоичном коде модуля. Двоичное исполняемое представление модуля, будь то компонуемая библиотека, DLL или EXE-файл, остается неизменным (выделено мною).
  • 30. Нарушает ли фабрика OCP? abstract class Importer { public abstract void ImportData(); } static class ImporterFactory { public static Importer Create(string fileName) { var extension = Path.GetExtension(fileName); switch (extension) { case "json": return new JsonImporter(); case "xls": case "xlsx": return new XlsImporter(); default: throw new InvalidOperationException("Extension is not supported"); } } }
  • 31. Принцип единственного выбора Всякий раз, когда система программного обеспечения должна поддерживать множество альтернатив, их полный список должен быть известен только одному модулю системы. Бербран Мейер
  • 33. Определение от Бертрана Мейера • Модуль называют открытым, если он еще доступен для расширения. Например, имеется возможность расширить множество операций в нем или добавить поля к его структурам данных. • Модуль называют закрытым, если он доступен для использования другими модулями. Это означает, что модуль (его интерфейс – с точки зрения скрытия информации) уже имеет строго определенное окончательное описание. На уровне реализации закрытое состояние модуля означает, что модуль можно компилировать, сохранять в библиотеке и делать его доступным для использования другими модулями (его клиентами).
  • 34. Open-Closed Principle • Что такое OCP? Это фиксация интерфейса класса/модуля, и возможность изменения или подмены реализации/поведения. • Цели OCP: борьба со сложностью и ограничение изменений минимальным числом модулей. • Как мы реализуем OCP? С помощью инкапсуляции, которая позволяет изменять реализацию без изменения интерфейса и с помощью наследования, что позволяет заменить реализацию, которая не затронет существующих клиентов базового класса.
  • 35. Типичный пример нарушения расширяемости (OCP) public static int Count<TSource>(this IEnumerable<TSource> source) { var collectionoft = source as ICollection<TSource>; if (collectionoft != null) return collectionoft.Count; var collection = source as ICollection; if (collection != null) return collection.Count; int count = 0; using (IEnumerator<TSource> e = source.GetEnumerator()) { while (e.MoveNext()) count++; } return count; }
  • 36. Расширяемость: OOP vs. FP • В ООП: легко добавлять новый тип, сложно – новую операцию • В ФП: легко добавлять новую операцию, сложно – новый тип Expression Problem!
  • 38. Иногда мы хотим вынести логику за пределы иерархии! Решение: Посетитель!
  • 40. public interface IValidationResultVisitor { void Visit(NoErrorValidationResult vr); void Visit(ContractErrorValidationResult vr); void Visit(ContractWarningValidationResult vr); void Visit(CustomWarningValidationResult vr); } public abstract class ValidationResult { private ICSharpStatement _statement; protected ValidationResult(ICSharpStatement statement) { Contract.Requires(statement != null); _statement = statement; } public abstract void Accept(IValidationResultVisitor visitor); }
  • 41. class IsIssueFixableVisitor : IValidationResultVisitor { public bool IsIssueFixable { get; private set; } public void Visit(NoErrorValidationResult vr) { IsIssueFixable = false; } public void Visit(ContractErrorValidationResult vr) { IsIssueFixable = vr.Error == MalformedContractError.VoidReturnMethodCall; } public void Visit(ContractWarningValidationResult vr) { IsIssueFixable = vr.Warning == MalformedContractWarning.NonVoidReturnMethodCall; } public void Visit(CustomWarningValidationResult vr) { IsIssueFixable = false; } }
  • 42. ФП подход: сопоставление с образцом public T Match<T>( Func<CodeContractErrorValidationResult, T> errorMatch, Func<CodeContractWarningValidationResult, T> warningMatch, Func<ValidationResult, T> defaultMatch) { var errorResult = this as CodeContractErrorValidationResult; if (errorResult != null) return errorMatch(errorResult); var warningResult = this as CodeContractWarningValidationResult; if (warningResult != null) return warningMatch(warningResult); return defaultMatch(this); }
  • 43. Пример использования ValidationResult vr = GetValidationResult(); bool isFixable = vr.Match( error => error.Error == MalformedContractError.VoidReturnMethodCall, warning => warning.Warning == MalformedContractWarning.NonVoidReturnMethodCall, @default => false);
  • 44. Как пользуюсь принципами? • Принципы – не самоцель! • Дизайн постоянно эволюционирует. Валидируйте его согласно этим принципам на каждой итерации.
  • 45. Цикл постов о SOLID-принципах • http://bit.ly/SingleResponsibilityPrinciple • http://bit.ly/OpenClosedPrinciple • http://bit.ly/LiskovSubstitutionPrinciple • http://bit.ly/InterfaceSegregationPrinciple • http://bit.ly/DependencyInversionPrinciple
  • 46. Чего почитать по теме • О культе карго в программировании sergeyteplyakov.blogspot.com/2013/09/blog-post_24.html • Критика книги Боба Мартина «Принципы, паттерны и методики гибкой разработки на языке C#» sergeyteplyakov.blogspot.com/2013/12/about-agile-principles-patterns-and.html • Цикл постов об управлении зависимостями http://sergeyteplyakov.blogspot.com/2013/10/articles.html#dependency_manage ment • Лучшая книга по ООП эвар! – Бертран Мейер «Объектно-ориентированное конструирование программных систем» http://sergeyteplyakov.blogspot.com/2012/03/blog-post_19.html

Editor's Notes

  • #7: Молодые разработчики и менеджеры стараются найти ответ на вопрос жизни
  • #20: Сказать о фабриках!