[Tut] Show Don’t Tell: Commenting Python Best Practices - Printable Version +- Sick Gaming (https://www.sickgaming.net) +-- Forum: Programming (https://www.sickgaming.net/forum-76.html) +--- Forum: Python (https://www.sickgaming.net/forum-83.html) +--- Thread: [Tut] Show Don’t Tell: Commenting Python Best Practices (/thread-98474.html) |
[Tut] Show Don’t Tell: Commenting Python Best Practices - xSicKxBot - 11-27-2020 Show Don’t Tell: Commenting Python Best Practices <div><p>This tutorial taken from my upcoming programming book “From One to Zero” (NoStarch, 2021) will show you how to write great comments. While most online tutorials focus on a bullet list of commenting tips, we dive deeper into the meat exploring the underlying reasons for the commonly recommended commenting principles. So, let’s get started!</p> <h2>Code For Humans Not Machines</h2> <p class="has-luminous-vivid-orange-background-color has-background"><em>“Any fool can write code that a computer can understand. Good programmers write code that humans can understand.”</em> — <strong>Martin Fowler</strong></p> <p>The main purpose of source code is to define what machines should do and how to do it. </p> <p>Yet, if this was the only criteria, you’d use a low-level machine language such as assembler to accomplish this goal because it’s the most expressive and most powerful language. </p> <p>The purpose of high-level programming languages such as Python is to help people write better code and do it more quickly. Our next principle for clean code is to constantly remind yourself that you’re writing code for other people and not for machines. </p> <p>If your code will have any impact in the real world, <strong><em>it’ll be read multiple times by you or a programmer that takes your place </em></strong>if you stop working on the code base. Always assume that your source code will be read by other people. What can you do to make their job easier? Or, to put it more plainly: <em>what can you do to mitigate the negative emotions they’ll experience against the original programmer of the code base their working on?</em> <strong><em>Code for people not machines!</em></strong></p> <h2>Reduce Time to Understanding</h2> <p>If you write code for humans not machines, you’ll need to use comments to help readers of your code understand it better and quicker. A short comment can greatly reduce the time to cognitively grasp the meaning of the code base. Consider the following code example:</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' f_words = re.findall('\\bf\w+\\b', text) print(f_words) l_words = re.findall('\\bl\w+\\b', text) print(l_words) ''' OUTPUT: ['frost', 'flower', 'field'] ['let', 'lips', 'long', 'lies', 'like'] ''' </pre> <p><strong><em>Bad code example without comments.</em></strong></p> <p>The previous code snippet analyzes a short text snippet from Shakespeare’s <em>Romeo and Juliet</em> using <a href="https://blog.finxter.com/python-regex/" title="Python Regex Superpower [Full Tutorial]" target="_blank" rel="noreferrer noopener">regular expressions</a>. If you’re not very familiar with regular expressions, you probably struggle understanding what the code does. Even the meaningful variable names don’t help much. Let’s see if a few comments can resolve your confusion!</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import re text = ''' Ha! let me see her: out, alas! he's cold: Her blood is settled, and her joints are stiff; Life and these lips have long been separated: Death lies on her like an untimely frost Upon the sweetest flower of all the field. ''' # Find all words starting with character 'f' f_words = re.findall('\\bf\w+\\b', text) print(f_words) # Find all words starting with character 'l' l_words = re.findall('\\bl\w+\\b', text) print(l_words) ''' OUTPUT: ['frost', 'flower', 'field'] ['let', 'lips', 'long', 'lies', 'like'] ''' </pre> <p><strong><em>Good code example with comments.</em></strong></p> <p>The two short comments greatly help understanding the <a href="https://blog.finxter.com/python-re-findall/" title="Python re.findall() – Everything You Need to Know" target="_blank" rel="noreferrer noopener">regular expression patterns</a> <code>'\\bf\w+\\b'</code> and <code>'\\bl\w+\\b'</code>. While I won’t dive deeply into regular expressions here, the example shows how comments can help you getting a rough understanding of other people’s code without understanding each and every syntactic sugar. For introductory tutorials into the powerful technology regular expressions, check out our two technical books <em><a href="https://pythononeliners.com/" target="_blank" rel="noreferrer noopener">Python One-Liners</a></em> and <em><a href="https://blog.finxter.com/ebook-the-smartest-way-to-learn-python-regex/" target="_blank" rel="noreferrer noopener" title="[eBook] The Smartest Way to Learn Python Regex">The Smartest Way to Learn Python Regular Expressions</a></em>.</p> <h2>You’re the Expert—Share Your Wisdom!</h2> <p>Helpful comments give a glimpse into your thinking—as you’ve written the code, you possess valuable insight into it only matched by very few persons. Don’t miss out on sharing your insights with other people! Comments can be very useful to “abstract” over blocks of code. For example, if you have five lines of code dealing with updating customer information in a database, add a short comment before the block to explain this. This will help the reader get a quick overview of your code and accelerates their and your “code loading time”. You can find an example of such an instance next:</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""># Process next order order = get_next_order() user = order.get_user() database.update_user(user) database.update_product(order.get_order()) # Ship order & confirm customer logistics.ship(order, user.get_address()) user.send_confirmation() </pre> <p><strong><em>Commented blocks help get an overview of the code.</em></strong></p> <p>The code exemplifies how an online shop completes a customer order in two high-level steps: (1) Processing the next order, and (2) Shipping the order. The comments help you understand the purpose of the code in a few seconds without the need to look at each individual method call. </p> <h2>Comments as WARNINGS!</h2> <p>You can also use comments as a warning of potentially undesired consequences. This increases the level of attention of the programmer working with your code. The following code shows such an example where programmers are warned before calling a function <code>ship_yacht()</code> that will actua ship an expensive yacht to a customer.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">########################################################## # WARNING # # EXECUTING THIS FUNCTION WILL SHIP A $1,569,420 YACHT!! # ########################################################## def ship_yacht(customer): database.update(customer.get_address()) logistics.ship_yacht(customer.get_address()) logistics.send_confirmation(customer) </pre> <p><strong><em>Comments as warnings.</em></strong></p> <p>There are many more ways to use comments in a useful way. Comments are always there for the human reader, so always keep in mind that you’re writing code for humans not machines!</p> <h2>Avoid Unnecessary Comments</h2> <p>Not all comments help readers understand code better. In fact, there are many cases where comments reduce the clarity and confuse the readers of a given code base. If your goal is to write clean code, you must not only use valuable comments but also avoid unnecessary comments. But what are unnecessary comments? Let’s dive into those next.</p> <p>During my time as a computer science researcher, many of my senior-level students described me in great detail how their job interviews at various companies went. A very skilled student had successfully applied for a job at Google. He told me that the Google headhunters—they’re usually Google engineers—criticized his code style because he added too many unnecessary comments. These types of comments are so called “code smells”—expert coders can figure out very quickly whether you’re a<a href="https://finxter.com/" target="_blank" rel="noreferrer noopener" title="https://finxter.com/"> beginner, intermediate, or expert coder </a>yourself. Unnecessary comments make this very obvious. But what are unnecessary comments? In most cases, they add a level of redundancy to the code. A great coder will use meaningful variable names (<strong>Principle</strong>: <em><a href="https://blog.finxter.com/tips-to-write-clean-code/" target="_blank" rel="noreferrer noopener" title="7 Tips to Write Clean Code">Use the Right Names</a></em>), so the code often becomes self-explanatory—at least in comparison to code that doesn’t use the right names. Let’s revisit the code snippet with meaningful variable names.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">investments = 10000 yearly_return = 0.1 years = 10 for year in range(years): print(investments * (1 + yearly_return)**year) </pre> <p><strong><em>No comments needed.</em></strong></p> <p>The code calculates your cumulative investment return for ten years assuming a 10% yield. Now, let’s add some unnecessary comments!</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">investments = 10000 # your investments, change if needed yearly_return = 0.1 # annual return (e.g., 0.1 --> 10%) years = 10 # number of years to compound # Go over each year for year in range(years): # Print value of your investment in current year print(investments * (1 + yearly_return)**year) </pre> <p><strong><em>Unnecessary comments.</em></strong></p> <p>All comments in the previous code snippet are redundant. Some of them would’ve been useful if you’d chosen less meaningful variable names such as <code>x</code>, <code>y</code>, or <code>z</code>. But explaining a variable named <code>yearly_return</code> by means of a comment doesn’t provide any relative value. Quite contrarily, it reduces the value because it adds unnecessary clutter to the code. The additional clutter makes your code less readable and less concise. There are a few rules that may help you avoid unnecessary comments—although the best rule is to use your common sense to identify whether a comment really improves the readability of your code.</p> <h2>Code Smells — Negative Commenting Principles</h2> <ul> <li><strong>Don’t use inline comments.</strong> They have little value and can be completely avoided by choosing meaningful variable names.</li> <li><strong>Don’t be redundant.</strong> Redundancy is the enemy of clarity—this also holds for comments!</li> <li><strong>Don’t add obvious comments. </strong>You can see an obvious comment in the previous code snippet just before the <a href="https://blog.finxter.com/python-loops/" target="_blank" rel="noreferrer noopener" title="Python Loops"><code>for</code> loop</a> statement. Any coder knows the <code>for</code> loop, so what additional value do you provide with the comment <code># Go over each year</code> when the for loop already states <code>for year in range(years)</code>? </li> <li><strong>Don’t comment out code.</strong> If you’re a programmer, it’s very likely that you’ve been guilty of this. We programmers often hang on to our beloved code snippets even if we already (grudgingly) decided to remove them. The shy approach to removing unnecessary code is to comment it out. However, commented code is a readability killer and you should avoid it at all costs if you want to write clean code. Instead of commenting out the unnecessary code, boldly remove it. For your piece of mind, you should use a version history tool such as Git that allows you to get any old code snippet if you need it.</li> </ul> <p>Many programming languages such as Python come with documentation functionality that allows you to describe the purpose of each function, method, and class in your code. If you’ve carefully chosen the abstraction level of each function (<em><strong><a href="https://blog.finxter.com/tips-to-write-clean-code/" title="7 Tips to Write Clean Code">Single-Responsibility Principle</a></strong></em>), it’s often enough to use the build in documentation functionality instead of comments to describe what your code does. This largely removes the need for additional comments in your code. </p> <hr class="wp-block-separator"/> <p>Do you want to develop the skills of a <strong>well-rounded Python professional</strong>—while getting paid in the process? Become a Python freelancer and order your book <a href="https://amzn.to/2Re2JqO" target="_blank" rel="noreferrer noopener"><strong>Leaving the Rat Race with Python</strong></a> on Amazon (<em>Kindle/Print</em>)!</p> <div class="wp-block-image"> <figure class="aligncenter size-medium is-resized"><a href="https://amzn.to/2Re2JqO" target="_blank" rel="noopener noreferrer"><img loading="lazy" src="https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-200x300.jpg" alt="Leaving the Rat Race with Python Book" class="wp-image-11850" width="200" height="300" srcset="https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-200x300.jpg 200w, https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-scaled.jpg 683w, https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-768x1152.jpg 768w, https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-1024x1536.jpg 1024w, https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-1365x2048.jpg 1365w, https://blog.finxter.com/wp-content/uploads/2020/08/final_cover-150x225.jpg 150w" sizes="(max-width: 200px) 100vw, 200px" /></a></figure> </div> <h2>Where to Go From Here?</h2> <p>Enough theory, let’s get some practice!</p> <p>To become successful in coding, you need to get out there and solve real problems for real people. That’s how you can become a six-figure earner easily. And that’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?</p> <p><strong>Practice projects is how you sharpen your saw in coding!</strong></p> <p>Do you want to become a code master by focusing on practical code projects that actually earn you money and solve problems for people?</p> <p>Then become a Python freelance developer! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.</p> <p>Join my free webinar <a rel="noreferrer noopener" href="https://blog.finxter.com/webinar-freelancer/" target="_blank">“How to Build Your High-Income Skill Python”</a> and watch how I grew my coding business online and how you can, too—from the comfort of your own home.</p> <p><a href="https://blog.finxter.com/webinar-freelancer/" target="_blank" rel="noreferrer noopener">Join the free webinar now!</a></p> <p>The post <a href="https://blog.finxter.com/show-dont-tell-commenting-python-best-practices/" target="_blank" rel="noopener noreferrer">Show Don’t Tell: Commenting Python Best Practices</a> first appeared on <a href="https://blog.finxter.com/" target="_blank" rel="noopener noreferrer">Finxter</a>.</p> </div> https://www.sickgaming.net/blog/2020/11/26/show-dont-tell-commenting-python-best-practices/ |