Finding Your Abstraction Sweet Spot
Johnny Ray Austin
@recursivefunk
https://recursivefunk.io/
JSConf EU 20190602
What's An Abstraction?
@recursivefunk
KISS?
Simple doesn't scale.
@recursivefunk
@recursivefunk
Elegance
Complexity, expressed, simply.
What Is An Abstraction?
The degree to which complexity is encapsulated.
@recursivefunk
Strong Abstraction
@recursivefunk
Encapsulates a lot of complexity. Not necessarily a good thing.
Weak Abstraction
@recursivefunk
Encapsulates very little complexity. Not necessarily a bad thing.
Let's play a game!
Guess the API!
@recursivefunk
exports = module.exports = createApplication;
/**
* Create an express application.
*
* @return {Function}
* @api public
*/
function createApplication() {
var app = function(req, res, next) {
app.handle(req, res, next);
};
mixin(app, EventEmitter.prototype, false);
mixin(app, proto, false);
// expose the prototype that will get set on requests
app.request = Object.create(req, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
// expose the prototype that will get set on responses
app.response = Object.create(res, {
app: { configurable: true, enumerable: true, writable: true, value: app }
})
app.init();
return app;
}
const express = require('express');
const app = express();
Ready?
var m;
var events;
var existing;
checkListener(listener);
events = target._events;
if (events === undefined) {
events = target._events = Object.create(null);
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener !== undefined) {
target.emit('newListener', type,
listener.listener ? listener.listener : listener);
// Re-assign `events` because a newListener handler could have caused
// the this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
EventEmitter.on()
😅
@recursivefunk
stream.on('data', () => /* ¯\_(ツ)_/¯ */);
let propName;
// Reserved names are extracted
const props = {};
let key = null;
let ref = null;
let self = null;
let source = null;
if (config != null) {
if (hasValidRef(config)) {
ref = config.ref;
}
if (hasValidKey(config)) {
key = '' + config.key;
}
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
React.createElement()
😅
@recursivefunk
const style = { style: { color: 'green' } };
const msg = 'Hello, world';
const welcome = React.createElement('h1', style, msg);
Not Just Code!
@recursivefunk
Infrastructure
@recursivefunk
Physical Servers
@recursivefunk
Virtual Machines
@recursivefunk
Computer emulation.
Containers
@recursivefunk
Computer resource emulation.
PaaS
@recursivefunk
Application-focused.
Serverless
@recursivefunk
Business logic-focused.
What Can Go Wrong?
@recursivefunk
😳
Breaking Changes
@recursivefunk
Not the good kind.
Tech Debt
@recursivefunk
Not the good kind.
User Confusion
@recursivefunk
Not the good kind?
Where's My Sweet Spot?
@recursivefunk
A few considerations.
Flexibility vs Ease-Of-Use
@recursivefunk
Audience
@recursivefunk
Platform
@recursivefunk
- JS Devs want strings and objects
- Golang devs want buffers, interfaces and errors?
- Rust devs want jobs [troll]
- I ❤️ Rust
API Lifespan
@recursivefunk
Wrapping Up
- Focus on elegance, not simplicity
- Simplicity doesn't scale!
- Think in terms of weak or strong abstractions
- Remember the tradeoffs
- Flexibility vs ease-of-use
- Think about the consequences of getting it wrong
- Frequent breaking changes
- Tech debt
- User confusion
- Always think about your audience
@recursivefunk
Thanks!
@recursivefunk
✌🏾
https://slides.com/johnnyray/abstractions
Abstractions
By Johnny Ray Austin
Abstractions
- 1,159