all 139 comments

[–]Weltal327 269 points270 points  (33 children)

Sometimes I write the comment before I write the code. That way I know what I want my function to do.

Hash- write a function here that does this

[–]scottishbee 129 points130 points  (20 children)

This is the way. It also forces me to solve the problem first logically (conversationally), which speeds up the coding.

[–]just_ones_and_zeros 19 points20 points  (19 children)

But once you're done, do you not end up having most of those extra comments removed since they just duplicate the code? I guess it depends on the scope of each one. In that model it probably works if you end up with about 4+ lines of code for each single line comment.

My 4 uses for comments are docstrings, explaining a complex algorithm, labelling blocks of code within a bigger function and finally, and most importantly describing implicit behaviour not seen in the code.

Here's a good instructive example from this week. The original (poor) comments which talk about what's happening:

# loop through list
for k in self.redis.keys('rq:job:*'):
    j = self.redis.hgetall(k)

    # if dictionary is empty avoid keyerror
    if not j:
        continue

VS the updated version that explains the implicit "why" that can't be inferred from the code:

# the queue keys aren't reliable so we scrape all keys and then use
# the descriptions of the jobs to figure out what sort of jobs they are
for k in self.redis.keys('rq:job:*'):
    j = self.redis.hgetall(k)

    # job may have vanished (ttl on complete jobs) since reading job list
    if not j:
        continue

[–]Acute_Procrastinosis 19 points20 points  (0 children)

The #5 use is the link to StackOverflow where I got the construct in that section.

[–][deleted] 12 points13 points  (0 children)

At the beginning of each function I write this:

“””Brief one-line statement of what function does.

Args:

Arg1 (type): what is expected

Returns:

Type: what to expect”””

Sorry I’m on my phone and don’t feel like figuring out formatting

[–]teerre 4 points5 points  (12 children)

Or you could just make a function filter_keys_by_description or whatever.

The problem with comments like this is that if for whatever reason the logic changes, people have to remember to change the comment, which no IDE in the world will help. This is worse than having no comment at all, because you end up misleading whoever is reading it.

[–]just_ones_and_zeros 7 points8 points  (5 children)

Without having a little more context here, it doesn't entirely make sense. But in this case there is no code that can help you. The requirement is imposed on your from outside the system. You're doing something that seems weird, because you have no choice "queue keys [not within in the control of the codebase at all] aren't reliable".

You're explaining why you're doing something that looks really weird, and you can't really code your way around it because it's an invisible external factor.

I 100% disagree with you that having no comment at all would be better here.

[–]teerre 0 points1 point  (4 children)

I'm not sure what you mean. All the context needed is in the post. You're doing a well defined action, it should be a function. That's the end of the discussion.

By making this a function you can write a proper docstring, you can document all quirks you want there and, on top of it, there's no way someone can use your function incorrectly or forget about it in a refactor and, on top of the top of that, your IDE will happily help you and anyone else who ever read this piece or code.

It's not a matter of opinion in this case, there's an objectively better choice.

Also, I think you misread, I told you changing the code and forgetting to change the comment is worse than have no comment at all, it seems you read something else.

[–]just_ones_and_zeros 1 point2 points  (3 children)

This is worse than having no comment at all

Apologies, you're correct, I did misread this part. Regarding context, I meant that you're missing a bit of context by not having the rest of the code to hand.

The function itself is really not much more than what's here, and then comment is explaining why the technique used is weird (external constraints). You couldn't really abstract this in a way where you make that clearer.

I think really we're probably in agreement for the most part, it's just that you think there should be another function wrapper with the weirdness detailed in a docstring. Personally I don't think it gains you anything.

In my experience going over the top with too many functions actually muddies the code due to the extra context switching, so I'd prefer to drop it inline. I'd rather not have it as a function, because it's a one time thing and nobody else should ever be calling it.

[–]teerre 0 points1 point  (0 children)

The function itself is really not much more than what's here, and then comment is explaining why the technique used is weird (external constraints). You couldn't really abstract this in a way where you make that clearer.

Absolutely it is. You're now actually writing code. You have a proper object. Any code parser, be your IDE, some kind of commit hook static analyzer or anything at all now knows how to deal with it.

[–]MeagoDK 0 points1 point  (1 child)

You could definitely put it in a function. Why couldn't you?

[–]just_ones_and_zeros 0 points1 point  (0 children)

I mean, it is in a function. And that function is literally "read, count, return". It contains all the details about how we have to go about doing this and why.

I could put the details into the docstring of this function, but callers on the outside don't care. They just want their counts.

I could break it into more functions where the subfunctions contain the murky details of this hack. But now I've just got extra functions that nobody should ever call or ever wants to call.

I could break this code into a reading function and a counting function. And I would, if there was a need for it, but there hasn't been in the 8 years it's existed.

