MicroPosts
- AI bias
I shared in Why Good Solutions Block Better Ones why the first idea that comes to your mind may make you ignore other ones.
And here we are!
- Dialog with Rails & Hotwire
At the end of
<body>
:<dialog data-controller="modal-dialog" class="tw-w-[calc(100%-0.5rem)] tw-max-w-xl tw-rounded-lg"> <div class="tw-p-8"> <button data-action="click->modal-dialog#close" class="tw-absolute tw-top-6 tw-right-8 tw-text-5xl tw-opacity-40 hover:tw-opacity-90 tw-select-none" >×</button> <%= turbo_frame_tag 'modal_dialog', data: { action: 'turbo:frame-load->modal-dialog#open' } %> </div> </dialog>
Stimulus controller:
import { Controller } from "@hotwired/stimulus"; export default class extends Controller { connect() { this.element.addEventListener("close", () => { this.element.classList.remove('open') }); } disconnect() { this.close(); } open() { this.element.showModal(); this.element.classList.add('open') } close() { this.element.close(); this.element.classList.remove('open') } }
CSS:
// This scrolls the page to the top, which is a problem if the // user opens the dialog not at the top of the page. // // The following would work but causes an horizontal layout // shift when the scrollbar disappears: // .no-scroll { // overflow: hidden; // } // // Keep an eye on the following thread for better solutions: // https://github.com/whatwg/html/issues/7732 body:has(dialog[open]) { overflow-y: scroll; position: fixed; width: 100%; } dialog { opacity: 0; transition: opacity 0.3s ease-out; box-shadow: 0 0 0 100vmax rgba(0, 0, 0, 0.8); } dialog.open { opacity: 1; } dialog::backdrop { display: none; }
Button that opens the dialog:
<%= link_to( fa_icon('plus', text: 'Invite user'), new_dashboard_organization_team_member_path(@organization), class: '!tw-py-2 !tw-px-3 !tw-text-base btn btn-default', data: { turbo: true, turbo_frame: 'modal_dialog' } ) %>
Form that gets rendered into the dialog:
<div class="container tw-py-20"> <div class="tw-max-w-xl"> <p class="text-muted"> <span data-toggle="tooltip" title="Organization name"><%= @organization.name %></span> / <%= link_to 'Team members', dashboard_organization_team_members_path(@organization) %> </p> <%= turbo_frame_tag 'modal_dialog' do %> <h1 class="tw-m-0 tw-mb-6">Invite team member</h1> <%= render partial: 'form', locals: { team_member_form: @team_member_form, form_method: :post, action_url: dashboard_organization_team_members_path, submit_value: 'Invite' } %> <% end %> </div> </div>
Controller:
def create team_member_form = TeamMemberForm::NewForm.new(new_team_member_params.merge(organization: organization, inviter_email: current_user.email)) if team_member_form.save flash[:success] = 'The user has been added to the team members.' respond_to do |format| format.turbo_stream do render turbo_stream: turbo_stream.action(:redirect, dashboard_organization_team_members_path(organization)) end format.html do redirect_to dashboard_organization_team_members_path(organization) end end else @team_member_form = team_member_form render :new end end
Redirect:
// Workaround for redirecting from within a Turbo Frame: // https://github.com/hotwired/turbo-rails/pull/367 Turbo.StreamActions.redirect = function () { Turbo.visit(this.target); };
- endoflife.date
End-of-life (EOL) and support information is often hard to track, or very badly presented. endoflife.date documents EOL dates and support lifecycles for various products.
Example:
Need to check what's the latest version of Ruby? Or until when it's supported?
- stdout vs stderr
Use
stdout
for the output of your program: the log ingit log
, the matching files withfind
, or the list fromls
.Use
stderr
for errors AND ANYTHING ELSE: the progress messages, the warns/info, and the jokes (if you really need to).For example, given the following output (on
stdout
):I, [2024-12-10T18:59:45.134882 #7388] INFO -- : Crystalball starts to glow... W, [2024-12-10T18:59:45.138463 #7388] WARN -- : Maps are outdated! I, [2024-12-10T18:59:45.311953 #7388] INFO -- : Starting RSpec. {"version":"3.13.2","messages":["No examples found."],"seed":41594,"examples":[],"summary":{"duration":6e-05,"example_count":0,"failure_count":0,"pending_count":0,"errors_outside_of_examples_count":0},"summary_line":"0 examples, 0 failures"}
I had to remove manually the first lines to parse the JSON:
command | tail -n1 | jq
- Ruby: default gems
Ruby's stdlib is composed of 3 different elements:
- Standard libraries that are embedded in the language's source
- Default gems that can be required, are maintained by the core team, and cannot be removed
- Bundled gems that come installed with Ruby and can be removed
Full list on stdgems.org.
- Ruby gem activation
This is how you use a Ruby gem usually:
require 'foo' Foo.bar
For the
require
to work, the gem needs to be available on theLOAD_PATH
:ruby -e 'puts $LOAD_PATH'
The act of adding a gem to the
LOAD_PATH
is called "activating a gem".In a vanilla Ruby situation, you can add a directory to the
LOAD_PATH
with:ruby -I ./foo/lib -e "puts(require 'foo')" # true
More often, you deal with a bundle that contains a Gemfile:
gem 'foo'
To activate the gems from the Gemfile (taking into account the versions from Gemfile.lock):
require 'bundler/setup' require 'foo'
or (equivalent):
require 'bundler' Bundler.setup require 'foo'
Notice that the
setup
step will first clear theLOAD_PATH
and activate only the gems in the bundle.For example, Rails does it here and here.
If you've ever wondered what the hell is up with
bundle exec ...
, the answer is simple: Bundler activates the gems in the bundle with something likeRUBYOPT="-rbundler/setup" ruby ...
Of course, things are more complex than that. But this should give you a starting point.
- Hi, thanks, bye
When travelling, strive to learn how to say three words: hi, thanks, bye.
You'll be surprised of what happens when you stop being "just another tourist."
- Convert RDA to CSV with a script
Throw the following into
rda2csv.r
:#!/usr/bin/env Rscript argv <- commandArgs(TRUE) inFile <- toString(argv[1]) print(paste("Reading:", inFile)) outFile <- gsub(".rda$", ".csv", inFile) print(paste("Writing:", outFile)) inData <- get(load(inFile)) write.csv(inData, file=outFile)
Make it executable:
chmod +x rda2csv.r
And run it on an RDA file:
./rda2csv.r path/to/file.rda
- Risking millions on coin flips
Using the Binomial Distribution to tilt the odds in your favor.
I found this pearl in Naked Statistics (chapter 5):
In 1981, the Joseph Schlitz Brewing Company spent $1.7 million for what appeared to be a shockingly bold and risky marketing campaign for its flagging brand, Schlitz. At halftime of the Super Bowl, in front of 100 million people around the world, the company broadcast a live taste test pitting Schlitz Beer against a key competitor, Michelob. Bolder yet, the company did not pick random beer drinkers to evaluate the two beers; it picked 100 Michelob drinkers.
It turns out, Schlitz's marketing department was not a bunch of idiots. And here's why.
If you toss a coin twice you can get either one of the following:
- heads, heads
- tails, tails
- heads, tails
- tails, heads
Therefore, the probability of getting one tails out of two flips is 2/4 (ie, case 3. and 4.).
That is described by the Binomial Distribution where n is the number of trials (coins) and k is the number of successes (tails):
p = n! / [k! * (n - k)!] * (1/2)^n 2! / [1! * (2 - 1)!] * (1/2)^2 2 / 1 * 1/4 1/2 (same as 2/4 from above)
The statisticians at Schlitz considered that:
- commercial beers taste the same
- in a blind tasting, a Michelob drinker would say that Schlitz tastes better 50% of the times (it's a coin flip)
- getting 40% or more of Michelob drinkers to say Schlitz is better is worth $1.7 million
But what's the probability?
If you take 10 Michelob drinkers, you need at least 4 successes. In other words, you want to sum the probability of 4, 5, 6, 7, 8, 9, and 10 tails with coin flips:
p = 10! / [4! * (10 - 4)!] * (1/2)^10 + 10! / [5! * (10 - 5)!] * (1/2)^10 + ... 10! / [10! * (10 - 10)!] * (1/2)^10 = 0,82
So there's a 82% chance of succeeding.
And if you raise the number of drinkers to 100, you get to a shocking 98%!
- The "opposite" test
When "positioning" something, if the opposite of what you claim is bullshit, what you claim is bullshit.
If you've ever heard any of the following statements:
- Our company is customer-first
- Our product is fast & easy-to-use
Ask yourself:
- Would any company pick customer-last as a strategy?
- Would any product go for slow & hard-to-use?
Nope. Because that's bullshit!
- How big things get done
How big things get done published the following breakdown:
- 100% of the mega-projects analyzed
- 47.9% finished on budget
- 8.5% finished on bugdet and time
- 0.5% finished on budget, time, and produced the expected benefits
Later, the book analyzes what are the prerequisites to get into the 0.5% Olympus:
- Know why all the time: is this code rewrite benefitting the product?
- Think slow, act fast:
- Make mistakes in the planning phase when screw-ups are cheap
- The more time the execution phase takes, the more you expose yourself to black swans (ie, catastrophic and unexpected events)
- Mitigate risks:
- Spike code to understand if and how something can be done
- Ask people who worked on similar features what went wrong/could have been done better
- Estimate using anchors:
- Hofstadter’s Law: “It always takes longer than you expect, even when you take into account Hofstadter’s Law.”
- We always estimate with the happy case in mind and, even the most paranoid, cannot prepare for unknown unknowns
- Ask others what was their experience building a similar thing and use their numbers as a starting point
- Lean on experience:
- Involve people who've worked on similar features in the past
- Learn from other similar projects—and no, you are not working on anything so unique that cannot draw from experience
- Use boring tech: "remove the words custom and bespoke from your vocabulary"
- Build a team
- Iterate:
- "we're terrible at getting things right the first time"
- "I have not failed ten thousand times," Thomas Edison said. "I’ve successfully found ten thousand ways that will not work."
- "If something works, you keep it in the plan. If it doesn’t, you “fail fast,"
- When talking about the success of the Empire State Building, "workers didn’t build one 102-story building, they built 102 one-story buildings."
The following sentence made me stop and think about my fuck-ups:
When delivery fails, efforts to figure out why tend to focus exclusively on delivery. That’s understandable, but it’s a mistake, because the root cause of why delivery fails often lies outside delivery, in forecasting, years before delivery was even begun.
- Learning requires sweating
Learning is not supposed to be fun. It doesn't have to be actively not fun either, but the primary feeling should be that of effort.
If you are not sweating, it's entertainment, not learning.
Source: Andrej Karpathy on X
- Horizontally scroll to center an element
<div class="width-full overflow-x-auto"> <div>...</div> <div>element</div> <div>...</div> </div>
const viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0) container.scrollLeft = element.offsetLeft // scroll to the left edge of element + element.offsetWidth / 2 // scroll to center of element - viewportWidth / 2 // scroll back half the viewport
- Comment your regular expressions
# ❌ usa_postal_code_pattern = /\A\d{5}(-\d{4})?\z/ # ✅ usa_postal_code_pattern = %r{ \A # Beginning of string \d{5} # 5 digits ( # ZIP+4 - # Hyphen \d{4} # 4 digits )? # ZIP+4 is optional \z # End of string }x
Source: Comment your regular expressions
- Dreamweaving unforgettable experiences
Will Guidara hires Dreamweavers in his restaurant.
Their job is to pull legends: creating, automating, and scaling unforgettable experiences.
- The 95/5 rule
Balancing out what's best for the user vs what's best for the business
Every decision I made seemed to expose the natural tensions between improving the quality of the experience the guests were having and doing what was best for the business. Restaurant-smart meant leading with trust—including allowing the people who worked for me to do what they felt was best for the guests. Corporate-smart meant running a tight ship. Which was right?
Will Guidara's answers his own question:
Manage 95% of your financials down to the penny while spending the remaining 5% “foolishly”, and “splurging” the 5% on the guest experience to create an unforgettable experience.
- Find unused indexes in Postgres
How to use the `pg_stat_user_indexes` table
SELECT * FROM pg_stat_user_indexes WHERE relname = 'TABLE_NAME'
:idx_scan
: how many times the index was usedidx_tup_read
: how many index entries were returned using the indexidx_tup_fetch
: how many rows were returned using the index
You want:
idx_scan
to move up (ie, the index is used)idx_tup_read
/idx_tup_fetch
to move up but not too much (ie, the index is highly selective)
- How to find content ideas
A cheap trick for unlimited inspiration
- Find a relevant subreddit
- Google:
"how to" site:reddit.com/r/SUBREDDIT/
Here are the top results for
"how to" site:https://www.reddit.com/r/javascript/
:- "How to actually Learn from the Documentation?"
- "How do I practice JavaScript?"
- "How did you learn Javascript?"
- "How to become a more well rounded dev"
- "How to develop android apps with javascript?"
- Html `<template>`
Hidden and re-usable pieces of Html
In some situations, you may want to render some hidden Html that can be later accessed by JavaScript to use as a template.
For example, a form to create a survey with a title and multiple questions:
<form> <input type="text" name="title" placeholder="Enter title" /> <button type="button" onclick="addQuestion()">Add question</button> <p>Question</p> <input type="text" name="question" placeholder="Enter question" /> </form> <template> <p>Question</p> <input type="text" name="question" placeholder="Enter question" /> </template> <script> function addQuestion() { const template = document.querySelectorAll("template")[0].content; const clone = template.cloneNode(true); document.querySelectorAll("form")[0].appendChild(clone); } </script>
What I used in the past is less elegant:
<form> <input type="text" name="title" placeholder="Enter title" /> <button type="button" onclick="addQuestion()">Add question</button> <p>Question</p> <input type="text" name="question" placeholder="Enter question" /> </form> <div class="template" style="display: none;"> <p>Question</p> <input type="text" name="question" placeholder="Enter question" /> </div> <script> function addQuestion() { const template = document.querySelectorAll(".template")[0]; const clone = template.cloneNode(true); clone.style.display = "block"; document.querySelectorAll("form")[0].appendChild(clone); } </script>
- Logarithm laws
A quick recap of some fundamental properties of logarithms
Power law
logbpn = n * logbp
Proof:
logbp = a
->ba = p
Raise to
k
->bk*a = pk
Apply
logb
->k * a = logbpk
Replace
a
withlogbp
->k * logbp = logbpk
Product law
logbm*n = logbm + logbn
Proof:
logbm = i
->bi = m
&logbn = j
->bj = n
Multiply ->
bi * bj = m * n
Simplify ->
bi+j = m * n
Apply
logb
->i + j = logbm*n
Replace
i
andj
->logbm + logbn = logbm*n
Quotient law
logbm/n = logbm - logbn
Proof:
logbm = i
->bi = m
&logbn = j
->bj = n
Divide ->
bi / bj = m / n
Simplify ->
bi-j = m / n
Apply
logb
->i - j = logbm/n
Replace
i
andj
->logbm - logbn = logbm/n
- Video to Gif oneliner
Using `ffmpeg` to transform an .mp4 into a .gif
This is how I created the demos for 3v0k4/exit.nvim:
- Recorded the screen with QuickTime into an .mp4
- Transformed into a .gif with
ffmpeg
ffmpeg \ -i input.mp4 \ -vf "fps=10,scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" \ -loop 0 \ output.gif
Source: SuperUser