Today I Learned

A Hashrocket project

342 posts by jakeworth @jwworth

Chrome DevTools Audit Panel

One highlight of the Chrome 63 update was the addition of four new audits to DevTools.

‘Audits’ are one of the many DevTools panels lurking in the background, waiting to make your application better; I hadn’t noticed them until today. They will analyze and provide a downloadable report on your application’s Progressiveness, performance, accessibility, and best practices.

‘Today I Learned’ scored 91 out of 100 on accessibilty. That’s something I’d like to improve, and this panel could help direct that journey.

Limiting Mock API Restarts with Rerun

On a recent project, we built a Sinatra mock API. A feature we added early on was hot code reloading via the rerun gem. Every time a file in the API changes, Sinatra automatically restarts.

It’s a nice system but not perfect, because the server restarts on changes to any file ending in .rb, .html, .md, and number of other extensions. This captures the README, integration tests, and other undesirables, slowing everything down for no particular reason.

rerun’s --dir flag scopes it to just files in the given directory. We chose the src/ directory, which includes the API, mock database, and helpers.

$ rerun --dir src "ruby src/mock_api.rb"

Import All Exports As Object

Here’s a technique for importing constants from a file:

import * as routes from './routes'

This wraps all the exports from routes.js in the object routes. We can access any of those constants like this:

<Route path={routes.exportedPath} />

I like this technique for this use case, because it keeps our import to one line and adds a meaningful namespace.

Vi + Imitation

It’s understood in the Vim community that the name ‘Vim’ stands for ‘Vi + Improved’, because this tool improves upon the classic Vi text editor.

Last night at the Vim Chicago Meetup, I learned that ‘Vim’ once stood for ‘Vi + Imitation.’ Bram Moolenaar, the creator of Vim, changed the name when the feature surpassed the tool it was originally built to imitate.

This was one of many facts I learned during from a fantastic lightning talk on the history of Vim. We recorded it and plan to post it online soon.

Page and Search Through MySQL

Need to explore results in the MySQL REPL? The pager command can help.

Let’s set our pager of choice (we’ll use Less):

mysql> pager less
PAGER set to 'less'

Then, execute the query:

mysql> select * from users;

The result will be loaded in the Less pager. From here, we can navigate or search through the results.

Leave the custom pager with \n:

mysql> \n
PAGER set to stdout

Toggle Mirror Display (OSX)

When using a separate display like a projector, I often switch between screen mirroring (my screen matches the secondary display screen) and not mirroring. Especially during a presentation that uses both slides and live-coding in the terminal.

Instead of navigating through ‘System Preferences’ > ‘Displays’ > ‘Arrangement’, and checking or unchecking the ‘Mirror Displays’ checkbox, I can toggle between the two with ⌘ + F1.

Slow Down, Sinatra

Right now we’re using Sinatra to mock an API. An important consideration for our frontend experience: what happens when the API takes a long time to respond? How do the pages look when they are waiting on a slow, or absent, server?

Sinatra’s support of before blocks allow us to gauge this:

before do
  sleep(3)
end

get 'some/endpoint' do
  200
end

get 'some/other/endpoint' do
  404
end

With this block, every mocked endpoint will wait three seconds before responding, giving us plenty of time to consider what, in development, would otherwise be an instantaneous delay.

Chrome Dev Tools Selection Variable

Highlight a few HTML elements in the Chrome Developer Tools Elements inspector, and you’ll have a traversable history. The selected element is stored in a variable called $0. We can manipulate it like so:

> $0.click();

Try this when the selected element is hidden or difficult to click. There are four more variables representing your most recently selected elements: $1, $2, $3, and $4.

h/t Josh Branchaud

Compare Form Values with Yup

We’ve been using yup to validate a JavaScript form, and found ourselves facing a common problem when a user signs up for a service:

How do we ensure a user’s email matches their email confirmation?

yup’s test function helped us find a solution. It’s documented like this:

mixed.test(name: string, message: string, test: function)

