The long way through Software Craftsmanship

Testing a component that includes randomness

Jun 15, 2018 - 6 minute read - Comments - testingrandomnesstddjavacodesnippet

Context

We have been tasked with designing a component to generate secrets for two-factor authentication (2FA), to ensure that the you also own that other ‘channel’.

It has to be secure enough to pass to verify a user, meaning no other user should be able to impersonating another one by guessing the secret.

Solution

A first solution that he have implemented is to provide a 6-digit pin code.

The solution (in java) is straightforward: get a Random to generate ints for you.

public class PinCodeFactory {
    private Random secureRandom = new SecureRandom();

    public PinCode aNewPinCode () {
        return new PinCode(secureRandom.nextInt(1_000_000));
    }
}

public class PinCode {
    public final String value;

    public PinCode (final String value) {
        this.value = value;
    }
}

Note: this is not the final solution; it does not include package, imports; might not even compile. Take it as pseudo-code.

Now that we this “obvious implementation” in mind, how can we test drive it?

Let’s start with the requirements:

  • the numbers are always six digits
  • they should be pseudo-random

We can test the first by taking one of them and verifying that it has six digits.

First requirement: type of pin code

The problem with that is that the SecureRandom gives random data. Now, the test will be passing, but later in the future, the build will break as this implementation has (some) defects. If you keep generating pin codes, you will get one as “123”, as per the definition of the nextInt method.

Easy. You add a base amount to always make it in the six digits. But, are you affecting the distribution of the pseudo-random generator? At this time, I’m not even sure. Don’t make me think too much. To make it easier, let’s pad the numbers with zeros on the left:

@Test
public void the_numbers_are_left_padded_with_zeros () {
    verifyEachOf(pinCodes(100), pincode -> assertThat(pincode.length(), is(6)));
}

@Test
public void the_numbers_do_not_contain_spaces () {
    verifyEachOf(pinCodes(100), pincode -> assertThat(pincode.contains(" "), is(false)));
}

Now that these tests are failing, I can focus on finding a simple implementation that satisfies them.

A passing solution:

package com.example;

import com.example.Pincode;

import java.net.URI;
import java.security.SecureRandom;
import java.util.Random;

public class PinCodeFactory {
    private Random secureRandom = new SecureRandom();

    public PinCode aNewPinCode () {
        return new PinCode(String.format("%06d", random.nextInt(1_000_000)));
    }
}

But, if you execute these tests long enough, they will fail. Because of the underlaying randomness of the code. We don’t want to modify the design of this class, as we started with “wishful programming” (reference, reference), specifying the desired public API, to later fill the implementation details.

A possible solution to this randomness is to consider the random a ‘setting’ aka policy that I can later override. But only for the test. We don’t want to make the API more complicated, so we will offer a protected method for ‘friends’ to use, but not for everyone:

package com.example;

import com.example.Pincode;

import java.net.URI;
import java.security.SecureRandom;
import java.util.Random;

public class PinCodeFactory {

    private Random random;

    public PinCodeFactory () {
        random = new SecureRandom();
    }

    public PinCode aNewPinCode () {
        final String payload = String.format("%06d", random.nextInt(1_000_000));
        final PinCode pinCode = new PinCode(payload);
        return pinCode;
    }

    protected void setGenerator (final Random generator) {
        this.random = generator;
    }
}

(Note: this is the final version)

(Note: in java, the SecureRandom implements the same API as Random –in fact it is a child class– so we prefer accepting the parent class.)

In this way, the test can always set the random seed to a fixed value. Therefore, the numbers will be stable and the behavior is no longer random, but controlled.

This is just one way how you can test components that have randomness: eliminating it without affecting the public API.

Second requirement: the pin codes don’t repeat

Even if this requirement cannot be met with enough requests (because with enough requests, you will repeat a six-digit code), finding no repeated codes in 100 consecutive pin codes is enough. The user has to input the exact code they received, so the chance of repetition is quite low.

@Test
public void there_are_no_repeated_with_the_given_seed () {
    final int desiredProofSize = 100;
    verifyAll(pinCodes(desiredProofSize), pinCodes -> assertThat(pinCodes.size(), is(desiredProofSize)));
}

