Created
July 24, 2018 05:44
-
-
Save jserle/e7a0220708e699dd1d877aaf3f5f01fb to your computer and use it in GitHub Desktop.
Test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Thought process notes | |
// | |
// -------------------------------------------- | |
// Step 1. Quick Review of Req's before coding® | |
// -------------------------------------------- | |
// | |
// Requirement 1: method/class/component to calculate sum | |
// of even numbers of fib seq. (each num sub of 2 prev.) | |
// - will need std. recursion with end condition based on current <= 4m | |
// | |
// Requirement 2: "Could be incorporated into a larger project" | |
// - init webpack? export module? (nah, just a 1hr test, 1-file, non-concat approach for now) | |
// - es6 or es5? (tbd, we'll see what's faster if no bigger picture req provided) | |
// - stay congnizant of component signature, straightfwd interface for public access, | |
// private methods if nec | |
// | |
// Requirement 3: "...evaluated for readability, testability, extensability" | |
// - readability - should stick with clean JS conventions, consistent | |
// spacing, useful variable and method names, (no functions named `func` or `doStuff`) | |
// - testability - code should provide consistent output for whatever testing | |
// framework will be implemented | |
// - extensability - always code with an eye for the future. How might this be used | |
// in varying circumstances and by consuming code? What extensions/modifications would be | |
// meaningful considering the deliverables specified? | |
// > for now, req indicates we/re just returning a numeric value | |
// based on fixed parameters. Conceivably in future, SCF HR team may want to evaluate | |
// more than just dev skills, but also want to know if dev work machine can handle | |
// huge numbers, so provided 4m limit may need to become a param | |
// > for now, req indicates we begin the fib seq from 1, that may change if SCF | |
// decides they want to throw minor twist in the dev test | |
// > if the purpose of this method/class/component is to test developers and their | |
// ability to show structured, reasonable thought processes, why stick with a fib seq? | |
// Perhaps the class should provide the ability for completely different sequence | |
// function to be swapped in? (OK, that's a bit heavy for a 1-hour test. "out of scope") | |
// > It's conceivable that SCF will want to mix things up by adding the odd numbers, | |
// not even | |
// | |
// Requirement 4: "clear communication around your approach" | |
// - communication, yes. clear, another story :) | |
// | |
// Requirement 5: "We also are looking for written tests to prove functionality" | |
// - Makes sense. Should we go ahead and scaffold out a test framework on Jest or Jasmine? | |
// Ok, we have only 1 hour and expected output is a gist. We'll go with a homegrown, inline | |
// test runner for now | |
// | |
// Requirement 6: "...With a plan for further extensability" | |
// - Seems to be a restatement of Requirement 3.2 | |
// | |
// | |
// ---------------------------------------------- | |
// Step 2. Getting Ready to Code let's plan this® | |
// ---------------------------------------------- | |
// - name of class/method/component? | |
// > What's the purpose of this piece of code? Is it really just about calculating | |
// some arbitraty numbers, or is it a well-thought-out project to be included | |
// in HR's toolkit for repeated modification and re-use over the years to come? | |
// > ok, let's go with "DevTestNumberCalculator" | |
// - ok great, what about method sig? | |
// > let's think about consuming code for a sec. one might that be like? | |
// > best guess: part of HR's central portal for automatically testing | |
// developer coding exercise submissions | |
// > OK, in that case it could be imported and instantiated in a "DevTestRunner" component. | |
// In that use case, we may want to pass *in* the expected result and use this component | |
// as an assertion, which should throw an error on failure instead of just returning a number. | |
// > We may also want to test the developer's coding efficiency by doing a bit of runtime | |
// profiling for execution time in milliseconds, or perhaps memory/CPU usage | |
// - for now, we'll seek to hit the nail on the head with a minimal MVP approach based on the | |
// requirements provided | |
// | |
// ----------------------------- | |
// Step 3. Let's write the tests | |
// ----------------------------- | |
// - OK, testing a function that's supposed to product a specific, unknown output | |
// is kinda tricky. | |
// - first let's through together a "testing framework in a tweet" | |
function assert(assertionValue, assertionName) { | |
if (assertionValue === true) { | |
console.log(assertionName, " succeeded"); | |
} else { | |
console.error(assertionName, " failed"); | |
} | |
} | |
// - now, here's where we get stuck in testing for scenarios w/out clear inputs and outputs: | |
function assertCalculatorReturnsTheCorrectAnswer() { | |
let theCorrectAnswer = null; // ? | |
let calculator = new DevTestNumberCalculator(); | |
assert(calculator.calculate() === theCorrectAnswer, | |
'DevTestNumberCalculator Returns the correct answer'); | |
} | |
// - OK, that didn't work, so let's dive deeper into the code architecture to see if | |
// we can come up with some useful test cases | |
// | |
// ---------------------------------- | |
// Step 4. Deep analysis+Coding time® | |
// ---------------------------------- | |
// | |
// - starting point: simple class that defines data members | |
// that can provide future extensibility | |
// - start from basic fibonacci recursion function | |
// - since we need to add up even numbers from the sequence, we need to | |
// either a) calculate this using an "as we go" approach, or | |
// b) first do the fibonacci cycle, then review the values we've stored | |
// - the first approach seems more memory/time efficient, let's start with that first | |
// - also, we need to go beyond a standard fibonacci approach of "pass in a number to calc" | |
// and instead contrive a "run until" approach. | |
// - first off, the above discussion leads us to at least one more test cases | |
// - now, in order to be able to test this, we can see that the class needs to | |
// track and expose it's iteration data, and expose a param | |
// to dictate how long we should iterate. | |
function assertCalculatorStopsIteratingWhenMaxReached() { | |
let stopNumber = 4000000; | |
let calculator = new DevTestNumberCalculator(stopNumber); | |
calculator.calculate(stopNumber); | |
let storage = calculator.getStorage(); | |
// get the last value in storage object | |
let maxValue = storage[Object.keys(storage).slice(-1)[0]] | |
// should be able to do something like: | |
assert(stopNumber >= maxValue, | |
'Calculator correctly iterated until stop number was reached'); | |
} | |
// - the problem with the above approach is that in the fib seq, when we go from the | |
// 33rd to the 34th position, we jump from the 3 millions to the 5m's. | |
// (time to fire off a quick slack msg to the PM or client to make sure we're on the right track!) | |
// - with the above in mind, let's go ahead and give the actual class a shot: | |
function DevTestNumberCalculator (stopNumber) { | |
this.storage = {}; | |
this.stopNumber = stopNumber; | |
this.didReachStopNumber = false; | |
this.calculate = () => { | |
this.storage = {}; | |
let currentIndex = 0; | |
do { | |
this.runFibonacci(currentIndex++); | |
} while (!this.didReachStopNumber); | |
}; | |
this.getStorage =() => { | |
return this.storage; | |
}; | |
this.runFibonacci = (currentNumber, stopNumber) => { | |
if (currentNumber in this.storage) { | |
return this.storage[currentNumber]; | |
} | |
let newFibValue = | |
currentNumber < 2 ? currentNumber : | |
this.runFibonacci(currentNumber - 1) + this.runFibonacci(currentNumber - 2); | |
if (newFibValue >= this.stopNumber) { | |
this.didReachStopNumber = true; | |
} | |
this.storage[currentNumber] = newFibValue; | |
return this.storage[currentNumber]; | |
} | |
} | |
// let calculator = new DevTestNumberCalculator(4000000); | |
// let result = calculator.calculate(); | |
// - we're on our way. Now we just need to add the method for adding up even | |
// numbers, and we're good to go for our MVP and demo with marketing. | |
// - first off, another test for the "evens" detection | |
function assertCanExtractEvenValuesFromStorage() { | |
let stopNumber = 4000000; | |
let calculator = new DevTestNumberCalculator(stopNumber); | |
calculator.calculate(stopNumber); | |
let storage = calculator.getStorage(); | |
// more code here | |
} | |
function DevTestNumberCalculator (stopNumber) { | |
this.storage = {}; | |
this.stopNumber = stopNumber; | |
this.didReachStopNumber = false; | |
this.calculate = () => { | |
this.storage = {}; | |
let currentIndex = 0; | |
do { | |
this.runFibonacci(currentIndex++); | |
} while (!this.didReachStopNumber); | |
}; | |
this.addEvens = () => { | |
} | |
this.getStorage =() => { | |
return this.storage; | |
}; | |
this.runFibonacci = (currentNumber, stopNumber) => { | |
if (currentNumber in this.storage) { | |
return this.storage[currentNumber]; | |
} | |
let newFibValue = | |
currentNumber < 2 ? currentNumber : | |
this.runFibonacci(currentNumber - 1) + this.runFibonacci(currentNumber - 2); | |
if (newFibValue >= this.stopNumber) { | |
this.didReachStopNumber = true; | |
} | |
this.storage[currentNumber] = newFibValue; | |
return this.storage[currentNumber]; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment