<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://bridgetownrb.com/" version="2.1.2">Bridgetown</generator><link href="https://eliseshaffer.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://eliseshaffer.com/" rel="alternate" type="text/html" /><updated>2026-08-10T00:01:06+00:00</updated><id>https://eliseshaffer.com/feed.xml</id><title type="html">Elise Shaffer</title><author><name>Elise Shaffer</name></author><entry><title type="html">I Don’t Like Shoulda Matchers</title><link href="https://eliseshaffer.com/2024/01/29/i-dont-like-shoulda-matchers/" rel="alternate" type="text/html" title="I Don&apos;t Like Shoulda Matchers" /><published>2024-01-29T00:00:00+00:00</published><updated>2024-01-29T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2024-01-29-i-dont-like-shoulda-matchers.md</id><content type="html" xml:base="https://eliseshaffer.com/2024/01/29/i-dont-like-shoulda-matchers/">&lt;p&gt;There’s a lot of testing tools for Ruby on Rails. Ruby started life with a strong testing culture. The ecosystem is brimming with tools. But not all of those tools spark joy. I love a lot of them. I’ve written about my &lt;a href=&quot;/2023/08/08/i-miss-cucumber/&quot;&gt;nostalgia for Cucumber&lt;/a&gt;. But one tool that always makes me feel weird is Shoulda matchers.&lt;/p&gt;

&lt;p&gt;Shoulda matchers are a tool written by thoughtbot that gives you one line tests for various Rails features:&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MenuItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: :model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;associations&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;belong_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;MenuCategory&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;validations&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;validate_presence_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;validate_uniqueness_of&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scoped_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:category_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This can seem like a great idea, but I can’t help feel that this style of testing breaks the boundary for Rails. The example above tests that the MenuItem model has particular associations and validations. I firmly believe that tests should act as a collaborator with the code under test. None of the collaborating modules or classes cares that a &lt;code class=&quot;highlighter-rouge&quot;&gt;MenuItem&lt;/code&gt;  &lt;code class=&quot;highlighter-rouge&quot;&gt;belongs_to&lt;/code&gt; a category. The collaborator cares that when it calls &lt;code class=&quot;highlighter-rouge&quot;&gt;menu_item.category&lt;/code&gt; it gets the appropriate &lt;code class=&quot;highlighter-rouge&quot;&gt;MenuCategory&lt;/code&gt; record back.&lt;/p&gt;

&lt;p&gt;This kind of test isn’t acting like a collaborator. It’s acting like a developer.  A better test would be some thing like this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MenuItem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: :model&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;#category&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;returns a category record&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;menu_item&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menu_items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:split_pea&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;menu_categories&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:soup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;menu_item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;category&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;category&lt;/span&gt;  
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This example uses fixtures, but you could imagine using FactoryBot as well. This test is longer. But, it’s much more specific and tests the expected return value of the association.&lt;/p&gt;

&lt;p&gt;It could be more acceptable to use some of the controller matchers, but even there I would choose to write more coarse tests that act like a user. For example, the &lt;code class=&quot;highlighter-rouge&quot;&gt;set_flash&lt;/code&gt; matcher will check that the flash contains a particular message. But, from the customer perspective that doesn’t matter. What matters is that the flash is rendered on the page and is visible.&lt;/p&gt;

&lt;p&gt;Both of these examples feel a bit too clever to me. That’s how all of the shoulda matchers feel.&lt;/p&gt;

&lt;p&gt;Write tests that act like real collaborators. Make them use the same methods a real collaborator would and assert on the return value. For your models, call the association the way you would in a controller. For your views, assert that the proper text is rendered in a response.  It will give you a real test of what the code is supposed to do.&lt;/p&gt;

&lt;p&gt;Do you use shoulda matchers? &lt;a href=&quot;mailto:elise.shaffer@hey.com&quot;&gt;Send me a email&lt;/a&gt; with your thoughts.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">There&apos;s a lot of testing tools for Ruby on Rails. Ruby started life with a strong testing culture. The ecosystem is brimming with tools. But not all of those tools spark joy. I love a lot of them. I&apos;ve written about my nostalgia for Cucumber. But one tool that always make me feel weird is Shoulda matchers.</summary></entry><entry><title type="html">Why I Write My Tests First</title><link href="https://eliseshaffer.com/2024/01/22/why-i-write-my-tests-first/" rel="alternate" type="text/html" title="Why I Write My Tests First" /><published>2024-01-22T00:00:00+00:00</published><updated>2024-01-22T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2024-01-22-why-i-write-my-tests-first.md</id><content type="html" xml:base="https://eliseshaffer.com/2024/01/22/why-i-write-my-tests-first/">&lt;p&gt;I am a pretty outspoken Test Driven Development advocate. I’ve recently appeared on a few podcasts talking about how I love TDD and why I think it’s the best way to write software. Test driven development advocates not only believe that automated software testing is necessary, they believe that the best way to develop software is to &lt;em&gt;start&lt;/em&gt; with the tests. When I advocate test driven development, I sometimes get some understandable pushback. When you are new to testing, it can be hard to imagine how you &lt;em&gt;could&lt;/em&gt; start with the tests. But, after some practice, it becomes second nature and you reap huge benefits.&lt;/p&gt;

&lt;p&gt;I follow the test driven development workflow most of the time. The workflow goes like this: you write a failing test that should pass when you’ve completed work, then you run the test to see that it fails. After you see the failure, you write &lt;strong&gt;&lt;em&gt;only the code that will fix the current failure or error.&lt;/em&gt;&lt;/strong&gt; This is important. You aren’t writing all the code to pass the test. You’re writing only the code that moves you past the current error message. You repeat this step, working from error to error, until the test passes. Then with working code and a test for safety, you refactor and clean up the code while making sure the test still passes.&lt;/p&gt;

&lt;p&gt;This approach grants me so many advantages.&lt;/p&gt;

&lt;p&gt;First, it ensures that my tests fail for the correct reasons. Sometimes a test could pass even if the code doesn’t work. When this happens, I start to lose trust in the tests. If I write the test first, I see it fail appropriately. The process of TDD helps me gain confidence that the tests will catch me if I break something in the future. This is one of the biggest strengths of TDD and a big factor in why I love it so much.&lt;/p&gt;

&lt;p&gt;Second, test driven development makes sure that every line of code has a specific purpose. Because I’m only writing the code that I need to move past the current error, each line of code has earned its place. I know that everything in the codebase is necessary. I think many of us agree that less code is better. There’s tons of memes about how satisfying it is to delete code. TDD lets me know that all that code has a purpose.&lt;/p&gt;

&lt;p&gt;The confidence means I can move more quickly. Because I know all the code is necessary and the tests fail appropriately, I can develop way more quickly. One of the biggest problems with big complex codebases is the need to hold the whole system in your head. When I know that I have comprehensive test coverage and I trust those tests, I can offload some of that mental work to the computer. I can start programming the software necessary for the current ticket. If I break anything, the test’s I’ve written in the past will catch the breakage and surface it to me.&lt;/p&gt;

&lt;p&gt;A problem arises if I don’t have enough tests to be able to do that. If only some cases are covered, then even with the tests, I need to think about all the edges and collaborations happening in the codebase. I almost dislike this more than having no tests. Either I don’t trust the tests and do all the mental work anyway. Or I do trust the tests and get burned by a testing gap.&lt;/p&gt;

&lt;p&gt;Test driven development also helps guide my software design. Because the tests are written first, I can think about what the hypothetical API of the thing I’m building should be. In the end, I will end up with an API that makes more sense to the collaborate because I have lived in the  shoes of the collaborator. The test itself is a collaborator.&lt;/p&gt;

&lt;p&gt;That might be controversial. I know some people think that TDD actually damages the design of software. I strongly disagree. While TDD is not a panacea for poor code, it encourages writing good code. The best code bases I’ve worked in have been the ones where the team practiced test driven development. The worst have been the ones with tests that were written after the fact, in unreliable ways that damaged trust in them.&lt;/p&gt;

&lt;p&gt;Test driven development leads to better on call shifts. When I write the test first, I know that I’ve covered all of the important code paths. This doesn’t mean that I’ll never have errors. But, I know that the things I care about work. Errors that do crop up will most likely not be catastrophic. This lessens the on call burden and reduces stress for the team.&lt;/p&gt;

&lt;p&gt;It helps me think about the boundaries of the problem. The discreet steps of TDD have conditioned my brain to be a little modal. When I’m in testing mode, I think about what the software has to do. While I work on writing one test, I might have a thought or insight about another test case. So I write that test. Or maybe I add an empty test that covers that case. In RSpec, skipped tests print a warning when you run the tests. I get a great reminder of the cases that I care about.&lt;/p&gt;

&lt;p&gt;Test driven development is a huge part of my workflow. It has so many benefits. I tried to talk about the ones I find most useful. But, there are others. For example, TDD is the easiest way I’ve found to enter a flow state while coding. I really take a lot of pride from test driven development. It helps me write better code, more quickly, and with less stress.&lt;/p&gt;

&lt;p&gt;Do you use test driven development? &lt;a href=&quot;mailto:elise.shaffer@hey.com&quot;&gt;Send me an email&lt;/a&gt; and tell me your test driven development experiences.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">I am a pretty outspoken Test Driven Development advocate. I&apos;ve recently appeared on a few podcasts talking about how I love TDD and why I think it&apos;s the best way to write software. Test driven development advocates not only believe that automated software testing is necessary, they believe that the best way to develop software is to start with the tests.</summary></entry><entry><title type="html">On Code Quality</title><link href="https://eliseshaffer.com/2024/01/15/on-code-quality/" rel="alternate" type="text/html" title="On Code Quality" /><published>2024-01-15T00:00:00+00:00</published><updated>2024-01-15T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2024-01-15-on-code-quality.md</id><content type="html" xml:base="https://eliseshaffer.com/2024/01/15/on-code-quality/">&lt;p&gt;There’s a quote that’s been nagging at me for the last month. I recently watched a talk from Allen Holub. In it, he says, “You can’t be agile when you’re fighting your code.” That line has been stuck on repeat inside my brain ever since.&lt;/p&gt;

&lt;p&gt;I’ve worked at many companies in my fourteen years of being a software engineer. I’ve seen quite a few codebases. Some of them were really easy to work in and others were quite challenging. The easiest codebases to work in were the ones that were well factored, using consistent patterns, with clear responsibilities and architectures, and comprehensive testing. The ones that were difficult to work in were the ones with tightly coupled code, models that made excessive use of callbacks, and dozens of layers of indirection with no testing or testing that was unreliable.&lt;/p&gt;

&lt;p&gt;Good quality code allows you to move so quickly. It’s easy to change, extend, and refactor. You can look at its structure and syntax and easily understand it. Poor code quality is complicated. It’s a tangled mess of interlocking method calls, objects, and  concepts. It’s hard to read and reason about. Moreover, it’s probably untested because poorly written code is hard to test (This is one of the reasons that TDD advocates want to write the test first), making it less reliable.&lt;/p&gt;

&lt;p&gt;Poorly written code makes programmers anxious and leads to longer development times. When you have a bug, it will be more difficult to find and fix. When a new feature is requested, it will be more difficult to integrate with the poor codebase. When something goes wrong, it will be more stressful on the team. So why do we let our codebases get so &lt;strong&gt;&lt;em&gt;bad?&lt;/em&gt;&lt;/strong&gt; Why do we write poor quality code?&lt;/p&gt;

&lt;p&gt;In my experience, it has many causes(most things do). Teams are under a lot of pressure. Tight deadlines lead to cut corners. Poor code leads to more poor code. If you don’t have time to clean up the existing code, it’s hard to write good new code that interacts with it. Micromanagement can hurt your motivation. If you aren’t allowed to clean things up, or if you get significant pushback when you do, then you’re less incentivized to write good code. Poor test coverage increases this problem. Tests are a safety net. If you aren’t automating them, then that creates a larger manual testing burden when you need to refactor or clean code up. A lower appetite for experimentation means that if the first thing you try solves the problem, but in a clunky way, you’re stuck with it.&lt;/p&gt;

&lt;p&gt;All of these issues impede our ability to write good quality code.&lt;/p&gt;

&lt;p&gt;Well written code is a superpower. Code that is well factored has so many advantages. It reduces your stress. It makes your software predictable. You’re less likely to have unforeseen errors. When you do, they’ll likely be easy to fix. On call shifts and incidents will be less frequent and easier to manage when they do emerge. New features are easier and faster to develop.&lt;/p&gt;

&lt;p&gt;A venture capital consultant once told me that code quality didn’t matter because you could always pay someone to deal with it. Or, you’d sell your company and it wouldn’t be your problem anymore. That felt so short sighted to me. What if you didn’t sell your company? What if the quality problems led to so many defects thats customer left before anyone was willing to buy your company?&lt;/p&gt;

&lt;p&gt;It’s tempting to just push something out as fast as possible without regard to code quality. It’s tempting to think that it’s removed from the customer. Or that it doesn’t matter. Or that it will be someone else’s problem. But everything the customer experiences is downstream from how well we write code. We should take that seriously. In this way, writing code well is a customer concern.&lt;/p&gt;

&lt;p&gt;As programmers we have to stand up for our craft. We need to make code quality a priority. We need to push back against the idea that code quality doesn’t matter. We need to stop cutting corners and mend the corners we’ve already cut. If we can’t move the quality needle in our current teams, we need to find teams where we can.&lt;/p&gt;

&lt;p&gt;Well written code will make you love your job. Poorly written code will make you hate it.&lt;/p&gt;

&lt;p&gt;I want to always get better at software development. I want the code I write today to be better than the code I wrote yesterday and tomorrow’s code to better than today’s. Well written code helps me get better. When I was a child, I did martial arts. My instructor had a saying, “Practice doesn’t make perfect. Perfect practice makes perfect.” There’s no such thing as perfect software, but that doesn’t mean we should stop caring about doing the best work we can. When code is well written, we all get better. It frees our minds from stress and lets us experiment more on solutions. That makes us better developers.&lt;/p&gt;

&lt;p&gt;If I can’t write good code, either because it’s hard within the current codebase, or because I’m not given the time or freedom, I am not getting better at my craft, I’m becoming stagnant.&lt;/p&gt;

&lt;p&gt;Code quality is one of my strong values. Well written code sparks joy, reduces stress, and improves productivity. Allen Holub made a quippy remark about code quality. And we should all take it to heart.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">There&apos;s a quote that&apos;s been nagging at me for the last month. I recently watched a talk from Allen Holub. In it he says, &quot;You can&apos;t be agile when you&apos;re fighting your code.&quot; That line has been stuck on repeat inside my brain ever since.</summary></entry><entry><title type="html">I Love Ruby</title><link href="https://eliseshaffer.com/2023/12/18/i-love-ruby/" rel="alternate" type="text/html" title="I Love Ruby" /><published>2023-12-18T00:00:00+00:00</published><updated>2023-12-18T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-12-18-i-love-ruby.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/12/18/i-love-ruby/">&lt;figure&gt;
    &lt;img src=&quot;/images/2023-12-18-ruby-logo.png&quot; alt=&quot;Ruby logo&quot; /&gt;
    &lt;figcaption&gt;
        The Ruby logo is Copyright © 2006, Yukihiro Matsumoto and is licensed under Creative Commons Attribution-ShareAlike 2.5
    &lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;I’ve done a lot in my career. From working on business support software to big backend systems and even robotics. If there’s been a consistent through-line to my career, it’s the Ruby programming language.&lt;/p&gt;

&lt;p&gt;In recent years, Ruby has fallen out of favor with the tech industry, but I still love it. It’s a great language with so many strengths that it hurts when I see people trash Ruby or say its time is over. Thankfully, I’m not alone. There are so many Ruby devs still out here. The community is niche, but thriving. People are puzzled by this sometimes. Once, a colleague once said “rubyists really love ruby,” with an air of surprise. I’ve heard others trash ruby for not having types. One person laughed at me when I said Ruby was an “expressive language” and said, “it doesn’t express anything about the implementation.”&lt;/p&gt;

&lt;p&gt;So why do myself and others love Ruby so much? I thought I’d explore this a bit.&lt;/p&gt;

&lt;h2 id=&quot;fostering-programmer-happiness&quot;&gt;Fostering Programmer Happiness&lt;/h2&gt;
&lt;p&gt;First and foremost, Ruby is a language that strives to make programmers happy. This is an underrated value and one that often gets our community mocked by our peers within other communities. The language is meant be joyful to use. This is a value and an ethos that permeates the language, the ecosystem of gems, and the community. Everything else that Ruby is stems from this value.&lt;/p&gt;

&lt;p&gt;When I write Ruby, I take so much joy out of the process. Even the bad parts. In the middle of a high stress incident, Ruby still sparks joy. In fact, the only time I don’t enjoy Ruby is when I’m working on a piece of code that doesn’t follow Ruby practices, patterns, and idioms. Which brings me to the next topic&lt;/p&gt;

&lt;h2 id=&quot;expressiveness-encouraged&quot;&gt;Expressiveness Encouraged&lt;/h2&gt;
&lt;p&gt;Ruby is probably the most expressive programming language on Earth. Between its metaprogramming features and cultural idioms, Ruby allows programmers to write code that clearly expresses its intent. Well written ruby code can often read like natural language. Features like predicate methods even give up punctuation. So you can easily write something like:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@subscription&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;supports_feature?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:feature_a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is often why ruby programmers don’t like comments. In most cases, the language makes comments unnecessary. And when you do need them, it’s often when you’re doing a very specific  or obscure thing that requires context to understand. It’s clear from the code why you need a comment in that case.&lt;/p&gt;

&lt;p&gt;Tied into this is the ecosystems embrace of domain specific languages(DSLs), which give us the power to write incredibly expressive code that reads like what it’s doing. For example, RSpec’s DSL reads exactly like how a person might talk about what they want to test:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Ticket&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;when the ticket is closed&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;emails the requestor with a confirmation&apos;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;del&gt;Methods&lt;/del&gt;, sorry “approaches,” like this have made Ruby so joyful to use.&lt;/p&gt;

&lt;h2 id=&quot;a-language-made-just-for-me&quot;&gt;A Language Made Just For Me&lt;/h2&gt;
&lt;p&gt;Many rubyists, myself included, recount stories of how Ruby and Rails just fit their brain. I recently told this story on &lt;a href=&quot;https://www.remoteruby.com/2260490/14003706-unlocking-the-power-of-state-machines-in-code-development-with-elise-schaefer&quot;&gt;Remote Ruby&lt;/a&gt; about learning ruby. I said that when I was learning Ruby it felt like it was made just for me. I could guess method names and signatures and I would be right most of the time. When I was wrong, I could switch the order of arguments. This was so true that quickly I learned to just try something based on intuition before reading the docs. I know so many rubyists who have similar stories.&lt;/p&gt;

&lt;p&gt;Feeling recognition in the language you’re programming is so powerful.&lt;/p&gt;

&lt;h2 id=&quot;community-and-values&quot;&gt;Community And Values&lt;/h2&gt;
&lt;p&gt;It’s so hard to talk about Ruby without talking about how the community shapes what Ruby is and how it feels to use the language. Ruby is a great language with so many benefits. There’s lots of features and values built into its core that make it a joy to use.&lt;/p&gt;

&lt;p&gt;But as Kent Beck said at RailsConf in 2020, “Software design is an exercise in human relationships.” He was talking about how we think about designing software. But I think this quote applies to our community and our values as well. If you’ve followed this blog or listened to The Ruby on Rails Podcast since I took over, you know that community is a big part of my value system. That value is shared by other rubyists.&lt;/p&gt;

&lt;p&gt;I attended RubyConf in San Diego this year. These conferences are always a blast. It feels like I’m coming home to see old friends. The community building that happens at these conferences makes lifelong colleagues and friends. There a spirit of learning, and cooperation. We want to help each other, teach each other, learn from each other. The Ruby community is an incredible group of people of welcoming, kind, and supportive peers. Without the community, Ruby couldn’t be what it is.&lt;/p&gt;

&lt;p&gt;There’s a lot of reasons to like ruby. And there’s so many things that rubyists love. I haven’t covered everything. But Ruby’s primary features are joy and community. That’s hard to beat.&lt;/p&gt;

&lt;p&gt;Do you love Ruby? &lt;a href=&quot;mailto:elise.shaffer+blog@hey.com&quot;&gt;Tell me what you love about it&lt;/a&gt;&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">I&apos;ve done a lot in my career. From working on business support software to big backend systems and even robotics. If there&apos;s been a consistent through-line to my career, it&apos;s the Ruby programming language.</summary></entry><entry><title type="html">The Technical Decisions Behind My Website Redesign</title><link href="https://eliseshaffer.com/2023/12/11/technical-decisions-website-redesign/" rel="alternate" type="text/html" title="The Technical Decisions Behind My Website Redesign" /><published>2023-12-11T00:00:00+00:00</published><updated>2023-12-11T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-12-13-technical-decisions-website-redesign.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/12/11/technical-decisions-website-redesign/">&lt;p&gt;Last week, I deployed a complete redesign of my personal website. I wrote briefly about the design decisions and iterations that went into the redesign. But, I also wanted to talk about the technical decisions of this redesign.&lt;/p&gt;

&lt;p&gt;I took this as an opportunity to explore some new technologies and methodologies in web development. I really enjoyed the process. I started this work by bringing all my dependencies up to date. Then I started switching various gems out. Let’s talk about my tech stack:&lt;/p&gt;

&lt;h2 id=&quot;bridgetown&quot;&gt;Bridgetown&lt;/h2&gt;
&lt;p&gt;My website is built using &lt;a href=&quot;https://www.bridgetownrb.com/&quot;&gt;Bridgetown&lt;/a&gt;. Bridgetown is a static site generator written in Ruby. It started as a fork of Jekyll, but has since been updated with modern features and tools. I really enjoy it. It’s really familiar if you are an experienced Ruby programmer. For this redesign, I started by bringing Bridgetown up to date with the latest version.&lt;/p&gt;

&lt;p&gt;I changed some of the default configurations. I chose to switch from the default Liquid templates to Embedded Ruby(ERB). When I used Jekyll, I used Liquid templates extensively. But, one of the big decisions I made last year was to switch to ERB. I was already using ERB in Rails apps and i thought it made the switch between the two easier.&lt;/p&gt;

&lt;h2 id=&quot;vanilla-css&quot;&gt;Vanilla CSS&lt;/h2&gt;
&lt;p&gt;For some time now, I’ve been wondering if the marginal utility of Sass is worth it. A lot of the features that made Sass(and SCSS) so great are now part of the CSS specification. And in a lot of cases, they’re better natively. For example, One of the big features of Sass early on was support for variables. but Sass variables are procedural. They are calculated at compile time, which means they can’t be changed or modified at runtime.&lt;/p&gt;

&lt;p&gt;In contrast, CSS custom properties are part of the standard. They can have different values at different scopes. They can be accessed and manipulated by Javascript in the browser and they are more declarative. They have so much more power than Sass variables. One of the big concerns with them used to be browser compatibility. But, all the big browsers have supported it for years now.&lt;/p&gt;

&lt;p&gt;CSS Custom properties also make things like dark mode a cinch to implement. You can decide your palettes and switch them redefining the variables. After deploying the redesign, I decided to add dark mode and it was incredibly easy thanks to CSS custom properties. All I had to do was change the variable declarations within the scope of dark mode.&lt;/p&gt;

&lt;p&gt;Other feature, like nesting are also supported by CSS natively now. This one has less browser support, but since I’m using PostCSS for compilation, I can use it and then it will get compiled down to a format that is supported browsers.&lt;/p&gt;

&lt;p&gt;With all of this in mind, I decided to remove Sass from my personal website and use vanilla CSS. This decision turned out to be great from both a dependency and developer experience perspective.&lt;/p&gt;

&lt;h2 id=&quot;cube-css-and-open-props&quot;&gt;CUBE CSS and Open Props&lt;/h2&gt;
&lt;p&gt;When I start new projects, I like to pick something that I want to get better at. This time, it was CSS. There are so many methodologies for how CSS should be organized and written. From design methodologies like Block-Element-Modifier to full blown utility first frameworks. There’s no shortage of ideas about how best to style HTML.&lt;/p&gt;

&lt;p&gt;For my personal website, I chose to pair Andy Bell’s &lt;a href=&quot;https://cube.fyi/&quot;&gt;CUBE CSS methodoloy&lt;/a&gt; with &lt;a href=&quot;https://open-props.style/&quot;&gt;Open Props&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;CUBE CSS is a CSS methodology that aims to be progressive and scalable. It focuses on starting with good HTML styling. Then, it organizes the rest of your styles into Composition, Utilities, Blocks, and Exception. One of the big benefits of it is that you can write much less CSS. It sorta feels like getting the best of everyone’s ideas. Starting with HTML styling is like starting with class-less CSS. It gives you a great starting point for your site. Then you layer on Composition. The composition is the set of styles that determine how content flows on the page. Bell even calls this section &lt;code class=&quot;highlighter-rouge&quot;&gt;.flow&lt;/code&gt; in his examples. CUBE also advocates utilities. Utilities are one-off classes that do one thing really well. Blocks are what you think of when you think of the block in BEM. And then you have Exceptions. One thing I like about the exceptions of CUBE is that they use data attribute selectors, which facilitates the use of state machines in your CSS.&lt;/p&gt;

&lt;p&gt;I coupled CUBE CSS with Open Props, a framework(might be a strong word) of custom properties with standardized colors, sizes, typography, animations, and much more. They fancy themselves a “sub-atomic” CSS framework, which I think is clever. Open Props dramatically sped up my development. It was also such a joy to use. I like the way the custom properties are defined. It’s easy to use them in your styles.&lt;/p&gt;

&lt;p&gt;These two things led me to write much less CSS in what I hope will be a more maintainable codebase.&lt;/p&gt;

&lt;h2 id=&quot;joy&quot;&gt;Joy&lt;/h2&gt;
&lt;p&gt;One of the biggest things I wanted with this redesign was to find joy in building my personal website. I picked things that were interesting to me, and also matched a lot of my web and software design philosophy. There’s a lot of joy in this redesign.&lt;/p&gt;

&lt;p&gt;One of the biggest strengths of the Ruby community is that we strive for programmer happiness. It’s an underrated value and one that often gets us mocked by our peers in other communities. This redesign was so much fun and I loved working on it. That’s perhaps the most important choice I made for this project.&lt;/p&gt;

&lt;p&gt;Have any questions or want to share your website design story? &lt;a href=&quot;mailto:elise.shaffer+blog@hey.com&quot;&gt;Drop me a line&lt;/a&gt;&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">Last week, I deployed a complete redesign of my personal website. I wrote briefly about the design decisions and iterations that went into the redesign. But, I also wanted to talk about the technical decisions of this redesign.</summary></entry><entry><title type="html">Redesigning My Website</title><link href="https://eliseshaffer.com/2023/12/04/redesigning-my-website/" rel="alternate" type="text/html" title="Redesigning My Website" /><published>2023-12-04T00:00:00+00:00</published><updated>2023-12-04T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-12-04-redesigning-my-website.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/12/04/redesigning-my-website/">&lt;p&gt;Yesterday, I merged a redesign of my website and so far, people seem to really like it. This was a multi-week project to bring some new life to my website and fix some accessibility and technical issues. I also wanted to explore some modern CSS features. This was a really fun project and I think the new site is much better than the old one.&lt;/p&gt;

&lt;p&gt;I started by bringing the code as up to date as I could. I was a version behind of Bridgetown’s latest release. Thankfully, the upgrade process was painless. 😊 I also took the time to upgrade all of the node modules I was using before evaluating the technical choices for the site going forward.&lt;/p&gt;

&lt;p&gt;I like to start projects like this by asking people for feedback on what I already have. One piece of feedback I got on the previous version of the site is that people really enjoyed the simplicity of it. It was the thing everyone I asked told me not to change with the redesign. I got many compliments on how good it was on phones.&lt;/p&gt;

&lt;p&gt;So I wanted to make sure I kept that simplicity as I worked through the new design. I removed the list of blog posts from the main page and made it a simple landing page where I introduce myself to the reader.&lt;/p&gt;

&lt;p&gt;I experimented with quite a few things while working on the redesign. Originally, I was going to leave the blog posts, but just have it be a list of links. I also wasn’t sure about the color scheme. I tried several things before landing on the subtle mix of purples that ended up on the site. I tried building a job for the contact form that would create an email thread with both myself and the submitter. Then, I abandoned that for the much simpler solution of including a &lt;code class=&quot;highlighter-rouge&quot;&gt;mailto&lt;/code&gt; link.&lt;/p&gt;

&lt;p&gt;There was a lot of that kind of exploration. One thing that never ceases to amaze me is how much work simplicity is. There are so many simple elements of my new website, but landing on those elements took quite a few revisions and feedback cycles from friends.&lt;/p&gt;

&lt;p&gt;There’s still a few things I want to do. Dark mode had been on my list, but I ended up putting it off for a bit. I also have some cool ideas about how I’d like to present my Resume page, but I’m still working through them.&lt;/p&gt;

&lt;p&gt;Overall, I’m very happy with how things turned out. It feels so much more alive now. I fixed a bunched of accessibility issues and got to exercise my CSS skills. I hope you enjoy the new site. Feel free to &lt;a href=&quot;mailto:elise.shaffer@hey.com&quot;&gt;drop me a line&lt;/a&gt; with feedback.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">Yesterday, I merged a redesign of my website and so far, people seem to really like it. This was a multi-week project to bring some new life to my website and fix some accessibility and technical issues. I also wanted to explore some modern CSS features. This was a really fun project and I think the new site is much better than the old one.</summary></entry><entry><title type="html">Dotbot Is Really Nice</title><link href="https://eliseshaffer.com/2023/08/23/dotbot-is-really-nice/" rel="alternate" type="text/html" title="Dotbot Is Really Nice" /><published>2023-08-23T00:00:00+00:00</published><updated>2023-08-23T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-08-23-dotbot-is-really-nice.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/08/23/dotbot-is-really-nice/">&lt;p&gt;I LOVE looking at other people’s dotfiles. There’s something great about looking at how someone has set up their development environment, taking inspiration from them and learning new things. For example, I recently learned that in Neovim there’s a setting for using the system clipboard for yank and paste. I’ve been using a separate keymap for interacting with the system clipboard for years. I enabled this setting and it’s amazing. Now, when I yank text in Neovim, I can paste is into a slack channel and it just works!&lt;/p&gt;

&lt;p&gt;I also love tinkering with my own &lt;a href=&quot;https://github.com/eliseshaffer/dotfiles&quot;&gt;dotfiles&lt;/a&gt;. Every so often I’ll look over things and add some conveniences like new aliases, or keymaps for Neovim. I’ve also created functions to make certain things easier(like automatically &lt;code class=&quot;highlighter-rouge&quot;&gt;cd&lt;/code&gt;-ing into a git repo after cloning it).&lt;/p&gt;

&lt;p&gt;Over the years, I’ve added various scripts to handle installing, linking, and setting up my dotfiles. These are mostly hand rolled shell scripts that link my dotfiles, install the applications I use, and configure git and Neovim on a new machine. My goal is to be able to run a single command, walk away, and come back to a fully set up machine.&lt;/p&gt;

&lt;p&gt;It’s never quite worked that way, however. I’ve run into issues with the installer many times. These small quirks sent me debugging the scripts on every new machine setup.&lt;/p&gt;

&lt;p&gt;I’ve written before about how &lt;a href=&quot;https://eliseshaffer.com/2020/01/26/i-am-not-a-power-user/&quot;&gt;I don’t consider myself a power user&lt;/a&gt;.  While making a series of changes to my dotfiles this weekend, I decided to retire my aging install scripts in favor of using a ready made dotfiles manager. I chose to use &lt;a href=&quot;https://github.com/anishathalye/dotbot#getting-started&quot;&gt;Dotbot&lt;/a&gt;. Reader, let me tell you: &lt;em&gt;Dotbot is really nice&lt;/em&gt;!&lt;/p&gt;

&lt;p&gt;Dotbot is a little bit like ansible, but way lighter weight. It uses a YAML file to configure how your dotfiles should be linked in your home folder.&lt;/p&gt;

&lt;p&gt;You install in into your dotfiles repo as a git submodule:&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git submodule add https://github.com/anishathalye/dotbot
git config &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; .gitmodules submodule.dotbot.ignore dirty
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And copy the install script into your dotfiles root folder:&lt;/p&gt;
&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;dotbot/tools/git-submodule/install &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;install.conf.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since everything is configured using a YAML file, it makes understanding all your linked files really simple. For example, this is one of my configuration files:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;defaults&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;relink&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;clean&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;pi&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;~&apos;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.aliases&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;aliases&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.config/nvim&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nvim&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.gitignore_global&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;gitignore_global&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.nvmrc&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;nvmrc&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.ruby-version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ruby-version&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.zsh_functions&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zsh_functions&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.zshenv&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zshenv&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;~/.zshrc&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;zshrc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;link&lt;/code&gt; section sets up symlinks to various files and folders. The key is the target location and the value is where the link points to.&lt;/p&gt;

&lt;p&gt;I’m also using a plugin called &lt;a href=&quot;https://github.com/eliseshaffer/dotbot-brew&quot;&gt;dotbot-brew&lt;/a&gt; that handles Homebrew packages as part of the Dotbot configuration. This is what my configuration for Homebrew looks like:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;install-brew&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;homebrew/cask-fonts&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; 
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;neovim&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;cask&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;font-fira-code-nerd-font&lt;/span&gt;

&lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;brewfile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;brew/home.brewfile&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I set up my taps, packages and the brewfile from my previous dotfiles setup. This lets me have a single command to install all the packages I need.&lt;/p&gt;

&lt;p&gt;So far, everything is working really well. I like Dotbot. It’s really simple to set up and it just works the way I expect. Sometimes you have to discard your custom stuff and use something off the shelf. I’m glad I could do that for my dotfiles setup.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">While making a series of changes to my dotfiles this weekend, I decided to retire my aging install scripts in favor of using a ready made dotfiles manager. I chose to use Dotbot. Reader, let me tell you: Dotbot is really nice! Dotbot is a little bit like ansible, but way lighter weight. It uses a YAML file to configure how your dotfiles should be linked in your home folder.</summary></entry><entry><title type="html">I Miss Cucumber</title><link href="https://eliseshaffer.com/2023/08/08/i-miss-cucumber/" rel="alternate" type="text/html" title="I Miss Cucumber" /><published>2023-08-08T00:00:00+00:00</published><updated>2023-08-08T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-08-08-i-miss-cucumber.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/08/08/i-miss-cucumber/">&lt;p&gt;I might be getting old. The other day, I was chatting with a coworker and waxing nostalgic about various tools and methods that I miss. The conversation had a whole “back in my day” vibe. Which, you know, I think I should just lean into at this point. Anyway, we started talking about Cucumber and it made me a little sad that the community had moved on from it.&lt;/p&gt;

&lt;p&gt;Cucumber is a Behavior Driven Development framework that lets you write acceptance style tests in the form of a user story. You might write the following test for what happens when a user logs in:&lt;/p&gt;