This test is passing from the beginning with the fixed seed 1L. But, if you enlarge the desiredProofSize to 1000, it does not pass anymore.

A note about process

We did not get much value of test-driving (TDD) this code, as the knew the desired API from the beginning, we had a clear implementation in mind and only a few cases left to iron out. Just test-first was enough in this case.

Conclusion

One way how you can test components that have randomness: eliminating it.

Do not use TDD (or any other tool) as an end in itself. Use it as a tool.

Appendix

All code can be found here

As a local copy:

//File PinCode.java
package com.example;

import java.util.Objects;

public class PinCode {
    public final String value;

    public PinCode (final String value) {
        this.value = value;
    }

    @Override
    public boolean equals (final Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        final PinCode pinCode = (PinCode) o;
        return Objects.equals(value, pinCode.value);
    }

    @Override
    public int hashCode () {
        return Objects.hash(value);
    }

    @Override
    public String toString () {
        final StringBuffer sb = new StringBuffer("PinCode{");
        sb.append("value='").append(value).append('\'');
        sb.append('}');
        return sb.toString();
    }
}
//File PinCodeFactory.java
package com.example;

import com.example.Pincode;

import java.net.URI;
import java.security.SecureRandom;
import java.util.Random;

public class PinCodeFactory {

    private Random random;

    public PinCodeFactory () {
        random = new SecureRandom();
    }

    public PinCode aNewPinCode () {
        final String payload = String.format("%06d", random.nextInt(1_000_000));
        final PinCode pinCode = new PinCode(payload);
        return pinCode;
    }

    protected void setGenerator (final Random generator) {
        this.random = generator;
    }
}
//File PinCodeFactoryTest.java
package com.example;

import org.junit.Before;
import org.junit.Test;

import java.util.Collection;
import java.util.HashSet;
import java.util.Random;
import java.util.function.Consumer;

import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

public class PinCodeFactoryTest {

    private PinCodeFactory pinCodeFactory;

    @Before
    public void setUp () {
        pinCodeFactory = new PinCodeFactory();
        pinCodeFactory.setGenerator(new Random(1L));
    }

    @Test
    public void there_are_no_repeated_with_the_given_seed () {
        final int desiredProofSize = 100;
        verifyAll(pinCodes(desiredProofSize), pinCodes -> assertThat(pinCodes.size(), is(desiredProofSize)));
    }

    @Test
    public void the_numbers_are_left_padded_with_zeros () {
        verifyEachOf(pinCodes(100), pincode -> assertThat(pincode.length(), is(6)));
    }

    @Test
    public void the_numbers_do_not_contain_spaces () {
        verifyEachOf(pinCodes(100), pincode -> assertThat(pincode.contains(" "), is(false)));
    }

    public void verifyEachOf (final Collection<String> pincodes, final Consumer<String> assertion) {
        for (final String pincode : pincodes) {
            assertion.accept(pincode);
        }
    }

    public void verifyAll (final Collection<String> pincodes, final Consumer<Collection<String>> assertion) {
        assertion.accept(pincodes);
    }


    private Set<String> pinCodes (final int desiredProofSize) {
        return Stream.generate(() -> pinCodeFactory.aNewPinCode().value)
                .limit(desiredProofSize)
                .collect(Collectors.toSet());
    }
}

Self-Study in May 2018

May 1, 2018 - 2 minute read - Comments - self-study-aggregationmay2018

Research Shows a Simple Way to Increase Your Engagement at Work

I’ve read this article By Michael Parke, Justin Weinhardt:

We found that increasing your engagement and productivity at work could be as simple as making a plan for the day

They talk about two types of planning: time management and contingent planning. The latter is about considering possible disruptions or interruptions they may face and a plan to tackle them (if they happen).

They argue that the latter is less frustrating than the former based on the non-accomplished tasks in the former. That the former is less effective when facing a high level of interruptions, as compared to the latter, equally effective no matter how many interruptions.

They suggest contingent planning for the days with high expected interruptions, time planning for the rest. But always use planning, for higher output, happiness at work

Tags: engagement, work, productivity, michael-parke, justin-weinhardt

You May Hate Planning, But You Should Do It Anyway

I’ve read this article by Elizabeth Grace Saunders. In it, she points that:

  • Planning will trigger pain — at least initially
  • Things tend to go better when you plan
  • Planning becomes the canary

She suggests that planning can help you become more productive, even considering the sunk cost of planning itself.

Tags: elizabeth-saunders, planning, hbr, management, time-management, plan

Books read in 2018Q1

Mar 31, 2018 - 9 minute read - Comments - bookreading2018Q1self-studycoduranceaprendicesreading-club

Read this quarter:

Note: re+read means I’m re-reading this book. The (+) stands for one-or-more times, as in the regexes.

Note: the tag “guillem” is for books suggested by Guillem Fernandez

  • Odessa; Forsyth; non-technical, own-it
  • Bogle on mutual funds: new perspectives for the intelligent investor; Bogle; own-it, non-technical, finance
  • Perros de la guerra, los; Forsyth; own-it, non-technical
  • avaro y el oro, el; Esopo; non-technical
  • Aulularia; Plauto; own-it, non-technical
  • Tus zonas erróneas; Dyer; non-technical, own-it
  • Alternativa del Diablo, la; Forsyth; own-it, non-technical
  • Guía, el; Forsyth; own-it, non-technical
  • Pied piper; Forsyth; own-it, non-technical
  • Hunt for the Red October, the; Clancy; own-it, non-technical
  • Peopleware; DeMarco, Lister (+); own-it
  • Time to kill, a; Grisham; own-it, non-technical
  • Ética promiscua; Easton, Hardy; own-it, non-technical
  • Checklist manifesto, the; Gawande; own-it, non-technical, guillem. How complexity can be managed by the lowest-rung workers by using a simple process: a checklist. The checklist is not a how-to list, but a list of well-known terms in the user jargon to remind them about actions to be performed. These recipes are a source of knowledge, therefore can be shared among users
  • Team geek (+); guillem, own-it
  • Kata de la voluntad; guillem, non-technical
  • Phoenix project, the ; Kim, Behr, Spafford; own-it
  • Obstacle is the way, the; guillem, non-technical
  • Guide to stoicism, a; Stock; own-it, non-technical. A quick guide into the Stoic philosophy. Interest in the authors, the way they structure knowledge.

backlog (partially sorted):

  • unsorted V
  • The Machine That Changed the World: The Story of Lean Production
  • Haskell Programming
  • Software Architecture in Practice
  • The five disfunctions of a team: a leadership fable; Lencioni
  • lucha por la desigualdad, la; Pontón; non-technical
  • psicología del dinero, la; Hammond; non-technical
  • Invirtiendo a largo plazo; García Paramés; non-technical
  • Well-Grounded Java Developer, the; own-it
  • Learn You a Haskell for Great Good!; own-it
  • camino al 18J, el; Payne; non-technical
  • Cartas desde la revolución bolchevique; Sadoul; non-technical
  • Java Performance: The Definitive Guide
  • Why programmers work at night
  • Shogun: The Life of Tokugawa Ieyasu; Sadler; non-technical
  • Scrum and XP from the trenches, 2nd edition;
  • Els jueus i Catalunya; Villatoro; non-technical
  • El problema de los tres cuerpos; Liu; non-technical
  • Amazon Web Services in Action; own-it
  • Clojure Programming - Practical Lisp for the Java World
  • Mature optimization
  • XUnit Test Patterns
  • Let Over Lambda
  • The Haskell Road to Logic, Math and Programming
  • Types and Programming Languages
  • Fundamentals of Object-oriented Design in UML
  • Clojure for the brave and true
  • How to Solve It: A New Aspect of Mathematical Method
  • Conceptual Mathematics: A First Introduction to Categories
  • Understanding Computation: From Simple Machines to Impossible Programs
  • Programming in Haskell
  • Programming Languages: Application and Interpretation
  • Doing Math with Python
  • Perfect Software: And Other Illusions about Testing
  • Computability and Complexity - From a Programming Perspective
  • Thinking Forth: a language and philosophy for solving problems
  • Concepts, Techniques, and Models of Computer Programming
  • Bridging the Communication Gap; Adzic
  • Specification by Example; Adzic
  • Cucumber book, the; Adzic
  • Software Architecture for Developers; Brown
  • Object Design: Roles, Responsibilities, and Collaborations
  • RESTful Web APIs
  • RESTful Web Services Cookbook
  • Building Maintainable Software
  • Serverless - Patterns of Modern Application Design Using Microservices (Amazon Web Services Edition)
  • A Pattern Language; Alexander
  • Types and Programming Languages, TAPL; Pierce; own-it
  • Speed Reading Book: Read More, Learn More, Achieve More, the; Buzan
  • Cómo crear mapas mentales (Crecimiento personal); Buzan
  • First things first; Covey
  • What’s best next; Perman
  • problems of philosophy, the; Russell
  • Requiem for the American dream; Chomsky
  • sun also rises, the; Hemingway
  • travels, the; Polo; non-technical
  • Homo Deus: A Brief History of Tomorrow; Harari; non-technical
  • Books by Aristotle; non-technical
  • Books by Plato
  • Books by Descartes
  • The idea of culture; Eagleton
  • Hereditary Intelligence; Galton; non-technical
  • Lean Software Development: An Agile Toolkit; Poppendieck
  • Chaos Monkeys: Obscene Fortune and Random Failure; Garcia Martinez
  • Implementing Lean Software Development: From Concept to Cash; Poppendieck
  • Joel on Software; Spolsky
  • Death March; Yourdon
  • Psychology of Computer Programming, The; Weinberg
  • Introduction to General Systems Thinking; Weinberg
  • En defensa de los ociosos; Stevenson; non-technical, own-it
  • Lao Tzu : Tao Te Ching : A Book About the Way and the Power of the Way; Tzu, Le Guin; non-technical
  • Gay Science, the; Nietzsche; non-technical
  • Being Geek; Lopp
  • Finance for Freelancers; Retallick
  • Object-oriented software engineering: a use case driven approach; Jacobson
  • Patterns of Enterprise Application Architecture; Fowler; own-it
  • Thinking fast and slow; Kahneman; non-technical
  • Emotional intelligence; Goleman; non-technical
  • Ética a Nicómaco; Aristotle; own-it, non-technical
  • Romeo y Julieta; Shakespeare; non-technical
  • Computer Systems: A Programmer’s Perspective; Bryant, O’Hallaron
  • My Journey to Lhasa: The Classic Story of the Only Western Woman Who Succeeded in Entering the Forbidden City; David-Néel; non-technical
  • Cathedral and the bazaar, the ; Raymond
  • Coding dojo handbook, the; Bache; own-it
  • Making software; Oram and Wilson; own-it
  • Code complete; McConnell; own-it
  • Soft skills; Sonmez; own-it
  • DSLs in action; Ghosh; own-it
  • Purely functional data structures; Okasaki; own-it
  • Working effectively with unit tests; Fields (+); own-it
  • First Nazi, the; Ludendorff; non-technical
  • Greatest story ever told … so far; Krauss; non-technical
  • Master algorithm, the; Domingos; non-technical
  • Invention of Science, the; Wootton; non-technical
  • Tesla: Inventor of the electrical age; Bernard Carlson; non-technical
  • Psychology in minutes; Weeks; non-technical
  • Alan Turing: The Enigma; Hodges; non-technical
  • How to think more about sex; de Botton; non-technical
  • Piccolo manuale di persuasione; Taylor; non-technical
  • arte de la guerra, el; Sun Tzu; non-technical, own-it
  • Piccolo manuale di leadership Confuciana; Adair; non-technical
  • How to Stop Worrying and Start Living; Carnegie; non-technical
  • Uomo - Guida allo stile; Roetzel; non-technical
  • Unwritten Laws of Engineering: Revised and Updated Edition; King
  • Test-Driven JavaScript Development (Developer’s Library); Johansen
  • Test Driven Development: By Example; Beck
  • Arquitectura Java JPA Domain Driven Design; Alvárez, Peláez
  • End of loyalty, the; Wartzman; non-technical
  • Basic Economics; Sowell; non-technical
  • Introduction to Economic Analysis; McAfee; non-technical
  • Patterns of Software; Gabriel
  • Coders at work; Seibel
  • Clean architecture; Martin
  • How to Be a Stoic: Using Ancient Philosophy to Live a Modern Life; Pigliucci; non-technical
  • Introduction to Object-Oriented Programming, an; Budd
  • Gafas de la felicidad, las; Santandreu; non-technical
  • Ser feliz en Alaska; Santandreu; own-it, non-technical
  • Mochila para el universo, una; Punset; non-technical
  • Gods themselves, the; Asimov; non-technical
  • Panamá papers, the; Obermayer, Obermaier; non-technical
  • Originals; Grant; non-technical
  • Optimism over despair; Chomsky; non-technical
  • SCIENCE OF BREATH: A Practical Guide; Ballentine, Hymes; non-technical
  • Yoga Explained: A New Step-by-step Approach to Understanding and Practising Yoga; Mehta,‎ Arjunwadkar; non-technical
  • Wanderlust: A Modern Yogi’s Guide to Discovering Your Best Self; Krasno; non-technical
  • How to Think About Money; Clements; non-technical, finance
  • By Way of Deception; Ostrovsky; non-technical
  • Printemps des sayanim, le; Cohen; own-it, non-technical
  • Deep work; Newport; non-technical, own-it
  • Hooked: How to Build Habit-Forming Products; Eyal, Hoover; non-technical
  • Irresistible: The Rise of Addictive Technology and the Business of Keeping Us Hooked; Alter; non-technical
  • The Attention Merchants: The Epic Scramble to Get Inside Our Heads; Wu; non-technical
  • Willpower: Why Self-Control is The Secret to Success; Baumeister, Tierney; non-technical
  • Principles of Psychology, the; James; own-it, non-technical
  • Our mutual friend; Dickens; non-technical
  • Crucial Conversations: Tools for Talking When Stakes Are High, Second Edition; Patterson, Grenny, McMillan, Switzler; non-technical
  • Amusing Ourselves to Death - Public Discourse in the Age of Show Business; Postman; non-technical
  • Mastery; Greene; non-technical, own-it
  • Silence in the age of noise; Kagge; non-technical
  • Functional programming simplified; Alexander; own-it
  • Your money or your life; Dominguez, Robin; non-technical, finance
  • Batalla del Ebro, la; Reverte; non-technical
  • Historia de la guerra civil española; Rojo; non-technical
  • Lucha por el poder, la; Evans; non-technical
  • Revolución rusa, la; Pipes; non-technical
  • Holocausto, el; Rees; non-technical
  • Martín Lutero, renegado y Profeta; Roper; non-technical
  • Siglo de la revolución, el ; Fontana; non-technical
  • Història de la revolución rusa; Trotsky; non-technical
  • Dispossessed, the; Le Guin; non-technical
  • Left hand of darkness; Le Guin; non-technical
  • Lathe of heaven; Le Guin; non-technical
  • https://www.amazon.com/Schopenhauer-Cure-Novel-Irvin-Yalom/dp/0060938102/
  • https://www.amazon.com/How-Schopenhauer-Through-Mid-Life-Crisis-ebook/dp/B00QXNB5PC/
  • Books in general – Epstein
  • Affluent society, the; Galbraith; non-technical, finance
  • Philosophy of the Buddha; Bahm; non-technical
  • Tribe of mentors; guillem, non-technical, own-it
  • 5 dysfunctions of a team; non-technical
  • Ziglar’s Top Performance; non-technical
  • Pragmatic Programmer (+)
  • High Output Management; Grove; non-technical
  • First Break All the Rules; non-technical
  • Managing for happiness; Appelo; non-technical
  • How to be a stoic - Pugliucci; non-technical
  • Why budism is true; Wright; non-technical

