Abstractions, complexities and off-ramps

Your Code

The browser

The user

npm install lodash
const lodash = require('lodash')

that looks nice!

DX

UX

DX

UX

npm install lodash
const lodash = require('lodash')

THIS IS SO EASY!

npm run build
npm install lodash
const lodash = require('lodash')

No visible cost

npm run build

But most of us aren’t making Figma. Most of us are still making documents [...].

Jason Godesky

https://scribe.rip/@jason.godesky/when-javascript-fails-52eef47e90db

The browser (and the user)

The browser (and the user)

Your framework

Your frameworks' dependencies

The browser (and the user)

A library from npm

The browser (and the user)

Your code.

The browser (and the user)

Dependencies, complexities and abstractions

An architectural lasagne!

Third party dependencies

Complexity

Third party dependencies

Complexity

Third party dependencies

Complexity

UX

No one purposefully set out to cause this

I am not saying that we should never use JavaScript.

 the thing that’s really bugged me for the past decade is the increasing complexity of “modern” frontend development when it isn’t driven by user needs

Jeremy Keith

https://pixelpioneers.co/blog/2023/speaker-spotlight-jeremy-keith

2

1.

2.

The impact of dependencies

Complexity & abstractions

Complexity & abstractions

https://www.theregister.com/2016/03/23/npm_left_pad_chaos/

becomes unmaintained on GitHub

has security vulnerability that no one is fixing

has bad perf case that your

website exposes

{
{

Every dependency you add to a project is one more potential single point of failure.

Jeremy Keith

https://adactio.com/journal/19021

Your code

Mission critical abstractions and dependencies

use the platform

jackfranklin.co.uk/blog/working-with-react-and-the-web-platform/

custom elements

HTML Form Validation

FormData API

Constraint Validation API

98%
96%
97%

data from caniuse.com on 28/04/2023

npm install event-emitter

Well I'd just use EventTarget

class BlogPostComments extends EventTarget {
  onUpdate() {
    this.dispatchEvent(new Event('updatedcomments'));
  }
}

const comments = new BlogPostComments();

comments.addEventListener('updatedcomments', () => {
  // we got some new comments!
});
class BlogPostComments extends EventTarget {
  onUpdate() {
    this.dispatchEvent(new Event('updatedcomments'));
  }
}

const comments = new BlogPostComments();

comments.addEventListener('updatedcomments', () => {
  // we got some new comments!
});
97%

https://caniuse.com/mdn-api_eventtarget

Can we shift our default starting point?

You can’t JavaScript your way out of an excess-JavaScript problem. These large JavaScript bundles are costly to site performance.

Zach Leat

https://www.zachleat.com/web/single-page-applications/

I have a problem to solve

what dependency will solve this for me?

npm install lodash
const lodash = require('lodash')

This is so easy!

npm run build

The problem with conveniences is that they come at a cost. How easy is it to add this one little convenience that will surely make our lives better, never think about it again and move on.

Pascal Schilp

https://dev.to/thepassle/the-cost-of-convenience-kco

I have a problem to solve

Does the browser provide a solution natively?

Does the browser provide a solution natively?

No: I need to implement or add a dependency

Yes!

Reduce the amount of

JavaScript we ship

moving away from

JavaScript by default

 

https://twitter.com/ksylor/status/1456341818698838016

The general idea of an “Islands” architecture is deceptively simple: render HTML pages on the server, and inject placeholders or slots around highly dynamic region

Jason Miller

https://jasonformat.com/islands-architecture/

Jake Archibald

https://twitter.com/jaffathecake/status/1448585986422808576

This means I can enhance little parts of the page without going all-in on a framework.

The Islands Architecture feels like the best of both worlds

Let's talk about abstractions and dependencies

The 4 easy methods YOU can use to MANAGE your JavaScript!

Maintaining control

Dependency awareness

Lean on browser primitives

Have an exit strategy

Maintaining control

Your code is in control

Your code is in control

The framework is in control

Your code is in control

The framework is in control

this.user = 'jack';
this.render();

Your code is in control

The framework is in control

this.user = 'jack';
this.render();
const [
  user,
  setUser
] = useState('');

setState('jack');

Your code is in control

Inversion of Control

this.user = 'jack';
this.render();
const [
  user,
  setUser
] = useState('');

setState('jack');

Libraries and a frameworks can be distinguished by looking at the Inversion of Control

Surma

https://surma.dev/things/cost-of-convenience/index.html

Use framework primitive to update data

Framework re-renders for you.

Render component

Use framework primitive to update data

Framework re-renders for you.

Render component

Update legacy jQuery component

 However, as frameworks often put themselves at the core of any architecture, it can be hard to opt out

Surma

https://surma.dev/things/cost-of-convenience/index.html

A library gives you an escape hatch by default

Because you never give up control

Maintaining Control

Prefer libraries, or ensure your framework's escape hatches are going to work for you.

Dependency Awarness

1. more code in your website's bundle
3. another thing to upgrade (or not) on a semi-regular basis
2. another potential point of failure
4. more complexity and code to understand

Dependencies must justify these costs

And we must look to mitigate the risks

Jack's ULTIMATE guide to dependency consideration

Was £299, now £49 for TODAY ONLY!!!!

WHAT

is this dependency providing?

would it be like to build it ourselves?

do we do if it becomes unmaintained?

is its impact on the bundle size?

if we have to replace it?

LitElement vs lit-html

CodeMirror vs in-house

Awareness of bundle size

Me! (is it weird to quote your blog posts in talks? Maybe. Egotistical? Definitely...)

https://www.jackfranklin.co.uk/blog/check-in-your-node-dependencies/

No more npm install locally or on CI bots

100% reproducible builds by default

No blocked builds if npm is down

Dependencies of dependencies are no longer invisible

You are forced to see the code you are committing.

Dependency update code changes are unmissable

no more energy used from npm installs

30 engineers with 100s of builds per day...

node_modules/*
!node_modules/new-dep

It fucks me up, we devops / sre do our best to advocate for good tools, do our best to educate people, and there's a dude coming from google saying "oh yeah no more npm installs" and i want to fucking cry

warning: approach may make you unpopular

Dependency Awarness

Weigh up the costs vs benefits of each dependency and make those costs visible.

Lean on browser primitives

<web-components>

<web-components> and the island architecture

The browser (and the user)

Large framework

The browser (and the user)

web components

Historically, it has been difficult to use Shadow DOM in combination with Server-Side Rendering because there was no built-in way to express Shadow Roots in the server-generated HTML

Jason Miller, Mason Freed

https://developer.chrome.com/en/articles/declarative-shadow-dom/

Islands Architecture
Web Components
Declarative Shadow DOM

Single Page Application advocates argue [...]. While we can debate those points (recognizing also that they will fade into irrelevance as the web platform progresses)

Zach Leat

https://www.zachleat.com/web/single-page-applications/

Lean on browser primitives

The browser keeps getting more powerful and abstractions that build on top of these primitives are here to stay

Have an exit strategy

Be British

a pessimist

KnockoutJS
Backbone

KnockoutJS
Backbone
Angular 1 & Object.observe()

KnockoutJS
Backbone
Angular 1 & Object.observe()
React
Vue

KnockoutJS
Backbone
Angular 1 & Object.observe()
React
Vue
React hooks
Svelte

KnockoutJS
Backbone
Angular 1 & Object.observe()
React
Vue
React hooks
Svelte
web-components, Lit, Stencil, islands

KnockoutJS
Backbone
Angular 1 & Object.observe()
React
Vue
React hooks
Svelte
web-components, Lit, Stencil, islands
what is next?
??

Jack of the present

* in this slide Jack of the future is played by Jack's dad

What can I do today?

Jack of the future*

To make the future maintainers happy?

You cannot future proof everything

Maintaining control

Dependency awareness

Lean on browser primitives

Have an exit strategy

the path to a less complex web

Reduce complexity

by leaning on the browser

Reduce the amount of code

by leaning on the browser

Reduce energy usage

by leaning on the browser

Reduce user frustrations

by leaning on the browser

Increase accessibility

by leaning on the browser

A website that uses standard HTML links for navigation is easier for assistive technologies and web crawlers to use.

[...]

It makes the default outcome the accessible one.

Jason Miller

https://jasonformat.com/islands-architecture/

The browser (and the user)

Framework internals

Core framework

Lean on the browser does not mean the end for frameworks

The browser (and the user)

Framework internals

Core framework

Reduce the reliance on abstractions and if you need them, prefer libraries over frameworks

Have an off-ramp and stay flexible to change.

you find yourself having outgrown the framework [...], and you want to switch. This can be really hard, because frameworks shape your code, and each framework is different, so there is no easy migration path

Surma

https://surma.dev/things/cost-of-convenience/index.html

Critically consider each dependency and mitigate the risks.

Be aware of what

you are shipping

The browser (and the user)

Your code.

Shrink this

The browser (and the user)

to this

DX

UX

DX

UX

DX

UX

Thank you.

jackf.io/talks/abstractions

jackf.io/toot

jackf.io/tweet

jackf.io/blog

 

abstractions-and-complexities

By Jack Franklin

abstractions-and-complexities

  • 209