<?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: Artur Martsinkovskyi</title>
    <description>The latest articles on DEV Community by Artur Martsinkovskyi (@arturmartsinkovskyi).</description>
    <link>https://dev.to/arturmartsinkovskyi</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%2F129933%2Fa1b22278-ac22-4391-8223-eb5420cf0a3c.jpeg</url>
      <title>DEV Community: Artur Martsinkovskyi</title>
      <link>https://dev.to/arturmartsinkovskyi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/arturmartsinkovskyi"/>
    <language>en</language>
    <item>
      <title>A terrain and actor simulator on Ruby</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Sun, 12 Apr 2020 22:34:40 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/a-terrain-and-actor-simulator-on-ruby-5093</link>
      <guid>https://dev.to/arturmartsinkovskyi/a-terrain-and-actor-simulator-on-ruby-5093</guid>
      <description>&lt;p&gt;I wrote a procedural world generator on Ruby and is dope. I couldn't even imagine how dope it can be until I started.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mzJcJXoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nb6pu3er1fa6qe7omz9q.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mzJcJXoa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/nb6pu3er1fa6qe7omz9q.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
From the first glance it is just a field of colored squares that looks like terrain. But the cool thing that is not visible is that the terrain is generated randomly and represents a seed value that can generate the same terrain every time you launch the generation or something else if you use another seed. It is generated with a few layers of noise and some secret sauce. The trees are also a noice, but a different kind. People may wander everywhere, but they still die in the end. You control the steps, also you can go around the map and see what is happening on it. Each point is accessible on click or keys movement.&lt;/p&gt;

&lt;p&gt;Here you can see the whole world. The world that can be traversed and settled with life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mYQyb_GZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zc7qg7ipp3cs49p621lt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mYQyb_GZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/zc7qg7ipp3cs49p621lt.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Pretty cool for a thing created on a language mostly used for web, huh?&lt;/p&gt;

&lt;p&gt;It is a social simulation project with desktop representation via 2d game gem Gosu and plain Ruby. Most of the initial world objects are generated with PCG methods(noises, FoN algorithms, random distributions, e.t.c). It has a stepping engine with ability to go back and replay various steps. For now, people just eat and die, but I hope to add diseases that can spread between them, murder and sex someday in the future.&lt;/p&gt;

&lt;p&gt;If you are interested, you can look at the project and clone it to run yourself &lt;a href="https://github.com/artur-martsinkovskyi/gocia"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Would it be interesting if I wrote more on that topic, describing how procedural generation can be done with Ruby, why Gosu is a great choice to start writing games for fun and pleasure and how to glue together Ruby ecosystem to have a fabulous experience so far from Rails?&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>pcg</category>
      <category>game</category>
    </item>
    <item>
      <title>Encryption cooked wrong or why not all top search result gems are equally aiding</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Sat, 07 Sep 2019 09:40:47 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/encryption-cooked-wrong-or-why-not-all-top-search-result-gems-are-equally-aiding-18b1</link>
      <guid>https://dev.to/arturmartsinkovskyi/encryption-cooked-wrong-or-why-not-all-top-search-result-gems-are-equally-aiding-18b1</guid>
      <description>&lt;h1&gt;
  
  
  Disclaimer
&lt;/h1&gt;

&lt;p&gt;I don't blame aes gem creator for doing anything wrong consciously. It was written 8 years ago, it never gained enough traction to be actually reviewed by someone who knew how such a gem should look like, it is just accidentally happened that his gem is on the top of 'aes gem' search at Google. Although, this gem has a few pain points and should not be used in production in the modern days at all. That is why.&lt;/p&gt;

&lt;h1&gt;
  
  
  TL; DR
&lt;/h1&gt;

&lt;p&gt;Don't use aes gem as your first choice in the google search, it does not properly work with ruby &amp;gt;= 2.4 and does not validate your key. Also, remember that Ruby 2.4 forward openssl gem does not cut the key and iv values, so any key/iv longer than 16/32/64/whatever_size bytes will fail with &lt;code&gt;ArgumentError(#{iv or key} must be #{n} bytes)&lt;/code&gt;. Cut it/generate with the proper size before passing it to the openssl or a library using it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Long story
&lt;/h1&gt;

&lt;p&gt;We are the rubyists. We all know and love gems. Gems are the foundation of our community and the ease of their incorporation into our shiny new projects is one of the main reasons of sharp growth in Ruby popularity and the speed of prototyping that has made our language the king of startups. Gems are the way to share our common knowledge and experience with everyone and make others happier than before. Alas, not all gems are equally mature and helpful. Some of them may be treacherous.&lt;/p&gt;

&lt;h1&gt;
  
  
  Encryption is a funny word for obfuscation
&lt;/h1&gt;

&lt;p&gt;Some time ago I came across an interesting dependency in one of my projects. Gem &lt;a href="https://github.com/chicks/aes"&gt;aes&lt;/a&gt; was used for symmetric encryption and it seemed fine until I realized(with the help of &lt;a href="https://blog.elpassion.com/simple-and-terrifying-encryption-story-c1f1d6707c07"&gt;some Medium articles&lt;/a&gt;) that from a point it was a bit bonkers for a developer that relies on the wisdom of gem creators. I kid you not, the gem allowed you to do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Sic transit gloria mundi."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;iv: &lt;/span&gt;&lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;#  =&amp;gt; "1c3c084a8f2384689aa2c440b8d24a3129104fb2dfef$HQVAxvfq1405HV0poYwC3zdEebWC05qhUlMkPbG+kLw="&lt;/span&gt;
&lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Sic transit gloria mundi."&lt;/span&gt;
&lt;span class="c1"&gt;# Seems fine.&lt;/span&gt;
&lt;span class="mf"&gt;2.3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;00&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"gassword"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Sic transit gloria mundi."&lt;/span&gt;
&lt;span class="c1"&gt;# Not fine.&lt;/span&gt;
&lt;span class="mf"&gt;2.3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mo"&gt;010&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;decrypted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;AES&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;encrypted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"gassworp"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Sic transit gloria mundi."&lt;/span&gt;
&lt;span class="c1"&gt;# WTF, does it even encrypt?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The devil is in this detail of the gem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;      &lt;span class="c1"&gt;# Create a new cipher using the cipher type specified&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="vi"&gt;@cipher&lt;/span&gt; &lt;span class="o"&gt;||=&lt;/span&gt; &lt;span class="no"&gt;OpenSSL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cipher&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cipher&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="vi"&gt;@options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:cipher&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="c1"&gt;# Toggles encryption mode&lt;/span&gt;
        &lt;span class="vi"&gt;@cipher&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;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="vi"&gt;@cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:padding&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="vi"&gt;@cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unpack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a2'&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&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;x&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;32&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;p&gt;Last line of this method &lt;a href="https://apidock.com/ruby/String/unpack"&gt;unpacks&lt;/a&gt; any string as a hex string even though it does not assertion as for if it is actually one. What does it produce? Any string without a valid two-letter hex sequence will end up just the same, so our locked encrypted data will end up with a pretty vast set of possible keys that match and decipher the string.&lt;/p&gt;

&lt;p&gt;I know, I know that you are not supposed to use non-hex value as a key for AES, but the library gotta tell me that I am wrong. It certainly should not do this without a blink of an eye, just letting me fail my cryptography like I was using rot13 instead of US government approved AES. This is the exact opposite of what we all strive to with cryptography - transparency and fail fast strategies, so we end up in the insecure mess that is hard to detect. Remember to check your key for being a valid hex, because your encryption may be way worse than you thought.&lt;/p&gt;

&lt;h1&gt;
  
  
  Update - fix - repeat
&lt;/h1&gt;

&lt;p&gt;Secondly, this library does not properly work with Ruby 2.4 and newer. By not working properly I mean your old code will fail with no changes after updating your Ruby up from 2.3 and you will need to patch to get it working. Why? Because it relies on OpenSSL and OpenSSL did &lt;a href="https://github.com/ruby/ruby/commit/ce635262f53b760284d56bb1027baebaaec175d1"&gt;this&lt;/a&gt; in 2016(they year aes gem master branch was last updated). It stopped truncating too long values for iv/key, so the code that was working just fine before the Ruby updated simply started failing because it did not have the valid key/iv length and no one bothered to fix it until the breaking change.&lt;/p&gt;

