Aaron Francis
Laravels atomic locks
updated
New Database School Channel: youtube.com/@thedatabaseschool
New Database School Podcast Channel: youtube.com/@DatabaseSchoolPodcast.
And today I'm releasing an interview with PlanetScale CEO Sam Lambert! I used to work at PlanetScale so this is a fun full-circle moment. Please go subscribe to youtube.com/@DatabaseSchoolPodcast and watch that episode. That would be a massive help to me! Plus there's a surprise at the end of the episode!
The full interview with Sam: youtube.com/watch?v=IB3mzON8Iyw
The second new channel is the Database School channel. There's nothing there yet, but this will be the home to all my database education videos. You can subscribe here: youtube.com/@thedatabaseschool
Follow Marcel:
Pixeltable: pixeltable.com
Pixeltable GitHub: github.com/pixeltable/pixeltable
LinkedIn: linkedin.com/in/marcelkornacker
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school: databaseschool.com
Chapters:
0:00 - Introduction
0:20 - Meet Marcel Kornacker
1:19 - Early career and grad school in databases
2:12 - Joining Google and building F1
3:42 - How F1 used Spanner at Google
4:01 - Starting Apache Impala at Cloudera
6:02 - Why SQL still matters
7:29 - What keeps Marcel fascinated with databases
9:37 - The “SQL is dead” waves and shift to AI
10:21 - Observing pain points in computer vision pipelines
13:02 - Multimodal data challenges and the idea for Pixetable
16:10 - How Pixeltable handles transformations with computed columns
26:29 - Example: processing video, audio, and transcripts in Pixeltable
33:12 - DAG execution and parallelism explained
37:00 - Transactional guarantees in Pixeltable
39:00 - Iterators and chunking data for search
42:26 - Using embeddings and semantic search
47:05 - Updating data and incremental recomputation
50:06 - Thoughts on RAG and hybrid search
53:14 - Real-world use cases and dataset curation
57:00 - Example: labeling food waste on cruise ships
1:02:00 - Labeling workflows and syncing annotations
1:02:41 - Pixel Table’s roadmap and cloud vision
1:07:10 - How to get involved with Pixeltable
1:09:03 - Closing and where to find Marcel
Follow Lev:
Twitter: twitter.com/levpgdog
PgDog: https://pgdog.dev
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school: databaseschool.com
Chapters:
00:00 - Intro
01:27 - Lev’s self-taught to computer science degree journey
04:50 - Transition to Postgres discussion
05:24 - History of PgCat
07:06 - What PG Cat does and key features
08:59 - Why Lev built PgCat instead of extending PG Bouncer
10:06 - PG Cat’s current status and usage
12:20 - Moving from PgCat to PgDog
13:09 - Applying to YC as a solo founder
16:24 - YC pitch: the market gap for Postgres sharding
18:52 - High-level overview of PgDog
23:32 - Why PgDog is not an extension
25:57 - When to build Postgres extensions vs standalone tools
27:49 - PgDog architecture and query parsing
30:39 - Handling cross-shard queries and current capabilities
33:47 - How PgDog shards an existing large Postgres database
36:37 - Parallel replication streams for faster sharding
39:07 - Alternate resharding approaches
42:52 - Where PgDog draws the orchestration line
44:00 - Vision for PgDog Cloud vs bring-your-own-database
46:47 - Company status: first hire, design partners, and production use
50:45 - How deploys work for customers
52:20 - Importance of building closely with design partners
54:05 - Paid design partnerships and initial deployments
56:23 - Benefit of sitting outside Postgres for compatibility
58:32 - Near-term roadmap and long-term vision
1:01:03 - Where to find Lev online
That’s what I did with modelsThat::useTrait. I wrote it first, then built it.
This is called programming by wishful thinking, and it’s one of my favorite ways to design code.
💻 Watch the full tutorial here → youtube.com/watch?v=Qr1lYJmBTWI
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Programming by wishful thinking
00:16 - The 'ModelsThat:useTrait' idea
00:47 - The hasEmbedding trait pattern
01:31 - Abstract methods for embeddings
02:29 - Applying the trait to different models
03:13 - Trait-provided relationships and scopes
03:54 - Writing the embeddings:create command
04:44 - Starting the helper: modelsThatUseTrait
06:00 - Scanning files and resolving class names
07:02 - Converting paths to PSR-4 class names
08:03 - Using ReflectionClass to inspect traits
09:00 - Filtering models by trait usage
10:12 - Returning class names as a collection
11:00 - Verifying the helper works
11:16 - Next step: creating
In this episode of Database School, I chat with Glauber Costa, CEO of Turso, about their audacious decision to rewrite SQLite from the ground up. We cover the technical motivations, open contribution philosophy, and how deterministic simulation testing is unlocking new levels of reliability.
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide.
Follow Glauber:
Twitter: twitter.com/glcst
Turso: https://tur.so/af
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school: databaseschool.com
Chapters:
00:00 - Intro to guest Glauber Costa
00:58 - Glauber's background and path to databases
02:23 - Moving to Texas and life changes
05:32 - The origin story of Turso
07:55 - Why fork SQLite in the first place?
10:28 - SQLite’s closed contribution model
12:00 - Launching libSQL as an open contribution fork
13:43 - Building Turso Cloud for serverless SQLite
14:57 - Limitations of forking SQLite
17:00 - Deciding to rewrite SQLite from scratch
19:08 - Branding mistakes and naming decisions
22:29 - Differentiating Turso (the database) from Turso Cloud
24:00 - Technical barriers that led to the rewrite
28:00 - Why libSQL plateaued for deeper improvements
30:14 - Big business partner request leads to deeper rethink
31:23 - The rewrite begins
33:36 - Early community traction and GitHub stars
35:00 - Hiring contributors from the community
36:58 - Reigniting the original vision
39:40 - Turso’s core business thesis
42:00 - Fully pivoting the company around the rewrite
45:16 - How GitHub contributors signal business alignment
47:10 - SQLite’s rock-solid rep and test suite challenges
49:00 - The magic of deterministic simulation testing
53:00 - How the simulator injects and replays IO failures
56:00 - The role of property-based testing
58:54 - Offering cash for bugs that break data integrity
1:01:05 - Deterministic testing vs traditional testing
1:03:44 - What it took to release Turso Alpha
1:05:50 - Encouraging contributors with real incentives
1:07:50 - How to get involved and contribute
1:20:00 - Upcoming roadmap: indexes, CDC, schema changes
1:23:40 - Final thoughts and where to find Turso
At PlanetScale, they double the cluster before taking anything down so they never give up fault tolerance.
It's called surging, and it's how they keep your data safe even when hardware fails.
🎥 Watch the full YouTube conversation with Richard Crowley of PlanetScale here: youtube.com/watch?v=3r9PsVwGkg4
🔊 Audio-only version: databaseschool.com
Send down low-quality placeholder strategy video: youtu.be/UNODn5b52u4
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Why prefetching matters for performance
00:49 - The problem with large above-the-fold images
01:12 - Strategy 1: Low-quality image placeholders
01:20 - Strategy 2: Prefetch full images on hover
01:49 - Inspecting media card components
02:17 - Looking into Inertia’s prefetch lifecycle
03:44 - Verifying event details and response data
04:53 - Parsing Inertia props to find prefetch targets
05:29 - Sending additional prefetch info from server
05:56 - Adding a `prefetch` prop with image URL
06:52 - Triggering fetch for extra URLs in app.js
07:42 - Confirming image fetch works in browser devtools
08:11 - Cleaning up with a Laravel-style macro
09:05 - Creating the Inertia prefetch macro
09:57 - Making prefetch smarter with request context
11:08 - Final test: Everything works!
Sign up for my newsletter here: aaronfrancis.com/newsletter
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - What we're building: a block email editor
00:39 - Live preview and Maizzle integration
02:06 - Real dev workflow: AI-assisted coding
03:02 - Starting the Laravel + Vue project
04:00 - Drawing out the UI layout
05:56 - Why this editor uses constrained blocks
06:58 - Planning reusable components (YouTube, promo, etc.)
09:11 - Setting up the Laravel route and view
13:00 - Writing the first AI prompt
14:47 - Feeding layout into Claude and refining structure
18:12 - Why emails are hard and Maizzle helps
20:20 - JSON block structure and the roundtrip render flow
27:11 - Implementing dynamic components
32:01 - Building the Vue editor UI
38:50 - Creating the Maizzle.js project and dev server
43:02 - Replacing JSON debugger with live preview
47:38 - Live rendering emails using Maizzle server
53:14 - Real-time email preview inside the app
1:00:47 - Drag-and-drop reordering with blue drop indicators
1:13:00 - Markdown block rendering
1:20:00 - Tailwind CSS purging fix with inline tokens
1:28:00 - Dynamic email preview fully working
1:35:00 - Copy HTML to clipboard
1:44:00 - Augmenting blocks with backend data
2:00:00 - Adding the YouTube block with video preview
2:10:00 - Final thoughts and how I’ll use this editor every week
▶️ Watch the full tutorial here: youtu.be/NecBFUJmov4
🚨 Unfortunately, this won't work when routes are cached.
Want to take advantage of SQLite's simplicity?
👉 Check out my High Performance SQLite video course, including my take on "It's just a file": highperformancesqlite.com/watch/its-just-a-file
📂 Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
🎥 Watch the full YouTube conversation with DHH here: youtube.com/watch?v=0rlATWBNvMw
🔊 Audio-only version: databaseschool.com
🚀 Want to get up to speed on modern SQLite for web apps? Check out this course: highperformancesqlite.com
📂 Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
Host unlimited podcasts at: https://transistor.fm
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Automating tasks I don’t want to do
01:08 - The Database School podcast setup
01:49 - Tech stack for this automation
03:18 - Starting with a Laravel command
03:45 - Fetching videos from the YouTube API
06:00 - Getting podcast episodes from Transistor
07:16 - Comparing YouTube videos to existing episodes
08:48 - Preparing new videos for publishing
10:45 - Downloading audio
13:35 - Storing audio and avoiding re-downloads
15:03 - Authorizing file uploads to Transistor
16:48 - Uploading the audio file
18:19 - Creating the episode draft on Transistor
20:00 - Confirming the episode was created
21:21 - Wrapping it all in automation
22:18 - Final test and wrap-up
Check out my courses. Use the code YOUTUBE to get 20% off:
masteringpostgres.com
highperformancesqlite.com
screencasting.com
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Running ads for our courses
00:18 - Why I need first-party tracking
00:42 - Using UTM parameters to track sources
01:18 - Strategy: store UTM params on login
01:52 - Using cookies for anonymous visitors
02:35 - Logging in triggers cookie check
03:02 - Writing UTM data to the user record
03:40 - Building it as Laravel middleware
04:01 - Capturing UTM params from requests
04:48 - Fallback to cookies if no params
05:06 - Logic for logged-in vs anonymous users
05:55 - Storing UTM data in a cookie for one year
06:31 - Reading and decoding the cookie
07:22 - Storing UTM data in JSON column
08:03 - Deleting the cookie after writing to user
08:55 - Final logic review of the middleware
09:49 - Benefits of simple, privacy-first tracking
10:05 - Tracking ROI from LinkedIn and Reddit ads
10:16 - Final thoughts and ad help request
▶️ Watch the full tutorial: youtu.be/ynExo2UUFro
Learn how to make videos like me at https://screencasting.com! Use the code YOUTUBE to get 20% off.
shape-outside: developer.mozilla.org/en-US/docs/Web/CSS/shape-outside
Unused CSS clip path tool: unused-css.com/tools/clip-path-generator
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters
00:00 - Redesigning my site with a magazine layout
01:19 - The CSS property you’ve never used: shape-outside
02:20 - Why shape-outside needs floats
02:56 - Laying out the initial images and content
04:51 - The problem with box-shaped margins
05:00 - Creating a polygon visually with a clip-path tool
06:52 - Why percent-based coordinates are important
08:48 - Applying the effect to the second image
09:58 - Hiding the second image on small screens
10:55 - Pulling inspiration from print design
Want to hear the full conversation?
▶️ YouTube: youtube.com/watch?v=C5-741uQPVU
🔊 Audio only: databaseschool.com
Want to hear the full conversation?
▶️ YouTube: youtube.com/watch?v=C5-741uQPVU
🔊 Audio only: databaseschool.com
Want to watch the full conversation?
▶️ YouTube: youtube.com/watch?v=28q9mFh87KY
🔊 Audio only: https://DatabaseSchool.com
Check out Bento at: bentonow.com and be sure to sign up for my weekly newsletter at aaronfrancis.com/newsletter
GitHub repo: github.com/laravel/serializable-closure
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Why you can’t serialize closures in PHP
00:22 - Introducing Laravel Serializable Closure
01:12 - Don’t install it—Laravel already includes it
02:35 - Demonstrating the closure serialization problem
03:01 - What serialization means in PHP
04:47 - How unserialization works
05:20 - The problem with closures and serialization
05:36 - How Laravel makes closures serializable
08:03 - Bringing closures back to life
10:13 - How Laravel uses serializable closures
13:55 - How to sign a closure for security
15:01 - Preventing tampering with signed closures
16:30 - Why Laravel doesn’t always sign closures
17:28 - Wrapping up
Want to hear the full conversation?
▶️ YouTube: youtube.com/watch?v=28q9mFh87KY
🔊 Podcast: https://DatabaseSchool.com”
We dive into the Laravel core and hack together a feature I’ve always wanted, route bindings that gracefully fall through if a model isn’t found. Along the way, I show how to safely extend Laravel with macros and custom validators without breaking future upgrades.
Check out Bento at: bentonow.com and be sure to sign up for my weekly newsletter at aaronfrancis.com/newsletter
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - What we're building: Ignore missing bindings
01:42 - The feature idea: graceful fallthrough for bindings
04:47 - Source diving into Laravel to add a macro
05:52 - Storing custom route info in the action array
06:44 - How Laravel matches routes under the hood
07:57 - Planning the safest extension approach
09:06 - Writing a custom route validator
10:48 - Hooking our validator into Laravel’s matching process
12:03 - Understanding validators in Laravel routing
14:41 - Confirming our validator works
15:55 - How to substitute route bindings safely
17:17 - Mimicking Laravel’s binding behavior
19:03 - Handling model not found exceptions cleanly
21:10 - Verifying fall-through works for unknown routes
22:56 - Final test: podcasts and episodes working together
Want to learn more about Postgres? Check out my course on Postgres: masteringpostgres.com/?ref=yt
Sugu's Vitess videos: youtube.com/watch?v=6yOjF7qhmyY&list=PLA9CMdLbfL5zHg3oapO0HvtPfVx6_iJy6
The big announcement: supabase.com/blog/multigres-vitess-for-postgres
Database school. databaseschool.com
Follow Sugu:
Twitter: twitter.com/ssougou
LinkedIn: linkedin.com/in/sougou
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Intro
1:38 - The birth of Vitess at YouTube
3:19 - The spreadsheet that started it all
6:17 - Intelligent query parsing and connection pooling
9:46 - Preventing outages with query limits
13:42 - Growing Vitess beyond a connection pooler
16:01 - Choosing Go for Vitess
20:00 - The life of a query in Vitess
23:12 - How sharding worked at YouTube
26:03 - Hiding the keyspace ID from applications
33:02 - How Vitess evolved to hide complexity
36:05 - Founding PlanetScale & maintaining Vitess solo
39:22 - Sabbatical, rediscovering empathy, and volunteering
42:08 - The itch to bring Vitess to Postgres
44:50 - Why Multigres focuses on compatibility and usability
49:00 - The Postgres codebase vs. MySQL codebase
52:06 - Joining Supabase & building the Multigres team
54:20 - Starting Multigres from scratch with lessons from Vitess
57:02 - MVP goals for Multigres
1:01:02 - Integration with Supabase & database branching
1:05:21 - Sugu's dream for Multigres
1:09:05 - Small teams, hiring, and open positions
1:11:07 - Community response to Multigres announcement
1:12:31 - Where to find Sugu
Database School: databaseschool.com
PlanetScale: planetscale.com
PlanetScale Metal: planetscale.com/blog/announcing-metal
Follow Richard:
Twitter: twitter.com/rcrowley
Website: rcrowley.org
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Intro: What is PlanetScale Metal?
00:39 - Meet Richard Crowley
01:33 - What is Vitess and how does it work?
03:00 - Where PlanetScale fits into the picture
09:03 - Why EBS is the default and its trade-offs
13:03 - How PlanetScale handles durability without EBS
16:03 - The engineering work behind PlanetScale Metal
22:00 - Deep dive into backups, restores, and availability math
25:03 - How PlanetScale replaces instances safely
27:11 - Performance gains with Metal: Latency and IOPS explained
32:03 - Database workloads that truly benefit from Metal
39:10 - The myth of the infinite cloud
41:08 - How PlanetScale plans for capacity
43:02 - Multi-tenant vs. PlanetScale Managed
44:02 - Who should use Metal and when?
46:05 - Pricing trade-offs and when Metal becomes cheaper
48:27 - Scaling vertically vs. sharding
49:57 - What's next for PlanetScale Metal?
53:32 - Where to learn more
Check out Bento at: bentonow.com and be sure to sign up for my weekly newsletter at aaronfrancis.com/newsletter
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Snappy site demo
00:58 - Overview of the 7 step checklist
01:40 - 1. Server-side rendering setup
06:32 - 2. Asset prefetching
08:24 - 3. Link prefetching
09:59 - 4. Partial reloads
15:13 - 5. Walking the DOM
19:01 - 6. Placeholder images
22:41 - 7. Laravel optimize
23:56 - Final thoughts
Want to learn more about SQLite? Check out my SQLite course: highperformancesqlite.com/?ref=yt
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
Livestore website: https://livestore.dev
LiveStore repo: github.com/livestorejs
LiveStore Discord: discord.gg/RbMcjUAPd7
Follow Johannes:
Twitter: x.com/schickling
LinkedIn: linkedin.com/in/schickling
Website: https://www.schickling.dev
Localfirst.fm Podcast: https://www.localfirst.fm
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: databaseschool.com
Chapters
00:00 - Intro to Johannes
01:00 - From Prisma to LiveStore
03:00 - Discovering local-first through Riffle
05:00 - What is local-first and who is it for?
07:00 - Why local-first is gaining popularity
10:00 - The inspiration from apps like Linear
13:00 - Gaps in local-first tooling in 2020
16:00 - Social apps vs. user-centric apps
18:00 - Distributed systems and why they’re hard
21:00 - The value of embracing local-first
24:00 - What LiveStore is and what it's not
26:00 - Event sourcing as the core of LiveStore
30:00 - Benefits of event sourcing for apps
33:00 - Schema changes and time travel via events
37:00 - Materializers and how they work
43:00 - Syncing data across clients and devices
48:00 - Sync servers and cross-tab communication
54:00 - Architecture choices and dev tooling
59:00 - State of the project and future vision
1:06:00 - How to get involved
Want to learn more about SQLite? Check out my SQLite course: highperformancesqlite.com/?ref=yt
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
Follow Josh:
Twitter: twitter.com/ajoshhoward
LinkedIn: linkedin.com/in/joshthoward
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: https://databaseschool.transistor.fm
Chapters
00:00 - Intro
00:37 - What is a Durable Object?
01:43 - Cloudflare’s serverless model and V8 isolates
03:58 - Why stateful serverless matters
05:14 - Durable Objects vs Workers
06:22 - How routing to Durable Objects works
08:01 - What makes them "durable"?
08:51 - Tradeoffs of colocating compute and state
10:58 - Stateless Durable Objects
12:49 - Waking up from sleep and restoring state
16:15 - Durable Object storage: KV and SQLite APIs
18:49 - Relationship between D1, Workers KV, and DOs
20:34 - Performance of local storage writes
21:50 - Storage replication and output gating
24:15 - Lifecycle of a request through a Durable Object
26:46 - Replication strategy and long-term durability
31:25 - Placement logic and sharding strategy
36:35 - Use cases: agents, multiplayer games, chat apps
40:33 - Scaling Durable Objects
41:14 - Globally unique ID generation
43:22 - Named Durable Objects and coordination
46:07 - D1 vs Workers KV vs Durable Objects
47:50 - Outerbase acquisition and DX improvements
49:49 - Querying durable object storage
51:20 - Developer Week highlights and new features
52:44 - Read replicas and sticky sessions
53:49 - Containers and the future of routing
56:47 - Deployment regions and infrastructure expansion
57:43 - Hiring and how to connect with Josh
Links:
Chargebee Cashier Repository: github.com/chargebee/cashier-chargebee
Chargebee: chargebee.com
Feedback email: dx@chargebee.com
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Laravel's starter kit strategy
00:50 - Zero-code walkthrough of the starter app
01:52 - Testing the subscription and checkout flow
03:01 - Chargebee overview and new cashier driver
03:33 - Installing the starter kit via CLI
05:52 - Syncing subscription plans
06:43 - How the cashier driver works
07:10 - Why use Chargebee for billing?
08:01 - Chargebee’s built-in accounting features
08:46 - Exploring the cashier-chargebee repo
09:28 - Built-in billing portal support
10:00 - Handling customer balances and credit
10:33 - Flexible subscription trial handling
11:14 - How to give Chargebee product feedback
11:50 - Wrap-up
Links:
Mastering Postgres Course: masteringpostgres.com/?ref=yt
Let's make postgres multi-threaded: postgresql.org/message-id/31cc6df9-53fe-3cd9-af5b-ac0d801163f4%40iki.fi
Hacker News discussion: news.ycombinator.com/item?id=36284487
Follow Heikki:
LinkedIn: linkedin.com/in/heikki-linnakangas-6b58bb203
Website: https://neon.tech
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: https://databaseschool.transistor.fm
00:00 - Introduction and Heikki's background
01:19 - How Heikki got into Postgres
03:17 - First major patch: two-phase commit
04:00 - Governance and decision-making in Postgres
07:00 - Committer consensus and decentralization
09:25 - Attracting new contributors
11:25 - Founding Neon with Nikita Shamgunov
13:01 - Why separation of compute and storage matters
15:00 - Write-ahead log and architectural insights
17:03 - Early days of building Neon
20:00 - Building the control plane and user-facing systems
21:28 - What "serverless Postgres" really means
23:39 - Reducing cold start time from 5s to 700ms
25:05 - Storage architecture and page servers
27:31 - Who uses sleepable databases
28:44 - Multi-tenancy and schema management
31:01 - Role in low-code/AI app generation
33:04 - Branching, time travel, and read replicas
36:56 - Real-time point-in-time query recovery
38:47 - Large customers and scaling in Neon
41:04 - Heikki’s favorite Neon feature: time travel
41:49 - Making Postgres multi-threaded
45:29 - Why it matters for connection scaling
50:50 - The next five years for Postgres and Neon
52:57 - Final thoughts and where to find Heikki
Atomic Locks Video: youtu.be/jGb5zIgwL4c
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Our courses:
High Performance SQLite: highperformancesqlite.com
Mastering Postgres: masteringpostgres.com
High Leverage Rails: highleveragerails.com
Screencasting: screencasting.com
Chapters:
00:00 - What is an atomic lock?
02:00 - Two real-world locking scenarios
03:10 - Desired API design using reservation scopes
04:44 - Basic cache lock implementation
06:54 - Improving lock key visibility in database
08:34 - Moving toward database query integration
11:05 - Setting up polymorphic relationships
12:13 - Reusing Laravel’s cache_locks table
15:00 - Generating reservation keys programmatically
19:00 - Using generated columns to parse reservation keys
22:00 - Verifying morph relationship and query behavior
25:00 - Handling timing and collision issues
29:00 - Making key parsing more robust
32:00 - Filtering out expired or invalid locks
34:00 - Implementing unreserved and reserveFor scopes
38:00 - Building a reserve() method on the model
40:00 - Live testing reservation behavior
41:30 - Wrapping up: robust, multi-database reservation system
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Our education products:
High Performance SQLite: highperformancesqlite.com
Mastering Postgres: masteringpostgres.com
High Leverage Rails: highleveragerails.com
Screencasting: screencasting.com
Chapters:
00:00 - Using AI to scale a traditional business
00:36 - Overview of our education products
01:11 - Where AI fits into our workflow
02:00 - Let computers do what computers are good at
03:13 - Principles for working with AI
03:57 - How we transcode and deliver video
04:59 - Using AI to write deterministic scripts
06:04 - Leveraging domain knowledge with AI
06:32 - Breaking down the publish workflow
07:00 - Automating transcription and captions
08:59 - Creating markdown transcripts from captions
10:08 - Building a modular, fault-tolerant system
11:59 - Syncing Cloudflare R2 with our database
13:37 - Handling transcription with 11Labs
16:01 - Generating VTT caption files
18:46 - Creating markdown transcripts with OpenAI
21:08 - Generating descriptions and snippets automatically
23:20 - Why small discrete steps matter
24:50 - Key principles for scaling with AI and programming
26:34 - Final thoughts on scaling without scaling headcount
In this episode, Carl Sverre and I discuss why syncing everything is a bad idea and how his new project, Graft, makes edge-native, partially replicated databases possible. We dig into SQLite, object storage, transactional guarantees, and why Graft might be the foundation for serverless database replicas.
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
SQLSync: https://sqlsync.dev
Stop syncing everything blog post: https://sqlsync.dev/posts/stop-syncing-everything
Graft: github.com/orbitinghail/graft
Follow Carl:
Twitter: twitter.com/carlsverre
LinkedIn: linkedin.com/in/carlsverre
Website: carlsverre.com
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: databaseschool.com
Chapters:
00:00 - Intro and Carl’s controversial blog title
01:00 - Why “stop syncing everything” doesn't mean stop syncing
02:30 - The problem with full database syncs
03:20 - Quick recap of SQL Sync and multiplayer SQLite
04:45 - How SQL Sync works using physical replication
06:00 - The limitations that led to building Graft
09:00 - What is Graft? A high-level overview
16:30 - Syncing architecture: how Graft scales
18:00 - Graft's stateless design and Fly.io integration
20:00 - S3 compatibility and using Tigris as backend
22:00 - Latency tuning and express zone support
24:00 - Can Graft run locally or with Minio?
27:00 - Page store vs meta store in Graft
36:00 - Index-aware prefetching in SQLite
38:00 - Prefetching intelligence: Graft vs driver
40:00 - The benefits of Graft's architectural simplicity
48:00 - Three use cases: apps, web apps, and replicas
50:00 - Sync timing and perceived latency
59:00 - Replaying transactions vs logical conflict resolution
1:03:00 - What’s next for Graft and how to get involved
1:05:00 - Hacker News reception and blog post feedback
1:06:30 - Closing thoughts and where to find Carl
Our platform powers:
- highperformancesqlite.com
- masteringpostgres.com
- highleveragerails.com
- screencasting.com
and even more coming soon!
Check out the whiteboard app I was using here: tldraw.com.
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Setting the stage: course vs e-commerce
01:40 - Why we’re moving to Stripe
02:12 - Requirements for access types
03:30 - Course tiers, bundles, and upgrades
06:50 - Access control and enrollments
07:57 - Digital downloads and bundling
10:00 - Separation of billing and access
11:45 - Modeling digital and physical access
13:20 - How Stripe products fit in
14:50 - Why we can’t link directly to assets
19:30 - Entitlements: the key concept
21:00 - Syncing Stripe data locally
22:40 - Attaching entitlements to products
24:10 - Why we use JSON for flexibility
27:00 - How entitlements generate access
28:40 - Checkout and checkout lines
30:40 - Linking Stripe prices to access
32:00 - Fulfillment and processing logic
34:30 - Admin UI for defining entitlements
39:00 - How checkouts are built and stored
43:50 - Stripe integration flow
46:20 - Access and fulfillment separation
47:50 - Checkout-instant explained
49:00 - Final database walkthrough
50:05 - End-to-end flow summary
52:00 - Avoiding webhooks with polling
54:00 - Stripe redirect and payment verification
56:00 - Offers: upsells and cross-sells
1:00:00 - Creating and configuring offers
1:03:40 - Final thoughts on modeling
In this video I built a very basic version of Cloudflare's image proxy that we use on our various sites, like highperformancesqlite.com. It's a single controller in our Laravel application!
Cloudflare Images: cloudflare.com/developer-platform/products/cloudflare-images
Intervention: image.intervention.io/v3
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - What we’re building: Cloudflare-style image transforms in Laravel
00:59 - Defining the route with dynamic options and path
02:41 - Writing regex constraints for the route
03:56 - Creating the image controller
05:01 - Verifying the image exists
06:40 - Installing and using Intervention Image
07:15 - Parsing the options from the URL
08:45 - Transforming options into a usable array
09:13 - Scaling and manipulating the image
10:00 - Supporting format and quality options
11:58 - Encoding the image with format and quality
13:17 - Returning the image with proper headers
14:49 - Adding cache-control headers for CDN caching
15:59 - Preventing cookies from disabling CDN caching
18:59 - Creating middleware to strip cookies
20:56 - Implementing simple rate limiting
22:32 - Gracefully handling rate limit errors
24:07 - Wrapping up: why this approach works for us
Want to learn more Postgres? Check out my Postgres course: https://masteringpostgres.com.
Follow Søren:
Twitter: twitter.com/sorenbs
GitHub: github.com/prisma/prisma
Prisma Postgres: prisma.io/postgres
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: https://databaseschool.transistor.fm
Chapters:
00:00 - Introduction
01:15 - The Origins of Prisma: From GraphQL to ORM
02:55 - Why Firebase & Parse Inspired Prisma
04:04 - The Pivot: From GraphQL to Prisma ORM
06:00 - Why They Abandoned Backend-as-a-Service
08:07 - The Open Source Business Model Debate
10:15 - The Challenges of Monetizing an ORM
12:42 - Building Prisma Accelerate & Pulse
14:55 - How Prisma Accelerate Optimizes Database Access
17:00 - Real-Time Database Updates with Prisma Pulse
20:03 - How Prisma Pulse Handles Change Data Capture (CDC)
23:15 - Users Wanted a Hosted Database (Even When Prisma Didn’t)
25:40 - Why Prisma Finally Launched Prisma Postgres
27:32 - Unikernels, Firecracker MicroVMs & Running Millions of Databases
31:10 - Bare Metal Servers vs. AWS: The Controversial Choice
34:40 - How Prisma Routes Queries for Low Latency
38:02 - Scaling, Cost Efficiency & Performance Benefits
42:10 - The Prisma Postgres Roadmap & Future Features
45:30 - Why Prisma is Competing with AWS & The Big Cloud Players
48:05 - Final Thoughts & Where to Learn More
Here is the latest code, as shown in the video: github.com/soloterm/solo/pull/56.
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Demo
00:39 - What we're after
02:05 - Defining the actions
04:03 - Crash course on how it works
08:53 - Laravel Dusk
Support the development of Fusion: aaronfrancis.com/backstage
Fusion GitHub repository: github.com/fusion-php/fusion (Note: this is a developer preview -- still has some rough edges, but we must ship! Hope you like it!)
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Mind-Blowing PHP in Javascript! 🤯
00:48 - Writing PHP Inside a Javascript Component?!
01:16 - What is Fusion? A Laravel + JavaScript Revolution
02:00 - No Routes, No Controllers—Just Magic ✨
02:48 - File-Based Routing & Route Model Binding
04:08 - Reactive Props and State Syncing
05:00 - Full Laravel Database Queries in Vue
06:26 - Automatic Type Safety (Coming Soon!)
07:14 - Seamless Error Handling for PHP & Vue
08:08 - Real-Time Search with Two-Way Data Flow
10:06 - Fusion's Built-In Loading & Success States
12:00 - Exposing PHP Functions Directly to Vue
14:00 - Alternative Syntax for PHP Purists
17:00 - The Future of Fusion: React, Svelte & More
19:32 - How to Get Involved & Support Fusion
Visit the Solo GitHub repository: github.com/soloterm/solo
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Intro: A Laravel CLI Tool
00:41 - Navigating the Solo Interface
01:27 - What is Solo? A Laravel Task Runner
02:48 - Viewing and Managing Laravel Logs
04:00 - Running NPM and Laravel Commands
04:56 - Interactive Mode: Creating Models
06:26 - Lazy Commands: Starting and Stopping Tasks
07:57 - Customizing Key Bindings and Vim Mode
08:42 - Configuring Solo for Your Workflow
09:52 - Quick Navigation with the Popup Menu
11:09 - Graceful Shutdown and Process Cleanup
11:30 - Try Solo for Laravel
In this episode, I sit down with Mike Buckbee to dive into the nitty-gritty of web application firewalls and his journey from using Redis to SQLite in Wafris. We talk about database architecture, operational challenges, and the fascinating ways SQLite improves performance and usability in cybersecurity tools.
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
Follow Mike:
Twitter: twitter.com/mbuckbee
LinkedIn: linkedin.com/in/michaelbuckbee
Wafris website: wafris.org
Rearchitecting Redis to SQLite article: wafris.org/blog/rearchitecting-for-sqlite
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: databaseschool.com
Chapters:
00:00 - Introduction and Guest Overview
01:06 - What is Wafris?
02:43 - Naming and Origins of Wafris
04:00 - Mike's Cybersecurity Background
07:17 - Challenges with Web Application Firewalls
10:01 - Wafris Architecture Overview
16:15 - Why Switch to SQLite?
18:01 - Handling IP Address Ranges
24:00 - Wild Redis Data Structures Explained
28:51 - Transitioning to SQLite
32:02 - Operational Advantages of SQLite
37:04 - How Wafris Leverages Threat Lists
40:13 - Performance Gains with SQLite
46:51 - Splitting Reads and Writes in the New Architecture
52:29 - Closing Thoughts and Where to Learn More
Want to learn more SQLite? Check out my SQLite course: highperformancesqlite.com
Get your free SQLite reference guide: highperformancesqlite.com/products/sqlite-reference-guide
Mentioned Links:
Turso: https://tur.so/a
libSQL: https://turso.tech/libsql
Nuno Maduro's OpenAI PHP client: github.com/openai-php/client
My video about using SQLite for my site: youtu.be/QiocnnlcXIU
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Introduction and Website Overview
00:26 - SQLite Database for the Website
00:39 - LibSQL Vector Support Introduction
01:21 - Creating Article Embeddings with OpenAI API
02:32 - Cleaning Article Contents
03:06 - Generating Embeddings from Article Data
04:55 - Storing Embeddings in libSQL
06:00 - Setting up Database for Embeddings
07:00 - Indexing and Storing Embeddings in SQLite
08:45 - Writing SQL Query for Related Articles
10:15 - Querying Article Embeddings for Nearest Neighbors
12:00 - Testing and Fetching Related Articles
14:10 - Improved Related Articles Display
16:00 - Conclusion and Future Plans
In this interview, I talk with Jesse Hanley, founder of Bento, about running a lean email service from Japan. We chat about the challenges of scaling infrastructure, managing databases, and maintaining a calm business while serving a global customer base.
Links Mentioned:
Bento: bentonow.com
Database school on YouTube: youtube.com/playlist?list=PLI72dgeNJtzqElnNB6sQoAn2R-F3Vqm15
Database school audio only: https://databaseschool.transistor.fm
Follow Jesse:
Twitter: twitter.com/jessethanley
Bento on Twitter: twitter.com/Bento
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Introduction to Jesse Hanley
01:02 - Running Bento from Japan
01:48 - The Lean Team Structure at Bento
03:00 - Managing Support via Discord
05:01 - Benefits of Using Discord for Customer Support
06:45 - The Role of Community in Customer Feedback
09:01 - How Bento Gained Traction
13:00 - Bootstrapping Bento and Profitable Growth
16:00 - Running Your Own Mail Servers
19:03 - The Economics and Redundancy of Email Delivery
21:00 - Bento's Heroku Setup and Scaling Challenges
26:00 - Handling and Querying Massive Data in Bento
29:52 - Leveraging Elasticsearch for Data Queries
35:40 - Moving Toward Multi-Database Solutions
37:45 - Exploring Crunchy Data and Citus for Database Scaling
42:00 - Optimizing Bento for Performance and Scalability
54:02 - Jesse’s Advice on Building a Calm and Profitable Business
57:00 - How Bento Uses WebSockets and Background Jobs
1:00:00 - Optimizing Bento with Action Cable
1:02:25 - Avoiding N+1 Queries with WebSockets
1:04:50 - Scaling Redis and Postgres at Bento
1:09:00 - Jesse’s Approach to Managing Growth and Multiple Services
1:11:00 - Final Thoughts on Scaling and Optimizing Databases
1:13:10 - Advice for Aspiring Builders: Stay Patient and True to Your Vision
1:16:00 - Bento’s Unique Approach to Email Marketing and Transactional Emails
1:19:50 - Closing Thoughts and Where to Find Jesse Hanley Online
Production ready Postgres for teams that ship fast: xata.io
In this interview, I talk with Monica Sarbu and Tudor Golubenco from Xata about their journey from Elastic to founding Xata. We deep dive on building a Postgres hosting platform, handling schema changes, and how they've made their free tier economical.
Links Mentioned:
Xata.io: xata.io
The economics of a Postgres free tier: xata.io/blog/postgres-free-tier
Follow Monica & Tudor:
Monica on Twitter: twitter.com/monicasarbu
Monica on LinkedIn: linkedin.com/in/monicasarbu
Tudor on Twitter: twitter.com/tudor_g
Tudor on LinkedIn: linkedin.com/in/tudorgolubenco
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Introduction
00:26 - What is Xata? Overview and Mission
01:32 - Open Source Projects: PG Roll and PG Stream
02:33 - Synchronizing Data: Postgres to Elastic Search
03:12 - Monica and Tudor's Background & Journey to Elastic
04:00 - Founding of Packetbeat: The Start of Open Source Monitoring
06:08 - Transition from Elastic to Starting Xata
07:00 - Launching a Nonprofit and Insights on Database Challenges
08:29 - The Idea Behind Xata: Simplifying Application Development
10:00 - Tudor Joins Xata: The Decision to Start Again
10:47 - The Technical Vision for Xata's Platform
12:06 - Founding Xata During the Pandemic
13:11 - Funding Journey: From Seed to Series A
15:07 - Building a Platform, Not Just a Hosted Database
17:20 - Introducing Postgres to Xata's Stack
20:19 - Navigating Postgres as a DBA
22:44 - Open Source Strategy & Community Building
27:48 - PG Stream Use Cases & Postgres Replication
32:08 - PG Roll for Zero Downtime Schema Changes
36:05 - Implementing Safe and Fast Schema Changes
39:49 - Blob Storage and Cloudflare Integration
45:11 - Xata's Unique Features: Serving Builders and Larger Teams
49:20 - Free Tier Economics and Why It Matters
56:04 - Working as a Husband-Wife Team
Production ready Postgres for teams that ship fast: xata.io
In this video, I'll show you how to keep your sanity by using best practices (aka the least frustrating way) to handle timezones in PostgreSQL!
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Introduction to Time Zones in PostgreSQL
00:51 - Why Time Zones Are Frustrating
01:42 - Best Practices for Handling Time Zones
02:24 - Using UTC for Consistency
03:04 - Setting the Time Zone for Your Database and Session
04:07 - Impact of Session Time Zone on Timestamps
05:00 - How PostgreSQL Stores and Displays Timestamps
06:03 - Converting UTC to Local Time Zones
06:40 - The Importance of Using Named Time Zones
07:06 - Using at time zone for Conversion
07:59 - Potential Pitfalls of Using Abbreviations (CST/CDT)
08:58 - The Problem with Hour Offsets
10:30 - Understanding Posix Style Time Zone Specifications
11:55 - Avoiding Mistakes with Time Zone Offsets
12:46 - Listing and Selecting Time Zone Names in PostgreSQL
13:39 - Final Recommendations for Handling Time Zones
In this interview, I dive deep with Craig Kerstiens from Crunchy Data into the world of Postgres, covering its rise to prominence, scaling at Heroku, and the power of Postgres extensions. Craig also shares insights on database sharding, the future of Postgres, and why developers love working with it.
Follow Craig:
Twitter: twitter.com/craigkerstiens
Crunchy Data Blog: crunchydata.com/blog
Follow Aaron:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.
Chapters:
00:00 - Introduction: Welcome to Database School
00:20 - Guest Introduction: Craig Kerstiens and Crunchy Data
01:40 - Craig's Journey from Heroku to Crunchy Data
02:55 - Scaling Postgres at Heroku
04:50 - Mastering Postgres Course Announcement
05:30 - The Importance of Postgres at Heroku
07:50 - The Value of Live SQL with Data Clips
09:25 - Data Clips for Business Intelligence and Real-Time Analytics
11:05 - Heroku’s Unique Company Culture and How Data Clips Came to Be
12:30 - Postgres Extensions and Marketplace
14:00 - Citus: Scaling Postgres for Multi-Tenant Applications
15:40 - The Challenges of Sharding in Databases
18:00 - Managing Large Databases and Sharding Keys with Citus
24:00 - The Evolution of Postgres and Its Growing Popularity
31:00 - Postgres for Developers and the Importance of Extensions
35:00 - Extensions as Proving Grounds for Core Postgres Features
37:50 - Building an Extension Marketplace for Postgres
41:00 - Postgres as a Data Platform and Developer Flexibility
46:00 - Why Developers Love Postgres: Stability, Extensions, and Ownership
51:00 - DuckDB: A Fascinating New Database Approach
53:30 - Crunchy Data: What They Offer and Why It Matters
58:30 - Expanding Postgres with DuckDB for Data Warehousing
01:00:00 - Wrapping Up: Where to Find Craig and Crunchy Data
Follow me:
Twitter: twitter.com/aarondfrancis
LinkedIn: linkedin.com/in/aarondfrancis
Website: aaronfrancis.com - find articles, podcasts, courses, and more.


