SlideShare uma empresa Scribd logo
1 de 27
Ted’s Tool Time
Ted Vinke
First8
Specifications Pattern
August 2016
“Separate the statement of how to
match a candidate, from the candidate
object that it is matched against”
-- Martin Fowler
http://martinfowler.com/apsupp/spec.pdf
Using specifications to describe the selection criteria for portfolios in contracts.
Using specifications to describe the selection criteria for portfolios in contracts.
Using specifications to constrain which containers can be used for transporting a cargo
Using a specification as an input to a route selector. This decouples the route selector from the
shipment.
Advantages
Treating the specification as a separate object has a number of advantages
Lets you decouple the design of requirements, fulfillment, and validation
Allows you to make your systemdefinitions more clear and declarative
3 simple requirements
1. Animal should be
female
2. Animal should not have
been tested before
(Herdbook API)
3. No existing genomic
tests (Breeding API)
Is a genomic test allowed?
version 1
(Warning: Groovy ahead!)
Render only animals for which genomic test is
allowed
Need:
HousingService housingService
Iterate and check:
Collection<Animal> animals = housingService.retrieveAnimals()
animals.each { animal ->
boolean matches = isGenomicTestAllowed(animal)
Animal should be female
Need:
class Animal {
AnimalId id
String name
String gender
}
Check:
gender.toLowerCase() == ‘female’
Animal should not have been tested before
Need:
HerdbookRepository herdbookRepository
Check:
AnimalHeredityResource heredity =
herdbookRepository.retrieveHeredity(animal.id)
heredity != null
No existing genomic tests
Need:
BreedingRepository breedingRepository
Check:
Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests()
GenomicTestResource existingTest = testResources.find { test ->
test.animalId == animal.id
}
Putting them
together
HousingService housingService
HerdbookBackendRepository herdbookBackendRepository
BreedingRepository breedingRepository
boolean isGenomicTestAllowed(Animal animal) {
boolean genderMatch = gender.toLowerCase() == ‘female’
AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id)
boolean heredityMatch = heredity != null
Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests()
boolean existingTestMatch = testResources.find { test ->
test.animalId == animal.id
}
return genderMatch && heredityMatch && existingTestMatch
}
}
Is a genomic test allowed?
version 2
(Warning: Groovy ahead!)
GenomicTestedBeforeCondition
class GenomicTestedBeforeCondition {
HerdbookRepository herdbookRepository
boolean isSatisfiedBy(Animal animal) {
final AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id)
return heredity?.heredity
}
}
GenomicTestRequestExistsCondition
class GenomicTestRequestExistsCondition {
BreedingRepository breedingRepository
boolean isSatisfiedBy(Animal animal) {
Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests()
return testResources.find { test ->
test.animalId == animal.id
}
}
Animal
class Animal {
AnimalId id
String name
String gender
boolean isFemale() {
gender.toLowerCase() == 'female'
}
}
Putting them together
GenomicTestRequestAllowedCondition (1)
class GenomicTestRequestAllowedCondition {
GenomicTestedBeforeCondition genomicTestedBeforeCondition
GenomicTestRequestExistsCondition genomicTestRequestExistsCondition
...
GenomicTestRequestAllowedCondition (2)
class GenomicTestRequestAllowedCondition {
GenomicTestedBeforeCondition genomicTestedBeforeCondition
GenomicTestRequestExistsCondition genomicTestRequestExistsCondition
private Closure isFemale = { Animal animal -> animal.female }
private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) }
private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) }
GenomicTestRequestAllowedCondition (3)
class GenomicTestRequestAllowedCondition {
GenomicTestedBeforeCondition genomicTestedBeforeCondition
GenomicTestRequestExistsCondition genomicTestRequestExistsCondition
private Closure isFemale = { Animal animal -> animal.female }
private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) }
private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) }
boolean isSatisfiedBy(Animal a) {
isFemale(a) && notTestedBefore(a) && noExistingGenomicTests(a)
}
}
Testing easier
Individual specification
class GenomicTestedBeforeConditionSpec extends Specification {
void "test condition should check that animal is tested before"() {
given:
GenomicTestedBeforeCondition condition = new GenomicTestedBeforeCondition()
when: "there are heredity characteristics"
condition.herdbookRepository = Mock(HerdbookRepository) {
1 * retrieveHeredity(_) >> new AnimalHeredityResource()
}
then: "animal must have been tested before"
condition.isSatisfiedBy(SOME_ANIMAL)
}
}
Combination of specifications
class GenomicTestRequestAllowedConditionSpec extends Specification {
GenomicTestRequestAllowedCondition condition = new GenomicTestRequestAllowedCondition()
void "test condition should be satisfied if all subconditions are met"() {
when: "all subconditions are met"
condition.isFemale = { true }
condition.notTestedBefore = { true }
condition.noExistingGenomicTests = { true }
then: "the condition is satisified"
condition.isSatisfiedBy(new Animal())
when: "one of the subconditions is not met"
condition.notTestedBefore = { false }
……...
Remember these closures? :-)
private Closure isFemale = { Animal animal -> animal.female }
private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) }
private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) }
That's it!
Thank you

Mais conteúdo relacionado

Semelhante a Specifications pattern - Ted's Tool Time

Test-driven development for TYPO3 (T3DD11)
Test-driven development for TYPO3 (T3DD11)Test-driven development for TYPO3 (T3DD11)
Test-driven development for TYPO3 (T3DD11)
Oliver Klee
 
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3
Oliver Klee
 
Recommending Method Invocation Context Changes
Recommending Method Invocation Context ChangesRecommending Method Invocation Context Changes
Recommending Method Invocation Context Changes
Beat Fluri
 
Test-Driven Development for TYPO3
Test-Driven Development for TYPO3Test-Driven Development for TYPO3
Test-Driven Development for TYPO3
Oliver Klee
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
Yi-Huan Chan
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4
Yi-Huan Chan
 

Semelhante a Specifications pattern - Ted's Tool Time (15)

JUnit Pioneer
JUnit PioneerJUnit Pioneer
JUnit Pioneer
 
Test-driven development for TYPO3 (T3DD11)
Test-driven development for TYPO3 (T3DD11)Test-driven development for TYPO3 (T3DD11)
Test-driven development for TYPO3 (T3DD11)
 
Test-driven Development for TYPO3
Test-driven Development for TYPO3Test-driven Development for TYPO3
Test-driven Development for TYPO3
 
JUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit TestsJUnit Kung Fu: Getting More Out of Your Unit Tests
JUnit Kung Fu: Getting More Out of Your Unit Tests
 
Recommending Method Invocation Context Changes
Recommending Method Invocation Context ChangesRecommending Method Invocation Context Changes
Recommending Method Invocation Context Changes
 
Generic
GenericGeneric
Generic
 
Be smart when testing your Akka code
Be smart when testing your Akka codeBe smart when testing your Akka code
Be smart when testing your Akka code
 
Test-Driven Development for TYPO3
Test-Driven Development for TYPO3Test-Driven Development for TYPO3
Test-Driven Development for TYPO3
 
API first with Swagger and Scala by Slava Schmidt
API first with Swagger and Scala by  Slava SchmidtAPI first with Swagger and Scala by  Slava Schmidt
API first with Swagger and Scala by Slava Schmidt
 
Test in action week 2
Test in action   week 2Test in action   week 2
Test in action week 2
 
Testing untestable code - DPC10
Testing untestable code - DPC10Testing untestable code - DPC10
Testing untestable code - DPC10
 
Mining Plant Pathogen Genomes for Effectors
Mining Plant Pathogen Genomes for EffectorsMining Plant Pathogen Genomes for Effectors
Mining Plant Pathogen Genomes for Effectors
 
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
QA Lab: тестирование ПО. Станислав Шмидт: "Self-testing REST APIs with API Fi...
 
Test in action week 4
Test in action   week 4Test in action   week 4
Test in action week 4
 
Junit_.pptx
Junit_.pptxJunit_.pptx
Junit_.pptx
 

Mais de Ted Vinke

Mais de Ted Vinke (10)

Spock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted VinkeSpock the enterprise ready specifiation framework - Ted Vinke
Spock the enterprise ready specifiation framework - Ted Vinke
 
Upcoming Events 2017 for a Java Software Developer - Ted's Tool Time
Upcoming Events 2017 for a Java Software Developer - Ted's Tool TimeUpcoming Events 2017 for a Java Software Developer - Ted's Tool Time
Upcoming Events 2017 for a Java Software Developer - Ted's Tool Time
 
Gmail Email Markup - Ted's Tool Time
Gmail Email Markup - Ted's Tool TimeGmail Email Markup - Ted's Tool Time
Gmail Email Markup - Ted's Tool Time
 
Code Generation with Groovy, Lombok, AutoValue and Immutables - Ted's Tool Time
Code Generation with Groovy, Lombok, AutoValue and Immutables - Ted's Tool TimeCode Generation with Groovy, Lombok, AutoValue and Immutables - Ted's Tool Time
Code Generation with Groovy, Lombok, AutoValue and Immutables - Ted's Tool Time
 