test takes a name, a message to show on failure, and a function that returns a boolean. We paired this with the email we get from our parent.

var schema = yup.object().shape({
  email: yup
    .string(),
  emailConfirmation: yup
    .string()
    .test('match', 
      'emails do not match', 
       function(emailConfirmation) { 
         return emailConfirmation === this.parent.email; 
       }),
}),

Vim Projectionist Default File of Type

When setting up vim-projectionist, we can add a directory and filetype like this:

{
  "src/components/*.js": {
    "command": "component"
  }
}

With this in place, :Ecomponent will tab-complete to any JavaScript file in src/components, and :Ecomponent navbar will jump straight to the navbar.js component.

Let’s add a second key that includes a hard-coded file name.

{
"src/components/*.js": {
    "command": "component"
  },
  "src/components/App.js": { "type": "component" }
}

This pair tells vim-projectionist to jump to App.js if no argument is provided to :Ecomponent.

Replace App.js with your root component, and you have a shortcut to the top of your component hierarchy.

Catchall in a React Router Switch

Today we built a 404 page for a React app using React Router, via a Switch statement with no specified path. Like a default clause, it catches if none of the other routes match:

<Switch>
  <Route path="/about" component={About}/>
  <Route component={NoMatch}/>
</Switch>

On any other path besides /about, we’ll render our NoMatch component.

Search Github Faster with Shortcuts

Last year, I wrote about Github repository shortcuts for code, issues, and pull requests.

Now Github has a projects tab on each repository. Ever the completist, here’s the shortcut for that tab: gb. Typing this on a Github repo’s page loads the projects tab.

Researching this led me to an even better shortcut, s. This is site-wide and it focuses the Github search bar.

Here’s the impressive full list of Github hotkeys.

Turn Off HTML5 Form Validations

HTML5 added a variety of input types such as date, email, and tel (telephone number). These make entering certain kinds of information easier by providing tools such as a datepickers, range sliders, and optimized keyboards on mobile devices.

These input types also introduce custom validations on some browsers, which are useful, but can potentially clash with your application’s look and feel.

To keep the input type, but disable the validations, add novalidate to your form tag:

<form novalidate />

h/t Dillon Hafer

docs

Install a Homebrew Formula at Master

We’ve been testing out the forthcoming Elixir 1.6 formatter on Tilex’s codebase, which requires a version of the langage that has not yet been officially released.

There’s a few ways to do this. Since Elixir is installed with Homebrew on my machine, here’s how to do it with Homebrew:

$ brew install elixir --HEAD

From the Homebrew man page:

If --HEAD is passed, and formula defines it, install the HEAD version, aka master, trunk, unstable.

Welcome to the bleeding edge!

h/t Brian Dunn

Clean Up Autojump

autojump is a command-line tool for faster directory changing. It’s a must-have on my workstation, because it lets me jump to deeply nested directories like this:

:~/$ j cli
/Users/jwworth/projects/2017/twitter-killer/client
:~/jwworth/projects/2017/twitter-killer/client$

There are two ways we can clean up autojump once it’s been running for a while. First, purge non-existant directories from the jump database:

$ j --purge
Purged 8 entries.

Second, edit the file ~/Library/autojump/autojump.txt (OSX), which stores the jump database. Here you can remove directories that should never be jumped to, or are weighted too highly because of frequent use in the past.

Happy jumping!

Tidy your Reducers with `combineReducers()`

Today I learned by necessity the value of the Redux combineReducers(reducers) function.

combineReducers() supports, in a pretty neat way, the crucial Redux task of delegating to reducing functions their own slice of the state.

The documentation example looks like this:

combineReducers({ todos: myTodosReducer, counter: myCounterReducer });

Which we can improve by naming the reducer functions after the state slices they manage, allowing ES6 shorthand notation:

combineReducers({ counter, todos });

This creates a state object like so:

{
  counter: ...,
  todos: ...,
}

Print Information about an Elixir Data Type

IEx ships with a neat feature, def i(term \\ v(-1)), which provides information about an argument. Here are two examples:

iex(1)> i ["one", "two"]
Term
  ["one", "two"]
Data type
  List
Reference modules
  List
Implemented protocols
  IEx.Info, Collectable, Enumerable, Inspect, List.Chars, String.Chars
iex(1)> i "three"
Term
  "three"
Data type
  BitString
Byte size
  5
Description
  This is a string: a UTF-8 encoded binary. It's printed surrounded by
  "double quotes" because all UTF-8 encoded codepoints in it are printable.
Raw representation
  <<116, 104, 114, 101, 101>>
Reference modules
  String, :binary
Implemented protocols
  IEx.Info, Collectable, Inspect, List.Chars, String.Chars

Use this to inspect an item, or learn more about Elixir.

Environmental Variables and Chaining with Postman

Postman is a tool for building APIs. We’ve been digging into it today; it’s got some great features.

Today I learned we can chain requests, passing the result from one API interaction to all subsequent interactions.

Let’s say one API call gets a token on success, a token that all other calls require. When we run the first request, we can add a test that pulls out and sets the token:

var data = JSON.parse(responseBody);
postman.setEnvironmentVariable("token", data.token);

Now, other tests can reference {{token}} in their headers. We can even chain calls in Postman’s automated test runner, ensuring that the token-getting request always runs first.

more info

Exit IEx Gracefully with `respawn()`

I love a debugger in my Elixir code. A pattern I follow is to load and call IEx in a Phoenix template or controller with:

require IEx; IEx.pry;

Then, I call functions and check data in the middle of an action, by starting my Phoenix server with the following command:

$ iex -S mix phx.server

Once finished, I usually end up just killing the server with CTRL-C.

Today I learned there’s a better way: respawn().

respawn() respawns the current shell by starting a new shell process. Which I think is a good thing. It lets me back out of my IEx session without killing my server, a much more graceful development experience.

Hub CI Status

hub is a command-line client for Github. It lets you manage pull requests, forks, issues, and more from the command line. I regularly find new ways to integrate it into my open-source gardening.

Today I learned hub can report on your CI integration. We recently switched TIL to Circle CI, are iterating toward a stable test build, so CI status is important and not always predictable.

I check the status of a commit with the following command:

$ hub ci-status 7aa1316fe8665ef8cab5dd10cc80da024625ba20
success
$ hub ci-status HEAD
failure

List Commits That Change a File

Today I’m wrapping a PR with a large Git rebase. There are many commits on my branch that change the same file (.circleci/config.yml) and aren’t valuable on their own. In the end, I want them all squashed into a single commit. The challenge is that I changed other files in between; it’s kind of a mess. How can I squash the branch down to something manageable?

One technique is to view just changes to my file:

$ git log --follow --oneline .circleci/config.yml

c9f7108 Try to decode file before unzipping
87c8092 Quick push
327d419 Try this!

Using this list, I can execute a rebase that just squashes the commits that touch the file, leaving everything else intact.

Visualize Your Elixir Dependencies

To visualize your Elixir dependencies, try this:

$ mix deps.tree

This prints a tree showing your dependencies (and their dependencies):

$ mix deps.tree
tilex
├── gettext ~> 0.13 (Hex package)
├── hackney 1.8.0 (Hex package)
│   ├── certifi 1.1.0 (Hex package)
│   ├── idna 4.0.0 (Hex package)
│   ├── metrics 1.0.1 (Hex package)
│   ├── mimerl 1.0.2 (Hex package)
│   └── ssl_verify_fun 1.1.1 (Hex package)

This is really handy when trying to track down where a deprecation warning or error is coming from.

h/t Dorian Karter

Conditional Variables in Phoenix Templates

A common Ruby on Rails technique is setting instance variables in a controller action, then using them in the view layer:

# app/controllers/users_controller.rb
def show
  @show_button = true
end
# app/views/users/show.html.haml
- if @show_button
  .button

