<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Ethan Fertsch</title>
    <description>The latest articles on Forem by Ethan Fertsch (@efertsch).</description>
    <link>https://forem.com/efertsch</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F720458%2Ff1b43f18-f40d-4ef5-a15b-78daca841604.jpeg</url>
      <title>Forem: Ethan Fertsch</title>
      <link>https://forem.com/efertsch</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/efertsch"/>
    <language>en</language>
    <item>
      <title>Gnarly Learnings from July 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Mon, 31 Jul 2023 19:52:52 +0000</pubDate>
      <link>https://forem.com/efertsch/gnarly-learnings-from-july-2023-45ch</link>
      <guid>https://forem.com/efertsch/gnarly-learnings-from-july-2023-45ch</guid>
      <description>&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rails/rails/pull/40095"&gt;&lt;code&gt;ComparisonValidator&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Gone are the days when we need to write custom validators in Rails to determine if a start date begins before an end date! Back in 2021, the &lt;code&gt;ComparisonValidator&lt;/code&gt; was added to Rails 7. While useful for solving the date comparison example above, that’s not all it can do! It can also compare strings, and it allows for the flexibility of custom comparisons. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rails/rails/pull/47473"&gt;Active Storage Can Pre-Process Variants&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Earlier this month Rails added a feature allowing Active Storage variants to be pre-processed &lt;em&gt;up front&lt;/em&gt; by adding &lt;code&gt;preprocessed: true&lt;/code&gt; to the variant definition. This makes the attachment ready to serve from the outset, rather than requiring the variant to be prepared/transformed on the fly. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex"&gt;JavaScript’s &lt;code&gt;findLast()&lt;/code&gt; and &lt;code&gt;findLastIndex()&lt;/code&gt; &lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There are a few new &lt;code&gt;Array&lt;/code&gt; functions included in ES2023, &lt;code&gt;findLast()&lt;/code&gt; and &lt;code&gt;findLastIndex()&lt;/code&gt;. The exciting piece is less about what these functions &lt;em&gt;do&lt;/em&gt; (you can probably figure it out from the names) and more about the convenience that they provide. As a Rubyist by trade, I am used to a super developer-friendly experience when it comes to the readability, and accessibility of functions so it’s great to see these being added to JavaScript - even if it took until 2023. 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://guides.rubyonrails.org/layouts_and_rendering.html#using-the-content-for-method"&gt;Partial Renders in Rails&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Partial rendering allows you to create a consistent template with different sections, for example “title”, “body”, and “footer.”  Then the templates can define content for each of those sections without having to know anything about the layout of the root template.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/facebook/create-react-app/pull/8177"&gt;&lt;code&gt;React.FC&lt;/code&gt; Removed From create-react-app Base TypeScript Template&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;If you build React apps with TypeScript, you're certainly used to seeing and using the &lt;code&gt;React.FC&lt;/code&gt; (or &lt;code&gt;React.FunctionalComponent&lt;/code&gt;) type at the declaration of your functional components. The folks maintaining create-react-app have decided to remove this type from their template as they believe it is more harmful than helpful. I tend to agree, particularly around the implicit definition of &lt;code&gt;children&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Steve Zelaznik&lt;/li&gt;
&lt;li&gt;Taylor Kearns&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>react</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How Generative AI Impacts Software Development at The Gnar</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Thu, 27 Jul 2023 18:50:26 +0000</pubDate>
      <link>https://forem.com/thegnarco/how-generative-ai-impacts-software-development-at-the-gnar-4662</link>
      <guid>https://forem.com/thegnarco/how-generative-ai-impacts-software-development-at-the-gnar-4662</guid>
      <description>&lt;p&gt;It would be difficult to make it through a day without hearing, reading, or seeing something related to Artificial Intelligence (AI). While the &lt;em&gt;concept&lt;/em&gt; of AI is nothing &lt;a href="https://en.wikipedia.org/wiki/2001:_A_Space_Odyssey_(film)"&gt;new&lt;/a&gt;, there is a new form of AI that has generated a lot of buzz: &lt;a href="https://en.wikipedia.org/wiki/Generative_artificial_intelligence#:~:text=Generative%20artificial%20intelligence%20or%20generative,media%20in%20response%20to%20prompts."&gt;generative AI&lt;/a&gt;. In the simplest terms, generative AI is a system that can generate content (text, images, code) in response to user input. This type of system has the potential to significantly impact many industries - from healthcare to legal to the software development industry. &lt;/p&gt;

&lt;p&gt;As a consultancy, we are constantly evaluating new tools and technologies that will help us to efficiently deliver high-quality work to our clients. At this point, it’s important to highlight that we are &lt;em&gt;consumers&lt;/em&gt; of AI, not &lt;em&gt;creators&lt;/em&gt; of it. That is to say, we won’t be building the next big natural language processing tool, but we may use one to help us write a test for a certain piece of code. There are a number of AI platforms that are already proliferating in the software design and development space, and our team is happy to experiment with them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Generative AI at The Gnar
&lt;/h2&gt;

&lt;p&gt;We asked our team what tools they were using to make their process more efficient and there were two at the top of the list: GitHub Copilot and ChatGPT. But we’re more than just an engineering shop - we also offer a full suite of design services and there are a number of tools that our designers use to improve the quality of their deliverables, such as MagiCopy. &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://github.com/features/copilot"&gt;GitHub Copilot&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;GitHub Copilot is marketed as an “AI pair programmer”. It is a paywalled service ($10/mo) that was released in the fall of 2021. The tool plugs into a text editor, such as VSCode, and can make real-time code suggestions based on input from the developer. &lt;/p&gt;

&lt;h4&gt;
  
  
  How We Are Using It
&lt;/h4&gt;

&lt;p&gt;The majority of our team is using it to increase velocity and reduce the monotony of repetitive tasks. GitHub Copilot is anticipatory so if you begin typing some code it will try to automatically complete a word, line of code, or function. This may sound simple, but when we look at time spent on the keyboard over the course of an engagement, all of those reserved keystrokes have a cost savings associated with them. As a more practical example, we are firm believers in the value of comprehensive test coverage in the applications that we build. However, writing tests is time-consuming, and by nature, there is quite a bit of repetitive setup for each file. GitHub Copilot really shines here because it can handle much of the setup and can even write complete tests &lt;em&gt;for&lt;/em&gt; you (though we strongly caution against accepting these at face value, more on this later). &lt;/p&gt;

&lt;p&gt;Here’s what one of our team members had to say when asked how they were using AI to make their life easier:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“Github Copilot! I much prefer the in-editor interface to anything prompt-based and while it often spits out nonsense for business logic it excels at test suites. [...]”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Why We Are Using It
&lt;/h4&gt;

&lt;p&gt;GitHub Copilot has been an easy choice for our team for a number of reasons. &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; is a credible and familiar platform. We use it almost exclusively for storing and managing code. Moreover, GitHub was &lt;a href="https://news.microsoft.com/2018/06/04/microsoft-to-acquire-github-for-7-5-billion/"&gt;acquired&lt;/a&gt; by Microsoft back in 2018 so we know that they have strong financial and technical backing, which is promising for the tool’s longevity. It also integrates directly with &lt;a href="https://code.visualstudio.com/"&gt;VSCode&lt;/a&gt; (another Microsoft brainchild) which is a favorite text editor of many of our team members and therefore has a low barrier to entry. This combined with the time and effort savings during development makes it really attractive for developers and clients alike. However, it’s not all kittens and rainbows (more on this in the &lt;em&gt;Challenges with Generative AI&lt;/em&gt; section). &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://openai.com/blog/chatgpt"&gt;ChatGPT&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Chat Generative Pre-Trained Transformer (affectionately referred to as &lt;a href="https://openai.com/blog/chatgpt"&gt;ChatGPT&lt;/a&gt;), is a natural language processing tool which is really just a fancy way of saying “an AI-based chatbot” which was developed by &lt;a href="https://openai.com/"&gt;OpenAI&lt;/a&gt; and released in late 2022. A user can engage with ChatGPT via prompts and receive human-like responses. It is not software specific/focused - you can ask it what the meaning of life is, to build a keto meal plan for you, or to convert a Ruby method to Python. The world is your oyster. &lt;/p&gt;

&lt;h4&gt;
  
  
  How We Are Using It
&lt;/h4&gt;

&lt;p&gt;ChatGPT is used less often than tools like GitHub Copilot but it did come up a number of times when discussing Generative AI with our team. It can be a great replacement for specific, simple questions about things like code syntax. With these types of questions, it’s often faster to use a tool like this than scouring blog posts or forums like &lt;a href="https://stackoverflow.com/"&gt;Stack Overflow&lt;/a&gt;. One team member finds utility in ChatGPT as a “&lt;a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging"&gt;rubber duck&lt;/a&gt;” when they are trying to solve a problem.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“It's better curated than Stack Overflow. Sometimes AI is my "rubber duck". The process of forming a coherent question for ChatGPT helps me better understand the problem I'm working on.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Why We Are Using It
&lt;/h4&gt;

&lt;p&gt;The primary reason for using ChatGPT is that it is super easy to get started. Getting started requires nothing more than an account with OpenAI and a question. Developers spend a significant amount of time learning, researching, and reading documentation. There are certain situations in which tools like ChatGPT cut down on reading so more time can be spent writing code.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://www.figma.com/community/plugin/1184110746118034942/MagiCopy-%E2%80%93-AI-Text-Generator"&gt;MagiCopy&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;MagiCopy is a &lt;a href="https://www.figma.com/"&gt;Figma&lt;/a&gt; plug-in. Figma is the choice interface design application of our design team. The plug-in can generate copy based on project type, company, desired tone, and content type. &lt;/p&gt;

&lt;h4&gt;
  
  
  How We Are Using It
&lt;/h4&gt;

&lt;p&gt;Our design team uses MagiCopy to generate meaningful text for wireframes and mockups.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why We Are Using It
&lt;/h4&gt;

&lt;p&gt;We use MagiCopy because it provides a more realistic feel to design deliverables, which translates to a more delightful experience for our clients and their stakeholders. Without a tool like this, there would be a time investment in generating realistic copy in the specific context of a project, or worse, we’d see a lot more &lt;a href="https://en.wikipedia.org/wiki/Lorem_ipsum"&gt;lorem ipsum&lt;/a&gt;. Additionally, as with many of the other tools mentioned in this article, MagiCopy integrates with a platform that we know and love, lowering the barrier to entry.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“There's a constant struggle when designing of whether we need copy before design or design before copy. In instances when copy isn't written yet or fully approved for a website, designers will use "Lorem Ipsum" as placeholder text in their work, but it doesn't do a good job of representing how real copy will flow on a page. Not only that, but telling the brand story is important to elevating the design, so if the copy isn't final I write my own to help make a design feel more real. Having the ability to generate copy for my designs with a tool like MagiCopy I not only save time, but no longer have to default to "Lorem ipsum" when copy is not available or I'm unable to write it myself.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While these tools have the potential to enhance the design and development process, we also envision a number of broad challenges that Generative AI poses to the industry. With great power comes great responsibility…&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenges with Generative AI
&lt;/h3&gt;

&lt;p&gt;While these recent advances in Generative AI are remarkable and the conceptual utility is there, there are a number of challenges that have prevented widespread adoption at The Gnar. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Overreliance.&lt;/strong&gt; At this stage, the output from these tools is often flat-out &lt;strong&gt;wrong&lt;/strong&gt; and still requires a careful eye to ensure what is being returned is usable and correct. Could ChatGPT build a web app for you? Probably. Would it be production-ready or usable out of the box? Almost certainly not. The responses from the tools are only as good as the level of detail and prompts that you provide to them. As users of ChatGPT and GitHub Copilot, we’re still required to take everything with a grain of salt and double-check the output - it would be a mistake to become overly reliant on these tools to perform our work for us.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Misrepresentation.&lt;/strong&gt; This applies less to our current team but more to potential hires (and the potential hires of our clients). It is becoming increasingly easier to misrepresent a skillset using tools like this. A design candidate could use an image-based Generative AI platform to create and submit a portfolio of work just as easily as a software developer could use ChatGPT or GitHub Copilot to complete a coding assessment. While we like to assume the best, this is a serious ethical concern that will need to be monitored as these tools become more advanced.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intellectual Property.&lt;/strong&gt; Generative AI tools are built and continuously trained on the data that they are fed. The more data they process, in theory, the more helpful they become. The work we produce is always considered the intellectual property of our clients. When it comes to the impact of using a plugin like Github Copilot, that intellectual property is being used as input data to improve that tool. There’s a big question mark in our minds about whether companies are aware of this and more importantly, if they’re &lt;em&gt;okay with it&lt;/em&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Impact on Cost and Quality.&lt;/strong&gt; While we don’t think AI is going to cost us our jobs or take over the world, there are specific concerns about how we work with AI that will impact software development:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;“In its current form, generative AI could be a repeat of the "low code" experiments of the 1990s: I think a lot of non-technical decision makers will think it can heavily automate software development. They will pay consultancies to ‘use AI’ to cheaply write their apps. The apps won't work very well and they need more money to fix them than it would have taken to write them properly the first time.”&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The takeaway from all of this? Generative AI tools are very powerful and have the potential to greatly impact the software development industry. We are still in the very early days of technology of this type and there are a lot of challenges and ethical concerns that prevent us from diving in head first. However, we plan to continue to evaluate these tools and to use them to boost productivity by assisting with repetitive tasks - &lt;strong&gt;but only when and where it makes sense to do so, without compromising quality&lt;/strong&gt;. &lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>chatgpt</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Meet The Gnarnians: Erik</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Fri, 21 Jul 2023 14:34:56 +0000</pubDate>
      <link>https://forem.com/thegnarco/meet-the-gnarnians-erik-894</link>
      <guid>https://forem.com/thegnarco/meet-the-gnarnians-erik-894</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Gnarnian [nahr-nee-uhn] &lt;em&gt;noun&lt;/em&gt;:&lt;/strong&gt; An employee of The Gnar Company
&lt;/h2&gt;

&lt;p&gt;In our &lt;em&gt;Meet The Gnarnians&lt;/em&gt; series, we unravel the stories, experiences, and passions that drive the folks on our talented team at The Gnar. Through a collection of interview-style questions, you’ll get a sneak peek into daily life on our fully-remote team, some epic origin stories, and answers to some questions as weird and wonderful as our team itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Basics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where are you located?&lt;/strong&gt; Chicago, IL&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is your Role?&lt;/strong&gt; Software Engineer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When did you join the Gnar?&lt;/strong&gt; December 2021&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the last song you played or are listening to right now?
&lt;/h2&gt;

&lt;p&gt;Ballroom Blitz. The Crucial Taunt version.&lt;/p&gt;

&lt;h2&gt;
  
  
  What was your career journey up until joining the Gnar?
&lt;/h2&gt;

&lt;p&gt;I started out in networking and servers and took a nice long education break before coming back as a developer, then worked for a nonprofit for a long time before joining an early stage startup. In general, I've just stayed curious by doing what I want and things have worked out pretty well.&lt;/p&gt;

&lt;h2&gt;
  
  
  In your role, do you have any specializations or areas of focus you really enjoy doing?
&lt;/h2&gt;

&lt;p&gt;I really enjoy designing software systems: Thinking in terms of architectural patterns, how best to model the real world concepts involved, how you can play to the strengths of your chosen language, and so on. There's something very satisfying about producing things that are easy to understand and do what you expect, and the design phase is generally where you're closest to what stakeholders really want in the end, whether it's a feature or a greenfield app.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is your ideal work/desk set-up?
&lt;/h2&gt;

&lt;p&gt;A standing desk, (not a convertible, which I will not convert) with good light, decently-but-not-maximally clackety keyboard, enough screen real estate to read a browser tab and a terminal (dark text, light background) at the same time. Zsh, tmux, vim, asdf. Good headphones for music, which I will feel weird about wearing for meetings. Coffee, for which my taste is utterly gauche.&lt;/p&gt;

&lt;h2&gt;
  
  
  What has your experience been at Gnar?
&lt;/h2&gt;

&lt;p&gt;I've gotten to be involved in a long standing state project with a really interesting back end architecture, which is maybe not the first thing you picture working on going into a Rails consulting shop. It's very satisfying to see features through not just to completion but all the way through fine tuning them in the real world. The best answer here though is the people--- folks at Gnar are really welcoming and supportive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What advice would you give someone who is just starting out in your industry?
&lt;/h2&gt;

&lt;p&gt;Don't let popular opinion tell you what success looks like for you. There are a ton of great jobs out there in the world, so keep an open mind and figure out what makes you happy and keeps you curious. And it's ok to go slow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outside of work, what do you enjoy doing?
&lt;/h2&gt;

&lt;p&gt;Music. Listening to it, playing it, recording it, talking about it, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you weren’t in your current role, what would you be doing?
&lt;/h2&gt;

&lt;p&gt;Live sound guy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about &lt;a href="https://www.thegnar.com/about"&gt;The Gnar and our team&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

</description>
      <category>softwareengineering</category>
      <category>culture</category>
      <category>community</category>
    </item>
    <item>
      <title>Gnarly Learnings from June 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Fri, 30 Jun 2023 19:18:49 +0000</pubDate>
      <link>https://forem.com/thegnarco/gnarly-learnings-from-june-2023-3lk8</link>
      <guid>https://forem.com/thegnarco/gnarly-learnings-from-june-2023-3lk8</guid>
      <description>&lt;p&gt;At The Gnar we are always reading, watching, and listening in order to keep our skills sharp and our perspectives fresh. Here are some of the resources we learned from this month.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.totaltypescript.com/typescript-5-2-new-keyword-using"&gt;Understanding TypeScript’s Newest Keyword: &lt;code&gt;using&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;One of the reasons I appreciate TypeScript’s place in the Node.js ecosystem is how they approach incoming JS proposals, and how eager and willing they are to bring these new advancements to the ecosystem early enough to get excited, but late enough to trust it. &lt;code&gt;using&lt;/code&gt; is a reflection of the upcoming ECMA TC39 proposal for more explicit handling of “temporary” connections (DB executions, file handlers, etc), and since it has made it far enough to be eventually adopted into JS proper, TypeScript is more than happy to prepare me by adopting it now. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://spin.atomicobject.com/2023/06/05/javascript-backtick-strings-wrong/"&gt;Backtick Strings vs &lt;code&gt;URLSearchParams&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The title of the article linked above is a _little _clickbait-y but hey, I read it and I am glad I did. The React documentation provides an example of building a URL string to query an API using template literals or “backtick strings”. However, as the author correctly points out, this is not the best tool for the job. Template literals will _work _but aren’t made for creating serializable strings. For that, we have &lt;code&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"&gt;URLSearchParams&lt;/a&gt;&lt;/code&gt;, which will properly escape parameter values, among other things.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rails/rails/pull/48339"&gt;Removing Active Storage Objects via Form POST&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Gone are the days of needing to reach for clunky conditionals to massage Active Storage-related params when using direct uploads! Previously, to remove an Active Storage object from a record it would need to be explicitly set to &lt;code&gt;nil&lt;/code&gt;. This was all well and good until you would try to do it on form submission and receive an error because the passed value in the &lt;code&gt;params&lt;/code&gt; was &lt;em&gt;actually&lt;/em&gt; an empty string. Now, setting the value to &lt;code&gt;nil&lt;/code&gt; or an empty string yields the same result. 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://mattbrictson.com/blog/gateway-pattern"&gt;The Gateway Pattern&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Especially on large projects, my services directory admittedly ends up looking a bit like a junk drawer. So, if you’re like me and wrap all external API communication in service objects, you’ll be glad you found this article. A gateway is used to formalize the boundary between your app’s domain and an external API, translating between the two. This is more specific and nuanced than how I typically use service objects, and helps clean up the codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://shopify.engineering/improving-the-developer-experience-with-ruby-lsp"&gt;Shopify’s Ruby LSP in VSCode&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I was shopping around for a simpler way to auto-format my Ruby code with minimal extensions and config. In my research I came across the Ruby LSP (Language Server Protocol) created by Shopify, who maintain one of the most well-known commercial Rails monoliths. This article describes the LSP and the VSCode integration of it, but it also includes a nice dive into LSPs in general.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://survey.stackoverflow.co/2023/#overview"&gt;Stack Overflow Releases Their 2023 Developer Survey&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here at The Gnar, we love a good developer survey. Admittedly, this is my first experience with the one released by Stack Overflow (SO). There are a bunch of interesting takeaways but I loved reading about how Postgres is now the most loved, admired, &lt;em&gt;and&lt;/em&gt; popular relational database (this is true here at The Gnar too - we have a whole &lt;a href="https://www.thegnar.com/blog/history-tracking-with-postgres"&gt;series&lt;/a&gt; on some of its lesser-known features). SO also includes a new section on the prevalence of AI search tools where ChatGPT (unsurprisingly) is sitting pretty with 83% of professional respondents leveraging it in the past year.&lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/alxjrvs"&gt;Alex Jarvis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mikestone14"&gt;Mike Stone&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/taylorkearns"&gt;Taylor Kearns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>ruby</category>
      <category>architecture</category>
      <category>rails</category>
    </item>
    <item>
      <title>Metaprogramming in Ruby: Advanced Level</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Fri, 30 Jun 2023 19:15:47 +0000</pubDate>
      <link>https://forem.com/thegnarco/metaprogramming-in-ruby-advanced-level-5e83</link>
      <guid>https://forem.com/thegnarco/metaprogramming-in-ruby-advanced-level-5e83</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is the third in a series focused on the application of Ruby metaprogramming. If you’re just starting to learn about metaprogramming, “&lt;a href="https://www.thegnar.com/blog/metaprogramming-in-ruby-beginner-level"&gt;Metaprogramming in Ruby: Beginner Level&lt;/a&gt;” is a great place to get started. For those seeking a more practical example of metaprogramming, check out “&lt;a href="https://www.thegnar.com/blog/metaprogramming-in-ruby-intermediate-level"&gt;Metaprogramming in Ruby: Intermediate Level&lt;/a&gt;”. In this article, we’ll discuss how a few popular Ruby gems make use of metaprogramming to solve everyday programming problems.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you go out for a walk, do you bring a paddle with you? Of course not! A paddle would be pointless. It’s only when you’re up the creek that a paddle is invaluable. &lt;/p&gt;

&lt;p&gt;So too it goes with metaprogramming.&lt;/p&gt;

&lt;p&gt;Welcome to the final installment of our &lt;em&gt;Metaprogramming in Ruby&lt;/em&gt; series. Up to this point, we’ve been going through relatively simple, handcrafted Ruby metaprogramming examples. In the &lt;a href="https://www.thegnar.com/blog/metaprogramming-in-ruby-beginner-level"&gt;beginner level post&lt;/a&gt;, we discussed how to use Ruby &lt;code&gt;define_method&lt;/code&gt; and &lt;code&gt;send&lt;/code&gt; to dynamically create methods. And in the &lt;a href="https://www.thegnar.com/blog/metaprogramming-in-ruby-intermediate-level"&gt;intermediate level post&lt;/a&gt;, we put those concepts into practice with a slightly more practical example.&lt;/p&gt;

&lt;p&gt;This time, we’re going to look at how metaprogramming is used in the wild by diving into the code underlying popular Ruby gems. The libraries we’ll be looking at are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/heartcombo/devise"&gt;devise&lt;/a&gt;: An authentication library designed for Rails&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/thoughtbot/factory_bot"&gt;factory_bot&lt;/a&gt;: A fixtures replacement&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rspec"&gt;rspec&lt;/a&gt;: A testing library&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ruby metaprogramming in the &lt;code&gt;devise&lt;/code&gt; gem
&lt;/h2&gt;

&lt;p&gt;Of the gems we’re analyzing today, this is probably the most straightforward example of metaprogramming in Ruby. &lt;/p&gt;

&lt;p&gt;When initially setting up devise in your project, you generally run &lt;code&gt;rails generate devise MODEL&lt;/code&gt;, where &lt;code&gt;MODEL&lt;/code&gt; is the name of your devise model. So if you wanted your users to have a model name of &lt;code&gt;User&lt;/code&gt; , you’d run &lt;code&gt;rails generate devise User&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To make this example a little clearer, let’s assume you run &lt;code&gt;rails generate devise Gnarnian&lt;/code&gt;, which will make your devise model &lt;code&gt;Gnarnian&lt;/code&gt; (that’s what we call ourselves at Gnar).&lt;/p&gt;

&lt;p&gt;After migrating, you’ll get access to a slew of helpers created by the generator, including some nifty url and path helpers like &lt;code&gt;new_gnarnian_session_path&lt;/code&gt;, &lt;code&gt;gnarnian_session_path&lt;/code&gt;, and &lt;code&gt;destroy_gnarnian_session_path&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;But that’s not all! As you add third-party sign in methods to your &lt;code&gt;app/models/gnarnian.rb&lt;/code&gt; file, you additionally get access to &lt;em&gt;those&lt;/em&gt; path helpers! For instance, you can add &lt;code&gt;:omniauthable, omniauth_providers: [:google_oauth2]&lt;/code&gt; to your devise modules to set up Google sign in; that should provide you with &lt;code&gt;user_google_oauth2_omniauth_authorize_path&lt;/code&gt; for redirecting users to Google sign in.&lt;/p&gt;

&lt;p&gt;At its core, this is made possible by &lt;a href="https://github.com/heartcombo/devise/blob/ec0674523e7909579a5a008f16fb9fe0c3a71712/lib/devise/controllers/url_helpers.rb"&gt;lib/devise/controllers/url_helpers.rb&lt;/a&gt;, which uses &lt;code&gt;define_method&lt;/code&gt; to create the path helpers, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/devise/controllers/url_helpers.rb&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate_helpers!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="k"&gt;begin&lt;/span&gt;
    &lt;span class="n"&gt;mappings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mappings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ss"&gt;:used_helpers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniq&lt;/span&gt;
    &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;URL_HELPERS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mappings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;module_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:url&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;path_or_url&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
        &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}#{&lt;/span&gt;&lt;span class="n"&gt;module_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path_or_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="ss"&gt;"&lt;/span&gt;

        &lt;span class="n"&gt;define_method&lt;/span&gt; &lt;span class="nb"&gt;method&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;resource_or_scope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;scope&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Mapping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_scope!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resource_or_scope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;router_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mappings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;router_name&lt;/span&gt;
          &lt;span class="n"&gt;context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;router_name&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;router_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_devise_route_context&lt;/span&gt;
          &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="si"&gt;}#{&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;module_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;path_or_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ruby metaprogramming in the &lt;code&gt;factory_bot&lt;/code&gt; gem
&lt;/h2&gt;

&lt;p&gt;Factory Bot is considered by many to be a must-have tool for testing Rails projects. The &lt;code&gt;factory_bot&lt;/code&gt; gem actually uses metaprogramming concepts in a couple of places, but here we’ll focus on the use of traits, callbacks, and the &lt;code&gt;evaluator&lt;/code&gt; argument.&lt;/p&gt;

&lt;p&gt;For the sake of example, let’s say you have &lt;code&gt;articles&lt;/code&gt; and &lt;code&gt;authors&lt;/code&gt; tables. Each &lt;code&gt;Article&lt;/code&gt; belongs to a specific &lt;code&gt;Author&lt;/code&gt; and each &lt;code&gt;Author&lt;/code&gt; can have many &lt;code&gt;Articles&lt;/code&gt;. You could create a basic factory like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/factories/authors.rb&lt;/span&gt;

&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:article&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"MyString"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"MyText"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;published&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;author&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But Factory Bot also provides callbacks that allow you to execute code for a given strategy. So if you’d like to run code after calling &lt;code&gt;create&lt;/code&gt;, then you could write something like &lt;code&gt;after(:create) do &amp;lt;something&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now let’s assume an &lt;code&gt;Author&lt;/code&gt; has written &lt;code&gt;Books&lt;/code&gt; that you need to access in your tests; to generate &lt;code&gt;Books&lt;/code&gt; written by your &lt;code&gt;Author&lt;/code&gt;, you could make something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# spec/factories/authors.rb&lt;/span&gt;

&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:author&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;transient&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;book_names&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'The Color of Magic'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="nb"&gt;name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'Terry Pratchett'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;trait&lt;/span&gt; &lt;span class="ss"&gt;:has_books&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="no"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;book_names&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;book_name&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:book&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="n"&gt;book_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;author: &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that you can use &lt;code&gt;evaluator&lt;/code&gt; to access transient properties. So in your test, you could write &lt;code&gt;create(:author, :has_books, book_names: ['Equal Rites', 'Mort'])&lt;/code&gt;, which would create two books with the provided names and the same &lt;code&gt;Author&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This flexible and powerful behavior is facilitated by the Ruby &lt;code&gt;define_method&lt;/code&gt; and &lt;code&gt;method_missing&lt;/code&gt; blocks found in &lt;a href="https://github.com/thoughtbot/factory_bot/blob/4a37cb64090d6354a719e8c5ef73653f5d242017/lib/factory_bot/evaluator.rb"&gt;factory_bot/lib/factory_bot/evaluator.rb&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# lib/factory_bot/evaluator.rb (selected snippets)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;method_missing&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond_to?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="no"&gt;SyntaxRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_attribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;instance_methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;private_instance_methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;include?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;undef_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@cached_attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="vi"&gt;@cached_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="vi"&gt;@cached_attributes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;instance_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more detailed examples, check out the &lt;a href="https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md#with-callbacks"&gt;getting started docs&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Ruby metaprogramming in the &lt;code&gt;rspec-core&lt;/code&gt; gem
&lt;/h2&gt;

&lt;p&gt;At long last, we’ve arrived at our final Ruby metaprogramming example: the 800-lb gorilla that is &lt;code&gt;rspec&lt;/code&gt; and its many associated gems. Of the three examples discussed here, &lt;code&gt;rspec&lt;/code&gt; uses metaprogramming most extensively. This makes some intuitive sense given that we’re talking about a full-fledged testing framework.&lt;/p&gt;

&lt;p&gt;That being said, the code and documentation for &lt;code&gt;rspec&lt;/code&gt; is generally clear and descriptive, making it a fantastic repository for learning about metaprogramming techniques. In &lt;a href="https://github.com/rspec/rspec-core/blob/8caecca0b9b299ccbaa5c7ea5dd885ab42cd57d3/lib/rspec/core/dsl.rb"&gt;rspec-core/lib/rspec/core/dsl.rb&lt;/a&gt;, for example, the implementation is spelled out in code comments.&lt;/p&gt;

&lt;p&gt;Let’s create an example for illustration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="s2"&gt;"posts/index"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :view&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"renders a list of posts"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="c1"&gt;# ...something&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Creates RSpec::ExampleGroups::PostsIndex&lt;/span&gt;
&lt;span class="c1"&gt;# $ RSpec::ExampleGroups::PostsIndex.describe&lt;/span&gt;
&lt;span class="c1"&gt;# $  =&amp;gt; RSpec::ExampleGroups::ArticlesIndex::Anonymous&lt;/span&gt;
&lt;span class="c1"&gt;# $ RSpec::ExampleGroups::PostsIndex.examples&lt;/span&gt;
&lt;span class="c1"&gt;# $  =&amp;gt; [#&amp;lt;RSpec::Core::Example "renders a list of posts"&amp;gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each spec, RSpec will construct the &lt;code&gt;RSpec::ExampleGroups::Example&lt;/code&gt; subclass. Note as well that &lt;code&gt;RSpec::ExampleGroups::Examples::Anonymous.describe&lt;/code&gt; will increment the id appended to the end of &lt;code&gt;RSpec::ExampleGroups::Examples::Anonymous&lt;/code&gt; (e.g., &lt;code&gt;Anonymous_2&lt;/code&gt;, &lt;code&gt;Anonymous_3&lt;/code&gt;, &lt;code&gt;Anonymous_4&lt;/code&gt;, etc.).&lt;/p&gt;

&lt;p&gt;When you create your spec file with &lt;code&gt;RSpec.describe&lt;/code&gt;, behind the scenes your arguments are being passed to &lt;code&gt;dsl.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rspec-core/lib/rspec/core/dsl.rb&lt;/span&gt;
&lt;span class="c1"&gt;# In this case, `args` are `["posts/index", {:type=&amp;gt;:view}]`&lt;/span&gt;
&lt;span class="c1"&gt;# and `example_group_block` is the block of code representing your spec &lt;/span&gt;

