{"id":23,"date":"2012-09-03T10:40:51","date_gmt":"2012-09-03T00:40:51","guid":{"rendered":"http:\/\/blog.rophuine.net\/coder\/?p=23"},"modified":"2014-11-21T08:00:24","modified_gmt":"2014-11-20T22:00:24","slug":"intuitive-interfaces","status":"publish","type":"post","link":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/","title":{"rendered":"Intuitive Interfaces"},"content":{"rendered":"<p><a href=\"http:\/\/agilemanifesto.org\/principles.html\">Agile<\/a>.\u00a0<a href=\"http:\/\/www.crisp.se\/kanban\">Kanban<\/a>.\u00a0<a href=\"http:\/\/theleanstartup.com\/\">Lean Startup<\/a>. We have more and more ways to think about the software development process, and our industry is getting better and better at what we do. We&#8217;re wasting less time, and delivering a more customer-focused product. New businesses have great tools to build great teams. We know how to manage source code, and some people have even worked out how to manage changing data models! Issue tracking is, by and large, a solved problem, and we have tools to keep our software fully tested and behaving the way it should.<\/p>\n<p>What I don&#8217;t see enough focus on these days is the code we write. Sure, we&#8217;re all doing peer reviews (right?) and we think we manage code quality through unit testing. What worries me is that, usually, this just ensures that our code\u00a0<em>works<\/em>. It does nothing to really manage quality. What&#8217;s wrong with this code?<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nclass CreditCard\r\n{\r\n  private Decimal _Limit;\r\n  \/\/...\r\n  public bool RaiseLimit(Decimal amount)\r\n  {\r\n    _Limit += amount;\r\n    \/\/....\r\n  }\r\n  \/\/...\r\n}\r\n<\/pre>\n<p>This is a blatant example, but it&#8217;s a problem I see all the time. The code looks clear enough, and it&#8217;s going to work. It will build, pass your unit tests, and there&#8217;s every chance it will pass peer review &#8211; but it shouldn&#8217;t. The problem is, there is a risk that someone will do this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nDecimal oldLimit = card.Limit;\r\nDecimal newLimit = ...;\u00a0\u00a0 \u00a0\/\/ Code to calculate the new limit\r\ncard.RaiseLimit(newLimit);\r\n<\/pre>\n<p>&#8230; and that would be awful! The caller has gone to the effort of calculating the new limit and passing it to RaiseLimit(), but that&#8217;s not what RaiseLimit() expects: it expects to be passed the amount the limit should be <em>increased by<\/em>. How do we solve this? There is a simple change we can make to reduce the risk this will happen. Our improved code might look like this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\npublic bool RaiseLimit(Decimal increaseAmount)\r\n{\r\n  _Limit += increaseAmount;\r\n  \/\/....\r\n}\r\n<\/pre>\n<p>Functionally, nothing has changed &#8211; but we&#8217;ve provided an extra clue to a developer calling our function. In these days of intelligent IDEs, coders usually get to see the method signature that they&#8217;re calling. We should endeavour to take every possible advantage of IDE features like these to streamline code creation and reduce the chance of errors.<\/p>\n<p>This is one simple example from a whole spectrum of things you can do to optimise code-writing. I have wasted countless hours reading through classes trying to work out how to use them. Here&#8217;s a recent example I ran into:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nclass ConfiguredTask\r\n{\r\n  public string ConfigFolder;\r\n  public string TaskExe;\r\n  public void WriteMainConfig(DateRange dates, string configName) {...}\r\n  public void WriteSecondaryConfig(DateRange dates, string configName) {...}\r\n  public void RunTask(string path, DateRange dates) {...}\r\n  public ResultSet GetResults(DateRange dates) {...}\r\n  \/\/....\r\n}\r\n<\/pre>\n<p>To use this effectively, you need to know quite a bit about the internal class. For a start, you need to know that you need to write the main and secondary config files before calling RunTask() &#8211; not as obvious as you might think, as there are dozens of other public methods and properties on this class. Second, you need to know that the two functions to write config files are expecting filenames with full path information, and they need to be different, but in the same folder. Third, you need to know that RunTask() persists the results of the task both into the database &#8211; something I didn&#8217;t want &#8211; and leaves output in the folder referenced by ConfigFolder. TaskExe must contain the name of the file to run, but must <em>not<\/em> contain any path &#8211; the executable must be in the path referenced by ConfigFolder. That wasn&#8217;t even the end of it! The code to run a task used to look like this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\ntask.WriteMainConfig(selectedDates, @&quot;c:\\main.cfg&quot;);\r\ntask.WriteSecondaryConfig(selectedDates, @&quot;c:\\second.cfg&quot;);\r\ntask.RunTask(task.ConfigFolder, selectedDates);\r\nResultSet results = task.GetResults(selectedDates);\r\n<\/pre>\n<p>Keep in mind that, if you didn&#8217;t have an example to hand, you had to read a fair portion of the class itself to make sure you had everything right! After I was finished with it, the class looked like this:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nclass ConfiguredTask\r\n{\r\n  public string PathToExecutable;\r\n  public string ResultsFolder;\r\n  private void WriteMainConfig(DateRange dates) {...}\r\n  private void WriteSecondaryConfig(DateRange dates) {...}\r\n  public ResultSet RunTask(DateRange dates,\r\n    bool persistResults=true, string WorkingFolder=null) {...}\r\n  public ResultSet GetResults(DateRange dates) {...}\r\n  \/\/...\r\n}\r\n<\/pre>\n<p>Just through a little re-factoring and a handful of code tweaks, the caller now knows to give a full path to the executable (which can now be anywhere), they don&#8217;t need to know about writing config files (it&#8217;s done during RunTask()), they know that results are persisted by default but they can override that behaviour, they know they can provide an optional working folder, and they don&#8217;t have to call GetResults() after every call to RunTask() when they want the results of that task.<\/p>\n<p>I&#8217;ve taken a class which needed quite a bit of reading to work out how to use it, and turned it into a class you can use with no more information than what IntelliSense shows you as you code. The code to run a task and get the results now looks like this, instead:<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\nResultSet results = task.RunTask(selectedDates);\r\n<\/pre>\n<p>I hope you can see why this would save a future developer time! We should strive for all of our classes to be like this. The idea of &#8216;self-documenting code&#8217; doesn&#8217;t quite capture this: the whole point is to not have to read the code\u00a0<em>at all<\/em>. I prefer the term &#8216;Intuitive Interface&#8217;. As a developer, you should aim for all of your classes to have this kind of intuitive interface. Think of the questions a caller might need answered, and then answer them &#8211; in your method signature if possible, and if not, in a method comment (ideally, in a fashion that leverages the IDE you&#8217;re working in):<\/p>\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\r\n\/\/\/ &lt;summary&gt;\r\n\/\/\/ If the instrument is not running, set the passed-in mode and start it running.\r\n\/\/\/ If the instrument is already running it will *NOT* change the mode.\r\n\/\/\/ &lt;\/summary&gt;\r\nprivate void EnsureInstrumentIsRunning(InstrumentMode mode)\r\n{\r\n  \/\/ ...\r\n}\r\n<\/pre>\n<p>Even in that example (which I took from a current project), the first line is really extraneous &#8211; it&#8217;s repeating information that&#8217;s already available in the method signature.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Agile.\u00a0Kanban.\u00a0Lean Startup. We have more and more ways to think about the software development process, and our industry is getting better and better at what we do. We&#8217;re wasting less time, and delivering a more customer-focused product. New businesses have great tools to build great teams. We know how to manage source code, and some &hellip; <a href=\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Intuitive Interfaces<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[1],"tags":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Intuitive Interfaces - Nerdhold Coder<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Intuitive Interfaces - Nerdhold Coder\" \/>\n<meta property=\"og:description\" content=\"Agile.\u00a0Kanban.\u00a0Lean Startup. We have more and more ways to think about the software development process, and our industry is getting better and better at what we do. We&#8217;re wasting less time, and delivering a more customer-focused product. New businesses have great tools to build great teams. We know how to manage source code, and some &hellip; Continue reading Intuitive Interfaces &rarr;\" \/>\n<meta property=\"og:url\" content=\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\" \/>\n<meta property=\"og:site_name\" content=\"Nerdhold Coder\" \/>\n<meta property=\"article:published_time\" content=\"2012-09-03T00:40:51+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2014-11-20T22:00:24+00:00\" \/>\n<meta name=\"author\" content=\"Lionell Pack\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Lionell Pack\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\",\"url\":\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\",\"name\":\"Intuitive Interfaces - Nerdhold Coder\",\"isPartOf\":{\"@id\":\"http:\/\/www.nerdhold.com\/coder\/#website\"},\"datePublished\":\"2012-09-03T00:40:51+00:00\",\"dateModified\":\"2014-11-20T22:00:24+00:00\",\"author\":{\"@id\":\"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/ca2988d5c0cb756a846e4d8c54e86b77\"},\"breadcrumb\":{\"@id\":\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"http:\/\/www.nerdhold.com\/coder\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Intuitive Interfaces\"}]},{\"@type\":\"WebSite\",\"@id\":\"http:\/\/www.nerdhold.com\/coder\/#website\",\"url\":\"http:\/\/www.nerdhold.com\/coder\/\",\"name\":\"Nerdhold Coder\",\"description\":\"Tinkerings of a C# Coder\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"http:\/\/www.nerdhold.com\/coder\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/ca2988d5c0cb756a846e4d8c54e86b77\",\"name\":\"Lionell Pack\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/image\/\",\"url\":\"http:\/\/0.gravatar.com\/avatar\/9be7b23cd97814ac4a40b9b4d2955b5a?s=96&d=mm&r=pg\",\"contentUrl\":\"http:\/\/0.gravatar.com\/avatar\/9be7b23cd97814ac4a40b9b4d2955b5a?s=96&d=mm&r=pg\",\"caption\":\"Lionell Pack\"},\"sameAs\":[\"http:\/\/blog.rophuine.net\"],\"url\":\"http:\/\/www.nerdhold.com\/coder\/author\/admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Intuitive Interfaces - Nerdhold Coder","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/","og_locale":"en_US","og_type":"article","og_title":"Intuitive Interfaces - Nerdhold Coder","og_description":"Agile.\u00a0Kanban.\u00a0Lean Startup. We have more and more ways to think about the software development process, and our industry is getting better and better at what we do. We&#8217;re wasting less time, and delivering a more customer-focused product. New businesses have great tools to build great teams. We know how to manage source code, and some &hellip; Continue reading Intuitive Interfaces &rarr;","og_url":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/","og_site_name":"Nerdhold Coder","article_published_time":"2012-09-03T00:40:51+00:00","article_modified_time":"2014-11-20T22:00:24+00:00","author":"Lionell Pack","twitter_misc":{"Written by":"Lionell Pack","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/","url":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/","name":"Intuitive Interfaces - Nerdhold Coder","isPartOf":{"@id":"http:\/\/www.nerdhold.com\/coder\/#website"},"datePublished":"2012-09-03T00:40:51+00:00","dateModified":"2014-11-20T22:00:24+00:00","author":{"@id":"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/ca2988d5c0cb756a846e4d8c54e86b77"},"breadcrumb":{"@id":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/"]}]},{"@type":"BreadcrumbList","@id":"http:\/\/www.nerdhold.com\/coder\/2012\/09\/03\/intuitive-interfaces\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"http:\/\/www.nerdhold.com\/coder\/"},{"@type":"ListItem","position":2,"name":"Intuitive Interfaces"}]},{"@type":"WebSite","@id":"http:\/\/www.nerdhold.com\/coder\/#website","url":"http:\/\/www.nerdhold.com\/coder\/","name":"Nerdhold Coder","description":"Tinkerings of a C# Coder","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"http:\/\/www.nerdhold.com\/coder\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/ca2988d5c0cb756a846e4d8c54e86b77","name":"Lionell Pack","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"http:\/\/www.nerdhold.com\/coder\/#\/schema\/person\/image\/","url":"http:\/\/0.gravatar.com\/avatar\/9be7b23cd97814ac4a40b9b4d2955b5a?s=96&d=mm&r=pg","contentUrl":"http:\/\/0.gravatar.com\/avatar\/9be7b23cd97814ac4a40b9b4d2955b5a?s=96&d=mm&r=pg","caption":"Lionell Pack"},"sameAs":["http:\/\/blog.rophuine.net"],"url":"http:\/\/www.nerdhold.com\/coder\/author\/admin\/"}]}},"_links":{"self":[{"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/posts\/23"}],"collection":[{"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/comments?post=23"}],"version-history":[{"count":49,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/posts\/23\/revisions"}],"predecessor-version":[{"id":124,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/posts\/23\/revisions\/124"}],"wp:attachment":[{"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/media?parent=23"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/categories?post=23"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nerdhold.com\/coder\/wp-json\/wp\/v2\/tags?post=23"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}