how to respect Post.CommentsAllowed if Post and Comment are separate aggregate roots? - microservices

In a classic example of 2 aggregate roots like:
class Post
{
string AuthorId;
string Title;
string Content;
boolean AllowComments;
...
}
class Comment
{
string AuthorId;
string Content;
DateTime Date;
...
}
When creating new comment, how to ensure that comments are added only to the post that have Post.AllowComments = true?
Having on mind that when user starts writing comment Post.AllowComments could very well be true but in the meantime (while comment is being written) the Post author might change it to false.
Or, even at the time of the submission => when we check Post.AreCommentsAllowed() it could return true but then when we do CommentRepository.Save(comment) it could be false.
Of course, one Post might have many Comments so it might not be practical to have single aggregate where Post have collection of Comments.
Is there any other solution to this?
PS.
I could do db transaction within which i'd check it but i'm looking for a DDD purist solution.

i'm looking for a DDD purist solution.
Basic idea first: if our Comments logic needs information from our Post aggregate, then what we normally do is pass a copy of that information as an argument.
So our application code would, in this case, get a local copy of AllowComments, presumably by retrieving the handle to the Post aggregate root and invoking some query in its interface.
Within the comments aggregate, you would then be able to use that information as necessary (for instance, as an argument to some branching logic)
Race conditions are hard.
A microsecond difference in timing shouldn’t make a difference to core business behaviors. -- Udi Dahan
If data here must be consistent with data there, then the answer is that we have to lock both when we are making our change.
In an application where information is stored locally, that's pretty straight forward, at least on paper: you just need to acquire locks on both objects at the same time, so that the data doesn't change out from under you. There's a bit of care required to ensure that you get deadlocked (aka the dining philosophers problem).
In a distributed system, this can get really nasty.
The usual answers in "modern purist DDD" is that you either relax the consistency requirement (the lock that you are reading is allowed to change while you are working) and you mitigate the inconsistencies elsewhere (see Memories, Guesses, and Apologies by Pat Helland) OR you change your aggregate design so that all of the information is enclosed within the same aggregate (here, that would mean making the comment entities parts of the post aggregate).
Also: creation patterns are weird; you expect that the entity you are intending to create doesn't yet exist in the repository (but off the happy path maybe it does), so that business logic doesn't fit as smoothly into the usual "get the handle from the repository" pattern.
So the conditional logic needs to sneak somewhere else -- maybe into the Post aggregate? maybe you just leave it in the application code? ultimately, somebody is going to have to tell the application code if anything is being saved in the repository.
As far as I can tell, there isn't a broad consensus on how to handle conditional create logic in DDD, just lots of different compromises that might be "good enough" in their local context.

Related

2 JSON Schema Questions, Is the type keyword required and what is the differencen between Core and Validation

Okay I have been UP and DOWN the internet and I cannot find an answer that DEFINITIVELY answers the following question.
"Is the type keyword required?" If it is not then can some one, for all that is holy, please, in EXCRUCIATING detail, describe what should happen when it is not provided, validation-wise.
I have found this...
http://json-schema.org/draft/2020-12/json-schema-validation.html#rfc.section.6.1.1
But I have found so many other examples where a schema object can be defined and not have this keyword.
For example I have found this repo with testing examples.
https://github.com/json-schema-org/JSON-Schema-Test-Suite/blob/master/tests/draft7/additionalProperties.json
Here they have a schema at line 5. It does not have a type but does look like they are talking about an object. Also on lines 21 - 25 they describe a test where an array is valid.
Can someone please clarify this for me.
Also for the second one,... What is the difference between the Core and the Validation as defined here...
https://json-schema.org/specification.html
Thank you in advanced
1. Is the type keyword required?
No. Keywords will respond to instances of the types they're designed for, otherwise they will be ignored (silently pass validation). So
{ "minimum": 5 }
will pass anything as long as it's not a number less than 5. Objects, strings, arrays, etc., all pass. But as soon as you introduce a number, this keyword becomes interested and it'll do its thing.
Every keyword has a type or set of types that it responds to. type is one of the ones that responds to all of them.
2. What are the different specs for?
We (the spec authors) thought it would make things a little simpler if we split the specification into two parts: one for the schema construction keywords (e.g. $id, $schema, allOf, properties, etc.), and one for value validation and annotation (e.g. minimum, minLength, etc.). It does mean that you have to look into several documents in order to create a validator, however.
It also allows us to revise one of them without the other, though we've never done that.
This split was done several iterations ago, and we've just kept it as it seems to work well.

Defining mutations in GraphQL via fields: Is this bad practice?

Suppose you have a user type, and a user has many posts. Then imagine you want to find a user, and delete all of their posts. One way to do this is to implement the following mutation field:
field deleteAllPosts, types[Types::PostType] do
argument :user_id, types.String
resolve -> (obj,args,ctx){
posts = Posts.where(user_id:args[:user_id])
posts.each{|post| post.destroy}
}
end
Then the query
mutation {
deleteAllPosts(user_id:1)
}
will delete all the posts of the user with id 1.
Before I did this, I thought about doing it a different way, which I've not seen anyone else do. I wanted to check that this different way doesn't have any pitfalls, or reasons I shouldn't use it.
The idea is to instead put a deletePost field for PostType, and a findUser field on mutation (which would typically be a query field). Assuming it's obvious how those fields would be defined, I would then make the query
mutation{
findUser(id:1){
posts{
deletePost{
id
}
}
}
}
Is this a bad idea?
Edit in response to feedback: One thing I'm concerned about is the possibility that a user could, in principle, make the deletePost selection inside of a query. But I'm tempted to say that that's "their fault". I'd like to say "this selection can only be made if it is inside of a mutation query", but I don't think that's possible in GraphQL.
In order to avoid the XY problem, here is why I am keen to use this idea rather than the initial one. It feels more expressive (said differently, it feels less redundant). Suppose that, after a while, you decide that you want to delete all the posts for those users belonging to a particular group. Then in what I regard as the 'convention', you should create a whole new mutation field:
field deleteAllPostsInGroup, types[Types::PostType] do
argument :group_id, types.String
resolve -> (obj,args,ctx){
posts = Group.find_by(args[:group_id]).users.map{|u| u.posts}.flatten
posts.each{|post| post.destroy}
}
end
whereas in my suggested convention you just define a trivial findGroup field (but you have to define it on mutation, where it doesn't belong), and make the query:
mutation{
findGroup(id:1){
users{
posts{
deletePost{
id
}
}
}
}
}
I suppose that really what I'm trying to do is use a query to find some data, and then mutate the data I've found. I don't know how to do this in GraphQL.
Second Edit: It seems like there is a well-defined component of this question, which I have asked here. It may turn out that one of these questions answers the other, and can be closed, but I don't know which way round yet.
This is basically a code quality issue and is similar to asking about the point of the DRY principle or encapsulation.
A quote from https://graphql.org/learn/queries/ reads:
In REST, any request might end up causing some side-effects on the server, but by convention it's suggested that one doesn't use GET requests to modify data. GraphQL is similar - technically any query could be implemented to cause a data write. However, it's useful to establish a convention that any operations that cause writes should be sent explicitly via a mutation.
This is a good convention as it makes maintenance, testing and debugging easier. Side-effects, whether intentional or not, can be awfully difficult to track and understand. Particularly if you have them in GraphQL queries, which can be arbitrarily large and complex. There is nothing preventing you from querying and modifying the same object and it's siblings at the same time, and doing this multiple times in one query by simple nesting. It is very easy to get this wrong.
Even if you pull it off, code readability and maintainability suffer. E.g. if you knew that only your mutations ever modified the data, and queries had no effect on it, you would immediately know where to start looking for the implementation of a particular behaviour. It is also a lot easier to reason about how your program works in general.
If you only write small, properly named, granular mutations, you can reason about what they do more easily than you could if you had a complex query which updated different data at different points.
Last but not necessarily least, sticking to conventions is useful if you ever need to transfer your work to someone else.
In short - it is all about making the lives of yourself and others easier in the future.
EDIT
OK, so I see where you are going with this - you want to give the flexibility of a GraphQL query to the mutations. Sure, this particular example would work. Not going this way would only be about the future. There is no point in discussing this if deletePost is the only operation you will ever define.
If that's not the case, then what if you wanted to delete, let's say, 5 specific user posts? Would you give extra parameters to findGroup and then pass those down the tree? But then why does findGroup method have to know about what you will do with it's results? That kind of defies the idea of a flexible query itself. What if you also wanted to perform mutations on users? More parameters for findGroup? What if users and posts can be queried in a different way, like, users by domains, posts by categories, etc.? Define the same parameters there too? How would you ensure that with every operation (especially if you do a few of them at once) all the relational links are properly erased in your database? You would have to imagine every possible combination of queries and query-mutations and code appropriately for them. Since query size is unlimited it could end up being very hard to do. And even if the purpose of an individual query-mutation (deletePost) is clear and easy to grasp, the overall query would not be. Quickly your queries would become too complex to understand even for you and you'd probably begin breaking them down to smaller ones, which would only do specific mutations. This way you'd go back to the original convention but a more complex version of it. You would probably also end up defining some regular mutations too. How would you update or add posts, e.g.? That would spread your logic all over the place.
These questions would not occur if you were writing mutations. That's slightly more work in exchange for better maintainability.
These are all potential issues in the future (and there are probably more). If these don't concern you, then please go ahead with the implementation. I personally would run away from a project that did this, but if you are really clever, I don't see anything that would technically completely prevent you from achieving what you want :]

