What the hell is an object?
EverythingIsAnObject... ?
var iAmAnObject = {};
var soAmI = 5 ;
var ifYouAreSoAmI = null ;
var imAnObject = [];
Definitions in JS
everything that isn't null/undefined
empty objects used as key-value stores
things that have functions in them that reference 'this'
Let's ask Alan Kay
OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.
Alan Kay
So what do Alan Kay's objects look like?
Technical diagram
messaging/late binding
hiding of state
Messaging & late-binding
component sends a message
another components receives and does... whatever it likes
Results of messaging
decouples intent from implementation (polymorphism)
can't see/modify state of receiver
What the hell are objects?
'Objects' are a pattern
not the specific implementation
Alan Kay's objects are
entities that accept messages
that access hidden state
and do something in response to the message
Everything
var a = 10 ;
a.toString()
Key value data
module.exports = /^hello$/ ;
var someData = JSON.parse(resp.body);
I mean the root
[objects are] like biological cells and/or individual computers on a network, only able to communicate with messages.
The pattern
yes inheritance sucks, but that's just one implementation
function Account (value) {
return function (command) {
switch (command) {
case "withdraw" :
return value -= arguments[1 ];
case "deposit" :
return value += arguments[1 ];
case "value" :
return value;
default :
throw new Error("No such message:" + command);
}
}
}
var account = Account(100 )
account("deposit" ,100 );
account("withdraw" ,50 );
account("value" );
So
a little cell, which has changable state
which accepts messages into its 'cell wall'
...and hides good ideas from us
What do objects imply?
EverythingIsAnObject
we need to track state
we model things in hierarchies
we need to hide data
Let's see how often that's true
'Controllers'
What the hell is a controller?
var PhotosController = new Controller();
PhotosController.show = function () {
this .title = this ._photo.title;
this .description = this ._photo.description;
this .render();
};
PhotosController.destroy = function () {};
PhotosController.resize = function () {};
HTTP
The Hypertext Transfer Protocol (HTTP) is an application-level protocol for distributed, collaborative, hypermedia information systems. It is a generic, stateless , protocol
Stateless
OO is about state-ful objects
HTTP is (one of many) stateless protocols
so using objects to respond to a request is...
Solving its own 'problems'
PhotosController.show = function () {
Where is the problem?
var ooHtml = new Template({controller: this , template: tpl})
.render();
var html = markdown(template,data);
What the hell is a model?
Typical code in user model
validation
checking password
sessions
data associated with user
signup flow
triggering emails etc etc...
What is the common theme?
'Vaguely relates to a customer'
Modelling fallacy
it's not a simulation
our job here is: take HTTP request, load data, turn into HTML string
What's wrong with modelling
casuses coupling a heap of unrealated concerns
concepts from auth, domain, presentation...
we're writing code on computers, not a simulation
Where is its state useful?
Stateless
we're using HTTP
we don't keep a user object around between requests
we load all data per request: from DB, session etc
The 'module as object' pattern
Most 'models' are modules
just a namespace
but loads more complex
now has constructor dependencies
Detecting a hidden module
unrelated functions
accessing different fields
made harder to use as they need initialisation
some that don't access fields at all
EverythingIsAnObject, state everywhere: not so great
Change is
Launching rockets
code that does things: DB, AJAX etc
vs code that computes
OO keeps both in same place
Generic means wonderful abstractions
works on any container
map transforms each 'value' inside
contains say "is there a value like X?"
_.map
_.contains
Let's make it specific
custom API for something simple
what has been abstracted?
function User () { }
User.prototype = {
getName: function () {
},
fullName: function () {
}
};
Why do we hide data at all?
Data
simply taking data and presenting it is stateless: HTTP
immutability
Immutability
Mutate === change
mutate is just jargon for change
"oh the DNA has mutated" = it changed
Benefits
if I have the 16th of October, 2007 it stays that way
var someDate = new Date(Date.parse("2007/10/16" ));
passDateSomewhere(someDate);
var timestamp = Date.parse("1995/05/23" );
releaseDateOfSomething.setTime(timestamp);
Wouldn't this be terrible?
if I have the number 0.30000000000000004
var almostZeroPointThree = 0.1 + 0.2 ;
passNumber(almostZeroPointThree);
almostZeroPointThree.setValue(104 )
A date does not have state
a date is a value
values don't change: e.g Point(x,y)
, Query(string: x, options: {})
A rule for values
if you can't meaningfully say "oh which one ?" about an instance
e.g "Oh which 4th of July 1987?"
it really should be a value
Objects are bad at values
Values for data structures
we can do the same with structures
Immutable list
function append (headValue,tailQueue) {
var head = {};
Object.defineProperties(head,{
item: { value: headValue, writable: false },
tail: { value: tailQueue, writable: false }
})
return head;
}
function vals (queue) {
var items = [];
while (queue) { items.push(queue.item); queue = queue.tail; }
return items;
}
var a = append;
var q1 = append(2 ,append(1 ));
var q2 = append(3 ,q1);
var q3 = append(4 ,q1);
console.log(vals(q1),vals(q2),vals(q3));
Use
we get undo immediately
can safely share structure without copy
var todos = undefined ;
function addTodo (todo) {
return append(todo,todos);
}
function undoAdd (todos) {
return todos.tail;
}
todos = append("buy eggs" ,todos);
todos = append("buy cheers" ,todos);
todos = undoAdd(todos);
console.log(todos.item);
Instead of _.clone
try mori
jargon for the idea: "persistent data structures"
So nothing needs to change?
We still need to store/hear about values
is user logged in
tell me when that changes
Events get us quite far
we're just re-rendering in response to new data
pubSub.on("login:change" ,renderLoginState);
Streams
amazing for pure-data (e.g node)
gulp.task('scripts' , function () {
return gulp.src(paths.scripts)
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js' ))
.pipe(gulp.dest('build/js' ));
});
Also in the browser
Bacon.js, RxJS
oh look, map
again
var leftTurns = $(".turnLeft" ).asEventStream("click" )
.map(toEvent("turnLeft" ));
var rightTurns = $(".turnRight" ).asEventStream("click" )
.map(toEvent("turnRight" ));
function toEvent (name) {
return function () {
return {type: name, at: Date.now()};
}
}
var commands = leftTurns.merge(rightTurns);
commands.onValue(applyCommand);
But...
Still need to know current value
Any solution?
Properties
Login
Logout
var logins = $(".login" ).asEventStream("click" ).map(true );
var logouts = $(".logout" ).asEventStream("click" ).map(false );
var loginState = logins.merge(logouts)
.scan(false ,function (_,loginState) { return loginState });
function not (x) { return !x }
loginState.assign($(".login" ),"prop" ,"disabled" );
loginState.map(not).assign($(".logout" ),"prop" ,"disabled" );
Actually objects are great
When they're used in the right places
e.g Promises
Hidden state and large API
many readers
contract: can't change state, only read
painful to do without objects
Other examples
buffers
Property
in streams
shared state of something in time/hardware, not state of stuff we're modelling
I don't think 'objects suck'
I'm just saying they're abused
And they've blinded us to good ideas
Learning derived ideas, not originals with justifications
Design patterns
Inheritance
SOLID
DCI
Dependency injection containers
Far from 'best practice', many are painkillers for OO abuse
How to avoid this happening again?
Keep an eye on your ends, not means
don't be religious
"Oh no, a helper function" - ItsNotAnObject
Check your assumptions
don't take things on authority
try things out for yourself
Today's 'one right way' is tomorrow's mistake
Don't be an X-programmer, be a programmer