• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Yuri Trukhin - Software developement best practices
 

Yuri Trukhin - Software developement best practices

on

  • 790 views

 

Statistics

Views

Total Views
790
Views on SlideShare
715
Embed Views
75

Actions

Likes
1
Downloads
17
Comments
0

1 Embed 75

http://oslab.by 75

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • В приложение «Вычислительная геометрия» попадает не нужная логика вместе с классом Rectangle.Если изменение графического приложения потребует изменить класс Rectangle, придется заново собирать, тестировать и развертывать приложение «Вычислительная геометрия».… или приложение «Вычислительная геометрия» неожиданно может перестать работать
  • ДА!Если может потребоваться изменение сигнатуры методов управления соединением, класс, вызывающий send и receive придется повторно компилировать и развертывать чаще, чем хотелось бы.Это приводит к жесткости дизайна. Следует разделить интерфейс на DataChannelи ConnectionНЕТ!Если приложение не модифицируют таким образом, что обязанности изменяются порознь, то разделять нет необходимости.Это приводит к излишней сложности. Изменения интерфейса не требуются.
  • ///Резюме:///это решение жесткое,///тк после добавление фигуры Triange(треугольник)///необходимо заново откомпилировать и развернуть файлы , содержащие опредлеление///Shape, Square,Circle и DrawAllShapes.//////это решение хрупкое,///т.к. есть много других switch/case и if/else, которые сложно отыскать и понять.//////это решение костное, потому что всякий, кто попытается использовать ///функцию DrawAllShapes в другой программе, вынужден будет тащить за собой ///определения Square и Circle, даже если в этой программе они не используются.
  • ///Резюме:///это решение жесткое,///тк после добавление фигуры Triange(треугольник)///необходимо заново откомпилировать и развернуть файлы , содержащие опредлеление///Shape, Square,Circle и DrawAllShapes.//////это решение хрупкое,///т.к. есть много других switch/case и if/else, которые сложно отыскать и понять.//////это решение костное, потому что всякий, кто попытается использовать ///функцию DrawAllShapes в другой программе, вынужден будет тащить за собой ///определения Square и Circle, даже если в этой программе они не используются.
  • ///Резюме:///это решение жесткое,///тк после добавление фигуры Triange(треугольник)///необходимо заново откомпилировать и развернуть файлы , содержащие опредлеление///Shape, Square,Circle и DrawAllShapes.//////это решение хрупкое,///т.к. есть много других switch/case и if/else, которые сложно отыскать и понять.//////это решение костное, потому что всякий, кто попытается использовать ///функцию DrawAllShapes в другой программе, вынужден будет тащить за собой ///определения Square и Circle, даже если в этой программе они не используются.