unfinished (unsorted):

  • Effective Java; Bloch; own-it
  • Functional Programming Patterns in Scala and Clojure; own-it
  • Release It! - Design and Deploy Production-Ready Software; own-it
  • Refactoring (+); Fowler; own-it
  • Leprechauns of Software Engineering (+), the; Bossavit; own-it
  • Domain-Driven Design: Tackling Complexity in the Heart of Software; Vernon (+); own-it
  • Pragmatic Thinking and Learning: Refactor Your Wetware; own-it
  • Readings in Database Systems, 5th Edition; own-it
  • Structure and Interpretation of Computer Programs (SICP); Abelson, Sussmann, Sussmann; own-it
  • La Sociedad De Coste Marginal Cero (Estado y Sociedad); Rifkin; non-technical
  • Odisea; Homero; non-technical
  • Switch: How to Change Things When Change Is Hard; Heath, Heath; own-it, non-technical
  • Como leer un libro; Adler, van Doren; non-technical, own-it

next (2):

  • Who rules the world?; Chomsky; non-technical
  • Working Effectively with Legacy Code (+); Feathers; own-it
  • Nonviolent communication (+); Rosenberg; own-it, non-technical
  • Introduction to Buddhism: Teachings, History and Practices, an; Harvey; non-technical, own-it
  • Meditations; Marcus Aurelius; non-technical, own-it

