SlideShare uma empresa Scribd logo
1 de 204
Baixar para ler offline
Unbreakable
Unbreakable
Craftsmanship
“Woz designed all the hardware and all the circuit boards
and all the software that went into the Apple II… not one
bug has ever been found … the circuit design of the
Apple II is widely considered to be astonishingly
beautiful, as close to perfection as one can get in
engineering.”
-- Vikram Chandra Geek Sublime
Unbreakable
Unbreakable
Craftsmanship
Unbreakable
Craftsmanship
Doing something good for its own sake
Woz Flow Chart:
Woz Flow Chart:
Be A
Genius
Build Stuff
Woz Flow Chart:
Be A
Genius
Build Stuff
Learn
Learn
Learn
Learn
Learn
Learn
Learn
LearnLearn
Learn Learn
Learn
Learn
Build
Build
Build
Build
Build
Build
BuildBuild
Build
Build
Build
Build
Build
Learn
Learn
Build
Build
Build
Learn
Learn
LearnLearn
Build
Build
Build
Learn
Build
Build
Learn
Learn
LearnLearn
Build
Build
Build
Build
Learn
Learn
Learn
Build
Build
Build
Learn
Learn
Learn
Build
Build
Learn
Learn
Build
Build
Build
Joe Morgan
Joe Morgan
@joesmorgan
Joe Morgan
@joesmorgan
Lawrence, KS
I write code
I write code
I try to get a little better everyday
Stages on craftsmanship
Apprentice
Apprentice
Apprentice: Guidance
Journeymen
Journeymen: Experience and Intuition
Master
Master: Creativity
How does that relate to software?
# of Devs
It works!
$$
Love
Self Evaluation
Frontend CodeServer CodeServers
Frontend CodeServer CodeServers
Frontend CodeServer CodeServers
Frontend CodeServer CodeServers
Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
Server Dev Ops Angular 2NoSQL Functional OOAWS SQL DB
How do we improve?
Eye: What can you see?
Eye: What can you see?
Hand: What can you build?
Eye: What can you see?
Hand: What can you build?
Mind: What do you know?
[The chipping paint] could be an
example of machine-cutting
"without sharp blades," adding
"it looks like they painted before
they actually cut the piece."
[The chipping paint] could be an
example of machine-cutting
"without sharp blades," adding
"it looks like they painted before
they actually cut the piece."
[The chipping paint] could be an
example of machine-cutting
"without sharp blades," adding
"it looks like they painted before
they actually cut the piece."
$offset = $argv[0];
$query = "SELECT id, name FROM products ORDER BY name LIMIT 20
OFFSET $offset;";
“Woz designed all the hardware and all the circuit boards
and all the software that went into the Appie II… not one
bug has ever been found … the circuit design of the
Apple II is widely considered to be astonishingly
beautiful, as close to perfection as one can get in
engineering.”
-- Vikram Chandra Geek Sublime
“Woz designed all the hardware and all the circuit boards
and all the software that went into the Apple II… not one
bug has ever been found … the circuit design of the
Apple II is widely considered to be astonishingly
beautiful, as close to perfection as one can get in
engineering.”
-- Vikram Chandra Geek Sublime
Hand: What we normally associate with craft
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
Mind: How much you understand
Mind: How much you understand
We can test you on this!
FizzBuzz:
Write a function that prints the numbers
from 1 to 20.
Print “Fizz” for multiples of 3
Print “Buzz” for multiples of 5
Print “FizzBuzz” for multiples of 3 and 5
FizzBuzz:
for (let i=1; i <= 20; i++) {
if (i % 3 === 0 && i % 5 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
for (let i=1; i <= 20; i++) {
if (i % 3 === 0 && i % 5 === 0) {
console.log("FizzBuzz");
} else if (i % 3 === 0) {
console.log("Fizz");
} else if (i % 5 === 0) {
console.log("Buzz");
} else {
console.log(i);
}
}
FizzBuzz:
Who cares?
function load($array) {
if(is_array($array)) {
foreach($array as $key=>$value) {
$this->vars[$key] = $value;
}
}
}
function unload($vars = '') {
if($vars) {
if(is_array($vars)) {
foreach($vars as $var) {
unset($this->vars[$var]);
}
}
else {
unset($this->vars[$vars]);
}
}
else {
$this->vars = array();
}
function fetch() {
$name= $argv[0];
$query = "SELECT id, $name FROM products;";
$result = pg_query($conn, $query);
}
function get_all() {
if($this->isAdmin) {
return $this->vars;
}
}
function load($array) {
if(is_array($array)) {
foreach($array as $key=>$value) {
$this->vars[$key] = $value;
}
}
}
function unload($vars = '') {
if($vars) {
if(is_array($vars)) {
foreach($vars as $var) {
unset($this->vars[$var]);
}
}
else {
unset($this->vars[$vars]);
}
}
else {
$this->vars = array();
}
function fetch() {
$name= $argv[0];
$query = "SELECT id, $name FROM products;";
$result = pg_query($conn, $query);
}
function get_all() {
if($this->isAdmin) {
return $this->vars;
}
}
function load($array) {
if(is_array($array)) {
foreach($array as $key=>$value) {
$this->vars[$key] = $value;
}
}
}
function unload($vars = '') {
if($vars) {
if(is_array($vars)) {
foreach($vars as $var) {
unset($this->vars[$var]);
}
}
else {
unset($this->vars[$vars]);
}
}
else {
$this->vars = array();
}
function fetch() {
$name= $argv[0];
$query = "SELECT id, $name FROM products;";
$result = pg_query($conn, $query);
}
function get_all() {
if($this->isAdmin) {
return $this->vars;
}
}
Understand Style
Understand Style
“When program statements were arranged in a
sensible order, experts were able to remember
them better than novices. When statements
were shuffled, the experts’ superiority was
reduced”
-- Steve McConnell Code Complete
Understand Style
function email() {
var form =
document.getElementById('contact-form');
var re =
/^(([^<>()[].,;:s@"]+(.[^<>()[].,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3}
.[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/;
for(input of form.elements) {if(input.test(re)) {
return input;
}
}
else{return false;
}
}
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
It works!
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
Cultivate Dissatisfaction
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
Learn Community Standards
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
Learn Community Standards:
Read Code
function AddToarray(arr, x)
{
var isInteger, updatedArr;
var val
isInteger = typeof x == 'number';
if (isInteger)
x = x + ''
var shoul_Add
if(Array.isArray(x)) {shoul_Add = false}
else {
shoul_Add=true
}
if(shoul_Add) {
if(x !== '14') {
arr.push(x);
}
}
return arr
}
Use A Linter
function addStringToArray(arr, value) {
const blackListedValue = '14';
if (Array.isArray(value)) {
return arr;
}
if (typeof value === 'number') {
value = value + '';
}
if (value !== blackListedValue) {
arr.push(value);
}
return arr;
}
function addStringToArray(arr, value) {
const blackListedValue = '14';
if (Array.isArray(value)) {
return arr;
}
if (typeof value === 'number') {
value = value + '';
}
if (value !== blackListedValue) {
arr.push(value);
}
return arr;
}
Readable.
Not Perfect.
Get Feedback
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
}
$h = new House();
$h->getRooms();
// 3
<?
class House {
public $rooms = 3;
static $bathrooms = 1;
public function getRooms() {
return $this->rooms;
}
static function getBathrooms() {
return self::$bathrooms;
}
}
$h = new House();
$h->getRooms();
// 3
$h::getBathroom();
// 1
<?
class House {
public $rooms = 3;
static $bathrooms = 1;
public function getRooms() {
return $this->rooms;
}
static function getBathrooms() {
return self::$bathrooms;
}
}
$h = new House();
$h->getRooms();
// 3
$h::getBathroom();
// 1
Code Review
<?
class House {
public $rooms = 3;
static $bathrooms = 1;
public function getRooms() {
return $this->rooms;
}
static function getBathrooms() {
return self::$bathrooms;
}
}
$h = new House();
$h->getRooms();
// 3
$h::getBathroom();
// 1
Why is this static?
<?
class House {
public $rooms = 3;
static $bathrooms = 1;
public function getRooms() {
return $this->rooms;
}
static function getBathrooms() {
return self::$bathrooms;
}
}
$h = new House();
$h->getRooms();
// 3
$h::getBathroom();
// 1
Uhh…..
<?
class House {
public $rooms = 3;
static $bathrooms = 1;
public function getRooms() {
return $this->rooms;
}
static function getBathrooms() {
return self::$bathrooms;
}
}
$h = new House();
$h->getRooms();
// 3
$h::getBathroom();
// 1
Be Deliberate
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
Do it again. Then
give it back to me.
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
Reviewers
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
Reviewers: You are
not being nice when
you withhold
feedback.
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
No feedback?
<?
class House {
public $rooms = 3;
public function getRooms() {
return $this->rooms;
}
static $bath_rooms = '1';
static function get_Bathrooms() {
$arr = [];
$arr.push(self::$bath_rooms);
if(false){
return self;
}
return self::$bath_rooms;
}
}
No feedback?
Write Test
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
Test
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
Async
Lots of conditionals
Calls another
method
Calls another
method
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
Every test and every
assertion is a statement
of why code exists
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
If it’s hard to test
function addAuthor() {
fetch('http://foo.com')
.then(data => {
return data.json();
})
.then(author => {
const { name } = author;
if(!name) {
dispatchState('Unknown')
} else {
if(name.indexOf(',')) {
const names = name.split(',');
dispatchState(`${name[0]} ${names[1]}`)
} else {
dispatchState(name);
}
}
fetchPostsByAuthor(author.id);
})
}
If it’s hard to test,
make it easier to test
Mind:
Mind: Not as important as you think
Mind: Not as important as you think
In Shakespeare:
The top 10 most frequently occuring words make up
21.4% of all words.
The top 100 most frequently occuring words make up
53.9% of all words.
Mind: Not as important as you think
✔ Basics
✔ Things work (at least it seems so)
✔ Learning by reading/doing
Relationships between parts
Relationships between parts
DNS Server Server Nginx/Apache
Index file
(backend)
RouterRender DOM
JavaScript
and CSS
Relationships between parts
/etc
/var
/sys
/sbin
/usr
Make Code Beautiful
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
?????
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
Smelly Code
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
Long parameter list
Complex conditional blocks
Uncommunicative name
Differing return statements
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
Coding Horror
Code Smells
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
Don’t
memorize
smells.
function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) {
var path;
// We need to check if they want
if(config && config.path && !config.path.match(/tmp/) && (defaultPath ||
alternativePath)) {
if(preferences.reroute && alternativePath) {
path = alternativePath + '/zone2/' + config.path;
return reroute(path); //Promise
}
if(!preferences.reroute && alternativePath) {
if(!alternativePath.match(/user/)) {
if(preferences.send) {
path = alternativePath + '/zone3' + config.path;
cb();
return;
}
path = alternativePath + '/zone2' + config.path;
}
}
// This goes on and on
}
return config.name + '/zone5/' + config.path;
}
Trust yourself
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
Build Intuition and Refactoring
Pop Quiz
Build Intuition and Refactoring
1. Get an array of unique items
2. Determines if a string starts
with an uppercase letter
3. Calculate the area of a circle
given radius
function getUniqueItems(arr) {
let unique = [];
for(let item of arr) {
if(!unique.includes(item)) {
unique.push(item);
}
}
return unique;
}
function getUniqueItems(arr) {
let unique = [];
for(let item of arr) {
if(!unique.includes(item)) {
unique.push(item);
}
}
return unique;
}
Cultivate Disatisfaction
function getUniqueItems(arr) {
let unique = [];
for(let item of arr) {
if(!unique.includes(item)) {
unique.push(item);
}
}
return unique;
}
You can look up
solved problems
function getUniqueItems(arr) {
return arr.reduce((unique, item) => {
return unique.includes(item) ? unique : [...unique, item];
}, [])
}
function getUniqueItems(arr) {
return arr.reduce((unique, item) => {
return unique.includes(item) ? unique : [...unique, item];
}, [])
}
Iterate Over Ideas
function getUniqueItems(items) {
return [...new Set(items)];
}
function getUniqueItems(items) {
return [...new Set(items)];
}
Test
Tools, Principles, Patterns
Why do things exist
Why do things exist
Why do things exist
const x = ['a', 'b', 'c'];
...x
// 'a', 'b', 'c'
Solve the problem
const x = ['a', 'b', 'c'];
x.push('d');
x;
['a', 'b', 'c', 'd'];
const x = ['a', 'b', 'c'];
x.push('d');
x;
['a', 'b', 'c', 'd'];
What is the [X] way to solve the
problem?
const x = ['a', 'b', 'c'];
x.push('d');
x;
['a', 'b', 'c', 'd'];
What is the JavaScript way to
solve the problem?
const x = ['a', 'b', 'c'];
x.push('d');
x;
['a', 'b', 'c', 'd'];
What is the JavaScript way to
solve the problem?
mutation
const x = ['a', 'b', 'c'];
const y = [...x, 'd'];
y;
['a', 'b', 'c', 'd'];
x;
['a', 'b', 'c'];
What is the JavaScript way to
solve the problem?
const x = ['a', 'a', 'b', 'c'];
const copyX = [...x];
const combined = [...x, ...y];
const unique = [...new Set(x)];
What is the JavaScript way to
solve the problem?
What is the JavaScript way to
solve the problem?
const x = ['a', 'a', 'b', 'c'];
const copyX = [...x];
const combined = [...x, ...y];
const unique = [...new Set(x)];
No Mutations
What is the Python way to solve
the problem?
Suspicious Python Devs
Learn Principles
Learn Principles
… BUT they should really be
there to solidify what you’ve
been seeing
Learn Principles
This was the book that showed me there were
names for so many patterns that I’d discovered
purely through fumbling around with my own code.
-- Rebecca Murphey on JavaScript Patterns
Learn Principles
… they are there to help
communicate
Learn Principles
Experience without theory is
blind, but theory without
experience is mere intellectual
play -- Immanuel Kant
Learn Principles
… run everything through your
hands or eyes
Learn Principles
… Before I created Rails, I redrew many of the
diagrams in OmniGraffle for Martin Fowler because
I liked the book so much
-- David on Patterns of Enterprise Architecture
Learn Principles
…The trick to reading this book is to carefully read
through every single refactoring pattern and then
try to apply it on your code base (you don’t have to
commit if it doesn’t fix things). You can’t just blow
through it or you won’t really learn it.
-- David on Refactoring
Learn Principles
✔ Algorithms
✔ Mutations/Side Effects
✔ Patterns (Gang of Four)
✔ SOLID
See Abstractions Across Projects
“We have included only designs
that have been applied more
than once in different systems…
Most … have never been
documented before”
-- Gang of Four Design Patterns
“How many times have you
had design déjà vu -- that
feeling that you’ve solved a
problem before but not
knowing exactly where or
how?
Foo.js
Foo.js -- src
-- components
-- button.js
-- link.js
-- footer.js
-- util
-- colors
Foo.js -- src
-- components
-- button.js
-- link.js
-- footer.js
-- util
-- colors
Reusable
Rule of three:
“The first time you do something, you just do
it. The second time you do something similar,
you wince at the duplication, but you do the
duplicate thing anyway. Third you do
something similar, you refactor.”
-- Martin Fowler Refactoring
Decoupled
import fetch from 'isomorphic-fetch';
function updateInventory(store) {
return fetch(`http://foo.com/inventory?key=abc&name=${store}`)
.then(response => response.json())
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
import fetch from 'isomorphic-fetch';
function updateInventory(store) {
return fetch(`http://foo.com/inventory?key=abc&name=${store}`)
.then(response => response.json())
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
Tightly coupled to api
import expect from 'expect';
import nock from 'nock';
import updateInventory from './coupled1';
describe('inventory update', () => {
it('should update inventory', () => {
nock('http://foo.com')
.get('/inventory')
.query({
key: 'abc',
name: 'bar',
})
.reply(200, { inventory: 1350 });
return updateInventory('bar').then((result) => {
expect(result).toEqual('Inventory is 1,350.');
});
});
});
import expect from 'expect';
import nock from 'nock';
import updateInventory from './coupled1';
describe('inventory update', () => {
it('should update inventory', () => {
nock('http://foo.com')
.get('/inventory')
.query({
key: 'abc',
name: 'bar',
})
.reply(200, { inventory: 1350 });
return updateInventory('bar').then((result) => {
expect(result).toEqual('Inventory is 1,350.');
});
});
});
Hijack the http request
import { getInventory } from './inventoryManager';
function updateInventory(store) {
return getInventory(store)
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
import { getInventory } from './inventoryManager';
function updateInventory(store) {
return getInventory(store)
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
Endpoint removed
import expect from 'expect';
import sinon from 'sinon';
import updateInventory from './coupled';
import * as i from './inventoryManager';
describe('inventory update', () => {
beforeEach(() => {
const fetchInventory = new Promise(resolve => resolve({ inventory: 1350 }));
sinon.stub(i, 'getInventory').returns(fetchInventory);
});
afterEach(() => {
i.getInventory.restore();
});
it('should update inventory', () => updateInventory('bar').then((result) => {
expect(result).toEqual('Inventory is 1,350.');
}));
});
import expect from 'expect';
import sinon from 'sinon';
import updateInventory from './coupled';
import * as i from './inventoryManager';
describe('inventory update', () => {
beforeEach(() => {
const fetchInventory = new Promise(resolve => resolve({ inventory: 1350 }));
sinon.stub(i, 'getInventory').returns(fetchInventory);
});
afterEach(() => {
i.getInventory.restore();
});
it('should update inventory', () => updateInventory('bar').then((result) => {
expect(result).toEqual('Inventory is 1,350.');
}));
});
Mocking
function updateInventory(store, fetchInventory) {
return fetchInventory
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
function updateInventory(store, fetchInventory) {
return fetchInventory
.then((result) => {
const count = result.inventory.toLocaleString();
return `Inventory is ${count}.`;
});
}
export default updateInventory;
Inject everything
import expect from 'expect';
import updateInventory from './coupled3';
describe('inventory update', () => {
it('should update inventory', () => {
const fetchInventory = new Promise(resolve => {
resolve({ inventory: 1350 })
});
return updateInventory('bar', fetchInventory).then((result) => {
expect(result).toEqual('Inventory is 1,350.');
});
});
});
Creatively Apply Ideas
Master the why of your language
first
Redux
Dan Abramov
Wanted to speak at a JS
conference in Europe.
Redux
Dan Abramov
Applied Elm architecture in React
Redux
Elm
UI
UpdateView
message
model
HTML
Redux
UI
ReducerView
action
state
HTML
JavaScript
Brendan Eich was recruited to make Scheme into a
scripting language. Netscape partner Sun Systems
demanded it be similar to Java.
Brendan Eich wrote it in 10 days.
Linux
Linus Torvalds wanted to try out a new
chip.
Linux
I'm doing a (free) operating system (just a hobby, won't be big and
professional like gnu)... This has been brewing since april, and is
starting to get ready. I'd like any feedback on things people
like/dislike in minix, as my OS resembles it somewhat (same
physical layout of the file-system...
Why
Bored.
Curious.
Dictated.
Why
They understood their inspirational
material enough to take what they needed.
Style Feedback Flow
Beautiful Refactor Patterns
Abstract Reusable Creativity
Why?
Joe Morgan
@joesmorgan | thejoemorgan.com

Mais conteúdo relacionado

Mais procurados

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIOJohn De Goes
 
History of jQuery
History of jQueryHistory of jQuery
History of jQueryjeresig
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patternsSamuel ROZE
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeStripe
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptGuy Royse
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeMongoDB
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingSamuel ROZE
 
The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212Mahmoud Samir Fayed
 
Node meetup feb_20_12
Node meetup feb_20_12Node meetup feb_20_12
Node meetup feb_20_12jafar104
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form componentSamuel ROZE
 
Writing Your App Swiftly
Writing Your App SwiftlyWriting Your App Swiftly
Writing Your App SwiftlySommer Panage
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Konstantin Kudryashov
 
Beautiful python - PyLadies
Beautiful python - PyLadiesBeautiful python - PyLadies
Beautiful python - PyLadiesAlicia Pérez
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICKonstantin Kudryashov
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testingVisual Engineering
 

Mais procurados (20)

Error Management: Future vs ZIO
Error Management: Future vs ZIOError Management: Future vs ZIO
Error Management: Future vs ZIO
 
History of jQuery
History of jQueryHistory of jQuery
History of jQuery
 
How I started to love design patterns
How I started to love design patternsHow I started to love design patterns
How I started to love design patterns
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 
Building Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at StripeBuilding Real Time Systems on MongoDB Using the Oplog at Stripe
Building Real Time Systems on MongoDB Using the Oplog at Stripe
 
Introduction to CQRS and Event Sourcing
Introduction to CQRS and Event SourcingIntroduction to CQRS and Event Sourcing
Introduction to CQRS and Event Sourcing
 
The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212The Ring programming language version 1.10 book - Part 70 of 212
The Ring programming language version 1.10 book - Part 70 of 212
 
mobl
moblmobl
mobl
 
Node meetup feb_20_12
Node meetup feb_20_12Node meetup feb_20_12
Node meetup feb_20_12
 
Symfony CoP: Form component
Symfony CoP: Form componentSymfony CoP: Form component
Symfony CoP: Form component
 
Writing Your App Swiftly
Writing Your App SwiftlyWriting Your App Swiftly
Writing Your App Swiftly
 
Hidden rocks in Oracle ADF
Hidden rocks in Oracle ADFHidden rocks in Oracle ADF
Hidden rocks in Oracle ADF
 
Say It With Javascript
Say It With JavascriptSay It With Javascript
Say It With Javascript
 
Min-Maxing Software Costs
Min-Maxing Software CostsMin-Maxing Software Costs
Min-Maxing Software Costs
 
Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015Min-Maxing Software Costs - Laracon EU 2015
Min-Maxing Software Costs - Laracon EU 2015
 
Method::Signatures
Method::SignaturesMethod::Signatures
Method::Signatures
 
Beautiful python - PyLadies
Beautiful python - PyLadiesBeautiful python - PyLadies
Beautiful python - PyLadies
 
Decoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DICDecoupling with Design Patterns and Symfony2 DIC
Decoupling with Design Patterns and Symfony2 DIC
 
Workshop 5: JavaScript testing
Workshop 5: JavaScript testingWorkshop 5: JavaScript testing
Workshop 5: JavaScript testing
 

Semelhante a Unbreakable Craftsmanship in Software Development

WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015Fernando Daciuk
 
Hypercritical C++ Code Review
Hypercritical C++ Code ReviewHypercritical C++ Code Review
Hypercritical C++ Code ReviewAndrey Karpov
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript FunctionsColin DeCarlo
 
Idioms in swift 2016 05c
Idioms in swift 2016 05cIdioms in swift 2016 05c
Idioms in swift 2016 05cKaz Yoshikawa
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Librariesjeresig
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Codemotion
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code DevelopmentPeter Gfader
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRaimonds Simanovskis
 
Pick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruitPick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruitVaclav Pech
 
Asynchronous Programming with JavaScript
Asynchronous Programming with JavaScriptAsynchronous Programming with JavaScript
Asynchronous Programming with JavaScriptWebF
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesAndrey Karpov
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...DevGAMM Conference
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React AlicanteIgnacio Martín
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++Alexander Granin
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchainedEduard Tomàs
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Ignacio Martín
 

Semelhante a Unbreakable Craftsmanship in Software Development (20)

ES6: The Awesome Parts
ES6: The Awesome PartsES6: The Awesome Parts
ES6: The Awesome Parts
 
WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015WordPress Realtime - WordCamp São Paulo 2015
WordPress Realtime - WordCamp São Paulo 2015
 
Hypercritical C++ Code Review
Hypercritical C++ Code ReviewHypercritical C++ Code Review
Hypercritical C++ Code Review
 
JavaScript Functions
JavaScript FunctionsJavaScript Functions
JavaScript Functions
 
Idioms in swift 2016 05c
Idioms in swift 2016 05cIdioms in swift 2016 05c
Idioms in swift 2016 05c
 
Secrets of JavaScript Libraries
Secrets of JavaScript LibrariesSecrets of JavaScript Libraries
Secrets of JavaScript Libraries
 
Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016Promises are so passé - Tim Perry - Codemotion Milan 2016
Promises are so passé - Tim Perry - Codemotion Milan 2016
 
Clean Code Development
Clean Code DevelopmentClean Code Development
Clean Code Development
 
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and JasmineRails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
Rails-like JavaScript Using CoffeeScript, Backbone.js and Jasmine
 
Pick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruitPick up the low-hanging concurrency fruit
Pick up the low-hanging concurrency fruit
 
lets play with "c"..!!! :):)
lets play with "c"..!!! :):)lets play with "c"..!!! :):)
lets play with "c"..!!! :):)
 
Asynchronous Programming with JavaScript
Asynchronous Programming with JavaScriptAsynchronous Programming with JavaScript
Asynchronous Programming with JavaScript
 
Best Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' MistakesBest Bugs from Games: Fellow Programmers' Mistakes
Best Bugs from Games: Fellow Programmers' Mistakes
 
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
Самые вкусные баги из игрового кода: как ошибаются наши коллеги-программисты ...
 
Redux Sagas - React Alicante
Redux Sagas - React AlicanteRedux Sagas - React Alicante
Redux Sagas - React Alicante
 
JQuery Flot
JQuery FlotJQuery Flot
JQuery Flot
 
The present and the future of functional programming in c++
The present and the future of functional programming in c++The present and the future of functional programming in c++
The present and the future of functional programming in c++
 
EcmaScript unchained
EcmaScript unchainedEcmaScript unchained
EcmaScript unchained
 
Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6Redux saga: managing your side effects. Also: generators in es6
Redux saga: managing your side effects. Also: generators in es6
 
The evolution of asynchronous JavaScript
The evolution of asynchronous JavaScriptThe evolution of asynchronous JavaScript
The evolution of asynchronous JavaScript
 

Mais de Joe Morgan

Git the easy way
Git the easy wayGit the easy way
Git the easy wayJoe Morgan
 
React Animations
React AnimationsReact Animations
React AnimationsJoe Morgan
 
Reference Interviews: Where the fun never ends
Reference Interviews: Where the fun never endsReference Interviews: Where the fun never ends
Reference Interviews: Where the fun never endsJoe Morgan
 
Statement of Teaching Philosophy
Statement of Teaching PhilosophyStatement of Teaching Philosophy
Statement of Teaching PhilosophyJoe Morgan
 
Library Committee Meeting
Library Committee MeetingLibrary Committee Meeting
Library Committee MeetingJoe Morgan
 

Mais de Joe Morgan (6)

Git the easy way
Git the easy wayGit the easy way
Git the easy way
 
React Animations
React AnimationsReact Animations
React Animations
 
Reference Interviews: Where the fun never ends
Reference Interviews: Where the fun never endsReference Interviews: Where the fun never ends
Reference Interviews: Where the fun never ends
 
Statement of Teaching Philosophy
Statement of Teaching PhilosophyStatement of Teaching Philosophy
Statement of Teaching Philosophy
 
Option 2
Option 2Option 2
Option 2
 
Library Committee Meeting
Library Committee MeetingLibrary Committee Meeting
Library Committee Meeting
 

Último

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.Curtis Poe
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfLoriGlavin3
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteDianaGray10
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch TuesdayIvanti
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Hiroshi SHIBATA
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsRavi Sanghani
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...panagenda
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Scott Andery
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesThousandEyes
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .Alan Dix
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesKari Kakkonen
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxLoriGlavin3
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityIES VE
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity PlanDatabarracks
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Strongerpanagenda
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 

Último (20)

How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.How AI, OpenAI, and ChatGPT impact business and software.
How AI, OpenAI, and ChatGPT impact business and software.
 
Moving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdfMoving Beyond Passwords: FIDO Paris Seminar.pdf
Moving Beyond Passwords: FIDO Paris Seminar.pdf
 
Take control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test SuiteTake control of your SAP testing with UiPath Test Suite
Take control of your SAP testing with UiPath Test Suite
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
2024 April Patch Tuesday
2024 April Patch Tuesday2024 April Patch Tuesday
2024 April Patch Tuesday
 
Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024Long journey of Ruby standard library at RubyConf AU 2024
Long journey of Ruby standard library at RubyConf AU 2024
 
Potential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and InsightsPotential of AI (Generative AI) in Business: Learnings and Insights
Potential of AI (Generative AI) in Business: Learnings and Insights
 
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
Why device, WIFI, and ISP insights are crucial to supporting remote Microsoft...
 
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
Enhancing User Experience - Exploring the Latest Features of Tallyman Axis Lo...
 
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyesHow to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
How to Effectively Monitor SD-WAN and SASE Environments with ThousandEyes
 
From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .From Family Reminiscence to Scholarly Archive .
From Family Reminiscence to Scholarly Archive .
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 
Testing tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examplesTesting tools and AI - ideas what to try with some tool examples
Testing tools and AI - ideas what to try with some tool examples
 
A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptxUse of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
Use of FIDO in the Payments and Identity Landscape: FIDO Paris Seminar.pptx
 
Decarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a realityDecarbonising Buildings: Making a net-zero built environment a reality
Decarbonising Buildings: Making a net-zero built environment a reality
 
How to write a Business Continuity Plan
How to write a Business Continuity PlanHow to write a Business Continuity Plan
How to write a Business Continuity Plan
 
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better StrongerModern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
Modern Roaming for Notes and Nomad – Cheaper Faster Better Stronger
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 

Unbreakable Craftsmanship in Software Development

  • 3.
  • 4.
  • 5. “Woz designed all the hardware and all the circuit boards and all the software that went into the Apple II… not one bug has ever been found … the circuit design of the Apple II is widely considered to be astonishingly beautiful, as close to perfection as one can get in engineering.” -- Vikram Chandra Geek Sublime
  • 9.
  • 10.
  • 12. Woz Flow Chart: Be A Genius Build Stuff
  • 13.
  • 14. Woz Flow Chart: Be A Genius Build Stuff Learn Learn Learn Learn Learn Learn Learn LearnLearn Learn Learn Learn Learn Build Build Build Build Build Build BuildBuild Build Build Build Build Build Learn Learn Build Build Build Learn Learn LearnLearn Build Build Build Learn Build Build Learn Learn LearnLearn Build Build Build Build Learn Learn Learn Build Build Build Learn Learn Learn Build Build Learn Learn Build Build Build
  • 19. I write code I try to get a little better everyday
  • 28. How does that relate to software?
  • 30.
  • 31.
  • 33.
  • 34. $$
  • 35.
  • 36. Love
  • 42. Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
  • 43. Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
  • 44. Server Dev Ops AngularNoSQL Functional OOAWS SQL DB
  • 45. Server Dev Ops Angular 2NoSQL Functional OOAWS SQL DB
  • 46. How do we improve?
  • 47. Eye: What can you see?
  • 48. Eye: What can you see? Hand: What can you build?
  • 49. Eye: What can you see? Hand: What can you build? Mind: What do you know?
  • 50.
  • 51.
  • 52.
  • 53. [The chipping paint] could be an example of machine-cutting "without sharp blades," adding "it looks like they painted before they actually cut the piece."
  • 54. [The chipping paint] could be an example of machine-cutting "without sharp blades," adding "it looks like they painted before they actually cut the piece."
  • 55.
  • 56.
  • 57. [The chipping paint] could be an example of machine-cutting "without sharp blades," adding "it looks like they painted before they actually cut the piece."
  • 58. $offset = $argv[0]; $query = "SELECT id, name FROM products ORDER BY name LIMIT 20 OFFSET $offset;";
  • 59. “Woz designed all the hardware and all the circuit boards and all the software that went into the Appie II… not one bug has ever been found … the circuit design of the Apple II is widely considered to be astonishingly beautiful, as close to perfection as one can get in engineering.” -- Vikram Chandra Geek Sublime
  • 60. “Woz designed all the hardware and all the circuit boards and all the software that went into the Apple II… not one bug has ever been found … the circuit design of the Apple II is widely considered to be astonishingly beautiful, as close to perfection as one can get in engineering.” -- Vikram Chandra Geek Sublime
  • 61.
  • 62. Hand: What we normally associate with craft
  • 63. function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
  • 64. function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
  • 65. function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
  • 66. Mind: How much you understand
  • 67. Mind: How much you understand We can test you on this!
  • 68. FizzBuzz: Write a function that prints the numbers from 1 to 20. Print “Fizz” for multiples of 3 Print “Buzz” for multiples of 5 Print “FizzBuzz” for multiples of 3 and 5
  • 69. FizzBuzz: for (let i=1; i <= 20; i++) { if (i % 3 === 0 && i % 5 === 0) { console.log("FizzBuzz"); } else if (i % 3 === 0) { console.log("Fizz"); } else if (i % 5 === 0) { console.log("Buzz"); } else { console.log(i); } }
  • 70. for (let i=1; i <= 20; i++) { if (i % 3 === 0 && i % 5 === 0) { console.log("FizzBuzz"); } else if (i % 3 === 0) { console.log("Fizz"); } else if (i % 5 === 0) { console.log("Buzz"); } else { console.log(i); } } FizzBuzz: Who cares?
  • 71. function load($array) { if(is_array($array)) { foreach($array as $key=>$value) { $this->vars[$key] = $value; } } } function unload($vars = '') { if($vars) { if(is_array($vars)) { foreach($vars as $var) { unset($this->vars[$var]); } } else { unset($this->vars[$vars]); } } else { $this->vars = array(); } function fetch() { $name= $argv[0]; $query = "SELECT id, $name FROM products;"; $result = pg_query($conn, $query); } function get_all() { if($this->isAdmin) { return $this->vars; } }
  • 72. function load($array) { if(is_array($array)) { foreach($array as $key=>$value) { $this->vars[$key] = $value; } } } function unload($vars = '') { if($vars) { if(is_array($vars)) { foreach($vars as $var) { unset($this->vars[$var]); } } else { unset($this->vars[$vars]); } } else { $this->vars = array(); } function fetch() { $name= $argv[0]; $query = "SELECT id, $name FROM products;"; $result = pg_query($conn, $query); } function get_all() { if($this->isAdmin) { return $this->vars; } }
  • 73. function load($array) { if(is_array($array)) { foreach($array as $key=>$value) { $this->vars[$key] = $value; } } } function unload($vars = '') { if($vars) { if(is_array($vars)) { foreach($vars as $var) { unset($this->vars[$var]); } } else { unset($this->vars[$vars]); } } else { $this->vars = array(); } function fetch() { $name= $argv[0]; $query = "SELECT id, $name FROM products;"; $result = pg_query($conn, $query); } function get_all() { if($this->isAdmin) { return $this->vars; } }
  • 74.
  • 75.
  • 77. Understand Style “When program statements were arranged in a sensible order, experts were able to remember them better than novices. When statements were shuffled, the experts’ superiority was reduced” -- Steve McConnell Code Complete
  • 78. Understand Style function email() { var form = document.getElementById('contact-form'); var re = /^(([^<>()[].,;:s@"]+(.[^<>()[].,;:s@"]+)*)|(".+"))@(([[0-9]{1,3}.[0-9]{1,3} .[0-9]{1,3}.[0-9]{1,3}])|(([a-zA-Z-0-9]+.)+[a-zA-Z]{2,}))$/; for(input of form.elements) {if(input.test(re)) { return input; } } else{return false; } }
  • 79. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr }
  • 80. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr } It works!
  • 81. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr } Cultivate Dissatisfaction
  • 82. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr }
  • 83. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr } Learn Community Standards
  • 84. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr } Learn Community Standards: Read Code
  • 85. function AddToarray(arr, x) { var isInteger, updatedArr; var val isInteger = typeof x == 'number'; if (isInteger) x = x + '' var shoul_Add if(Array.isArray(x)) {shoul_Add = false} else { shoul_Add=true } if(shoul_Add) { if(x !== '14') { arr.push(x); } } return arr } Use A Linter
  • 86. function addStringToArray(arr, value) { const blackListedValue = '14'; if (Array.isArray(value)) { return arr; } if (typeof value === 'number') { value = value + ''; } if (value !== blackListedValue) { arr.push(value); } return arr; }
  • 87. function addStringToArray(arr, value) { const blackListedValue = '14'; if (Array.isArray(value)) { return arr; } if (typeof value === 'number') { value = value + ''; } if (value !== blackListedValue) { arr.push(value); } return arr; } Readable. Not Perfect.
  • 89. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } } $h = new House(); $h->getRooms(); // 3
  • 90. <? class House { public $rooms = 3; static $bathrooms = 1; public function getRooms() { return $this->rooms; } static function getBathrooms() { return self::$bathrooms; } } $h = new House(); $h->getRooms(); // 3 $h::getBathroom(); // 1
  • 91. <? class House { public $rooms = 3; static $bathrooms = 1; public function getRooms() { return $this->rooms; } static function getBathrooms() { return self::$bathrooms; } } $h = new House(); $h->getRooms(); // 3 $h::getBathroom(); // 1 Code Review
  • 92. <? class House { public $rooms = 3; static $bathrooms = 1; public function getRooms() { return $this->rooms; } static function getBathrooms() { return self::$bathrooms; } } $h = new House(); $h->getRooms(); // 3 $h::getBathroom(); // 1 Why is this static?
  • 93. <? class House { public $rooms = 3; static $bathrooms = 1; public function getRooms() { return $this->rooms; } static function getBathrooms() { return self::$bathrooms; } } $h = new House(); $h->getRooms(); // 3 $h::getBathroom(); // 1 Uhh…..
  • 94. <? class House { public $rooms = 3; static $bathrooms = 1; public function getRooms() { return $this->rooms; } static function getBathrooms() { return self::$bathrooms; } } $h = new House(); $h->getRooms(); // 3 $h::getBathroom(); // 1 Be Deliberate
  • 95. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } }
  • 96. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } } Do it again. Then give it back to me.
  • 97. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } } Reviewers
  • 98. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } } Reviewers: You are not being nice when you withhold feedback.
  • 99. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } } No feedback?
  • 100. <? class House { public $rooms = 3; public function getRooms() { return $this->rooms; } static $bath_rooms = '1'; static function get_Bathrooms() { $arr = []; $arr.push(self::$bath_rooms); if(false){ return self; } return self::$bath_rooms; } } No feedback? Write Test
  • 101. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) }
  • 102. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) } Test
  • 103. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) } Async Lots of conditionals Calls another method Calls another method
  • 104. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) } Every test and every assertion is a statement of why code exists
  • 105. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) } If it’s hard to test
  • 106. function addAuthor() { fetch('http://foo.com') .then(data => { return data.json(); }) .then(author => { const { name } = author; if(!name) { dispatchState('Unknown') } else { if(name.indexOf(',')) { const names = name.split(','); dispatchState(`${name[0]} ${names[1]}`) } else { dispatchState(name); } } fetchPostsByAuthor(author.id); }) } If it’s hard to test, make it easier to test
  • 107. Mind:
  • 108. Mind: Not as important as you think
  • 109. Mind: Not as important as you think In Shakespeare: The top 10 most frequently occuring words make up 21.4% of all words. The top 100 most frequently occuring words make up 53.9% of all words.
  • 110. Mind: Not as important as you think ✔ Basics ✔ Things work (at least it seems so) ✔ Learning by reading/doing
  • 112. Relationships between parts DNS Server Server Nginx/Apache Index file (backend) RouterRender DOM JavaScript and CSS
  • 114.
  • 116. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; }
  • 117.
  • 118. ?????
  • 119.
  • 120. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; }
  • 121. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; } Smelly Code
  • 122. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; } Long parameter list Complex conditional blocks Uncommunicative name Differing return statements
  • 123. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; } Coding Horror Code Smells
  • 124. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; } Don’t memorize smells.
  • 125. function formatPathStr(config, preferences, defaultPath, alternativePath, reroute, cb) { var path; // We need to check if they want if(config && config.path && !config.path.match(/tmp/) && (defaultPath || alternativePath)) { if(preferences.reroute && alternativePath) { path = alternativePath + '/zone2/' + config.path; return reroute(path); //Promise } if(!preferences.reroute && alternativePath) { if(!alternativePath.match(/user/)) { if(preferences.send) { path = alternativePath + '/zone3' + config.path; cb(); return; } path = alternativePath + '/zone2' + config.path; } } // This goes on and on } return config.name + '/zone5/' + config.path; } Trust yourself
  • 126.
  • 127. function createThunkMiddleware(extraArgument) { return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; } const thunk = createThunkMiddleware(); thunk.withExtraArgument = createThunkMiddleware; export default thunk;
  • 128.
  • 129. Build Intuition and Refactoring
  • 130. Pop Quiz Build Intuition and Refactoring
  • 131. 1. Get an array of unique items 2. Determines if a string starts with an uppercase letter 3. Calculate the area of a circle given radius
  • 132. function getUniqueItems(arr) { let unique = []; for(let item of arr) { if(!unique.includes(item)) { unique.push(item); } } return unique; }
  • 133. function getUniqueItems(arr) { let unique = []; for(let item of arr) { if(!unique.includes(item)) { unique.push(item); } } return unique; } Cultivate Disatisfaction
  • 134. function getUniqueItems(arr) { let unique = []; for(let item of arr) { if(!unique.includes(item)) { unique.push(item); } } return unique; } You can look up solved problems
  • 135. function getUniqueItems(arr) { return arr.reduce((unique, item) => { return unique.includes(item) ? unique : [...unique, item]; }, []) }
  • 136. function getUniqueItems(arr) { return arr.reduce((unique, item) => { return unique.includes(item) ? unique : [...unique, item]; }, []) } Iterate Over Ideas
  • 137. function getUniqueItems(items) { return [...new Set(items)]; }
  • 138. function getUniqueItems(items) { return [...new Set(items)]; } Test
  • 140. Why do things exist
  • 141. Why do things exist
  • 142. Why do things exist const x = ['a', 'b', 'c']; ...x // 'a', 'b', 'c'
  • 143. Solve the problem const x = ['a', 'b', 'c']; x.push('d'); x; ['a', 'b', 'c', 'd'];
  • 144. const x = ['a', 'b', 'c']; x.push('d'); x; ['a', 'b', 'c', 'd']; What is the [X] way to solve the problem?
  • 145. const x = ['a', 'b', 'c']; x.push('d'); x; ['a', 'b', 'c', 'd']; What is the JavaScript way to solve the problem?
  • 146. const x = ['a', 'b', 'c']; x.push('d'); x; ['a', 'b', 'c', 'd']; What is the JavaScript way to solve the problem? mutation
  • 147. const x = ['a', 'b', 'c']; const y = [...x, 'd']; y; ['a', 'b', 'c', 'd']; x; ['a', 'b', 'c']; What is the JavaScript way to solve the problem?
  • 148. const x = ['a', 'a', 'b', 'c']; const copyX = [...x]; const combined = [...x, ...y]; const unique = [...new Set(x)]; What is the JavaScript way to solve the problem?
  • 149. What is the JavaScript way to solve the problem? const x = ['a', 'a', 'b', 'c']; const copyX = [...x]; const combined = [...x, ...y]; const unique = [...new Set(x)]; No Mutations
  • 150. What is the Python way to solve the problem?
  • 152.
  • 153.
  • 155. Learn Principles … BUT they should really be there to solidify what you’ve been seeing
  • 156. Learn Principles This was the book that showed me there were names for so many patterns that I’d discovered purely through fumbling around with my own code. -- Rebecca Murphey on JavaScript Patterns
  • 157. Learn Principles … they are there to help communicate
  • 158. Learn Principles Experience without theory is blind, but theory without experience is mere intellectual play -- Immanuel Kant
  • 159. Learn Principles … run everything through your hands or eyes
  • 160. Learn Principles … Before I created Rails, I redrew many of the diagrams in OmniGraffle for Martin Fowler because I liked the book so much -- David on Patterns of Enterprise Architecture
  • 161. Learn Principles …The trick to reading this book is to carefully read through every single refactoring pattern and then try to apply it on your code base (you don’t have to commit if it doesn’t fix things). You can’t just blow through it or you won’t really learn it. -- David on Refactoring
  • 162. Learn Principles ✔ Algorithms ✔ Mutations/Side Effects ✔ Patterns (Gang of Four) ✔ SOLID
  • 163.
  • 164.
  • 166.
  • 167. “We have included only designs that have been applied more than once in different systems… Most … have never been documented before” -- Gang of Four Design Patterns
  • 168. “How many times have you had design déjà vu -- that feeling that you’ve solved a problem before but not knowing exactly where or how?
  • 169.
  • 170. Foo.js
  • 171. Foo.js -- src -- components -- button.js -- link.js -- footer.js -- util -- colors
  • 172. Foo.js -- src -- components -- button.js -- link.js -- footer.js -- util -- colors
  • 174. Rule of three: “The first time you do something, you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. Third you do something similar, you refactor.” -- Martin Fowler Refactoring
  • 176.
  • 177. import fetch from 'isomorphic-fetch'; function updateInventory(store) { return fetch(`http://foo.com/inventory?key=abc&name=${store}`) .then(response => response.json()) .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory;
  • 178. import fetch from 'isomorphic-fetch'; function updateInventory(store) { return fetch(`http://foo.com/inventory?key=abc&name=${store}`) .then(response => response.json()) .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory; Tightly coupled to api
  • 179. import expect from 'expect'; import nock from 'nock'; import updateInventory from './coupled1'; describe('inventory update', () => { it('should update inventory', () => { nock('http://foo.com') .get('/inventory') .query({ key: 'abc', name: 'bar', }) .reply(200, { inventory: 1350 }); return updateInventory('bar').then((result) => { expect(result).toEqual('Inventory is 1,350.'); }); }); });
  • 180. import expect from 'expect'; import nock from 'nock'; import updateInventory from './coupled1'; describe('inventory update', () => { it('should update inventory', () => { nock('http://foo.com') .get('/inventory') .query({ key: 'abc', name: 'bar', }) .reply(200, { inventory: 1350 }); return updateInventory('bar').then((result) => { expect(result).toEqual('Inventory is 1,350.'); }); }); }); Hijack the http request
  • 181. import { getInventory } from './inventoryManager'; function updateInventory(store) { return getInventory(store) .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory;
  • 182. import { getInventory } from './inventoryManager'; function updateInventory(store) { return getInventory(store) .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory; Endpoint removed
  • 183. import expect from 'expect'; import sinon from 'sinon'; import updateInventory from './coupled'; import * as i from './inventoryManager'; describe('inventory update', () => { beforeEach(() => { const fetchInventory = new Promise(resolve => resolve({ inventory: 1350 })); sinon.stub(i, 'getInventory').returns(fetchInventory); }); afterEach(() => { i.getInventory.restore(); }); it('should update inventory', () => updateInventory('bar').then((result) => { expect(result).toEqual('Inventory is 1,350.'); })); });
  • 184. import expect from 'expect'; import sinon from 'sinon'; import updateInventory from './coupled'; import * as i from './inventoryManager'; describe('inventory update', () => { beforeEach(() => { const fetchInventory = new Promise(resolve => resolve({ inventory: 1350 })); sinon.stub(i, 'getInventory').returns(fetchInventory); }); afterEach(() => { i.getInventory.restore(); }); it('should update inventory', () => updateInventory('bar').then((result) => { expect(result).toEqual('Inventory is 1,350.'); })); }); Mocking
  • 185. function updateInventory(store, fetchInventory) { return fetchInventory .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory;
  • 186. function updateInventory(store, fetchInventory) { return fetchInventory .then((result) => { const count = result.inventory.toLocaleString(); return `Inventory is ${count}.`; }); } export default updateInventory; Inject everything
  • 187. import expect from 'expect'; import updateInventory from './coupled3'; describe('inventory update', () => { it('should update inventory', () => { const fetchInventory = new Promise(resolve => { resolve({ inventory: 1350 }) }); return updateInventory('bar', fetchInventory).then((result) => { expect(result).toEqual('Inventory is 1,350.'); }); }); });
  • 188.
  • 190. Master the why of your language first
  • 191. Redux
  • 192. Dan Abramov Wanted to speak at a JS conference in Europe. Redux
  • 193. Dan Abramov Applied Elm architecture in React Redux
  • 196. JavaScript Brendan Eich was recruited to make Scheme into a scripting language. Netscape partner Sun Systems demanded it be similar to Java. Brendan Eich wrote it in 10 days.
  • 197.
  • 198. Linux Linus Torvalds wanted to try out a new chip.
  • 199. Linux I'm doing a (free) operating system (just a hobby, won't be big and professional like gnu)... This has been brewing since april, and is starting to get ready. I'd like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system...
  • 201. Why They understood their inspirational material enough to take what they needed.
  • 202. Style Feedback Flow Beautiful Refactor Patterns Abstract Reusable Creativity
  • 203. Why?
  • 204. Joe Morgan @joesmorgan | thejoemorgan.com