{"id":659,"date":"2016-05-31T20:18:39","date_gmt":"2016-06-01T04:18:39","guid":{"rendered":"http:\/\/www.timrosenblatt.com\/blog\/?p=659"},"modified":"2016-05-31T20:23:26","modified_gmt":"2016-06-01T04:23:26","slug":"dependency-inversion-principle","status":"publish","type":"post","link":"http:\/\/www.timrosenblatt.com\/blog\/2016\/05\/31\/dependency-inversion-principle\/","title":{"rendered":"Dependency Inversion Principle"},"content":{"rendered":"<p><a href=\"https:\/\/en.wikipedia.org\/wiki\/Dependency_inversion_principle\" target=\"_blank\">Dependency Inversion<\/a> is one of the five SOLID OO principles that&#8217;s become so popular in recent years (sometimes referred to as DIP). My opinion is that it&#8217;s a highly valuable concept, and is not well-named. &#8220;Dependency inversion&#8221; doesn&#8217;t mean a great deal on its own, and a lot of attempts to explain it tend to get very heady.<\/p>\n<p>(Speaking of unfortunate naming, &#8220;hexagonal architecture&#8221; is another concept that I find\u00a0poorly named. Ironic that the concept is about using abstraction to avoid unnecessary coupling, yet the name itself couples the idea to the number 6, which is totally unrelated to the idea. Fortunately, it&#8217;s slowly being renamed as &#8220;ports and adapters&#8221; in most discussions, which is a much better description.)<\/p>\n<p>My personal preference is towards explanations that are more intuitive, and I&#8217;d like to put my two cents in for Dependency Inversion.<\/p>\n<p>To me, a way of describing Dependency Inversion is to <strong><em>use classes to separate the features of the application (the parts that a user might use) from the technology that makes the feature work<\/em><\/strong>.<\/p>\n<p>For example, let&#8217;s say you have a feature where a user can sign themselves up, and once the user&#8217;s information is saved to the database, you have some more steps that need to take place. You could make an <a href=\"http:\/\/eng.joingrouper.com\/blog\/2014\/03\/03\/rails-the-missing-parts-interactors\" target=\"_blank\">interactor<\/a> called<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">CompleteUserSetup<\/pre>\n<p>and it will handle the actions necessary (instead of using a callback).<\/p>\n<p>Let&#8217;s say one of the things it needs to do is send an email welcoming the user.\u00a0Let&#8217;s also pretend that you use SendGrid to manage emails. That would mean we\u00a0<em><strong>could<\/strong><\/em> end up with something like<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nclass CompleteUserSetup\r\n  def self.perform\r\n    SendGridClient.email &quot;subjectline&quot;, &quot;body of email&quot;\r\n  end\r\nend\r\n\r\nCompleteUserSetup.perform\r\n<\/pre>\n<p>Will this run? Absolutely. Is it a good example of code that meets the criteria for Dependency Inversion? No.<\/p>\n<p>What&#8217;s happening here is that the feature (user setup) is directly mentioning the technology that implements it (SendGrid). It literally has the name of the tool in the code that is defining the feature.<\/p>\n<figure style=\"width: 500px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"\" src=\"http:\/\/65.media.tumblr.com\/tumblr_m3yvstPTXq1rskrjjo10_500.jpg\" alt=\"\" width=\"500\" height=\"386\" \/><figcaption class=\"wp-caption-text\">Literally Rob Lowe<\/figcaption><\/figure>\n<p>Since there are probably lots of places in the code that send email, if you ever need to switch away from SendGrid, you need to change all those places. Usually it&#8217;s not as simple as find-replacing all the instances of &#8220;SendGrid&#8221; from the code, so a better way is to abstract all of the email interactions into your own class.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nclass CompleteUserSetup\r\n  def self.perform\r\n    OurEmailClient.send_welcome_email\r\n  end\r\nend\r\n\r\nclass OurEmailClient\r\n  def self.send_welcome_email\r\n    SendGridClient.email &quot;subjectline&quot;, &quot;body of email&quot;\r\n  end\r\nend\r\n\r\nCompleteUserSetup.perform\r\n<\/pre>\n<p>Now the feature doesn&#8217;t mention the implementation technology. If you kept this pattern going, &#8220;SendGrid&#8221; would only ever appear in your email client class, and this means that the technology would be decoupled from the features. This is an Adapter pattern, which is basically the first half of Dependency Inversion. (IMHO this is the most common implementation of DI, and this makes testing really easy)<\/p>\n<p>To close the loop of &#8220;Dependency Inversion&#8221; is to actually pass the client an instance of an email client so it can use more than one.<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\nclass CompleteUserSetup\r\n  def self.perform(client)\r\n    client.send_welcome_email\r\n  end\r\nend\r\n\r\nclass OurEmailClient\r\n  def send_welcome_email\r\n    SendGridClient.email 'subjectline', 'body of email'\r\n  end\r\nend\r\n\r\nclass OurOtherEmailClient\r\n  def send_welcome_email\r\n    MailChimpClient.email 'subject, 'body of email'\r\n  end\r\nend\r\n\r\nemail_client = OurEmailClient.new\r\nCompleteUserSetup.perform(email_client)\r\n\r\n# or\r\n\r\nemail_client = OurOtherEmailClient.new\r\nCompleteUserSetup.perform(email_client)\r\n<\/pre>\n<p>Now we&#8217;re actually passing the dependency into the location where it&#8217;s needed. This means the CompleteUserSetup interactor is totally decoupled from which messaging system it will use.<\/p>\n<p>The reason this matters is that now we can choose any type of email provider we currently support, and we can also add new types of email providers that we didn&#8217;t previously use.<\/p>\n<p>To be fair, in Ruby, this isn&#8217;t quite the same as in Java. Ruby will allow duck typing, which means that we don&#8217;t have to write an Interface. Also, <a href=\"http:\/\/metabates.com\/2011\/02\/07\/building-interfaces-and-abstract-classes-in-ruby\/\" target=\"_blank\">Ruby doesn&#8217;t support Interfaces at all<\/a>, so that aspect of this is missing. Still &#8212; the principle\u00a0behind decoupling does make it very easy to write readable code, and testable code, and I\u00a0always love that.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Dependency Inversion is one of the five SOLID OO principles that&#8217;s become so popular in recent years (sometimes referred to as DIP). My opinion is that it&#8217;s a highly valuable concept, and is not well-named. &#8220;Dependency inversion&#8221; doesn&#8217;t mean a great deal on its own, and a lot of attempts to explain it tend to &hellip; <a href=\"http:\/\/www.timrosenblatt.com\/blog\/2016\/05\/31\/dependency-inversion-principle\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Dependency Inversion Principle&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":{"footnotes":""},"categories":[145],"tags":[],"_links":{"self":[{"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/posts\/659"}],"collection":[{"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/comments?post=659"}],"version-history":[{"count":10,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/posts\/659\/revisions"}],"predecessor-version":[{"id":669,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/posts\/659\/revisions\/669"}],"wp:attachment":[{"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/media?parent=659"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/categories?post=659"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.timrosenblatt.com\/blog\/wp-json\/wp\/v2\/tags?post=659"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}