Things I wish Makersquare had taught me.

Four disjointed, unrelated topics on engineering delivered by a person with issues, lots of issues, in a stream of conciousness format where I can't promise I won't digress and end up talking about the Victorian infatuation with tobacco rectal inflation or the intraparty conflicts inherent to the Irish Parliamentary system.

brian boyko

Software Development Engineer in Test - ESO Solutions
Graduate, Maker Square Austin Cohort #21

@boyko4tx - github.com/brianboyko - http://brianboyko.us

Before
WE
BEGIN

Stop me if you get bored, and you want me to move on. 

I don't know your names, so when you raise your hands to ask questions, Im'ma point to you.

Should I skip?

Topic 1

Your Job Hunt after makersquare

tOPIC 1:

Your Job Hunt

  • As a novice developer, they're more interested in seeing what you've done than where you went to school or where you worked.
     
  • GITHUB.
     
  • A personal site. Github pages is fine if you like working with Jekyll, otherwise Ghost/WP on a hosted account. 
  • It takes time. You can't always shorten that time, so use it.
    • Study.
    • Make. 
    • Catch up with family.
    • (but don't forget to keep applying. 5x a day. It works.)

Post-Bootcamp study

  • Online Courses:
    • Front-end Masters (You have this!)
    • Pluralsight (languages)
    • Udemy (esp. for game dev.) 
    • Coursera or edX (comp sci)
  • Books: 
    • My favorites: Pragmatic Bookshelf & No Starch Press. 
  • Projects: 
    • Add to open source project
    • Create your own (Now'd be a good time to build that game!) 
  • No Source Control.
  • No Unit Tests.
  • No Daily Builds.
  • No Bug Database (like Jira).
  • No Spec.
  • No Testers.
  • No Code Reviews.
  • You were not asked to actually code or whiteboard during your interview. 
  • Engineers do not have admin/sudo access on dev. machines. 

Red Flags Before
YOU TAKE THAT FIRST JOB

This is what happens when you ignore red flags.

Google "The Joel Test." It was written in 2004, it's still applicable.

  • Source control is CVS or Subversion, instead of Git or Mercurial.
     
  • Application is written in a in-house, proprietary language that nobody else in the world uses.
     
  • The company has no marketing department. As a result, they are developing a product no one needs or wants.
     
  • The company's website looks like it's from 1998. On Purpose.

 

RED FLAGS afTER
YOU TAKE THAT FIRST JOB

I AM SPEAKING

FROM EXPERIENCE.

  • The company uses the money from new clients for new features to pay developers to fulfill old promises from older clients.

How to tell if you are working for an Accidental ponzi scheme.

  • The software you are working on is something that nobody has asked for, nobody needs, and nobody wants, but your company makes it because it shows off the "capabilities" of some fancy vaporware. 

In most cases, "ponzi scheme-like" companies aren't breaking the law, or being bad people, but they dug themselves a hole and kept digging. 

Topic 2

Programming Paradigms

 

or why you should focus on Javascript now, but as soon as you feel you're able, branch out to a second language.

FUNCTIONAL

Best when you have a fixed set of "things" and as you build, you add new operations on those things. 

Object-Oriented

Best when you have a fixed set of operations and as your code evolves you primarily add new "things" which use those operations. 

TOPIC 2: PROGRAMMING PARADIGms

Haskell

Elm

Scala

cLISP

Clojure (JVM)

Scheme

Go

Python

C++

Kotlin (JVM)

JAVASCRIPT

Ruby

Groovy (JVM)

C#

Objective-C

Java 7/8 (JVM)

Visual Basic

More Functional

More Object-Oriented

Functional Programming

  • avoids (if possible) mutable variables and mutable "states".
  • Easier to write high-performance multi-threaded applications. 
  • Around for longer, but taking off now because of the move from higher clock speeds to multi-cores.
  • Not just testable, *provable.*

Object Oriented Programming

  • uses classes which can inherit from one another. 
  • classes most often have a mutable state. 
  • If you are working with any prior code in your organization, 99% of it will be object oriented.

Should I skip?

Functional Programming

  • Adding a new type of "thing" to a functional program may require editing many function definitions to add a new case.

Object Oriented Programming

  • Adding a new type of operation may require editing many class definitions to add a new method.  

AN OVERSIMPLIFIED and entirely non-accurate METAPHOR

You own a car factory. 

WWII breaks out, you must now make Tanks, not Cars.

  • Functional:
    • You have to redesign your entire operation to account for the different needs of tanks.
  • Object Oriented:
    • Just create a Tank class that extends your SUV class, add on a bigGun() method & this.armor, and you're golden. 

Electric cars become a thing

  • Functional:
    • You simply replace your current "gas" engine function, with electric engine functions, and go. 
  • Object Oriented:
    • Every single car in the line must be redesigned to account for electric engines. 

TOY PROBLEM

Solved in two ridiculous ways

  • Write a function, "commonCharacters()" that accepts two strings as arguments, and returns only the characters common to both strings.
     
  • Ignore whitespace.
     
  • Return the characters in the order they first appear in the FIRST of the two entries.
// your test case

describe('commonCharacters()', () => {
    it('should return common characters', () => {
        expect(commonCharacters('acexivou', 'aegihobu')).to.equal('aeiou')
    })
})

Should I skip?

commonCharacters = (string1, string2) => 
    string1.split("")
        .reduce((pv, char) => 
            (char !== " " && 
             !pv.join("").includes(char) && 
             string2.includes(char)) ? pv.concat(char) : pv, []
        ).join("");

The EXTREMELY Functional Solution

commonCharacters = (string1, string2) => string1.split("").reduce((pv, char) => (char !== " " && !pv.join("").includes(char) && string2.includes(char)) ? pv.concat(char) : pv, []).join("");
class Entry {
  constructor(thing){
    this.entry = thing;
  }
  
  getEntry(){
    return this.entry;
  }
  
  setEntry(thing){
    this.entry = thing;
  }
  
  concatEntry(thing){
    this.entry += thing;
  }
  
  toArray () {
    if(typeof(this.entry) == "string"){
      this.entry = this.entry.split("");
    }
  }
  
  toString() {
    if(Array.isArray(this.entry)){
      this.entry = this.entry.join("")
    }
  }
  
  isIncluded (char) {
    return this.entry.includes(char)
  }
  
  stripWhitespace () {
    this.toArray();
    let newEntry = [];
    for(let el of this.entry){
      if(el !== " "){
        newEntry.push(el);
      }
    }
    this.entry = newEntry; 
  }
  
  stripDuplicates () {
    this.toArray();
    let newEntry = [];
    for(let el of this.entry){
      if(!newEntry.includes(el)){
        newEntry.push(el)
      }
    }
    this.entry = newEntry; 
  }

}

commonCharacters = (string1, string2) => {
  let entry1 = new Entry(string1)
  let entry2 = new Entry(string2)
  let answer = new Entry("")
  
  entry1.toArray()
  entry1.stripWhitespace()
  entry1.stripDuplicates()
  entry2.toArray()
  entry2.stripWhitespace()
  entry2.stripDuplicates()
  for(let el of entry1.entry){
    if(entry2.isIncluded(el)){
      answer.concatEntry(el)
    }
  }
  answer.toString()
  return answer.entry
}

The EXTREMELY Object-Oriented Solution

class Entry {
  constructor(thing){
    this.entry = thing;
  }
  
  getEntry(){
    return this.entry;
  }
  
  setEntry(thing){
    this.entry = thing;
  }
  
  concatEntry(thing){
    this.entry += thing;
  }
  
  toArray () {
    if(typeof(this.entry) == "string"){
      this.entry = this.entry.split("");
    }
  }
  
  toString() {
    if(Array.isArray(this.entry)){
      this.entry = this.entry.join("")
    }
  }
  
  isIncluded (char) {
    return this.entry.includes(char)
  }
  
  stripWhitespace () {
    this.toArray();
    let newEntry = [];
    for(let el of this.entry){
      if(el !== " "){
        newEntry.push(el);
      }
    }
    this.entry = newEntry; 
  }
  
  stripDuplicates () {
    this.toArray();
    let newEntry = [];
    for(let el of this.entry){
      if(!newEntry.includes(el)){
        newEntry.push(el)
      }
    }
    this.entry = newEntry; 
  }

}

commonCharacters = (string1, string2) => {
  let entry1 = new Entry(string1)
  let entry2 = new Entry(string2)
  let answer = new Entry("")
  
  entry1.toArray()
  entry1.stripWhitespace()
  entry1.stripDuplicates()
  entry2.toArray()
  entry2.stripWhitespace()
  entry2.stripDuplicates()
  for(let el of entry1.entry){
    if(entry2.isIncluded(el)){
      answer.concatEntry(el)
    }
  }
  answer.toString()
  return answer.entry
}

Now

which Ridiculous program would be easier to modify so that...

...it returns all characters that are not duplicates?

...it takes an array of objects instead of a string?

What oBJECT oRIENTED Programmers think ABout fUNCTIONAL programmers

  • Functional programming makes it hard for programmers to figure out what you can do with the program; keeping data and behavior separate means that it can be difficult to see the use of either, just like you don't make sentences without nouns and verbs.
     
  • Functional code is so full of chains that you get lost in the whole thing. (Lisp stands for "Lots of Irritating Superfluous Parentheses")
     
  • Our methodology results in self-contained units of computation, whereas a functional programmer might call functions from all over the place, leaping around the source code as you try to track what's happening to your parameter. 

What Functional Programmers think ABout object oriented programmers

  • It mingles "data" and "behavior."
     
  • It is tightly coupled, lowly cohesive code.
     
  • If I pass in the same parameters to the same methods, I will not get the same result, because any previous function could change the behavior of the class instance.
     
  • “They’ve got all this implicit environment that they carry around with them. You wanted a banana, but what you got was a gorilla holding the banana and the entire jungle.” -- Joe Armstrong, creator of Erlang.

What I think about both.

  • Learning functional programming concepts helped me to write loosely coupled, reusable code that tended to be smaller (and thus easier to debug) and more easily testable.
     
  • Learning object oriented programming concepts helped me to model more complex operations and to break down large problems into smaller ones.
     
  • They're both important.
  • They're both good.
  • Learn them both. 

Topic 3: TEST WHILE DRIVEN DEVELOPMENT

If you can, write the tests before the code.

If you must, write the TESTS immediately after the code.

DO NOT check-in CODE that other developers can use THAT DOES NOT HAVE TESTS. EVER.

Tests are how you can tell whether or not your code breaks things or changes something someone else depends on.

Why you need tests (PART 1):

  • They tell you when something you change breaks the code... or, alternatively, prove that when what you change breaks the code, it's not your fault.
     
  • TWDD requires you to focus on *one* thing at a time.  It allows you to solve pieces of the puzzle, until you have the whole thing solved.
     
  • Tests are the "show, don't tell" version of documentation.
     
  • You can try new things with your code confident you won't break existing functionality.
     
  • TWDD requires that your code be written in a way that it IS testable. Testable code is modular, maintainable code that doesn't rely on "bad things" like global variables.

Why you need tests (PART 2):

  • They make it MUCH easier to go back and refactor the code you've written, making it look better for the code review, and all your friends in your coding team look at you like: Damn, that's good code.  
  • Tests make it easier to focus on the features in your sprint, instead of letting in "feature creep" which delays projects. 
  • When you find a bug and fix it, make a test to make sure that it doesn't happen.  That'll prevent another developer from making a change which re-introduces the bug. 

Dependency Injection

A Dev's Best Testing Friend.

import database from 'database' //
import {config} from 'config'

let connection = database(config);

// can't test this function without actually connecting to the database. 

export function addRecord (record) => { 
    connection.addOne(record)
}
// testable, database and config need to be defined in every single call. 

export function addRecord (database, config, record) => {
    let connection = database(config);
    connection.addOne(record)
}
// AHA!  Testable!

export const Connector = (database, config) => {
    let connection = database(config); 
    return {
      addRecord: function(record){
        connection.addOne(record);
      }
    }
}

cannot test.

Very testable!

let testConnector = 
  Connector(fakeDB, fakeConfig);

testConnector
  .addRecord(fakeRecord); 
addRecord(fakeDB, 
  fakeConfig, fakeRecord); 
// for every test 
// and every use.

Should I skip?

Dependency Injection

A Dev's Best Testing Friend.

// AHA!  Testable!

export const Connector = (database, config) => {
    let connection = database(config); 
    return {
      addRecord: function(record){
        connection.addOne(record);
      }
    }
}
//YOUR TEST SUITE

describe(".addRecord()", () => {
  it('adds a record', (done) => {
    let fakeConn = Connector(fakeDB, fakeConfig);
      expect(fakeConn.addRecord({foo: 'bar'})
        .then((response) => response.status))
        .to.eventually.equal(200).notify(done); 
    })
})
//YOUR PROGRAM

db = Connector(knex, config); 

db.addRecord({data: "Some Real Data"})
  .then((response) => {
        //do stuff
   }).catch((rejection) => {
     throw new Error(rejection); 
   })

Topic 4: Junior/Senior Devs

As a job title, it's kinda meaningless. 

save for one thing.

It's a ratio. 

How much mentoring you need to get up to speed in the current organization

How much mentoring you are able to give to others in the current organization

compared to:

This is why you can have:

Junior developer positions that require 5+ years of experience

Bootcamp grads landing senior posititions right away

These positions do require a great deal of knowledge, but there's very little mentoring/management responsibility.


I.E., they don't want to take the time to train you, but you don't have to train anyone else.

You will not just be expected to "engineer" or "develop" - you will be expected to teach others your specialized knowledge - like coming in as a Node.js expert in a room full of C# devs.

What that means:

Don't strive to be a "Senior Engineer"

 

Strive to be the most informed, most helpful engineer.

The rest will follow. 

A corollary:

It's easy to look brilliant when you work with idiots.

But that won't make you very happy. 

MAKERSQUARE

makes you useful to employers.

YOUR WORK AND STUDY

IS WHAT MAKES YOU MIGHTY.

Finally, the # 1 thing to takeaway:

BE MIGHTY.

Thank you.

Things I Wish MakerSquare Had Taught Me

By brianboyko

Things I Wish MakerSquare Had Taught Me

  • 1,626