Be creative while inventing ideas, but be disciplined while implementing them.
In this module you will explore different ways to break down and solve coding challenges. Along with structured workflows for approaching challenges, you will learn the JavaScript you need to write clear and maintainable solutions including: reading and writing tests, higher order functions, arrays and object.
What does the function do? What are itβs arguments and itβs return value? How could you use it in a program? Behavior is all about what your function looks like "from the outside", without caring about what is written inside.
Functions behavior is generally described using documentation, unit tests and use cases:
Documentation (JSDoc comment)
/**
* repeats a string a specific number of times
* @param {string} [text=''] - the string to repeat. defaults to empty string
* @param {number} [repetitions=1] - how many times to repeat. defaults to 1
* repetitions cannot be negative, and must be an integer
* @return {string} the text repeated as many times as repetitions
*/
Unit Tests (pass/fail assertions)
describe('repeats a string any number of times:', () => {
describe('an empty string', () => {
it('0 times', () => {
expect(repeatString('', 0)).toEqual('');
});
it('10 times', () => {
expect(repeatString('', 10)).toEqual('');
});
it('100 times', () => {
expect(repeatString('', 100)).toEqual('');
});
});
describe('zero repetitions', () => {
it('"asdf"', () => {
expect(repeatString('asdf', 0)).toEqual('');
});
it('"tommywalk"', () => {
expect(repeatString('tommywalk', 0)).toEqual('');
});
});
describe('standard use cases', () => {
it('repeat a phrase 3 times', () => {
expect(repeatString('go to school', 3)).toEqual(
'go to schoolgo to schoolgo to school'
);
});
it('phrases with punctuation', () => {
expect(repeatString('"Go!", said Dr. Seuss?', 2)).toEqual(
'"Go!", said Dr. Seuss?"Go!", said Dr. Seuss?'
);
});
it('special characters', () => {
expect(repeatString('\\ \n \t s', 2)).toEqual('\\ \n \t s\\ \n \t s');
});
});
describe('default values', () => {
it('repetitions default should be 1', () => {
expect(repeatString('asdf')).toEqual('asdf');
});
it('text default should be an empty string', () => {
expect(repeatString()).toEqual('');
});
});
});
Use Cases ("real-world" examples)
// repeating a string inside an I/O loop
let repeatedText = '';
while (true) {
const userString = promptForSomething('input a string to repeat');
const userRepetitions = promptForNumber('how many times to repeat it?');
const repeatedInput = repeatString(userString, userRepetitions);
const userConfirmed = confirm(`is this correct: "${repeatedInput}"`);
if (userConfirmed) {
repeatedText = repeatedInput;
break;
}
}
console.log(repeatedText);
// repeating a string from the DOM
const userString = document.getElementById('text-input').value;
const userRepetitions = document.getElementById('number-input').value;
const repeatedInput = repeatString(userString, userRepetitions);
document.getElementById('repeated-value-display').innerHTML = repeatedInput;
How do you approach solving the problem? There are many strategies to solve the same problem! A way to practice strategy is to think of transforming the arguments to the return value in small steps, focusing on the data not the code. This is the realm of flow charts, diagrams, and pseudo-code.
One way to approach strategy is to solve the problem a few different ways by hand, writing what you expect to change in memory at each step. Like if you were the debugger and you couldn't see the source code. Using a pencil and paper is a the best way to go, pick a few test cases and see how you'd solve them manually.
Here are four possible strategies to approach repeating a string. Each one is written as block comment with step-by-step goals focusing on what should happen at each step, not how it will happen. This type of comment is helpful to include in your code:
Iterate until string is long enough
/* iterating until the new string's length is correct
repeatString(text, repetitions) =>
1. calculate the final length for the new string
2. create a new string to fill with many text's
3. iterate as long as the new string is too short
a. check if the new string is long enough
stop if it is, keep going if it is not
b. append text to the new
c. repeat
return: the new repeated string
*/
Iteration with a stepper variable
/* iterating over the number of repetitions
repeatString(text, repetitions) =>
1. create a new string to fill with many text's
2. create a stepper variable, starting at 0
3. iterate from 0 to repetitions
a. check if stepper is still less than repetitions
keep going if it is, otherwise stop iterating
b. append text to the new string
c. increment the stepper
d. repeat
return: the new repeated string
*/
Recurse with base-case 0
/* recursion with base-case 0
i'm using 0 as the base-case because that is the fewest possible repetitions
zero repetitions is an empty string, so if repetitions is 0 it will return ''
otherwise i'll need to combine the text with a string that has one fewer reptitions
repeatString(text, repetitions) =>
base-case: repetitions is 0
return: an empty string
recursive case: repetitions is greater than 0
nextRepetitions = subtract one from repetitions
recursedValue = recursively call repeatString with text and nextRepetitions
return: text + recursedValue
*/
Native JS methods
/* use built-in .js methods
repeatString(text, repetitions) =>
1. make sure the data is the correct type and format for the method you're using
2. use the method
return: the result
*/
Which language features and which lines of code can you use to make your strategy a reality? There are many ways to code the same strategy. let's look at multiple implementations for each strategy described above, all of these functions will pass the unit tests written in the Behavior section:
While loop, true and break
/* unconventional and pretty old-school
there is a lot of reinventing the wheel
while loops are designed to check conditions
this is not the simplest solution to read or maintin
*/
const repeatString = (text = '', repetitions = 1) => {
const finalLength = text.length * repetitions;
let repeatedText = '';
while (true) {
if (repeatedText.length === finalLength) {
break;
}
repeatedText = repeatedText + text;
}
return repeatedText;
};
While loop, logic in head
/* the cleanest implementation for this strategy
it uses the language feature designed for this type of strategy
*/
const repeatString = (text = '', repetitions = 1) => {
const finalLength = text.length * repetitions;
let repeatedText = '';
while (repeatedText.length < finalLength) {
repeatedText += text;
}
return repeatedText;
};
For loop with only a condition check
/* not the best implementation, it's confusing to read
this strategy does not use stepping, and for loops are designed for stepping
implementing this strategy with a for loop is putting a square peg in a round hole
when someone sees a for loop they expect it to be used like a for loop
this implementation uses a for loop like a while loop
the computer doesn't care, but the intention is confusing for other devs
*/
const repeatString = (text = '', repetitions = 1) => {
const finalLength = text.length * repetitions;
let repeatedText = '';
for (; repeatedText.length < finalLength; ) {
repeatedText += text;
}
return repeatedText;
};
While loop, true and break
/* unconventional and pretty old-school
there is a lot of reinventing the wheel
while loops are designed to check conditions
this is not the simplest solution to read or maintain
*/
const repeatString = (text = '', repetitions = 1) => {
let repeatedText = '';
let count = 0;
while (true) {
if (count === repetitions) {
break;
}
repeatedText += text;
count++;
}
return repeatedText;
};
While loop, condition in head
/* a better way to user the while loop since the condition is known
easier to read and more conventional than the previous implementation
maybe you find this easier to read than a for loop
*/
const repeatString = (text = '', repetitions = 1) => {
let repeatedText = '';
let count = 0;
while (count < repetitions.length) {
repeatedText = repeatedText + text;
count++;
}
return repeatedText;
};
For loop
/* the cleanest implementation for this strategy
it uses the language feature designed for stepping
*/
const repeatString = (text = '', repetitions = 1) => {
let repeatedText = '';
for (let count = 0; count < repetitions.length; count++) {
repeatedText += text;
}
return repeatedText;
};
Ternary Operator
// in all it's ES6 one-line glory
// some people find this easier to read than conditionals
const repeatString = (text = '', repetitions = 1) =>
repetitions === 0 ? '' : text + repeatString(text, nextRepetitions - 1);
Conditional Statement
// good old fashioned conditional blocks
// some people find this easier to read than ternaries
const repeatString = (text = '', repetitions = 1) => {
if (repetitions === 0) {
return '';
} else {
const nextRepetitions = repetitions - 1;
const oneRepetitionShort = repeatString(text, nextRepetitions);
return text + oneRepetitionShort;
}
};
Conditional Statement (tail-call recursion)
/* this implementation is "backwards compatible"
that means that it has a different signature (the extra `repeated` parameter)
but can still replace previous implementations without breaking anything
*/
const repeatString = (text = '', repetitions = 1, repeated = '') => {
if (repetitions === 0) {
return repeated;
} else {
const nextRepeated = repeated + text;
const nextRepetitions = repetitions - 1;
return repeatString(text, nextRepetitions, nextRepeated);
}
};
Sting.prototype.repeat
// short and sweet, no room for mistakes
const repeatString = (text = '', repetitions = 1) => text.repeat(repetitions);
Array.prototype.fill
// less clear and more complex, but still pretty clear to read
const repeatString = (text = '', repetitions = 1) => {
const oneEntryPerRepetition = Array(repetitions).fill(text);
const repeatedString = oneEntryPerRepetition.join('');
return repeatedString;
};
- Getting Started
- Study Tips
- About Programming
- Learning Objectives
- Suggested Study
- Break-Down
- Class Recordings
- study.hackyourfuture.be
- home.hackyourfuture.be
You will need NPM and nvm on your computer to study this material
- Clone this repository:
git clone [email protected]:HackYourFutureBelgium/behavior-strategy-implementation.git
(SSH)git clone https://github.com/HackYourFutureBelgium/behavior-strategy-implementation.git
(HTTPS)gh repo clone HackYourFutureBelgium/behavior-strategy-implementation
(GH CLI)
cd
into the repositorycd behavior-strategy-implementation
Using a browser with good DevTools will make your life easier: Chromium, FireFox, Edge, Chrome
- Install or update the
study-lenses
package globallynpm install -g study-lenses
(if you do not have it already)npm update -g study-lenses
(if you already have it installed)
- Run the
study
command from your CLIstudy
- The material will open in your default browser, you're good to go!
- if a
.test.js
file does not work, you can manually check on tests from the config options
- if a
If you have a windows computer and get this error:
... /study.ps1 cannot be loaded because running scripts ...
follow the instructions in this StackOverflow answer, that should take care of it ; )
The debugger built into VSCode is very good, it's all you'll need. Don't forget to set breakpoints!
- Running files in
.js
(without.test
):- debugger: open the file, select the debug option from your VSCode side-bar, choose the
Current JS File (no tests)
option, and click the triangle button. (hint you will need to use breakpoints) - console:
node path/to/file.js
, simple and easy
- debugger: open the file, select the debug option from your VSCode side-bar, choose the
- Running files ending in
.test.js
or.spec.js
:- debugger: open the file, select the debug option from your VSCode side-bar, choose the
Current JS File (with tests)
option, and click the triangle button. (hint: you will need to use breakpoints) - console: files ending in .test.js or .spec.js must be run with
npm run test -- path/to/file.test.js
.
- debugger: open the file, select the debug option from your VSCode side-bar, choose the
- Don't rush, understand! Programming is hard.
- The examples and exercises will still be there to study later.
- It's better to fail tests slowly and learn from your mistakes than to pass tests quickly and not understand why.
- Don't skip the examples! Understanding and experimenting with working code is a very effective way to learn programming.
- Write lots of good comments, learn more about this in ./studying-javascript
- Practice Pair Programming: two people, one computer.
- Take a look through the Learning From Code guide for more study tips
If you can't finish all the material in this repository, that's expected! Anything you don't finish now will always be waiting for you to review when you need it. These 3 emoji's will help you prioritize your study time and to measure your progress:
- π₯
:egg:
- Understanding this material is required, it covers the base skills you'll need for this module and the next. You do not need to finish all of them but should feel comfortable that you could with enough time. - π£
:hatching_chick:
- Do your best to start this material. you don't need to master it or finish it but getting the main idea will be helpful for taking the next steps. - π₯
:hatched_chick:
- Have you finished all the π₯'s and started all the π£'s? push yourself with these challenges.
There's sooo many examples and exercises in this repository, it's easy to forget of what you still need to finish or what you want to review again. Luckily VSCode is really good at searching through folders of code.
You can write hashtags in your comments while you're studying, then search for those hashtags later so you don't miss anything. Here's some ideas:
// #not-done, still a few blanks left
- search for#not-done
in VScode to find all the exercises you've started and not finished// coercion is confusing, #review this again next week
- search for#review
to find the files you need to study again- ... anything goes! Find the hashtags that work for you
If you create a fork of this repository you can open a project board in your fork to track your progress through the module. Just 3 columns can be enough: Todo, Doing, Done.
What can you expect to learn in this module?
expand/collapse
- Learning from Code
- Reading & understanding other people's code
- Making small, incremental experiments
- Copying & modifying others' code
- Reading and writing unit tests
describe
it
expect(actual).toEqual(expected)
- TDD
- Trust the tests!
- Solving challenges one test at a time
- Debugging
- Stepping through tests in the debugger
- Reading test results to debug code behavior
- Interpreting assertion errors
- Reading and writing documentation
- Code review
Helpful resources for this module
expand/collapse
- Separate Repositories
- π₯,π£,π₯: Solution Write-Ups Learn to solve coding challenges by studying other people's solutions.
- Fork the repository
- Clone your fork
- Push your work regularly so others can study it
- π£: document-and-pass: write your own solutions and documentation to some coding challenges. Practice debugging and using testing libraries in VSCode
- π£: practice-code-review (coming soon for week 3)
- π₯,π£,π₯: Solution Write-Ups Learn to solve coding challenges by studying other people's solutions.
- In this Repo
- π₯: ./about-testing: A quick introduction to
describe
,it
, andexpect
- π₯: ./array-methods: Learn array methods by first understanding the strategies they are designed for.
- π£ ./hoisting: That famous thing about JS! It's not so bad once you get it, the key to understanding hoisting is to understand the program life-cycle: creation phase and execution phase. This chapter is more abstract, hoisting is something "invisible" about JavaScript program execution. These exercises will help you see hoisting by exploring the debugger at different points in program execution.
- π£: ./parsons-problems: Explore behavior, strategy and implementation by reconstructing different solutions to coding challenges.
- π£: ./function-design: Learn a structured approach to understanding and solving coding challenges
- π₯: ./about-testing: A quick introduction to
- π₯: More Practice:
Are we missing a great set of exercises? Send a PR!
- FunFunFunction:
- js-unit-testing-guide (very detailed)
- javascript.info
- FunFun: Map, Reduce Basics
- CYF
- Una Kravets
- Cheat Sheet
- Oliverjam: learn-map-filter, tdd-array-methods
- short, sweet, with a loop (video)
- Sorting an Array of Objects (video)
- another Sorting (video+article)
- Search from Array of Objects (video)
- Create, Update and Loop (article)
- The Coding Train (video)
The best problem solvers don't start from nothing, they've seen many similar problems before and have learned to adapt other people's code to fit their programs.
This week take your first step to becoming an expert problem solver by studying the many ways people before you have solved common problems.
expand/collapse
- Fork solution-write-ups
- Read through the README, this will be your main exercise for the week.
- create a new folder called
add-up-the-numbers-from-a-single-number
- create a README.md file in this folder using the
write-up-template.md
- create an empty javascript file called
sandbox.test.js
- Read through ./about-testing/examples to be familiar with the syntax for
describe
,it
, andexpect
- Create an account on Edabit
In class you will practice writing tests and analyzing solutions using a challenge from Edabit:
Description, Syntax, Test Cases and Use Cases.
- All together:
- look through the examples at the beginning of this README. What is behavior, strategy and implementation?
- go over the README from solution-write-ups
- read through the first 4 sections in the example from solution-write-ups
- In small groups:
- Complete the first 4 sections of the writeup for
Add up the Numbers ...
- You can use the most popular solution solution by _sir to write your tests:
function addUp(num) { return (num * (num + 1)) / 2; }
- Complete the first 4 sections of the writeup for
Strategy, Implementation and Possible Refactors.
-
All together:
- read through the rest of the example in solution-write-ups
-
In small groups:
-
practice writing up 2-3 solutions to the
Add up the Numbers ...
challenge (be sure to test them all!) -
here's a few suggestions to study:
// _sir function addUp(num) { return (num * (num + 1)) / 2; } // Gabriel function addUp(num) { let sum = 0; for (let i = 1; i <= num; i++) { sum += i; } return sum; } // λ²λ function addUp(num) { var a = 0; for (var i = num; i > 0; i--) { a += i; } return a; } // doodledob function addUp(num) { x = 0; while (num >= 0) { x += num; num--; } return x; }
-
Take your time this week to explore other people's code. In the past modules you've studied only a small part of what JS, now you're in the wild! You'll come across all sorts of JS features and new coding styles.
Complete as many write-ups as you can. No need to rush ahead! Take your time studying solutions at your level. It's more helpful to study a variety of solutions than to study a few hard ones:
Here's two important JS concepts you should study while doing your write-ups:
- π£ ./array-methods
- π£ ./hoisting
These exercises will help you understand test cases, and be important for next week:
- π£ ./about-testing
While these are great for when you need a little break:
- π£ ./parsons-problems
Learn to write unit tests and to write your own solutions one step at a time.
expand/collapse
Read through the steps of Function Design and study the example
Continue writing Solution Write-Ups. To help you gain a deeper understanding of how to write your own solutions, take some time to study these exercises:
- π£ ./about-testing
- π£ ./parsons-problems
- π£ ./function-design
Just like last week, there's no reason to rush yourself. You can learn how to write tests and how to design functions with simple challenges just as well as with hard challenges. So find your level, settle in, and study as many problems as you can.
Code Review! Practice reviewing
- Students: Here you can find recordings of this module from past classes. Enjoy!
- Do you have a favorite? Send a PR giving it a π
- Coaches: When sending your PR's with links please ...
- Indicate which class you were teaching
- Which week it was (if the module is more than 1 week)
- Give your name
- and a helpful description
- Week 1:
- Sunday Part 1: Reference vs. Value
- Sunday Part 1: Map, Reduce, Filter, Every
- Sunday Part 2: Mini-project intro
- Sunday Part 3: Recap & Homework
- Week 2:
- Sunday Part 1: The Callstack
- Sunday Part 1: Higher Order Functions
- Sunday Part 1: Arrows vs. Functions
- Sunday Part 1: Error: EADDRINUSE
- Sunday Part 2: Reverse-Engineering
- Sunday Part 2: R-E & Assignments
- Week 3:
- Sunday Part 1: Objects 1
- Sunday Part 1: Objects 2
- Sunday Part 2: User input in Objects
- Week 1
- Week 2 - server crash :(
- Week 3: Objects Pt. 1, Objects Pt. 2, Project Intro