&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;__send__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:define_method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ExampleGroup&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__send__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;group&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those arguments are then passed to &lt;code&gt;RSpec::Core::ExampleGroup&lt;/code&gt;, which determines if the block is top-level and, if so, defines a new &lt;code&gt;ExampleGroup&lt;/code&gt; subclass.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rspec-core/lib/rspec/core/example_group.rb (selected snippets)&lt;/span&gt;
&lt;span class="c1"&gt;# In this case, `name` is `:describe`&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_example_group_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="n"&gt;idempotently_define_singleton_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;thread_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Support&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;thread_local_data&lt;/span&gt;
    &lt;span class="n"&gt;top_level&lt;/span&gt;   &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;ExampleGroup&lt;/span&gt;

    &lt;span class="n"&gt;registration_collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;top_level&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;thread_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:in_example_group&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="s2"&gt;"Creating an isolated context from within a context is "&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
                &lt;span class="s2"&gt;"not allowed. Change `RSpec.&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;` to `&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;` or "&lt;/span&gt; &lt;span class="p"&gt;\&lt;/span&gt;
                &lt;span class="s2"&gt;"move this to a top-level scope."&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

        &lt;span class="n"&gt;thread_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:in_example_group&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
        &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;example_groups&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;children&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;begin&lt;/span&gt;
      &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shift&lt;/span&gt;
      &lt;span class="n"&gt;combined_metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;
      &lt;span class="n"&gt;combined_metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt; &lt;span class="no"&gt;Hash&lt;/span&gt;
      &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;combined_metadata&lt;/span&gt;

      &lt;span class="n"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registration_collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;ensure&lt;/span&gt;
      &lt;span class="n"&gt;thread_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:in_example_group&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;top_level&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;DSL&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expose_example_group_alias&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registration_collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;subclass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_it_up&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registration_collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;module_exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;example_group_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;example_group_block&lt;/span&gt;

  &lt;span class="c1"&gt;# The LetDefinitions module must be included _after_ other modules&lt;/span&gt;
  &lt;span class="c1"&gt;# to ensure that it takes precedence when there are name collisions.&lt;/span&gt;
  &lt;span class="c1"&gt;# Thus, we delay including it until after the example group block&lt;/span&gt;
  &lt;span class="c1"&gt;# has been eval'd.&lt;/span&gt;
  &lt;span class="no"&gt;MemoizedHelpers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_helpers_on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subclass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;subclass&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned subclass, in this case, would be &lt;code&gt;RSpec::ExampleGroups::PostsIndex&lt;/code&gt;. Calling &lt;code&gt;subclass.module_exec&lt;/code&gt; will step through the &lt;code&gt;example_group_block&lt;/code&gt; and define &lt;code&gt;Example&lt;/code&gt;s (i.e., tests) for the &lt;code&gt;RSpec::ExampleGroups::PostsIndex&lt;/code&gt; subclass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rspec-core/lib/rspec/core/example_group.rb&lt;/span&gt;
&lt;span class="c1"&gt;# In this case, `name` is `:it`&lt;/span&gt;
&lt;span class="c1"&gt;# and `all_args` is `renders a list of posts`&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define_example_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extra_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
  &lt;span class="n"&gt;idempotently_define_singleton_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;all_args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;all_args&lt;/span&gt;

    &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Metadata&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build_hash_from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:skip&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Pending&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;NOT_YET_IMPLEMENTED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extra_options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Core&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Example&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the &lt;code&gt;ExampleGroups&lt;/code&gt; subclass (i.e., the spec) and its &lt;code&gt;Examples&lt;/code&gt; (i.e., the tests within the spec) have been defined, the runner is called to execute the tests!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# rspec-core/lib/rspec/core/runner.rb&lt;/span&gt;
&lt;span class="c1"&gt;# If we're running only this spec, `example_groups` would be&lt;/span&gt;
&lt;span class="c1"&gt;# a single-member array containing `RSpec::ExampleGroups::PostsIndex`&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_specs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;examples_count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@world&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;example_count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;example_groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;examples_passed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples_count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;reporter&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="vi"&gt;@configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_suite_hooks&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;examples_count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="vi"&gt;@configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fail_if_no_examples&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="vi"&gt;@configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure_exit_code&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;example_groups&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reporter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;all?&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;exit_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;examples_passed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Is metaprogramming in Ruby pointless?
&lt;/h2&gt;

&lt;p&gt;If you’ve read all three installments in this series, then firstly – thank you! We hope we adequately addressed your Ruby metaprogramming questions, or at least inspired curiosity.&lt;/p&gt;

&lt;p&gt;Secondly, you’ve probably noticed we reiterated &lt;em&gt;ad nauseum&lt;/em&gt; that metaprogramming is a “break glass in case of emergency” kind of tool.&lt;/p&gt;

&lt;p&gt;So let’s wrap this up by addressing the elephant in the room one last time: is Ruby metaprogramming useful to the average developer? Our hope is that these three articles have proven to you that the answer should be an emphatic, “YES”....&lt;/p&gt;

&lt;p&gt;…followed by a cautiously muttered, “under the right circumstances and for specific use-cases.”&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development/ruby-on-rails-development"&gt;builds Ruby on Rails applications&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>programming</category>
    </item>
    <item>
      <title>Meet The Gnarnians: Taylor</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Thu, 29 Jun 2023 17:56:14 +0000</pubDate>
      <link>https://forem.com/thegnarco/meet-the-gnarnians-taylor-56k0</link>
      <guid>https://forem.com/thegnarco/meet-the-gnarnians-taylor-56k0</guid>
      <description>&lt;h2&gt;
  
  
  Gnarnian [nahr-nee-uhn] &lt;em&gt;noun&lt;/em&gt;: An employee of The Gnar Company
&lt;/h2&gt;

&lt;p&gt;In our &lt;em&gt;Meet The Gnarnians&lt;/em&gt; series, we unravel the stories, experiences, and passions that drive the folks on our talented team at The Gnar. Through a collection of interview-style questions, you’ll get a sneak peek into daily life on our fully-remote team, some epic origin stories, and answers to some questions as weird and wonderful as our team itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Basics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where are you located?&lt;/strong&gt; Charlestown, MA&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is your Role?&lt;/strong&gt; Software developer / grumpy old man&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When did you join the Gnar?&lt;/strong&gt; 2016&lt;/p&gt;

&lt;h2&gt;
  
  
  If you were in the middle of a zombie apocalypse, who are three people you'd want on your team?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;My wife Lauren: she's the most practical person I know. The kids we can leave behind.&lt;/li&gt;
&lt;li&gt;Nick Maloney. I'm not saying he's already prepared for this exact scenario, but he's probably pretty close.&lt;/li&gt;
&lt;li&gt;Zach Galifianakis. I just feel like someone would need to lighten the mood.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What’s the last song you played or are listening to right now?
&lt;/h2&gt;

&lt;p&gt;"Rust" by Lagwagon is generally running through my head a few times a week. &lt;/p&gt;

&lt;h2&gt;
  
  
  In your role, do you have any specializations or areas of focus you really enjoy doing?
&lt;/h2&gt;

&lt;p&gt;From a technical perspective I'm a Rubyist and a Javascripter. I have had a lot of fun and made a lot of web applications armed with these very powerful tools. Being a full-stack developer means I never get tired of writing back-end or front-end code, as I get a pretty good mix of both all year round.&lt;/p&gt;

&lt;p&gt;From a career perspective, I have always gravitated toward the people side of the work. Building software is fun, but seeing what it means for a founder and their users is what makes the work exciting for me. Consulting has given me an opportunity to build software and build relationships at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you weren’t in your current role, what would you be doing?
&lt;/h2&gt;

&lt;p&gt;If I didn't work at the Gnar, I would probably be starting a coffee roasting business. I have been a hobbyist coffee roaster for some time now, and have put most of my Gnar anniversary gifts towards grinders, roasters, espresso machines, even a refractometer! Google that one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What has your experience been at Gnar?
&lt;/h2&gt;

&lt;p&gt;I was the first full-time hire at The Gnar, more than six years ago. When I first met Mike (I already knew Nick), the company was located in the conference room of another company. There was a big white board with all of the client work organized on it, two large desks, about six chairs, and cables everywhere. I said to myself ""this is definitely where I want to work."" &lt;/p&gt;

&lt;p&gt;Since that day I have upgraded offices four times, and I have watched the team grow from four to twenty-five. And throughout all of this change and growth, my sense of belonging and pride in the company has only grown. It's been a pleasure thus far.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's your favorite part of working at Gnar?
&lt;/h2&gt;

