<?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>DEV Community: Dominik</title>
    <description>The latest articles on DEV Community by Dominik (@dominik_alberski).</description>
    <link>https://dev.to/dominik_alberski</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%2F239160%2F3d203814-7fa6-4691-9941-3437b2b0bd63.jpeg</url>
      <title>DEV Community: Dominik</title>
      <link>https://dev.to/dominik_alberski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/dominik_alberski"/>
    <language>en</language>
    <item>
      <title>Rails Integration Testing with Fixtures: A Practical Approach for Complex Data Sets</title>
      <dc:creator>Dominik</dc:creator>
      <pubDate>Tue, 07 May 2024 07:47:48 +0000</pubDate>
      <link>https://dev.to/dominik_alberski/rails-integration-testing-with-fixtures-a-practical-approach-for-complex-data-sets-mce</link>
      <guid>https://dev.to/dominik_alberski/rails-integration-testing-with-fixtures-a-practical-approach-for-complex-data-sets-mce</guid>
      <description>&lt;h4&gt;
  
  
  The Challenge of Realistic Test Data
&lt;/h4&gt;

&lt;p&gt;I recently faced a unique challenge in writing integration specs for a Rails application. The goal was to simulate real-world complexity within our test environment, involving interactions across 13 models like orders, line items, and products. The catch? I needed to generate around 10,000 interrelated records, reflecting the kind of volume and complexity we see in production. Typically, I'd reach for the &lt;code&gt;factory_bot&lt;/code&gt; gem for test data generation, but due to the sheer volume and the need for persistent data, this method proved too slow. My ideal solution needed to enable the insertion of a large volume of data into the database efficiently, mirroring production data characteristics as closely as possible.&lt;/p&gt;

&lt;h4&gt;
  
  
  Solution: Tapping into Production DB and Fixtures
&lt;/h4&gt;

&lt;p&gt;After exploring several avenues, I discovered that leveraging Rails' default fixtures, combined with our staging database (which mirrors the last three months of production records), provided an unexpectedly effective solution. Here’s how I transformed real production data into a manageable, anonymized test suite:&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fixture_creator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;anonymized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&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="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/spec/fixtures/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.yml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s2"&gt;"w+"&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;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;fixture_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in_batches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;of: &lt;/span&gt;&lt;span class="mi"&gt;100&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;batch&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;batch&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;record&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;fixture_data&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;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&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;fixture_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&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;anonymized&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="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt; &lt;span class="n"&gt;fixture_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_yaml&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;h4&gt;
  
  
  Exploring the Code
&lt;/h4&gt;

&lt;p&gt;In this snippet, &lt;code&gt;fixture_creator&lt;/code&gt; function does the heavy lifting:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Batch Processing&lt;/strong&gt;: By processing the data in batches (&lt;code&gt;model.in_batches(of: 100)&lt;/code&gt;), we efficiently handle large volumes of data without overwhelming memory usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unique Keys for Fixtures&lt;/strong&gt;: We create unique keys for each record (&lt;code&gt;"#{record.id}_#{fixture_data.size + 1}"&lt;/code&gt;), ensuring each entry in our fixtures file is distinct and easily identifiable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anonymization&lt;/strong&gt;: The &lt;code&gt;anonymized&lt;/code&gt; parameter is a hash that overrides sensitive attributes with dummy values, crucial for maintaining data privacy.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach significantly speeds up the process compared to individually creating records via &lt;code&gt;factory_bot&lt;/code&gt;. By directly exporting data from a staging environment (a subset of our production data), we ensure our tests are running against data that closely reflects real user interactions, both in volume and complexity.&lt;/p&gt;

&lt;h4&gt;
  
  
  Anonymization and Security
&lt;/h4&gt;