Pointless getter checks when updating an object

Hopefully this will not come across as a silly or pedantic question, but I'm curious.
Occasionally I'll be in a situation where an existing object's properties may need to be updated with new variables, and I'll do it like this (in no particular language):
public void Update(date, somevar){
if(date > this.Date){
this.Var = somevar;
}
}
The idea being that if the date passed to the function is more recent than the date in the current object, the variable is updated. Think of it as like a basic way of caching something.
Now, the interesting part is that I know somevar will never be "old" when compared to this.Var, but it may be the same. So as far as I can see, checking the date is pointless, and therefore a pointless operation for the program to perform.
So what this is really about is whether it's better - in whatever way - to perform a write to this.Var every time Update is called, or getting this.Date, comparing it, then possibly performing the write. And just to throw in something interesting here, what if Update were to be called multiple times?
If the example I've given makes no sense or has holes in it, I apologise; I can't think of another way of giving an example, but hopefully you can see the point I'm trying to make here.
Unless for some reason assignment is an expensive operation (e.g. it always triggers a database write), this isn't going to make your programme faster.
The point of putting checks in your setters is usually to enforce data integrity, i.e. to preserve programme invariants, and thus the correctness of your other code, which is rather more important.

Best Practice for comments in Java source files?

This doesn't have to be Java, but it's what I'm dealing with. Also, not so much concerned with the methods and details of those, I'm wondering about the overall class file.
What are some of the things I really need to have in my comments for a given class file? At my corporation, the only things I really can come up with:
Copyright/License
A description of what the class does
A last modified date?
Is there anything else which should be provided?
One logical thing I've heard is to keep authors out of the header because it's redundant with the information already being provided via source control.
Update:
JavaDoc can be assumed here, but I'm really more concerned about the details of what's good to include content-wise, whether it's definitive meta-data that can be mined, or the more loose, WHY etc...
One logical thing I've heard is to keep authors out of the header because it's redundant
with the information already being provided via source control.
also last modified date is redundant
I use a small set of documentation patterns:
always documenting about thread-safety
always documenting immutability
javadoc with examples
#Deprecation with WHY and HOW to replace the annotated element
keeping comments at minimum
No to the "last modified date" - that belongs in source control too.
The other two are fine. Basically concentrate on the useful text - what the class does, any caveats around thread safety, expected usage etc.
Implementation comments should usually be about why you're doing something non-obvious - and should therefore be rare. (For instance, it could be because some API behaves in an unusual way, or because there's a useful shortcut you can use but which isn't immediately obvious.)
For the sanity of yourself and future developers, you really ought to be writing Javadocs.
When you feel the need to write comments to explain what some code does, improve the readability of the code, so that comments are not needed. You can do that by renaming methods/fields/classes to have more meaningful names, and by splitting larger methods into smaller methods using the composed method pattern.
If even after all your efforts the code is not self-explanatory, for example the reason why some unobvious code had to be written is not clear from the code, then apologize by writing comments. (Sometimes you can document the reasons by writing a test which will fail, if somebody changes the unobvious-but-correct code to do the obvious-but-wrong thing. But having a comment in addition to that is also useful. I prefix such comments often with "// HACK:" or "// XXX:".)
An overall description of the purpose of the class, a description for each field and a contract for each method. Javadoc format works well.
If you assign ownership of components to particular developers or teams, owners should be recorded in the component source or VCS metadata.