Doing the same thing in Elixir/Phoenix is a little different.

Since Phoenix 0.14.0, the framework raises on missing assigns (link). Thus our conditional will fail on any loaded template whose controller function that does not define the variable.

One solution is to check if the variable is assigned:

# lib/my_app_web/templates/users/show.html.eex
<%= if assigns[:show_button] do %>
  <div class="button"></div>

If show_button is assigned in your controller function (via assign), the button will be displayed. If not, the button will not be displayed, and the application will not raise an error.

Rails Ignore Pending Migrations

Ruby on Rails gives us a nice warning in development when we haven’t run a pending database migration. But what if we’re iterating on a migration, and the results can best be viewed in the browser? We might want to temporarily disable this warning.

Here’s how to do it:

# config/environments/development.rb
config.active_record.migration_error = false

Don’t forget to turn it back on when you’re finished.

Better Rails SQL Migrations

Some people on our team, including me, write raw SQL in Ruby on Rails migrations. But they can get unwieldy when iterating on a complex migration that does multiple things.

Mitigate this is to break up your statements into separate HERDOCs, like so:

def up
  execute <<-SQL
    update pixaxes set metal = 'diamond' where metal = 'iron';
    -- many things...
  SQL

  execute <<-SQL
    update swords set metal = 'diamond' where metal = 'iron';
    -- many more things...
  SQL
end

If the migration fails, we’ll get an error pointing to the specific problematic HEREDOC, instead of essentially ‘the entire statement is invalid’. You then put a debugger between any HEREDOC to iterate on the issue.

h/t Jack Christensen

Elixir Static Code Analysis in Vim

Today I learned how to set up Credo, a static analysis tool for Elixir, to run on every Vim buffer write, using Neomake.

To start, I added Credo to my project:

# mix.exs
defp deps do
  {:credo, "~> 0.8", only: [:dev, :test], runtime: false}
end

Including it with:

$ mix deps.get

Next, I loaded and sourced the Neomake plugin with Pathogen:

" ~/.vimbundle
neomake/neomake

Next, I told Neomake to run on every file, enabling Credo for Elixir files:

" ~/.vimrc
let g:neomake_elixir_enabled_makers = ['credo']
autocmd! BufWritePost * Neomake

Now I have Credo style recommendations right in my text editor.

Complete a Whole Line in Vim

This week I picked up an excellent Vim command: CTRL-X CTRL-L. This command searches backwards through your project and inserts a matching line after the cursor.

So, if there’s a line in your project like this:

defimpl Phoenix.Param, for: Tilex.Developer do

And I type defimpl (which is unique enough to match just a few lines of code in my project), Vim will suggest matching options, letting me choose a match to complete it:

defimpl Phoenix.Param, for: Tilex.Developer do
defimpl Phoenix.Param, for: Tilex.Developer do

This is useful when writing code in a framework like React.js, where the head of many files often includes a group of repetitive import statements.

See ‘Insert mode completion’ inside insert.txt in the Vim help for more information.

h/t Dorian Karter

Screengrab to Clipboard on Mac

If you’ve ever taken a screengrab on a Mac with CMD + SHIFT + 4, then pasted or dragged that image into a text area such as a Github issue description, there is a better way: CMD + CTRL + SHIFT + 4. This saves your screengrab right to the clipboard, ready to paste wherever.

The same command with 3– take a screenshot instead of screengrab– also works as expected, sending the data to your clipboard.

While not a particularly ergonomic key combination, this helps me add visuals to bug reports and feature requests.

h/t Dorian Karter

List Merged Branches

Today I learned a new Git trick: to show branches already merged into a branch, try this command:

$ git branch --merged master
  add-basic-auth
  add-channels
  add-developer-username
  add-developers
  add-developers-show
  add-hashtag-to-slack-post

For an open source project like Today I Learned, this is an interesting way to get a sense of the project.

Authenticate With Username or Email

Today I learned a way to implement a login form that accepts email or username as the login. I’ve been on the other side of a form like this many times, but had never written one myself.

