intermediate_ruby     about     articles

Jekyll Bug Fix with Matt Series Index

Part 2 Table of Contents

This is the third part of a short series on pairing with a super-experienced software developer to fix an open-source issue in Jekyll.

In the last post, Matt explained how he identified this particular issue for us to work on.

This series (and more series in the future) will constantly attempt to surface the tacit knowledge that experienced developers use to do their work.

How to read this particular post #

Remember, the goal of this entire series is for you to do the exact same things an expert does.

How to follow along with us #

To follow along, in your local environment, you’ll need to clone down the repo, and check out a commit from before our fix gets merged.

Since you’re not necessarily making your own PR, you don’t have to fork it to your own repo, you can just clone it. Here’s how to set it up:

// get the repo
$ git clone

// now check out from the same commit Matt and I were working with:
$ git checkout 8403184b 

Now you’ve got the codebase in the same place we had it in!

Open up the Contribution Guidelines and work through the video with us! The Jekyll docs talk about the various scripts we used here

Video Walkthrough #

Video Timestamps #

  • 0:00 Talking about what setup Matt has done (almost none!)
  • 0:40 Jekyll contribution docs:
  • 0:48 Looking for CONTRIBUTING.markdown in project
  • 1:15 Running tests locally, running scripts (we start with script/bootstrap)
  • 1:35 exploring script directory, running recommended scripts
  • 2:00 how to execute scripts in the shell
  • 2:45 Looking at GH Issue for clue of what file to start with
  • 3:05 #1 keyboard shortcut to know: Fuzzy-finder/go-to-file
  • 3:30 “run tests for current file” - I’ve never used this extension, but I’ve also never used .NET or Java.
  • 4:40 installing all the gems takes FOREVER
  • 4:53 Matt does some amazing keyboard work to do something specific, quickly.
  • 5:32 reading the method in question, starting to figure out what it does, what jumps out at Matt
  • 6:36 quick select-find-jump usage to jump around file
  • 8:15 the bootstrap script is finished, finally!
  • 9:00 still exploring relationship between Utils#slugify and Utils#replace_character_sequence_with_hyphen
  • 10:00 “we’re getting warmer” with finding what to pay attention to, what to ignore
  • 11:20 explaining what I18n means, and a16z, not mentioned but commonly seen: a11y => “accessibility”
  • 12:40 Matt supposing that #slugify probably changes a lot. It’s “a hotspot”.
  • 13:40 Matt searches for slugify, then .slugify.
  • 15:38 Running ./script/cibuild, 2nd script recommended in contribution guidelines. (because the first script finally finished)
  • 16:30 Matt explains how he found the file to add the test too
  • 18:29 splitting tabs, test on one side, lib on the other. (SEE NOTES FOR FURTHER THOUGHTS ON SPLITTING PANES)
  • 19:40 Matt mentions that this repo is in his /junk folder 😂
  • 20:10 Checking out a new branch! 🙌
  • 20:23 Odd issue where git was picking up test artifacts. Must have been a temporary file.
  • 21:27 Figuring out how to run an individual test file
  • 21:57 What test framework ARE we using? Looking at script/test
  • 22:53 Running just the test_utils.rb file.
  • 23:40 Talking about test output, how overwhelming this all is!
  • 24:04 What is the “options –seed” thing?
  • 25:51 Expounding on test coverage, timing, understanding the “time” output (real vs. user vs. system)
  • 26:50 “the only thing that is of minor use to use… is the test coverage percentage”
  • 28:55 Figuring out WHERE to put our new test.
  • 30:16 Narrowing down to the “#slugify” context block
  • 31:10 Starting to actually add lines of code. 👩‍💻
  • 31:33 copying from the test below to get our basic test
  • 31:48 copying expected/actual values from @deepestblue’s issue (thanks again, @deepestblue, for such a good bug report)
  • 32:44 running the file again, this time expecting a failure. And getting it! 🎉🎊🎉🎊

Expanding on things that came up in the video: #

Running scripts per the contribution guidelines #

The Jekyll Contribution Guidelines specifies running a certain script (script/boostrap) to kick off all the tests.

This means there’s a directory of scripts (appropriately lableled script, which presumably has many scripts, but we care about only one of them. boostrap)

To execute a script, you have to prepend it with ./. This will tell your operating system that you do indeed intend on running the given script.

So, Matt runs the script with:

$ ./script/boostrap

and that runs under the hood something like:

bundle install

While it installs, Matt and I talk about a next iteration of this project that might involve work on It’s more of an application than a library (Jekyll is a library) so it might be a bit more relevant to the day-to-day of the normal software developer.

Shipping a library for your day job is different than working on an application.

