{"id":806,"date":"2015-01-12T16:14:30","date_gmt":"2015-01-12T21:14:30","guid":{"rendered":"http:\/\/wcarss.ca\/log\/?p=806"},"modified":"2015-01-12T19:42:46","modified_gmt":"2015-01-13T00:42:46","slug":"write-once-copy-once-refactor-once","status":"publish","type":"post","link":"https:\/\/wcarss.ca\/log\/2015\/01\/write-once-copy-once-refactor-once\/","title":{"rendered":"Write once, copy once, refactor once."},"content":{"rendered":"<p>This post is about effectively using your time. It is not a defence of taking on huge technical debt to make your life easier for a single\u00a0day, and you are hopefully smart enough to avoid doing that. It&#8217;s just a simple approach to growing a system you&#8217;re working on while avoiding duplication of effort and over-engineering.<\/p>\n<h1>Write once.<\/h1>\n<p>The first time you have to do it, just get it done. You&#8217;ll be in the best position to improve your solution once it <strong>actually exists<\/strong>, by knowing real things about how well it solves your problem. Plus, at that point, it&#8217;s already solving your problem.<\/p>\n<p>You may be tempted to\u00a0figure out\u00a0the best solution\u00a0before writing <em>anything<\/em>, which in my experience is a huge waste of time. If you haven&#8217;t written it yet, figuring out which bells and whistles to add is time-consuming and error-prone.<\/p>\n<h1>Copy once.<\/h1>\n<p>You got it done, a week\u00a0passes, and a new problem comes up that feels almost the same. Assuming you can&#8217;t just use\u00a0the thing you wrote\u00a0before, you can:<\/p>\n<ol>\n<li>Refactor your code to make the original useable\u00a0in both spots.<\/li>\n<li>Copy your code\u00a0to the new spot.<\/li>\n<\/ol>\n<p>Most people\u00a0want to refactor now, but I think you should copy. Why?<\/p>\n<h2>It is very hard to determine\u00a0patterns from just two\u00a0examples.<\/h2>\n<p>With two instances, statements about the group as a whole are wild\u00a0guesses. A simple illustration &#8212;\u00a0consider these two numbers:\u00a01, 2, &#8230;<\/p>\n<p>The next number might\u00a0be 4, 3, 1, 57, or anything else. No clear\u00a0pattern shows up, because <em>two data points<\/em> only have\u00a0<em>one relationship<\/em>, and patterns are formed from the relationships between things. Try three numbers: 1, 2, 3, &#8230;<\/p>\n<p>4 is next, and I&#8217;m sure you saw it coming. This example is admittedly a little weak, but it clearly illustrates that patterns can leap out at 3 things, while being unclear\u00a0at 2. With\u00a0<em>three things<\/em>, you can have up to <em>three relationships<\/em>, and similarities between multiple\u00a0relationships\u00a0are <strong>way<\/strong>\u00a0easier to be think about than similarities between &#8230; one.<\/p>\n<h2>Refactoring after two instances<\/h2>\n<p>Let&#8217;s say you chose to refactor. You put the shared code somewhere ideal for the two cases you know, and rewrite the tests.<\/p>\n<p>Two weeks later, the problem shows up\u00a0elsewhere.\u00a0Is the code\u00a0useable right away in this new spot? If you&#8217;re like me, you gave your abstraction the smallest scope necessary, and you&#8217;ll probably have to move it\u00a0again. You parameterized the minimum amount required, and you may have to add new controls. That was all wasted time and effort.<\/p>\n<h2>So just copy it!<\/h2>\n<p>Almost no effort needed. You&#8217;ll probably have to refactor in two weeks, but you didn&#8217;t waste the time today.<\/p>\n<h2>Objections to copying things:<\/h2>\n<blockquote><p>&#8220;I might forget to update a copy later!&#8221;<\/p>\n<p>&#8220;Copying and pasting leads to typos!&#8221;<\/p><\/blockquote>\n<p>These are both valid points. In the first case, making synchronized changes might lead you to refactor (after all, you&#8217;ve already written once and copied once), and in the second case, the risks aren&#8217;t as big they seem.\u00a0The second case has a nastier form:<\/p>\n<blockquote><p>&#8220;That&#8217;s not DRY!&#8221;<\/p><\/blockquote>\n<p>Not repeating yourself is a well known rule, and endless repetition is obviously bad, but I caution readers to ensure that they aren&#8217;t following DRY\u00a0blindly. You should consider things like the following:<\/p>\n<ul>\n<li>will\u00a0your code be\u00a0easier to read\u00a0with a copy, or with a new abstraction?<\/li>\n<li>will\u00a0the abstraction that makes sense today last beyond\u00a0tomorrow?<\/li>\n<li>will a bad\u00a0abstraction be harder to remove than repetition is?<\/li>\n<\/ul>\n<p>As for copies and typos, most people are intelligent and careful enough to deal with a single copy well. The real horror stories occur\u00a0when you make several copies (3+) of something and they&#8217;re all just a little bit different. Don&#8217;t make three or more copies: just copy once.<\/p>\n<h1>Refactor once.<\/h1>\n<p>Back to that choice from earlier: say you&#8217;d copied it instead of refactoring. Now it&#8217;s two weeks later and you hit a third instance of the problem.<\/p>\n<p>As a quick aside, the &#8220;third instance&#8221; may\u00a0just be a need to change your code in both copies.\u00a0This is a sufficient condition to refactor. Two distant, identical pieces of code needing similar non-trivial changes is a great way to create a bug by messing up minor differences of context. After\u00a0you&#8217;ve written once and copied once, the next step in this approach is always to refactor once.<\/p>\n<p>With\u00a0three instances, you have a good chance of finding patterns. A quick refactor here is going to yield\u00a0even better code than a slow, thoughtful one would have with just two instances of the problem. <em>Context rules.<\/em><\/p>\n<p>Before we move on, what <em>exactly<\/em> does &#8220;having three instances of the problem&#8221; and &#8220;the next step is refactoring it&#8221; mean? There are two paths upon discovering you need the code a third time:<\/p>\n<ol>\n<li>Make a third copy just to see how it fits and that it works, then refactor.<\/li>\n<li>Jump straight to refactoring the first two, and just\u00a0apply\u00a0the solution.<\/li>\n<\/ol>\n<p>The first choice takes longer, but is safer: your code never leaves a working state. This is a little bit like long-division. In complex situations, or when you&#8217;re less experienced, it&#8217;s best to write everything down. You&#8217;ll know which feels right\u00a0when you&#8217;re in this position.<\/p>\n<h2>The Fourth Instance<\/h2>\n<p>What if\u00a0two weeks after your refactor step, you hit the problem yet again, and for some reason you can&#8217;t just use your past work? Why not write once, refactor twice? Or write once, copy twice, refactor once?<\/p>\n<p>In my experience, the fourth-instance-that-doesn&#8217;t-fit-the-pattern is surprisingly rare. Refactoring at the third instance is usually good enough for a long time, so doing it then minimizes the odds that you&#8217;ll have to refactor the same thing twice in a short period.<\/p>\n<p>As for copying twice and refactoring at the fourth instance&#8230; this gets back\u00a0into that &#8220;three copies or more&#8221; zone, where it gets hard to keep minor differences between your solutions straight. Feel free to try, but I bet you&#8217;ll find it to be a serious, bug-causing hassle.<\/p>\n<h1>Write once, copy once, refactor once.<\/h1>\n<ol>\n<li>It&#8217;s faster.<\/li>\n<li>It&#8217;s only slightly more error prone, if at all.<\/li>\n<li>It will probably yield better code in the end.<\/li>\n<\/ol>\n<p>So do what the title says.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This post is about effectively using your time. It is not a defence of taking on huge technical debt to make your life easier for a single\u00a0day, and you are hopefully smart enough to avoid doing that. It&#8217;s just a simple approach to growing a system you&#8217;re working on while avoiding duplication of effort and [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/posts\/806"}],"collection":[{"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/comments?post=806"}],"version-history":[{"count":21,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/posts\/806\/revisions"}],"predecessor-version":[{"id":813,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/posts\/806\/revisions\/813"}],"wp:attachment":[{"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/media?parent=806"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/categories?post=806"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wcarss.ca\/log\/wp-json\/wp\/v2\/tags?post=806"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}