specifications pattern - teds tool time
TRANSCRIPT
![Page 1: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/1.jpg)
Ted’s Tool TimeTed VinkeFirst8
Specifications Pattern
August 2016
![Page 2: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/2.jpg)
“Separate the statement of how to match a candidate, from the candidate object that it is matched against”
-- Martin Fowlerhttp://martinfowler.com/apsupp/spec.pdf
![Page 3: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/3.jpg)
Using specifications to describe the selection criteria for portfolios in contracts.
![Page 4: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/4.jpg)
Using specifications to describe the selection criteria for portfolios in contracts.
![Page 5: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/5.jpg)
Using specifications to constrain which containers can be used for transporting a cargo
![Page 6: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/6.jpg)
Using a specification as an input to a route selector. This decouples the route selector from the
shipment.
![Page 7: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/7.jpg)
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
![Page 8: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/8.jpg)
![Page 9: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/9.jpg)
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)
![Page 10: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/10.jpg)
Is a genomic test allowed?version 1
(Warning: Groovy ahead!)
![Page 11: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/11.jpg)
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)
![Page 12: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/12.jpg)
Animal should be female
Need:
class Animal {
AnimalId id
String name
String gender
}
Check:
gender.toLowerCase() == ‘female’
![Page 13: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/13.jpg)
Animal should not have been tested before
Need:
HerdbookRepository herdbookRepository
Check:
AnimalHeredityResource heredity =
herdbookRepository.retrieveHeredity(animal.id)
heredity != null
![Page 14: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/14.jpg)
No existing genomic tests
Need:
BreedingRepository breedingRepository
Check:
Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests()
GenomicTestResource existingTest = testResources.find { test ->
test.animalId == animal.id
}
![Page 15: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/15.jpg)
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
}
}
![Page 16: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/16.jpg)
Is a genomic test allowed?version 2
(Warning: Groovy ahead!)
![Page 17: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/17.jpg)
GenomicTestedBeforeCondition
class GenomicTestedBeforeCondition {
HerdbookRepository herdbookRepository
boolean isSatisfiedBy(Animal animal) {
final AnimalHeredityResource heredity = herdbookRepository.retrieveHeredity(animal.id)
return heredity?.heredity
}
}
![Page 18: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/18.jpg)
GenomicTestRequestExistsCondition
class GenomicTestRequestExistsCondition {
BreedingRepository breedingRepository
boolean isSatisfiedBy(Animal animal) {
Collection<GenomicTestResource> testResources = breedingRepository.retrieveTests()
return testResources.find { test ->
test.animalId == animal.id
}
}
![Page 19: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/19.jpg)
Animal
class Animal {
AnimalId id
String name
String gender
boolean isFemale() {
gender.toLowerCase() == 'female'
}
}
![Page 20: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/20.jpg)
Putting them together
![Page 21: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/21.jpg)
GenomicTestRequestAllowedCondition (1)
class GenomicTestRequestAllowedCondition {
GenomicTestedBeforeCondition genomicTestedBeforeCondition
GenomicTestRequestExistsCondition genomicTestRequestExistsCondition
...
![Page 22: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/22.jpg)
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) }
![Page 23: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/23.jpg)
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)
}
}
![Page 24: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/24.jpg)
Testing easier
![Page 25: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/25.jpg)
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)
}
}
![Page 26: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/26.jpg)
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) }
![Page 27: Specifications pattern - Teds Tool Time](https://reader030.vdocuments.site/reader030/viewer/2022020411/589dc2041a28abf7288b681b/html5/thumbnails/27.jpg)
That's it!
Thank you