As I’ve mentioned, one of the goals of this project is to find instances where the expert uses Tacit Knowledge. I’ll use this section to bring attention to as much of Matt’s tacit knowledge as possible.

Top keyboard shortcut for Atom/VS Code #

Matt says “the top two shortcuts…”

  1. fuzzy finder (Atom, VS Code)
  2. run test file for current file (Josh needs to find this, requires a plugin)

For “run tests for current file” I usually want to look at the test file before running it, so my workflow is:

  1. use fuzzy finder to open up the desired test file
  2. Use keyboard shortcut to copy the relative path of the test file to my clipboard. Atom: shift+ctrl+c
  3. Run the test file in whatever method the project requires: ruby <file>, bundle exec ruby -Itest <file>, ./test <file>, etc.

copy-find-paste-enter keyboard shortcuts #

keyboard shortcuts! Matt uses this one all the time, and if you’re not using this keyboard shortcut, might be time to start.

This file we’re looking at is 350+ lines long. Scrolling up and down is a waste of time.

Here’s what he does:

  1. Double-click the method name or constant he wants to jump to.
  2. hit ⌘+c to copy it to his clipboard
  3. hit ⌘+f to open the find in current file tool.
  4. Hit ⌘+v to paste the clipboard contents into the search box
  5. hit return on his keyboard to jump to the top result. Hitting enter repeatedly cycles through all the instances of the string in the file.

This isn’t just fast, but allows him to not waste thought trying to find bits of code, or scroll around. He doesn’t care where in the file a constant or method is defined, just wants to look at it.

Please add this general process to your own workflow, if it’s not already there.

Note - When you’re staying inside the editor, at least for Atom, I can double-click any text, and when I hit ⌘+f Atom inserts the selected string in the search box. This saves me a copy/paste.

Jargon: I18N (internationalization) #

i18n, a16z, a11y are all phrases you might have come accros in the industry.

  • i18n=> internationalization (there are 18 letters between the i and the n)
  • a16z=> AndreessenHorowitz (there are 16 letters between the a and the z)
  • a11y=> accessibility (there are 11 letters between the a and the y)

Running another script (cibuild) #

Runs rubocop, the unit tests.

The Jekyll team has confidence in the build setup, so we run the tests to make sure we’re starting in a clean state.

Splitting panes horizontally vs. vertically #

Add screenshots here, mention being able to see lots of test output at the same time

Matt says

Usually I split my panes vertically…

Here’s why. Look at the line counts:

so much text

With the keyboard shortcut of ⌘+\, you can toggle the visibility of the sidebar effortlessly.

visible sidebar

If instead we split the screens horizontally, here’s what we’d get:

horizontal split

Matt splits the panes horizontally, since he’s running his fonts unsually large so they come through better in the recording.

How Matt decided which file to add the failing test to #

Searching for slugify vs. .slugify

Ah, the file name convention is different from what I expected.

I expected {class_under_test}_test.rb, but it’s actually test_{class_under_test}.rb

Try this yourself, in your editor of choice. Do you see the difference in results?

Keybindings #

Matt has keyboard shortcuts set up for his commonly used applications.

I noticed that I don’t think he used alt-tab once.

I’ve got keyboard shortcuts set up for Atom, Firefox, iTerm, and a few other tools. I hardly ever use alt+tab on my laptop, and it feels like this saves time and effort.

I’m all for copying what experts do, might be worth setting something similar up on your own machine.

I’ve written extensively about exactly how I have my “environment” set up here

Writing the first test #

At about an hour in, we’ve written three lines of code:

# test/test_utils.rb:140
it 'should not break certain tamil characters' do
  assert_equal "மல்லிப்பூ-வகைகள்", Utils.slugify("மல்லிப்பூ வகைகள்")

Checks for Understanding #

  1. When prepping to do open-source work, should you fork the repo before cloning it?
  2. What script should we run that, according to the Jekyll docs, makes sure the project is set up and running correctly?
  3. How do you run a script? What directory would we expect scripts to be in?
  4. Why would you run a script?
  5. What 2 things does ./script/bootstrap do?
  6. What’s the keyboard shortcut for opening go-to-file/fuzzy-finder for your editor?
  7. What script would we use to make sure the repo is in good shape to work with? Hint: CircleCI runs against every new PR. What does this script do?
  8. What script do you use to run tests?
  9. How would you find every spot that slugify is mentioned? How about every time the method is called?
  10. What does the test_utils script do?
  11. What are the implications of Jekyll’s test coverage? (It’s 64%).
  12. How would we run tests for just the lib/jekyll/utils.rb file?
  13. When you add the first test, what should the assert_equals arguments be? (Hint: they come from the Jekyll issue report)

Next, jump over to part 3.

But before you go, why not subscribe to get updates when more guides in this series are done, as well as when future guides go up?