JUnit 5 - The Next Generation of JUnit - Ted's Tool Time
JUnit 5 - The Next Generation of JUnit - Ted's Tool TimeJUnit 5 - The Next Generation of JUnit - Ted's Tool Time
JUnit 5 - The Next Generation of JUnit - Ted's Tool Time
 
JEP 286 Local-Variable Type Inference - Ted's Tool Time
JEP 286 Local-Variable Type Inference - Ted's Tool TimeJEP 286 Local-Variable Type Inference - Ted's Tool Time
JEP 286 Local-Variable Type Inference - Ted's Tool Time
 
Devoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and DockerDevoxx 2015 - Web Application Development using Grails and Docker
Devoxx 2015 - Web Application Development using Grails and Docker
 
Working with Groovy Collections
Working with Groovy CollectionsWorking with Groovy Collections
Working with Groovy Collections
 
The Apache Software Foundation - Ted's Tool Time - Sep 2015
The Apache Software Foundation - Ted's Tool Time - Sep 2015The Apache Software Foundation - Ted's Tool Time - Sep 2015
The Apache Software Foundation - Ted's Tool Time - Sep 2015
 
Devoxx 2014 Report
Devoxx 2014 ReportDevoxx 2014 Report
Devoxx 2014 Report
 

Último

Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
UK Journal
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
FIDO Alliance
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
FIDO Alliance
 

Último (20)

Breaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdfBreaking Down the Flutterwave Scandal What You Need to Know.pdf
Breaking Down the Flutterwave Scandal What You Need to Know.pdf
 
How we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdfHow we scaled to 80K users by doing nothing!.pdf
How we scaled to 80K users by doing nothing!.pdf
 
Portal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russePortal Kombat : extension du réseau de propagande russe
Portal Kombat : extension du réseau de propagande russe
 
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
Event-Driven Architecture Masterclass: Integrating Distributed Data Stores Ac...
 
TopCryptoSupers 12thReport OrionX May2024
TopCryptoSupers 12thReport OrionX May2024TopCryptoSupers 12thReport OrionX May2024
TopCryptoSupers 12thReport OrionX May2024
 
Your enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4jYour enemies use GenAI too - staying ahead of fraud with Neo4j
Your enemies use GenAI too - staying ahead of fraud with Neo4j
 
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdfThe Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
The Value of Certifying Products for FDO _ Paul at FIDO Alliance.pdf
 
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
(Explainable) Data-Centric AI: what are you explaininhg, and to whom?
 
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptxHarnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
Harnessing Passkeys in the Battle Against AI-Powered Cyber Threats.pptx
 
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
ASRock Industrial FDO Solutions in Action for Industrial Edge AI _ Kenny at A...
 
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider  Progress from Awareness to Implementation.pptxTales from a Passkey Provider  Progress from Awareness to Implementation.pptx
Tales from a Passkey Provider Progress from Awareness to Implementation.pptx
 
WebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM PerformanceWebAssembly is Key to Better LLM Performance
WebAssembly is Key to Better LLM Performance
 
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
1111 ChatGPT Prompts PDF Free Download - Prompts for ChatGPT
 
Event-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream ProcessingEvent-Driven Architecture Masterclass: Challenges in Stream Processing
Event-Driven Architecture Masterclass: Challenges in Stream Processing
 
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdfWhere to Learn More About FDO _ Richard at FIDO Alliance.pdf
Where to Learn More About FDO _ Richard at FIDO Alliance.pdf
 
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties ReimaginedEasier, Faster, and More Powerful – Notes Document Properties Reimagined
Easier, Faster, and More Powerful – Notes Document Properties Reimagined
 
ADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptxADP Passwordless Journey Case Study.pptx
ADP Passwordless Journey Case Study.pptx
 
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
Human Expert Website Manual WCAG 2.0 2.1 2.2 Audit - Digital Accessibility Au...
 
Working together SRE & Platform Engineering
Working together SRE & Platform EngineeringWorking together SRE & Platform Engineering
Working together SRE & Platform Engineering
 
2024 May Patch Tuesday
2024 May Patch Tuesday2024 May Patch Tuesday
2024 May Patch Tuesday
 

Specifications pattern - Ted's Tool Time

  • 1. Ted’s Tool Time Ted Vinke First8 Specifications Pattern August 2016
  • 2. “Separate the statement of how to match a candidate, from the candidate object that it is matched against” -- Martin Fowler http://martinfowler.com/apsupp/spec.pdf
  • 3. Using specifications to describe the selection criteria for portfolios in contracts.
  • 4. Using specifications to describe the selection criteria for portfolios in contracts.
  • 5. Using specifications to constrain which containers can be used for transporting a cargo
  • 6. Using a specification as an input to a route selector. This decouples the route selector from the shipment.
  • 7. Advantages Treating the specification as a separate object has a number of advantages Lets you decouple the design of requirements, fulfillment, and validation Allows you to make your systemdefinitions more clear and declarative
  • 8.
  • 9. 3 simple requirements 1. Animal should be female 2. Animal should not have been tested before (Herdbook API) 3. No existing genomic tests (Breeding API)
  • 10. Is a genomic test allowed? version 1 (Warning: Groovy ahead!)
  • 11. Render only animals for which genomic test is allowed Need: HousingService housingService Iterate and check: Collection<Animal> animals = housingService.retrieveAnimals() animals.each { animal -> boolean matches = isGenomicTestAllowed(animal)
  • 12. Animal should be female Need: class Animal { AnimalId id String name String gender } Check: gender.toLowerCase() == ‘female’
  • 13. Animal should not have been tested before Need: HerdbookRepository herdbookRepository Check: AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id) heredity != null
  • 14. No existing genomic tests Need: BreedingRepository breedingRepository Check: Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests() GenomicTestResource existingTest = testResources.find { test -> test.animalId == animal.id }
  • 15. Putting them together HousingService housingService HerdbookBackendRepository herdbookBackendRepository BreedingRepository breedingRepository boolean isGenomicTestAllowed(Animal animal) { boolean genderMatch = gender.toLowerCase() == ‘female’ AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id) boolean heredityMatch = heredity != null Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests() boolean existingTestMatch = testResources.find { test -> test.animalId == animal.id } return genderMatch && heredityMatch && existingTestMatch } }
  • 16. Is a genomic test allowed? version 2 (Warning: Groovy ahead!)
  • 17. GenomicTestedBeforeCondition class GenomicTestedBeforeCondition { HerdbookRepository herdbookRepository boolean isSatisfiedBy(Animal animal) { final AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id) return heredity?.heredity } }
  • 18. GenomicTestRequestExistsCondition class GenomicTestRequestExistsCondition { BreedingRepository breedingRepository boolean isSatisfiedBy(Animal animal) { Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests() return testResources.find { test -> test.animalId == animal.id } }
  • 19. Animal class Animal { AnimalId id String name String gender boolean isFemale() { gender.toLowerCase() == 'female' } }
  • 21. GenomicTestRequestAllowedCondition (1) class GenomicTestRequestAllowedCondition { GenomicTestedBeforeCondition genomicTestedBeforeCondition GenomicTestRequestExistsCondition genomicTestRequestExistsCondition ...
  • 22. GenomicTestRequestAllowedCondition (2) class GenomicTestRequestAllowedCondition { GenomicTestedBeforeCondition genomicTestedBeforeCondition GenomicTestRequestExistsCondition genomicTestRequestExistsCondition private Closure isFemale = { Animal animal -> animal.female } private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) } private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) }
  • 23. GenomicTestRequestAllowedCondition (3) class GenomicTestRequestAllowedCondition { GenomicTestedBeforeCondition genomicTestedBeforeCondition GenomicTestRequestExistsCondition genomicTestRequestExistsCondition private Closure isFemale = { Animal animal -> animal.female } private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) } private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) } boolean isSatisfiedBy(Animal a) { isFemale(a) && notTestedBefore(a) && noExistingGenomicTests(a) } }
  • 25. Individual specification class GenomicTestedBeforeConditionSpec extends Specification { void "test condition should check that animal is tested before"() { given: GenomicTestedBeforeCondition condition = new GenomicTestedBeforeCondition() when: "there are heredity characteristics" condition.herdbookRepository = Mock(HerdbookRepository) { 1 * retrieveHeredity(_) >> new AnimalHeredityResource() } then: "animal must have been tested before" condition.isSatisfiedBy(SOME_ANIMAL) } }
  • 26. Combination of specifications class GenomicTestRequestAllowedConditionSpec extends Specification { GenomicTestRequestAllowedCondition condition = new GenomicTestRequestAllowedCondition() void "test condition should be satisfied if all subconditions are met"() { when: "all subconditions are met" condition.isFemale = { true } condition.notTestedBefore = { true } condition.noExistingGenomicTests = { true } then: "the condition is satisified" condition.isSatisfiedBy(new Animal()) when: "one of the subconditions is not met" condition.notTestedBefore = { false } ……... Remember these closures? :-) private Closure isFemale = { Animal animal -> animal.female } private Closure notTestedBefore = { Animal animal -> !genomicTestedBeforeCondition.isSatisfiedBy(animal) } private Closure noExistingGenomicTests = { Animal animal -> !genomicTestRequestExistsCondition.isSatisfiedBy(animal) }