tdd and decomposition

78
Роль декомпозиции функционала на отдельные классы при следовании TDD Бибичев Андрей декабрь 2011

Upload: andrey-bibichev

Post on 04-Dec-2014

1.860 views

Category:

Technology


5 download

DESCRIPTION

Presentation for XPDays Ukraine

TRANSCRIPT

Page 1: Tdd and decomposition

Роль декомпозиции функционала

на отдельные классы при следовании TDD

Бибичев Андрей

декабрь 2011

bibigine

Андрей Бибичев

bull E-mail bibiginegmailcom

bull Twitter bibigine

bull Profile httptinyurlcombibigine

bull Slideshare httpwwwslidesharenetbibigine

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 2: Tdd and decomposition

bibigine

Андрей Бибичев

bull E-mail bibiginegmailcom

bull Twitter bibigine

bull Profile httptinyurlcombibigine

bull Slideshare httpwwwslidesharenetbibigine

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 3: Tdd and decomposition

Пример

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 4: Tdd and decomposition

Subscription

UserName String Email String Organization String Status ConfirmationGuid MailedAt DateTime

ToBe Confirmed

Confirming

Confirmed

Error

Subscribed

Письмо

отправлено Ошибка

отправки

письма

laquoЖмакнутаraquo

ссылка

Перегружено

в систему рассылки

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 5: Tdd and decomposition

Что делать если ввели email

который уже есть

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 6: Tdd and decomposition

public class AllSubscriptions IAllSubscriptions public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10))) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 7: Tdd and decomposition

if (subscriptionConfirmationGuid = guid ampamp new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt currentMomentAddMinutes(-10)))

Это старая

запись

И так попадет в

систему рассылки

И так должен

получить письмо

со ссылкой

С момента отправки письма со ссылкой

прошло больше 10 минут (возможно

пользователь не получил его и повторно

подписывается) А если прошло меньше

времени то это больше похоже

на laquoпаразитныйraquo Reload

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 8: Tdd and decomposition

Тестировать такой метод ой как неприятно и муторно

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 9: Tdd and decomposition

Разделяй и властвуй тестируй

Лозунг TDD

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 10: Tdd and decomposition

Specification

SubscriptionCanBeRenewed

IsSatisfiedBy(obj) bool

ISpecificationltSubscriptiongt

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 11: Tdd and decomposition

public class SubscriptionCanBeRenewed ISpecificationltSubscriptiongt public const int PARASITIC_RELOAD_INTERVAL_IN_MINUTES = 10

public SubscriptionCanBeRenewedSpecification( DateTime currentMoment) thiscurrentMoment = currentMoment

public bool IsSatisfiedBy(Subscription subscription) var mailedBefore = currentMomentAddMinutes( -PARASITIC_RELOAD_INTERVAL_IN_MINUTES)

return new[] SubscriptionStatusConfirmed SubscriptionStatusToBeConfirmed Contains(subscriptionStatus) ampamp (subscriptionStatus = SubscriptionStatusConfirming || subscriptionMailedAt == null || subscriptionMailedAtValue lt mailedBefore)

private readonly DateTime currentMoment

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 12: Tdd and decomposition

Тестировать такой класс ndash одно удовольствие

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 13: Tdd and decomposition

given var subscription = new Subscription Status = SubscriptionStatusConfirming MailedAt = new DateTime(2011 12 17 18 10 0) var now = DateTime = new DateTime(2011 12 17 18 22 0) var sepcification = new SubscriptionCanBeRenewed(now) when var isOk = sepcificationIsSatisfiedBy(subscription) then isOkShould()BeTrue()

FluentAssertions

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 14: Tdd and decomposition

Возвращаемся к нашему laquoбарануraquo

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 15: Tdd and decomposition

public Subscription CreateOrUpdate( string userName string email string organization DateTime currentMoment) var guid = GuidNewGuid()ToString(D CultureInfoInvariantCulture)

INSERT INTO subscriptions() VALUES () ON DUPLICATE KEY UPDATE subscription_id = subscription_id

var subscription = FindByEmail(email) var isOldRecord = subscriptionConfirmationGuid = guid if (isOldRecord) var spec = new SubscriptionCanBeRenewed(currentMoment) if (specIsSatisfiedBy(subscription)) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = subscriptionid

return subscription

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 16: Tdd and decomposition

bull Можно сделать фабрику для спецификации

инжектить ее в репозиторий на тестах mock-ать

Но это столько возниhellip

bull Лучше продолжим отрывать куски в отдельные

классы

Но как теперь тестировать UPDATE

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 17: Tdd and decomposition

public interface ICommandltTgt void ExecuteFor(T obj) internal class SubscriptionRenewCommand ICommandltSubscriptiongt public SubscriptionRenewCommand(IDataContext dataContext) hellip public void ExecuteFor(Subscription obj) UPDATE subscriptions SET status = ToBeConfirmed WHERE subscription_id = objid

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 18: Tdd and decomposition

Можно еще сделать laquoнаворотraquo

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 19: Tdd and decomposition

public static class CommandExtensions public static ICommandltTgt IfltTgt( this ICommandltTgt command ISpecificationltTgt condition) return new IfCommandltTgt(command condition)

private class IfCommandltTgt ICommandltTgt public IfCommand( ICommandltTgt command ISpecificationltTgt condition) thiscommand = command thiscondition = condition

public void ExecuteFor(T obj) if (conditionIsSatisfiedBy(obj)) commandExecuteFor(obj)

private readonly ICommandltTgt command private readonly ISpecificationltTgt condition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 20: Tdd and decomposition

Тогда код будет выглядеть

new SubscriptionRenewCommand(dataContext) If(new SubscriptionCanBeRenewed(currentMoment)) ExecuteFor(subscription)

Почти jQuery Или даже монада )

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 21: Tdd and decomposition

bull Аналогично для выполнения команды в цикле

bull Для цепочки команд

bull Если что можно команды конструировать с

объектом контекста (мутабельным)

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 22: Tdd and decomposition

laquointerfaceraquo

ISpecificationltTgt

IsSatisfiedBy(obj)bool

Composite Specification

NotSpecification AndSpecification OrSepcification

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 23: Tdd and decomposition

public static class SpecificationExtensions public static ISpecificationltTgt AndltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new AndSpecification(left right) public static ISpecificationltTgt OrltTgt( this ISpecificationltTgt left ISpecificationltTgt right) return new OrSpecification(left right) public static ISpecificationltTgt NotltTgt( this ISpecificationltTgt spec) return new NotSpecification(spec)

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 24: Tdd and decomposition

laquoФилософияraquo мелких классов

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 25: Tdd and decomposition

Sprout Method

Sprout Class

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 26: Tdd and decomposition

someMethod(hellip)

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 27: Tdd and decomposition

При использовании TDD логики в не-public методах

почти не содержится да и самих таких методов обычно

очень мало (тупые хелперы)

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 28: Tdd and decomposition

Sprout Class

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 29: Tdd and decomposition

UsefulClass

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 30: Tdd and decomposition

Математика

bull Теорема

bull Лемма

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 31: Tdd and decomposition

Автопром

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 32: Tdd and decomposition

Проблемы с мелкими классами

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 33: Tdd and decomposition

bull тяжело придумывать имена классов o Правило чем уже scope использования класса тем длиннее

может быть его имя

o Плюс помогают постфиксы из шаблонов проектирования

bull легко запутаться в таком количестве

классов o Помогает (но не спасает) хорошая упаковка классов по

пакетампространствам имен

o см ниже

bull большая косвенность кода o современные среды разработки слегка спасают

bull как организовать взаимодействие o см ниже

bull есть проблемы с областью видимости o Обычно на это плюютhellip

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 34: Tdd and decomposition

laquoУпаковкаraquo мелких классов

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 35: Tdd and decomposition

MyMegaLogic

MegaClass

CoolClass

UsefulClass

HelperClass

laquoOld Schoolraquo Packaging

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 36: Tdd and decomposition

Cool

CoolClass

InterfaceOne

laquoNew Schoolraquo Packaging

InterfaceTwo

HelperClass1

HelperClass2

TinyUsefulClass

UtilClass

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 37: Tdd and decomposition

Пространства имен

bull MyLogic oMegaCool

bull здесь ваши классы CoolClass MegaClass OtherClass

bull вложенные пространства имен

o InternalsCoolClass

o Internals MegaClass

o SomethingOther

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 38: Tdd and decomposition

Увязывание классов между собой

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 39: Tdd and decomposition

Задачка от Yandex

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 40: Tdd and decomposition

include ltstdiohgt class Feature public enum FeatureType eUnknown eCircle eTriangle eSquare Feature() type(eUnknown) points(0) ~Feature() if (points) delete points bool isValid() return type = eUnknown

bool read(FILE file) if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType) return false short n = 0 switch (type) case eCircle n = 3 break case eTriangle n = 6 break case eSquare n = 8 break default type = eUnknown return false points = new double[n] if (points) return false return fread(amppoints sizeof(double) n file) == nsizeof(double)

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 41: Tdd and decomposition

void draw() switch (type) case eCircle drawCircle(points[0] points[1] points[2]) break case eTriangle drawPoligon(points 6) break case eSquare drawPoligon(points 8) break protected void drawCircle(double centerX double centerY double radius) void drawPoligon(double points int size) double points FeatureType type

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 42: Tdd and decomposition