&lt;p&gt;One key aspect of using production data for testing is ensuring all sensitive information is thoroughly anonymized. In my case, the &lt;code&gt;anonymized&lt;/code&gt; hash includes mappings of original attribute names to anonymized values, applied to each record. This step is crucial not just for security and privacy, but also for complying with legal obligations like GDPR.&lt;/p&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;This method of generating fixtures from production data presents a robust way to create realistic, high-volume test environments for Rails applications. It's particularly useful when the test scenarios are complex, and the realism of data interrelations is crucial. While this approach worked well in my case, it's important to tailor the solution to the specific needs and constraints of your project and always prioritize data security in any testing strategy.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>testing</category>
      <category>fixtures</category>
    </item>
    <item>
      <title>Memoization in Modern Ruby: How a Shape-Based Approach to Instance Variables Lookup Impacts Performance.</title>
      <dc:creator>Dominik</dc:creator>
      <pubDate>Thu, 02 Nov 2023 11:32:39 +0000</pubDate>
      <link>https://dev.to/dominik_alberski/memoization-in-modern-ruby-using-a-shape-based-approach-to-instance-variables-lookup-2lok</link>
      <guid>https://dev.to/dominik_alberski/memoization-in-modern-ruby-using-a-shape-based-approach-to-instance-variables-lookup-2lok</guid>
      <description>&lt;p&gt;Memoization is a classic technique in Ruby programming, greatly assisting in boosting performance. With Ruby's ongoing evolution, particularly towards a shape-based method in instance variable lookups, thoughtfully implementing memoization can be beneficial. Inspired by Jean Boussier's insights on RailsAtScale.com, this post highlights some suggested best practices.&lt;/p&gt;

&lt;h4&gt;
  
  
  Why Consider Memoization?
&lt;/h4&gt;

&lt;p&gt;Memoization helps cache results of resource-heavy function calls, aiming to speed up subsequent executions. Ruby’s newer shape-based mechanism for instance variable lookups suggests organizing objects based on their instance variables. This approach influences performance and memory usage, but it's important to note that using memoization indiscriminately could lead to a range of object shapes, which might inadvertently affect performance. Understanding these subtleties can be helpful for developers looking to craft efficient and thoughtful Ruby code.&lt;/p&gt;

&lt;h4&gt;
  
  
  Suggested Best Practices
&lt;/h4&gt;

&lt;p&gt;Aligning with Ruby's shape-based approach and optimizing memoization strategies, developers might consider the following approaches:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mindful Use of Memoized Variables&lt;/strong&gt;: It’s generally a good idea to keep memoized variables to a minimum. Ideally, aiming for one or two per class helps. If you find yourself needing more, initializing these variables to &lt;code&gt;nil&lt;/code&gt; in the constructor could be a proposed better approach:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;     
        &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;   
    &lt;span class="k"&gt;end&lt;/span&gt;    

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_value&lt;/span&gt;     
        &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="n"&gt;compute_expensive_value&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Handling Falsy Values with Tokens&lt;/strong&gt;: When dealing with memoized values that might return falsy results, using a token could be a neat way to differentiate between an uninitialized state and a value that's legitimately falsy:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyClass&lt;/span&gt;   
    &lt;span class="no"&gt;NOT_SET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;   
    &lt;span class="n"&gt;private_constant&lt;/span&gt; &lt;span class="ss"&gt;:NOT_SET&lt;/span&gt;    
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;     
        &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;NOT_SET&lt;/span&gt;   
    &lt;span class="k"&gt;end&lt;/span&gt;    

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;expensive_value&lt;/span&gt;     
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;NOT_SET&lt;/span&gt;     &lt;span class="vi"&gt;@expensive_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;compute_expensive_value&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;h4&gt;
  
  
  Wrapping Up
&lt;/h4&gt;

&lt;p&gt;Adjusting to Ruby's shape-based approach for variable lookups, we might consider refining our memoization tactics to help maintain efficient performance and thoughtful memory usage. For those interested in exploring this topic further, Jean Boussier provides a deeper dive in his article at &lt;a href="https://railsatscale.com/2023-10-24-memoization-pattern-and-object-shapes/"&gt;RailsAtScale&lt;/a&gt;. It's a thought-provoking read for anyone interested in evolving their Ruby coding practices in harmony with the latest language developments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This summary reflects ideas from Jean Boussier's article published on October 24, 2023, on RailsAtScale.com. To broaden your understanding, the original article is well worth a read.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>performance</category>
    </item>
  </channel>
</rss>
