Takeaway 479 nodes
Borrow From Non-Rails View ApproachesDon't be afraid to use non-Rails view patterns (Hanami View, ViewComponent, Phlex) in Rails apps.
Default to row-level partitioning
Row-level partitioning handles most multi-tenancy cases; battle-tested at Shopify and Salesforce.
Give Each Kind of Work Its Own Shelf
Route each kind of code (business rules, mutations, external calls, app logic) to a dedicated layer.
Identify Data Calculations Actions In Your System
The core FP practice: classify each part of your code as data, calculation, or action.
Layer security in depth on your Kamal VM
Stack cloud firewall, UFW, fail2ban, Tailscale and a non-root user even if they overlap.
Migrate off Webpacker to cssbundling/jsbundling
Replacing Webpacker with css/js bundling dramatically reduced Bearer's build time.
Start with Pundit, add granity for FGA, adopt authorization-as-a-service at distributed scale
Progressive path for Rails authorization complexity.
Adopt event sourcing gradually
Start from CRUD and introduce events/aggregates where they add value.
Adopt TypeScript or Flow for maintainability
Typed JavaScript catches bugs early and eases refactoring.
Declare gem runtime dependencies in the gemspec
Don't rely on a README — add required gems via spec.add_dependency.
Don't be afraid of event sourcing
Event sourcing is 'just a persistence pattern' — easier than DDD, CQRS or EDA.
Don't reinvent multi-tenancy — use existing gems
Peer-reviewed gems like acts_as_tenant already implement row-level multi-tenancy correctly.
Encapsulation Via Function-Style Objects
Hide implementation behind objects called like functions for isolated testing.
Event sourcing gives durable execution for free
Each event is a snapshot of the last successful step — so retries pick up where they left off.
Event Sourcing Is A Side Effect Of Pub/Sub
Pub/sub is the real architectural win; event sourcing just follows naturally.
Give Each Ractor A Different Strategy To Beat A Single Thread
Parallel Ractors only beat one thread when each explores a different starting point / cooling schedule.
Give users customization interfaces or they'll patch your privates
Without proper extension points users override private methods, making refactoring impossible.
Hotwire suits B2B desktop apps; React suits B2C mobile and canvas UIs
Pick Hotwire for B2B/desktop iteration; pick React when mobile APIs or canvas UIs are required.
Inject test doubles via dependency injection
Replace ad-hoc stubs with an injected fake collaborator behind an extracted interface.
LangChain Is Dead
LangChain's abstractions are obsolete now that LLM servers provide unified APIs.
Log state changes to make tests assert on behavior
Append events on every state change so tests and debuggers can see the full execution trace.
Make existence checks asynchronous to prevent enumeration
Move registration/reset existence checks into background jobs so timing is constant.
Master Your Tools
Don't just know your workshop tools — master them, with a minimal toolset.
MySQL Data Directory in RAM
Mounting the MySQL data directory in RAM collapsed a 10-minute test suite to ~1 minute.
One Ubiquitous Language Per Bounded Context
Each bounded context must have its own ubiquitous language.
Optimize MP4 for streaming with faststart
Use ffmpeg flags that move MP4 metadata to the front of the file.
ORMs Entangle Business Logic
ORMs are structurally prone to being a worm with no boundaries between organs.
Phlex is only faster than ERB at scale
Phlex beats ActionView on component-heavy pages, not on single-tag rendering.
Prefer atomic components over slots
Ruby UI favors many small composable components instead of a slots API.
Prefer policies/strategies over nested aggregates
Extract growing aggregate logic into testable policies instead of nesting aggregates.
Provided Buffers Enable Automatic Buffer Management
Share one buffer pool across all reads instead of allocating per-operation buffers.
Read Ruby source to understand Ruby
Dig into parse.y and Rubinius to learn how Ruby features really work.
Real Rails Apps Are Not IO-Bound
Mature Rails apps do heavy CPU work, limiting pure-IO concurrency gains.
Redundancy provides no value
Master axiom: anything redundant in code or semantics adds no value and should be removed.
Replace SQLite's C busy_timeout with a GVL-releasing Ruby handler
Implement busy_handler in Ruby using Sleep so it releases the GVL during DB waits.
Resilience Through Independent Infra
Independent PDSs, App Views, and clients kept Bluesky usable during the Thursday outage.
Run Litestream as a Kamal accessory
Ship Litestream alongside SQLite apps as a Kamal accessory with user 1000 to share the volume.
Smoke Test ViewComponents via Lookbook Previews
Use Capybara to visit every Lookbook preview; rely on end-to-end tests for business logic.
Split Active Record into write and read objects
Extract decisions into a pure write object; leave display/associations to Active Record.
Three Ways To Delete User Data In Event-Sourced Systems
GDPR erasure options: reactive (Fowler), encrypt-and-lose-key, or Kafka compaction.
Tuples must be kept in sync with domain data
Moving many-to-many relationships into an FGA store creates a sync obligation.
UringMachine as EventMachine Replacement
UringMachine exists to replace long-abandoned EventMachine.
Use existing parser generators and VMs instead of rolling your own
In practice, leverage lexer/parser generators and existing VMs (YARV, JRuby, TruffleRuby, Parrot, LLVM, .NET).
Use Logux for optimistic UI with Rails
Logux integrates with existing Rails apps to deliver optimistic, real-time UIs.
Use touch: true for fragment cache invalidation
Add touch: true on child associations so parents' cache keys invalidate.
Acknowledge and Name Your Emotion
Naming the emotion you feel makes it fade faster and reveals what is missing.
Action Cable Crowded-Channel Trade-off
Action Cable is fine up to ~thousands of subscribers per channel; beyond that, switch.
Active Job Is A Poor Workflow Container
Active Job jobs are hard to identify, query and treat as stable workflow state.
Add enhanced-sqlite3-adapter for production SQLite on Rails
Three CLI commands package SQLite-on-Rails production readiness.
Adopt CSS-in-JS for modern component-based frontends
Use CSS-in-JS to improve maintainability and reduce bundle size.
Adopt SQLite to cut Rails infrastructure cost and DevOps overhead
A small team can replace Postgres+Render with SQLite on one server for ~10× less cost.
Aggregates Should Not Emit Events
Making aggregate-root a code pattern that emits events is a mistake — it's not what aggregate meant.
All writes must go through the aggregate
If an aggregate owns an invariant, every write path must use it or the stream lies.
Always output YUV 4:2:0
Force YUV 4:2:0 so every browser plays the video.
Audit and reduce existing log volume before adding more
Cut logging cost by auditing volume; structured logging reveals duplicates.
Automate the whole release workflow
Use GitHub Actions to test, lint, label, draft notes, and publish gems.
Avoid Data-Dictated Development
Shape data to serve the app; don't let inherited data shape the app.
Avoid fetching external/view state inside event upcasters
Event upcasting must not depend on view models that can be rebuilt.
Avoid logic in tests
Conditionals, loops, and production helpers inside tests produce green-but-wrong suites.
Avoid params-driven development
Map request params to specific commands early instead of threading them through the stack.
AWS Postgres Pricing Trap
Unmonitored AWS contact emails can silently turn an outdated Postgres into €10k/month of surcharges.
Baseline Metrics Before Building AI Features
Measure operation time and token cost baselines before and after to decide if an AI feature has impact.
Be conservative with breaking changes in mature frameworks
Prefer stable interfaces over refactors; users' installations are often years old.
Beware apartment-style database switching under threaded servers
Re-establishing Active Record connections per tenant is not thread-safe.
Bounded Contexts Are Natural Microservice Seams
Bounded contexts, if kept stateless across boundaries, become clean microservice candidates.
Bounded Contexts Are Not Microservices
Do not conflate bounded contexts with microservices.
Break Code Into Small Units Orchestrated By A Process Engine
Model software as small callable units with inputs/outputs; let a workflow engine compose them.
Bring your own ffmpeg arguments
Bypass library DSLs and pass custom ffmpeg args for control.
Budget extra RAM for Kamal blue-green deploys
Provision more RAM than you expect — blue-green deploys run old and new versions in parallel.
Build APIs with immutability, EDN, context-free, flat
Four-step recipe for API design: immutable, EDN-based, context-free, flat.
Build your gem in a Docker container
Packaging in Docker isolates the build from your local environment.
Business logic is mostly about state machines
Most business logic reduces to state machines that can be implemented without libraries.
Cache Clear Hook Killed a Test Suite
A `Rails.cache.clear` in an RSpec before(:each) inflated a suite from 40s to 15 minutes.
CDN is not always the answer
CDNs help global distribution but can hurt when HTTP/2 would be faster with one origin.
Classes Should Configure Their Own Dependencies
Don't outsource operational dependency wiring to Rails config, IoC containers or needle.
Client-Side JavaScript as Liability
Treat client JS as a liability and use as little as possible to achieve what users need.
Collapse controllers and background jobs into one command layer
Treat synchronous and asynchronous work as a single command-handler abstraction.
Collect data before enabling risky features
Define indicators and capture data before rolling out hard-to-predict features.
Complexity Grows Inward in Service Objects
Left unchecked, service objects accrete responsibilities and become large internal monsters.
Contribute to Arkency aggregates repository
Add new aggregate implementations to the public Arkency aggregates repo.
Copy streams when transcoding
Copy unchanged streams (e.g. audio) across variants instead of re-encoding.
Coupling Is Neither Good Nor Bad
Coupling is a context-dependent force like gravity — sometimes high, sometimes loose.
Decouple request from response for SXG
Think of SXG responses as independently-lived, cache-friendly artifacts — not request-scoped.
Design Must Be Described Precisely Before It Can Be Improved
Learn vocabulary for design first; better design follows precise communication.
Design UX Before Technology
Decide the user experience with business/UX before choosing the tech, especially for services.
Ditch the AMP framework, keep the cached-signed-page idea
SXG preserves AMP's privacy and control benefits without its HTML limitations.
Don't Auto-Convert Calendar Units
Libraries must not pick an answer for '31 January + 1 month' — the domain decides.
Don't Bring MVC-CRUD Thinking To Services
Service architectures collapse when the mental model stays MVC-CRUD.
Don't Conflate Entity, Handler and Projection
Keep entities, handlers, and projections as separate, independently testable classes.
Don't Cram Eventide Into Legacy Apps
Adopting Eventide in an existing messy codebase is playing with fire.
Don't Enqueue Jobs Inside A Transaction
Jobs queued inside a DB transaction can run before or instead of commit.
Don't follow JSON API religiously
Use JSON API with company exceptions; pick the right spec per use case.
Don't kill dependencies — use backoff
Retries without backoff can push an already-struggling receiver over the edge.
Don't kill your team — alert only on unexpected errors
Only page the team on unexpected errors; use metrics/alarms for the expected ones.
Don't Store Sensitive Data Yourself
Offload PII/EHR to specialized third parties and work only with metadata where possible.
Don't test randomness — understand, extract, control it
Closing message: rather than testing random output, isolate randomness behind an abstraction you can control.
Don't Use Interactors
The interactor gem adds boilerplate with no real benefit over plain functions.
Draw Call Graphs To Expose Wrong-Way Dependencies
Upward arrows in a layered call graph mean something has gone wrong.
Elevate Validations Into The Domain
Treat validation as core domain logic in a service, not a persistence concern.
Eliminate Primitives With Value Types
Replace string/int/bool primitives in domain code with value types.
Enable requires_ancestor when adopting Sorbet
Turn on Sorbet's experimental requires_ancestor feature immediately.
Enable WebMock on legacy apps
Drop WebMock into a legacy Ruby app to catch unexpected third-party HTTP calls.
Enterprise Means Using Existing Tools
Enterprise software means reusing standardized tooling instead of rebuilding per project.
EPOLLONESHOT removes ready sockets automatically
EPOLLONESHOT gives bouncing-select behavior for free on Linux.
Events as Stem Cells
Events are the most reusable form of data, transformable into any representation.
Event Sourcing Enables Distribution
Event sourcing naturally sets up bounded contexts, event-driven flow and distribution.
Event Sourcing Is About State Not Distribution
Event sourcing solves state persistence, not inter-service communication.
Event Sourcing Is Not A Silver Bullet
Event-based architecture fits some systems and not others.
Events Record What Occurred, Nothing Else
Never add view-only fields to events to make UI composition easier.
Every commit must be an improvement, atomic, and deployable
Enforced constraint: every single commit must improve the system, be atomic, pass checks, and be deployable.
Extract Scopes When Partials Get Too Many Locals
Use scopes to keep partials reusable without threading a long list of locals through templates.
Extract the slow server out of Ruby
Keep business logic in Ruby, push low-level WebSocket I/O to Go/Erlang.
Fat Model Skinny Controller Is A Design Mistake
Concentrating business logic in models puts specific code on highly afferent objects.
Form objects must not save
Form objects handle UI input and validation only; persistence belongs to commands.
Freeze Or Make_Shareable Non-Sharable Objects For Ractors
Ractors reject plain mutable objects; freeze or Ractor.make_shareable to pass them in.
Generate RBI files instead of writing inline signatures
Keep Sorbet sigs out of your .rb files by generating them via Tapioca into RBI files.
Give Unto Rails That Which Is Rails
Keep business logic out of Rails and in lib/; treat Rails as a thin web-server layer.
Graph resolvers compute minimal API calls automatically
Small resolvers composed into a graph yield batched, parallel, fallback-aware fetching.
Group models into folders by entity dependency
Create model folders by aggregation-root-style entity dependencies from day one.
Grow Frontend Complexity Organically
Start at the top of the complexity stack and only add when required.
Handlers Must Control Their Dependencies
Command handlers should own their projection and writer, not delegate to framework.
Harden Ruby Production Systems
Freeze core classes, disable eval and method_missing in production to fight ecosystem drag.
Inconsistency provides no value
Style inconsistency across a codebase adds no value; agree on a shared style.
Interoperation via Shared Lexicons
Public lexicons and shared PDS storage let unrelated apps interoperate by default.
Introduce bounded-context controller namespaces
Model bounded contexts like moderation as their own controller namespaces.
Invite business experts into EventStorming sessions
DDD only works when business collaborates directly via simple tools like sticky notes.
io_uring Beats Threads More as Concurrency Grows
UringMachine's advantage over threads widens as concurrency level increases.
Isolate ffmpeg due to its vulnerability history
Sandbox ffmpeg because it has had server-compromising CVEs.
JRuby opens Ruby to enterprises
JRuby solves the three main enterprise objections to shipping Ruby.
JRuby startup time is mostly solved
JRuby startup is now ~400ms baseline and 1–1.5s for large rake tasks.
Keep business classes free of framework dependencies
Don't infect business objects with framework or library imports.
Keep Entities Free Of Messaging
Entities should be pure domain logic, not aware of commands or events.
Keep refresh tokens in HttpOnly Secure SameSite cookies
Put long-lived refresh tokens in server-controlled cookies, not JS-accessible storage.
Keep Sidekiq Job Parameters Simple
Pass references (IDs) to Sidekiq jobs, not complex objects or raw values.
Learn to Read EXPLAIN
Reading EXPLAIN output is the prerequisite for debugging slow Postgres queries.
Limit Devise password length to 72 bytes
Align Devise password length with bcrypt's real limit to prevent silent truncation.
LLMs Amplify Existing Patterns
LLMs aren't especially bad developers; they just throw many more darts past your automation.
LLMs Are Just Token Generators
Everything beyond 'predict next token' is scaffolding written around the LLM.
Look outside Ruby for better patterns
Borrow ideas from TypeScript, Java, .NET to improve Ruby projects.
MCP Servers Have No Security Model
Using an MCP server effectively hands control of your LLM to whoever runs it.
Measure Client-Side Performance First
Before migrating off an SPA, instrument real-user core web vitals to prove impact.
Measure SXG with a canary, not before/after
Compare SXG traffic with working vs broken sub-resource prefetching, not pre- vs post-deploy.
Metrics Alone Don't Fix a Coupled Legacy Codebase
Coupling metrics are overwhelmed on legacy projects; precise communication matters more.
MFA improves account-sharing health
Selective MFA significantly reduces account sharing and boosts signups.
Microservices Were Never About HTTP
The 'micro' in microservices just meant 'no IBM/Microsoft/Oracle' — not HTTP between every component.
Microsoft is becoming a friend of the open web
Post-Ballmer Microsoft invests in TypeScript, Ember, MobX, and PWAs.
Migrate schemas first, then data
Make the schema SQLite-compatible while still on Postgres before swapping the adapter.
Model permissions as a graph, check them as path existence
Frame authorization as graph reachability over relationship tuples.
Mutant as complexity metric and refactoring guide
The number of mutations generated per subject is a better complexity metric than cyclomatic complexity.
Mutation testing replaces dumb review questions
Mutation testing answers ~90% of mechanical review questions automatically, freeing human reviewers.
Name your types to reuse and document them
Extract and name composite types (Latitude, UserID, GroupMembers) so they become first-class domain concepts.
Narrow Agent Responsibilities For Reliability
Shrink an agent's task set to make it reliable; avoid open chat UIs in production.
Negotiate for idempotency-key support
If a third-party API lacks idempotency support, negotiate the feature or switch providers.
Never Estimate Integrations Up-front
Integrations depend on vendor reality, not your code — don't accept fixed-price for them.
Norbert's Golden Rule of Rewriting
Rewrite if and only if you want to build on different principles.
One file rules them all
Keep a component's view and logic in a single Ruby file for simplicity and maintainability.
Opal missed its window with Rails
Opal lost traction when Rails adopted Webpacker/ES over Opal.
Open Source Maintainer Lessons
Be responsive, friendly, welcoming and helpful — attention spans are finite.
OpenTelemetry lowers vendor lock-in but switching costs remain
OTel makes swapping vendors easier, but alerts/dashboards/UI still lock you in.
Pad Your Estimates
Double or triple raw estimates; deliver later but on time.
Paperclip Disable Convert Trick
Disabling Paperclip's file conversion in tests cut a suite from 3.5 minutes to under 30 seconds.
Pay the open-source maintainers you depend on
As OSS customers, dependents should financially support the maintainers of their dependencies.
Permissionless Building
On AT Protocol you can ship ideas without API keys or approvals.
Pick the highest H.264 profile you can afford
Higher H.264 profiles mean smaller/better videos but fewer compatible devices.
Port Pathom's ideas to Ruby
The Pathom approach isn't Clojure-specific and can be implemented in Ruby.
Port Python Libraries With ChatGPT
Paste missing Python libraries into ChatGPT and have it rewrite them in Ruby.
Pre-compile engine assets to shield host apps
Ship compiled CSS/JS in the engine so the host app doesn't need your toolchain.
Prefer Brotli over gzip when available
Brotli saves 10–20% bytes and CPU vs gzip, with automatic gzip fallback.
Prefer class-method services over stateful service objects
Implement services as class methods to structurally prevent instance state.
Prefer conventions over custom code
Follow established standards and framework conventions instead of rolling your own.
Prefer DB-derived columns over recomputed values
Store rarely-changing derived values (e.g. number_of_stars) in the DB via callbacks.
Prefer extending ViewComponent classes/attrs over multiplying variants
Allow callers to append custom CSS classes and data attributes instead of adding component variants.
Prefer LATERAL over CTE for filtered top-N per group
LATERAL joins outperform CTEs when the outer query filters.
Prefer . over :: for method calls
RuboCop and community convention: reserve :: for constants, use . for methods.
Prefer Prepend Over Inheritance For Jobs
Share job behavior via prepended modules, not a big shared parent class.
Prefer Small Sidekiq Jobs
Split work into small jobs for faster concurrency, easy retries and progress tracking.
Prefer SQL Window Functions over Ruby Aggregation
Window functions replace two-query-and-combine logic with one fast query.
Prompts as Business Logic
Put business SOPs into prompts and let the LLM orchestrate execution across tools.
Publish a roadmap to align contributors
A public roadmap gives users certainty and focuses community contributions.
Publish Small Findings To Scale Debugging
A team debugs in parallel and across time zones only if everyone publishes tiny observations.
Put data-input validations on the command form, not the command
Input validations belong to the view layer, not domain commands.
Ractors Still Experimental In Ruby 4.0
Ractors remain experimental in Ruby 4.0 but the warning was softened; 4.1 may stabilize them.
Rails Tests Are Mostly Integration Tests
The test pyramid doesn't apply to Rails; treat DB-backed tests as integration tests.
Raise in production rather than silently continue
Better to crash on a type error than to corrupt data silently.
Rate-limit login forms with a skip path
Rate-limit login by email, but provide an easy way to fall back to IP-based limiting.
Read models must not depend on each other
Keep read models denormalised and independent; never read one from another.
Real-time multiplayer for free via CQRS pub/sub
Decoupling reads from writes over a shared pub/sub gives multiplayer and streaming UIs automatically.
Recognize theoretical CS patterns under the hood
Compiler and runtime design reuse classical formal-language and automata patterns.
Recommend Reading The Eventide Project
Garofolo recommends reading Eventide's docs even if you don't use it day-to-day.
Record CloudFront request headers on sessions
CloudFront can enrich requests with IP/geo headers but accuracy is limited.
Redact PII in one central place before sending to vendors
Use Rails parameter filter centrally; don't rely on vendor-side redaction.
Reform 2's single mutable form instance was the core design mistake
Letting one form instance render, validate and persist invited misuse.
Reform 3 makes strong_parameters obsolete
A Reform form already ignores undeclared params, removing the need for controller whitelisting.
Reframe domain errors as events
Most 'errors' in a business domain are just another kind of event you should record and react to.
Rename app/models to app/data
Use ActiveRecord models only as scaffolded data carriers; put logic elsewhere.
Replay events to reproduce bugs
Event sourcing turns bug reproduction into replaying the stored event.
Reset session parameters under Rails connection pooling
Always reset RLS session parameters because Active Record reuses connections.
Risks of DDD: Hierarchy, Perfectionism, Constraints
Main risks when adopting DDD in an organization.
Ruby as a Data Management Language
Ruby is a first-class language for data-management roles, not just web apps.
Ruby Regex compiles to a finite-state automaton
Every Ruby Regexp is implemented as a finite-state machine under the hood.
Run Litestream from day one
Stream SQLite writes to S3 from the first deploy — production data loss is too costly otherwise.
Runtime types give you most of the safety for little effort
Ruby's === plus a gem like Literal delivers ~80% of type safety without full static annotation.
Senior Developers Should Say 'I Don't Know'
Admitting lack of knowledge builds, not hurts, senior reputation.
Separate DAG Definition From Node Execution
Keep workflow topology declarative and node code imperative — don't conflate them.
Separate iOS and Android code bases for hybrid apps
Never share one codebase across iOS and Android — build native backbones in each.
Serve preheated static pages via nginx
Pre-render and pre-gzip pages to public/cache so nginx serves them without touching Rails.
Service objects are mappers from params to commands
Shrink service objects to thin params-to-commands mappers.
Service Objects Are Not Domain Services
Real-world Rails service objects fail most of Fowler/Evans/Martin's criteria.
Set a page-load time budget
Define an explicit page-load ceiling organization-wide.
Setup Code Reveals System Quality
The amount of setup code in a test — not its assertions — tells you how good your system is.
Signed On-the-fly URLs
Sign processing URLs with a server-only secret to prevent DDoS.
Silver Bullet Anti-Pattern
Beware tools marketed as solving hard distributed-systems problems for you.
Socratic Debugging With Juniors
Coach juniors through debugging by asking about observations and hypotheses, not by taking over.
Sorbet fits big refactorable codebases, not greenfield
Use Sorbet for confidence while refactoring legacy Ruby; skip it on new projects.
Sorbet signatures are free; assertions are not
Sigs erase at startup with zero overhead; T.let/T.cast/T.must/T.unsafe stay in code and slow it down.
Splice sockets in the kernel
Use kernel splice to move bytes between two sockets without copying to userspace.
Standard Meetings Kill Collaboration
Seated circle meetings inhibit modeling; stand at a shared wall instead.
Start from a live problem, not a three-month observability project
Add only the observability needed to answer a real question today.
Start mutation testing incrementally
Adopt mutation testing on large codebases only on subjects touched by current changes.
Start simple: single-node SQLite is usually enough to reach revenue
Most applications don't actually need multi-node or exotic infrastructure to start.
Start with Action Cable, switch when performance hurts
Use Action Cable for MVPs and small apps; swap in AnyCable when scaling.
Stop Building Web Apps, Build Software
Large enterprise systems are rarely just web request/response; model them as general software.
Store webhooks as technical events
Persist third-party webhook payloads as events, then process async.
Stratified Design Applies At Every Scale
Layering thinking applies to functions, classes, apps, microservices and architecture.
Stub third-party APIs to unblock development
Use WebMock stubs to build and demo features before the third-party API is available.
Study The Past
Re-read old papers — compute has caught up with ideas from decades ago.
Switch on HTTP/2
Enable HTTP/2 in nginx for a ~20% boost with minimal effort.
Take Compliance Seriously From Day One
Don't defer security/compliance to a later audit — plan for it up front.
Take distractions seriously
Structure your day to contain (not eliminate) distractions.
TDD Is Process And Philosophy, Not Mechanics
Red-green-refactor is TDD's routine; its objective is validated, understanding-free implementations.
Teach Cultural Values During Onboarding
Onboarding should include cultural training, not just technology.
Test Code Can Be Generalized Like Production Code
Fixtures can compose and depend on other fixtures, opening a new frontier for test frameworks.
The consumer doesn't care about your app's underlying technology
Users judge apps by whether they accomplish the task, not by web vs native.
Three Steps of DDD
Extract the right model, express it semantically, protect it from corruption.
Timeline Diagrams Reveal Possible Race Conditions
Per-worker timelines analyze your system for race conditions tests cannot find.
Trailblazer tracing saves thousands of debugging hours
Trailblazer's step tracer shows execution path and exceptions across deeply nested flows.
Trust but verify ffmpeg output
ffmpeg can lie; validate output files (but beware ffprobe duration guesses).
Turbo Frames, Turbo Streams and Stimulus can be used independently
Learn each Hotwire primitive alone before combining them.
Upgrade Ruby version for free speed
New Ruby releases (e.g. 2.5) can bring ~10% speedups with no code change.
Use a fair retry interval for SQLite writes
Constant 1 ms retry beats SQLite's native exponential-ish backoff for steady write streams.
Use Argon2id when you need pepper
For new apps, replace bcrypt with Argon2id to get native salt+pepper support.
Use async for Heavy IO LLM Workloads
Switch Active Job adapter to async and use async's barrier to scale concurrent LLM IO calls.
Use at-least-once plus idempotence to build self-healing systems
Combine at-least-once delivery with idempotent receivers so systems resume and self-heal.
Use bouncing IO.select to avoid spin-lock in bidirectional proxies
Remove ready sockets from IO.select arrays until a transmission actually happens.
Use cloud-init instead of Ansible for simple bootstraps
For simple single-VM setups, a cloud-init user-data script beats pulling in Ansible.
Use devise_token_auth for API tokens
Prefer devise_token_auth over rolling custom token auth or JWTs.
Use dry-container for swappable dependencies
Register real/stub implementations in a dry-container instead of threading adapters through calls.
Use EventStorming to align co-founders and onboard stakeholders
EventStorming surfaces disagreements and becomes a living onboarding artifact.
Use ffmpeg presets
Offload encoder tuning to ffmpeg's ultrafast…ultraslow presets.
Use fully namespace-qualified keywords to bridge services
Namespaced keywords enable aliasing identifiers across services in one API.
Use generic and object-specific ViewComponents together
Mix parameter-driven ViewComponents with record-driven ViewComponents depending on the use case.
Use GraphQL when clients need flexible queries
GraphQL wins when clients need varying attribute and object selections.
Use gRPC for high-performance internal service communication
gRPC fits same-architecture service-to-service links needing top performance.
Use hybrid when your app's core is a server-rendered web app
Hybrid shines when HTML/CSS/JS is the beating heart; skip it for deep-native apps.
Use Immediate Transactions for Rails
Set default_transaction_mode: immediate to avoid SQLite3::BusyException in Rails.
Use JVM libraries from Ruby
Pull any of hundreds of thousands of Maven Central libraries straight into JRuby.
Use MCP for LLM integrations
MCP is the natural protocol when exposing tools to LLMs.
Use MinIO for S3 testing
Run MinIO locally so tests use the real S3 API against local storage.
Use MQTT for IoT and bidirectional messaging
MQTT fits IoT and scenarios needing broker-mediated bidirectional messages.
Use Paper Trail For Workflow History
Don't store workflow state history inside the workflow; version the hero with paper_trail.
Use Parts To Guarantee Non-Nil Collections
Wrap exposed values in Hanami View parts so templates get safe defaults like empty arrays instead of nil.
Use Rack socket hijacking for long-running connections
Detach the raw socket from Rack to run a proxy thread outside the request cycle.
Use temporary storage to avoid orphan files
Use separate temporary + permanent storages, and auto-expire temp uploads.
Use top-level controller namespaces per wave
Replace respond_to with top-level namespaces like Web, API, RSS, PDF.
Use === to put Procs in case/when
Since Ruby 2.2, any Proc can act as a case/when condition via ===.
Use typed: strict as the lower bound
Prefer strict typing over typed: true to force real signatures instead of runtime assertions.
Use Unicode Sparklines Instead Of A Charting Library
Render simple distributions inline with Unicode block characters to avoid adding UI dependencies.
Use Unlogged Tables to Speed Up Rails Test Suites
Forcing RSpec to create unlogged tables shaves minutes off test runs.
Validate image dimensions to prevent image bombs
Validate dimensions (not just file size) to defeat image-bomb attacks.
Validate MIME type from file content
Use magic bytes, not the Content-Type header, to validate uploaded MIME types.
Vibe Coding An Unfamiliar Domain Is Risky
LLM-assisted coding multiplies ignorance when you don't understand the domain.
ViewComponent Checklist
Radoslav Stankov's criteria for when to use a ViewComponent vs a partial or helper.
Watch WebAssembly for real performance wins
WebAssembly's streaming + tree-shaking will let tools generate ever more wasm output.
Write Domain Code Free of Frameworks
Protect domain code from framework, database, and messaging corruption.
17% of OSS bugs are planted deliberately
GitHub estimates 17% of open-source bugs are planted as exploits, largely unaddressed.
A Bug Is Fixed When You Understand It
Pushing to production isn't the end — understanding the cause is.
Accept the Blocker Before Fixing It
Acknowledge the stressful nature of a blocker first; calm first, debug second.
Act as a perfect tool on reviews
Human reviewers should flag everything an ideal automated tool would flag, even if today's tools don't.
ActiveSupport Notifications as cheap built-in instrumentation
Rails ships rich instrumentation; subscribe to ActiveSupport Notifications before buying a SaaS.
Add Fun to Keep Remote Workshops Human
Icons, smileys, and playful visuals make hard conversations easier — even with the CEO.
Add SEO alternate links across regions
When splitting an app into regional siblings, add alternate-link tags in the header.
Adopt the No Hello Rule in Chat
Write the issue directly in the first chat message instead of 'hi, how are you'.
AI Made Understanding and Generation Cheap
Modularity must be re-justified by what AI didn't make cheap: review, shipping, reverting, downtime.
AI Will Not Replace Developer-Client Empathy
High-level business collaboration is safe from AI; low-level coding is not.
Always evaluate trade-offs of GraphQL optimizations
Performance wins like look_ahead can cost readability and onboarding time.
Always Have Backup Plans for Remote Workshops
Assume network, audio, power, and data-location will fail — prepare backups for each.
Always Measure, Never Assume
Performance intuition is wrong by definition; benchmark with hypothesis before and after.
Ask For Employee References
Call the previous employer before hiring — it's underused in tech recruitment.
Ask the Most Human Question Possible
Sometimes typing the plainest human question into Google is the fastest path to the fix.
Automate Phantom Migration Rollback
Track executed migrations per branch so switching branches automatically rolls back missing ones.
Avoid Active Record callbacks for media processing
Callbacks turn media processing code into a codependent mess.
Avoid CarrierWave for non-trivial media processing
CarrierWave is fine for thumbnails but breaks down for complex video workflows.
Avoid complexity before fighting it
Push back on business requests before accepting days-long implementation detours.
A Week Of Up-Front Design Is Not Waterfall
Closing the laptop to design a service for a week is agile, not waterfall.
A Week Or Two Of Up-front Analysis Is Still Agile
Event-based systems need real up-front analysis; one-to-two weeks is not waterfall.
Balance Lab And Library Time
Balance reading docs/source (library) with running experiments (lab) — neither alone is enough.
Batteries-Included Observability
Yippee will ship exception, performance, job monitoring, logs and DB inspection out of the box.
Be Assertive As Your Rate Grows
A growing share of a senior rate is pay for saying no to bad ideas.
Be kind and build useful things
Adrian's closing call to build useful software, share it, and be kind.
Best UI Is No UI
Adam Okoń's opinion that the best user interface is the absence of one.
Build The System That Solves The Problem
Engineers are hired to solve problems, not to apply canonical solutions like ML.
Build Your Own Internal CLI Tools
Replacing copy-paste docs with an internal CLI saves the whole team huge amounts of time.
Bump asset version when debugging multi-layer caches
Invalidate Cloudflare, Google SXG and browser caches at once by changing asset versions.
Buy Faster Hardware
A faster developer laptop or CI server pays for itself in months.
Chess as a Hobby for Programmers
Programmers should play chess — meritocratic, measurable, scientific, and full of engineering-adjacent patterns.
Choose Frontend Stack Based on Product Constraints
View components for Rails monoliths, React/React Native when the product needs it — each is a trade-off.
Choose No UI Framework For First Prototype
Skip CSS/JS bundlers and UI libraries on early prototypes; pure HTML is often enough.
Collect as much video metadata as you can
Grab metadata from every input and output to enable cross-analysis.
Colocate Data Fetching with Data Usage
When per-query cost is negligible, fetch data inside views next to where it is rendered.
Commit messages must start with a transformation verb
CI rejects commit messages that don't begin with remove, fix, refactor, change, add (or synonyms).
Community Distinguishing Heavy CPU vs Heavy IO
Ruby community increasingly separates heavy-CPU and heavy-IO concurrency patterns.
Compound Simple Habits to Reach Top Percentiles
A handful of modest habits (one book/year, teach, mentor, conferences, blog/podcast) beats most developers.
Connect engineers to observability costs
Engineers don't see observability bills; close that feedback loop.
Controller tests as highest-ROI tests
Start every new Rails test suite by hitting every controller endpoint.
Control the Input and the Evaluation, Not the Model
Treat the LLM as a black box; put effort into acceptance criteria and reviewing small outputs.
Courage to Try New Patterns
Introducing new patterns like DDD is risky but rewarding with good sources.
Culture Is a Second-Order Effect
Fix the deterministic automation layer before investing in culture; culture is encoded discipline.
Cut Test Suites Under 15 Minutes
A test suite longer than 15 minutes loses developer focus to social media.
DDD Is More Than Aggregates
Aggregates are sometimes unnecessary — DDD strategy and event modeling matter more.
Decide the tenancy approach early
Commit to a partitioning strategy early to avoid costly rework.
Default to Postgres with good indexes before reaching for Elasticsearch
Proper indexes and a well-designed schema handle most filterable index endpoints.
Delay mutations to background jobs
Offload slow mutation work (external calls, bulk ops) to background jobs.
Delegate Event-Model-To-Test Translation To LLMs
Translating given/when/then specifications to tests is boring and ideal work for juniors or LLMs.
Deploy many small projects to one Kamal VM
Host multiple independent projects on a single VM by giving each its own Kamal config pointing to the same IP.
Developer's Understanding Translates Into Code
It is not the expert's knowledge but the developer's understanding that ends up in the code.
Discipline Doesn't Scale (Takeaway)
At any team size, discipline statistically fails; only automation reliably enforces quality.
Dockerize Exotic Dependencies
Dockerize hard-to-install services like Elasticsearch and ship default config.
Don't Abuse Abbreviations
Use acronyms sparingly — newcomers and non-native speakers pay the hidden cost.
Don't Be Greedy With Data
Delete data you don't need; don't hoard it 'just in case'.
Don't create controllers at Rails boot time
Creating controllers before Spring forks makes them immortal across reloads.
Don't Lose Data Unintentionally
Store every business-relevant change; you can't put a future price on data you never captured.
Don't modularise with microservices or engines
Avoid microservices and Rails engines as your primary modularisation technique.
Don't Over-Index On The Senior Title
'Senior developer' is an ill-defined label that can substitute for real growth or raises.
Don't reuse service objects across applications
Avoid sharing service objects between admin, public, mobile, Shopify, etc.
Don't Start a Design System from Button Components
Buttons are the most varied, most opinionated component — extract them last.
Don't Vibe-Code Critical Thinking
LLMs can't solve deep performance or domain-modeling problems for you.
Download first vs transcode from URL is not universal
URL-based ffmpeg transcoding can be 50× slower for some inputs.
Enforce domain boundaries dynamically via ActiveRecord hooks
Wrap save/update at runtime to reject cross-domain writes that skip public APIs.
Enhanced Charisma With Regulators
Ledger-based event-sourced systems delight regulators in regulated industries.
Event Sourcing Mind Shift Trade-off
Shifting senior engineers from current-state to event-projection thinking is hard.
Eventual Consistency Trade-off
Embracing eventual consistency is hard, especially with legacy and external systems.
Every Model Is Wrong But Some Are Useful
Every software model is wrong — aim for usefulness within a specific context.
Extract a partial only when it earns its keep
Every partial adds significant rendering overhead; don't extract one lightly.
Find Your Own Motivation To Volunteer
Pick any point on a volunteering-reasons list (or your own) that actually motivates you.
Gradual migration via steps
Break big multi-region migrations into small, deployable stages instead of one leap.
Hindsight is 20/20 — don't judge past code
Don't judge old code or other developers harshly; experience is earned over time.
Hiring For Event Sourcing Trade-off
Engineers with prior event-sourcing experience are scarce and hard to hire.
Horizontal Scale Superpower
Splitting read and write models lets each side scale independently.
Immutable Database Raises Mistake Cost
Mistakes in event-sourced systems are far more expensive than in mutable databases.
Investigate any sub-1-second request you touch
Maciej's personal heuristic: requests over 1s deserve at least a look.
Isolate Messy HTML Rather Than Fix Prematurely
Keep messy code contained on one page until you have a better idea; don't over-extract.
Keep cache keys simple
Complex cache keys can cost more to compute than the render they save.
Keep Calm and Carry On — It's Just a Job
When everything falls apart, remember it's just a job.
Keep fake implementations out of production code
Test doubles belong in the test suite, not shipped alongside production files.
Keep Project Setup Simple
Optimize for `bundle; db setup; rails c` so new developers can work in minutes.
Keep the DSL, rewrite the runtime API
In Reform 3 the declarative DSL is kept; only the runtime and internals changed.
Knowledge, not code, is what DRY is about
Apply DRY to duplicated domain knowledge only — not to coincidentally similar code.
Know thy app
Know your code, your framework, your libraries, and the language — otherwise bugs like this are inevitable.
Layered DDD is junior-friendly and estimation-friendly
Small building blocks make onboarding and estimating easier than a big ball of mud.
Learn SQL to analyze your product
Analyzing application indicators effectively requires writing custom SQL.
Learn to Rephrase Problems
Switch coordinate systems / abstractions to make hard problems easy.
Make performance a team mindset
Optimization must be continuous and owned by the whole engineering team.
Manual Coefficient Tweaking Is Informal Training
Iteratively hand-tuning weights while watching outputs is a backwards form of model training.
Mentor by Guiding, Not Coding
Write no code, deflect credit, absorb blame — and strip complexity for the junior's sake.
Mentorship Grows Both Sides
Experienced Rubyists should mentor — they gain more than they expect.
Mobile JavaScript performance has improved ~3x since 2014
Modern phones make 2012-era anti-hybrid arguments obsolete.
Model Domain By Reverse-Engineering Apps You Use
Train DDD intuition by modeling Uber/e-commerce domains and their new features.
Modularity As Business Capability
Well-modularized systems expose business capabilities that can be recombined into new products or paid extensions.
Monitoring is the most important optimization habit
Without layered monitoring you can't identify real GraphQL bottlenecks.
Monolith is not the problem — God objects are
Complaints about monolith scalability/maintainability usually reflect God objects, not the monolith itself.
Most SPAs See Only One Soft Navigation
On average users make one soft navigation after landing; SPA weight rarely pays off.
Name Sidekiq Jobs After Their Responsibility
Use meaningful, specific job class names including 'Job' suffix.
Name Things To Find Their Properties
Extract essences from talks, give them new names, then discover their properties.
Narrow the Blocker by Comparing Environments
Isolate blockers across apps, browsers, and OSes to locate the fault outside your code.
Never self-censor on reviews
When reviewing, voice every concern — worst case you learn something, best case you catch a real issue.
Never store tokens in plain text
Treat tokens as passwords — hash them before writing to the database.
No YAML Configuration
Yippee will ship with no YAML config and minimal generated configuration.
Observability becomes addictive
Once teams have graphs, curiosity drives continuous bug discovery.
One Definition, Three Surfaces: REST + OpenAPI + MCP
A single step-based service definition generates REST, OpenAPI docs, and an MCP server.
Ontologies Are the Only Domain-Specific Part
Reuse a knowledge-graph extractor on any domain just by defining its ontology.
OSS support needs automation, not goodwill
Without automated, graph-wide support, leaf dependencies and mid-tier gems go unfunded.
Our Work Is About Business Value, Not Code
Almost nobody in business cares about code — they want problems solved.
Own your HTTP layer with a single client class
Route all outbound HTTP through a class you own so you can swap/intercept behavior globally.
Parsing is already validation
Coercion steps inside parsing are validations, suggesting parse/validate should form a cycle.
Pass IDs to background jobs, not objects
Serializing big objects into jobs can be slower than reloading from the database.
Patch Instead of Rewrite Breaking Changes
Deploy breaking changes as patches on the old rule with a multi-year adoption window.
Per-Event Backups Via Reactors
A reactor consuming every event provides trivial, redundant backups.
Persist extracted metadata
Persist any extracted file metadata in the database for later retrieval.
Pick Important-But-Not-Urgent OSS Problems
Build open source for problems that are important, not urgent, and generic across domains.
Polars Ruby for Fast CSV Parsing
Polars Ruby is ~22× faster than stdlib CSV and light enough for in-request 300MB parses.
Port Chrono Ideas To Ruby
Take Chrono's abstractions and build an idiomatic Ruby version.
Power is dangerous without constraints
Good teams develop explicit constraints to control Ruby's power.
Practice Makes Permanent
Whatever level you practice at is what you get better at; choose your best.
Precognition Superpower
New features can be built as if they had existed from day one.
Prefer a simple top-to-bottom worker
A plain processing worker beats gem-slapping and Rails callbacks.
Prefer delegation over inheritance
Inheritance rarely fits real domains; prefer delegation or extraction.
Prefer exploration over alerts; noisy alerts are worse than none
Build exploratory tools; reserve alerts for truly critical thresholds.
Prefer fixtures and stubs over factories and mocks
Use fixtures for test data and stubs for external collaborators; avoid factories and mocks where possible.
Prefer libvips over ImageMagick
libvips is typically 3–5× faster than ImageMagick for web image processing.
Prefer Procedural Code For Everyday Rails
Most daily Rails code should be simple procedures, not OOP machinery.
Provide Seeds for All Data
Ship seed data so developers can reset the DB without losing their local work.
Publish solutions that work for you
If you have a solution that works for you, publish it — others may find it useful.
Purity Is The Wrong Lens; Dependency On Time Is The Right One
Classify code by when/how-many-times dependencies, not by 'pure vs side-effectful'.
Push constraints down to the lowest level
Ingrain invariants as deep in the stack as possible — into the database, not just the model.
Quantify Wasted Time to Convince the Business
Track CI wait, queue time, and bug rework; multiply by salary; show the money.
Quote Your rm -rf Paths
Unquoted spaces in rm -rf commands can blow away your home directory — always quote.
rails_event_store is the most productive DDD tool in Ruby
Bold claim: rails_event_store beats Java/.NET/Python equivalents for DDD.
Rails leads JS frameworks on Core Web Vitals
Rails origins pass all three Core Web Vitals thresholds at higher rates than JS SPA frameworks.
Rails Way vs Design Way
The Rails Way trades two weeks of speed for months of hell by ignoring structural design laws.
Ratios Not Absolutes
Think in ratios of red to green contributions, not absolute counts.
Read the Documentation
Read the docs — lazy developers wrote them and there's usually something interesting there.
Read The Documentation At Every Learning Step
Documentation is valuable at every level of seniority and every learning phase.
Read the Ruby standard library
Ruby's stdlib hides powerful tools like PStore, DRb, TSort.
Refactor with clear business merit
Tie every refactor to a business need and slice features — never a big-bang rewrite.
Rehearse the go-live
Run the full migration procedure repeatedly on staging/local before touching production.
Reject invalid input as early as possible
Validate at the boundary and return an HTTP error rather than coercing bad data.
Release DB connections around external HTTP calls
Don't let idle DB connections sit inside open transactions while waiting on external services.
Replace Code Review With Architecture Execution
Fight for quality at planning time; make code review a formality by executing a pre-agreed architecture.
Replay-Based Debugging
Replaying events from a known good state collapses race-condition debugging from days to minutes.
Reuse Command Model Aggregate For Response
Synthesize the response from the command-model aggregate when legacy clients demand immediacy.
Reuse existing observability infrastructure
If infra already runs Prometheus/Grafana, publish your metrics there instead of rolling your own.
Roll back the verification transaction
Wrap on-production verification in a rolled-back transaction to avoid polluting real data.
Rushing Causes Design Mistakes
Ladd's recurring failure mode: enjoying the first 20% and declaring work done when only 'working'.
Scrutinize Community Thought Leaders
Communities and leaders can suppress critical thinking; hold popular ideas under scrutiny.
Senior Is a Billing Title
In business, 'senior' often just means 'we can charge 2× for this person'.
Separate sample collection from verification
Decouple recording old-flow samples from verifying the new flow so you can iterate safely.
Share Browser-Support Config Across Front-End And Back-End
Keep a single browsers JSON config and share it between Browserslist and a Ruby port.
Shared Hardware Is a 1970s Feedback Loop
Pushing to CI without running locally puts you in a shared-terminal-era queue.
Shorter Code Is Not Easier To Understand
Code golfing teaches the language, but shorter code does not equal clearer code.
Sign serverlessforruby.org petition
Help make Ruby a first-class FaaS runtime by signing the petition.
Simpler Tests Without Updates Or Deletes
Tests over append-only event-sourced code become simpler and faster.
Simplicity Yields Leverage Yields Value
Yippee's philosophy: aggressive simplicity earns leverage, which converts into developer value.
Single Accountable Owner for Workshop Outcomes
Assign one empowered person to push workshop outcomes into delivery.
Software Perfection Is An Ongoing Process
'Software is never done' means the process of perfecting it never ends, not that more features remain.
Split Reads From Writes With Projections
Project event streams into any read-optimized database to separate writes from reads.
Spoken Test Feedback with say + iTerm Triggers
Wire iTerm triggers to the macOS say command for hands-free test feedback.
Stable commits enable bisect
Keep every commit green so git bisect (and similar tooling) remains usable.
Stakeholder Explainability Sells Simpler Solutions
Simple, explainable algorithms empower stakeholders and make non-ML solutions easier to sell.
Standardized building blocks onboard new developers faster
Well-defined command/handler/event patterns simplify onboarding despite boilerplate.
Start With a Hypothesis, Not a Fix
Without evidence, shouting 'remove the gem' or 'revert the commit' is just an opinion.
Stickies Translate Directly To Code
EventStorming stickies map 1:1 to events, commands, objects, and tests — convincing developers.
Stop delegating decisions to popular library authors
Develop your own reasoning instead of trusting 5k-star gems and their READMEs.
Suggest Workarounds to Unblock Clients
While investigating a blocker, give clients and management a workaround (e.g. drag-and-drop) to defuse urgency.
Sunday-On-Or-After-Saturday Trick
Rephrase 'first Sunday after X' as 'Sunday on or after X+1' to eliminate edge cases.
Support Your Local Ruby Community
Talk to your boss about sponsoring meetups and conferences — communities are shrinking post-COVID.
Table swap faster than deletion
Copy wanted rows into an empty clone and rename — faster than deleting unwanted rows.
Take Notes During Debugging
Write down every observation, question, and hypothesis — notes beat 'flow state' myths.
Tech is Easy, People Are Not
Tech is predictable and rational; people are neither.
Tests and Deployment in Under One Second
Yippee's aspirational bar: 10,000 tests and a full deploy each complete in under a second.
The best code is no code
Sometimes the right performance fix is deleting the feature.
Time-box performance exploration to find leverage
10–30 minutes of scouting beats diving straight into an optimization of unknown value.
Time Travel Superpower
Keeping all events enables temporal queries and projecting any past state.
Tooling Never Forced Your Monolith
Don't blame Rails (or any tool) for your god classes — and don't expect Elixir to fix them.
Top-down beats bottom-up for bucketing
Starting from the domain root and walking down is simpler and faster than leaf-up.
Total Self-Reconstruction Superpower
With a backed-up event store, current state can be fully rebuilt after disasters.
Transfer Knowledge To Retain It
Telling someone what you learned — on Slack, at a meetup, or over a beer — is how you keep it.
Travel To Meet Your International Team
In-person visits can unblock cross-cultural cooperation that remote contact can't.
Treat existing system behavior as a specification
When business rules are undocumented, let production behavior be the spec and validate by replay.
Treat models as domain models
Keep associations, business rules, state machines, and defaults in models — move the rest out.
Treat users' rewrites as a loud red flag
When users start replatforming, the maintainability issues are already serious.
Tune retry duration to the actor
Humans want fast feedback; machines should retry for days so systems self-heal.
UI Data Is Never Truly Fresh
Business should accept a few seconds of projection lag; fresh data is already stale on display.
Understand what the framework is actually doing
High-level Ruby/Rails code hides real work — five-letter changes (each→find_each) can prevent memory explosions.
Use 302 not 301 for region redirects
Chrome caches 301 redirects too aggressively — use 302 for region routing.
Use BFS and a Notebook to Fully Remove Code
Traverse code usage graph breadth-first and track CSS/i18n/JS hooks too.
Use CQRS And Event Sourcing Independently
Apply CQRS or event sourcing where each fits; mixing one half is risky.
Use Fish Abbreviations for Readable Aliases
Prefer fish-shell abbreviations to opaque aliases so pair-programming stays readable.
Use Refinements for Coordinated Modernization
Use refinements to adopt new Ruby features without bumping required version.
Use Refinements for Dependency Reduction
Use refinements to drop optional dependencies like ActiveSupport.
Use Ruby Packer for Single-Binary CLIs
Ship internal Ruby CLIs as single binaries via Ruby Packer to avoid gem/Ruby version pain.
Use Ruby to debug Ruby
When off-the-shelf tools don't fit, writing a small Ruby script is often the fastest diagnostic tool.
Use state machines instead of boolean flags
When behavior depends on state, make the state explicit via a state machine.
Use Unique Per-Site Emails To Catch Leaks
Register with a site-specific email alias so spam reveals who leaked your data.
Use Uppy regardless of backend
Uppy gives you great UI and direct-to-S3 support out of the box — use it regardless of Ruby upload library.
Use Whiteboard Experiments To Find Module Boundaries
Ask what happened before/after each event to discover autonomous module boundaries.
Write an explicit go-live runbook
Define exact steps, commands, checks and owners before the maintenance window.
Write For Your Future Self
Blog what you learn — the main audience is future-you, and it pays off later.
You Can Actually Test Rails.env Branches
Use stub_any_instance (minitest) or RSpec temp-scope to run development- or production-only code in tests.
Your Data Already Belongs To Criminals
If you have 50+ online accounts, some of your personal data has already leaked.