&lt;p&gt;You would say that you just pass the truncated key/iv to the library and you're good to go with the gem... You are unless you want to properly decrypt those nasty string you've encrypted with the wrong length iv in the past. 'aes' gem does not give you a normal encrypted string, it prepends the iv right next to it using $ sign as a separator. I would not say it is totally a bad thing, iv should be public after all, but it influences your future choices, bounding you to the gem format of ciphered data that would require a transformation for all encrypted strings you have.&lt;/p&gt;

&lt;p&gt;To fix failures due to iv length mismatch on encryption, you would also need to preprocess, split and truncate the iv before feeding it to the library. It works fine until the next breaking change and you've bound yourself with your encrypted data to the legacy gem that has a few vulnerabilities and was not updated for 3 years. Congratulations, you played yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  What should I do?
&lt;/h1&gt;

&lt;p&gt;Why should you patch around to get the gem working after you updated the Ruby if the gem is basically just 160 lines long? It is better to just read &lt;a href="https://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html"&gt;OpenSSL::Cipher&lt;/a&gt; and use AES yourself. The docs are wholesome and warn you of possible caveats, the whole encryption process is explained in code, so instead of using the gem that goes first in the search, stay calm and go more distance with standard library, that will stay here for a much longer period of time with maintainers and updates unlike the gem. This works if you did not yet incorporate the aes gem into your application. If you did, then, well, secure the risks and plan migration, buddy.&lt;/p&gt;

&lt;h1&gt;
  
  
  Better to be safe than sorry
&lt;/h1&gt;

&lt;p&gt;Gems are useful and they immensely speed up our pace of development. However, they are just pieces of code that were written by other developers. The fact that the code is open source does not make it better than yours(unless it is a big library with 1000 stars and contributors from the whole world, in that case, hivemind polishes the code pretty well). You should not just blindly trust every piece of code you found on the Rubygems, especially if it is related to security. Read the gem code and docs, check its popularity, common issues, and PRs. This way you can ensure that the gem you bring into your application is really a gem and not a malicious piece of glass. aes gem is not &lt;em&gt;that&lt;/em&gt; bad, but still, it may cause troubles even though it is just a thin layer on top of OpenSSL that you could write yourself in less than an hour. Choose wisely. Good luck and have fun with Ruby, friend.&lt;/p&gt;

</description>
      <category>gem</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Testing Factory Bot sequences</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Fri, 19 Jul 2019 12:40:27 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/factory-bot-sequence-testin-274i</link>
      <guid>https://dev.to/arturmartsinkovskyi/factory-bot-sequence-testin-274i</guid>
      <description>&lt;p&gt;Once I was working on a feature that was a validation for UUID of a certain entity that matched the regular expression of &lt;code&gt;/^ENT-\d\d\d\.\d\d\d\.\d\d\d$/&lt;/code&gt;. It was a Rails project with RSpec and FactoryBot. I wrote the code and tests for the feature and everything seemed to work fine until I pushed it to GitHub and the CI tests run. CI environment, unlike the local one, was set up to run in parallel(this will be important later). CI seemed to break at about 300 tests that ran just fine on the local environment. After a few hours of investigation, it appeared to me that the sequence for UUID in the factory was giving the wrong results for any element past 999 which was certainly unacceptable. I fixed the problem, but to be sure that everything worked properly I needed to validate the results of the sequence were correct.&lt;/p&gt;

&lt;h1&gt;
  
  
  Problem
&lt;/h1&gt;

&lt;p&gt;FactoryBot sequence is a sort of enumerator that passes subsequent integer values starting at one to a block and returns the result of the block back. In case if its block is implemented right, it is a pure function, a reflection from the set of integers n to a set of values. Below you can see an example syntax of a sequence.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&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;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:uuid&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;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&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;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "0"&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;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:uuid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "1"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;It is great as a &lt;strong&gt;tool&lt;/strong&gt; for testing, but not as &lt;strong&gt;the code being tested&lt;/strong&gt;. We could test Factory Bot sequences from the outside checking the output of &lt;code&gt;generate&lt;/code&gt; and then rewinding the sequence to its original state with &lt;code&gt;FactoryBot.sequence_by_name(:UUID).rewind&lt;/code&gt;. This would mean that our sequence tests would need to be run first to avoid uniqueness clashes after rewinding the sequence and creating the same values over again. But to be true to ourselves and to be sure that we test properly we need to ensure the validity of our sequences in all cases possible. How can we do this?&lt;/p&gt;

&lt;h1&gt;
  
  
  Solution
&lt;/h1&gt;

&lt;p&gt;The answer is pretty easy and straightforward - we should use plain &lt;em&gt;Ruby&lt;/em&gt; code to solve the issue. FactoryBot sequence is a mechanism to provide unique values to the factories, it is a part of DSL of the testing domain and it operates in it, so the fact that it is not testable from the outside is a hardly evitable part of the user-friendly design. Instead of trying to outsmart the library interface and test the sequence itself, it is better to think of the body of the design of this function. Instead of trying to outsmart the library interface and test the sequence itself, it is better to think of the body of this function. Practically, it is a function that gets an integer value and returns whatever reflection of it deems appropriate. That means that we can just inject our code for such function inside of the sequence and test it instead, not taking the whole FactoryBot DSL for a ride. There are a few possible ways to do so, some exotic, some more commonplace:&lt;/p&gt;

&lt;h2&gt;
  
  
  Module functions
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Sequences&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Uuid&lt;/span&gt;
    &lt;span class="kp"&gt;module_function&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;company_uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="s2"&gt;"CMP-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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="c1"&gt;# Then you can use it either casting the method to proc after retrieving it with #method method or just calling it inside of the block.&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;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_uuid_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Sequences&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_uuid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_uuid_2&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;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="no"&gt;Sequences&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;company_uuid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&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;Comment: &lt;code&gt;module_function&lt;/code&gt; in the global scope at the tope basically extends module with itself and makes all method both module-level and object-level(if the module is included inside of some class).&lt;/p&gt;

&lt;h2&gt;
  
  
  Proc-like objects
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Procable&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_proc&lt;/span&gt;
    &lt;span class="no"&gt;Proc&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&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;module&lt;/span&gt; &lt;span class="nn"&gt;Sequences&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompanyUuid&lt;/span&gt;
    &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Procable&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="s2"&gt;"CMP-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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="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;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Sequences&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CompanyUuid&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Comment: &lt;code&gt;&amp;amp;something&lt;/code&gt; is basically an alternate syntax for &lt;code&gt;#to_proc&lt;/code&gt; -&amp;gt; convert to block conversion in that case. If the object is already a Proc it just converts it to block.&lt;/p&gt;

&lt;h2&gt;
  
  
  Module with proc/lambda constants
&lt;/h2&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Sequences&lt;/span&gt;
  &lt;span class="no"&gt;COMPANY_UUID_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"CMP-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&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="c1"&gt;# lambda&lt;/span&gt;
  &lt;span class="c1"&gt;# or&lt;/span&gt;
  &lt;span class="no"&gt;COMPANY_UUID_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&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;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="s2"&gt;"CMP-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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="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;sequence&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:company_uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="no"&gt;Sequences&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;COMPANY_UUID_1&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;p&gt;Those look nice and decoupled from their definitions in the test factories, so the factories themselves look more declarative as they should be. But this is not the main point. The main point of that conversion is to make this code testable. And now it is(because it is plain Ruby). You can test it like that:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Procable&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_proc&lt;/span&gt;
      &lt;span class="no"&gt;Proc&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:call&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;class&lt;/span&gt; &lt;span class="nc"&gt;Sequences&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompanyUuid&lt;/span&gt;
      &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Procable&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&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="n"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Sequences&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CompanyUuid&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
    &lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;each_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&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;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s2"&gt;"is expected to eq &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; on input &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;desdule&lt;/span&gt; &lt;span class="no"&gt;Sequences&lt;/span&gt;
    &lt;span class="no"&gt;COMPANY_UUID_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"CMP-&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;n&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="c1"&gt;# lam&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Sidenote: better not to put the test file in the same folder as the sequences code if this folder is a &lt;code&gt;spec/support&lt;/code&gt; folder. It most project setups this folder is loaded on RSpec startup, so your tests for sequences will run twice. If you don't use RSpec or support folder, you should be fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Afterword
&lt;/h2&gt;

&lt;p&gt;Your testing code is a citizen of the same dignity as the normal code in your system because it grows and changes with it and ensures an important quality of your system - validity and proper functioning. It works under the same pressure as other parts of your system and has to be DRYed, decoupled and abstracted away as much as possible same as the actual code of the system. If this act of hygiene is not performed well, you should be sure to expect trouble on one or another stage of development of your system: flaky tests, a lot of commented out tests and overall sliding down in the mud of bugs and swamp of dead unusable tests that were not updated properly, so they grown useless. One of the parts of your testing infrastructure that can be tested outside of going into the infinite loop of 'Quis custodiet ipsos custodes?'(Who'll watch the watchmen?). It is the generative code that gives you mock data for the tests. This code can and should be tested because it is a link that bounds your testing suite to reality and provides it with real-world looking data. The sequence is a kind of such code and they should be tested to avoid problems with flakiness that I experienced and many others. Happy testing!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>test</category>
      <category>factorybot</category>
    </item>
    <item>
      <title>Myopic rationality of software cludge</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Fri, 31 May 2019 17:27:07 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/myopic-rationality-of-software-cludge-19h7</link>
      <guid>https://dev.to/arturmartsinkovskyi/myopic-rationality-of-software-cludge-19h7</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; &lt;em&gt;People love with their eyes, not their minds. They usually don't estimate what they don't see or comprehend, so without of proper voice of reason, software project turns into cruft pretty quickly. It seems rational to do so in the short-term, but strategically it is a way to failure.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Clinging to a cliff
&lt;/h1&gt;

&lt;p&gt;People are not good at predicting the future. Gosh, even thinking about the future realistically varies from pretty hard to impossible. Future is a slice of the entangled mess of reasons and consequences that create a huge and highly intertwined system, so no wonder our little biological computers are bad at a simulation of it. We may dream about the future, we may create an approximate vision of what is going to happen, but we never know exactly. Looking further in the future it becomes harder and harder to see even the unfocused blurry vision of what is going to happen. So people do the best they can - they rely on the old mechanisms nature has built into us a long time ago - intuition, aspiration, Gestalt of the future if you wish. This vision is highly material, it relies on what they see and feel rather than what they reason about. They see the future as a continuation of the present, so their mind cuts the corners on unknown or uncertain things focusing on what it deems important - actual factual data it manages to retrieve from the surrounding world. But there are a lot of factors we cannot properly perceive but still need to take into account to judge rationally. &lt;/p&gt;

&lt;h1&gt;
  
  
  Step in line and stand in line
&lt;/h1&gt;

&lt;p&gt;It takes a deliberate and conscious effort to start taking such unknowns seriously. Software development team managers, business owners, business analysts - all of those people are doing future predictions as their job, so they've got to excel in it. Unfortunately, this is not always the case. They try, they really do, but it is quite hard to do it properly unless you know about the traps of your mind and listen to those doing the job whose actual state of affairs is pretty hard to estimate without their part. Failures of design and wrong functionality take immediate effect and signal that something is wrong. Managers are used to handling those warnings and know how to track them when it is not yet too late. But they don't do it with crust simply because only measurable metrics - expansion of feature development time and bugs seem fairly tangential to the perceived code quality and the only actual signal you may get is frustration of developers and their moans while they dig through the codebase trying to fetch things together in a manner that will not break everything. Those are frequently ignored due to their immeasurable nature. Crust works like radiation - it kills off the project without you seeing the effect until the fatal or semi-fatal damage is done. Basically, when you start noticing the crust it may be too late to fix it while doing the new features because the damage of cut corners, wrong abstractions, and improper domain language will stack up faster than development team resolves it.&lt;/p&gt;

&lt;h1&gt;
  
  
  We wanted the best - you know the rest
&lt;/h1&gt;

&lt;p&gt;Once I heard a nice story from a fellow developer. He said that his team lead liked to repeat one interesting observation. He used to say that there are two stages in software development: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do it dirty and make it work &lt;/li&gt;
&lt;li&gt;Clean up and make it shine&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"Nobody ever reached stage two." - he usually finished the saying. And I agree with this. Mostly, people don't seem to integrate dirt and future problems in their minds with something that looks beautiful on the outside. This common misconception along with "know it all" attitude and a will to fulfill customers' needs to the fullest extent creates an effect of the local maximum. Once a manager manages to get a solution in a much faster manner using hacky and patchy solutions he starts falling into a spiral, a spiral of "we will fix it later". This strategy does not take an immediate negative effect, so it tickles their minds in pursuit of more and more immediate benefits. Even though they may think and believe that technical debt is a thing and that it requires handling, their human nature and instincts say that crust is not that big. They cannot check it up themselves, so usually it is too late when the big break comes and application is suddenly far away from normal. We can see that it gets even bigger if we notice the practice of one-two year rotation managers and software engineers are used to in modernity, so the crust they are creating maybe not even their own problem to solve and lie on the shoulders of poor fellows getting on the job after they get away. In order to avoid it, we as an industry have to integrate refactoring and continuous synchronization with the domain as a part of everyday practices for every software project. Some do it, but most of the projects I've seen or heard about the move from one catastrophe to another. &lt;/p&gt;

&lt;h1&gt;
  
  
  Although, also
&lt;/h1&gt;

&lt;p&gt;Sometimes the crust is here to stay. You need the project to be done and you need it fast. Maybe you need to be faster than your competitor, there is a pool of venture capitalist sharks behind your door or simply your idea is not yet formulated good enough so moving fast and breaking things is the only option to survive and strive. In that case the only things you can do is to choose less crust-prone technologies and languages, those that can do prototyping fairly easily(Ruby gets out of the corner) and then skip to other tech stacks once you are done, hire a nice bunch of seniors that have seen a hell ton of kludge in their life and know how to make it less poisonous. But you should remember that debts are here to stay and they have got to be paid sooner or later. The price may be a success of your project if you take it to the extreme. The only question is, is the crust worth it?&lt;/p&gt;

&lt;h1&gt;
  
  
  Aspirations
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/articles/is-quality-worth-cost.html"&gt;Is High Quality Software Worth the Cost? by Martin Fowler&lt;/a&gt; &lt;/p&gt;

</description>
      <category>projectmanagement</category>
      <category>software</category>
    </item>
    <item>
      <title>Rails are a cult</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Fri, 31 May 2019 06:12:07 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/rails-are-a-cult-51b</link>
      <guid>https://dev.to/arturmartsinkovskyi/rails-are-a-cult-51b</guid>
      <description>&lt;p&gt;It is going to be a rant. But a nice one. A piece of consideration from a desperate cult member that wants to make his beloved language better, that wants its worshippers to get away from the choking grip of the cult and become freer, more diverse in their thoughts, less ignorant to the problems of the ecosystem surrounding them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Love bombing
&lt;/h1&gt;

&lt;p&gt;My first commercial experience that counts happened to be with Rails. I've started working with the framework when I entered a bootcamp of one of the small companies in my hometown. I was a late sophomore, smart but not really diligent. I knew some C++ programming, a bit of Python and Java, but every attempt to get started with actual application development of something harder than simple hello world blog was failing due to various reasons. Sometimes my motivation was simply gone after a few days of fighting with compilation errors and wrong test outputs, at other times I was starting a project just to throw it away after a few days not looking in the code. I could not build my skillset to be good enough for me to have a desire to last longer and stay interested in things. Fortunately, Rails turned out a completely different piece of cake.&lt;/p&gt;

&lt;p&gt;After a few fixed red 500 screens and fighting with database setup my initial blog was finally set up. I was amused by how smooth it went. Firing up first application was nothing like Spring or even Django. It worked right out of the box. And it was beautiful. At first, I was really hooked up on the idea of convention over configuration. The whole smart setup already is done for me by the framework. I had model, controller, and views and that was all I needed to make my application do the job. Do you have a problem not solved by the framework? Look up the docs, most likely you just don't know the in-box solution yet. Sometimes I even guessed up the names of the methods I needed. Pure magic! If you have a problem that does not fit into the framework limits like authentication, adminpanel, currency handling, integration with Google Maps or Stripe - just Google a &lt;code&gt;gem&lt;/code&gt; for it. Most likely you will find the one to suit your needs. Package manager was advanced and had a nice interface, scaffolding was bliss after all the boilerplate I had to deal with using Java Server Faces.&lt;/p&gt;

&lt;p&gt;The community seemed to be fancy and I've got answers to my questions on StackOverflow and forums, most of them were asked before me. Nice people were doing nice things and I felt warm and welcome amongst them. Also, there were personalities. DHH, the creator of the framework, active on Twitter and his blog, always having an advice for you and steering the ship of Rails in the right direction, Yehuda Katz, co-creator of Ember.js and writer of numerous books about Rails and their surroundings, Avdi Grimm and Gary Bernhardt, whose screencasts I highly appreciated.&lt;/p&gt;

&lt;h1&gt;
  
  
  Appointment with disappointment
&lt;/h1&gt;

&lt;p&gt;After a while, first impression started to fade away. About six months in, I understood that I didn't know Ruby well enough(I had no problems with Rails themselves, but the feeling that I could do more started to kick in). I learned more of Ruby and general OOP and started to realize some strange things. First of all, it turned out that a lot of things I used in Rails like &lt;code&gt;#transform_keys!&lt;/code&gt;, &lt;code&gt;in?&lt;/code&gt;, &lt;code&gt;delegate&lt;/code&gt; were not a part of the Ruby core library. They were a part of ActiveSupport. They weren't wholesome either, turning out to be a bunch of hacky monkey-patches that sometimes were in conflict with some of the gems I tried to use.&lt;/p&gt;

&lt;p&gt;Secondly, Ruby turned out to have a &lt;code&gt;require&lt;/code&gt; method and everything did not really need to hang around in the global namespace as it was(and is) in Rails. I understood that it was purposefully made to serve as a convenience, but a bad taste of a big memory footprint and loading issues was here in my mouth. After that, my controllers got bloated with business logic. I googled the problem and found motto &lt;code&gt;thin controllers - fat models&lt;/code&gt;, so I followed it. But then models also started to bloat. I started to use concerns but they were not helping much either, putting out the logic that should have been in the class itself in the separate file, not really solving the problem correctly from OOP perspective. Rails did not have any abstraction of their own, so I started to make them myself with POROs and patterns from the books I've read. Rails were hiding a lot of complexities you might have needed to comprehend and change deep down underneath the user level of abstraction, making developers employ hacky and wrong solutions to get the work done when it was not in line with easy vision it had on how those features should have been done by convention. It seemed like configuration was not there when you were out of the conventional path. Gems also cluttered global namespace like ActiveSupport did, so sometimes they accidentaly broke trying to redefine the same method. It was not looking like a strive for cleaness, rather a strive to get the work done no matter dirty or not. Standard way of handling actions on update/create - callbacks, also turned into complete mess when app got more full-fleged and filled with business logic.&lt;/p&gt;

&lt;p&gt;Frustration started to raise and my feeling was like I was doing something that was not intended to be done with that framework at all. On the other hand, problems with ORM kicked in, every query harder than a trivial join with counting and some conditions in where was out of reach for the standard means of ActiveRecord, so I had to write SQL by hand or stick to Arel with quite a weird syntax. Rails also did not(and do not yet) support any means of view abstractions. Global helpers, erb, and partials - this is everything you have to deal with out of the box. No wonder I've started looking for the better ways of handling the problems of rising complexity I had. When I got on the Internet, I've seen Sinatra, Hanami, ROM-rb, Roda and some other good libraries, but they were not that popular. There were voices of dissent, Elixir with Phoenix, Clojure, and Crystal, but they  were trying to get Ruby attitude and culture out of Ruby ecosystem, while the original ecosystem was vastly occupied by Rails. Most of Ruby developers were Rails developers and did not seem to have any problem with the framework being essentially the body of work and economic existence of the language. They liked what DHH said and followed the practices even though it hurted them sometimes. 'Convention over configuration, TDD is dead, Rails is your application, you're using Rails wrong if you have troubles with it, just use another gem' they said. Then I realized that I've engaged in a cult.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b0KQE3Bq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8bo64tn9vcm3vcjctc3b.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b0KQE3Bq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/8bo64tn9vcm3vcjctc3b.jpg" alt="Cult"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Cult of easy
&lt;/h1&gt;

&lt;p&gt;Let's get down to the basics. What defines a cult? As Robert Jay Lifton &lt;a href="https://culteducation.com/brainwashing1.html"&gt;says&lt;/a&gt; there are three main characteristics of a cult.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a charismatic leader who increasingly becomes an object of worship as the general principles that may have originally sustained the group lose their power;&lt;/li&gt;
&lt;li&gt;a process of coercive persuasion or thought reform;&lt;/li&gt;
&lt;li&gt;economic, sexual, and other exploitation of group members by the leader and the ruling coterie.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, DHH is a leader. He is a great entrepreneur and evangelist. I like the way he writes and the way he acts. He created Rails(not singlehandedly, but still). But what is the body of his words? What does he impose on us? Here are a few tweets of his for you to get the hang of it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a class="comment-mentioned-user" href="https://dev.to/paulca"&gt;@paulca&lt;/a&gt;
 Fuck. That. Shit. Same complete wank. “Rails is not your application”. If you’re building a web app, of course it is.  — DHH (@dhh) June 29, 2012&lt;/p&gt;

&lt;p&gt;Hello, my name is David. I would fail to write bubble sort on a whiteboard. I look code up on the internet all the time. I don't do riddles. - DHH(@dhh) January 21, 2017&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those speak for themselves, so let's move on to the culture Rails and DHH create in Ruby community. He values easy solutions over simple ones. Why should use decompose your application when you can put the whole domain logic in the model and call it a day? Why use SOLID and GRASP when you can do thins more &lt;em&gt;easily&lt;/em&gt; than before, no matter what cost it will have in the future. It is better to have everything at the reach of hand in the complete mess than sorted out with a few more hops to get to the functionality. Those solutions work in the short-term, but in longer scope, you end up with an entangled mess in deep need of a complete rewrite. With such an approach, that is dictated by a leader, Rails do not scale well neither cognitively, nor resource-wise. But the lord is still praised and his Rails vision pollutes not only Rails, but also &lt;a href="https://solnic.codes/2015/06/06/cutting-corners-or-why-rails-may-kill-ruby/"&gt;Ruby ecosystem&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This leads us to the next point. Process of coercive persuasion. Rails are not only bloating themselves and the minds of developers who work with them. They are contagious to the ecosystem. Active Support features slowly get merged into Ruby core and most of the gems need to be compatible with Rails in order to gain any popularity. A long time ago &lt;a href="https://yehudakatz.com/2008/12/23/rails-and-merb-merge/"&gt;Rails killed off Merb&lt;/a&gt;. Now Rails are practically a monopolist in the Ruby field, so it is quite hard for new frameworks to get popular when libraries are polluted with Rails specifics, a huge chunk of rubyists are practically railsists and Rails were a thing for more than 10 years keeping in mind that business likes established and time-proven solutions. Rails are a cage and this cage transform the mind of developer to either give up and embrace sloppiness or get out either to a safe place like Trailblazer or out of the Ruby community to those prominent rubyists that created Elixir and Clojure.&lt;/p&gt;

&lt;p&gt;Exploitation. Rails drain brains from the community like a vacuum cleaner. Why do something else when you've got the most popular solution on your fingertips? Why create general solutions when 90% of your gems' users will be on Rails? Why bother if Rails are a default choice? Some people go against the current, but most of them don't. So Rails popularity works like a snowball. The popular framework gets more popular because people choose it because of its ecosystem and support(Stackoverflow, Github issues, etc.) and then contribute to the ecosystem making it even more of a desirable choice. Many other visions, other libraries would have been created and existing libraries would be created differently if not for the hurtful impact and &lt;em&gt;easy&lt;/em&gt; practices imposed by the monopolist. People either play by the rules or leave. Only a few stay to dissent. &lt;a href="https://www.lesswrong.com/s/M3TJ2fTCzoQq66NBJ/p/ZQG9cwKbct2LtmL3p"&gt;Here&lt;/a&gt; is a nice explanation of how it works.&lt;/p&gt;

&lt;p&gt;Rails are a cult even though they do not employ sleep deprivation and do not claim soon apocalypse. Rails embrace and worship hurtful practices that do not work properly in the current world. Rails are easy to start with but following its best practices word by word is a good road to callback hell and complexity bursting out of control. Rails make developers worse by normalizing monkey-patching, denial of SOLID, GRASP, LoD and other good OOP practices for the mere immediate convenience. Rails kickstarted initial Ruby popularity, but they do a bad job at being a good citizen in Ruby country now.&lt;/p&gt;

&lt;h1&gt;
  
  
  Ruby without Rails?
&lt;/h1&gt;

&lt;p&gt;I would like to have a solution in this section, but I don't. Ruby popularity seems to be stagnating for the last few years and Rails move in the same old way only adopting the inevitable needed features or the ones that Rails Core Team and Basecamp need. There are voices of dissent and new frameworks but they do not skyrocket in popularity, leaving Rails a monopolist almost like it was in 2010. Some rubyists leave, some stay and face the problems that cannot be fixed with existing attitude, churn and framework structure. Will there be a solution? Will we get a better ecosystem and more choice? Will the cultists break their chains? I hope so. But only the future will tell.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sources of aspiration
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=34_L7t7fD_U"&gt;Simple Made Easy by Rich Hickey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://harmful.cat-v.org/software/ruby/rails/is-a-ghetto"&gt;Rails is a ghetto by Zed Shaw&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://solnic.codes/2016/05/22/my-time-with-rails-is-up/"&gt;My time with Rails is up by Piotr Solnic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>programming</category>
      <category>framework</category>
      <category>rant</category>
    </item>
    <item>
      <title>Vim in modernity - why and why not </title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Thu, 30 May 2019 10:41:00 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/vim-in-modernity-why-and-why-not-5gad</link>
      <guid>https://dev.to/arturmartsinkovskyi/vim-in-modernity-why-and-why-not-5gad</guid>
      <description>&lt;p&gt;I am a Vim acolyte now. I haven't always been one. First I used simple Gedit but it started to raise frustration in me. It was too bare-bones and I needed to switch context over and over to do some simple tasks like rerunning the server, playing with the console, looking up logs.  I skipped to a more complicated and seemingly featurefull Rubymine. It suited me for some time, but I felt like something was off. It was almost like a burden was put on my neck. It worked well when properly set up, but it was big. Pretty big. Memory footprint was enormous for all the misses in code suggestions, for every piece of additional configuration that I needed to set up once something changed in my environment. The other problem was the language I was working with. Ruby is straight out unpredictable chaos at times. Virtually everything can be generated, deleted and redefined at runtime. Methods come and go, it is interpreted, so it is quite hard(almost impossible) to compose proper Go to  Definition, code suggestions and overall static analysis tool for it. After some time(and an incident when Rubymine devoured 16 gigs of RAM and broke) I left. My team lead was using Vim, so I decided to try it out. It was painful at first, but after about two weeks of sinking in the sea of cryptic commands and being frustrated with my mouse habits I started to feel something good. It was the start of enlightenment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Nothing alike
&lt;/h1&gt;

&lt;p&gt;Vim is obviously a console editor(you can get a GUI version but it is not really needed). It runs in a terminal as any terminal program, so it can be stopped with Ctrl^Z and then brought back with &lt;code&gt;fg&lt;/code&gt;. It is installed on virtually every UNIX-like system in the world and can run through &lt;code&gt;ssh&lt;/code&gt;. You can edit multiple files at once using tabs and panes and traverse easily between them using only keyboard. It is modal. Its modes are insert, normal, visual, search and command mode. It may scare you at first, but this is actually a feature, not an issue. I was always a bit frustrated with the fact that I need to use the mouse to go to an arbitrary point in the text to edit it, so I reach it, point at the needed place and then get back to the keyboard. Modes resolve the issue - in normal mode you traverse the text with the use of arrows or keys H, J, K, L and when you want to insert something you just go in the insert mode, do the job and get back to the normal mode. Command mode is used for commands like substitution, help, running shell commands, various custom scripts, etc. Commands of vim are mnemonics. &lt;code&gt;a&lt;/code&gt; stands for append, &lt;code&gt;d&lt;/code&gt; for delete, 0 is the begginning of the line, $ is the end. They can be combined in various ways and after some time a user forgets about their existence, they are basically on the tips of his fingers. It is like cycling(if a bycicle could be controlled by neurointerface and fly you to the moon). Once you know how to do it, is is done instinctively.&lt;/p&gt;

&lt;h1&gt;
  
  
  Opium of minimal optimum
&lt;/h1&gt;

&lt;p&gt;So, why do I use Vim over all those shiny editors and IDEs? It is minimalistic. Just enough to do the job. No overcomplicated tools, no cascading context menus, no overgrown memory footprint and caching, no pollution of your project library with editor tempiles. Just you and your terminal and the Art of Vim. You don't switch the context every time you use the mouse to point at something, you stay at your keyboard and you can reach everything with it. It allows you to focus and concenrate on the job, to meditate over your code and change it with a slight flip of your fingers. It is faster to move between files and faster to type. I don't need all those diff editors, GUI for git, tools for every integration like Puppet, Chef or loggers when I have my console. It shifts the focus on what is important. When you are in Vim, you are in the terminal, so a single Ctrl^Z gets you back in the context so you run the commands you need and get back to the editor. It is a Zen practice of its own, monotonous accurate movements, focus on one thing and absence of unneccesary. Once you configured it - you don't really need to change a thing(the fatigue of configuration I had with Emacs was driving me mad because I was configuring stuff more than doing actuall job, even though it was a delightful experience). Learning Vim is a never ending experience, you can combine commands and its capabilities in a long range of ways, so it becomes something like the martial art with an infinte field of capabilities.&lt;/p&gt;

&lt;h1&gt;
  
  
  Elegant weapon for a more civilized age
&lt;/h1&gt;

&lt;p&gt;Vim is old. It was created in 1991 and and its predecessor vi was created in 1976. It has a vast and vibrant community that writes plugins, updates it and even rewrites it as with Neovim or embeds it in other editors like Vim mode in JetBrains products or evil mode for Emacs. It has a cultural influence on the industry because of what it is - an elgant instrument for editing the code. It is elegant and easy to use once you embrace its vibe. It suits and I like to use it for almost all of my programming tasks. But would I use it if I was writing Java? C#? C++? Those languages can facilitate much from the static analysis tools,  precompilation and their ecosystems require quite a lot of effort to start something from scratch. Configuration files, orchestration, containers and application servers - those things are interconnected with IDEs and even though it is possible to handle all of that in the console mostly there is not much sense to do so. Once I am using scripting languages or something with small overhead - I'll go with Vim. But if IDE can grant me better capabilities and save time - I will go with it and use Vim-mode plugin. Even though it will break full immersion, it is better to choose the tools for the job, not just the tool you like. I dream that someone would create something with Vim interface and all facilities of the modern editor, but for now it is just a dream. Will it come true some day?&lt;/p&gt;

&lt;p&gt;P.S. This article was also written in Vim :)&lt;/p&gt;

</description>
      <category>vim</category>
      <category>editors</category>
      <category>programming</category>
    </item>
    <item>
      <title>I don't want to be a full-fullstack developer or why division of labour still matters</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Sat, 25 May 2019 14:51:50 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/i-don-t-want-to-be-a-full-fullstack-developer-or-why-division-of-labour-still-matters-ff0</link>
      <guid>https://dev.to/arturmartsinkovskyi/i-don-t-want-to-be-a-full-fullstack-developer-or-why-division-of-labour-still-matters-ff0</guid>
      <description>&lt;p&gt;I am a Ruby Developer. I am a fullstack web dev. And I am tired of being one. I am also tired of being a business analyst and a manual QA at times. As years go by the industry is going deeper and deeper down the rabbit hole of developer-focused engineering process and developers go on to combine more and more responsibilities beneath the surface of single cranium. &lt;/p&gt;

&lt;h1&gt;
  
  
  Long time ago in the prehistoric Internet
&lt;/h1&gt;

&lt;p&gt;There were DBAs long time ago, you are quite rare to find a beast like that in the shadows of cubicles nowadays. Indeed.com &lt;a href="https://www.indeed.com/jobs?q=full+stack+web+developer&amp;amp;l="&gt;search&lt;/a&gt; yields 7k results on the term &lt;em&gt;fullstack web developer&lt;/em&gt; and 40k for just &lt;em&gt;web developer&lt;/em&gt;. The separate roles of UX Engineer and Frontend Developer are also slowly being blended together on the premise of working on essentially the same thing. More and more agencies are looking for people who can do both frontend and backend, also participating in the business requirement development, writing unit and integration tests, being everywhere and doing everything.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cut the cost, take the rest
&lt;/h1&gt;

&lt;p&gt;That seems like a great idea at first, a person knows and does everything needed from scratch to shipped feature, controlling the whole process. It is easier for the business: you need to check with one person and process of development does not get too complicated with 'who does what' issues, it also cuts the costs making a little tradeoff with quality and development time. Communication and context switching also don't influence the people anymore as they go through the whole process rather than picking it up from where their successor in the chain left off. That seems like a nice enhancement... ...if you don't know a thing about how those professionals you crammed into one person actually work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Complexity strikes back
&lt;/h1&gt;

&lt;p&gt;Backend development is a complex field, including understanding of network layer, the way servers work overall, deployment, AWS/Google/Azure services(they are vital to modern web applications), specifics of server application language and framework, protocols used, authentication, database connectivity and setup and a lot of other things. Frontend includes solid knowledge of web standards, quirks and oddities of particular browsers, ES5, ES6, CSS, HTML, frameworks, preprocessors, transpilers, build tools, UX, UI, networking from the browser perspective, browser storages, sometimes even specifics of mobile apps with Flutter, Ionic and React Native. Don't even get me started on business analyst and QA roles for they are completely different bowls or rice.&lt;/p&gt;

&lt;p&gt;Each of this roles has its own learning curve and essential skills to master. You can't just expect a person to read a few articles or a book, write a sample app and start bringing a good result. The result will always be somehow &lt;strong&gt;substandard&lt;/strong&gt;. If you hire a fullstack web developer, you don't hire an equivalent of two half-time specialists at once, you hire one normal and one impaired(in the best case, you may as well get the equivalent of two so-so half-time devs). It requires devotion and motivation to keep track and stay relevant and brilliant even in one field, put aside two or more. Time is finite. You cannot succeed in two unless you have no personal  life and time for yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wider or deeper?
&lt;/h1&gt;

&lt;p&gt;Don't get me wrong, I think it is good to widen up the field of knowledge and employ understanding of your parts surrounding to do a better job on your section, but making developers be Jacks of all trades directly influences code quality, choice of solutions and the future of the project developed. Space in our heads is finite. We may fill it in with either deeper and better knowledge of one or a few fields or start chewing information on the multitude of domains resulting in superficial knowledge of everything. This knowledge creates a bubble of confidence that unfortunately does not justify itself, resulting in worse solutions and reinventing the wheel/employing wrong technique/banging the nails with a microscope.&lt;/p&gt;

&lt;h1&gt;
  
  
  Not all cuts are equally healthy
&lt;/h1&gt;

&lt;p&gt;Fullstack is interesting because is seems to be almost unique to the software engineering field. Other fields mostly have more division of labour, you don't expect the dentist to cure your heart and neurosurgeon to fix your hemorrhoids. The reason it is employed in software engineering seems for to be the fact of virtual and failsafe nature of the field. Your code quality does not directly influence the outcomes visible for users, so you can hack around with patchy solutions long enough before the thing falls apart(and frequently it does when you are not around anymore). Also, that idea seems appealing on the intuitive level for money spending, hiring person with broader skills(no matter quality) may look like doing more for the same cost.&lt;/p&gt;

&lt;p&gt;We get mediocre solutions created by people who don't have enough expertise in the particular field to see the better way, with a sketchy knowledge filled with Stackoverflow answers and copy-paste. We get people who stay stale in their improvements, having to keep up with too many topics. We get the professionals that don't create amazing things because they don't have time to dig in enough time to actually create some value to the field. We get &lt;strong&gt;substandard&lt;/strong&gt; products by lower development price that fades off after the bugs and lost customers come in because of issues the projects inevitably face when developed in such the fashion.&lt;br&gt;
Fullstack may be worth it from the short-term economical perspective, but it is harmful for the industry overall and for the projects we build.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>fullstack</category>
    </item>
    <item>
      <title>DSLs for non-programmers are a hoax</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Sat, 25 May 2019 08:44:20 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/dsls-for-non-programmers-are-a-hoax-3m47</link>
      <guid>https://dev.to/arturmartsinkovskyi/dsls-for-non-programmers-are-a-hoax-3m47</guid>
      <description>&lt;h1&gt;
  
  
  The bright future
&lt;/h1&gt;

&lt;p&gt;In software engineering there were always ideas of automation and generality that will lead the body of work for the field to be elevated to the context where someone who does not know ins and outs of particular domains low structure and basis to perform tasks and fulfill the needed features easily. The belief in an all-powerful magic wand that is able to make most of the professionals of the field obsolete. Visual programming, code generation - there are a lot of flavors that muddle the minds of every new generation of programmers and executives in the field. Every time it fails for a reason - the domain is complex and so is the software engineering. Any simplified and constrained procedure that magically lets you create software without actually writing it sooner or later reveals itself as inefficient and inadequate when complexity of the features rises and details emerge form the murky minds of the business team.&lt;/p&gt;

&lt;h1&gt;
  
  
  Kings in their domain
&lt;/h1&gt;

&lt;p&gt;Another idea that seems treacherously different from beforesaid ones is the domain specific languages concept. Domain specific language is an extension of general-purpose language or a brand-new separate one that exists in the context of particular domain, trying to simulate the structure, concepts and vocabulary used in the domain in order to let people write code in a highly abstracted fashion leaving off technical details and focusing on important topics and actual features. Sounds great, yeah? Programmers extend the DSL as needed, business team writes its own code and configures the program the way the would have written requirements for the development team, everything is developed faster and more in line with what was actually intended, everyone is happy, world is getting better.&lt;/p&gt;

&lt;h1&gt;
  
  
  [A-Z]*L in the wild
&lt;/h1&gt;

&lt;p&gt;As with any silver bullet, the theory looks amazing, but in practice it turns out to be quite &lt;em&gt;shite&lt;/em&gt;. Why so? Remember SQL? &lt;a href="https://dl.acm.org/citation.cfm?doid=800296.811515"&gt;Actually&lt;/a&gt; it was intended for non-programmers such as engineers, accountants or architects(not software ones).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;However, there is also a large class of users who, while they are not computer specialists, would be willing to learn to interact with a computer in a reasonably high-level, non-procedural query language. Examples of such users are accountants, engineers, architects, and urban planners. It is for this class of users that SEQUEL is intended...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The last time I had a business analyst that wanted to write SQL, he tripped over one join and ask me to do the job. SQL is used widely, but it does not work that well for people who are not programmers. HTML and XML were also originally intended for non-programmers - where are they now? They are used by amateurs or enthusiasts sometimes, but most of the time programmers do the job.&lt;/p&gt;

&lt;h1&gt;
  
  
  Domain specific madness
&lt;/h1&gt;

