one of the most crucial skills that experienced developers have, but usually isn't taught explicitly, is the ability to trace through code in their head one operation at a time. without this skill new programmers are left having to blindly fix bugs, write new code by pasting together other snippets hoping for the best, and settling for rough behavior-level understadings of new code they encounter.
all of this can be easily avoided if you explicitly teach how to look inside a dense block of code and see it for what it is, nothing but a well-defined series of understandable operations.
at first glance the expanded code may feel like just a lot of extra work, but that's naturally part of "explicitly teaching the implicit". All the little things we do naturally without thinking need to be explicitly laid out in steps for studying. After a couple minutes (or days), you'll get used to working with it and you'll probably find yourself expanding all the time. Learning to work with expanded code will help enormously understanding new code, tracking down bugs, and inferring strategies from new code.
- how to do
- if, else if, else
- for loop
below are two snippets of code, one made up of an if/elseif/else and one of a for loop. each snippet has been refactored 3 different ways - each more explicit than the last
try playing around with each refactor in the console passing through different values. which version is easier to understand and explain back to someone else?
run the fully expanded & logged snippet in the console, then scroll the markdown up to the original unexpanded snippet. how does this compare to trying to step through the same code without a log?
{
const a = ;
const b = ;
const c = ;
const expected = ;
let actual;
if (a == b || a && c) {
actual = a + b + c;
} else if (!c > !b) {
actual = c || b + '';
} else {
actual = null;
};
console.log(actual === expected, actual + ' !== ' + expected);
};
{
const a = ;
const b = ;
const c = ;
const expected = ;
let actual;
const condition_1 = a == b || a && c;
const condition_2 = !c > !b;
if (condition_1) {
actual = a + b + c;
} else if (!c > !b) {
actual = c || b + '';
} else {
actual = null;
};
console.log(actual === expected, actual + ' !== ' + expected);
};
{
const a = ;
const b = ;
const c = ;
const expected = ;
let actual;
let condition_1; { // = a == b || a && c;
const val_1 = a == b;
const val_2 = a && c;
const val_3 = val_1 || val_2;
condition_1 = val_3; };
let condition_2; { // = !c > !b;
const val_1 = !c;
const val_2 = !b;
const val_3 = val_1 > val_2;
condition_2 = val_3; };
if (condition_1) {
actual; { // = a + b + c;
const val_1 = a + b;
const val_2 = val_1 + c;
actual = val_2; };
} else if (!c > !b) {
actual; { // = c || b + '';
const val_1 = b + '';
const val_2 = c || val_1;
actual = val_2; };
} else {
actual = null;
};
console.log(actual === expected, actual + ' !== ' + expected);
};
{
const a = ;
const b = ;
const c = ;
const expected = ; const log = [{a,b,c}];
let actual;
let condition_1; { // = a == b || a && c;
const val_1 = a == b;
const val_2 = a && c;
const val_3 = val_1 || val_2; log.push({condition_1:'a == b || a && c',val_1,val_2,val_3});
condition_1 = val_3; };
let condition_2; { // = !c > !b;
const val_1 = !c;
const val_2 = !b;
const val_3 = val_1 > val_2; log.push({condition_2: '!c > !b', val_1, val_2, val_3});
condition_2 = val_3; };
if (condition_1) {
actual; { // = a + b + c;
const val_1 = a + b;
const val_2 = val_1 + c; log.push({actual:'a + b + c', val_1, val_2});
actual = val_2; };
} else if (!c > !b) {
actual; { // = c || b + '';
const val_1 = b + '';
const val_2 = c || val_1; log.push({actual: "c || b + ''", val_1, val_2});
actual = val_2; };
} else {
actual = null; log.push({actual});
};
console.log(actual === expected, actual + ' !== ' + expected);
console.log(log);
};
your notes:
{
let a = ;
const b = [null, ];
const limit = ;
const expected = ;
let actual;
for (const i = 0; i < limit; i+=2) {
b.push(a + i * b[i-1]);
a *= b[i];
};
actual = b.pop();
console.log(actual === expected, actual + ' !== ' + expected);
};
{
let a = ;
const b = [null, ];
const limit = ;
const expected = ;
let actual;
{
let i = 0;
while (i < limit) {
b.push(a + i * b[i-1]);
a *= b[i];
i+=2;
};
};
actual = b.pop();
console.log(actual === expected, actual + ' !== ' + expected);
};
{
let a = ;
const b = [null, ];
const limit = ;
const expected = ;
let actual;
{
let i = 0;
let condition = i < limit;
while (condition) {
let next_item; { // a + i * b[i-1]
const val_1 = i - 1;
const val_2 = b[val_1];
const val_3 = i * val_2;
const val_4 = a + val_3;
next_item = val_4; };
b.push(next_item);
let next_a { // = a * b[i];
const val_1 = b[i];
const val_2 = a * val_1;
next_a = val_2; };
a = next_a;
const next_i = i + 2;
i = next_i;
};
};
actual = b.pop();
console.log(actual === expected, actual + ' !== ' + expected);
};
{
let a = ;
const b = [null, ];
const limit = ;
const expected = ; const log = [{a,b:b.slice(),limit}];
let actual;
{
let i = 0; log.push({i});
let condition = i < limit; log.push({condition, op: 'i < limit'});
while (condition) {
let next_item; { // a + i * b[i-1]
const val_1 = i - 1;
const val_2 = b[val_1];
const val_3 = i * val_2;
const val_4 = a + val_3; log.push({next_item:'a + i * b[i-1]',val_1,val_2,val_3,val_4});
next_item = val_4; };
b.push(next_item); log.push({b:b.slice()});
let next_a; { // = a * b[i];
const val_1 = b[i];
const val_2 = a * val_1; log.push({a:'a * b[i]',val_1,val_2});
next_a = val_2; };
a = next_a;
const next_i = i + 2; log.push({i:'i + 2',next_i});
i = next_i;
condition = i < limit; log.push({condition, op: 'i < limit'});
};
};
actual = b.pop();
console.log(actual === expected, actual + ' !== ' + expected);
console.log(log);
};
your notes: