Today I Learned

A Hashrocket project

Ready to join Hashrocket? Find Openings here and apply today.

460 posts by jakeworth @jwworth

Clean Paste 🧼

When you copy text from the internet, a bunch of formatting and HTML gets copied, too. Copy a link’s text and paste it into Mac Notes, and there’s some of the text formatting of the website, plus the link.

I almost never want this extra stuff, so I use an alternate paste dubbed the ‘Clean Paste.’ On MacOS, instead of CMD + V, try CMD + OPTION + SHIFT + V. You’ll get just the text, minus all the extras.

Note: I learned this via the newsletter Recomendo, which I (pause for effect) recommend. It’s so helpful me and I’ve looked it up so many times, that I’m re-sharing it here.

TypeScript Union Types

Today I got a chance to try out the TypeScript union type. It looks like this.

interface FlashMessageWithSuccess {
  state: 'success';
  message: string;
}

interface FlashMessageWithFailure {
  state: 'failure';
  message: string;
}

export type FlashMessageInterface =
  | FlashMessageWithSuccess
  | FlashMessageWithFailure;

This lets me tell consumers of FlashMessageInterface that it is allowed to have two shapes: one with a state key of success and one with a state key of failure. I can use this to change how I present the flash message.

Yarn Upgrade to Latest ⬆️

Sometimes I just want to blow away a JavaScript library’s versioning in the lockfile and go to the latest. This happens with projects still in development or requiring very stable libraries– I want to be on latest now, rather than creeping up the semantic versioning ladder. Here’s how this is done with Yarn.

$ yarn upgrade --latest react

Enjoy the latest features.

Ruby Itself

Today I stumbled across a neat Ruby object, itself. itself returns the receiver, itself.

string = "my string"
string.itself.object_id == string.object_id #=> true

What’s a use case for this object? I used it to divide an array into arrays of matching integers.

 > [1,99,99,1,2,3,2,5].group_by(&:itself)
 => {1=>[1, 1], 99=>[99, 99], 2=>[2, 2], 3=>[3], 5=>[5]}

Ruby Delete Prefix

Today I was working with a Ruby method that deletes the prefix from a string, turning --code into code. While there are several ways to get this done, a handy Ruby feature I discovered today is delete_prefix:

> "--code".delete_prefix("--")
=> "code"

Intention-revealing and very Ruby.

Group Related ActiveRecord Validations

Today I learned about the with_options feature of ActiveRecord. It’s used to group validations together in a block. You could use it to transform code like this:

class User < ApplicationRecord
  validates :password, length: { minimum: 10 }, if: :is_admin?
  validates :email, presence: true, if: :is_admin?
end

Into this:

class User < ApplicationRecord
  with_options if: :is_admin? do |admin|
    admin.validates :password, length: { minimum: 10 }
    admin.validates :email, presence: true
  end
end

A use case for this might be a collection of validations that should only be checked when a boolean feature flag like enabled? is true.

Kill a Program with pkill

I have a cronjob to open macOS’s Photo Booth every weekday so I can take a picture of my work life. Unfortunately, it opens the program every weekday; I’d rather it quickly closes itself if I’m not there or otherwise occupied. Today I used pkill in the cronjob to terminate the program five minutes after opening:

20 9 * * 1-5  pkill "Photo Booth"

pkill kills a process by name. You can figure out how to make pkill effective using pgrep, a companion program that searches for running processes by name. Using it, I learned that the string “Photo Booth” was specific enough to find and kill Photo Booth:

$ pgrep -l "Photo"
292 Photo Booth

“Photo Booth”, PID 292 (today), is the process I programmatically kill every weekday at 9:20 AM.

Classnames Computed Keys

Here’s some fun code:

import React from 'react';
import cn from 'classnames'

const App = ({ appClass }) => <div className={cn({[appClass]: !!appClass})} />

export default App

Notice the object inside className– what’s going on here?