Here’s one solution, with ActiveRecord:

User.where('username = ? or email = ?', "jwworth", "jake@example.com")

title or slug are represented by the same parameter, and either can be nil.

login = params.fetch('username_or_email')
User.where('username = ? or email = ?', login, login)

Allow an Empty Commit

Today my pair did something I’d never seen: create an empty commit. Out goal was to test a third-party integration, but we didn’t have a meaningful change to contribute at the time. In this situation, I think an empty commit is a good compromise, because it’s honest about our intent— to simply kick off a remote process.

Here was the command:

$ git commit --allow-empty

h/t Dorian Karter

Fork A Heroku Project

The Heroku CLI has a useful command I recently learned about, called heroku fork. Here’s how it works:

$ heroku fork --from tilex-staging --to tilex

As the example suggests, I’ve used this tool to clone a tricky-to-set-up Heroku staging application as a production application. It’s great.

The bad news is that Heroku us sunsetting fork as a core CLI command. Use it while you can. After that, you can fork the Github repo and use it as CLI plugin.

Refresh A Twitter Summary Card Image

Twitter provides a feature called summary card images: if you’ve ever seen a tweet with a rectangular image included, that’s it. We can specify this image via HTML meta tags. Most tweets from the @hashrocketil follow this pattern.

Changing the image is tricky, however, because Twitter caches summary cards for an unknown amount of time (I’ve read one week). Which means past and future Tweets could include an outdated image for a while.

One solution is to use Twitter’s card validator on your site. Running the site it through the validator seems to refresh the cache for your summary cards.

Mass-Delete Git Tags

Building off this post:

I’m an advocate of Semantic Version tagging. It communicates to a team about every deploy and makes that rare rollback easier. So when does it not make sense to use a tag?

When you’re the only developer (nobody to communicate with except yourself), and also using a platform like Heroku that tags every release (your tags are redundant). This the case with my blog, so today I set out to delete all my Git tags.

First, delete them remotely (assuming a remote named origin):

$ git tag | xargs git push --delete origin

We also have to delete our local tags, or a tag push with create them again on the remote:

$ git tag | xargs git tag -d

$ git tag now returns nothing, and there are no remote tags.

Netrw Special Command

Building off this previous post, today I learned a new command in Netrw: the ‘special command’.

When navigating, enter x over any file, and your operating system will open it with its tool of choice (Preview for images and Finder for directories on a Mac, etc.). This is great for exploring a directory.

From the Netrw help:

Certain files, such as html, gif, jpeg, (word/office) doc, etc, files, are
best seen with a special handler (ie. a tool provided with your computer's
operating system).  Netrw allows one to invoke such special handlers by:

        * when Exploring, hit the "x" key
        * when editing, hit gx with the cursor atop the special filename
          (latter not available if the g:netrw_nogx variable exists)

Send SQL to a Tmux Window

Hashrocket.vim provides a mapping that is awesome:

autocmd FileType sql nmap <buffer> <leader>t :<C-U>w \| call Send_to_Tmux("\\i ".expand("%")."\n")<CR>

With this command, if you’re editing an SQL file in a Tmux session, run <leader>t from normal mode, and your file will be read into the session and window of your choice. If there’s a psql session listening there, you’ve got a fast way to iterate on an SQL statement from Vim.

The command even writes the file for you before sending the SQL.

When Was This File Added to Version Control?

I learned a helpful Git command today. To determine when a file was added to version control, run the following:

$ git log --follow --diff-filter=A <filename>

This returns the Git history, following files through renames, filtering on when a file was added to version control. Here’s the output for the README of ‘Today I Learned’:

$ git log --follow --diff-filter=A README.md
commit 9a7984a48db19489bb4113378298ddaa97121c7a
Author: Jake Worth <dev+jwworth@hashrocket.com>
Date:   Sat Mar 28 12:52:19 2015 -0400

    Add a basic README

Useful for explaining mystery files in the repository 🔎.