I must admit I do not agree with some of the things that the other answers recommended, so I'm going to throw my two cents;
Comments
Documentation is extremely helpful for strangers reading your code. Usually many things will not be verbose enough to be read and understood immediately, and you should then explain what you are doing.
Edit: the discussion in the comment section has pointed out something right – over-commenting is usually done when writing bad code.
Commenting your work should be precise and minimal, but, in my opinion, should definitely be present. At least a comment for every 15 lines of code. For example, on top of blocks on code, add a line about what you're doing:
def login(username: str, password: str, create_session: bool = True):
# Filter the user we need from the database
hash = md5(password)
users = db.table("users", db_entities.USER)
results = [x for x in users.query(lambda c: c.get("username") == username and c.get("password_hash") == hash)]
if len(results) == 0:
return None, None
else:
# Create a login session record in the database.
if create_session:
sessions = db.table("sessions", db_entities.SESSION)
ses = sessions.new()
ses.set("username", username) \
.set("expiery", 31536000 + time.time())
sessions.update(ses)
return results[0], ses
else:
return results[0], None
Minimal comments that explain why and what you're doing are very helpful throughout the code. I do not agree with the answer that states
If I come across code containing comments, I prepare for the worst: the code is likely to be bad, and to be honest the comments are likely to be bad too.
Many times, gracefully, good code is documented. It is true that bad programmers see their documentation like "Alright, my code is bad, let's add a few sentences to make it clearer".
Yes, and while this occurs quite a lot, it is also true that good programmers that write clean code also want to make sure that they return to their code and understand why they want their function to behave like that, or why did they need that line that seems a bit redundant, etc...
Yes, comments that explain obvious things, comments that are unclear, comments that were just put together to make sure that "this code is documented, yeah, whatever", are code smell. They make reading the code harder and irritating. (Adding an example below)
# Logging into Gmail when the module is imported
_client = login()
def get_client():
global _client
return _client
Example clarification: "No shit, Sherlock. does _client = login()
log into the mail service? OMG!"
More clarification: the login()
method has no relation to the login()
method from the above example.
But comments that do match the standards, explain the why's and not the how's, and answer the right questions, are very very (very) helpful.
Inline comments
One thing you should NOT (and if I could write that bigger, I would) do, is write your comments in the same line of the code. It makes comments very line-specific, which completely misses the purpose of commenting your code.
For example, bad inline comments:
outer = MIMEText(details["message"]) # Constructing a new MIMEText object
outer["To"] = details["to"] # Setting message recipient
outer["From"] = "xAI No-Reply" # Setting message sender
outer["Subject"] = details["subject"] # Setting message subject
outer.preamble = "You will not see this in a MIME-aware mail reader.\n" # I don't know what I'm doing here, I copied this from SO.
msg = outer.as_string() # Getting the string of the message
_client = details["client"] # Assigning the client
_client.sendmail(SENDER, details["to"], msg) # Sending the mail
Would be much easier to read and understand this code without the comments, that make it messy and unreadable.
Instead, comments inside your code should be placed above blocks on code, and they should answer the important questions that may arise while reading the code block.
# Constructing the email object with the values
# we received from the parameter of send_mail(details)
outer = MIMEText(details["message"])
outer["To"] = details["to"]
outer["From"] = "xAI No-Reply"
outer["Subject"] = details["subject"]
outer.preamble = "You will not see this in a MIME-aware mail reader.\n"
msg = outer.as_string()
# Sending the mail using the global client (obtained using login())
_client = details["client"]
_client.sendmail(SENDER, details["to"], msg)
Much clearer, right? Now you also know that you have to use the login()
function and provide the parameters to send_mail()
with everything you used. Helps a bit, but one thing is still missing.
Function documentation
Has been widely discussed. You should always let your readers know what your function is about, why and what it does. How it does that, this does not belong to the documentation, but maybe to footnotes of the function.
You should clearly describe what you expect your parameters to be, and if you want them to be obtained/created in a specific method. You should declare what your function should return, what its use is, etc.
Again, that's my opinion and methodology while writing my code. Not only those, but those are just some of the things I could not agree with the other answers about. Oh, and of course, not just the comments read your code out, but your code itself. Write clean code, understandable and maintainable. Think about your future self while coding ;-)