{"id":860,"date":"2010-05-31T10:54:41","date_gmt":"2010-05-31T16:54:41","guid":{"rendered":"http:\/\/thesmithfam.org\/blog\/?p=860"},"modified":"2019-08-12T07:15:31","modified_gmt":"2019-08-12T13:15:31","slug":"some-thoughts-on-readability","status":"publish","type":"post","link":"https:\/\/thesmithfam.org\/blog\/2010\/05\/31\/some-thoughts-on-readability\/","title":{"rendered":"Some Thoughts on Readability"},"content":{"rendered":"<p>Communication is everything in software development.<\/p>\n<p>Unless you work on a team of one, it&#8217;s important that your code communicates easily to your team members. Even if you do work on a team of one, it&#8217;s important to communicate <b>to your future self<\/b>. Yeah, everyone has to read their own code once in a while, and unless your brain is a steel trap, you&#8217;ll forget stuff.<\/p>\n<p>So do yourself and your team a favor. Choose names carefully. Here are some examples.<\/p>\n<p><b>Example 1: Use enumerations instead of booleans<\/b><\/p>\n<p>This example is C++. Let&#8217;s pretend you&#8217;re writing a <tt>parse()<\/tt> function that looks like this:<\/p>\n<p><tt>bool parse(const char *file_name, employee *e, bool validate_only)<\/tt><\/p>\n<p>That seems pretty clear, doesn&#8217;t it? Let&#8217;s break it down:<\/p>\n<p>Inputs:<\/p>\n<ul>\n<li>The path to the file to parse (called <tt>file_name<\/tt>)<\/li>\n<li>The employee struct to populate with the parsing results<\/li>\n<li>A flag to control whether to actually parse the file, or just dry-run (<tt>validate_only<\/tt>)<\/li>\n<\/ul>\n<p>Outputs:<\/p>\n<ul>\n<li>A true or false return value to indicate success or failure<\/li>\n<li>The <tt>out<\/tt> structure, populated on success<\/li>\n<\/ul>\n<p>So far so good? Yeah, probably.<\/p>\n<p>Reading the code so far, the purpose of each parameter is very clear, but don&#8217;t make people read your header files if they don&#8217;t have to. Consider the code that actually <b>calls<\/b> this function. It would look something like this:<\/p>\n<pre>\r\nemployee e;\r\nbool ret = parse(\"\/tmp\/foo.txt\", &e, true);\r\nif (ret) {\r\n   ...\r\n<\/pre>\n<p>Without looking back at the header file, can you tell me what this function does? For the most part, it&#8217;s obvious, but that <tt>true<\/tt> parameter is not  clear. I&#8217;m also not happy with the boolean return value (though it is the lesser of the two offenders).<\/p>\n<p>Don&#8217;t make me think so hard. If I stumble across the code above, I shouldn&#8217;t have to go hunt down a header file just to figure out what it does. We can make this easier on developers by changing those <tt>bool<\/tt>s to <tt>enum<\/tt>s, like so:<\/p>\n<pre>\r\nenum parse_result { success, failure };\r\nenum parse_mode { validate_only, full_parse };\r\nparse_result parse(const char *file_name, employee *e, parse_mode mode);\r\n<\/pre>\n<p>By making these changes, callers would see this instead:<\/p>\n<pre>\r\nemployee e;\r\nparse_result result = parse(\"\/tmp\/foo.txt\", &e, validate_only);\r\nif (result == parse_success) {\r\n   ...\r\n<\/pre>\n<p>Instead of <tt>true<\/tt>, we read <tt>validate_only<\/tt>, and it&#8217;s immediately clear what this function is doing. The returned value is also very clear. There is no need to consult documentation or other header files to figure it out.<\/p>\n<p><b>Example 2: Mutants<\/b><\/p>\n<p>In Python, you can remove white space from strings with the <tt>strip()<\/tt> function. However, if I stumbled across code like this, I probably wouldn&#8217;t realize that it had a bug:<\/p>\n<pre>\r\ns = \"   foobar   \"\r\ns.strip()\r\nprint s # What does this print?\r\n<\/pre>\n<p>That&#8217;s because the <tt>strip()<\/tt> function doesn&#8217;t actually strip whitespace from the string, but rather it <b>returns a new string<\/b> with the whitespace stripped.<\/p>\n<p>In this case, I would recommend that <tt>strip()<\/tt> be renamed <tt>stripped()<\/tt> or <tt>tostripped()<\/tt> to make it more clear that it returns a new string.<\/p>\n<p>For methods that <b>mutate<\/b> their instances, I recommend present-tense verbs like <b>strip()<\/b>, <b>rename()<\/b>, or <b>clear()<\/b>. But for methods that return modified copies of the instance, I recommend past-participle names like <b>stripped()<\/b>, <b>renamed()<\/b>, or <b>cleared()<\/b>.<\/p>\n<p>Qt4 got this right with their changes to <tt>QString<\/tt>. Under Qt3, <tt>QString<\/tt> had a method called <tt>stripWhiteSpace()<\/tt>, so bugs like this were common:<\/p>\n<pre>\r\nQString str = \"   foobar   \";\r\nstr.stripWhiteSpace();\r\n\/\/ BUG: Is str actually stripped now?\r\n<\/pre>\n<p>In version 4, they renamed this method to <tt>trimmed()<\/tt>, so now there&#8217;s no question:<\/p>\n<pre>\r\nQString str = \"   foobar   \";\r\nstr.trimmed();\r\n\/\/ The bug is more obvious now\r\n<\/pre>\n<p><b>Example 3: Be specific<\/b><\/p>\n<p>When reading others&#8217; code it is common to come across words like <b>data<\/b> or <b>ret<\/b> or <b>node<\/b>. While there are exceptions to this rule, these words usually aren&#8217;t specific enough to communicate your intent.<\/p>\n<p>For example, let&#8217;s say I&#8217;m writing a Python program to run Linux commands and store their results in a map. Perhaps I make a function like this:<\/p>\n<pre>\r\ndef run_commands(commands):\r\n    data = {}\r\n    for command in commands:\r\n        output = subprocess.Popen(command,\r\n            stdout=subprocess.PIPE).communicate()\r\n        data[command] = output[0]\r\n    return data\r\n<\/pre>\n<p>This just runs each command given to the function and puts the command&#8217;s output into a dictionary. Obviously, this is a tiny function, and as such, it may be an exception to the rule. However, if this were a more complicated function, perhaps one that executed each command in a separate thread and aggregated the results, <b>data<\/b> would not be very clear. Instead, I&#8217;d recommend renaming <b>data<\/b> to <b>command_results<\/b>. I might even go so far as to name it <b>command_results_dict<\/b> so it could be perfectly clear. Obviously, this rule can be taken too far. I would not recommend, for example, using a variable name like <b>command_subprocess_stdout_result_dict<\/b>. That would be insane.<\/p>\n<p><b>Conclusion<\/b><\/p>\n<p>So there you have it. Just a few pointers that are probably obvious to most of you already. We can all stand to clean up our communication now and then, so take this as a chance clean up the code you write today. I know I will.<\/p>\n<p>Happy hacking!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Communication is everything in software development. Unless you work on a team of one, it&#8217;s important that your code communicates easily to your team members. Even if you do work on a team of one, it&#8217;s important to communicate to your future self. Yeah, everyone has to read their own code once in a while, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-860","post","type-post","status-publish","format-standard","hentry","category-code-and-cruft"],"_links":{"self":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/860","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/comments?post=860"}],"version-history":[{"count":22,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/860\/revisions"}],"predecessor-version":[{"id":1516,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/posts\/860\/revisions\/1516"}],"wp:attachment":[{"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/media?parent=860"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/categories?post=860"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/thesmithfam.org\/blog\/wp-json\/wp\/v2\/tags?post=860"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}