&lt;div class=&quot;language-gherkin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;Feature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; Sign In
  &lt;span class=&quot;kn&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;Given &lt;/span&gt;a user exists

  &lt;span class=&quot;kn&quot;&gt;Scenario&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;a &lt;/span&gt;user signs in successfully
    &lt;span class=&quot;nf&quot;&gt;When &lt;/span&gt;the user visits the sign in page
    &lt;span class=&quot;nf&quot;&gt;And &lt;/span&gt;the user enters their username
    &lt;span class=&quot;nf&quot;&gt;And &lt;/span&gt;the user enters their password
    &lt;span class=&quot;nf&quot;&gt;And &lt;/span&gt;the user clicks submit
    &lt;span class=&quot;nf&quot;&gt;Then &lt;/span&gt;the user is routed to the dashboard
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each step in that example would be defined like this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;SignInSteps&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a user exists&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;username: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;alice&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;ss&quot;&gt;password: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;password&apos;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;step&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;the user enters their username&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;fill_in&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;Username&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;with: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;username&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cucumber has a few advantages. The syntax reads like a user story. It puts you in the mind of the user and that’s a powerful framework to think in. This can help you codify your requirements in the same language as the customer who will use and talk about your product.&lt;/p&gt;

&lt;p&gt;Having that language helps you build a shared understanding of your software. What do we mean when we say “the user fills in their username?” Using a tool like cucumber, you can write that step in code, run it in a browser and make sure the whole team agrees that you accurately captured the behavior.&lt;/p&gt;

&lt;p&gt;So what happened to cucumber?&lt;/p&gt;

&lt;p&gt;Cucumber was sold in part based on its human readable nature. The promise was that lay people could write acceptance tests. You could give a product manager or a customer service representative a list of steps and they could assemble them, filling in steps for missing functionality that would then be fleshed out by developers.&lt;/p&gt;

&lt;p&gt;That didn’t happen. Instead, developers wrote all the code. Since developers were used to writing and understanding code, the extra tooling to make BDD style frameworks possible seemed like unnecessary overhead. It was just as simple to write all the same acceptance style code without the fancy domain specific language.&lt;/p&gt;

&lt;p&gt;Cucumber is still around. It’s still being worked on and developed. But, the industry has moved on. That makes me sad. I really do miss it. I think we gave up something great when we stopped using Cucumber.&lt;/p&gt;

&lt;p&gt;I miss how it forced me to think in real world terms. It forced me to put myself in the customer’s shoes and write down how the system should work from their perspective.&lt;/p&gt;

&lt;p&gt;I miss how easy it was to write new acceptance tests. Over time, you build a library of steps and then composing new tests is like writing a story out of precomposed sentences.&lt;/p&gt;

&lt;p&gt;I think Cucumber sparks joy. At least it did for me. And I miss using it.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">I might be getting old. The other day, I was chatting with a coworker and waxing nostalgic about various tools and methods that I miss. The conversation had a whole &quot;back in my day&quot; vibe. Which, you know, I think I should just lean into at this point. Anyway, we started talking about Cucumber and made me a little sad.</summary></entry><entry><title type="html">Joining The Linear Side</title><link href="https://eliseshaffer.com/2023/07/04/joining-the-linear-side/" rel="alternate" type="text/html" title="Joining The Linear Side" /><published>2023-07-04T00:00:00+00:00</published><updated>2023-07-04T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-07-04-joining-the-linear-side.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/07/04/joining-the-linear-side/">&lt;p&gt;&lt;img src=&quot;/images/2023-07-04-joining-linear-side-banner.jpg&quot; alt=&quot;Image of a mechanical keyboard&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I’m standing at my desk writing this blog post and all I can think about is how great this keyboard feels. I’m falling in love with this keyboard: the buttery smooth travel of the keys, the satisfying &lt;em&gt;thock&lt;/em&gt; as my fingers hit the end of travel. For the first time, I enjoy typing on a linear switch. This keyboard is using the &lt;a href=&quot;https://divinikey.com/products/gateron-ks-3-milky-yellow-pro-linear-switches&quot;&gt;Gateron Milky Yellow Pro&lt;/a&gt; switches and they feel so nice. I just want to keep using it.&lt;/p&gt;

&lt;p&gt;Let’s back up.&lt;/p&gt;

&lt;p&gt;Back in 2016, I joined Sphero. Everyone there had mechanical keyboards, while I was used to the Apple Magic Keyboard. On my first day, the Director of Engineering asked what kind of keyboard I’d like to use. I didn’t know anything about mechanical keyboard, so I told him I wasn’t sure. He invited me into his office to pick one out from our vendor. This was my first introduction to mechanical keyboards. Prior to this I didn’t know what “linear,” “tactile,” and “clicky” meant. I asked him for advice and he said, “a lot of us are using linears.” So, I picked the Cherry MX Red and we placed the order.&lt;/p&gt;

&lt;p&gt;I worked at Sphero for 18 months and in that time, I came to hate that keyboard. It was so hard to type on. I missed letters and typed gibberish accidentally. The big problem for me was that I was never sure if I’d actually hit the key. I left that job with a strong aversion to linear switches.&lt;/p&gt;

&lt;p&gt;When I purchased my next mechanical keyboard, I picked a strong tactile switch, the &lt;a href=&quot;https://www.cherrymx.de/en/cherry-mx/mx-special/mx-clear.html&quot;&gt;Cherry MX Clear&lt;/a&gt;. This keyboard was much better. It had a noticeable bump and that meant that I typed much more confidently. I very rarely had typos and I was more accurate in hitting the keys.&lt;/p&gt;

&lt;p&gt;Prebuilt mechanical keyboards can only take you so far. I started to want things that I couldn’t get buying off the shelf. I wanted a quieter keyboard. I wanted to try something other than a Cherry switch. Most of all, I wanted a project. Something I could pour myself into. So, I decided to build my own keyboard. I chose to again go with tactile switches. This time, silent switches: the &lt;a href=&quot;https://zealpc.net/products/zilent?variant=5894832324646&quot;&gt;Zilent 67g&lt;/a&gt; switches. These switches also had a noticeable bump and I could feel when the switch actuated. But, I made several mistakes with that first build. I spent significant money on the switches, but spent no money on stabilizers, opting to use the ones that came with my kit. On top of that, I didn’t mod or lube the stabilizers. So while my keys were whisper quiet, the space bar, return, and shift keys were rattly and annoying. To make matters worse, I had opted to buy a solder kit instead of a hot swap kit. So fixing this would be a huge endeavor.&lt;/p&gt;

