Skip to content

Instantly share code, notes, and snippets.

@Theartbug
Last active April 6, 2018 02:27
Show Gist options
  • Save Theartbug/842e61ea21c6b17fa0ee811e770c53f5 to your computer and use it in GitHub Desktop.
Save Theartbug/842e61ea21c6b17fa0ee811e770c53f5 to your computer and use it in GitHub Desktop.
Notes from backend bootcamp class

Asynchronous, Events, Node architecture

Node.js Architecture

  • node someFile.js will start the event loop process in synchronous-land
    • will end process after it knows there is nothing else to do
  • when asynchronous is present, the event loop stays active until the asynchronous event is finished.
    • will often return something with a callback
    • if there is no callback, the loop will not stay active waiting for a response
    • follows completion order not dispatch order
  • setInterval() is asynchronous and will continue to run forever unless the interval is cleared
  • asynchronous server:
  http.createServer((req, res) => {
    console.log('got web request');
    res.end('yo');
  }).listen(3000);
  • other architectures use multiple threads
    • issues with accessing the same spot of memory
    • thread must wait until asynchronous activity is done

Event emitter

const fs = require('fs');

const readStream = fs.createReadStream('./test/hipster-ipsum', {
  encoding: 'utf8',
  highWaterMark: 256 //bytes
});
const writeStream = fs.createWriteStream('copy.txt');

readStream.on('data', chunk => {
  console.log('chunk', chunk.length, data.slice(0,15))
  writeStream.write(chunk);
});
// can control data in chunks, read the file through a chunk at a time

readStream.on('close', data => {
  console.log('all done');
  writeStream.end();
});

Testing Mocha Async

  • bring in promisify
const promisify = require('util');
const unlink = promisify(require('fs').unlink);


beforeEach(() => {
  return unlink(actualFileName)
    .catch(err => {
      if(err.code !== 'ENOENT') throw err;
    });
});

Binary / Hex data

  • ASCII codes align with byte and hex values
  • what files read and convert

Binary

  • two states 0 or 1
  • placement matters
  • places
    • farthest right is 20, each place increases by 21
    • 3 = 11, 4 = 100
  • each place is called a bit
  • a byte is 2 bits
  • any 4 bits has a corresponding hexadecimal code
  • 8-bit integer maximum is 255

Hex

  • base 16
  • once unit is beyond 9, then begin to count in alphabet
    • 10 = a, 11 = b, 15 = e, etc.

code

  • to write code in binary / hex start 0b for binary and 0x for hex

Endianness

  • byte order
  • direction of storage of data
  • Little-endian (LE) stores data at least significant figure
  • Big-endian (BE) stores data at mostsignificant figure
  • there is no endianness for an 8-bit integer as it is one byte

Node Buffer class

  • access to buf.read utilities
    • reads based on LE or BE, 8 / 16 / 32 bit files, etc, signed or unsigned (Int / UInt)
    • Signed vs unsigned
      • signed keep track of negative integers
const fs = require('fs');
const buffer = fs.readFileSync('EDIT.md');

const charB = 'B'.charCodeAt(0);
const charb = 'b'.charCodeAt(0);
const charF = 'F'.charCodeAt(0);
const charf = 'f'.charCodeAt(0);
for(let i = 0; i < buffer.length; i++) {
  const number = buffer.readInt8(i);
  if(number === charB) buffer.writeInt8(charF, i)
  else if(number === charb) buffer.writeInt8(charf, i);
} //converts all b's to f's

const number = buffer.readUInt8(11);

console.log(number) //66
console.log(String.fromCharCode(number)) //b

buffer.writeInt8(70,11) //replacing b with f at the offset 11 (where the b was)

//must write changes made to file when working with buffer
fs.writeFileSync('EDIT.md', buffer) 

//unicode characters require 3 bytes
// unsure how to read it with buffer

Javascript fundamentals

random notes

  • command + d to select similar kinds
    • command + k + d to skip selection onto next
  • node debugger
    • change in settings: "program": ${file}
      • debugger will launch from current file
    • step over: go to next line
    • step into / out: go into / out of function
  • node gets dunderdirname __dirname
    • where am I and what is my file name?

ES6 review

Template strings / literals

  • cannot use control flow within interpolator, can still use ternary as that is an expression
  • can multiline without carriage returns
  • escape backticks with backslashes
  • if you tab within multiline, will show up

destructuring

  • can pull properties / methods off of objects if the variable name is the same as the one you want to call it
  • can use in functions to pull off desired properties
  • can alias const { person: name, age } = this.person
  • requires parenthesis in arrow function to disambiguate ({ note }) => {}

Curly brace useage

  • blocks
  • object literals
  • template literal interpolator
  • destructuring
  • interpolator in JSX

variable storage

assigned by value

  • primitive values
    • Number, String, Boolean, undefined, null Symbol
  • immutable

assigned by reference

  • compound values
    • Object, Array
  • mutable
  • places the contents in a heap and only a reference is stored
  • copies of compound objects need to be more creative
    • .slice(); for arrays
    • {...spread} for objects

variable table

  • stores the name of the variable, data type, value
  • const declaration will not allow rewriting of data in variable table
  • references only point at contained values, NOT other variables or references
  • typeof value assigned to variable decides whether the value is stored by value or by reference
  • function variable parameters will create a new variable pointer for arguments
    var magneto = [8,4,8];
    (function(x) {        //IIFE
        x.push(99);
        console.log(x);   //[8,4,8,99]
        x = [1,4,1];      //reassign variable (create new reference)
        x.push(88);
        console.log(x);   //[1,4,1,88]
    })(magneto);
    console.log(magneto); //[8,4,8,99]

