Skip to content

Latest commit

 

History

History
333 lines (249 loc) · 7.87 KB

1-explicitly-teach-the-implicit.md

File metadata and controls

333 lines (249 loc) · 7.87 KB

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.

Index


how to do

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?

TOP



if, else if, else

if: original code

{
  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);
};

if: expand control flow

{
  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);
};

if: expand expressions

{
  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);
};

if: log execution

{
  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:

TOP



for loop

for: original code

{
  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);
};

for: expand control flow

{
  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);
};

for: expand expressions

{
  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);
};

for: log execution

{
  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:

TOP



Janke Learning