wip (2):

  • Continuous Delivery; Humble, Farley; own-it
  • Prince, the; Macchiavello; non-technical, own-it

done:

  • Senior software developer, the; Copeland; own-it
  • Scandal in Bohemia, a; Doyle; own-it
  • Getting things done, …; Allen (+); own-it, non-technical
  • Nature of Software Development, the; Jeffries; own-it
  • Team Geek; Fitzpatrick, Collins-Sussman; own-it
  • Aprendo Yoga; Van Lysebeth; non-technical, own-it
  • Clean Coder: A Code of Conduct for Professional Programmers, the; Martin; own-it
  • ML for the working programmer, 2nd edition [5th chapter only]; Paulson; own-it
  • Lazarillo de Tormes, el; anónimo; non-technical
  • Tom Clancy’s power plays - Politika; Preisler; own-it, non-technical
  • Moon is a harsh mistress, the; Heinlein; own-it, non-technical
  • Old man’s war; Scalzi; non-technical, own-it
  • Nightfall; Asimov, Silverberg; own-it, non-technical
  • Interface; Stephenson, George; non-technical, own-it
  • Man who sold the moon, the; Heinlein; own-it, non-technical
  • Agents of innocence; Ignatius; own-it, non-technical
  • Fist of god, the; Forsyth; own-it, non-technical
  • Avaro, el; Molière; own-it, non-technical
  • Bogleheads’ Guide to Investing, the; Larimore, Lindauer, LeBoeuf; own-it, non-technical, finance
  • Lazyperson’s guide to investment; Farrell; own-it, non-technical, finance
  • Millionaire next door, the; Stanley, Danko; own-it, non-technical, finance
  • Little Book of Common Sense Investing; Bogle; own-it, non-technical, finance
  • Monje que vendió su Ferrari, el; Sharma; own-it, non-technical
  • Siddhartha; Hesse; non-technical, own-it
  • If you can: how millenials can get rich slowly; Bernstein; own-it, non-technical, finance
  • Odessa; Forsyth; non-technical, own-it
  • Bogle on mutual funds: new perspectives for the intelligent investor; Bogle; own-it, non-technical, finance
  • Perros de la guerra, los; Forsyth; own-it, non-technical
  • avaro y el oro, el; Esopo; non-technical
  • Aulularia; Plauto; own-it, non-technical
  • Tus zonas erróneas; Dyer; non-technical, own-it
  • Alternativa del Diablo, la; Forsyth; own-it, non-technical
  • Guía, el; Forsyth; own-it, non-technical
  • Pied piper; Forsyth; own-it, non-technical
  • Hunt for the Red October, the; Clancy; own-it, non-technical
  • Peopleware; DeMarco, Lister (+); own-it
  • Time to kill, a; Grisham; own-it, non-technical
  • Ética promiscua; Easton, Hardy; own-it, non-technical
  • Checklist manifesto, the; Gawande; own-it, non-technical, guillem
  • Team geek (+); guillem, own-it
  • Kata de la voluntad; guillem, non-technical
  • Phoenix project, the ; Kim, Behr, Spafford; own-it
  • Obstacle is the way, the; guillem, non-technical
  • Guide to stoicism, a; Stock; own-it, non-technical. A

rejected:

  • Stanger in a strange land; Heinlein; own-it, non-technical

lists:

Self-Study in February 2018

Feb 1, 2018 - 1 minute read - Comments - self-study-aggregationfebruary2018

Contract test

I’ve read this bliki article by Martin Fowler on how to test the integration with external service providers. On how it should be integrated into the building pipeline, but maybe not fail exactly as the rest.

Tags: bliki, martin-fowler, contract-test, microservices, pact, integration-test, pipeline, continuous-integration