Основные принципы разработки ПО.

Download Report

Transcript Основные принципы разработки ПО.

TDD в Magento. С чего всё
начиналось.
Agenda
• Введение в TDD
• Важные принципы при разработке ПО
Введение в TDD
Введение в TDD
Введение в TDD
Введение в TDD
Стили разработки через
тестирования
• Traditional (традиционный)
• Active (активный)
• Acceptance (приёмочный)
Введение в TDD
Traditional (традиционный)
• Разработка только через “сначала-тестпотом-код”.
• Тесты диктуют архитектуру.
• На первых итерациях получаются простые
“тупые” решения задач.
Введение в TDD
Active (активный)
• Разработка только через “сначала-тестпотом-код”.
• Разработчик продумывает дизайн решения
задачи заранее и потом используя TDD
пытается к нему прийти.
Введение в TDD
•
•
•
•
Acceptance (приёмочный)
Разработчик пишет один большой тест на всю
задачу вместо того, чтоб писать много
маленьких.
На каждой итерации этот один тест постоянно
увеличивается.
Разработчик использует множество Mockобъектов.
После того, как функциональность готова,
заменяет Mock-объекты реальными классами.
Введение в TDD
Только “Традиционный” стиль является
настоящим TDD
Введение в TDD
Минусы “Активного” стиля
• Бессмысленно потраченное время на
продумывание архитектуры, так как при
TDD часто приходишь к другой архитектуре.
• До решения некоторых задач возможна
ситуация “design deadlock” (архитектурный
тупик): “Традиционный” TDD помогает
выйти из этой ситуации.
Введение в TDD
Минусы “Приёмочного” стиля
• Нарушение определения “unit”. Тест
становится бесполезным для поиска и
фикса багов.
• Тест слишком большой и трудно
понимаемый.
• Тест намного меньше влияет на архитектуру
решения, так как “тестируемость” кода не
играет особой роли.
Что необходимо знать перед
началом разработки через
тестирование:
• Основные принципы разработки ПО.
• Паттерны проектирования.
• Приёмы рефакторинга кода.
Основные принципы разработки ПО
S.O.L.I.D принципы
• SRP: Single Responsibility Principle (Принцип
единственной ответственности)
• OCP: Open Closed Principle (Принцип
открытости-закрытости)
• LSP: Liskov Substitution Principle (Принцип
подстановки Лисков)
• ISP: Interface Segregation Principle (Принцип
сегрегации интерфейса)
• DIP: Dependency Inversion Principle (Принцип
инверсии зависимости)
Основные принципы разработки ПО
SRP: Single Responsibility Principle (Принцип
единственной ответственности)
Цель:
• У класса должна быть только одна причина
для изменения. Иными словами класс
должен уметь делать что-то одно.
Основные принципы разработки ПО
Основные принципы разработки ПО
SRP: Single Responsibility Principle (Принцип
единственной ответственности)
Пример
Example 1:
Основные принципы разработки ПО
SRP: Single Responsibility Principle (Принцип
единственной ответственности)
Решение:
Основные принципы разработки ПО
OCP: Open Closed Principle (Принцип
открытости-закрытости)
Цель:
• Программные элементы (классы, модули,
функции) должны быть открыты для
расширения, но закрыты для модификации.
Основные принципы разработки ПО
Основные принципы разработки ПО
Пример:
class Logger
{
public function log($logText)
{
// save log into file
}
}
class SmtpMailer
{
private $logger;
public function __construct()
{
$this->logger = new Logger();
}
public function sendMessage($message)
{
//... sending message
$this->logger->log(sprintf("Message sent: '%s'", $message));
}
}
Основные принципы разработки ПО
Проблема: Что, если мы захотим поменять
файловый логгер на логгер в базу данных?
Мы изменим SmtpMailer класс:
public function __construct()
{
//$this->logger = new Logger();
$this->logger = new DatabaseLogger();
}
Нарушение принципа!
Основные принципы разработки ПО
Решение:
interface ILogger
{
public function log($logText);
}
class Logger implements ILogger
{
public function log($logText)
{
// save log into file
}
}
class SmtpMailer
{
private $logger;
public function __construct(ILogger $logger)
{
$this->logger = $logger;
}
public function sendMessage($message)
{
//... sending message
$this->logger->log(sprintf("Message sent: '%s'", $message));
}
}
Основные принципы разработки ПО
LSP: Liskov Substitution Principle (Принцип
подстановки Лисков)
Цель:
• Функции, которые используют объекты
определённых классов, не должны
ломаться, если в них передать наследники
от этих классов.
Основные принципы разработки ПО
Основные принципы разработки ПО
Для того, чтоб не нарушался этот принцип,
класс должен иметь Контракт и наследники
не должны его нарушать.
Контракт – список публичных методов с
ожидаемым поведением.
Основные принципы разработки ПО
ISP: Interface Segregation Principle (Принцип
сегрегации интерфейса)
Цель:
• Не следует заставлять клиентов зависеть от
интерфейсов, которые им не нужны.
Основные принципы разработки ПО
Основные принципы разработки ПО
Пример:
abstract class ServiceClient
{
public function getServiceUrl() {...}
public function setServiceUrl($url) {...}
abstract public function sendData($data);
abstract public function flush();
}
class HttpServiceClient extends ServiceClient
{
public function sendData($data)
{
$channel = Channel::openChannel($this->getServiceUrl());
$channel->send($data);
}
public function flush()
{
//do nothing!
}
}
class BufferingHttpServiceClient extends ServiceClient
{
public function sendData($data)
{
$this->buffer .= $data;
}
public function flush()
{
$channel = Channel::openChannel($this->getServiceUrl());
$channel->send($this->buffer);
}
}
Основные принципы разработки ПО
Решение:
abstract class ServiceClient
{
public function getServiceUrl() {...}
public function setServiceUrl($url) {...}
abstract public function sendData($data);
}
abstract class BufferingServiceClient extends ServiceClient
{
abstract public function flush();
}
class HttpServiceClient extends ServiceClient
{
public function sendData($data)
{
$channel = Channel::openChannel($this->getServiceUrl());
$channel->send($data);
}
}
class BufferingHttpServiceClient extends BufferingServiceClient
{
public function sendData($data)
{
$this->buffer .= $data;
}
public function flush()
{
$channel = Channel::openChannel($this->getServiceUrl());
$channel->send($this->buffer);
}
}
Основные принципы разработки ПО
DIP: Dependency Inversion Principle (Принцип
инверсии зависимости)
Цели:
• Высокоуровневые модули или классы не
должны зависить от низкоуровневых, оба
должны зависеть от абстракций.
• Абстракции не должны зависить от деталей
реализации. Детали реализации должны
зависеть от абстракций.
Основные принципы разработки ПО
Стандартная архитектура приложения
Основные принципы разработки ПО
Модифицированная архитектура
Основные принципы разработки ПО
Пример:
Основные принципы разработки ПО
Код:
class KeyboardReader
{
public function read() {...}
}
class FileWriter
{
public function write($data, $filename) {...}
}
class Copier
{
protected $_reader;
protected $_writer;
public function __construct()
{
$this->_reader = new KeyboardReader();
$this->_writer = new FileWriter();
}
public function copy($toFile)
{
$data = $this->_reader->read();
$this->_writer->write($data, $toFile);
}
}
Основные принципы разработки ПО
Проблемы:
• Класс Copier не тестируемый, так как нельзя
изолироваться от KeyboardReader и
FileWriter.
• Теперь в любом месте приложения ты
должен использовать Copier только с
классами KeyboardReader и FileWriter, даже
если захочешь использовать PrinterWriter
класс.
Основные принципы разработки ПО
Решение:
Основные принципы разработки ПО
Решение:
interface IReader
{
public function read();
}
interface IWriter
{
public function write($data);
}
class KeyboardReader implements IReader
{
public function read() {...}
}
class FileWriter implements IWriter
{
public function __construct($filename)
{
$this->_filename = $filename;
}
public function write($data) {...}
}
class Copier
{
protected $_reader;
protected $_writer;
public function __construct(IReader $reader, IWriter $writer)
{
$this->_reader = $reader;
$this->_writer = $writer;
}
public function copy()
{
$data = $this->_reader->read();
$this->_writer->write($data);
}
}
Основные принципы разработки ПО
Что мы получили:
• Лёгкое тестирование. Reader и Writer можем
подменить Mock-объектами.
• Гибкость. Теперь в любом месте приложения
мы можем использовать Reader и Writer, какой
захотим.
• Намного более прозрачный контракт. В
процессе разработки нам не нужно
заглядывать в реализацию Reader и Writer,
достаточно посмотреть интерфейсы, чтобы
понять, что они делают.