December 05, 2018
Continuing from the post yesterday when I briefly touched on the concept of creative and defensive programming i thought it would be best to show an example. This example is of a unit that can tell if two words are different by one letter.
In essence it’s a get an implementation that passes the tests to quickly as possible, The advantage of the “creative” mind set encourages experimentation and fast fail/pass cycles in order to reach working solutions.
describe('Validate that two words are different by one letter', () => {
it('WHEN GIVEN two words that are different by one letter, return true', () => {
assert.equal(diff('cat', 'cot'), true)
});
it('WHEN GIVEN two words that are different by one letter THEN return false', () => {
assert.equal(diff('cat', 'dog'), false);
});
// fast "creative" solution
function diff(a, b) {
let count = 0;
for(let i = 0; i < a.length; i+=1) {
if(a[i] !== b[i]) { count += 1;}
}
return count === 1;
}
})
Things that are required,
In the following example, there are some tests and a refactored version of our diff, which has been renamed to diffrenByOneLetter which handles potential use-cases more predictably.
describe('Validate that two words are different by one letter', () => {
it('WHEN GIVEN two words that are different by one letter, return true', () => {
assert.equal(diff('cat', 'cot'), true)
assert.equal(diffrentByOneLetter('cat', 'cot'), true)
});
it('WHEN GIVEN two words that are different by one letter THEN return false', () => {
assert.equal(diff('cat', 'dog'), false);
assert.equal(diffentByOneLetter('cat', 'dog'), false);
});
it('WHEN GIVEN two words which are of unequal sizes of more than one, THEN return false', () => {
assert.equal(diff('foo', 'foods'), false); // Fail
assert.equal(diffrentByOneLetter('foo', 'foods'), false); // Pass
})
// fast "creative" solution
function diff(a, b) {
let count = 0;
for(let i = 0; i < a.length; i+=1) {
if(a[i] !== b[i]) { count += 1;}
}
return count === 1;
}
// defensive approach
function diffrentByOneLetter(firstWord, secondWord) {
// Type checking
if(typeof(firstWord) !== 'string' || typeof(secondWord) !== 'string') {
return false;
}
// exit early if one of the word is longer by more than two characters
const diffrenceInLength = Math.abs(firstWord.length - secondWord.length);
if(diffrenceInLength > 1) { return false; }
// length of the longest word
const maxLength = (
firstWord.legnth < secondWord.length
) ? secondWord.length : firstWord.length;
let numberOfUniqueLetters = 0;
for(let i = 0; i < maxLength; i += 1) {
if(firstWord[i] !== secondWord[i]) {
numberOfUniqueLetters += 1;
}
}
return numberOfUniqueLetters === 1;
}
});
The results of using both minds sets is that when using the “creative mindset” more time can be put in to trying-out solutions with minium time and effort (like the struggle to name things), once a workable solution is found it can then be refined in to a more robust unit by refactoring with a “defensive mind set”.
Watched 7 minutes, 26 seconds, and the Fundamental Theorem of Agile Software Development . The main idea of the talk was to reduce the cost caused by accidental complicity, which in layman terms would making a job more difficult than it needs to be.
Today’s exercise from learn-c-the-hard-way, Intermediate Makefiles was focused building a skeleton project template (for later use) which automates the process and running tests.
Then I read into types of unit tests, specifically stubs, spies and mocks to find out what I didn’t know and when to use each of them. In short spies are callbacks, stubs are simple interfaces /objects for emulating a dependency or parameter so the unit to be tested with controlled values, and mocks duplicate the behaviour of a dependency such as the DOM.
Written by Marc McIntosh Find him on github