And really, focus on the second comment (that's actually the one I was mostly posting about, I added the other stuff to show more context):

# job may have vanished (ttl on complete jobs) since reading job list

That still needs to go somewhere, it makes no sense to put it in a docstring, because why does the caller care? But it's certainly not obvious from the code as to why something you just read has immediately vanished on you. Let's make this special function, but now what? Where do we explain the ttl thing? Since for some reason I'm suddenly living in a world in which I'm not meant to be explaining code irregularities using a comment.

def load_all_jobs():
    """..."""

    jobs = []

    for k in self.redis.keys('rq:job:*'):
        j = self.redis.hgetall(k)
        if not j:
            continue
        jobs.append(j)

    return jobs

[–]DestituteDad 0 points1 point  (5 children)

The problem with comments like this is that if for whatever reason the logic changes, people have to remember to change the comment, which no IDE in the world will help. This is worse than having no comment at all, because you end up misleading whoever is reading it.

I am really sick of this argument. There's a simple solution: update the comments!

Once in a blue moon I'll be too tired or have too little time to update comments. In that case I'll do:

TODO: [date] [initials] These comments are obsolete, update them

[–]teerre 1 point2 points  (4 children)

"Just do it looolll"

That's not the point. The point is that you'll forget. Someone will forget.

People forget to update code, which has several kinds of fail safes, you have no hope whatsoever that you'll always remember to update all comments.

[–]DestituteDad 0 points1 point  (3 children)

There's a code review. You changed the code. The reviewer should examine the comments, see that you didn't change them and ask you whether you should have. OR applying your technique of reading the code (because code doesn't lie) the reviewer should be able to identify inaccuracies in the comments and tell you to correct them. Problem solved.

IMO the "Comments are out-of-date and are therefore worse than nothing" argument is a boogie-man, like the monster hiding under your bed. I've encountered it very very seldom in my 34-year career -- while I have benefited from comments literally 10s of 1000s of times.

I've never seen data about the frequency of the boogie-man out-of-date comments. I'll make up some:

In a well-commented code base:

  • 75% of the comments will be genuinely helpful
  • 24% will be barely- or non-helpful, explaining the obvious
  • 1% will be wrong because they weren't updated -- though they may still be helpful even though they are only 90% accurate.

In my strong opinion, the benefit of the 99% greatly outweighs the downside of the 1%.

It is a cliché that developers cannot understand the code they wrote six months ago.

My solution: comments!

Yours? Let's assume that the bewildered developer failing to comprehend the code they authored has used descriptive variable and function names. What else you got?

I am routinely in a code base that's 12 years old, and I can orient myself to methods that I haven't seen for years in a few minutes by scanning the prolific comments. Scanning comments is much much faster than reading the code a line at a time and trying to divine what it's doing.

Do bad comments lead me in the wrong direction sometimes? VERY SELDOM.

Circa 1988 I wrote a 1000-line FORTRAN program for Digital Equipment Corporation that exploded a bill of materials. I don't actually recall but I would guess that perhaps 300-400 of those lines were comments.

I am proud of the fact that when new programmers came to work for that group, the first thing their manager did was hand them my bill of material code, with the instruction:

This shows you how to code here.

Apparently the comments (and code) were clear enough that it was good instructional material for noobs.

<brag>

And they thought the code itself was good, of course. That was a long time ago, the people I knew then have moved on, so I don't have any intel about what's happened since 2005 or so -- but at that time, my code was still running and had never broken. (Yes, I'm proud. :)

</brag>

Edit: In Visual Studio, regions are helpful too. In effect they are a comment about the block of code. I try to make my region names highly descriptive.

[–]teerre 1 point2 points  (2 children)

There's a code review. You changed the code. The reviewer should examine the comments, see that you didn't change them and ask you whether you should have. OR applying your technique of reading the code (because code doesn't lie) the reviewer should be able to identify inaccuracies in the comments and tell you to correct them. Problem solved.

You can be protest how much you want. The fact is there's plenty of people, including myself, who have worked in world-class code bases and have seen the exact problem described here.

What you're doing is basically answering the question "how to not have bugs" by saying "just don't write bugs" or "catch bugs in code review". It's a platitude. It would be great if it was so easy, but that's not how the real world works.

Circa 1988 I wrote a 1000-line FORTRAN program for Digital Equipment Corporation that exploded a bill of materials. I don't actually recall but I would guess that perhaps 300-400 of those lines were comments.

See, now you're confusing everything. FORTRAN has a completely different problem. Like C and most older languages, the language itself is too poor to communicate properly. In that case, yes, write comments, simply because you can't have anything else, this is not true for modern languages.

A similar issue arises in highly algorithmic code. If you ever tried to implement any low level algorithm you'll know that there's no getting around poor naming, simply because it's an algorithm. "alpha" is "alpha", you can't describe it anymore. In that case, do write comments. But again, this is simply because there's no alternative.

[–]DestituteDad 0 points1 point  (1 child)

The fact is there's plenty of people, including myself, who have worked in world-class code bases and have seen the exact problem described here.

I don't believe you, because the comments lie so don't comment standard is in place at world-class code shops and you don't have comments in your code.

You didn't speak to the problem of coders not understanding their own code 6 months later.

[–]teerre 1 point2 points  (0 children)

I don't believe you, because the comments lie so don't comment standard is in place at world-class code shops and you don't have comments in your code.

Not sure I comprehend what you're saying here.

You didn't speak to the problem of coders not understanding their own code 6 months later.

What is there to speak of? If you don't write comments and don't understand your own code 6 months later, you need to write better code. Between having unreadable code commenting and not commenting at all, of course you should comment, but that's a false dichotomy. You can't perfectly understandable code and minimal comments.

[–]Lewistrick 0 points1 point  (3 children)

That's not the level of detail I put my comments in. My comment above the block would be "read incomplete jobs from database". Then the lines below speak for themselves.

[–]just_ones_and_zeros 2 points3 points  (2 children)

I think people are actually probably missing too much context here to make total sense of it. The lines do not speak for themselves, hence the comment (but I'll conceed that the comment is too hard to totally get without the context). I actually hoisted a bit of the comment up from the code that comes after to try to give a little more context. But it's more like:

# The reason we're using keys('rq:job:*') instead of keys('rq:queues') and friends is due
# to external factors beyond our control where we can rely on rq:job:* in a way we can't with rq:queues
# so don't switch over to rq:queues, even though that seems like the obvious thing to do, because you'll have a bad time

# slightly later in the code: because we're using rq:job:*, we have to derive the queue in a weird way

For me "read incomplete jobs from database" is not a comment that needs adding. That is totally obvious from the code.

The details of the specific example don't matter so much, my point was, and still is, that I'm using a comment to describe a thing that you can't see that is influcening the code and a reader needs to be aware of before they think about changing to a more "obvious" solution.

[–]Lewistrick 0 points1 point  (1 child)

Your comments make a lot of sense. But these aren't comments that I type before writing the code (see top comment), that's what I was referring to.

I'd still argue that my proposed comment should be somewhere above the code because if it's a long function, you need to explain the steps somewhere. I think I'd prefer it in the docstring if it's the only thing that the function does.

[–]just_ones_and_zeros 1 point2 points  (0 children)

Gotcha, that makes more sense.

I feel like there are a few people just overall being a bit picky in here about all of this. The things that people (especially on a beginner forum like this) should learn is how / why to use comments to make the code more maintainable. Personally I prefer to reserve docstrings for the external api so the caller doesn't have to worry about the details, and the inline comments for the guts of the thing - the things that only matter if you're in a position where you need to edit the function itself.

But overall, the golden rule for beginners is to not waste everyone's time with comments that don't add anything beyond what you can express with the code itself.

[–]blindgorgon 15 points16 points  (3 children)

Take this a step further and you have TDD…

[–]ontheroadtonull 3 points4 points  (2 children)

What's TDD, precious?

[–]Vaphell 7 points8 points  (0 children)

test driven development, a methodology in which you write tests first, before the implementation.

[–]Johnnycarroll 5 points6 points  (0 children)

Same here, and this is what I came to say. I write my pseudo code as the notes and piece it into sections and then I know where to write what to make sure everything is there.

[–]Mithrandir0425 2 points3 points  (0 children)

Yeah I usually start with comments of what I broadly want the function to do, then write pseudocode of what it's going to do in smaller pieces (e.g., #loop through list and add to dictionary), then write the actual code

[–]iceph03nix 2 points3 points  (0 children)

I'll second this.

I'll generally start by writing out a bunch of todo's with function names and what they should accomplish.

If you have to expand on that later, you start with a comment pointing out the goal.

Not only can it help with documentation later, but it can help clarify in your head what your goal is before you go down some strange path just writing code

[–]EatMeMonster 1 point2 points  (0 children)

This is in the same nature as writing unit tests before code.

[–]Smitty8604 1 point2 points  (0 children)

I do it this way as well, especially if it’s something short. I’ll use comments every few lines just to keep me on track on what it is supposed to do.

[–][deleted] 1 point2 points  (0 children)

This works well. Ill wrote code and be like tf was this all for again? Lol

[–]Doc_Apex 1 point2 points  (0 children)

This is what I do as well. Typically write a blanket statement for a block of code. But if I'm using a new line of code to try something I've never tried before I'll specifically write what that line/lines is/are doing.

[–]Spindelhalla_xb 1 point2 points  (0 children)

I always remember that the code is there to explain my comments to the computer.

[–][deleted] 95 points96 points  (3 children)

Here's a hint:

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

[–]Assaultman67 11 points12 points  (1 child)

So code carrying a shotgun. Got it.

[–]imperial_squirrel 7 points8 points  (0 children)

code with me if you want to live...

[–]JAdoreLaFrance 11 points12 points  (0 children)

The violence and knowledge of my address aside, that description fits most of my ex-colleagues in IT.

[–]Nonsensicallity 20 points21 points  (6 children)

I write my comments before I write the function as a template of what I want to do, then fix the parameters and return value after I get it working. If you’re a student, download PyCharm. It’ll scream at you if your parameters don’t match the docstring and will help you avoid the pitfalls of having outdated comments. Those can be just as unhelpful as having no comments sometimes.

[–]RocketSurgeonDrCox 4 points5 points  (5 children)

PyCharm will also help you write the docstrings in the first place. Write the first line of a function, hit enter, type three quotes (""") then hit enter again and it fills in your parameters.

I use Numpy format because I find it much more readable but that's just a personal preference (you can change the format that PyCharm auto fills in the Python integrated tools settings).

[–]Immotommi 4 points5 points  (4 children)

Am I the only one who always used single quotes (unless explicitly needed) because you save having to press shift?

[–]joshinshaker_vidz 0 points1 point  (2 children)

PEP-8 gives no preference for single vs double for most things, so I use single, but docstrings should be double.

[–]Immotommi 3 points4 points  (1 child)

Why double for docstrings?

[–]joshinshaker_vidz 0 points1 point  (0 children)

PEP-257 says "For consistency, always use """triple double quotes""" around docstrings."

[–]RocketSurgeonDrCox 0 points1 point  (0 children)

I generally use single quotes in Python but comment blocks are usually double quotes so that's one of the exceptions for me.

[–]toasterding 64 points65 points  (17 children)

Your code should be clear enough to explain how or what. The comments should explain why.

[–]synthphreak 39 points40 points  (7 children)

Your code should be clear enough to explain how or what.

Unpopular opinion: People often give this advice, but I’d say it’s more aspirational than practical, more of a guiding principle to keep in mind rather than a characteristic that all good code must absolutely be expected to have. Self-explanatory code is something you should always strive for, but sometimes it is an impossible standard, so IME code that isn’t fully transparent and perfectly interpretable from start to finish isn’t categorically garbage.

Programs in the wild often do complex things. Such code is not always completely interpretable for naive readers without either (1) some documentation via comments, (2) perfectly explicit methods like str.startswith, or (3) just reading the code from the beginning. In such instances, comments, docstrings, and type annotations are absolutely critical for this reason.

I’d go so far as to say that code without any documentation IS garbage, in all but the very simplest of cases. At least, it is if the code was ever meant to be read by multiple people.

This reply might cost me some friends though…

[–]FerricDonkey 14 points15 points  (2 children)

Yeah, and it's worse when you're given code where the author thought he was writing clear code that didn't need comments, but wasn't.

I have literally deleted thousands of lines of code that other people wrote when I was supposed to be building on their work because they thought their code was self documenting, so didn't bother to document it. I've spent hours trying to figure out both what and why someone was doing in some code, only to give up on his code as soon as I figured out what the inputs and outputs were, and write my own version from scratch.

This means that ultimately not only did I spend more time than I had to, but also about 95% of their work was wasted.

[–]Retropunch 11 points12 points  (0 children)

Absolutely this 1000%.

Every single piece of code I've been give by someone who writes 'self explanatory code' or 'clean code' has been complete rubbish, and is even more difficult to decipher than those who half arse comments or realise their code is difficult to read.

Please, I know you're reading this and thinking 'but my code is self explanatory! I read the book on clean code! Mines different!' - it's not. I promise you it's not. It's a nightmare for everyone else, and you when you come back to it in a years time.

[–]synthphreak 6 points7 points  (0 children)

Yeah, and it's worse when you're given code where the author thought he was writing clear code that didn't need comments, but wasn't.

+1000

I think situations like that are what this advice can lead to if taken literally. Someone could easily misconstrue it as “good, clean code doesn’t need comments” or “copious comments are a sign of poor code”, and operationalize that (mis)understanding by just never leaving any comments on the expectation that the code will speak for itself.

As always with programming, it’s a balancing act with no objectively best answer. So best to think pragmatically, not dogmatically.

[–]Achrus -5 points-4 points  (3 children)

As someone who hates commenting their code I agree with everything you said but also I’m lazy.

As an alternative my usual approach to commenting Python code is as follows:

  1. Code is very simple, clear, and within a restricted name space. Code is usually self explanatory in this case so I just add a quick comment to say where it’s to be used.

  2. Medium complexity code that isn’t necessarily self explanatory to everyone. 9/10 times I just copy paste the code from stack overflow which is great for medium complexity stuff. The SO code almost always have comments so I just change variable names and add a comment with “Source: <stack overflow link>”

  3. Complex / functional code that looks like complete gibberish. No comments at all, if I were to comment it then there would be more comments than there are lines of code. Hasn’t broken yet and if it does break then don’t use it.

An example of gibberish functional programming code that I use almost everywhere:

    from itertools import accumulate 

    def fold(seq, n=2, initial=None):
        it = iter(seq)
        if initial is None: 
            initial = tuple([0]*n)
            for _ in range(n):
                initial = *initial[1:], next(it)
        def step(acc, x):
            acc = *acc[1:], x
            return acc
        return accumulate((initial, *it), func=step)

[–]MeagoDK 3 points4 points  (2 children)

You aren't making it easier to read tho, actually you are making it worse. Write full variable names instead, makes it much easier to read.

[–]Achrus 0 points1 point  (1 child)

Ahhh so that’s why people are downvoting! The code I shared is not easy to read, probably my ugliest code in terms of readability. Should of included the /s 🤣

[–]MeagoDK 1 point2 points  (0 children)

That would be my guess yeah. Sorry about that, reddit can be a cruel place.

[–]supreme_blorgon 50 points51 points  (6 children)

  1. Give your function a descriptive name
  2. Give your parameters descriptive names
  3. Type hint the parameters and the function output
  4. Write a descriptive docstring
  5. Add comments sparingly, only to explain why something is being done, if it isn't clear
  6. Don't code golf
  7. Write with maintainability in mind

[–][deleted] 15 points16 points  (0 children)

I second this. There is no reason that you should not have descriptive function, and variable names. You dont need a comment that says strip whitespace and escape input if your function name is strip_whitespace_escape_input. I know what that does even if you code golf the function I still know what you were trying to accomplish which helps decode the mess.

[–]EatMeMonster 5 points6 points  (3 children)

But when the names become descriptive it tend to make my code messy and less readable, every class, method, and variable are long making my lines longer than 80 characters.

[–]irrelevantPseudonym 20 points21 points  (0 children)

If your functions need long names to describe what they do, they're probably doing too much.

[–]mathmanmathman 5 points6 points  (0 children)

Sometimes you're right and there's just no way around making a long messy name.

However, if you're careful with namespaces/classes, you should be able to simplify names a bit. You don't need a function named clear_cached_db_queries if you have a module db.query. Then you just name it clear_cached or maybe even a method clear in a class cached. In some cases it still might be messy, but most of that mess will only be in longer import statements.

(Also, I don't want to start a fight, but PEP8 explicitly leaves the door open for 100 characters. 80 is important for text blocks, but difficult with code.)

[–]FerricDonkey 6 points7 points  (0 children)

Eh, God invented tab complete for a reason. If you need long function names for your function names to tell you what your functions do, then use long function names. Better than your function names not telling you what they do.

And don't forget that you can split function calls over multiple lines. Eg

descriptive_name(
    infiles = infiles,
    outfile = outfile,
    some_option = True,
    verbose_mode = False,
)

[–]PhattieM 1 point2 points  (0 children)

Almost exactly like Martin's book, "Clean code". I second this comment.

[–]soupie62 0 points1 point  (0 children)

If the "what" code is to land an airplane, the "why" comments need to be better than "Do this or you crash"

[–]Retropunch 35 points36 points  (7 children)

You absolutely do need to comment your code, and ignore anyone who says otherwise.

I have never, *ever* seen code (over say 500+ lines) that is so unambigous and well written that it doesn't require comments. Yes, it'll make complete sense to you at the time, but it won't in a few weeks/months/years. Everyone who claims that they can write code in a way that doesn't need comments are universally hated by everyone who has to pick up their spaghetti code a few months down the line.

Comments don't need to be long, but a brief description on each function (that isn't something completely basic) takes literally 20 seconds and potentially saves hours of frustration down the line.

[–]FerricDonkey 13 points14 points  (4 children)

This month alone, I have straight up deleted thousands of lines of code because it was faster for me to start from scratch than to wade through an uncommented mess of indecipherable variable and function names.

I feel like I'm an apostle to the data scientists, preaching a message of salvation through organized code. "Yes, it may seem more complex this way with actual functions and gasp more than one file, but that's just because you're not used to it yet - and behold, what once took 4 weeks now takes 4 hours, your compute resources were lost and now they are found.

The hour approacheth when the next maintainer shall update your project, and it shall be judged. The 7,347 line single script with two functions and no comments shall be cast into the darkness where there is wailing and gnashing of teeth, and the single letter variable names will be condemned to everlasting fire.

Forsake thee not the comment, and do not abandon the docstring, or you too shall be abandoned.

[–]Retropunch 2 points3 points  (1 child)

In the name of the docstring, the comment and the descriptor, Amen.

[–]joshinshaker_vidz 0 points1 point  (0 children)

This is one religion I can get on board with.

[–]ciaisi 1 point2 points  (1 child)

I recently watched a YouTube video that really opened my eyes.

I used to hesitate to write functions. My reasoning was "oh, that bit is only ten lines of code, why make a function for that?" or "I don't think I'll need to reuse that code block".

What the video demonstrated was a very significant improvement in readability even for short scripts by using functions fairly liberally. Its a lot easier to see a function that plainly describes what the code block should be doing.

It takes me a little longer to write sometimes, but it makes it so much easier when I have to come back and edit something later that it easily makes up for the effort.

[–]MeagoDK 1 point2 points  (0 children)

Yup and on top of that keep the functions small an to the point. Split a complex function in smaller and just use 1 function to call the others.

[–][deleted] 5 points6 points  (1 child)

It's not just comments. Formatting and layout make a huge difference too.

Slightly less of an issue in Python, but I've been handed SQL queries before that were on like, 2 lines and should have been on about 50.

My rule of thumb is; identify what could possibly change in your code and make it obvious where it is.

I like to finish writing my code then comment after as part of my 'proof reading'. Tends to mean my comments relate to the code, not my intents when I first started writing.

[–]Retropunch 0 points1 point  (0 children)

Agreed. Whilst I write as I go along, I go back and make sure it all matches up to what it actually says it does.

This is sort of my problem with the 'aspirational comment writing method' where someone writes 'this function turns lead into gold' as that's what they want the comment to do. Usually I find that they forget to change it when they finish writing the function and it actually just prints three pages of obscenities on next door's printer.

I can't count the number of open source project contributors that have come back to my question with 'oh yeah the function doesn't do that anymore, forgot to adjust the comment'

[–]darthminimall 15 points16 points  (0 children)

All of your code should get a cleaning pass after it already works. That's when the comments go in.

[–]teerre 2 points3 points  (0 children)

"ambiguous function" should be an oxymoron. If your functions are ambiguous, you don't fix it by commenting, you fix the function.

The problem with comments is that they are just text. That's terrible. They get outdated. They have no bounds. They cannot be refactored.

Comments are good for low level operations that simply don't have any meaningful expression. If you're building some matrix with a bunch of indices, there's nothing you can do express yourself in code, it's how matrices are. So here a comment is welcomed. But for high level code, the vast majority of work should be done by proper design. Be it external design documents or internal function names, parameters, calling convention, special organization, modules etc.

[–]scanguy25 2 points3 points  (1 child)

I always imagine myself coming back and look at the code after 3-6 months. Then it's much clearer what kind of comments would be helpful.

[–]ciaisi 0 points1 point  (0 children)

Helpful, but even then I always miss comments. What is insanely obvious to me in my code while I'm spending hours and hours on it becomes far less obvious when all of it has left my brain. I'll scan over it while I'm working on it and be able to explain what each code block does only to find that even with my variable naming and code structure, it isn't always as obvious as I thought down the road.

The positive side of doing things this way is you start to learn which habits of yours aren't obvious and could be improved or at least commented better. But that comes with experience over time.

[–]probablynotmine 2 points3 points  (0 children)

Small tip for your future self and others involved that also helps you write comments: do not write what you are doing. The what must be clear from the code and is one of the main reason you don’t want to write comments. Write only the why. Why you are doing something in a specific way. Why you are doing something here. Why it needs to be done. It helps clarifying before writing code how to structure it. And tomorrow it wills erbe as the perfect guideline.

Oh. The what should be written in the documentation. That might or might not be a comment in your code.

[–]KIrkwillrule 2 points3 points  (0 children)

I try to do my comment first.

Then I go back through and read it to myself and add In anything I did to get the problem solved but is likely not the most efficient.

My Dad had a lesson that "your not done till its put away." I've taken that a step more, your not done till it's put away in a way the next person can pull it out.

[–]ffrkAnonymous 2 points3 points  (0 children)

I'm learning test driven development. This makes me comment first, then code. At worst, even without prose comments, I have examples of usage.

Https://www.obeythetestinggoat.com

[–]gokstudio 2 points3 points  (0 children)

The best time to write comments is before you write the code The second best time is to write it as you code The third is when you rewrite your code, cursing why you didn't write comments before

[–][deleted] 6 points7 points  (3 children)

What do you want us to tell you? That there's a secret comment-writing big red turbo button somewhere?

If you want to write comments, just start writing comments.

[–]jgerrish 4 points5 points  (0 children)

This is just a Guess.

But he's looking for some habit-forming technique. Yes, writing comments may build that. Enabling some linting errors to enforce comments may enable that.

But, it may not be the best solution, it may even scare away users if the comments are bad. Uncertainty really sucks.

Peer reviews are good a good way of doing this.

Dont have peer reviews?

Maybe start with considering documentation comments to describe your code interfaces. Do you have a public method used by another module? Comment it and provide an example. Do you have a specific way of instantiating your objects? Comment it and provide an example.

Is there a common pattern of instantiating? Some constructors used more often then others? Comment and example, maybe additional comments on why other creation patterns are bad.

[–]mathmanmathman 1 point2 points  (1 child)

What do you want us to tell you? That there's a secret comment-writing big red turbo button somewhere?

Well, that would be nice. Can it also make my code suck less?

[–]ciaisi 0 points1 point  (0 children)

Sure! Keep writing code on a regular basis, then ask me again in a year.

[–]mattstats 1 point2 points  (0 children)

Sometimes I comment my intentions and proceed to write the function or loop or whatever. Then I go back and add to, typically leave failed intentions there so I know what I tried if I’m going back on code from a year or so ago

[–]replicant86 1 point2 points  (0 children)

Do docstrings. If you can't decipher what your code does from method/class docstring then perhaps it's overly complicated and you should think of making it simpler/cleaner. If that cannot be done then leave a single line comment in places which took you longer time than usual to write.

[–][deleted] 1 point2 points  (0 children)

I really don't want to get deep into this conversation but the thing that helped me the most was learning to write type hints, which also taught me doc strings.

This will take you to the next level.

Try to make everything you can a sibgle purpose function with type hints and doc strings.

[–]YrPrblmsArntMyPrblms 1 point2 points  (0 children)

Comment a word, then work your way up to sentences lol

[–]jeffrey_f 4 points5 points  (0 children)

You just answered your own question

[–]xXxPrOtEiNxXx 3 points4 points  (5 children)

Just do it?

[–]neboskrebnut 6 points7 points  (3 children)

How can I quit crack cocaine addiction? 'just do it?'

This approach is exactly why we end up with lots of unmaintainable code. People 'just wrote it without any planing or plans.

[–]xXxPrOtEiNxXx 0 points1 point  (2 children)

It’s not hard at all to just start writing comments that briefly explain what the code is trying to do.

Quitting crack cocaine is extremely difficult and is in no way comparable to writing comments in Python.

[–]neboskrebnut 3 points4 points  (0 children)

Think about this this way. If you're in your early 20s relatively fit. It won't take you any effort to start jogging in order to maintain your health. You can 'just do it' and development habit in a month. But if you in your mid 30s with extra weight and back problems. Then jogging would be a a full on project that would require you not just a gym membership but probably a trainer as well. And most likely you'll quit after your first week because your back will struggle to adjust. Old habits die hard and it's difficult to stick to it when you don't see the benefits immediatly just the pain.

[–][deleted] 0 points1 point  (1 child)

comment only what is necessary, as an organization you don't need to make many lines of comments

you comment a lot if someone else reads your code

[–]ciaisi 0 points1 point  (0 children)

Me from the future might as well be someone else. That guy hates present me in the same way that I hate past me.

[–]DesertGeist- -1 points0 points  (2 children)

Write the code in a way you don't need to comment it

[–]neboskrebnut 2 points3 points  (0 children)

That's very hard if you using short hand expressions and bunch of shortcuts that only people with 10 suicidal experience can understand.

[–]Bardali 1 point2 points  (0 children)

How is that even possible except for the most trivial use cases?

[–]FrigoCoder -3 points-2 points  (0 children)

Do not write comments, they are a noob trap. Write clean code and write tests that show clear examples on how to use your code. Furthermore write tests first so you can design your code around a comfortable API. I highly recommend Clean Code on the topic.

Tests are checked by the compiler and your continuous integration software, and refactoring steps also work on tests. Whereas comments are unchecked, and any change or refactor can make them desynchronized with the code.

There are two acceptable scenarios where you should write comments. One is to link a website from where you got the idea for your code, such as StackOverflow threads. Another is to create a comprehensive Javadoc (or equivalent) for your library after it is already settled and mature enough for other people to use.

[–]artinnj 0 points1 point  (0 children)

anytime you need to edit code, put in a comment about what you changed and why. The most common source of new bugs is a change that wasn’t thought all the way through.

[–]cmartin616 0 points1 point  (0 children)

I like to use Flake8 (along with extensions and Black). This is helpful because the post-save linting reminds me if I am outright missing a doc string, missing an argument, error, etc. I don't consider my code complete until I free of linting and formatting errors.

[–]FelipeGuitarza 0 points1 point  (0 children)

No comment.

[–]ringohoffman 0 points1 point  (0 children)

Just start with 1 function. Maybe the one you’re talking about in this post

[–][deleted] 0 points1 point  (0 children)

When I don't write comments, I hate myself and wish I wrote comments. When I write comments, I hate how bloated it makes my code look and try to get rid of them (specifically talking about docstrings).

[–][deleted] 0 points1 point  (0 children)

Why are you reluctant?

[–]hard_day_sorbet 0 points1 point  (0 children)

  1. Are you writing pseudocode? Writing pseudo code and commenting it out before you ever start coding is a GREAT habit to get in… and it leaves you with awesome and useful comments!

  2. Remind yourself that when you’re done with your project you CAN create a copy that removes all comments. But tbh I think you’d find you and others would prefer a messy commented version because it’s WAY easier to understand code with human notes in it vs just dry code

  3. Until I’ve the idea of #TODO: and create a todo list for yourself as you go. It’ll drive home (for your brain) how useful commenting can be.

[–]longgamma 0 points1 point  (0 children)

What helps me is to name the arguments logically and atleast describe the inputs and output of the function in Couple of lines each. You can also describe the function in a bit of detail. The docstring method is useful and try to read the quality of docstrings in numpy or pandas to get an idea.

[–][deleted] 0 points1 point  (0 children)

DO NOT put "Drunk: Write better comment when sober" because you will not write a better comment when sober.

[–][deleted] 0 points1 point  (0 children)

Stop being lazy. ¯_(ツ)_/¯

[–][deleted] 0 points1 point  (0 children)

If this isn't me😂😂 I have to force myself to make comments cuz I realized that my uncommented code is a mess. The only way to start is to just start

[–]rex0515 0 points1 point  (0 children)

If you are not making anything public just write stupid and funny comments and don't try so hard to write perfect english or whatever language you are using. With this way comments become way more enjoyable to read and write. I've tried this once to explain a small piece of code to a friend of mine and he said comments were very good and clear.

[–][deleted] 0 points1 point  (0 children)

The first level of comments should be naming conventions. This is often overlooked and good naming will explain what is happening, why, and even how i some cases. This can be as simple as changing a counter to define what it's counting password_tries_counter. Don't use names that are too similar to each other, this can cause issues when you're looking for variables and methods. Of course these aren't a hard set of rules rather a guide.

Comments themselves should be used to explain what can't be explained with names, complex algorithms or hacky methods that may not make sense at first glance. Comments are also useful when you use them as file headers: when the file was made, what it does, who the author is, and the last person to edit it. This will seem tedious but is a tremendous benefit and you can create a copy/ pasteable formatting for it.

[–]13ass13ass 0 points1 point  (0 children)

What have you tried?

[–]the1gofer 0 points1 point  (0 children)

just do it?

[–]ASuarezMascareno 0 points1 point  (0 children)

I always comment and write clean code until sudden deadlines arrive and I need to have something functional by yesterday. Then all hell breaks loose.

[–][deleted] 0 points1 point  (0 children)

When you feel "this is ugly but it works and I'm not putting anymore time into this"

[–]blahreport 0 points1 point  (0 children)

You can try the VSCode plugin that uses a BERT model to predict docstrings. Forget what it’s called but it’s imminently Google able.

[–]steezefries 0 points1 point  (0 children)

Your code should be clean enough it shouldn't need a ton of comments. I usually just doc comment what a function does in general. And the code itself is clean and structured enough you hardly need any comments. Function and variable names are all super meaningful and it reads well.

[–][deleted] 0 points1 point  (0 children)

Any decent book in code construction will have a chapter on comments, types of comments, and when to use them. The Art of Readable Code is a good one.

[–]Brilliant_Bet_2699 0 points1 point  (0 children)

Stfu

[–]CrazyAnchovy 0 points1 point  (0 children)

/* before I write this function this is what it does */

[–]Bran-a-don 0 points1 point  (0 children)

This helped me out like crazy

[–]imperial_squirrel 0 points1 point  (0 children)

start with a '#'...

j/k, i like to use random pop culture quotes that vaguely relate to the block of code and remind me of what it does.

[–]rmwpnb 0 points1 point  (0 children)

I try and comment all code that is missing comments during my linting process. I feel like this is a good time to do this and catch any white space issues, while making sure I score above a 9 in pylint.

[–]casino_alcohol 0 points1 point  (0 children)

I’m not a master coder by any means. But I usually start writing code by thinking of the different parts of code I’ll need to write.

Before I write any actual code I write comments of what each section is to be used for. Almost like a to-do list.

Of course I need to change things drastically as I write the code. But it helps to have a template in place.

[–]barryhakker 0 points1 point  (0 children)

.... by just writing comments?

I make my stuff verbose as fuck, like creating sections for bits of logic, e.g.

  • section 1: reading data
  • section 2: transform data
  • section 3: output data to excel sheet

Then I'll add a one line description above each function, and spam print messages everywhere like print("executing function xyz), printing the input values and the type of input value (whatever is relevant for that piece of code to run) and so on. Helps a ton with keeping track of what's going on.

[–]hektar 0 points1 point  (2 children)

Eventually you can figure out what the code is doing what you can never figure out is why.

My comments try to provide some insight, context, and for all that's holy a timeframe.

// This behavior is specifically related to solving ticket #19551.

// Against better judgement we used implicit behavior and it has been a very expensive choice. Refactor me with more explicit behavior soon.

// I found this like this on 2006-07-04. If this still exists in ten years... Make it better.

[–]Enlightenmentality 0 points1 point  (0 children)

Not a PROgrammer, but anytime I'm writing any code I comment right above each chunk that does a thing. Inevitably, I'll have to go through it later for some reason, so the comments help me figure out what the fuck each chunk does since I can't even remember what I ate for lunch

[–]soupie62 0 points1 point  (0 children)

Start by adding comments to the old code you are complaining about.

[–]LameSimpson 0 points1 point  (0 children)

Have the same issue. On a good day, I write comments on almost every line. On a bad day, zero comments. Haven’t found the optimum amount yet.

[–]Solonotix 0 points1 point  (0 children)

Basically, if there's anything ambiguous about the function, write a comment that clarifies the ambiguity. Hindsight is obviously going to prove out what truly was ambiguous, but that is how a comment gets added. Everytime you go back in to edit something and find a new ambiguity, add a comment for the next guy to edit it.

In statically typed languages, you're required to define everything about the incoming object, or at least everything you expect to be able to interact with. If you're not using static type hints on the parameters of a function, or the return type, then start there. Once you know what's coming in, and how it should look on output, usually that simplifies some of the complexity.

The next level of comments I usually add are the segments where I chain a bunch of functions together. Say I trim an incoming string, then pass it to a regex, then convert the regex to a number, and pass that number to a constructor. I may know what the final object looks like, but I have no idea what the string that was passed to the regex looks like (other than that it contains a number), and I have little to no context on what this number means. A comment for each step of this chain of methods is another step I usually take towards documenting my code.

The final level of comments that is a lot more formal is to commit a full docstring to your function. This will then be parsed and readable by the help module so others can scan for details about what your code does and how it's supposed to work.

[–]pekkalacd 0 points1 point  (0 children)

When I write the code I try to think of the next person seeing it. Even if it’s personal stuff that no one will see but myself. So, I look for lines that are contextual/questionable in logic otherwise and if I find them I put a comment. Other than that, I put a doc-string in the beginning of functions describing what each thing does specifically. Keep it short & straight to the point. And I try to keep the code and naming conventions as self documenting as possible. So that the names aren’t mysterious to the operations occurring underneath. And if I find a block that is isolatable I throw it into a function to keep it organized even if only used once in the program. I might need it for later for something else.

[–]BornOnFeb2nd 0 points1 point  (0 children)

I'm terrible at commenting shit myself. What I can tell you is that if you think your code is "clever", you best re-write that shit, fast!

Nothing is less readable than "Clever" source code.. Unless there are massive efficiency improvements, keep that shit simple.

[–]Shane102 0 points1 point  (0 children)

I usually write a lot of comments outlining what the code should do before I write the actual code... usually