<?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: Rost Khaniukov</title>
    <description>The latest articles on DEV Community by Rost Khaniukov (@rostkhaniukov).</description>
    <link>https://dev.to/rostkhaniukov</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%2F2148030%2F875e43dd-f719-4dcb-85f7-9cf628ff8d9e.jpg</url>
      <title>DEV Community: Rost Khaniukov</title>
      <link>https://dev.to/rostkhaniukov</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rostkhaniukov"/>
    <language>en</language>
    <item>
      <title>Transforming DevEx Through Bulk Refactoring (and How AI Can Assist)</title>
      <dc:creator>Rost Khaniukov</dc:creator>
      <pubDate>Mon, 30 Sep 2024 19:19:24 +0000</pubDate>
      <link>https://dev.to/rostkhaniukov/transforming-devex-through-bulk-refactoring-and-how-ai-can-assist-44ph</link>
      <guid>https://dev.to/rostkhaniukov/transforming-devex-through-bulk-refactoring-and-how-ai-can-assist-44ph</guid>
      <description>&lt;p&gt;Developer Experience today is not just a trend but a real way of boosting efficiency in tech companies. A suitable set of tools, well-established processes, and a supportive environment can transform an ordinary workday into a productive and inspiring one. What’s better: spending a whole day on the creative process and developing interesting solutions or getting stuck in monotonous configuration updates for dozens of repositories? The answer is obvious. When a developer is satisfied, they not only perform their job better but also generate new ideas that drive the company's progress.&lt;/p&gt;

&lt;p&gt;I have mentioned dozens of repositories not accidentally — it’s my sore point. Throughout my career, I’ve repeatedly faced situations where I had to make the &lt;em&gt;same&lt;/em&gt; type of changes across &lt;em&gt;a huge number&lt;/em&gt; of repositories. With each such task, work that was supposed to be creative turned into something mechanical: cloning the repository, creating a branch, making changes, committing, pushing, submitting a pull request, and repeating endlessly. Of course, we’re not the only ones who’ve struggled with this. Spotify team, for instance, shared their experience in a blog post, explaining how they handled updating the Log4j version across all their projects after the notorious security issue.&lt;/p&gt;

&lt;p&gt;Sooner or later, after a series of repetitive tasks, every developer eventually thinks: "Why not automate this process?". The idea is simple but effective — to write a CLI tool that automates the manual work across multiple repositories: creating branches, modifying files, pushing them to GitHub, and creating Pull Requests using the GitHub API. Building such a tool itself can be more interesting than making manual changes, and on top of that, we won't have to waste time on manual tasks since we'll automate them. Such an approach temporarily enhances the Developer Experience, but soon you’ll realize it’s &lt;em&gt;not enough&lt;/em&gt;. Time will pass, and you'd like to move to the next level. Instead of writing separate scripts for each task, it becomes easier to describe everything &lt;em&gt;declaratively&lt;/em&gt;, for instance, in YAML. Something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;definition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;update-license&lt;/span&gt;
  &lt;span class="na"&gt;commit-message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Update&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;license"&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
      &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;package.json&lt;/span&gt;
      &lt;span class="na"&gt;op&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jq&lt;/span&gt;
      &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.license | startswith("UNLICENSED") | not&lt;/span&gt;

  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;do&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;take-file&lt;/span&gt;
          &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;package.json&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replace&lt;/span&gt;
          &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
          &lt;span class="na"&gt;what&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;"license":\s+"(.*)"'&lt;/span&gt;
          &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;"license":&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;"UNLICENSED"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To begin with, parameters &lt;code&gt;to&lt;/code&gt; and &lt;code&gt;commit-message&lt;/code&gt; are simply names for the branch and commit so that we won't dwell on them. Let’s move on to something more interesting: the &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;steps&lt;/code&gt; blocks. The &lt;code&gt;if&lt;/code&gt; block allows us to define which specific repositories need changes. After all, updating all 10, 100, or 1000 repositories in the organization is not always necessary. In our case, the filter selects only those repositories where the package.json file contains the &lt;code&gt;license&lt;/code&gt; attribute that doesn’t start with UNLICENSED. In the &lt;code&gt;steps&lt;/code&gt; block, we describe the specific actions: we take the file and replace the &lt;code&gt;license&lt;/code&gt; attribute with UNLICENSED. It’s simple but &lt;em&gt;effective&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Creating such a configuration and running a CLI tool to apply it takes much less time than manually updating even ten repositories. And when we're talking about hundreds of repositories, the need for such a tool becomes clear — it's an obvious requirement for any team.&lt;/p&gt;

&lt;p&gt;The next logical step would be to expand the tool's capabilities: add more ways to filter repositories and provide more options for manipulating files (since regular expressions aren't a silver bullet, moreover, not every developer can easily handle them — and we want to make sure they don’t have to struggle with them, right?). But frankly, diving into these details here would be too boring.&lt;/p&gt;

&lt;p&gt;So, let’s wrap up with something more spectacular, like in the finale of my favorite childhood show, MythBusters — a real explosion! Let’s throw the YAML manifest out of the script. If writing it is so simple that even a trainee can handle it, then why not delegate this task to  &lt;strong&gt;&lt;em&gt;AI&lt;/em&gt;&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;To begin with, we’ll train the AI to create manifests, and then it will be able to generate them independently, receiving only a description of the task from the developer. Since the AI configuration part is always the same, we’ll hide it under the hood to avoid bothering developers with unnecessary details. In the end, the generated manifest will be passed to our CLI tool — and it works!&lt;/p&gt;

&lt;p&gt;To finish, here’s a video showing a PoC demo.&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/Mf6uPfjgxgM"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>devex</category>
      <category>refactoring</category>
      <category>tooling</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