Yuri Trukhin - Software developement best practices Yuri Trukhin - Software developement best practices Presentation Transcript

  • Лучшие практики разработки ПО
    Принципы гибкого проектирования
    Юрий Трухин
    senior developer, CNIPGIS LLC
    Microsoft Student Partner Guru
  • беларуская версія
    Лепшыя практыкі распрацоўкі праграмнага забеспячэння
    прынцыпы гнуткага праектавання
    Юрий Трухин
    senior developer, CNIPGIS LLC
    Microsoft Student Partner Guru
  • Признаки плохого дизайна ПО
  • Признаки плохого дизайна ПО
    Жесткость: дизайн трудно поддается изменению
    Хрупкость: дизайн легко разрушается
    Косность: дизайн трудно использовать повторно
    Вязкость: трудно добиться желаемого
    Ненужная сложность: избыточное проектирование
    Ненужные повторения: чрезмерное использование копирования и вставки
    Непрозрачность: плохо выраженная цель
    Часто эти признаки появляются в результате нарушения одного из принципов проектирования.
  • Пример загнивания программы
  • public partial class Copier
    {
    public static void Copy()
    {
    int c;
    while ((c = Keyboard.Read()) != -1)
    {
    Printer.Write(c);
    }
    }
    }
  • public class CopierWithPerfocards
    {
    /// <summary>
    /// не забудьте сбросить этот флаг
    /// </summary>
    private static boolptFlag = false;
    public static void Copy()
    {
    int c;
    while ((c = (ptFlag ? PaperTape.Read() : Keyboard.Read())) != -1)
    Printer.Write(c);
    }
    }
  • public class CopierWithPerfocardsReadAndWrite
    {
    //не забудьте сбросить этот флаг
    public static boolptFlag = false;
    public static boolpunchFlag = false;
    public static void Copy()
    {
    int c;
    while ((c = (ptFlag ? PaperTape.Read() : Keyboard.Read())) != -1)
    punchFlag ? PaperTape.punchFlag(c) : Printer.Write(c);
    }
    }
  • public interface Reader
    {
    int Read();
    }
    public class KeyboardReader : Reader
    {
    public int Read() { return Keyboard.Read(); };
    }
    public partial class Copier
    {
    public static Reader reader = new KeyboardReader();
    public static void Copy()
    {
    var c;
    while ((c = (reader.Read())) != -1 )
    {
    Printer.Write(c);
    }
    }
    }
  • Принципы гибкого проектирования
  • Принципы гибкого проектирования
    Принцип единственной обязанности
    Принцип открытости/закрытости
    Принцип подстановки Лисков
    Принцип инверсии зависимости
    Принцип разделения интерфейсов
    Принцип эквивалентности повторного использования и выпуска
    Принцип общей закрытости
    Принцип совместного повторного использования
    Принцип ацикличности зависимостей
    Принцип устойчивых зависимостей
    Принцип устойчивых абстракций
  • Принцип единственной обязанности (SRP)
    «Никто кроме Будды не должен брать на себя ответственность за сокровенные знания»
    Э.Кобхэм Брюэр, 1897
  • Принцип единственной обязанности (SRP)
    У класса должна быть только одна причина для изменения.
    Любое изменение требований проявляется в изменении распределения обязанностей между классами. Если класс берет на себя несколько обязанностей – у него появляется несколько причин для изменения.
    Если класс отвечает за несколько действий, его обязанности оказываются связанными.
    Это является причиной хрупкого дизайна приложений.
  • Принцип единственной обязанности (SRP)
    Более одной обязанности
    Rectangle
    Приложение «Вычислительная геометрия»
    +draw()
    +area() : double
    Графическое приложение
    GUI
  • Принцип единственной обязанности (SRP)
    Проблемы:
  • Принцип единственной обязанности (SRP)
    Проблемы:
    В приложение «Вычислительная геометрия» попадает не нужная логика вместе с классом Rectangle.
    Если изменение графического приложения потребует изменить класс Rectangle, придется заново собирать, тестировать и развертывать приложение «Вычислительная геометрия».
    … или приложение «Вычислительная геометрия» неожиданно может перестать работать
  • Принцип единственной обязанности (SRP)
    Обязанности разделены
    Rectangle
    GeometricRectangle
    Приложение «Вычислительная геометрия»
    Графическое приложение
    +draw()
    +area() : double
    GUI
  • Принцип единственной обязанности (SRP)
    Обязанность – причина изменения
    Если вы можете найти несколько причин для изменения – у класса несколько обязанностей.
  • Принцип единственной обязанности (SRP)
    Пример:
    Public interface Modem
    {
    public void Dial(string pno);
    public void Hangup();
    public void Send (char c);
    public char Recv();
    }
    Сколько обязанностей у интерфейса Modem?
  • Принцип единственной обязанности (SRP)
    Сколько обязанностей?:
    Public interface Modem
    {
    public void Dial(string pno); //управление соединением
    public void Hangup();//управление соединением
    public void Send (char c);//передача данных
    public char Recv(); //передача данных
    }
    Нужно ли разделить интерфейс?
  • Принцип единственной обязанности (SRP)
    Нужно ли разделять интерфейс?:
    ДА!
    Если может потребоваться изменение сигнатуры методов управления соединением, класс, вызывающий send и receive придется повторно компилировать и развертывать чаще, чем хотелось бы.
    Это приводит к жесткости дизайна. Следует разделить интерфейс на DataChannelи Connection
  • Принцип единственной обязанности (SRP)
    Нужно ли разделять интерфейс?:
    НЕТ!
    Если приложение не модифицируют таким образом, что обязанности изменяются порознь, то разделять нет необходимости.
    Это приводит к излишней сложности. Изменения интерфейса не требуются.
  • Принцип единственной обязанности (SRP)
    Нужно ли разделять интерфейс?:
    НЕТ!
    Если приложение не модифицируют таким образом, что обязанности изменяются порознь, то разделять нет необходимости.
    Это приводит к излишней сложности. Изменения интерфейса не требуются.
    Вывод: ось изменения становится таковой, если изменение имеет место. Если на то нет причин, неразумно применять ЛЮБОЙ принцип проектирования.
  • Принцип единственной обязанности (SRP)
    Разделение связанных обязанностей. Обеспечение сохранности.
    Employee
    +CalculatePay
    +Store
    Persistense System
    Связь бизнес-правил и подсистемы сохраниния -> неприятности!
    Обычно тесты заставляют их разделять, если нет – в случае если появляется жесткость и хрупкость – нужен рефакторинг!
    (Для данного случая применимы паттерны Фасад, Объект доступа к данным, Прокси для разделения обязанностей).
  • Принцип открытости-закрытости
    «Голланская дверь: существительное. Дверь, разделенная на две части по горизонтали так, что каждая створка может открываться и закрываться независимо»
    The American Heritage Dictionary of English language, 2000
  • Принцип открытости-закрытости
    Программные сущности (классы, модули, функции) должны быть открыты для расширения и закрыты для модификации.
    Если единственное изменение в каком-то месте программы приводит к каскаду изменений в зависимых модулях – это признак жесткого дизайна.
  • Принцип открытости-закрытости
    Основные храктеристики модулей, разработанных в соответствии с принципом открытости-закрытости:
    Они открыты для расширения (поведение модуля можно расширить, можно менять состав функций модуля).
    Они закрыты для модификации (расширение поведение модуля не сопряжено с изменением в исходном или двоичном коде модуля).
    Как это сделать?
  • Принцип открытости-закрытости
    Как это сделать?
    С ПОМОЩЬЮ АБСТРАКЦИИ!
    Абстракция – абстрактный базовый класс, поведение – производный класс.
    Модуль, манипулирующий абстракцией можно сделать закрытым для модификации – он зависит от ФИКСИРОВАННОЙ абстракции.
    Модуль при этом остается расширяемым.
  • Принцип открытости-закрытости
    Пример:
    Client
    Server
    Класс Client не является открытым и закрытым.
  • Принцип открытости-закрытости
    Применив паттерн «Стратегия» получим:
    “interface”
    Client Interface
    Client
    Server
    Класс Client одновременно является открытым и закрытым.
  • Принцип открытости-закрытости
    Альтернатива: Паттерн «Шаблонный метод»
    Открытые методы в policy реализуют некую политику, они аналогичны методам класса Client (описывают определенные функции в терминах абстрактных интерфейсов, часть класса policy, в C# это абстрактные методы, реализуются в подтипах policy).
    Поведения, описанные внутри policy, можно расширять и модифицировать.
    Policy
    Implementation
    +PolicyFunction()
    #ServiceFunction()
    #ServiceFunctiom
  • Принцип открытости-закрытости
    Пример принципа OCP
  • Принцип открытости-закрытости
    --shape.h--------------------------------------------------------------------
    enumShareType (circle, square);
    struct Shape
    {
    ShapeTypeitsType;
    }
    --circle.h-------------------------------------------------------------------
    struct Circle
    {
    ShapeTypeitsType;
    double itsRadius;
    Point itsCenter;
    };
    void DrawCircle(struct Circle*);
    --square.h-------------------------------------------------------------------
    struct Square
    {
    ShapeTypeitsType;
    double itsSide;
    Point itsTopLeft;
    };
    void DrawSquare(struct Square*);
  • Принцип открытости-закрытости
    --drawAllShapes.cc-----------------------------------------------------------
    typedefstruct Shape *ShapePointer;
    //функция не может быть закрытой для добавления других фигур, //не удовлетворяет принципам OCP
    void DrawAllShapes(ShapePointer list[], int n)
    {
    int i;
    for (i=0; i<n; i++)
    {
    struct Shape* s = list[i];
    switch (s->itsType)
    {
    case square:
    DrawSquare((struct Square*)s);
    break;
    case circle:
    DrawCircle((struct Circle*)s);
    break;
    }
    }
    }
    ///Резюме:
    ///это решение жесткое,
    ///тк после добавление фигуры Triange(треугольник)
    ///необходимо заново откомпилировать и развернуть файлы , содержащие опредлеление
    ///Shape, Square,Circle и DrawAllShapes.
    ///
    ///это решение хрупкое,
    ///т.к. есть много других switch/case и if/else, которые сложно отыскать и понять.
    ///
    ///это решение костное, потому что всякий, кто попытается использовать
    ///функцию DrawAllShapes в другой программе, вынужден будет тащить за собой
    ///определения Square и Circle, даже если в этой программе они не используются.
  • Принцип открытости-закрытости
    public interface Shape
    {
    void Draw();
    }
    public class Square : Shape
    {
    public void Draw()
    {
    //нарисовать квадрат
    }
    }
    public class Circle : Shape
    {
    public void Draw()
    {
    //нарисовать круг
    }
    }
    public void DrawAllShape(IList shapes)
    {
    foreach (Shape shape in shapes)
    shape.Draw();
    }
  • Принцип открытости-закрытости
    Внимание, изменились требования!
  • Принцип открытости-закрытости
    Изменившиеся требования
    Необходимо, чтобы все круги рисовались раньше всех квадратов.
  • Принцип открытости-закрытости
    Вывод 1
    Модель Shape не является естественной в системе, где упорядоченность связана с типом фигуры.
    Каким бы закрытым не был модуль, всегда найдется такое изменение, для которых он не закрыт.
    Не существует моделей, естественных во всех контекстах!
    Проектировщик должен решить, от каких изменений закрыть дизайн.
    OCP применим только с вероятными изменениями.
  • Принцип открытости-закрытости
    Расстановка «точек подключения»
    «Обманул меня раз». Первоначально код пишется без учета возможных изменений. Если изменение происходят – реализуется абстракция, в будущем защищающие от подобного рода изменений.
    «Стимулирование изменений»
    Сначала пишем тесты.
    Разработку ведем очень короткими циклами, измеряемыми в днях, а не в неделях
    Разрабатываем содержательные функции до инфраструктуры и часто демонстрируем их заинтересованным сторонам
    Первую версию ПО выпускаем быстро, а последующие часто.
  • Принцип открытости-закрытости
    Заключение
    Следование этому принципу позволит получить от ООП максимум обещанного: гибкость, возможность повторного использования и удобство сопровождения.
    Отказ от преждевременного абстрагирования столь же важен, как и само абстрагирование.
  • Принцип подстановки лисков
    «Должна быть возможность вместо базового типа подставить любой его подтип»
  • Принцип инверсии зависимостей
    Модули верхнего уровня не должны зависеть от модулей нижнего уровня. И те и другие должны зависеть от абстракций.
    Абстракции не должны зависеть от деталей. Детали должны зависеть от абстракций.
  • Принцип разделения интерфейсов
    Клиенты не должны вынужденно зависеть от методов, которыми не пользуются.
  • Принцип эквивалентности повторного использования и выпуска
    Единица повторного использования равна единице выпуска.
    (либо все классы, включенные в компонент можно повторно использовать, либо ни один!)
  • Принцип общей закрытости
    Все классы внутри компонента должны быть закрыты относительно изменений одного и того же вида. Изменение, затрагивающее компонент, должно затрагивать все классы в этом компоненте и только в нем.
  • Принцип совместного повторного использования
    Все классы внутри компонента используются совместно. Если вы можете повторно использовать один класс, то можете использовать и остальные.
  • Принцип ацикличности зависимостей
    В графе зависимостей между компонентами не должно быть циклов
  • Принцип устойчивых зависимостей
    Зависимости должны быть направлены в сторону устойчивости (изменяемые компоненты должны быть сверху графа, и из них собирается неизменяемый)
  • Принцип устойчивых абстракций
    Компонент должен быть столь же абстрактным, сколь и устойчивым (иначе устойчивость будет препятствовать его расширению).
  • Что дальше?
    • DI/IOC
    • Prism
    • Вред реинжиниринга
    • Паттерны
    • Постоянное развитие
    • Смотрите исходный код (codeplexи др)
    • Помогайте другим (форумы msdnи др)
  • Спасибоза внимание!
    Юрий Трухин
    Senior developer (CNIPGIS LLC)
    Microsoft Student Partner GURU
    trukhin.yuri@hotmail.com
    trukhinyuri.blogspot.com
    twitter.com/trukhinyuri
    Удачных проектов!
  • © 2008 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries.
    The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.