&lt;p&gt;Those were the existing languages developed by committees, thought and worked through, more or less general. They did not become widely popular among business people and other professions because they needed some attention, learning and understanding from the user in order to be effective. In the end when the serious stuff comes in it was always a better choice to hire someone who really understood what he was doing. In some sense they succeeded. But, every once in a while an executive, CTO or somebody else on the semi-technical/semi-management position gets a brilliant idea of writing own DSL for business processes of the project. Let's do it, people, write a language and it will be easier for everybody to work on the project. They choose Ruby, Python, some flavor of LISP or JVM family and start writing code that must look similar to proper English of the domain. Business people start using it, handing a lot of complaints on mismatches, dumb stuff and insufficient documentation. Programmers fix and extend the DSL, but abstraction starts to leak revealing corner cases and essential technical details. More and more work and actual domain code writing is done by the programmers and the project ends up with another wheel developed inside the team that is not really used by the business, but programmers have to write code for it because the codebase is quite large enough already and rewrite will take ages. &lt;/p&gt;

&lt;p&gt;Why does it happen like that? There are multiple reasons. Business is complex and domains transform every now and then. Domain specific language is intended to represent the body of the domain and in order to sync up it needs to change frequently same as its real world counterpart. It overlays the need to write fluent interface that will be convenient to use which makes the task even harder. Actual language is written by the people that don't know that much about the domain - software engineers. There will be missed significant details, improper wording and all kinds of issues with understanding. The user of this language, a business person, is not a software engineer, so when the existing language won't be enough for some feature it will inevitably lead to another language extension and more changes to codebase that may cause errors of its own. Domain languages are constrained, ideas are not. Unfortunately, degeneration and rot is immanent, so sooner or later support cost and meandering of the monster created by a thousand extensions starts to outweigh seeming benefits of the DSL.&lt;/p&gt;

&lt;h1&gt;
  
  
  Not all DSLs
&lt;/h1&gt;

&lt;p&gt;After all of this, you might have though that I deem DSLs to be a totally bad idea. I don't. I dislike them only when they are developed to display some business domain or to be handed over to regular users, non-programmers. If it is developed for programmers or for the domain that does not change frequently it is perfectly fine. There are AWK, RSpec, EJS, Emacs Lisp, bash scripts and a lot of others that are cool because their domains are steady and they are used by professionals.&lt;/p&gt;

&lt;p&gt;P.S. I hate Gherkin, Cucumber and other DSLs that let you write the tests that "read like English", but that is the conent for another story.&lt;/p&gt;

</description>
      <category>dsl</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to bring some intelligence from your work to your fun</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Thu, 09 May 2019 17:23:23 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/enlightened-entertainment-4h8b</link>
      <guid>https://dev.to/arturmartsinkovskyi/enlightened-entertainment-4h8b</guid>
      <description>&lt;h1&gt;
  
  
  Life is short, but thinking about it only makes it shorter
&lt;/h1&gt;

&lt;p&gt;Humans have an expiration date. You have to admit this. The clock is ticking and every second goes into the past leaving your cycle with one less step to be executed. The thread will inevitably be dead sooner or later(unless you believe into zombies or recurring threads but this is a different story). It is not guaranteed that it will execute its purpose and you never know when the scheduler goes awry and wipes you out. But... You have something. You have now. If you are reading this, you are a living and (I hope) thinking creature. A creature that has some time left.&lt;/p&gt;

&lt;p&gt;Our life consists of many parts - we sleep for about 8 hours a day, we work for about the time 5 days a week, we lie around questioning our existence for another hour before or after work depending on our circadian rhythm. Also, we amend our Vim config for a substantial amount of time. We do a lot of stuff that may be worth a couple of other posts. But now I want to speak about the thing you certainly do no matter how old you are. where you are from or what is your puppy middle name(do they have those? they have passports, gosh). I want to speak about the entertainment.&lt;/p&gt;

&lt;h1&gt;
  
  
  Entertainment enterprise explained by escapists
&lt;/h1&gt;

