grammar, usage, punctuation edits, Part 1, sections 3.1 - 4.6
This commit is contained in:
parent
fa4a678d53
commit
374db1ebd4
11 changed files with 102 additions and 102 deletions
|
@ -22,7 +22,7 @@ Here's what you should see if you are doing it for the first time:
|
|||
|
||||
The toggler button <span class="devtools" style="background-position:-168px -76px"></span> opens the tab with files.
|
||||
|
||||
Let's click it and select `index.html` and then `hello.js` in the tree view. That's what should show up:
|
||||
Let's click it and select `index.html` and then `hello.js` in the tree view. Here's what should show up:
|
||||
|
||||

|
||||
|
||||
|
@ -36,7 +36,7 @@ Now you could click the same toggler <span class="devtools" style="background-po
|
|||
|
||||
## Console
|
||||
|
||||
If we press `Esc`, then a console opens below, we can type commands there and press `key:Enter` to execute.
|
||||
If we press `Esc`, then a console opens below. We can type commands there and press `key:Enter` to execute.
|
||||
|
||||
After a statement is executed, its result is shown below.
|
||||
|
||||
|
@ -50,7 +50,7 @@ Let's examine what's going on within the code of the [example page](debugging/in
|
|||
|
||||
Congratulations! You've set a breakpoint. Please also click on the number for line `8`.
|
||||
|
||||
Should look like this (blue is where you should click):
|
||||
It should look like this (blue is where you should click):
|
||||
|
||||

|
||||
|
||||
|
@ -67,7 +67,7 @@ We can always find a list of breakpoints in the right pane. That's useful when w
|
|||
```smart header="Conditional breakpoints"
|
||||
*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression is truthy.
|
||||
|
||||
That's handy when we need to stop only for a certain variable value or for a certain function parameters.
|
||||
That's handy when we need to stop only for a certain variable value or for certain function parameters.
|
||||
```
|
||||
|
||||
## Debugger command
|
||||
|
@ -91,13 +91,13 @@ That's very convenient when we are in a code editor and don't want to switch to
|
|||
|
||||
## Pause and look around
|
||||
|
||||
In our example, `hello()` is called during the page load, so the easiest way to activate debugger -- is to reload the page. So let's press `key:F5` (Windows, Linux) or `key:Cmd+R` (Mac).
|
||||
In our example, `hello()` is called during the page load, so the easiest way to activate the debugger is to reload the page. So let's press `key:F5` (Windows, Linux) or `key:Cmd+R` (Mac).
|
||||
|
||||
As the breakpoint is set, the execution pauses at the 4th line:
|
||||
|
||||

|
||||
|
||||
Please open the informational dropdowns to the right (labelled with arrows). They allow you to examine the current code state:
|
||||
Please open the informational dropdowns to the right (labeled with arrows). They allow you to examine the current code state:
|
||||
|
||||
1. **`Watch` -- shows current values for any expressions.**
|
||||
|
||||
|
@ -129,9 +129,9 @@ There are buttons for it at the top of the right pane. Let's engage them.
|
|||
|
||||

|
||||
|
||||
The execution has resumed, reached another breakpoint inside `say()` and paused there. Take a look at the "Call stack" at the right. It has increased by one more call. We're inside `say()` now.
|
||||
The execution has resumed, reached another breakpoint inside `say()` and paused there. Take a look at the "Call stack" at the right. It has increased by one more call. We're inside `say()` now.
|
||||
|
||||
<span class="devtools" style="background-position:-137px -76px"></span> -- make a step (run the next command), but *not go into the function*, hotkey `key:F10`.
|
||||
<span class="devtools" style="background-position:-137px -76px"></span> -- make a step (run the next command), but *don't go into the function*, hotkey `key:F10`.
|
||||
: If we click it now, `alert` will be shown. The important thing is that `alert` can be any function, the execution "steps over it", skipping the function internals.
|
||||
|
||||
<span class="devtools" style="background-position:-72px -76px"></span> -- make a step, hotkey `key:F11`.
|
||||
|
@ -149,7 +149,7 @@ There are buttons for it at the top of the right pane. Let's engage them.
|
|||
```smart header="Continue to here"
|
||||
Right click on a line of code opens the context menu with a great option called "Continue to here".
|
||||
|
||||
That's handy when we want to move multiple steps forward, but too lazy to set a breakpoint.
|
||||
That's handy when we want to move multiple steps forward, but we're too lazy to set a breakpoint.
|
||||
```
|
||||
|
||||
## Logging
|
||||
|
@ -165,20 +165,20 @@ for (let i = 0; i < 5; i++) {
|
|||
}
|
||||
```
|
||||
|
||||
Regular users don't see that output, it is in the console. To see it -- either open the Console tab of developer tools or press `key:Esc` while in another tab: that opens the console at the bottom.
|
||||
Regular users don't see that output, it is in the console. To see it, either open the Console tab of developer tools or press `key:Esc` while in another tab: that opens the console at the bottom.
|
||||
|
||||
If we have enough logging in our code, then we can see what's going on from the records, without the debugger.
|
||||
|
||||
## Summary
|
||||
|
||||
As we can see, there are 3 main ways to pause a script:
|
||||
As we can see, there are three main ways to pause a script:
|
||||
1. A breakpoint.
|
||||
2. The `debugger` statements.
|
||||
3. An error (if dev tools are open and the button <span class="devtools" style="background-position:-264px -4px"></span> is "on")
|
||||
|
||||
Then we can examine variables and step on to see where the execution goes the wrong way.
|
||||
Then we can examine variables and step on to see where the execution goes wrong.
|
||||
|
||||
There's much more options in developer tools than covered here. The full manual is at <https://developers.google.com/web/tools/chrome-devtools>
|
||||
There are many more options in developer tools than covered here. The full manual is at <https://developers.google.com/web/tools/chrome-devtools>
|
||||
|
||||
The information from this chapter is enough to begin debugging, but later, especially if you do a lot of browser stuff, please go there and look through more advanced capabilities of developer tools.
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ if (n < 0) {
|
|||

|
||||
|
||||
As a summary:
|
||||
- For a really short code one line is acceptable: like `if (cond) return null`.
|
||||
- For a really short code, one line is acceptable: like `if (cond) return null`.
|
||||
- But a separate line for each statement in brackets is usually better.
|
||||
|
||||
### Line length
|
||||
|
@ -94,7 +94,7 @@ There are two types of indents:
|
|||
|
||||
A horizontal indentation is made using either 2 or 4 spaces or the "Tab" symbol. Which one to choose is an old holy war. Spaces are more common nowadays.
|
||||
|
||||
One of advantages of spaces over tabs is that spaces allow more flexible configurations of indents than the "Tab" symbol.
|
||||
One advantage of spaces over tabs is that spaces allow more flexible configurations of indents than the "Tab" symbol.
|
||||
|
||||
For instance, we can align the arguments with the opening bracket, like this:
|
||||
|
||||
|
@ -125,11 +125,11 @@ There are two types of indents:
|
|||
}
|
||||
```
|
||||
|
||||
Insert an extra newline where it helps to make the code more readable. There should not be more than 9 lines of code without a vertical indentation.
|
||||
Insert an extra newline where it helps to make the code more readable. There should not be more than nine lines of code without a vertical indentation.
|
||||
|
||||
### A semicolon
|
||||
|
||||
A semicolon should be present after each statement. Even if it could be possibly be skipped.
|
||||
A semicolon should be present after each statement. Even if it could possibly be skipped.
|
||||
|
||||
There are languages where a semicolon is truly optional. It's rarely used there. But in JavaScript there are few cases when a line break is sometimes not interpreted as a semicolon. That leaves a place for programming errors.
|
||||
|
||||
|
@ -160,7 +160,7 @@ for (let i = 0; i < 10; i++) {
|
|||
}
|
||||
```
|
||||
|
||||
The similar thing can be done with `if/else` and `return`.
|
||||
A similar thing can be done with `if/else` and `return`.
|
||||
|
||||
For example, two constructs below are identical.
|
||||
|
||||
|
@ -258,11 +258,11 @@ That's because when reading a code, we first want to know "what it does". If the
|
|||
|
||||
## Style guides
|
||||
|
||||
A style guide contains general rules about "how to write": which quotes to use, how many spaces to indent, where to put line breaks etc. A lot of minor things.
|
||||
A style guide contains general rules about "how to write": which quotes to use, how many spaces to indent, where to put line breaks, etc. A lot of minor things.
|
||||
|
||||
In total, when all members of a team use the same style guide, the code looks uniform. No matter who of the team wrote it, still the same style.
|
||||
In total, when all members of a team use the same style guide, the code looks uniform. No matter who of the team wrote it, it's still the same style.
|
||||
|
||||
Surely, a team may think out a style guide themselves. But as of now, there's no need to. There are many tried, worked out style guides, easy to adopt.
|
||||
Surely, a team may think out a style guide themselves. But as of now, there's no need to. There are many tried, worked-out style guides, which are easy to adopt.
|
||||
|
||||
For instance:
|
||||
|
||||
|
@ -321,7 +321,7 @@ Then install/enable the plugin for your editor that integrates with ESLint. The
|
|||
|
||||
It is possible to download style rule sets from the web and extend them instead. See <http://eslint.org/docs/user-guide/getting-started> for more details about installation.
|
||||
|
||||
Using a linter has the great side-effect. Linters catch typos. For instance, when an undefined variable is accessed, a linter detects it and (if integrated with an editor) highlights. In most cases that's a mistype. So we can fix it right ahead.
|
||||
Using a linter has a great side-effect: linters catch typos. For instance, when an undefined variable is accessed, a linter detects it and (if integrated with an editor) highlights it. In most cases that's a mistype. So we can fix it right ahead.
|
||||
|
||||
For that reason even if you're not concerned about styles, using a linter is highly recommended.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Comments are generally a good thing. But novices in programming generally get th
|
|||
|
||||
But the amount of such "explanatory" comments should be minimal.
|
||||
|
||||
Seriously, a good code should be easy to understand without them.
|
||||
Seriously, good code should be easy to understand without them.
|
||||
|
||||
There's a great rule about that: "if the code is so unclear that it requires a comment, then maybe it should be rewritten instead".
|
||||
|
||||
|
@ -122,14 +122,14 @@ Document a function usage
|
|||
}
|
||||
```
|
||||
|
||||
Such comments allow to understand the purpose of the function and use it the right way without looking in its code.
|
||||
Such comments allow us to understand the purpose of the function and use it the right way without looking in its code.
|
||||
|
||||
By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking.
|
||||
|
||||
Also, there are tools like [JSDoc 3](https://github.com/jsdoc3/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at <http://usejsdoc.org/>.
|
||||
|
||||
Why the task is solved this way?
|
||||
: What's written is important. But what's *not* written maybe even more important to understand what's going on. Why the task is solved exactly this way? The code gives no answer.
|
||||
Why is the task solved this way?
|
||||
: What's written is important. But what's *not* written maybe even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer.
|
||||
|
||||
If there are many ways to solve the task, why this one? Especially when it's not the most obvious one.
|
||||
|
||||
|
@ -145,6 +145,6 @@ Any subtle features of the code? Where they are used?
|
|||
|
||||
## Summary
|
||||
|
||||
One of signs of a good developer is his comments. Good comments allow to maintain the code well, return to it after a long delay and use features more effectively.
|
||||
One sign of a good developer is his comments. Good comments allow us to maintain the code well, return to it after a long delay and use features more effectively.
|
||||
|
||||
Comments are also used for auto-documenting tools: they read them and generate HTML-docs (or in another format).
|
||||
|
|
|
@ -38,13 +38,13 @@ Another way to code faster (and much worse!) is to use single-letter variable na
|
|||
|
||||
A short variable disappears in the code like a real ninja in the forest. No one will be able to find it using "search" of the editor. And even if someone does, he won't be able to "decipher" what the name `a` or `b` means.
|
||||
|
||||
...But there's an exception. A real ninja will never use `i` as the counter in a `"for"` loop. Anywhere, but not here. Look around, there are so much more exotic letters. For instance, `x` or `y`.
|
||||
...But there's an exception. A real ninja will never use `i` as the counter in a `"for"` loop. Anywhere, but not here. Look around, there are many more exotic letters. For instance, `x` or `y`.
|
||||
|
||||
An exotic variable as a loop counter is especially cool if the loop body takes 1-2 pages (make it longer if you can). Then if someone looks deep inside the loop, he won't be able to figure out fast that the variable named `x` is the loop counter.
|
||||
An exotic variable as a loop counter is especially cool if the loop body takes 1-2 pages (make it longer if you can). Then if someone looks deep inside the loop, he won't be able to quickly figure out that the variable named `x` is the loop counter.
|
||||
|
||||
## Use abbreviations
|
||||
|
||||
If the team rules forbid to use one-letter and vague names -- shorten them, make abbreviations.
|
||||
If the team rules forbid the use of one-letter and vague names -- shorten them, make abbreviations.
|
||||
|
||||
Like this:
|
||||
|
||||
|
@ -53,7 +53,7 @@ Like this:
|
|||
- `browser` -> `brsr`.
|
||||
- ...etc
|
||||
|
||||
Only the one with a truly good intuition will be able to understand such names. Try to shorten everything. Only a worthy person should be able to uphold the development of your code.
|
||||
Only the one with truly good intuition will be able to understand such names. Try to shorten everything. Only a worthy person should be able to uphold the development of your code.
|
||||
|
||||
## Soar high. Be abstract.
|
||||
|
||||
|
@ -66,7 +66,7 @@ The great image has no form.
|
|||
|
||||
While choosing a name try to use the most abstract word. Like `obj`, `data`, `value`, `item`, `elem` and so on.
|
||||
|
||||
- **The ideal name for a variable is `data`.** Use it everywhere where you can. Indeed, every variable holds *data*, right?
|
||||
- **The ideal name for a variable is `data`.** Use it everywhere you can. Indeed, every variable holds *data*, right?
|
||||
|
||||
...But what to do if `data` is already taken? Try `value`, it's also universal. After all, a variable eventually gets a *value*.
|
||||
|
||||
|
@ -74,9 +74,9 @@ While choosing a name try to use the most abstract word. Like `obj`, `data`, `va
|
|||
|
||||
Give them a try. A young ninja may wonder -- do such names make the code worse? Actually, yes!
|
||||
|
||||
From one hand, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code -- he'll be surprised to see that there's actually no information at all!
|
||||
From one hand, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, he'll be surprised to see that there's actually no information at all!
|
||||
|
||||
Indeed, the value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number it stores? There's just no way to figure out without a good meditation!
|
||||
Indeed, the value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? There's just no way to figure out without a good meditation!
|
||||
|
||||
- **...But what if there are no more such names?** Just add a letter: `item1, item2, elem5, data1`...
|
||||
|
||||
|
@ -182,9 +182,9 @@ function render() {
|
|||
}
|
||||
```
|
||||
|
||||
A programmer who jumps inside the `render` will probably miss to notice that there's a local `user` shadowing the outer one.
|
||||
A programmer who jumps inside the `render` will probably fail to notice that there's a local `user` shadowing the outer one.
|
||||
|
||||
Then he'll try to work with `user` it assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger...
|
||||
Then he'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger...
|
||||
|
||||
|
||||
## Side-effects everywhere!
|
||||
|
@ -223,6 +223,6 @@ Imagine, another developer wants only to check the email, and not output any mes
|
|||
|
||||
All "pieces of advice" above are from the real code... Sometimes, written by experienced developers. Maybe even more experienced than you are ;)
|
||||
|
||||
- Follow some of them -- and your code will become full of surprises.
|
||||
- Follow many of them -- and your code will become truly yours, no one would want to change it.
|
||||
- Follow all -- and your code will become a valuable lesson for young developers looking for enlightment.
|
||||
- Follow some of them, and your code will become full of surprises.
|
||||
- Follow many of them, and your code will become truly yours, no one would want to change it.
|
||||
- Follow all, and your code will become a valuable lesson for young developers looking for enlightenment.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Automated testing with mocha
|
||||
|
||||
Automated testing will be used further in tasks.
|
||||
Automated testing will be used in further tasks.
|
||||
|
||||
It's actually a part of the "educational minimum" of a developer.
|
||||
|
||||
|
@ -8,19 +8,19 @@ It's actually a part of the "educational minimum" of a developer.
|
|||
|
||||
## Why we need tests?
|
||||
|
||||
When we write a function, we usually can imagine what it should do: which parameters give which results.
|
||||
When we write a function, we can usually imagine what it should do: which parameters give which results.
|
||||
|
||||
During the development, we can check the function by running it and comparing the outcome with the expected one. For instance, we can do it in the console.
|
||||
During development, we can check the function by running it and comparing the outcome with the expected one. For instance, we can do it in the console.
|
||||
|
||||
If something's wrong -- then we fix the code, run again, check the result -- and so on till it works.
|
||||
If something is wrong -- then we fix the code, run again, check the result -- and so on till it works.
|
||||
|
||||
But such manual "re-runs" are imperfect.
|
||||
|
||||
**When testing a code by manual re-runs -- it's easy to miss something.**
|
||||
**When testing a code by manual re-runs, it's easy to miss something.**
|
||||
|
||||
For instance, we're creating a function `f`. Wrote some code, testing: `f(1)` works, but `f(2)` doesn't work. We fix the code and now `f(2)` works. Looks complete? But we forgot to re-test `f(1)`. That may lead to an error.
|
||||
|
||||
That's very typical. When we develop something, we keep a lot of possible use cases and mind. But it's hard to expect from programmer to check all of them manually after every change. So it becomes easy to fix one thing and break another one.
|
||||
That's very typical. When we develop something, we keep a lot of possible use cases in mind. But it's hard to expect a programmer to check all of them manually after every change. So it becomes easy to fix one thing and break another one.
|
||||
|
||||
**Automated testing means that tests are written separately, in addition to the code. They can be executed easily and check all the main use cases.**
|
||||
|
||||
|
@ -36,7 +36,7 @@ Enough words. Let's see the example.
|
|||
|
||||
Let's say we want to make a function `pow(x, n)` that raises `x` to an integer power `n`. We assume that `n≥0`.
|
||||
|
||||
That task is just an example: there's `**` operator in JavaScript that can do that, but here we concentrate on the development flow that can be applied to more complex tasks as well.
|
||||
That task is just an example: there's the `**` operator in JavaScript that can do that, but here we concentrate on the development flow that can be applied to more complex tasks as well.
|
||||
|
||||
Before creating the code of `pow`, we can imagine what the function should do and describe it.
|
||||
|
||||
|
@ -73,7 +73,7 @@ The flow of development usually looks like this:
|
|||
|
||||
1. An initial spec is written, with tests for the most basic functionality.
|
||||
2. An initial implementation is created.
|
||||
3. To check whether it works, we run the testing framework [Mocha](http://mochajs.org/) (more details soon) that runs the spec. Errors are displayed. We make corrections till everything works.
|
||||
3. To check whether it works, we run the testing framework [Mocha](http://mochajs.org/) (more details soon) that runs the spec. Errors are displayed. We make corrections until everything works.
|
||||
4. Now we have a working initial implementation with tests.
|
||||
5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail.
|
||||
6. Go to 3, update the implementation till tests give no errors.
|
||||
|
@ -112,7 +112,7 @@ The result:
|
|||
|
||||
As of now, the test fails, there's an error. That's logical: we have an empty function code in `pow`, so `pow(2,3)` returns `undefined` instead of `8`.
|
||||
|
||||
For future, let's note that for there are advanced test-runners, like [karma](https://karma-runner.github.io/) and others. So it's generally not a problem to setup many different tests.
|
||||
For the future, let's note that there are advanced test-runners, like [karma](https://karma-runner.github.io/) and others. So it's generally not a problem to setup many different tests.
|
||||
|
||||
## Initial implementation
|
||||
|
||||
|
@ -130,7 +130,7 @@ Wow, now it works!
|
|||
|
||||
## Improving the spec
|
||||
|
||||
What we've done -- is definitely a cheat. The function does not work: an attempt to calculate `pow(3,4)` would give an incorrect result, but tests pass.
|
||||
What we've done is definitely a cheat. The function does not work: an attempt to calculate `pow(3,4)` would give an incorrect result, but tests pass.
|
||||
|
||||
...But the situation is quite typical, it happens in practice. Tests pass, but the function works wrong. Our spec is imperfect. We need to add more use cases to it.
|
||||
|
||||
|
@ -172,11 +172,11 @@ The principal difference is that when `assert` triggers an error, the `it` block
|
|||
|
||||
Making tests separate is useful to get more information about what's going on, so the second variant is better.
|
||||
|
||||
And besides that, there's one more rule good to follow.
|
||||
And besides that, there's one more rule that's good to follow.
|
||||
|
||||
**One test checks one thing.**
|
||||
|
||||
If we look at the test and see two independent checks in it -- better to split it into two simpler ones.
|
||||
If we look at the test and see two independent checks in it, it's better to split it into two simpler ones.
|
||||
|
||||
So let's continue with the second variant.
|
||||
|
||||
|
@ -361,11 +361,11 @@ function pow(x, n) {
|
|||
*/!*
|
||||
|
||||
let result = 1;
|
||||
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
result *= x;
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
@ -388,7 +388,7 @@ The spec can be used in three ways:
|
|||
|
||||
With the spec, we can safely improve, change, even rewrite the function from scratch and make sure it still works right.
|
||||
|
||||
That's especially important in large projects when a function is used in many places. When we change such a function -- there's just no way to manually check if every place that uses them still works right.
|
||||
That's especially important in large projects when a function is used in many places. When we change such a function, there's just no way to manually check if every place that uses it still works right.
|
||||
|
||||
Without tests, people have two ways:
|
||||
|
||||
|
@ -397,7 +397,7 @@ Without tests, people have two ways:
|
|||
|
||||
**Automatically tested code is contrary to that!**
|
||||
|
||||
If the project is covered with tests -- there's just no such problem. We can run tests and see a lot of checks made in a matter of seconds.
|
||||
If the project is covered with tests, there's just no such problem. We can run tests and see a lot of checks made in a matter of seconds.
|
||||
|
||||
**Besides, a well-tested code has better architecture.**
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue