<?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: Federico Ramirez</title>
    <description>The latest articles on DEV Community by Federico Ramirez (@gosukiwi).</description>
    <link>https://dev.to/gosukiwi</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%2F1507%2F161972.jpeg</url>
      <title>DEV Community: Federico Ramirez</title>
      <link>https://dev.to/gosukiwi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gosukiwi"/>
    <language>en</language>
    <item>
      <title>Vim Advanced Search and Replace</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Sun, 01 Oct 2023 19:30:08 +0000</pubDate>
      <link>https://dev.to/gosukiwi/vim-advanced-search-and-replace-4akn</link>
      <guid>https://dev.to/gosukiwi/vim-advanced-search-and-replace-4akn</guid>
      <description>&lt;p&gt;I find search and replace to be a remarkably interesting topic, because it touches on so many Vim concepts.&lt;/p&gt;

&lt;p&gt;When I started using Vim, one of the first things I wanted to do was search for some text in my project and replace it with something else.&lt;/p&gt;

&lt;p&gt;Unfortunately for me, it was not as simple as I had initially thought :)&lt;/p&gt;

&lt;p&gt;In this post I will show how several different ways to search and replace text in Vim. From the obvious, beginner-friendly way, to the more advanced, &lt;em&gt;vimmish&lt;/em&gt; way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before we begin: Reading key sequences
&lt;/h2&gt;

&lt;p&gt;I will use Vim's format to describe sequences of keys. That means &lt;code&gt;&amp;lt;C-r&amp;gt;&lt;/code&gt; means press the &lt;code&gt;CONTROL&lt;/code&gt; key, and while holding it, press the &lt;code&gt;r&lt;/code&gt; key. &lt;code&gt;&amp;lt;CR&amp;gt;&lt;/code&gt; means &lt;code&gt;ENTER&lt;/code&gt; key, &lt;code&gt;&amp;lt;Esc&amp;gt;&lt;/code&gt; means &lt;code&gt;ESCAPE&lt;/code&gt;, &lt;code&gt;&amp;lt;Space&amp;gt;&lt;/code&gt; means &lt;code&gt;SPACEBAR&lt;/code&gt;, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Searching in a single file
&lt;/h2&gt;

&lt;p&gt;Let's start with our most simple use-case: Searching for some text in a single file.&lt;/p&gt;

&lt;p&gt;This is quite a common need. In my regular Vimming, I think one of my most used (and favorite) keys is &lt;code&gt;*&lt;/code&gt;. In NORMAL mode, simply press &lt;code&gt;*&lt;/code&gt; on top of a word, and Vim will highlight all the instances of that word in your current buffer.&lt;br&gt;
If you want to go to the next instance, press &lt;code&gt;n&lt;/code&gt;, if you want to go back, press &lt;code&gt;N&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I use that a lot for typos, if I want to make sure I didn't make a typo on some word, and I know that word is already defined somewhere in the same file, I quickly press &lt;code&gt;*&lt;/code&gt; to see if other words highlight.&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;


&lt;p&gt;It's also useful to quickly navigate to all instances of that word, for example, navigate through all the usages of some variable in your current file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help 03.8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help *&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help n&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replacing in a single file: One by one
&lt;/h2&gt;

&lt;p&gt;Another quite common need is to rename an identifier. This can be tricky when the variable exists in multiple files, but for local variables, it's amazingly easy.&lt;/p&gt;

&lt;p&gt;You can use the &lt;code&gt;.&lt;/code&gt; operator to &lt;em&gt;repeat the last thing I did in INSERT mode&lt;/em&gt;, together with &lt;code&gt;*&lt;/code&gt; and &lt;code&gt;n&lt;/code&gt; you can easily do fine-grained replacements.&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;


&lt;p&gt;With this approach you can skip some matches, so it's great when you don't want to just replace all matches, and instead want to choose which ones you want to operate on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section Help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help 04.3&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Replacing in a single file: Bulk
&lt;/h2&gt;

&lt;p&gt;Alternatively, you can replace all matches in the file in one go, with the &lt;code&gt;:substitute&lt;/code&gt; command, or just &lt;code&gt;:s&lt;/code&gt;, as it's normally used.&lt;/p&gt;

&lt;p&gt;Without flags, &lt;code&gt;:substitute&lt;/code&gt; will only replace one match per line. Most of the time, the &lt;code&gt;g&lt;/code&gt; flag is passed, to substitute all matches. You can also pass the &lt;code&gt;c&lt;/code&gt; flag so Vim asks for confirmation before doing each replacement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;%s&lt;span class="sr"&gt;/this/&lt;/span&gt;that/gc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If you already were searching for something using &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;?&lt;/code&gt;, then Vim populates the search register for you. When using &lt;code&gt;:s&lt;/code&gt;, and the search string is empty, Vim will use the search register to perform the replacement.&lt;/p&gt;

&lt;p&gt;For example, you were searching for all instances of the word &lt;code&gt;this&lt;/code&gt; by typing &lt;code&gt;/this&lt;/code&gt;. You then notice you want to change them.&lt;/p&gt;

&lt;p&gt;You can now simply type &lt;code&gt;:%s//that/&lt;/code&gt; to run the replacement. Vim "remembers" our last search.&lt;/p&gt;

&lt;p&gt;You can also manually use the register by typing &lt;code&gt;&amp;lt;C-r&amp;gt;&lt;/code&gt; followed by the register you want to use, such as &lt;code&gt;"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:%s/&amp;lt;C-r&amp;gt;"/replacement/g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help registers&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help 10.2&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help i_CTRL-R&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Searching in multiple files
&lt;/h2&gt;

&lt;p&gt;To search across multiple files, Vim provides the &lt;code&gt;:vimgrep&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;It works out of the box. For example, you can run the following command to search for all instances of &lt;code&gt;SomeModelClass&lt;/code&gt; inside the &lt;code&gt;app/models&lt;/code&gt; directory:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:vimgrep SomeModelClass app/models
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Nice! By default, Vim will populate the &lt;em&gt;quickfix&lt;/em&gt; list with the search results, but it won't display it. You can open the quickfix window with the &lt;code&gt;:copen&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;While that works, it's not the best. You see &lt;code&gt;:vimgrep&lt;/code&gt; uses Vim's internal implementation of grep, which is totally compatible but terribly slow. Not really what you want to use for most modern software projects (&lt;em&gt;ahem&lt;/em&gt; &lt;code&gt;node_modules&lt;/code&gt; &lt;em&gt;ahem&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Experienced Vim users will instead use something like &lt;a href="https://github.com/BurntSushi/ripgrep"&gt;ripgrep&lt;/a&gt; or &lt;a href="https://github.com/ggreer/the_silver_searcher"&gt;ag&lt;/a&gt; for searching across multiple files.&lt;/p&gt;

&lt;p&gt;Being the good first-class UNIX citizen that Vim is, it integrates nicely with external programs, so we can easily set this up:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="nb"&gt;grepprg&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;rg\ &lt;span class="p"&gt;--&lt;/span&gt;&lt;span class="k"&gt;vimgrep&lt;/span&gt;\ &lt;span class="p"&gt;--&lt;/span&gt;smart&lt;span class="p"&gt;-&lt;/span&gt;case
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We can now use the &lt;code&gt;:grep&lt;/code&gt; command to search in our files, using &lt;code&gt;ripgrep&lt;/code&gt;!&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;grep&lt;/span&gt; myvariable app&lt;span class="sr"&gt;/models/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :vimgrep&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :grep&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help grepprg&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help quickfix&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Replacing in multiple files
&lt;/h2&gt;

&lt;p&gt;Once you have performed your search, and have the quickfix list populated with all your matches, you can then run a replacement with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:cfdo %s/pattern/replacement/g
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;:cfdo&lt;/code&gt; command will take each file in your quickfix list and apply a command to it. We use the &lt;code&gt;:substitute&lt;/code&gt; command (a.k.a &lt;code&gt;:s&lt;/code&gt;) to do the actual replacement.&lt;/p&gt;

&lt;p&gt;That's it! This approach might seem complicated to non-Vim users, but it is made of smaller pieces, composed together to create one big action.&lt;/p&gt;

&lt;p&gt;Being composable, I can replace commands here and there. For example, instead of replacing, I could actually delete all lines containing the match, with &lt;code&gt;:global&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:cfdo %g/&amp;lt;my-grep-pattern&amp;gt;/d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help :cfdo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :cdo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help :global&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Filtering results
&lt;/h2&gt;

&lt;p&gt;What if you want to make a replacement, but only to &lt;strong&gt;some&lt;/strong&gt; of the files in your quickfix list? Do you run a second, more specific search?&lt;/p&gt;

&lt;p&gt;No need! Vim provides a plugin named &lt;code&gt;cfilter&lt;/code&gt;, which can helps us in this case. You can use it by adding this to your &lt;code&gt;.vimrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;packadd&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; cfilter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Check it out with &lt;code&gt;:help cfilter&lt;/code&gt;. It gives you a nifty little command to filter the results of the quickfix list: &lt;code&gt;:Cfilter&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;:Cfilter app/models  # display only entries matching `app/models`
:Cfilter! .swp       # remove entries matching `.swp`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That's great, and most of the time, it's just enough. But sometimes, it might make sense to cherry-pick the entries you want to keep, by going one by one over them. For that, I have mapped &lt;code&gt;x&lt;/code&gt; to remove the entry under the cursor:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:QfRemoveAtCursor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; abort
  &lt;span class="k"&gt;let&lt;/span&gt; currline &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nb"&gt;items&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getqflist&lt;/span&gt;&lt;span class="p"&gt;()-&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nb"&gt;index&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;index&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; currline &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;setqflist&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'r'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'normal '&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; currline &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'G'&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

augroup quickfix
  autocmd&lt;span class="p"&gt;!&lt;/span&gt;
  autocmd &lt;span class="nb"&gt;FileType&lt;/span&gt; qf nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;x&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;SID&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;QfRemoveAtCursor&lt;span class="p"&gt;()&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
augroup END
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now whenever I press &lt;code&gt;x&lt;/code&gt; on top of an entry in the quickfix list window, it gets deleted.&lt;/p&gt;

&lt;p&gt;Trimming the quickfix list like this is useful, not only to find what you are looking for, but to perform batch operations on all matches with &lt;code&gt;:cdo&lt;/code&gt; and &lt;code&gt;:cfdo&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help usr_40.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help usr_41.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  :Grep
&lt;/h2&gt;

&lt;p&gt;Remember we had to manually run &lt;code&gt;:copen&lt;/code&gt; to see the quickfix list after every&lt;br&gt;
&lt;code&gt;:grep&lt;/code&gt;? Let's make that automatic by creating a custom &lt;code&gt;:Grep&lt;/code&gt; command to&lt;br&gt;
open the quickfix list for us:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:Grep&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; abort
  &lt;span class="k"&gt;let&lt;/span&gt; pattern &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; pattern &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nb"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'silent! grep! "'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;pattern&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'"-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'" '&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;path&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' | redraw! | copen'&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

command&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=+&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;file&lt;/span&gt; Grep &lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;s:Grep&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Neat! Now all we have to do is use &lt;code&gt;:Grep&lt;/code&gt; instead of &lt;code&gt;:grep&lt;/code&gt;! We even get file autocompletion for grep's optional second parameter.&lt;/p&gt;
&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help usr_40.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help key-mapping&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help mapleader&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help i_CTRL-R&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  :Replace
&lt;/h2&gt;

&lt;p&gt;Following on &lt;code&gt;:Grep&lt;/code&gt;, let's implement a &lt;code&gt;:Replace&lt;/code&gt; command, so our whole search and replace quest can be reduced to just running two easy to remember commands.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'s:latest_greps'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s:latest_greps&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:Grep&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt; abort
  &lt;span class="k"&gt;let&lt;/span&gt; pattern &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; pattern &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;s:latest_greps&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;pattern&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nb"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'silent! grep! "'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;pattern&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'"-'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'" '&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;path&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;' | redraw! | copen'&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;s:Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;original&lt;span class="p"&gt;,&lt;/span&gt; replacement&lt;span class="p"&gt;)&lt;/span&gt; abort
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nv"&gt;a:original&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="p"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;a:replacement&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="k"&gt;endif&lt;/span&gt;

  &lt;span class="nb"&gt;execute&lt;/span&gt; &lt;span class="s1"&gt;'cfdo %s/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nb"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;a:original&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/'&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;a:replacement&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/ge'&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; LatestGreps&lt;span class="p"&gt;(&lt;/span&gt;ArgLead&lt;span class="p"&gt;,&lt;/span&gt; CmdLine&lt;span class="p"&gt;,&lt;/span&gt; CursorPos&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;s:latest_greps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;endfunction&lt;/span&gt;

command&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=+&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="k"&gt;file&lt;/span&gt; Grep &lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;s:Grep&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;
command&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;nargs&lt;span class="p"&gt;=+&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;customlist&lt;span class="p"&gt;,&lt;/span&gt;LatestGreps Replace &lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt; &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;s:Replace&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;args&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt;

nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;g&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;Grep&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Space&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Leader&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="k"&gt;r&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;feedkeys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':Replace&amp;lt;Space&amp;gt;&amp;lt;Tab&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'t'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Our &lt;code&gt;:Grep&lt;/code&gt; now stores a list of previous searches, so it can then be used as autocompletion for &lt;code&gt;:Replace&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;:Replace&lt;/code&gt; itself simply runs &lt;code&gt;:cfdo&lt;/code&gt; with a &lt;code&gt;:substitute&lt;/code&gt; command. It takes two arguments: a search string, and a replacement string. The search string is autocompleted, so we don't have to worry about it.&lt;/p&gt;

&lt;p&gt;Finally we map &lt;code&gt;&amp;lt;Leader&amp;gt;g&lt;/code&gt; to the &lt;code&gt;:Grep&lt;/code&gt; command, and &lt;code&gt;&amp;lt;Leader&amp;gt;r&lt;/code&gt; to the &lt;code&gt;:Replace&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;When searching, all we need to do now is press &lt;code&gt;&amp;lt;Leader&amp;gt;g&lt;/code&gt;, and type what we want. For replacing, we simply press &lt;code&gt;&amp;lt;Leader&amp;gt;r&lt;/code&gt; and type our replacement.&lt;/p&gt;


&lt;div class="ltag_asciinema"&gt;
  
&lt;/div&gt;



&lt;p&gt;Now we're talking! We can even filter the quickfix list in any way we want before doing our replacement. Or we could make the replacement confirm on each match, if we wanted to, using the &lt;code&gt;c&lt;/code&gt; flag of the &lt;code&gt;:substitute&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;You can also run all the search and replace machinery in a single file if you want, too. Simply do &lt;code&gt;:Grep my-pattern %&lt;/code&gt; to search in the current buffer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Section help
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:help usr_40.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:help usr_41.txt&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this post I showed several ways to search and replace text in Vim.&lt;/p&gt;

&lt;p&gt;It might be more complex than in regular editors, but that complexity has several advantages. Composability being one of the big ones.&lt;/p&gt;

&lt;p&gt;Composability is the way of Vim. It allows you to compose several small atoms together, through a "Vim language", into something bigger and more complex. It gives Vim users a lot of power, and it's incredibly fun to learn :)&lt;/p&gt;

&lt;p&gt;Every new thing you learn in Vim adds a lot to your final user experience, because you can compose it with all the other tools you know.&lt;/p&gt;

&lt;p&gt;Let me know of any feedback you might have - I'm still learning Vim :) - and I hope you find this useful!&lt;/p&gt;

</description>
      <category>vim</category>
      <category>coding</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Best Way to Deploy Your Own Apps</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Thu, 13 Jul 2023 19:58:00 +0000</pubDate>
      <link>https://dev.to/gosukiwi/the-best-way-to-deploy-your-own-apps-k79</link>
      <guid>https://dev.to/gosukiwi/the-best-way-to-deploy-your-own-apps-k79</guid>
      <description>&lt;p&gt;I've used &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt; in the past for a few hobby projects, but their pricing always kept me from considering it for serious projects.&lt;/p&gt;

&lt;p&gt;For tiny projects I know for certain they won't scale, Heroku was great, but for serious projects, its &lt;strong&gt;way&lt;/strong&gt; cheaper to just get your own VPS and do everything yourself, although of course, it's much more work!&lt;/p&gt;

&lt;p&gt;With services like Heroku you end up paying for management, which is a perfectly fine approach sometimes. I'm no stranger to configuring my own server, but still, I'd rather avoid it if I can.&lt;/p&gt;

&lt;p&gt;Since Heroku removed their free tier, I've been migrating my little Discord bot from server to server. My latest server was &lt;a href="https://railway.app/"&gt;Railway&lt;/a&gt;, but given they were also removing their free tier, and I couldn't find anything I liked, I just bit the bullet and set up my own VPS.&lt;/p&gt;

&lt;p&gt;I ended up deciding on &lt;a href="https://hostinger.com?REFERRALCODE=1FEDEKILLER02"&gt;Hostinger&lt;/a&gt;, because not only they give me more bang for my buck (2 vCPUs, 8GB RAM and 100GB SSD for $6.99 a month is not bad at all) but also they provide built-in weekly backups, unlike most other services that you must pay separately for that feature. They also have been in the hosting business since forever so it's a solid choice.&lt;/p&gt;

&lt;p&gt;With a VPS in place, I could certainly just manually set up everything I need, but that's just what I wanted to avoid by using services like Heroku and Railway. Then, I remembered &lt;a href="https://dokku.com/"&gt;Dokku&lt;/a&gt; and decided to &lt;a href="https://dokku.com/docs/getting-started/install/vagrant/"&gt;give it a shot&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used &lt;a href="https://developer.hashicorp.com/vagrant/downloads"&gt;Vagrant&lt;/a&gt; to try it locally, and I was surprised just how easy it was to set everything up! Just two commands and it's up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget &lt;span class="nt"&gt;-NP&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; https://dokku.com/install/v0.30.9/bootstrap.sh
&lt;span class="nb"&gt;sudo &lt;/span&gt;&lt;span class="nv"&gt;DOKKU_TAG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v0.30.9 bash bootstrap.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It uses Docker under the hood, so you can deploy your Dockerized apps very easily, and if your app doesn't use Docker, no worries! Dokku is great at just guessing your app's Buildpack. It "just works" for most languages, such as Node.js, Ruby, Python and PHP.&lt;/p&gt;

&lt;p&gt;Setting up Dokku in my VPS only took a couple of minutes following their documentation. Getting my bot up there was as easy as just setting up the environment variables with &lt;code&gt;dokku config:set&lt;/code&gt; and doing a &lt;code&gt;git push&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;What's so great about Dokku is that you can host several apps on the same server if you want. That's great for hobby projects. Create databases and apps on the fly, remove them, play with them, and don't worry about pricing. It's all included in the fixed price you pay for your VPS.&lt;/p&gt;

&lt;p&gt;If you ever need more power you can always move that app outside to either it's own Dokku server with more resources, or something like AWS to take full advantage of horizontal scaling. You can even use a mixed solution by having a few workers for your web server and a managed database on AWS with unlimited scaling. The good thing is that, by then, you'll know for certain how much resources your app consumes and what you'll need, so you can take a better informed decision.&lt;/p&gt;

&lt;p&gt;I was just blown away by how easy it was to set everything up! You can even limit resources for some of your apps, limiting things like CPU and RAM.&lt;/p&gt;

&lt;p&gt;All in all, I really recommend trying out &lt;a href="https://dokku.com/"&gt;Dokku&lt;/a&gt; if you are a developer interested in hosting your own projects. It makes it super easy to get everything you need to get up and running without having to worry about the specifics. And the price is impossible to beat!&lt;/p&gt;

&lt;p&gt;Give it a shot locally! It's so easy it feels like cheating.&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>dokku</category>
      <category>vps</category>
      <category>docker</category>
    </item>
    <item>
      <title>Vim Tips: Snippets without plugins</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Mon, 21 Mar 2022 16:08:21 +0000</pubDate>
      <link>https://dev.to/gosukiwi/vim-tips-snippets-without-plugins-18c2</link>
      <guid>https://dev.to/gosukiwi/vim-tips-snippets-without-plugins-18c2</guid>
      <description>&lt;p&gt;There are many Vim plugins to create code snippets. But did you know Vim already supports this functionality?&lt;/p&gt;

&lt;p&gt;I like relying on &lt;em&gt;vanilla&lt;/em&gt; Vim as much as possible, and keep plugins to a minimum. For that reason, I ended up using &lt;code&gt;:help abbreviations&lt;/code&gt; to make a simple snippet engine. &lt;/p&gt;

&lt;p&gt;It works so well, I'd like to share it! Below is an example of my current setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;augroup haml
  autocmd&lt;span class="p"&gt;!&lt;/span&gt;
  autocmd &lt;span class="nb"&gt;FileType&lt;/span&gt; haml inorea &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="se"&gt;        \&lt;/span&gt; table %table&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%thead&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;th&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;%header row%&lt;span class="p"&gt;}&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;BS&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;BS&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%tbody&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%td &lt;span class="p"&gt;{&lt;/span&gt;%body row%&lt;span class="p"&gt;}&lt;/span&gt;
augroup END
nnoremap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GoToNextPlaceholder &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nb"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'{%[^%]*%}'&lt;/span&gt;&lt;span class="p"&gt;)&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;va&lt;span class="p"&gt;{&lt;/span&gt;
imap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;e&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;v&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-]&amp;gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GoToNextPlaceholder
nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GoToNextPlaceholder
imap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GoToNextPlaceholder
vmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;silent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;q&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Esc&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;Plug&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;GoToNextPlaceholder
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mappings I use are &lt;code&gt;&amp;lt;C-q&amp;gt;&amp;lt;C-e&amp;gt;&lt;/code&gt; to expand, and &lt;code&gt;&amp;lt;C-q&amp;gt;&amp;lt;C-q&amp;gt;&lt;/code&gt; to go to next placeholder, but feel free to change this to whatever you like.&lt;/p&gt;

&lt;p&gt;I define snippets inside an &lt;code&gt;augroup&lt;/code&gt;, in this case, all HAML snippets are there. Each snippet ends with &lt;code&gt;ctrl-a&lt;/code&gt;, that's just so snippets don't get automatically triggered all the time, we want to manually trigger them.&lt;/p&gt;

&lt;p&gt;You can input the &lt;code&gt;&amp;lt;ctrl-a&amp;gt;&lt;/code&gt; character while typing by pressing &lt;code&gt;&amp;lt;ctrl-v&amp;gt;&amp;lt;ctrl-a&amp;gt;&lt;/code&gt; in insert mode.&lt;/p&gt;

&lt;p&gt;The snippet itself looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;autocmd &lt;span class="nb"&gt;FileType&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;my&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;filetype&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; inorea &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;my&lt;span class="p"&gt;-&lt;/span&gt;sippet&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="k"&gt;a&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;|&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;my&lt;span class="p"&gt;-&lt;/span&gt;expansion&lt;span class="p"&gt;|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;code&gt;{%placeholders%}&lt;/code&gt; in the expansion, to be navigated with &lt;code&gt;&amp;lt;C-q&amp;gt;&amp;lt;C-q&amp;gt;&lt;/code&gt;. A HAML table snippet looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight viml"&gt;&lt;code&gt;autocmd &lt;span class="nb"&gt;FileType&lt;/span&gt; haml inorea &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
&lt;span class="se"&gt;        \&lt;/span&gt; table %table&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%thead&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;th&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;%header row%&lt;span class="p"&gt;}&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;BS&lt;span class="p"&gt;&amp;gt;&amp;lt;&lt;/span&gt;BS&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%tbody&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%&lt;span class="k"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;CR&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;%td &lt;span class="p"&gt;{&lt;/span&gt;%body row%&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope you find it useful!&lt;/p&gt;

&lt;p&gt;EDIT: If you like this approach, I created an actual plugin &lt;a href="https://github.com/gosukiwi/vim-zensnippets"&gt;here&lt;/a&gt; :) It's less than 100 lines of Vimscript, so if you are into minimal, no-dependency plugins, you'll feel right at home.&lt;/p&gt;

</description>
      <category>vim</category>
      <category>snippets</category>
    </item>
    <item>
      <title>Software Design: Deep Modules</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Fri, 02 Jul 2021 00:24:55 +0000</pubDate>
      <link>https://dev.to/gosukiwi/software-design-deep-modules-2on9</link>
      <guid>https://dev.to/gosukiwi/software-design-deep-modules-2on9</guid>
      <description>&lt;p&gt;I'm reading &lt;a href="https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201"&gt;A Philosophy of Software Design&lt;/a&gt;, by John K. Ousterhout, a professor of computer science at Stanford University and the creator of the &lt;a href="https://www.tcl.tk/about/"&gt;Tcl&lt;/a&gt; programming language. &lt;/p&gt;

&lt;p&gt;According to &lt;a href="https://johz.bearblog.dev/book-review-philosophy-software-design/"&gt;this other review&lt;/a&gt; he has almost two decades of real world software experience, so he seems to know a thing or two about software design.&lt;/p&gt;

&lt;p&gt;I love software design, and I love reading different takes on it. I admit I haven't finished the book yet, but so far I love his simple yet complete approach.&lt;/p&gt;

&lt;p&gt;So far, I'd recommend it, even though I both agree and disagree on what he calls &lt;em&gt;Classitis&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Classitis
&lt;/h2&gt;

&lt;p&gt;I don't want to spoil or copy too much from his book but to make things short, let's say classes are a type of module, and he encourages modules to be deep, instead of shallow.&lt;/p&gt;

&lt;p&gt;A shallow module is module is one with a big public interface, compared to it's implementation. A deep module, is one with a small public interface, compared to it's implementation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   DEEP MODULE
  ┌────────────┐
  │            ├─────► Interface
  ├────────────┤
  │            │
  │            │
  │            ├─────► Implementation
  │            │
  │            │
  │            │
  └────────────┘

  SHALLOW MODULE
  ┌────────────┐
  │            ├─────► Interface
  │            │
  │            │
  │            │
  ├────────────┤
  │            │
  │            ├─────► Implementation
  │            │
  └────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;His argument is that shallow modules don't help to manage complexity, because the benefit they provide (hiding implementation) is dwarfed by the cost of having to learn a big, complicated public interface. Thus, they must be avoided when possible.&lt;/p&gt;

&lt;p&gt;I think he makes a great point. The example he gives (a perfect one, I must add) is the Java File API:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileInputStream&lt;/span&gt; &lt;span class="n"&gt;fileStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;BufferedInputStream&lt;/span&gt; &lt;span class="n"&gt;bufferedStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BufferedInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileStream&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ObjectInputStream&lt;/span&gt; &lt;span class="n"&gt;objectStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bufferedStream&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complexity of the &lt;code&gt;ObjectInputStream&lt;/code&gt; interface is huge. You need to know a lot of things in order to use that class. And that unknown, is complexity.&lt;/p&gt;

&lt;p&gt;Sure, the class is very flexible, but the API is not great. He calls having several small classes like this &lt;strong&gt;Classitis&lt;/strong&gt;, and says it must be avoided.&lt;/p&gt;

&lt;h2&gt;
  
  
  But... Small classes are good, right?
&lt;/h2&gt;

&lt;p&gt;Small classes are a staple of OOP languages like Smalltalk, and to some extent, Ruby inherited that.&lt;/p&gt;

&lt;p&gt;Authors like &lt;a href="https://sandimetz.com/"&gt;Sandi Metz&lt;/a&gt;, a Ruby consultant with 30+ years of experience, and a Smalltalk background, strongly &lt;a href="https://thoughtbot.com/blog/sandi-metz-rules-for-developers"&gt;advises for small classes and small methods&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Small objects seem to make following the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;Object Oriented Design Principles&lt;/a&gt; easier.&lt;/p&gt;

&lt;p&gt;So, how can two well-respected authors have polar opposite opinions? Well, for one, because software is hard, but also, because writing good, maintainable software is more an art than a mathematical formula you can blindly apply.&lt;/p&gt;

&lt;p&gt;Different people with different backgrounds and different experience reach the goal in different ways. Shocker right? 😉&lt;/p&gt;

&lt;h2&gt;
  
  
  A case for small objects
&lt;/h2&gt;

&lt;p&gt;I am biased. Being a Ruby developer, and sharing Sandi's philosophy, I love small objects with tiny interfaces. But I know sometimes, they can make things more complex.&lt;/p&gt;

&lt;p&gt;Something Sandi and John have in common is that they both care a lot about abstractions. Abstractions are very important, and they require constant refactor, in order to accommodate them to the software we are writing.&lt;/p&gt;

&lt;p&gt;Sandi says "it's better to have duplication, than the wrong abstraction". And in this sense, we can see that it's not enough to blindly follow some rules. And &lt;strong&gt;that&lt;/strong&gt; is the trick to it.&lt;/p&gt;

&lt;p&gt;Whether you approach it from the right or from the left, whether you prefer small objects or deep modules, you need a critical eye, and always be watching the design of your software.&lt;/p&gt;

&lt;p&gt;Take time to refactor, accommodate the abstractions, think about different solutions, and sometimes, recognize that you just can't come up with a good solution, in which case, it's better to leave it as it is for now, until you have more code. The more repetition you have, the easier it is to notice the pattern, and abstract it away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to the Java example
&lt;/h2&gt;

&lt;p&gt;Remember this?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;FileInputStream&lt;/span&gt; &lt;span class="n"&gt;fileStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FileInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileName&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;BufferedInputStream&lt;/span&gt; &lt;span class="n"&gt;bufferedStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BufferedInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileStream&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="nc"&gt;ObjectInputStream&lt;/span&gt; &lt;span class="n"&gt;objectStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ObjectInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bufferedStream&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ugly right? One could look at it and blame the small classes. But you could also look at it, and realize you are looking at an implementation, not an interface.&lt;/p&gt;

&lt;p&gt;What if you used a &lt;a href="https://en.wikipedia.org/wiki/Builder_pattern"&gt;builder object&lt;/a&gt; to abstract it away? I don't know much about the Java API, but in Ruby-land, it could look like this:&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="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;StreamBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;buffered: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowing the name of the classes and what it takes to instantiate them is a dependency. You can abstract those away, think of them as implementation details. The consumers of &lt;code&gt;StreamBuilder&lt;/code&gt; don't even need to know they exist.&lt;/p&gt;

&lt;p&gt;We now exposed a small interface -- only a constructor -- and hide the implementation details, which is the name of classes and how to arrange them all together.&lt;/p&gt;

&lt;p&gt;You will still need to know the name of the builder class, and what it expects in the constructor, but that can be easily documented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complexity
&lt;/h2&gt;

&lt;p&gt;It is true small classes have issues. A class will always be more complex than just a function, and debugging OOP code can feel like following Alice through the rabbit hole. You look at one object which uses another which uses another.&lt;/p&gt;

&lt;p&gt;But they also have advantages. For example, you don't have to hold several objects in your head at once, but you might need to hold a lot of state if you are debugging one big method.&lt;/p&gt;

&lt;p&gt;Also, small classes force you to separate the algorithm into smaller parts. A fundamental part of your problem could easily be intermingled and hidden away, you might not even know it exist, if it was just one big method or massive class.&lt;/p&gt;

&lt;p&gt;Yet another advantage is that the average complexity of your code will be smaller. It might not be perfect, but it will be &lt;strong&gt;consistent&lt;/strong&gt;. It will allow your software to not be consumed by it's own inevitable complexity.&lt;/p&gt;

&lt;p&gt;There's a great talk by Sandi called &lt;a href="https://www.youtube.com/watch?v=8bZh5LMaSmE"&gt;All the Little Things&lt;/a&gt; which explains this in detail.&lt;/p&gt;

&lt;p&gt;So, what's better? It depends. We know that both extremes are wrong, so it's up to you to come with a happy middle! What do &lt;strong&gt;you&lt;/strong&gt; prefer?&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>oop</category>
      <category>ruby</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Am I Senior Yet?</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Mon, 07 Sep 2020 20:47:23 +0000</pubDate>
      <link>https://dev.to/gosukiwi/am-i-senior-yet-2bgm</link>
      <guid>https://dev.to/gosukiwi/am-i-senior-yet-2bgm</guid>
      <description>&lt;p&gt;There's been some fuss at &lt;a href="https://www.reddit.com/r/programming/"&gt;/r/programming&lt;/a&gt; about a post by a developer with 2 years of experience claiming to be a senior, and evangelizing others on what they need to do to be like him.&lt;/p&gt;

&lt;p&gt;Needless to say, the post blew up, and mods had to delete it.&lt;/p&gt;

&lt;p&gt;Now I don't mean to bash the original author, he has all the right in the world to do/think whatever he wants with his title. But it does fire up an interesting topic I've been wanting to write for some time now.&lt;/p&gt;

&lt;h1&gt;
  
  
  What do I need to learn?
&lt;/h1&gt;

&lt;p&gt;That seems to be the most common question new developers ask when they want to reach &lt;em&gt;senior status&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The answer is... it's not that simple. Not only the things you need to know are many and vary from place to place, but quality also matters.&lt;/p&gt;

&lt;h1&gt;
  
  
  An analogy: Martial Arts
&lt;/h1&gt;

&lt;p&gt;Let's take martial arts as an example. As you might know, many different martial arts give you different colored belts as you progress in their system.&lt;/p&gt;

&lt;p&gt;For the sake of analogy, let's say black belt is considered Senior.&lt;/p&gt;

&lt;p&gt;Now, different systems have different ways of grading. Just like different companies have different ways of giving titles around.&lt;/p&gt;

&lt;p&gt;Some places give the student an exam every fixed amount of time, like 3 months. If they pass, they advance one step. Others have longer periods of time. And others don't even have a fixed amount of time, when the instructor thinks you are ready, he gives you the belt.&lt;/p&gt;

&lt;p&gt;The gist of it is, it's totally &lt;strong&gt;subjective&lt;/strong&gt;, it depends on the context. &lt;/p&gt;

&lt;p&gt;Some systems just want to earn money — they are called &lt;a href="https://www.urbandictionary.com/define.php?term=McDojo"&gt;McDojos&lt;/a&gt;. In those systems, it makes total sense to have frequent exams, where you pass as long as you pay.&lt;/p&gt;

&lt;p&gt;Other systems, like Brazilian Jiu-Jitsu, are more informal. At most of those places, the instructor just gives you the belt when he thinks you are ready. Maybe after competing, or maybe he just decides to test you that day.&lt;/p&gt;

&lt;p&gt;BJJ cares about the quality and transmission of their art. So it makes sense that it takes lots of years to get the black belt. Sometimes it takes 6, sometimes 10, sometimes it never comes. It depends on the person.&lt;/p&gt;

&lt;p&gt;Just like that, some companies will give you a title and keep you happy. It works for them, they want you to be happy, and to continue working for them. Evangelize about how great they are, etc. It also gives you a feeling of growth. And you surely did grow! But what some places consider black belt, others might consider white. It totally depends on the particular company.&lt;/p&gt;

&lt;h1&gt;
  
  
  The belt is so your pants dont fall
&lt;/h1&gt;

&lt;p&gt;At the end of the day, it's just a title. There's the infamous case of &lt;a href="https://en.wikipedia.org/wiki/Eddie_Bravo"&gt;Eddie Bravo&lt;/a&gt;. Being a brown belt, he submitted and won in a competition against Royler Gracie, a black belt, and not just any black belt, a direct relative of the founders of the art (needless to say he got the black belt after that match).&lt;/p&gt;

&lt;p&gt;Words associate a sound, or group of letters, to a particular meaning. But sometimes we miss the word for the actual thing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What's in a name? That which we call a rose&lt;br&gt;
By any other name would smell as sweet&lt;br&gt;
— William Shakespeare&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't get too stuck up in names. What someone means by senior others might now as architect, semi-senior, or whatever funny name companies can come up with.&lt;/p&gt;

&lt;h1&gt;
  
  
  Yeah that's all nice but...
&lt;/h1&gt;

&lt;p&gt;I know. Senior jobs pay more than junior jobs. Also, you have more chance at being hired if you are senior. So you want that title.&lt;/p&gt;

&lt;p&gt;In my opinion, everyone that has had worked on a tech job for a few years can already submit their CV to other companies as Senior. It's up to the other company to really know where you are at.&lt;/p&gt;