Closures

  • point to the variable table, not the value
  • functions only remember variables that were defined by a parent

Importing / exporting in node

exposure:

 module.exports = {};
 exports = module.exports; //do not use as it is easy to overwrite

 modules.exports.desiredFunction = () => {};
 // preferred way

import:

 const imported = require('../labs/art-gallery');
  • files are cached when initially required so they are more quickly connected from then on
  • files become something like a magic function representing the file

Export patterns

  • combine exports together at the end of a file:
  module.exports = {
    add,
    subtract,
    multiply
  }
  • a helper function that modifies functions with different configurations
module.exports = function() {
  return function(name) {
    function[name]
  }
}
  • a revealer
  module.exports = function(config) {
    return //reveal stuff
  }
  • a class

Classes

extends

  • will become an extension of another class
  • usually will need to call super() to obtain the stuff inside the parent classes constructor
  • tight coupling, not recommended composition over inheritance
  • compose each piece what it needs
  • a has relationship opposed to a is a

Javascript fundamentals, TTD

Random Notes:

  • add '''js''', '''html''', '''sh''' to markdown code to better highlight things in readME.md

Node.js

  • the environment gives access to process

    • .argv exposes what was typed on the command line
    • Will split into individual parts
    console.log('Hello ${process.argv[2]}');
    
    //command line
    
    node greet.js world // Hello world
    

    step by step

    // 1. extract argv from cli
    const name = process.argv[2];
    
    //2. format a greeting to supplied name
    const greeting = 'Hello ${name}';
    
    //3. log a result to the console
    console.log(greeting);
    
    • single responsibility principle, easier to change and maintain code
    • from a server standpoint, only 2 is relevant
  • If you run with no arguments, you will get a console command line

    • command + c to escape

npm

  • npm init
    • creates a package.json
  • npx
    • tests out something installed locally

testing in general

  • Unit test : test logic in classes by programmers to show code level correctness. They should be fast and not depend on other parts of the system that you don't intend to test
  • Functional acceptance test : test use case scenario's on a limited (specially created) data set done by the test department to show that every specified scenario works as specified.
  • User acceptance test : test use case scenario's on production like data done by representatives of the users to make them formally accept the application
  • Integration test : Test communication paths between different parts of the module done by the test department or by developers to show that all modules work correctly together.

Mocha vs jest

  • Mocha is older and more flexible. Does not come with assertion library or mocking framework. More widely supported. Difficult snapshot testing. Lots of set up.
  • Jest is younger and comes as a full package. Easy snapshot testing. Not widely supported
    • use with Enzyme to snapshot test react components

unit testing

  • npm install mocha -D
    • a dev dependency
  • create a folder with the name test within the project root
    • any name with the ending .test.js
  • mocha is a test runner, will need an assertion library to test if things came out as expected
    • const assert = require('assert');
    • assert.equal(greeting, 'Hello world');
  • do the simplest thing to get your tests to pass
  • must module.export = nameOfFunction;
  • in package.json under scripts
    • "test": "mocha", "start": "npm run test -- -w"
  • describe() is a testing suite organizational tool

example:

//cli.test.js
const assert = require('assert');
const getArgs = require('../lib/get-args');

describe('greet cli', () => {
  it('extracts name from args', () => {
    const name = getArgs(['node, 'greet-cli.js', 'world']);
    assert.equal(name, 'world');
  })
})

//get-args.js

function getArgs(args) {
  return args[2];
}

//greet-cli.js

const getArgs = require('../lib/get-args');
const greet = require('../lib/greet');

const name = getArgs(process.argv);
const greeting = greet(name);
console.log(greeting);

integration testing

  • when individual software modules are combined and tested as a group (end-to-end)
  • execSync tells something to run, like from the terminal
const childProcess = require('child_process').execSync;

it('works end-to-end', () => {
  execSync('node ./bin/greet-cli.js world');
  assert.equal(result.toString(), 'Hello World\n');
})

demo:

in calc.test.js:

const assert = require('assert');

//can create a function that will preform the test if need many of the same kind
// Don't do unless there is good reason, often more difficult

describe('calculator', () => {

  function calcTest(name, firstAddend, secondAddend, expected) {
    it(name, () => {
      const sum = calc.add(firstAddend, secondAddend);
      assert.equal(sum, expected);
    });

  }
  calcTest('add one and two', 1, 2, 3);
  calcTest('multiply', 2,2,4);

});

Functional patterns

  • when a function is defined, it is still an object until the magic invocation parenthesis are typed after the function name.
    function silly() {};
    
    silly //will only refer the the written function
    silly(); //will invoke!
    
  • passing functions
    function square(x) {
      return x * x;
    }
    
    //wrap in callback
    number.map( n => square(n));
    
    //pass directly as return value to hand to map
    number.map(square);
    
    // (won't work), likely never need
    number.map(square());
    

Array method demo

  • Array.prototype.some():
const some = (array, test) => {
  for(let i = 0; i < array.length; i++) {
    if(test(array[i])) return true;
  }
  return false;
}

testing:


describe('some', () => {

const hasEven = some(arr, x => x % === 0);

  it('returns false if no elements match', () => {
    const arr = [1, 3, 5, 7];
    assert.equal(hasEven, false);
  })

  it('returns true if at least one element matches', () => {
    const arr = [1, 3, 4, 7];
    assert.equal(hasEven, true);
  })

  it('some short-circuits when one element is true', () => {
    const arr = [2, 3, 5, 6];
    const called = [];
    some(arr, x => {
      called.push(x);
      return isEven(x);
    });
    assert.deepEqual(called, [2])
  })
})
  • deepEqual assesses if two thing are semantically equal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment