Skip to content

Instantly share code, notes, and snippets.

@jserle
Created July 24, 2018 05:44
Show Gist options
  • Save jserle/e7a0220708e699dd1d877aaf3f5f01fb to your computer and use it in GitHub Desktop.
Save jserle/e7a0220708e699dd1d877aaf3f5f01fb to your computer and use it in GitHub Desktop.
Test
// 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