Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions 2-write-test-case/1-function-design/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Function Design

Solving code challenges doesn't need to be like walking in the dark.
We can't provide you with a perfect recipe to solve every problem, but there are some steps you can take to learn a structured workflow.
The goal of the examples and exercises in this folder is to help you explore a _function design workflow_ that you can master
and apply in your own projects.

This README is a big-picture walk through this workflow, the `./examples` directory will go into more detail.
The format of these exercises will take a little time to get used to, but that's all part of the learning!

- [The Workflow](#the-workflow)
- <a href='./examples?hyf' target='_blank'>Examples</a> : contains a .js file for each step in the workflow for an example problem.
- <a href='./exercises?hyf' target='_blank'>Exercises</a> : contains only one .js file per problem. You will solve it step by step in the same file.
- [References](#references)

---

## The Workflow

0. Starter Code
1. Write Tests
1. Find a Strategy
1. Design Cycles
1. More Strategies

Your first instinct may be to just start writing a function hoping for the best.
This workflow will help you work against that instinct and build new ones.
You will first think about

1. how to describe the function's behavior (JSDoc description)
2. what types go in and out of your function (JSDoc @params & @returns)
3. how the function behaves (test cases)
4. how you can approach the problem (a strategy)
5. and finally ... what code to write (implementation)

One of the trickiest (but most important!) parts of this workflow will be writing tests for the challenge _before_ writing your solution.
Writing tests is not easy to learn but is worth the effort.
Writing tests will force you to understand the challenge from the outside in and will not let you get away with a half-understanding.
Building this understanding before writing your function will make the problem solving and debugging easier.

### 0. Starter Code

- <a href='./examples/repeat-a-string/0-starter-code.test.js?study' target='_blank'>./examples/repeat-a-string/0-starter-code.test.js</a>

Each challenge will come with some starter code that includes:

- a JSDoc describing the challenge
- test cases (sometimes empty, sometimes started)
- a secret solution that you can use to write tests

---

### 1. Write Tests

> some exercises will come with starter tests, that's just a start. add more!

- <a href='./examples/repeat-a-string/1-write-tests.test.js?study' target='_blank'>./examples/repeat-a-string/1-write-tests.test.js</a>

Don't rush this step! Taking a little extra time to think about your function's behavior and
to consider [_edge cases_](https://www.geeksforgeeks.org/dont-forget-edge-cases/) will help in more than one way:

1. You will better understand the problem, so solving it will be easier.
2. You can have more confidence in your solution since the tests are more thorough.
3. Debugging will be easier when you have a clear idea of the expected results.

In these exercises you will always write your tests by calling `solution()`, this is to use the variable declared in the testing loop. If you call a different function than `solution`, you will not be able to run your tests against different solutions.

To help you write good tests, each exercise has a compressed, complicated, and hard-to-read solution included in the file (don't cheat! honor code.).
You will use this `secretSolution` to test your tests. There's nothing more frustrating than trying to use broken tests.
If your tests are wrong, it becomes nearly impossible to debug your solution!
So be sure to run your tests against the `secretSolution` before testing your own solution.
If a test fails the `secretSolution` then you know the test is bad, adjust it until it passes before moving on.

Finally, don't worry yourself trying to write perfect tests for every possible case. You can always add more tests as you design your solution.

---

### 2. First Strategy

- <a href='./examples/repeat-a-string/2-first-strategy.test.js?study' target='_blank'>./examples/repeat-a-string/2-first-strategy.test.js</a>

Think of a first strategy for solving this challenge. You might write is as numbered steps, pseudo-code or a short paragraph, whatever helps you most.

Anything goes! This is a chance to think big and imagine new ways you could approach this problem without worrying about how you will code it. You'll explore different implementations in the next step.

---

### 3. Design Cycles

- <a href='./examples/repeat-a-string/3-design-cycles.test.js?study' target='_blank'>./examples/repeat-a-string/3-design-cycles.test.js</a>

Try to write as many implementations as possible for your strategy. Keep all of the, especially the ones that don't work! In this step it's _very_ important that you keep all of your experiments and take notes on what you tried in each one. If you take good notes you can always come back to them when you have a similar problem in a project.

Be sure to run your tests after every small change you make in a function. And don't forget to double check which solutions are commented ;)

---

### 4. More Strategies

- <a href='./examples/repeat-a-string/4-more-strategies.test.js?study' target='_blank'>./examples/repeat-a-string/4-more-strategies.test.js</a>

So you've written a few solutions with your first strategy? Pick a new strategy and try solving it again!

You can often learn more from approaching the same problem in new ways than from always starting a new problem. Being very familiar with what you are trying to achieve frees your mind to be creative.

---

## References

- Similar Online Resources
- Looking for more explanation and a softer start? take a look through these:
- [The Learning Collective JS](http://tlcjs.org/index.html) - chapters 1, 2, 3
- [Systematic Function Design in JS](https://wavded.com/post/htdp-functions/) - short article
- Good Code
- [Improve Code Readability](https://dev.to/briwa/simple-ways-to-improve-code-readability-2n8c)
- [Comments, Clean Code, JS](https://medium.com/better-programming/javascript-clean-code-comments-c926d5aae2cb)
- [Comments: Best Practices](https://www.elegantthemes.com/blog/wordpress/how-to-comment-your-code-like-a-pro-best-practices-and-good-habits)
- [How to Design Programs](https://htdp.org/2019-02-24/part_preface.html)
- This gold-standard textbook is written for the Racket programming language
- The design workflow you will learn in `behavior-strategy-implementation` is inspired by HTDP then adapted for JS and Study Lenses
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// #todo

'use strict';

/* 0. Starter Code

Each exercises will have this format:
- a JSDoc describing the behavior
- an empty space where you'll write your solutions
- a for-of loop with test cases inside
- a secret solution you can use to write tests

*/

// =============== JSDoc description of the challenge ===============

/**
* 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 must be greater than zero, and must be an integer.
* @return {string} The text repeated as many times as repetitions.
*/

// =============== your solutions will go here ===============

// =============== a for-of loop to control which solution(s) are tested ===============

for (const solution of [secretSolution]) {
// =============== test cases for this challenge ===============

describe(solution.name + ': _', () => {
describe('_', () => {
it('_', () => {});
});
});
}

// =============== a minified solution you can use to test your test cases ===============

// prettier-ignore
function secretSolution(a = "", b = 1) { if ("string" != typeof a) { throw new TypeError("text is not a string"); } if ("number" != typeof b) { throw new TypeError("repetitions is not a number"); } if (0 > b) { throw new RangeError("repetitions is less than zero"); } if (!Number.isInteger(b)) { throw new RangeError("repetitions is not an integer"); } return Array(b).fill(a).join(""); }
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// #todo

'use strict';

/* 1. Write Test Cases

Write as many test cases as you can to understand the challenge
try thinking of edge cases!

The secret solution is correct. if your tests fail, fix your tests ;)

After this step you will have a full suite of tests to check your own solutions.

*/

// =============== JSDoc description of the challenge ===============

/**
* 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 must be greater than zero, and must be an integer
* @return {string} the text repeated as many times as repetitions
*/

// =============== your solutions will go here ===============

// =============== a for-of loop to control which solution(s) are tested ===============

for (const solution of [secretSolution]) {
// =============== test cases for this challenge ===============

describe(solution.name + ': repeating a string:', () => {
describe('default parameters', () => {
it('repeat once if no repetitions is passed', () => {
expect(solution('asdf')).toEqual('asdf');
});
it('expect an empty string if no arguments are passed', () => {
expect(solution()).toEqual('');
});
});
describe('an empty string', () => {
it('repeat an empty string 0 times -> ""', () => {
expect(solution('', 0)).toEqual('');
});
it('repeat an empty string 10 times -> ""', () => {
expect(solution('', 10)).toEqual('');
});
it('repeat an empty string 100 times -> ""', () => {
expect(solution('', 100)).toEqual('');
});
});
describe('zero repetitions', () => {
it('repeat "asdf" 0 times -> ""', () => {
expect(solution('asdf', 0)).toEqual('');
});
it('repeat "tommywalk" 0 times -> ""', () => {
expect(solution('tommywalk', 0)).toEqual('');
});
});
describe('standard use cases', () => {
it('repeating a longer phrase 3 times', () => {
expect(solution('go to school', 3)).toEqual(
'go to schoolgo to schoolgo to school'
);
});
it('repeating a phrase with punctuation', () => {
expect(solution('"Go!", said Dr. Seuss?', 2)).toEqual(
'"Go!", said Dr. Seuss?"Go!", said Dr. Seuss?'
);
});
it('a string with special characters can be repeated', () => {
expect(solution('\\ \n \t s', 2)).toEqual('\\ \n \t s\\ \n \t s');
});
});
});
}

// =============== a minified solution you can use to test your test cases ===============

// prettier-ignore
function secretSolution(a = "", b = 1) { if ("string" != typeof a) { throw new TypeError("text is not a string"); } if ("number" != typeof b) { throw new TypeError("repetitions is not a number"); } if (0 > b) { throw new RangeError("repetitions is less than zero"); } if (!Number.isInteger(b)) { throw new RangeError("repetitions is not an integer"); } return Array(b).fill(a).join(""); }
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// #todo

'use strict';

/* 2. First Strategy

Think of a strategy for solving this challenge, it doesn't need to be perfect!

write out your strategy in a block comment, as pseudocode or normal sentences

you will try finding a few implementations for your strategy.

*/

// =============== JSDoc description of the challenge ===============

/**
* 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 must be greater than zero, and must be an integer
* @return {string} the text repeated as many times as repetitions
*/

// =============== your solutions will go here ===============

/* -- iteration: append the string to itself once for each repetition --

1. create a new empty string to store the accumulated result
2. iterate from zero the the number of repetitions
a. add the text to the accumulator one more time
return: the accumulated result

*/

const forLoopTry1 = (text = '', repetitions = 1) => {};

// =============== a for-of loop to control which solution(s) are tested ===============

for (const solution of [
// secretSolution, // <--- comment out the secretSolution
forLoopTry1, // <--- write your function's name here. and you're ready to test!
]) {
// =============== test cases for this challenge ===============

describe(solution.name + ': repeating a string:', () => {
describe('default parameters', () => {
it('repeat once if no repetitions is passed', () => {
expect(solution('asdf')).toEqual('asdf');
});
it('expect an empty string if no arguments are passed', () => {
expect(solution()).toEqual('');
});
});
describe('an empty string', () => {
it('repeat an empty string 0 times -> ""', () => {
expect(solution('', 0)).toEqual('');
});
it('repeat an empty string 10 times -> ""', () => {
expect(solution('', 10)).toEqual('');
});
it('repeat an empty string 100 times -> ""', () => {
expect(solution('', 100)).toEqual('');
});
});
describe('zero repetitions', () => {
it('repeat "asdf" 0 times -> ""', () => {
expect(solution('asdf', 0)).toEqual('');
});
it('repeat "tommywalk" 0 times -> ""', () => {
expect(solution('tommywalk', 0)).toEqual('');
});
});
describe('standard use cases', () => {
it('repeating a longer phrase 3 times', () => {
expect(solution('go to school', 3)).toEqual(
'go to schoolgo to schoolgo to school'
);
});
it('repeating a phrase with punctuation', () => {
expect(solution('"Go!", said Dr. Seuss?', 2)).toEqual(
'"Go!", said Dr. Seuss?"Go!", said Dr. Seuss?'
);
});
it('a string with special characters can be repeated', () => {
expect(solution('\\ \n \t s', 2)).toEqual('\\ \n \t s\\ \n \t s');
});
});
});
}

// =============== a minified solution you can use to test your test cases ===============

// prettier-ignore
function secretSolution(a = "", b = 1) { if ("string" != typeof a) { throw new TypeError("text is not a string"); } if ("number" != typeof b) { throw new TypeError("repetitions is not a number"); } if (0 > b) { throw new RangeError("repetitions is less than zero"); } if (!Number.isInteger(b)) { throw new RangeError("repetitions is not an integer"); } return Array(b).fill(a).join(""); }
Loading