&lt;p&gt;The people. First and foremost, if Mike and Nick were not the people they are, this company would not be what it is. The trickle-down effect is that we have hired really great team members. Strong developers, designers, and relationship managers, of course. But as importantly, we've hired people with interesting perspectives, different ideas, and bold opinions. And mutual respect is table stakes. It makes for this evolving culture of growth and energy, pulled in a slightly different direction by each new hire.&lt;/p&gt;

&lt;p&gt;Also clapping. There's a lot of clapping.&lt;/p&gt;

&lt;h2&gt;
  
  
  What advice would you give someone who is just starting out in your industry?
&lt;/h2&gt;

&lt;p&gt;Ask questions early and often. Whether it's a question to a colleague about writing code or a question to a client about a requirement, make sure you understand exactly what is happening and what is needed. Nobody will ever fault you for wanting to get it right.&lt;/p&gt;

&lt;h2&gt;
  
  
  Outside of work, what do you enjoy doing?
&lt;/h2&gt;

&lt;p&gt;I really enjoy gardening when I'm outside and reading fiction when I'm inside. I grew up in the Rocky Mountains, so winter sports are a big part of my life. I have used the term "gnar" many times prior to working here.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about &lt;a href="https://www.thegnar.com/about"&gt;The Gnar and our team&lt;/a&gt;.&lt;/em&gt; &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>culture</category>
      <category>community</category>
    </item>
    <item>
      <title>Meet The Gnarnians: Erica</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Thu, 01 Jun 2023 17:50:11 +0000</pubDate>
      <link>https://forem.com/thegnarco/meet-the-gnarnians-erica-e52</link>
      <guid>https://forem.com/thegnarco/meet-the-gnarnians-erica-e52</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Gnarnian [nahr-nee-uhn] &lt;em&gt;noun&lt;/em&gt;:&lt;/strong&gt; An employee of The Gnar Company
&lt;/h2&gt;

&lt;p&gt;In our &lt;em&gt;Meet The Gnarnians&lt;/em&gt; series, we unravel the stories, experiences, and passions that drive the folks on our talented team at The Gnar. Through a collection of interview-style questions, you’ll get a sneak peek into daily life on our fully-remote team, some epic origin stories, and answers to some questions as weird and wonderful as our team itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Basics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where are you located?&lt;/strong&gt; Philadelphia, PA&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is your Role?&lt;/strong&gt; Design Director&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When did you join the Gnar?&lt;/strong&gt; November 2022&lt;/p&gt;

&lt;h2&gt;
  
  
  What's the best advice you've ever received?
&lt;/h2&gt;

&lt;p&gt;When I was in college I used to order enough Chinese food to last me a couple of days (very normal, we all did it). The best part of not only having cheap meals that would last the week but the large amount of fortune cookies they would include in the assumed large family sized order. Most of the time the messages you get are pretty repetitive, "Don't hold onto things. that require a tight grip,"  "A faithful friend is a strong defense, " or like "Good luck will find you soon". However, this one night while I was stressing over my end of year portfolio, I opened one that said, "You can do anything but not everything", then another that said, "Don't Panic". Both very different than you'd typically get. I kept them, and taped them to a post card I pinned to my wall, and carried them with me until I lost them in a move. So yeah, I could say that was the best advice I've received thanks to my delivery food.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s the last song you played or are listening to right now?
&lt;/h2&gt;

&lt;p&gt;Currently listening to "I'm a Princess" by Bill Wurtz. &lt;/p&gt;

&lt;h2&gt;
  
  
  What was your career journey up until joining the Gnar?
&lt;/h2&gt;

&lt;p&gt;My entire career has been in the design industry but not the same mediums. When I graduated I worked for small NYC design studios, designing identities specifically for hotels, restaurants, and food &amp;amp; beverage companies. That work included a lot of print design, web design and creation of die-lines for physical product packaging. The work I did for restaurants focused around menus, branding for the interior, signage, and their websites. After working for a few small studios I moved to a global agency in NYC, and developed design systems for healthcare and consumer brands like Vonage, Amtrak, and Nestle Waters. At some point everyone was switching from agencies to tech start-ups and I thought I'd might try that out too. While working at various tech start-ups, I got to wear many hats (marketing hats, product management hats, and even an office design hat), was able to build my experience in product design, lead several small design teams, and most recently was part of a fintech start-up that went public during my tenure there.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you weren’t in your current role, what would you be doing?
&lt;/h2&gt;

&lt;p&gt;There was a point in my life where I was torn between culinary school and art school. Obviously I picked art school, but if I didn't I would 100% be doing Pastry/baking. &lt;/p&gt;

&lt;h2&gt;
  
  
  What is your ideal work/desk set-up?
&lt;/h2&gt;

&lt;p&gt;I recently moved into my own house and for the first time had the freedom to put my desk in its own room other than my bedroom or living room. I built a wall-length desk with a counter top, added some table legs and desk drawers. Since it's technically a kitchen countertop I don't have to worry about the condensation from all my iced coffees ruining it. I also keep a lot of design books within reach, pens, my sketchbook, and a Wacom tablet. On the other end of the desk is a work area for my partner and the xbox. With summer coming, I'll probably move to take some calls on my back patio, but I prefer to work from my office. It's important to me to maintain that feeling of stepping away from my "work area" for a mental break which is why I tend to only be productive from one area versus multiple set-ups throughout my house. &lt;/p&gt;

&lt;h2&gt;
  
  
  How do you structure your work day or week?
&lt;/h2&gt;

&lt;p&gt;One thing about me that has been forever true, I am NOT a morning person. I am not productive at all. I start my day either taking a brisk walk with my dog to a local coffee shop or just the walk and then make coffee at home. Either way I need coffee, coffee is a priority. Knowing my focus isn't the best in the morning I tend to designate that time then to things like, checking emails, planning my tasks for the day, and attending stand-ups for various projects. One of the best things about working remotely is I actually am more productive earlier than when I used to commute to work. Before lunch, I typically spend time doing any additional research, and looking up design inspiration. By the afternoon I am more heads down on client work which ranges from writing user research plans, designing, connecting with contract designers, and working internal projects for The Gnar like, designing social posts, writing blog posts, or documenting internal processes. At 3pm my dog reminds me it's time for her walk, and after that 'm usually heads down for the rest of the afternoon to early evening. Being a night-owl I will often be back online after 8pm for anything that is still swirling around in my head. &lt;/p&gt;

&lt;h2&gt;
  
  
  Outside of work, what do you enjoy doing?
&lt;/h2&gt;