What is your personal approach/take on commenting?

Duplicate
What are your hard rules about commenting?
A Developer I work with had some things to say about commenting that were interesting to me (see below). What is your personal approach/take on commenting?
"I don't add comments to code unless
its a simple heading or there's a
platform-bug or a necessary
work-around that isn't obvious. Code
can change and comments may become
misleading. Code should be
self-documenting in its use of
descriptive names and its logical
organization - and its solutions
should be the cleanest/simplest way
to perform a given task. If a
programmer can't tell what a program
does by only reading the code, then
he's not ready to alter it.
Commenting tends to be a crutch for
writing something complex or
non-obvious - my goal is to always
write clean and simple code."
"I think there a few camps when it
comes to commenting, the
enterprisey-type who think they're
writing an API and some grand
code-library that will be used for
generations to come, the
craftsman-like programmer that thinks
code says what it does clearer than a
comment could, and novices that write
verbose/unclear code so as to need to
leave notes to themselves as to why
they did something."
There's a tragic flaw with the "self-documenting code" theory. Yes, reading the code will tell you exactly what it is doing. However, the code is incapable of telling you what it's supposed to be doing.
I think it's safe to say that all bugs are caused when code is not doing what it's supposed to be doing :). So if we add some key comments to provide maintainers with enough information to know what a piece of code is supposed to be doing, then we have given them the ability to fix a whole lot of bugs.
That leaves us with the question of how many comments to put in. If you put in too many comments, things become tedious to maintain and the comments will inevitably be out of date with the code. If you put in too few, then they're not particularly useful.
I've found regular comments to be most useful in the following places:
1) A brief description at the top of a .h or .cpp file for a class explaining the purpose of the class. This helps give maintainers a quick overview without having to sift through all of the code.
2) A comment block before the implementation of a non-trivial function explaining the purpose of it and detailing its expected inputs, potential outputs, and any oddities to expect when calling the function. This saves future maintainers from having to decipher entire functions to figure these things out.
Other than that, I tend to comment anything that might appear confusing or odd to someone. For example: "This array is 1 based instead of 0 based because of blah blah".
Well written, well placed comments are invaluable. Bad comments are often worse than no comments. To me, lack of any comments at all indicates laziness and/or arrogance on the part of the author of the code. No matter how obvious it is to you what the code is doing or how fantastic your code is, it's a challenging task to come into a body of code cold and figure out what the heck is going on. Well done comments can make a world of difference getting someone up to speed on existing code.
I've always liked Refactoring's take on commenting:
The reason we mention comments here is that comments often are used as a deodorant. It's surprising how often you look at thickly commented code and notice that the comments are there because the code is bad.
Comments lead us to bad code that has all the rotten whiffs we've discussed in the rest of this chapter. Our first action is to remove the bad smells by refactoring. When we're finished, we often find that the comments are superfluous.
As controversial as that is, it's rings true for the code I've read. To be fair, Fowler isn't saying to never comment, but to think about the state of your code before you do.
You need documentation (in some form; not always comments) for a local understanding of the code. Code by itself tells you what it does, if you read all of it and can keep it all in mind. (More on this below.) Comments are best for informal or semiformal documentation.
Many people say comments are a code smell, replaceable by refactoring, better naming, and tests. While this is true of bad comments (which are legion), it's easy to jump to concluding it's always so, and hallelujah, no more comments. This puts all the burden of local documentation -- too much of it, I think -- on naming and tests.
Document the contract of each function and, for each type of object, what it represents and any constraints on a valid representation (technically, the abstraction function and representation invariant). Use executable, testable documentation where practical (doctests, unit tests, assertions), but also write short comments giving the gist where helpful. (Where tests take the form of examples, they're incomplete; where they're complete, precise contracts, they can be as much work to grok as the code itself.) Write top-level comments for each module and each project; these can explain conventions that keep all your other comments (and code) short. (This supports naming-as-documentation: with conventions established, and a place we can expect to find subtleties noted, we can be confident more often that the names tell all we need to know.) Longer, stylized, irritatingly redundant Javadocs have their uses, but helped generate the backlash.
(For instance, this:
Perform an n-fold frobulation.
#param n the number of times to frobulate
#param x the x-coordinate of the center of frobulation
#param y the y-coordinate of the center of frobulation
#param z the z-coordinate of the center of frobulation
could be like "Frobulate n times around the center (x,y,z)." Comments don't have to be a chore to read and write.)
I don't always do as I say here; it depends on how much I value the code and who I expect to read it. But learning how to write this way made me a better programmer even when cutting corners.
Back on the claim that we document for the sake of local understanding: what does this function do?
def is_even(n): return is_odd(n-1)
Tests if an integer is even? If is_odd() tests if an integer is odd, then yes, that works. Suppose we had this:
def is_odd(n): return is_even(n-1)
The same reasoning says this is_odd() tests if an integer is odd. Put them together, of course, and neither works, even though each works if the other does. Change it a bit and we'd have code that does work, but only for natural numbers, while still locally looking like it works for integers. In microcosm that's what understanding a codebase is like: tracing dependencies around in circles to try to reverse-engineer assumptions the author could have explained in a line or two if they'd bothered. I hate the expense of spirit thoughtless coders have put me to this way over the past couple of decades: oh, this method looks like it has the side effect of farbuttling the warpcore... always? Well, if odd crobuncles desaturate, at least; do they? Better check all the crobuncle-handling code... which will pose its own challenges to understanding. Good documentation cuts this O(n) pointer-chasing down to O(1): e.g. knowing a function's contract and the contracts of the things it explicitly uses, the function's code should make sense with no further knowledge of the system. (Here, contracts saying is_even() and is_odd() work on natural numbers would tell us that both functions need to test for n==0.)
My only real rule is that comments should explain why code is there, not what it is doing or how it is doing it. Those things can change, and if they do the comments have to be maintained. The purpose the code exists in the first place shouldn't change.
the purpose of comments is to explain the context - the reason for the code; this, the programmer cannot know from mere code inspection. For example:
strangeSingleton.MoveLeft(1.06);
badlyNamedGroup.Ignite();
who knows what the heck this is for? but with a simple comment, all is revealed:
//when under attack, sidestep and retaliate with rocket bundles
strangeSingleton.MoveLeft(1.06);
badlyNamedGroup.Ignite();
seriously, comments are for the why, not the how, unless the how is unintuitive.
While I agree that code should be self-readable, I still see a lot of value in adding extensive comment blocks for explaining design decisions. For example "I did xyz instead of the common practice of abc because of this caveot ..." with a URL to a bug report or something.
I try to look at it as: If I'm dead and gone and someone straight out of college has to fix a bug here, what are they going to need to know?
In general I see comments used to explain poorly written code. Most code can be written in a way that would make comments redundant. Having said that I find myself leaving comments in code where the semantics aren't intuitive, such as calling into an API that has strange or unexpected behavior etc...
I also generally subscribe to the self-documenting code idea, so I think your developer friend gives good advice, and I won't repeat that, but there are definitely many situations where comments are necessary.
A lot of times I think it boils down to how close the implementation is to the types of ordinary or easy abstractions that code-readers in the future are going to be comfortable with or more generally to what degree the code tells the entire story. This will result in more or fewer comments depending on the type of programming language and project.
So, for example if you were using some kind of C-style pointer arithmetic in an unsafe C# code block, you shouldn't expect C# programmers to easily switch from C# code reading (which is probably typically more declarative or at least less about lower-level pointer manipulation) to be able to understand what your unsafe code is doing.
Another example is when you need to do some work deriving or researching an algorithm or equation or something that is not going to end up in your code but will be necessary to understand if anyone needs to modify your code significantly. You should document this somewhere and having at least a reference directly in the relevant code section will help a lot.
I don't think it matters how many or how few comments your code contains. If your code contains comments, they have to maintained, just like the rest of your code.
EDIT: That sounded a bit pompous, but I think that too many people forget that even the names of the variables, or the structures we use in the code, are all simply "tags" - they only have meaning to us, because our brains see a string of characters such as customerNumber and understand that it is a customer number. And while it's true that comments lack any "enforcement" by the compiler, they aren't so far removed. They are meant to convey meaning to another person, a human programmer that is reading the text of the program.
If the code is not clear without comments, first make the code a clearer statement of intent, then only add comments as needed.
Comments have their place, but primarily for cases where the code is unavoidably subtle or complex (inherent complexity is due to the nature of the problem being solved, not due to laziness or muddled thinking on the part of the programmer).
Requiring comments and "measuring productivity" in lines-of-code can lead to junk such as:
/*****
*
* Increase the value of variable i,
* but only up to the value of variable j.
*
*****/
if (i < j) {
++i;
} else {
i = j;
}
rather than the succinct (and clear to the appropriately-skilled programmer):
i = Math.min(j, i + 1);
YMMV
The vast majority of my commnets are at the class-level and method-level, and I like to describe the higher-level view instead of just args/return value. I'm especially careful to describe any "non-linearities" in the function (limits, corner cases, etc) that could trip up the unwary.
Typically I don't comment inside a method, except to mark "FIXME" items, or very occasionally some sort of "here be monsters" gotcha that I just can't seem to clean up, but I work very hard to avoid those. As Fowler says in Refactoring, comments tend to indicate smally code.
Comments are part of code, just like functions, variables and everything else - and if changing the related functionality the comment must also be updated (just like function calls need changing if function arguments change).
In general, when programming you should do things once in one place only.
Therefore, if what code does is explained by clear naming, no comment is needed - and this is of course always the goal - it's the cleanest and simplest way.
However, if further explanation is needed, I will add a comment, prefixed with INFO, NOTE, and similar...
An INFO: comment is for general information if someone is unfamiliar with this area.
A NOTE: comment is to alert of a potential oddity, such as a strange business rule / implementation.
If I specifically don't want people touching code, I might add a WARNING: or similar prefix.
What I don't use, and am specifically opposed to, are changelog-style comments - whether inline or at the head of the file - these comments belong in the version control software, not the sourcecode!
I prefer to use "Hansel and Gretel" type comments; little notes in the code as to why I'm doing it this way, or why some other way isn't appropriate. The next person to visit this code will probably need this info, and more often than not, that person will be me.
As a contractor I know that some people maintaining my code will be unfamiliar with the advanced features of ADO.Net I am using. Where appropriate, I add a brief comment about the intent of my code and a URL to an MSDN page that explains in more detail.
I remember learning C# and reading other people's code I was often frustrated by questions like, "which of the 9 meanings of the colon character does this one mean?" If you don't know the name of the feature, how do you look it up?! (Side note: This would be a good IDE feature: I select an operator or other token in the code, right click then shows me it's language part and feature name. C# needs this, VB less so.)
As for the "I don't comment my code because it is so clear and clean" crowd, I find sometimes they overestimate how clear their very clever code is. The thought that a complex algorithm is self-explanatory to someone other than the author is wishful thinking.
And I like #17 of 26's comment (empahsis added):
... reading the code will tell you exactly
what it is doing. However, the code is
incapable of telling you what it's
supposed to be doing.
I very very rarely comment. MY theory is if you have to comment it's because you're not doing things the best way possible. Like a "work around" is the only thing I would comment. Because they often don't make sense but there is a reason you are doing it so you need to explain.
Comments are a symptom of sub-par code IMO. I'm a firm believer in self documenting code. Most of my work can be easily translated, even by a layman, because of descriptive variable names, simple form, and accurate and many methods (IOW not having methods that do 5 different things).
Comments are part of a programmers toolbox and can be used and abused alike. It's not up to you, that other programmer, or anyone really to tell you that one tool is bad overall. There are places and times for everything, including comments.
I agree with most of what's been said here though, that code should be written so clear that it is self-descriptive and thus comments aren't needed, but sometimes that conflicts with the best/optimal implementation, although that could probably be solved with an appropriately named method.
I agree with the self-documenting code theory, if I can't tell what a peice of code is doing simply by reading it then it probably needs refactoring, however there are some exceptions to this, I'll add a comment if:
I'm doing something that you don't
normally see
There are major side effects or implementation details that aren't obvious, or won't be next year
I need to remember to implement
something although I prefer an
exception in these cases.
If I'm forced to go do something else and I'm having good ideas, or a difficult time with the code, then I'll add sufficient comments to tmporarily preserve my mental state
Most of the time I find that the best comment is the function or method name I am currently coding in. All other comments (except for the reasons your friend mentioned - I agree with them) feel superfluous.
So in this instance commenting feels like overkill:
/*
* this function adds two integers
*/
int add(int x, int y)
{
// add x to y and return it
return x + y;
}
because the code is self-describing. There is no need to comment this kind of thing as the name of the function clearly indicates what it does and the return statement is pretty clear as well. You would be surprised how clear your code becomes when you break it down into tiny functions like this.
When programming in C, I'll use multi-line comments in header files to describe the API, eg parameters and return value of functions, configuration macros etc...
In source files, I'll stick to single-line comments which explain the purpose of non-self-evident pieces of code or to sub-section a function which can't be refactored to smaller ones in a sane way. Here's an example of my style of commenting in source files.
If you ever need more than a few lines of comments to explain what a given piece of code does, you should seriously consider if what you're doing can't be done in a better way...
I write comments that describe the purpose of a function or method and the results it returns in adequate detail. I don't write many inline code comments because I believe my function and variable naming to be adequate to understand what is going on.
I develop on a lot of legacy PHP systems that are absolutely terribly written. I wish the original developer would have left some type of comments in the code to describe what was going on in those systems. If you're going to write indecipherable or bad code that someone else will read eventually, you should comment it.
Also, if I am doing something a particular way that doesn't look right at first glance, but I know it is because the code in question is a workaround for a platform or something like that, then I'll comment with a WARNING comment.
Sometimes code does exactly what it needs to do, but is kind of complicated and wouldn't be immediately obvious the first time someone else looked at it. In this case, I'll add a short inline comment describing what the code is intended to do.
I also try to give methods and classes documentation headers, which is good for intellisense and auto-generated documentation. I actually have a bad habit of leaving 90% of my methods and classes undocumented. You don't have time to document things when you're in the middle of coding and everything is changing constantly. Then when you're done you don't feel like going back and finding all the new stuff and documenting it. It's probably good to go back every month or so and just write a bunch of documentation.
Here's my view (based on several years of doctoral research):
There's a huge difference between commenting functions (sort of a black box use, like JavaDocs), and commenting actual code for someone who will read the code ("internal commenting").
Most "well written" code shouldn't require much "internal commenting" because if it performs a lot then it should be broken into enough function calls. The functionality for each of these calls is then captured in the function name and in the function comments.
Now, function comments are indeed the problem, and in some ways your friend is right, that for most code there is no economical incentive for complete specifications the way that popular APIs are documented. The important thing here is to identify what are the "directives": directives are those information pieces that directly affect clients, and require some direct action (and are often unexpected). For example, X must be invoked before Y, don't call this from outside a UI thread, be aware that this has a certain side effect, etc. These are the things that are really important to capture.
Since most people never read full function documentations, and skim what they do read, you can actually increase the chances of awareness by capturing only the directives rather than the whole description.
I comment as much as needed - then, as much as I will need it a year later.
We add comments which provide the API reference documentation for all public classes / methods / properties / etc... This is well worth the effort because XML Documentation in C# has the nice effect of providing IntelliSense to users of these public APIs. .NET 4.0's code contracts will enable us to improve further on this practice.
As a general rule, we do not document internal implementations as we write code unless we are doing something non-obvious. The theory is that while we are writing new implementations, things are changing and comments are more likely than not to be wrong when the dust settles.
When we go back in to work on an existing piece of code, we add comments when we realize that it's taking some thought to figure out what in the heck is going on. This way, we wind up with comments where they are more likely to be correct (because the code is more stable) and where they are more likely to be useful (if I'm coming back to a piece of code today, it seems more likely that I might come back to it again tomorrow).
My approach:
Comments bridge the gap between context / real world and code. Therefore, each and every single line is commented, in correct English language.
I DO reject code that doesn't observe this rule in the strictest possible sense.
Usage of well formatted XML - comments is self-evident.
Sloppy commenting means sloppy code!
Here's how I wrote code:
if (hotel.isFull()) {
print("We're fully booked");
} else {
Guest guest = promptGuest();
hotel.checkIn(guest);
}
here's a few comments that I might write for that code:
// if hotel is full, refuse checkin, otherwise
// prompt the user for the guest info, and check in the guest.
If your code reads like a prose, there is no sense in writing comments that simply repeats what the code reads since the mental processing needed for reading the code and the comments would be almost equal; and if you read the comments first, you will still need to read the code as well.
On the other hand, there are situations where it is impossible or extremely difficult to make the code looks like a prose; that's where comment could patch in.

Resources