specifications pattern - teds tool time

Post on 22-Jan-2018

72 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Ted’s Tool TimeTed VinkeFirst8

Specifications Pattern

August 2016

“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

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

top related