This is a dynamic class name via ES2015+ computed keys. If appClass is provided as a truthy prop, the class is enabled; if it is not provided or provided as a falsy prop, the class is not enabled.

Tmux Clear Server Pane

Here’s a situation: you’re watching a server log in Tmux, about to trigger an action that will produce log data you care about. You hit return a bunch of times to create a visual break in the server log. Then you can scroll up and see the beginning of your revelant history.

What actually happens? Sometimes, the server logs tons and tons of information, and your visual break gets buried way above the fold. It’s hard to find the break, and you’re searching through all that information, plus anything that happened before.

There’s a better way! Tmux’s clear-history command “removes and frees the history of the specified pane.” In the Hashrocket Dotmatrix, we combine that with send keys -R, which “causes the terminal state to be reset.” Here’s the mapping:

 bind-key C-k send-keys -R \; clear-history

Type the Tmux leader, then C-k, and your terminal pane will be visually cleared and cleared of its history, making reading and reverse searching much easier.

h/t Gabe Reis

Alias a Git Branch Name 🏷

I’m working on a long-running Git branch with a long name, and I’d like to have an alias for that long branch name. The best solution I’ve found so far is to use a Git symbolic ref:

$ git symbolic-ref refs/heads/epic refs/heads/long-epic-branch-name

Once in place, this alias can be used to reference the longer branch name:

$ git checkout epic
Switched to branch 'epic'
$ git branch --show-current
long-epic-branch-name

Resources:

git-symbolic-refs
Answer: Creating aliases for Git branch names

Finding a Data Attribute

Some codebases use data attributes for automated testing, and today I learned how to access and manipulate these attributes from a DevTools console.

document.querySelector(`[data-test-attribute="submit-button"]`).click()

This technique lets me visually verify that the attribute is in the right place and behaves as test software expects it should, without reading the HTML at all.

10x Your Playback Rate

Consuming pre-recorded conference talks, video tutorials, and podcasts at accelerated speeds is possible and addictive. Each week I send a newsletter containing at least one recent conference talk I’ve watched, and I wouldn’t be able to do this without the following hack:

Most videos players (YouTube, Vimeo, QuickTime) let you increase the playback rate, but often these controls are hard to find or have an arbitrary ceiling like 2x. If there’s a video element in the DOM, I like to bump up the rate in the DevTools console like this:

document.querySelector('video').playbackRate = 3

‘3’ equals three-times the normal speed, and that seems to be my limit for the moment.

playbackRate MDN docs

The Zen of Python 🐍

$ python
>>> import this
The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>

Gonna be pondering these for some time. Thanks Phil!

All Jest Describes Run First

When writing a Jest test, the setup code inside any top-level describe function gets run before any scenario. So, if you setup a world in one describe, and a competing world in another, the last one that is run wins.

This even applies when you’ve marked a describe as ‘skip’ via xdescribe. The code inside that setup will still be run.

This is a first pass at a TIL, because I’m not sure the behavior I’m seeing is expected, and if so, why it is expected. It certainly surprised me 😳. I think one solution is to limit your tests to one top-level describe which has the important benefit of being more readable, too.

Google Font Popular Pairings

Google fonts are an incredible resource, and I use them a lot because of how easy they are to set up. Today I learned that Google has a ‘popular pairings’ feature at the bottom of each font page. Here’s that page for the Spectral font:

image

The Spectral/Open Sans pairing shown above gives design newbies like myself a nice serif/sans-serif combination to play with. When you click the ‘+’ icon, your paired font is added to the import statement, so you can get both with one link tag.

Design for everyone.

Git + NPM: Resolving Lockfile Conflicts 🤝

Here’s a challenging real-world scenario: you’re doing a big merge or rebase on a JavaScript project, and you keep getting conflict after conflict in your package-lock.json. These conflicts are tough to resolve, because your package-lock.json is not easy to read, and is, say, 30,000 lines long. What do you do?

When you hit to conflict, on the the conflicting Git SHA, run the following command. Your lockfile will be regenerated, conflict resolved:

$ npm install --package-lock-only

💥

From the resolving lockfile conflicts docs:

image

Tmux Send Keys to Pane

I wrote a script the other day designed to help me download and edit files faster. In part of the script, I wanted to open Vim in an existing Tmux pane, and in the process I learned about the tmux send-keys command. Here’s how it works:

$ tmux send-keys -t 3 "vim" Enter

send-keys, aliased send, sends your string of commands to your pane (t) of choice. Running the above opens Vim in pane #3.

The -t flag accepts negative numbers, too, like an array index. In my version of the above command, I send the keys to pane -1, the last pane on the screen, which is where I keep Vim in my Tmux session.

Enzyme debug() 🐞

Debugging React unit tests can be tricky. Today I learned about the Enzyme debug() function. Here’s the signature:

.debug([options]) => String

This function:

Returns an HTML-like string of the wrapper for debugging purposes. Useful to print out to the console when tests are not passing when you expect them to.

Using this in a log statement will dump a ton of valuable data into your test runner’s output:

console.log(component.debug());

debug() docs

Supercharge Your Script with psql -c 🥞

Want to execute a PostgreSQL command from the command line? You can! The --command or -c flag takes a string argument that will be executed on your database of choice.

I’ve been using it as part of a script that creates a remote database backup, downloads the backup, drops and creates a local database, dumps the database backup into the local database, and then runs a select statement on the dataset. That final command looks like this (query has been simplified):

$ psql -d tilex_prod_backup -c "select count(*) from posts";

 count
-------
  2311
(1 row)

List Files by Updated

I’m currently working on an app that forwards logging around to various locations on the Linux server. It’s a bit tricky for me to figure out where any action I take in the browser is being logged. I need those logs!

A nice way to figure out where the logging is happening is to narrow it down to one directory (say, /var/log/) then ls that directory, ordering by most recently updated. The items at the top of the list have been recently updated, and thus probably contain valuable loggings!

$ ls -lt

I’m throwing on the -l flag for more detail. If there are lot of logs, filter it down with head:

$ ls -lt | head

Thanks for the idea, Kori!

Base64 Encode Your Images

This is a companion to my previous post about inline HTML styles. If you want to put your images inline in your HTML, GNU coreutils provides the base64 program.

Here’s me running it in Vim command mode, sending the output right to my current line:

:.! base64 -w 0 public/images/bg.gif

The -w 0 disables line wrapping, which I don’t want for inline images. Prefix this string with "data:image/<MIME TYPE>;base64," and you’re good to go.

What Styles are Being Used?

I like my exceptional pages (404, 500, 503) to rely as little as possible on the webserver to render in the browser. A nice tool to support this is CSS Used for Chrome.

CSS Used adds a panel to DevTools that reports which CSS classes from external stylesheets are being used on your page. You can then paste these styles inside a style tag and remove stylesheet references in your HTML. I iterate on this by opening the HTML file in my browser outside of my project repo; when all the styles are loading, I’ve removed the stylesheet dependency.

image

DNS Lookup with host

Today while doing some sleuthing, I learned about the host command. host “is a simple utility for performing DNS lookups.” It helped me connect a series of domains to their respective AWS EC2 servers, without a visit to the domain registrar.

Example:

$ host jakeworth.com
jakeworth.com has address 184.168.131.241
jakeworth.com mail is handled by 10 mailstore1.secureserver.net.
jakeworth.com mail is handled by 0 smtp.secureserver.net.

More info: man host

UUIDs in Vim with Ruby/JavaScript 🆔

UUID’s (universally unique identifiers) are really handy. I use them for all sorts of things, like key props in a React map, and I like to have them easily accessible when writing code.

Today I wrote two Vim mappings to support this workflow. I can shell out to Ruby and use SecureRandom:

" Insert a UUID with Ruby
nnoremap ruid :read !ruby -e "require 'securerandom'; p SecureRandom.uuid"<cr>

Or, if you’re happier in the JavaScript ecosystem, here’s a similar command using Node and the uuid library. I did not have to install uuid, it was already available to me.

