Slide 1

Slide 1 text

Tests - simplificateur de code? Johan Martinsson @johan_alps changit.fr

Slide 2

Slide 2 text

Exceptions! exceptionalMethod(userId, data) { try { let isOwner try { isOwner = this.authservice.isOwnerOf(userId, data.id) } catch (e) { this.logger.error('got http exception while invoking authService') } if (isOwner) { this.dao.update(data.id, data) } } catch (daoException) { this.logger.error('exception caught') } } nonExceptionalMethod(userId, data) { let isOwner = this.authservice.isOwnerOf(userId, data.id) if (isOwner) { this.dao.update(data.id, data) } }

Slide 3

Slide 3 text

l’angoisse de null function printItemNames(data) { if (data.prop) { if (data.prop.cart) { if (data.prop.cart.getList() !== null && data.prop.cart.getList() !== undefined) { for (let listItem of data.prop.cart.getList()) { if (listItem.description) { if (listItem.description.name) { console.debug('Phew, finally here!') // actual business logic console.log('And the item name is... ' + listItem.description.name) } } } } } } } function printItemNames(data) { for (let listItem of data.prop.cart.getList()) { console.debug('Phew, finally here!') // actual business logic console.log('And the item name is... ' + listItem.description.name) } }

Slide 4

Slide 4 text

Conditions function conditionalMethod(data) { if (data.something === 'val') { doSomething() if (data.age <= 40 || 'toto' !== data.something) { doAThirdThing() } else { doSomethingAdditional() } } }

Slide 5

Slide 5 text

Conditions, quand on aime … function conditionalCode(data) { if (data.prop) { if (data.prop.service) { if (data.prop.service.getList() === null && data.prop.service.getList().size > 0) { return 'processed ' + data.prop.service.getList().length + ' results' } else { let defaultResult = 'waiting' return defaultResult; } } } }

Slide 6

Slide 6 text

Duplication registerEmail(person) { if (person.age < 13) { throw new Error('too young') } if (person.name === null) { throw new Error('person must have name') } if (person.email.indexOf('@') <= 0) { throw new Error('invalid email') } console.log('do some stuff') this.dao.insertPerson(person) } registerMobile(person) { if (person.age < 13) { throw new Error('too young') } if (person.name === null) { throw new Error('person must have name') } if (this.hasNonDigits(person.phoneNumber)) { new Error('invalid phone number') } console.log('do some stuff') this.dao.insertPerson(person) } hasNonDigits(phoneNumber) { return /[^\d]+/.test(phoneNumber) }

Slide 7

Slide 7 text

Arguments indirects updateCartItems() { let httpSession = HttpSession.getInstance() let rawCart = httpSession.getCookie().getValue('cart') let cart = new Cart(rawCart) if (cart.lastModificationDate < Date.now() - 24 * 60 * 60 * 1000) { cart.removeAllItems(); } // etc ... // heavy logic to make sure availability is still ok, // that prices haven't changed // that items in the cart haven't expired etc }

Slide 8

Slide 8 text

Service injection, injection, injection … "Chaque nouvelle dépendance doit être passée sur toute la callstack" NOT Injection par constructeur - un seul endroit

Slide 9

Slide 9 text

Code inspectable function hardToTest() { let data = getStuffFromWebservice() // // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // let result let saveResult = saveToDatabase(result) } function easyToTest() { let data = getStuffFromWebservice() let result = easyToTestPureFunction(data) let saveResult = saveToDatabase(result) } function easyToTestPureFunction(data) { // // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // pure logic // }

Slide 10

Slide 10 text

Améliore-t-on le code?

Slide 11

Slide 11 text

Avec tests on a la possibilité de simplifier le code

Slide 12

Slide 12 text

Cercle vicieux/ vertueux

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

“Sometimes we find it difficult to write a test … this usually means that our design can be improved” - S. Freeman, N. Pryce “The tests are a canary in coal mining revealing by their distress the presence of evil design vapors” - Kent Beck

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

TDD requiert une maîtrise cognitive Etat préalable? Action? Résultat attendu?

Slide 17

Slide 17 text

Chunking

Slide 18

Slide 18 text

Mémoire court terme

Slide 19

Slide 19 text

Mémoire long terme Gael Varoquaux flickr Attribution 2.0 Generic (CC BY 2.0)

Slide 20

Slide 20 text

Notre cerveau a besoin de Blocs de 4-5 éléments noms cohésion assembler plutôt que modifier

Slide 21

Slide 21 text

Notre code de prod a besoin de peu de duplication peux de couplage morceaux à assembler BugsZero

Slide 22

Slide 22 text

Les tests ont besoin de être rapides Petites choses Responsabilités séparés Isolation des dépendances

Slide 23

Slide 23 text

Laissons les tests nous aider dans la quête du bon design Ayons zéro tolérance pour des mauvais tests

Slide 24

Slide 24 text

? @johan_alps changit.fr Tom Mullen (cognitive psychology) Michael Feathers (synergy between testablity and good design)