int main(int argc char argv[]) Feature feature FILE file = fopen(featuresdat r) featureread(file) if (featureisValid()) return 1 return 0

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 43: Tdd and decomposition

Шаг 1

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 44: Tdd and decomposition

laquointerfaceraquo

Shape

read(file)bool draw() isValid()bool

Polygon

-points[]

Circle

-centerX -centerY -radius

Triangle Square

NullShape

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 45: Tdd and decomposition

class Feature public Feature() shape(new NullShape()) ~Feature() delete shape bool isValid() return shape-gtisValid

bool read(FILE file) FeatureType type if (fread(amptype sizeof(FeatureType) 1 file) = sizeof(FeatureType)) return false delete shape switch (type) case eCircle shape = new Circle() break case eTriangle shape = new Triangle() break case eSquare shape = new Square() break default shape = new NullShape() return shaperead(file)

void draw() shape-gtdraw()

private Shape shape enum FeatureType eUnknown eCircle eTriangle eSquare

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 46: Tdd and decomposition

Этот switch ужасен и нарушает OCP

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 47: Tdd and decomposition

Шаг 2

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 48: Tdd and decomposition

typedef Shape ShapeConstructor()

class Feature public static int registerShape( int uniqueCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( uniqueCode constructor)) return uniqueCode hellip

bool read(File file) auto it = shapeMapfind(type) shape = it == shapeMapend() new NullShape() it-gtsecond() return shape-gtread(file)

hellip private hellip static stdmapltint ShapeConstructorgt shapeMap

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 49: Tdd and decomposition

Circleh class Circle public Shape hellip private hellip static const int _readCodeNotUsed

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = FeatureregisterShape(1 ampcircleConstructor)

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 50: Tdd and decomposition

Если повторять этот подход на JavaC

при помощи статических конструкторов то надо не забыть

в статическом конструкторе Feature принудительно инициировать все классы

наследники от Shape

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 51: Tdd and decomposition

Shape Feature

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 52: Tdd and decomposition

Шаг 3

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 53: Tdd and decomposition

Shape Feature

ShapeFactory

Circle

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 54: Tdd and decomposition

class Feature public hellip bool read(File file) shape = ShapeFactory()createBy(type) return shape-gtread(file) hellip

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 55: Tdd and decomposition

typedef Shape ShapeConstructor() class ShapeFactory public static int registerShapeType( int typeCode ShapeConstructor constructor) shapeMapinsert(stdpairltint ShapeConstructorgt( typeCode constructor)) return uniqueCode Shape createBy(int typeCode) auto it = shapeMapfind(typeCode) return it == shapeMapend() new NullShape() it-gtsecond() private static stdmapltint ShapeConstructorgt shapeMap

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 56: Tdd and decomposition

Circlecpp Shape circleConstructor() return new Circle() int _readCodeNotUsed = ShapeFactoryregisterShapeType(1 ampcircleConstructor)

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 57: Tdd and decomposition

ОДНАКО

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 58: Tdd and decomposition

MyDomain

SomeSpec

MyPersistance

WhereGenerator

-visitAnd() -visitOr() -visitSomeSpec()

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 59: Tdd and decomposition

SomeSpec

AndSpecification

OrSpecification

NotSpecification NotVisitorItem

OrVisitorItem

AndVisitorItem

SomeSpecVisitorItem

Словарь соответствия

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 60: Tdd and decomposition

Решается специализированным тестом в рамках тестов на MyPersistance

через reflection перебираются все классы из MyDomain

реализующие ISpecificationltgt и проверяется что для каждого из них

есть элемент в словаре spec lt-gt visitorItem

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 61: Tdd and decomposition

Наличие mixin-ов и duck-typing в системе типов сильно бы помогло

См например google GO

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 62: Tdd and decomposition

laquoОбщениеraquo мелких классов

между собой

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 63: Tdd and decomposition

Приёмы

bull ServiceLocator

bull Dependency Injection

bull Callbacks Events

bull шаблон HasValue

bull EventAggregator

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 64: Tdd and decomposition

Event Aggregator

bull C Prism

bull Java GWT (EventBus)

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 65: Tdd and decomposition

public interface IEventAggregator void RegisterltTMessagegt(ActionltTMessagegt action) void SendltTMessagegt(TMessage message) void UnregisterltTMessagegt(ActionltTMessagegt action)

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 66: Tdd and decomposition

Полуминус

Event Aggregator-а

Скрытая часть API

Но параметр EventAggregator eventAggregator

в конструкторе какбэ намекает

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 67: Tdd and decomposition

Итого

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 68: Tdd and decomposition

А почемузачем

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы

Page 69: Tdd and decomposition

bibigine

bibiginegmailcom

httptinyurlcombibigine

httpwwwslidesharenetbibigine

Спасибо за внимание

Вопросы