{"id":215,"date":"2021-01-28T00:44:02","date_gmt":"2021-01-27T22:44:02","guid":{"rendered":"http:\/\/victorrentea.ro\/blog\/?p=215"},"modified":"2021-01-28T00:44:02","modified_gmt":"2021-01-27T22:44:02","slug":"the-clean-switch-rules","status":"publish","type":"post","link":"https:\/\/victorrentea.ro\/blog\/the-clean-switch-rules\/","title":{"rendered":"The Clean Switch Rules"},"content":{"rendered":"<div id=\"bsf_rt_marker\"><\/div><p>From all the syntax constructs of modern programming languages, the <code>switch<\/code> construct is the most prone to degenerate into an unmaintainable mess unless we take aggressive actions. This article introduces the rules to follow to keep your switches clean and pleasant.<\/p>\n<h2>Switches in Legacy Code<\/h2>\n<p>I asked hundreds of developers attending my classes if they love switches. The developers just starting their careers are usually inclined to answer \u201cyes\u201d, while those older in our branch all tend towards a firm \u201cno\u201d, especially if they got to work on a 5+ years-old legacy codebase. Here, the term \u201clegacy\u201d stands for massive code written in an extremely procedural, monolithic style, with some functions having over 1000 lines of code. <\/p>\n<p>Many of the monster legacy functions contain switches that span 4-5 screens, sometimes up to hundreds of lines. Those more unfortunate of us even saw switches nested inside other switches. That\u2019s something you can never forget, once you see it:<\/p>\n<pre><code>switch(y) {\ncase a:\n  ...\n  switch (x) {\n    case xa:\n      ...\n      break;\n    ...\n  }\n  \/\/ more pain\ncase b:\n  ...\n}<\/code><\/pre>\n<p>You would never write such code, I know. The clean code principles are far more popular today than 15 years ago, but it\u2019s interesting to ask ourselves: why? What makes switches grow this big? What\u2019s unique about this particular syntax construct?<\/p>\n<p>The reason is human psychology. <\/p>\n<p>Let me explain.<\/p>\n<p>When you create a switch, it always starts small and cute:<\/p>\n<pre><code>switch (...) {\n  case STUFF: \n    \/\/ one line of code\n    break;\n  case FLUFF: \n    \/\/ just a bit more code\n    break;\n}<\/code><\/pre>\n<p>But then, sometime after, a colleague (or maybe yourself) comes around with 3 lines of FLUFF logic to add somewhere. And since the switch already has 10 lines of code, adding 3 more doesn\u2019t harm, right? So now it\u2019s 13 lines. Several weeks after another fellow comes by, carrying 5 lines of STUFF logic. And of course, where 13 lines fit, 5 more won\u2019t make any difference. 18 lines. And so, the switch starts growing.<\/p>\n<p>The theory behind this phenomenon is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Broken_windows_theory\">The Broken Windows Theory<\/a>: \u201ca criminological theory that states that visible signs of crime, anti-social behavior, and disorder create an environment that encourages further crime and disorder, including serious crimes\u201d.<\/p>\n<p>In other words, abandonment attracts more abandonment.<\/p>\n<p>What\u2019s unique about a <code>switch<\/code> is that it is by definition a \u2018lengthy\u2019 syntax: even a simple switch can easily span dozens of lines, leading people to feel it\u2019s ok to add more code to it.<\/p>\n<h2>Switch Statement Weaknesses<\/h2>\n<p>Besides attracting more code, the <code>switch<\/code> statement has a series of technical limitations, both in Java and C\/C++;<\/p>\n<h3>Break!<\/h3>\n<p>You need to remember to <code>break;<\/code> at the end of each <code>case<\/code> block. But it\u2019s worse: sometimes you need to fall-through from one <code>case<\/code> to the next one because multiple values are handled in the same way. So you can\u2019t demand a <code>break;<\/code> after each <code>case<\/code>. <\/p>\n<p>However, if you ever encounter code like<\/p>\n<pre><code>case X:\n  \/\/ code1\ncase Y:\n  \/\/ code2\n  break;<\/code><\/pre>\n<p>That\u2019s almost always a bug &#8211; a <code>break;<\/code> is missing after <code>\/\/ code1<\/code>. However, the code could be correct if <code>\/\/ line1<\/code> would not be there.<\/p>\n<h3>Variable Leaking<\/h3>\n<p>Variables defined in one <code>case<\/code> are visible in the <code>case<\/code> clauses below! For example, this code doesn\u2019t compile:<\/p>\n<pre><code>switch (x) {\n  case A:\n    int i = 1;\n    break;\n  case B:\n    int i = 2; \/\/ does not compile !!\n    break;\n}<\/code><\/pre>\n<p>This variable leaking can make the code harder to trace, especially in large, gruesome legacy code. But here\u2019s a nice trick you can use to work your way out: enclose the body of each <code>case<\/code> within an artificial block: <code>case A: { int i = 1; break;}<\/code>. This will cause the variable <code>i<\/code> to be scoped to that <code>{ }<\/code> block, stoping it from leaking to the next <code>case<\/code>.<\/p>\n<p>But now let&#8217;s fix the switch.<\/p>\n<h2>The Clean Switch Rules<\/h2>\n<p>I\u2019ve brainstormed these rules with hundreds of developers, but I\u2019ll try to summarize the main points here. Let me start with the strangest one:<\/p>\n<blockquote>\n<p>Rule #1: The <code>switch<\/code> is the only thing in that function.<\/p>\n<\/blockquote>\n<p>In other words, there must be nothing before or after the <code>switch<\/code>. No method call or <code>return<\/code> afterward. No variable definition or initial call before it. Nothing. The switch should occupy the entire body of the host function. Crisp, sharp code.<\/p>\n<p>Why? To minimize the temptation to add more code in there, given the <code>switch<\/code> syntax is inherently lengthy by itself.<\/p>\n<p>The only <strong>exception<\/strong> to this rule is an initial <code>null<\/code> guard-clause for the String you switch on: in Java there\u2019s a bytecode performance optimization that may cause <code>NullPointerException<\/code> if <code>s<\/code> comes <code>null<\/code>:<\/p>\n<pre><code>public void f(String s) {\n  if (s == null) return; \/\/ exit, avoid NPE\n  switch(s) {\n    ...\n  }\n}<\/code><\/pre>\n<p>But passing <code>null<\/code> Strings around is a bad idea anyway, so this case turns up very rarely in practice.<\/p>\n<blockquote>\n<p>Rule #2: Every <code>switch<\/code> must end with <code>default: throw ...<\/code> <\/p>\n<\/blockquote>\n<p>I guess that\u2019s obvious for most developers. You want to throw an exception for any unexpected value. <\/p>\n<p>Imagine switching on an enum. You carefully defined a <code>case<\/code> for each enum value, and everything goes well. Later you add a new value to that enum, but you forget to add the corresponding <code>case<\/code> to this <code>switch<\/code>. Having a <code>default: throw<\/code> in place will signal the problem at runtime, which is almost always preferable to ignore it silently.<\/p>\n<pre><code>default: throw new IllegalArgumentException(\u201cUnsupported: \u201c + value);<\/code><\/pre>\n<p>There\u2019s only one <strong>exception<\/strong> to this rule: if you are 100% certain that any unexpected value won\u2019t ever need to be handled, you can either (a) skip the <code>default:<\/code> clause if you\u2019re in a function returning <code>void<\/code>, or (b) <code>default: return 0;<\/code> (or any reasonable value) instead of <code>throw new<\/code>. Be extra careful as by <em>unexpected value<\/em> I mean both strings\/ints that you didn\u2019t plan for, but also enum values that will be added in the future if you switch on an enum.<\/p>\n<p>But in the vast majority of cases, Rule #2 applies perfectly<\/p>\n<p>And now, the most powerful and difficult rule to follow:<\/p>\n<blockquote>\n<p>Rule #3: Every <code>case<\/code> must have a single line.<\/p>\n<\/blockquote>\n<p>In other words, any logic longer than a single line of code needs to go into a separate function that you call from the <code>case<\/code>.<\/p>\n<pre><code>case X: return computeForX(...);<\/code><\/pre>\n<p>This rule will keep your switch devoid of logic. Deciding between multiple flows is enough for the poor <code>switch<\/code>. Don\u2019t overload it!<\/p>\n<p>But what if the <code>switch<\/code> is in a function returning <code>void<\/code>? Then, you have to <code>break;<\/code> after calling the function, like this:<\/p>\n<pre><code>case X: handleX(...); break;<\/code><\/pre>\n<p><strong>Exceptions<\/strong> to this rule?<br \/>\nVery tiny switches with only 2-3 cases, that need to do 2 lines of code. Only then&#8230; Maybe&#8230;<br \/>\nBut by any means NEVER put a <code>for<\/code>, an <code>if<\/code> or a <code>try<\/code> under a <code>case:<\/code>!<\/p>\n<h2>Summary<\/h2>\n<p>The three rules of a clean <code>switch<\/code>:<\/p>\n<ol>\n<li>it is the only thing in that function<\/li>\n<li>ends with <code>default: throw ...<\/code><\/li>\n<li>has one-liner <code>case<\/code> clauses<\/li>\n<\/ol>\n<p>PS: for the Java developers moving to Java 17 in autumn 2021, following these three rules will ease the transition to the long-awaited enhanced switch. More on that in a future blog post. \ud83d\ude42<\/p>\n","protected":false},"excerpt":{"rendered":"<p>From all the syntax constructs of modern programming languages, the switch construct is the most prone to degenerate into an unmaintainable mess unless we take aggressive actions. This article introduces the rules to follow to &hellip; <\/p>\n","protected":false},"author":1,"featured_media":216,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[8,2],"class_list":["post-215","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-practical-tips","tag-best-practices","tag-clean-code"],"_links":{"self":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/215","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/comments?post=215"}],"version-history":[{"count":1,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/215\/revisions"}],"predecessor-version":[{"id":217,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/posts\/215\/revisions\/217"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/media\/216"}],"wp:attachment":[{"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/media?parent=215"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/categories?post=215"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/victorrentea.ro\/blog\/wp-json\/wp\/v2\/tags?post=215"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}