" Insert a UUID with JS
nnoremap juid :read !node -e "var uuid = require('uuid'); console.log(uuid.v4())"<cr>

Include vs. Includes 🤷‍♂️

A hallmark of switching back and forth between Ruby and JavaScript: I mistype the respective array inclusion function a lot. In JavaScript, it’s includes, and in Ruby, it’s include (with a question mark). Each language does not care what I meant.

The way I remember which function to use: in Ruby, I say: “does this array include this item?”. Then when I’m writing JavaScript, I remember I’m not writing Ruby. This technique is… lacking.

Chris Erin’s pneumonic is better: “JavaScript has an ‘s’ in it, so it includes. Ruby does not, so it is include.”

Heroku Psql Oneline 🐘

I cooked up this Heroku/subshell command today, and I like it:

$ psql $(heroku config:get DATABASE_URL)

This will connect me to the primary PostgreSQL database for my Heroku application in the psql client. Now I’m ready to query!

NOTE: why not $ heroku pg:psql? I’m not sure. I think Heroku was reporting status issues today, and I wanted to bypass any infrastructure I could.

Firefox Profiles for Work and Home 👤

I’m managing two Firefoxes on my laptop: one for work and one for after work. A feature that supports this well is Firefox profiles. Visit them in Firefox by typing about:profiles into the browser bar.

These work like Chrome People— separate sessions, histories, bookmarks, etc. I have styled the two browsers a little differently so I can quickly tell them apart.

I used to use Incognito/Private Windows for this setup, but those aren’t great for long-running browser sessions, because when you close or crash the browser, anything you’ve done in that browser is gone. Profiles give me the isolation I need with some persistence, too.

Perform on Zoom 🎸

Planning to use Zoom for something other than a meeting, like a reading or musical performance, that would benefit from room noise and a softer audio experience? If so, read on!

Zoom has several default audio features in place to make your business calls sound great. We don’t want those features in place in a performance setting. Jettison them by enabling ‘original sound’ under advanced audio settings:

image

All you need to do from here is turn on your best (quality and/or position) microphone option. For me, that’s my display audio.

h/t Suzanne Erin

Git Checkout in Patches

Something I’ve learned pairing with Chris Erin is to checkout code you don’t want in patches. Here’s the command:

$ git checkout --patch

Like the git add --patch command many developers know, this puts you an interactive workflow where you can decide how to handle each chunk, or patch, of your changes. It works opposite of git add --patch, in that y means check out the patch (abandon the changes), and n means keep the changes.

This is a great flow to go through before trying to commit code; use it to get rid of debugger statements, pseudocode, unwanted autoformatter changes, etc.

Toggle Dark Reader 🌓

I really love the Dark Reader Browser plugin (h/t Chris Erin). It turns most websites into a dark mode that is really easy on my eyes. However, some sites just don’t look right in dark mode. Luckily, the plugin can be toggled on and off with ALT + SHIFT + D on Firefox and Chrome. I use it a couple of times a day on websites I encounter on the internet.

Bonus: Here’s an example of this plugin in action, that is very meta.

image

Dark Reader

Git 101

There are lot of tutorials about Git. One that is built right into Git is the ‘everyday help’. Print this help with:

$ git help everyday

The output is a series of must-know commands for a variety of roles in a technical organization: individual developer (standalone), individual developer (participant), integrators, and admins.

Pick a lane and go! 🏁

Run Git Commands From Any Dir

Git has one feature that I find irksome; you have to be in the directory with the Git repository to run commands against it.

…Or do you?

Git provides the -C flag for this scenario. Follow it with a directory name, and Git will execute your command as if it was run from <path>.

$ git -C ~/tilex status
On branch master
Your branch is up to date with 'origin/master'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   lib/tilex_web/templates/layout/app.html.eex

no changes added to commit (use "git add" and/or "git commit -a")

Tmux Clear History