&lt;p&gt;Enter my second(and current) build.&lt;/p&gt;

&lt;p&gt;For this build, I opted for a hot swap board. And I bought the &lt;a href=&quot;https://divinikey.com/products/durock-v2-stabilizers-screw-in?variant=32275866681409&quot;&gt;Durock V2 Stabilizers&lt;/a&gt;. I was looking for a lighter switch and opted for the Zilent 62gs. But, they weren’t in stock. So, I bought a temporary switch, the &lt;a href=&quot;https://drop.com/buy/drop-halo-switch-pack?defaultSelectionIds=975863,975868&quot;&gt;Halo Drop Clears&lt;/a&gt; with the intention to swap them out when the Zilents were back in stock(spoiler alert: I’m not doing that).&lt;/p&gt;

&lt;p&gt;When I assembled the board, I was surprised at the feel. I couldn’t feel the bump at all. I was sure they’d sent me the wrong switch. So, I decided to take one of the switches apart. There was a bump. I just couldn’t feel it while typing. Over the next week, I was able to pick up the bump. But, it was so much softer than I was used to.&lt;/p&gt;

&lt;p&gt;I decided to buy a different switch and figured I’d give linear another shot. After all, this was all a stopgap until I could get the real switch I wanted. I was looking for a budget friendly linear and I picked up the Gateron Milky Yellow Pro. They were pretty cheap at 23 cents per switch and they came pre-lubed so I didn’t need to make a big time investment to lube them myself.&lt;/p&gt;

&lt;p&gt;Over a month later, I’ve really come to love this switch. It’s smoother than any switch I’ve ever used. It’s also really comfortable to type on. I find myself wanting to sit at my desk a lot more because the typing experience is borderline addictive. The sound of the keyboard is also really pleasing.&lt;/p&gt;

&lt;p&gt;While typing on it, I’m’ ever presently aware of how good the keys feel, how satisfying the sound is and how smooth the travel is. And what’s more, these switches are really reasonably priced. I’ve even been researching other linear switches. After the last six weeks, it’s safe to say I’ve finally joined the dark, buttery smooth side that is linears.&lt;/p&gt;

&lt;p&gt;I can’t say that I’ll never go back to tactile switches, but I think I finally gained an appreciation for the smoothness of linear switches. What switches are you using?&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">I&apos;m standing at my desk writing this blog post and all I can think about is how great this keyboard feels. I&apos;m falling in love with this keyboard: the buttery smooth travel of the keys, the satisfying thock as my fingers hit the end of travel. For the first time, I enjoy typing on a linear switch.</summary></entry><entry><title type="html">Introducing Darklight.nvim</title><link href="https://eliseshaffer.com/2023/05/22/introducing-darklight-nvim/" rel="alternate" type="text/html" title="Introducing Darklight.nvim" /><published>2023-05-22T00:00:00+00:00</published><updated>2023-05-22T00:00:00+00:00</updated><id>repo://posts.collection/_posts/2023-05-22-introducing-darklight-nvim.md</id><content type="html" xml:base="https://eliseshaffer.com/2023/05/22/introducing-darklight-nvim/">&lt;p&gt;&lt;img src=&quot;/images/2023-05-22-darklight-announcement.png&quot; alt=&quot;Image of a terminal with two
colorschemes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I made my first lua plugin for Neovim! It’s called &lt;a href=&quot;https://github.com/eliseshaffer/darklight.nvim&quot;&gt;Darklight.nvim&lt;/a&gt; and it makes it super simple to switch between dark mode and light mode colorschemes in Neovim.&lt;/p&gt;

&lt;p&gt;About a year ago, I switched my whole Neovim setup to Lua and stopped sharing the same configuration with Vim. This was such a breath of fresh air. Lua is a fun little scripting language and it made configuring Neovim a delight. But I haven’t created any plugins with it until now.&lt;/p&gt;

&lt;p&gt;Darklight is an extraction of some setup that I’d had in my own Neovim config for a while. When a friend asked me how I’d done the color switching, I decided to extract the relevant code into a plugin and add some configuration around it.&lt;/p&gt;

&lt;p&gt;The bulk of the work in making it a plugin was setting up the Config object. There was some validation that was necessary as well as figuring out how to gracefully fallback in situations where the configuration was invalid. I added a Lua table for the &lt;code class=&quot;highlighter-rouge&quot;&gt;Config&lt;/code&gt; object and made a function that validated the passed in configuration.&lt;/p&gt;

&lt;p&gt;With that, Darklight was born.&lt;/p&gt;

&lt;p&gt;Darklight has three different modes, &lt;code class=&quot;highlighter-rouge&quot;&gt;background&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;colorscheme&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;custom&lt;/code&gt;. Background is the simplest mode. In this mode, Darklight will chang the background setting in vim between “dark” and “light.” Because many themes already support light and dark modes, this is the simplest way to use Darklight.&lt;/p&gt;

&lt;p&gt;In &lt;code class=&quot;highlighter-rouge&quot;&gt;colorscheme&lt;/code&gt; mode, Darklight will switch between two completely different colorschemes. And in &lt;code class=&quot;highlighter-rouge&quot;&gt;custom&lt;/code&gt; mode, you can provide callbacks that will let you completely control the switching behavior. You can learn more &lt;a href=&quot;https://github.com/eliseshaffer/darklight.nvim&quot;&gt;on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was a fun little project and I’m happy to share this with the Neovim community. I have a few ideas for others features that I want to add, but the core pieces of functionality are pretty solid. After this experience, I look forward to making other plugins in the future.&lt;/p&gt;</content><author><name>Elise Shaffer</name></author><summary type="html">I made my first lua plugin for Neovim! It&apos;s called Darklight.nvim and it makes it super simple to switch between dark mode and light mode colorschemes in Neovim.</summary></entry></feed>