&lt;p&gt;My partner and I own a small gelato shop in Fishtown, Philadelphia. If I'm not there helping him in the shop, I'm either out with my dog, playing video games or visiting friends in NYC for the weekend.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about &lt;a href="https://www.thegnar.com/about"&gt;The Gnar and our team&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>design</category>
      <category>culture</category>
      <category>community</category>
    </item>
    <item>
      <title>Gnarly Learnings from May 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Wed, 31 May 2023 16:23:20 +0000</pubDate>
      <link>https://forem.com/thegnarco/gnarly-learnings-from-may-2023-3clo</link>
      <guid>https://forem.com/thegnarco/gnarly-learnings-from-may-2023-3clo</guid>
      <description>&lt;p&gt;At The Gnar we are always reading, watching, and listening in order to keep our skills sharp and our perspectives fresh. Here are some of the resources we learned from this month.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://nextjs.org/docs/app/building-your-application/data-fetching#automatic-fetch-request-deduping"&gt;Automatic Fetch Request Deduping with Next.js&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;NextJS focuses a lot on optimization. So it was no surprise to learn about &lt;a href="https://nextjs.org/docs/app/building-your-application/data-fetching#automatic-fetch-request-deduping"&gt;fetch request deduping&lt;/a&gt;. When using fetch with Next, any GET requests with the same input will be cached, so that if there are multiple requests for the same resource during a render cycle or between page refreshes, Next will not make the HTTP request again.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://fonts.google.com/variablefonts"&gt;Variable Fonts in Google Fonts&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I am always deliberating over which and how many font weights and variants to import from Google Fonts. I want them all, but am I willing to accept the file size overhead? Luckily Google has come up with a significant improvement to web fonts: variable fonts. These fonts allow for a single font to be selected, and that font can be adjusted by weight, slant, and more. Read more about &lt;a href="https://fonts.google.com/knowledge/introducing_type/introducing_variable_fonts"&gt;variable fonts&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-rewhere"&gt;Active Record’s &lt;code&gt;rewhere&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It now takes two hands to count the number of years I have been working with Ruby on Rails and I &lt;em&gt;still&lt;/em&gt; regularly discover new concepts and methods. This month, it was &lt;code&gt;rewhere&lt;/code&gt;, an Active Record method that allows you to change a previously set &lt;code&gt;where&lt;/code&gt; condition for an attribute. If you’re thinking “Hey…that sounds an awful lot like the behavior of &lt;code&gt;unscope&lt;/code&gt;” you’d be right! That’s because it is a shorthand for &lt;code&gt;unscope(where: conditions.keys).where(conditions)&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://web.dev/import-maps-in-all-modern-browsers/"&gt;Cross-Browser Support for Import Maps&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A modern choice for including and reusing JavaScript code in web apps is ES modules. There are a variety of ways to implement ES modules but &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap"&gt;import maps&lt;/a&gt; have been gaining popularity in recent years. Popularity, in this case, equates to industry adoption. For example, Rails 7 (released in 2021) allowed us to break away from the Node.js and webpack bundling strategy and leverage import maps instead. Now, import maps are compatible across the three major browser engines which will make developing with them much easier.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rails/rails/blob/83217025a171593547d1268651b446d3533e2019/activerecord/lib/active_record/connection_adapters/abstract/schema_statements.rb#L381"&gt;Migration Method: &lt;code&gt;create_join_table&lt;/code&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I was late to this party! When creating a join table in Rails, there's no need to pass &lt;code&gt;id: false&lt;/code&gt; to a typical table creation method. Instead, just reach for &lt;a href="https://api.rubyonrails.org/v7.0.4.2/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-create_join_table"&gt;&lt;code&gt;create_join_table&lt;/code&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://github.com/taylorkearns"&gt;Taylor Kearns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>nextjs</category>
      <category>ruby</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Gnarly News April 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Sun, 30 Apr 2023 14:51:31 +0000</pubDate>
      <link>https://forem.com/thegnarco/gnarly-news-april-2023-1efo</link>
      <guid>https://forem.com/thegnarco/gnarly-news-april-2023-1efo</guid>
      <description>&lt;p&gt;The software development landscape is constantly changing. As a software consultancy, it’s our responsibility to keep our finger on the pulse of the industry. Here are some headlines that caught our attention recently. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://rubyonrails.org/2023/4/6/rails-world-is-coming"&gt;Rails World: A New Conference in 2023&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Conference season is upon us! There have been many announcements as of late about conference dates and CFPs but one of the most buzzworthy for us is Rails World. Rails World is a brand-new conference that is sponsored by the Rails Foundation and will be held in Amsterdam, Netherlands (😏)  on October 5th and 6th. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.ruby-lang.org/en/news/2023/03/30/ruby-3-2-2-released/"&gt;Ruby 3.2.2 Released&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Ruby 3.2.2 was released at the end of last month. There’s nothing super shiny in this release but there are some important security fixes in the &lt;code&gt;&lt;a href="https://www.ruby-lang.org/en/news/2023/03/30/redos-in-time-cve-2023-28756/"&gt;Time&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href="https://www.ruby-lang.org/en/news/2023/03/28/redos-in-uri-cve-2023-28755/"&gt;URI&lt;/a&gt;&lt;/code&gt; classes that you’ll want to get in ASAP.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://nextjs.org/blog/next-13-3"&gt;Next.js Version 13.3 Released&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This release is all about community-requested features! Four main improvements are described in the release notes such as the ability to dynamically generate sitemaps and Open Graph images. It also adds SPA support for Server Components and adds some new advanced routing features for the App Router.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>ruby</category>
      <category>rails</category>
      <category>news</category>
    </item>
    <item>
      <title>Gnarly Learnings from April 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Sun, 30 Apr 2023 14:39:47 +0000</pubDate>
      <link>https://forem.com/thegnarco/gnarly-learnings-from-april-2023-501g</link>
      <guid>https://forem.com/thegnarco/gnarly-learnings-from-april-2023-501g</guid>
      <description>&lt;p&gt;At the Gnar we are always reading, watching, and listening in order to keep our skills sharp and our perspectives fresh. Here are some of the resources we learned from this month.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.zdnet.com/article/css-to-get-support-for-trigonometry-functions/"&gt;CSS Supports Trigonometry Functions&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Trig functions in CSS make it easier to rotate objects and let us avoid using magic numbers. For example, &lt;code&gt;sin(60 degrees)&lt;/code&gt; expresses the developer's intent more clearly than &lt;code&gt;0.866025&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/rails/rails/pull/47630"&gt;Action Mailer Now Supports *_deliver Callbacks&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Three callbacks (&lt;code&gt;before_deliver&lt;/code&gt;, &lt;code&gt;after_deliver&lt;/code&gt;, &lt;code&gt;around_deliver&lt;/code&gt;) have been added to Action Mailer. You may have strong feelings about callbacks and I probably tend to agree with you, but &lt;em&gt;sometimes&lt;/em&gt; they are the right tool to reach for. The described use cases for this include updating an Active Record model’s &lt;code&gt;delivered_at&lt;/code&gt; (which is especially useful when dealing with async deliveries), handling delivery errors, and executing tasks that require a delivery provider’s &lt;code&gt;message_id&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://dev.to/github/a-beginners-guide-to-prompt-engineering-with-github-copilot-3ibp"&gt;Useful Tips for Using GitHub Copilot&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Like any other tool, GitHub Copilot has a learning curve. This article from GitHub developer advocate &lt;a href="https://blackgirlbytes.dev/about-me"&gt;Rizel Scarlett&lt;/a&gt; gives us a few tips to quickly improve the quality of Copilot suggestions. One thing I didn’t realize: Copilot uses your open tabs to provide context for the questions you ask! That tip in and of itself really helped me make better use of the tool in my day-to-day work. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://developer.chrome.com/blog/css-text-wrap-balance/"&gt;CSS text-wrap: balance&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Chrome Canary now includes a new experimental CSS feature, &lt;code&gt;text-wrap: balance&lt;/code&gt;, that evaluates line breaks to balance blocks of text. As developers, we often look for solutions that help to keep text consistent regardless of final font size, screen size, and language, which are often unknown. This property aims to mitigate those concerns, though it is not without its challenges. It is currently limited to four wrapped lines (and under) and presents some performance considerations due to the iterative technique used to perform the wrapping. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html#inferring-within-conditional-types"&gt;TypeScript’s infer&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;TypeScript’s &lt;a href="https://www.typescriptlang.org/docs/handbook/2/conditional-types.html"&gt;Conditional types&lt;/a&gt; have allowed developers to build internal type logic based on types provided to the conditional—&lt;code&gt;Model&amp;lt;string&amp;gt;&lt;/code&gt; might have subtle differences in signature from &lt;code&gt;Model&amp;lt;number&amp;gt;&lt;/code&gt;. Now, TypeScript has given us &lt;code&gt;infer&lt;/code&gt;, allowing us to identify and refer to dynamic type values from within a Conditional type. It &lt;em&gt;sounds&lt;/em&gt; like a lot - and it kind of is, the uses for this are pretty niche! - but once you wrap your head around it, you’ll have a powerful new TypeScript tool in your arsenal. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="//github.com/alxjrvs"&gt;Alex Jarvis&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/jrthreadgill"&gt;Royce Threadgill&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/zelaznik"&gt;Steve Zelaznik&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>rails</category>
      <category>github</category>
      <category>css</category>
    </item>
    <item>
      <title>Design Systems: What They Are and Why You Need One</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Fri, 28 Apr 2023 19:50:18 +0000</pubDate>
      <link>https://forem.com/thegnarco/design-systems-what-they-are-and-why-you-need-one-44lo</link>
      <guid>https://forem.com/thegnarco/design-systems-what-they-are-and-why-you-need-one-44lo</guid>
      <description>&lt;p&gt;By definition a design system is a complete set of standards intended to manage design at scale using reusable components and patterns. When properly implemented, a design system provides a lot of benefits not only to design teams but development teams as well. &lt;/p&gt;

&lt;p&gt;Imagine you are tasked with baking a cake. You know what it looks like from the outside and from your extensive experience eating cakes you know that cakes have layers, frosting and, sometimes, decorations. But do you know just from looking at it what ingredients were used to make it? To successfully make your cake you will need to know more than just the experience of eating cake. You need to know the ingredients and how to use them. Creating a design system is a lot like creating a recipe. &lt;/p&gt;

&lt;p&gt;Taking this very relatable scenario one step further, you are now a cake baking superstar. Customers love you, you're getting very busy and you need to hire staff. As you look to expand your cake baking enterprise you know you want scalability, consistency, to maintain productivity, and to share your cake knowledge with the new bakers so they can follow the recipes. So what do you do? You create a recipe book. &lt;/p&gt;

&lt;p&gt;In designing digital products, as in establishing your very own cake shop, the overarching goal is to be able to build for scale. Having to produce digital products (or cakes) without any clear guidance on how to do it isn’t very helpful. &lt;/p&gt;

&lt;p&gt;When creating a design system one method that I like to reference is &lt;a href="https://atomicdesign.bradfrost.com/chapter-2/"&gt;Brad Frost’s Atomic Design&lt;/a&gt;. Atomic design is a methodology composed of five distinct stages working together to create interface design systems in a more deliberate and hierarchical manner. Frost defines the five stages of Atomic Design as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Atoms&lt;/strong&gt;: The foundational building blocks that comprise all user interfaces. “Atoms” include basic HTML elements like form labels, inputs, buttons, colors, fonts and others that can’t be broken down any further without ceasing to be functional.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Molecules&lt;/strong&gt;: In interfaces, molecules are relatively simple groups of UI elements functioning together as a unit. For example, a form label, search input, and button can join together to create a search form molecule. Creating simple components helps UI designers and developers do one thing and do it well. Burdening a single pattern with too much complexity makes software unwieldy. Therefore, creating simple UI molecules makes testing easier, encourages reusability, and promotes consistency throughout the interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Organisms&lt;/strong&gt;: Organisms are relatively complex UI components composed of groups of molecules and/or atoms and/or other organisms. These organisms form distinct sections of an interface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Templates&lt;/strong&gt;: Page-level objects that place components into a layout and articulate the design’s underlying content structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pages&lt;/strong&gt;: Specific instances of templates that show what a UI looks like with real representative content in place. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Atomic Design method is not a linear process&lt;/strong&gt;, but rather a mental model to help us think of user interfaces as both a cohesive whole and a collection of parts at the same time. While this method is appropriate for designing and developing evergreen design systems for digital products, there are plenty of other &lt;a href="https://www.uxpin.com/studio/blog/best-design-system-examples/"&gt;existing design systems&lt;/a&gt; that designers often use such as:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://material.io/"&gt;Google Material Design&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://polaris.shopify.com/"&gt;Shopify Design System Polaris&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.apple.com/design/"&gt;Apple Human Interface Guidelines&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So far, we've primarily focused on the methods of understanding the value of creating and following a design system for digital products, but the practice of design systems also extends to how a brand is expressed through other communication touchpoints. Similar to design systems for digital products, designers create traditional “&lt;a href="https://www.ebaqdesign.com/blog/brand-guidelines"&gt;Brand Guides&lt;/a&gt;” which focus on the overall strategy and consistency of a brand as it relates to a logo, colors, and brand personality, which include visual examples of how the brand should be executed in various communications. &lt;/p&gt;

&lt;p&gt;It’s been common practice to create brand guidelines ahead of website design in order to ensure that the brand look and feel is in place first. The problem is that these brand guidelines often don't include guidance for digital products. With the digitization of work, products, and communication, this is now changing.&lt;/p&gt;

&lt;p&gt;The practice of creating Design Systems for digital products is still relatively new and rapidly evolving. In 2005, Jenifer Tidwell published her book &lt;a href="https://www.amazon.com/Designing-Interfaces-Patterns-Effective-Interaction/dp/1492051969"&gt;Designing Interfaces&lt;/a&gt; followed by Yahoo! publishing their open source &lt;a href="https://www.libraryinformationsystem.org/yui2/Index.html"&gt;Yahoo User Interface Library&lt;/a&gt; (YUI) in 2006. In 2008, phrases such as "CSS Libraries", and “pattern portfolios” paved the way for the creation of "&lt;a href="https://24ways.org/2011/front-end-style-guides/"&gt;Front End Style Guides&lt;/a&gt;" and "&lt;a href="http://uxdesignmasterclass.com/wp-content/uploads/2018/02/UXDMC-02-09-Style-Tiles.pdf"&gt;Style Tiles&lt;/a&gt;". In 2011, Twitter shared their own open-source framework around design patterns, Blueprint (later renamed Bootstrap), and Google's Material Design followed in 2014. &lt;/p&gt;

&lt;p&gt;Since then we've seen design systems from &lt;a href="https://carbondesignsystem.com/"&gt;IBM&lt;/a&gt;, &lt;a href="https://airbnb.design/building-a-visual-language/"&gt;AirBnb&lt;/a&gt;, and &lt;a href="https://www.uber.com/blog/introducing-base-web/"&gt;Uber&lt;/a&gt; that encompass not just their brand guidelines, but also full-scale design systems.&lt;/p&gt;

&lt;p&gt;Whether you’re a small design team or a large enterprise business, defining, scaling and streamlining your design ensures a more holistic user experience, saves money and prepares you for the future. To quote former IBM president Thomas J. Watson Jr., "Good design is good business", and there is no easier way to bring value to your business than establishing a strong design system. &lt;/p&gt;

&lt;p&gt;When developing design systems at The Gnar, we take a holistic approach to ensure that all aspects of your unique brand seamlessly integrate into your digital experiences. From website content to software error messages, each touchpoint with your customer is an opportunity to reinforce your brand values alongside a consistent look and feel.&lt;/p&gt;

&lt;p&gt;After establishing your design system, the work doesn’t end there. Technology is rapidly evolving and so are the needs of your users. Thinking back to our super star baker, the original cake that won over customers years ago may not be as good as it is today, or perhaps you’ve added a lot of new desserts as a result of customer requests and the products are longer as consistent as they once were. &lt;/p&gt;

&lt;p&gt;In my next post, I will break down why it’s important to reevaluate your current design system in order to see what is and isn’t working through an analysis commonly referred to as a "Design Audit". &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Credit where credit is due:&lt;/strong&gt; There is an open issue related to author re-assignment on this platform. This post was written by the one and only &lt;a class="mentioned-user" href="https://dev.to/ericaknauss"&gt;@ericaknauss&lt;/a&gt; and published by the Content Manager at The Gnar Company.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/services/ux-brand-design"&gt;builds design systems&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>designsystem</category>
      <category>designpatterns</category>
      <category>design</category>
    </item>
    <item>
      <title>Gnarly News March 2023</title>
      <dc:creator>Ethan Fertsch</dc:creator>
      <pubDate>Wed, 29 Mar 2023 19:03:11 +0000</pubDate>
      <link>https://forem.com/thegnarco/gnarly-news-march-2023-3f2g</link>
      <guid>https://forem.com/thegnarco/gnarly-news-march-2023-3f2g</guid>
      <description>&lt;p&gt;The software development landscape is constantly changing. As a software consultancy, it’s our responsibility to keep our finger on the pulse of the industry. Here are some headlines that caught our attention recently. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://code.womenwhocode.com/100-technologists-to-watch/"&gt;Women Who Code Opens Nominations for 100 Technologists to Watch&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It's Women's History Month, and Women Who Code are opening nominations for top technologists. WHC's mission is to "empower diverse women to excel in technology careers". Let the voting begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://twitter.com/hashtag/ruby30th"&gt;Ruby Turns 30&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I was in my first year of life when Ruby was released. I wasn’t slinging code until much, much later but the metric provided perspective on the longevity of the language and how far it has come. We ♡ you Ruby, and we’re not alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://tuple.app/blog/the-realness"&gt;Tuple Now Supports Linux and “Mob” Pairing&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Tuple is a great tool for pair programming and they just shipped with a bunch of new features! The Tuple team teased the linked article back in November 2022 and recently sent an email to subscribers boasting a Slack integration, Linux support, increased call sizes of up to 6 people, and more. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contributors
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/efertsch"&gt;Ethan Fertsch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/taylorkearns"&gt;Taylor Kearns &lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Learn more about how The Gnar &lt;a href="https://www.thegnar.com/software-development"&gt;builds software&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>news</category>
      <category>ruby</category>
      <category>womenintech</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