I’ve been doing an experiment lately that requires reading and searching lots of logs in Tmux. Something that makes this harder is that we collect a deep history there. Sometimes I’ll ‘find’ a query I’ve been looking for 😀, only to realize it is hours or days old ️😐.

Tmux clear-history has been our solution. Running this command on an already cleared Tmux pane clears your history for that pane; you can’t scroll up or search the previous output.

We’re doing this enough that I put this alias in our terminal dotfiles.

alias tc='clear; tmux clear-history; clear'

tmux clear-history is the CLI version of the Tmux meta command :tmux clear-history.

Vim Mark That Test! 🔖

This week Chris Erin taught me a technique that has changed my testing game: Vim mark your current Ruby test with mA.

When writing TDD-style code in a test-crazy language like Ruby, I tend to follow a predictable workflow: create a test, watch it fail, bounce around the code making changes, and run/edit the test again. This loop can repeat for hours on a complex feature.

There are many ways you could navigate back to your test from elsewhere; a very efficient method is to mark it in Vim with mA. Like any mark, you can return to it with `A. Why ‘A’? Capitalized marks are file marks and are valid between files. With this command, you can mindlessly jump back to your test from anywhere in the jumplist stack.

Git Diff Matches Paths 📁

Today I learned that the git-diff command accepts a <path> argument. I used this knowledge to construct a command that runs only the RSpec test files on my branch that differ from master.

(not-master)$ git diff master --name-only spec | xargs rspec

This is handy on a big test suite; when you can’t run every test, make sure you run the ones that you have changed.

See man git-diff for more info.

Mac Notes Default Text Size 🔎

I use Mac Notes a lot during pairing and brainstorming. It works, and it’s right there on the Mac!

One issue I’ve had is that the default text size on Mac Notes is unreadably small on a big monitor or iMac. I always end up creating a note, then bumping the text size with CMD-SHIFT ..

Of course, there’s a better way. Set the default font size in preferences.

image

Byline Class and Time Tag 📰

I’ve been hacking on TIL to optimize our site for Safari Reader mode. A lot of this is black box, because Apple doesn’t have easy-to-find documentation about how the feature works.

One thing that seems to matter is a class called byline for your author information, and an HTML tag time for the publication date. Here’s an example, borrowed from this site:

<p class="byline">
  <%= name %>
  <time datetime="<%= inserted_at %>">
    <%= inserted_at %>
  </time>
</p>

It gives us relevant reader information, shown here in Safari:

image

Here’s the PR:

https://github.com/hashrocket/tilex/pull/650

Meta Charset Top That! 🔝

When writing HTML, make sure that your meta charset tag is in the first 1024 bytes on the page.

Per MDN:

The <meta> element declaring the encoding must be inside the <head> element and within the first 1024 bytes of the HTML as some browsers only look at those bytes before choosing an encoding.

What does this mean practically? Keep this tag near the top of your document, and use a website validator like https://validator.w3.org to check your tag placement.

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta

Type "text/javascript" is Redundant

Have a script tag in your HTML annotated with <script type="text/javascript">? Per the HTML5 specification, the MIME type of a script tag, when omitted, is text/javascript. We are encouraged to omit it.

Delete that code and go green 💚.

Per MDN:

Omitted or a JavaScript MIME type: This indicates the script is JavaScript. The HTML5 specification urges authors to omit the attribute rather than provide a redundant MIME type. In earlier browsers, this identified the scripting language of the embedded or imported (via the src attribute) code. JavaScript MIME types are listed in the specification.

Source:

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script

Git Interactive Single Key 👇

Today I became familiar with the Git configuration interactive.singleKey. In the Hashrocket dotfiles this is enabled by default, and I’m not sure how common it is out in the wild. To quote the docs:

In interactive commands, allow the user to provide one-letter input with a single key (i.e., without hitting enter).

This allows git add --patch to be very powerful by enabling a quick vote up or down on a patch with a single keystroke.

Make sure you have the Perl module Term::ReadKey installed; it is a dependency.