&lt;p&gt;It is a lovely nice thing we do to escape the dystopian reality we live in that comes closer to the cyberpunk dreams of Philip K. Dick or goddamn Gibson each time Apple/Samsung/Google launches something and ships to a third-world(I mean developing, of course, don't blame me, I live in one) country. Low live, high tech, you know. Where was I? Oh yeah, entertainment. Mostly, nowadays, this activity involves some kind of screen. It may be a screen of your phone, your 4K TV set, E-Book, laptop, public cinema theatre, you name it. Some of us do sports, drugs or other activities, but in the digital era, digital fun is the most popular one.&lt;/p&gt;

&lt;p&gt;You work, you study to get better for work, you optimize your time and get better with what you do. But entertainment is the different thing - there is no need to optimize this - you are just having fun, this area historically does not involve any kind of consideration, planning or analysis, it is a place out of work, so you do the thing that feels better. Right? Wrong. Your life is a whole, why put limits on which approaches should come where? Try to use your &lt;em&gt;serious&lt;/em&gt; mind and approach your fun with it. What do you do for fun? You play video games, watch cool stuff on Netflix and YouTube, read 9gag and Twitter, traverse Facebook feed and Reddit. What does it bring to you? A bunch of useless information about the people you don't care about, life-changing experiences that did not happen to you but the magic of video and plot design does let you feel that you are living through that, aggression throwaway by killing other people online and a few memes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Junk life is no life
&lt;/h1&gt;

&lt;p&gt;Let's bring in the analogy. There is healthy food and junk food - first is delicious mostly if you are used to it and get a whip of the diet, the second is created to be tasty enough for you to want to eat it &lt;strong&gt;despite&lt;/strong&gt; its malicious effect in the long-term. Your stomach intestines are a machine to process food and extract energy from it, your brain also is a processing engine. It processes information. Not all information is equally good. It may feel good but is actually junk. Most of the modern entertainment industry serves the purpose of getting your money one way or another. Those people want you to feel like you are getting something valuable(feelings, information, a lesson for life), but actually, you are not. If you get proper food and stick to a diet, your digestive system will function properly and you will be feeling good. Same goes for your brain. In order to create something valuable, it needs to deconstruct something valuable.&lt;/p&gt;

&lt;p&gt;If all you get is lets plays, dumb comedies and so-so clickbaity news about celebs and crime, you are highly unlikely to produce something with better quality with your mind. There is a lot of stuff in the world you don't yet know about: Sumerians, Lead 70-s in Italy, Enlightened monarchs, von Neumann, Claude Shannon, Dwarf Fortress, Nestor Makhno. There are better ways and better material to read, watch, play and think over than the featured stuff you are fed with by mainstream. Mainstream is oriented on the average citizen - a person with moderate views, absent taste that is not willing to get much information for consideration. Their expected audience expects for most of the a-ha moments to be chewed and fermented for them. It affects the depth of material, the real meaning of certain events and dumbs down ideas you may get from your media. Don't fool yourself, seek for the source, not for the preprocessed semifabricate.&lt;/p&gt;

&lt;h1&gt;
  
  
  All lives are final
&lt;/h1&gt;

&lt;p&gt;So, you have a resource - time and a way to use that resource - entertainment. Time is limited, your desire for entertainment is endless. It is better to plan what you will digest into your information tube the next time. Look through the watchlists, read lists, playlists of other people in order to get some aspiration. Last.fm may suit for music, Goodreads is great if you want to get some suggestions on less well-known great literature to read, for movies you can just traverse shortlists of famous awards and personal blogs of people that are not critics but love movies - some of them may suggest you pretty good directors and movies to get your spot on.&lt;/p&gt;

&lt;p&gt;Sometimes professional development also needs some motivation. There are popularly written books on the history of a lot of professions, biopics, and biographies. Knowing personalities in the field lets you wire yourself with the industry a bit closer and reflect their experience on your own. For engineers, there are tons of techno-porn in sci-fi, cyberpunk and other tech-related genres that will load you up with energy to stand up and do stuff to get the world from the screen or page closer to you.&lt;/p&gt;

&lt;h1&gt;
  
  
  No refund or return policy is provided
&lt;/h1&gt;

&lt;p&gt;Also, try to get yourself out of the digital world sometimes. Transhumanism is soon to come and we will all be in the Matrix without an ability to walk under the sun having fun in the virtual reality, so you gotta enjoy the real world while you can be in one. On a serious note, our minds and bodies need a variety of activities in order to function properly. Having all your fun before the screen and your head is not the ultimate way. Cycling, other sports, low-level electronics with wires and magnifiers, carving and steelworks, there are ways to feel the same joy in the real world as you do virtually. This way you will be able to enjoy both real and virtual world pleasures not feeling too full on some side.&lt;/p&gt;

&lt;p&gt;Most importantly - don't divide fun and work into two different and disjoint worlds. Try to have fun when you work and get benefit while you play around. This is the same life in both cases. Make it holistic, make it worth it.&lt;/p&gt;

</description>
      <category>life</category>
      <category>entertainment</category>
    </item>
    <item>
      <title>I failed last onsite step of Facebook interview at Dublin, Ask Me Anything!</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Mon, 06 May 2019 15:55:09 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/i-am-a-computer-science-student-in-ukraine-and-ruby-software-engineer-working-in-outsource-ask-me-anything-50eg</link>
      <guid>https://dev.to/arturmartsinkovskyi/i-am-a-computer-science-student-in-ukraine-and-ruby-software-engineer-working-in-outsource-ask-me-anything-50eg</guid>
      <description>

</description>
      <category>ama</category>
    </item>
    <item>
      <title>IMHO considered harmful</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Mon, 06 May 2019 09:39:22 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/imho-considered-harmful-l74</link>
      <guid>https://dev.to/arturmartsinkovskyi/imho-considered-harmful-l74</guid>
      <description>&lt;p&gt;People like to share their opinions. They do it in the comments, articles, in their speech, even the text you are reading now is an opinion of the one who wrote the post. It is alright to have an opinion, to think about reality, map the teritory of surrounding world and stuff in it then sharing your map with others. Expressing your thoughts to others and getting their mind on some topic is a valuable element of societal development and aids us all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Onion of opinon, crying up for help
&lt;/h1&gt;

&lt;p&gt;Although, shielding yourself and your opinion from the possible criticism and serious consideration by other people is not alright. Quite frequently I see people start their posts or comments with IMHO disclaimer followed by actual material they want to share with the world. This is wrong on many levels.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--diX5fqkJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p4qosm2520mai52flbrd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--diX5fqkJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/p4qosm2520mai52flbrd.png" alt="IMHO"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Humility considered harmful
&lt;/h1&gt;

&lt;p&gt;IMHO serves as training wheels of idea, saying to the world - don't judge me, it is just an opinion and may be wrong. It discourages people from getting into discussion and taking the opinion seriously. Why even start expressing the thought if you are not certain that you can protect and/or adjust it if someone points at some warts of your theory? &lt;/p&gt;

&lt;p&gt;Being unsure of some things in your worldview is normal as far as you point at the explicitly and explain the uncertainty you have about them. Such explanation may be a foundation of fruitful conversation and aspire people to get their mind on an issue. IMHO is different, it is a kind of discussion-stopper that does not pose any questions to ask being only a stop sign. It does not explain anything, it simply shows that person is reassuring to avoid an attack on their ideas and building a safehouse of  (rather helpless) humility.&lt;/p&gt;

&lt;p&gt;It is a way of lazy thinking that leads to slippery ice of &lt;a href="https://en.wikipedia.org/wiki/Relativist_fallacy"&gt;subjectivist fallacy&lt;/a&gt;. If this is &lt;em&gt;only&lt;/em&gt; your opinion and not an idea you want to show to be true, you can just hop through the steps required to make it credible, you can claim that truth in this context is relative because we speak about &lt;em&gt;opinions&lt;/em&gt; and not &lt;em&gt;facts&lt;/em&gt; and deflect any criticisim with a shiny shield of &lt;strong&gt;relativism&lt;/strong&gt;. It is a magic wand of ignorance that should not be used by any measures. Some subjectives are better than the others and there is a measure to it which is disbanded by this four letter abbreviation. Some ideas are better than the others and giving every idea a participation prize we don't get closer to the truth and practicality. We harm them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Baby, don't do no harm
&lt;/h1&gt;

&lt;p&gt;Stand for your ideas, be brave to mistake and correct your hypothesis until you reach a level of certainty that makes an idea good. But please, don't shell up with being humble as this does not help you to get closer to the truth.&lt;/p&gt;

&lt;p&gt;P.S. This is my opinion, but I don't regard it as humble and ready to discuss it.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>blogging</category>
    </item>
    <item>
      <title>Rubyish flyweight</title>
      <dc:creator>Artur Martsinkovskyi</dc:creator>
      <pubDate>Mon, 06 May 2019 08:10:33 +0000</pubDate>
      <link>https://dev.to/arturmartsinkovskyi/rubyish-flyweight-3afp</link>
      <guid>https://dev.to/arturmartsinkovskyi/rubyish-flyweight-3afp</guid>
      <description>&lt;p&gt;Ruby is a nice and elegant language, which is magically appealing in its expressiveness. Thanks to its agility, it allows natural and intuitive solutions where other languages require boilerplate and bloat to reach the same goal. Here is an example of it.&lt;/p&gt;

&lt;p&gt;Recently I was hacking through a game design patterns handbook and encountered an interesting pattern used all over the place in game development. This pattern is &lt;a href="http://gameprogrammingpatterns.com/flyweight.html"&gt;&lt;em&gt;Flyweight&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ufD9IHSi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frdix37cxdjrtki5g3kg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ufD9IHSi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/frdix37cxdjrtki5g3kg.png" alt="Flyweight"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As Wikipedia says: "In computer programming, flyweight is a software design pattern. A flyweight is an object that minimizes memory usage by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. Often some parts of the object state can be shared, and it is common practice to hold them in external data structures and pass them to the objects temporarily when they are used."&lt;/p&gt;

&lt;p&gt;Commonly in most languages this pattern is &lt;a href="https://sourcemaking.com/design_patterns/flyweight/python/1"&gt;implemented&lt;/a&gt; using a factory, an abstract class and inheritance of that class. In Ruby, it may be implemented less noisy. Due to the fact that Object.new is not a special language construct, but just a method we are able to have our own class constructor serve as a factory, just overriding it. Below you can see how it works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Flyweightable&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stored_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;stored_instance&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stored_instance&lt;/span&gt;

    &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;allocate&lt;/span&gt;
    &lt;span class="n"&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="ss"&gt;:initialize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;store&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;attributes&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&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;store&lt;/span&gt;
    &lt;span class="vi"&gt;@store&lt;/span&gt; &lt;span class="o"&gt;||=&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;class&lt;/span&gt; &lt;span class="nc"&gt;Point&lt;/span&gt;
  &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:y&lt;/span&gt;
  &lt;span class="kp"&gt;extend&lt;/span&gt; &lt;span class="no"&gt;Flyweightable&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
    &lt;span class="vi"&gt;@y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;y&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;euclidian_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="no"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&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="nf"&gt;manhattan_distance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;point&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;y&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;abs&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;Flyweightable module overrides new method and creates a memoized storage inside of the class that will hold a registry of all flyweights instantiated. If a flyweight with parameters passed in the constructor exists it just returns it, else it creates a flyweight and writes it into the registry.&lt;/p&gt;

&lt;p&gt;Such Flyweight implementation has all the benefits of original pattern, leaving instatiation untouched, making external interface as fluent as it was before makin class a Flyweight. It is important to remeber that this pattern should be used for classes that you deem values like points, textures or other enumeratable objects that can be uniquely identified, not references at objects with changeable state.&lt;/p&gt;

&lt;p&gt;Caveats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Classes that mix in that module must be read-only as a requirement for Flyweight (else it becomes clumsy and out of sync when objects get their state updated elsewhere)&lt;/li&gt;
&lt;li&gt;Registry is implemented using hash will most likely be live through the whole runtime of you program, so in case of a gazillion of unique objects Flyweight might not be suitable&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same technique(constructor override) may be used in a variety of ways, like dynamic building dispatch or multiple dedicated constructor with different names to break one constructor per class restriction.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

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