&lt;p&gt;If they have competent people, no matter what your title is, they will know where you are at, and whether or not you are a good fit for their team, technically speaking.&lt;/p&gt;

&lt;p&gt;If they don't have competent people, well... the hiring process gets more random. They might hire you because they like your face, or your gender, or some project you did/participated on. &lt;/p&gt;

&lt;h1&gt;
  
  
  Senior is whatever it needs to be
&lt;/h1&gt;

&lt;p&gt;Some people like being a jack of all trades, and they certainly have their place. Others, prefer specialization, and they surely have a place too. Someone good at what they do, whatever it is, will always be precious to any team.&lt;/p&gt;

&lt;p&gt;This might be a controversial opinion, but let me tell you this: Someone who does something because they enjoy it, will always be much better at what they do that someone who does it just for the money.&lt;/p&gt;

&lt;p&gt;Now, you can do both, of course. Who doesn't like money, right? But if you don't have passion for what you do, you are doing something wrong. You only have one life, better spend it doing something you like!&lt;/p&gt;

&lt;p&gt;The good news is, if you enjoy what you do, you don't have to worry about anything! All knowledge will come on it's own. With time, with your own inspiration and desire to know and learn.&lt;/p&gt;

&lt;p&gt;That's why I hate those "X THINGS YOU NEED TO KNOW TO BECOME SENIOR" posts. Besides being clickbaity, they totally miss the point.&lt;/p&gt;

&lt;p&gt;I think a more realistic definition would be: A senior developer is not someone who knows everything, but someone who can solve any problem they throw at them.&lt;/p&gt;

&lt;p&gt;But again, remember those are just words :) What do &lt;strong&gt;you&lt;/strong&gt; think is a good definition?&lt;/p&gt;

</description>
      <category>senior</category>
      <category>junior</category>
      <category>hierarchy</category>
      <category>bureaucracy</category>
    </item>
    <item>
      <title>On Adding Types to Ruby</title>
      <dc:creator>Federico Ramirez</dc:creator>
      <pubDate>Thu, 30 Jul 2020 01:22:23 +0000</pubDate>
      <link>https://dev.to/gosukiwi/on-adding-types-to-ruby-4n6c</link>
      <guid>https://dev.to/gosukiwi/on-adding-types-to-ruby-4n6c</guid>
      <description>&lt;p&gt;This post started out as a reply on Reddit about &lt;a href="https://developer.squareup.com/blog/the-state-of-ruby-3-typing"&gt;this blog post&lt;/a&gt;, but it ended up being so long, I think a blog post would make more sense.&lt;/p&gt;

&lt;p&gt;Basically, the blog post talks about how Ruby 3 will implement type checks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static typing vs Dynamic typing
&lt;/h2&gt;

&lt;p&gt;I've always had mixed feelings when it comes to dynamic vs static typing. One one side, it's great to have a strict type system where you can easily apply enterprise design patterns, like &lt;a href="https://java-design-patterns.com/blog/build-maintainable-systems-with-hexagonal-architecture/"&gt;Hexagonal Architecture&lt;/a&gt; and whatnot. It makes it much easier to work with big systems, with lots of developers.&lt;/p&gt;

&lt;p&gt;On the other side, Ruby (and particularly Rails) was born from the opposite point of view: "We don't need all this crap to build our little app". So I can see why many Ruby devs dislike adding types to the language.&lt;/p&gt;

&lt;p&gt;There's also the argument that for small teams of senior devs, a dynamic language like Ruby can make you more productive. Just good design and strict good practices is enough to have maintainable software.&lt;/p&gt;

&lt;p&gt;The problem is not everyone is on the same page where it comes to code, and when working with junior devs, or external libraries, it's easy to end up mixing everything up.&lt;/p&gt;

&lt;p&gt;I used to believe conventions and "good code" was enough, but after having to work with junior devs, particularly when you cant just write everything yourself and need to delegate stuff, limitations end up being a good thing.&lt;/p&gt;

&lt;p&gt;Otherwise, you are stuck in an endless cycle or reviewing code and nobody is happy. The junior dev is frustrated because you bounce their code over and over again, and you are frustrated you have to review it many times, and end up looking like a strict asshole. What's worse, you might end up lowering the bar and just allowing for bad code in order to "get things done", which is one of the worst things that can happen to software.&lt;/p&gt;

&lt;p&gt;A common mistake junior devs do is not caring about inconsistency in their return types. Sometimes they return an object, other times nil. A type system can easily catch this, and force them to make a decision. No need for you to point it out, the compiler/checker can do it. Many common mistakes like that can be fixed just by having a stricter language/ecosystem.&lt;/p&gt;

&lt;p&gt;I love Ruby. It's by far my favorite language, and I feel very productive with it. But Ruby gives you too much power, after years of using it, sometimes I just want a simpler, redundant, less powerful solution with less possible headaches.&lt;/p&gt;

&lt;p&gt;That being said though, I can't help but think: "Yeah but if you really want types, why use Ruby at all?" Sometimes, you are just stuck with a big codebase, and there's no way around it. But for new projects, it feels like the wrong language if you worry about that. And that's okay. Ruby doesn't &lt;strong&gt;have&lt;/strong&gt; to do everything.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>statictyping</category>
      <category>dynamictyping</category>
      <category>proglang</category>
    </item>
  </channel>
</rss>
