I prefer the strategy of wrapping my sentences in things like, "I think" or "I prefer".
So, I'd write, "This loop doesn't seem to terminate." or "I think that this condition needs a test." It's an implicit admission that I could be wrong and an invitation to push back. Just as often, I'll walk over and say, "Could you explain why you did that to me?" This is especially acceptable when it's agreed that a good review requires the reviewer understand what's going on.
I am reluctant to go for the direct "wtf?!" response, because as above, it bruises egos and people get defensive - and that is unhelpful to actually resolving issues. I tend to phrase it as "Perhaps I'm confused, but...". (One advantage of this is that sometimes, I am wrong, and this gives someone an opportunity to explain why, and in the process hopefully re-examining their thought process and testing it just in case.) I think I caught that pattern, as well as excessive usage of "though", from a good friend. One interpretation of this is that perhaps I've spent nigh-on 2½ decades being confused. <g>
There is, however, a place for the genuine WTF. I reserve it for "there's no way you could be that stupid" situations, like someone cheerfully telling me about the 256-bit encryption they used, and my discovering it's RSA-256.
The management-by-Perkele has however seemed to work to keep the Linux kernel clean up 'til now, although they don't really want to insult people.
You can phrase things directly, even adding minimizing language (to save face), but be clear about the problem during the review.
I second this notion. When you have doubt whether a loop terminates the question is appropriate but next to something as obvious as "for(;;) {}" it will simply sound insulting to the recipient's intelligence.
Also, think that the programmer might have already thought of that issue. Does that loop really never terminates? Isn't that test obvious/really needed?
But in all seriousness, projecting issues as character flaws is a really destructive thing to do, not just in programming but in any relationship. It's a really good habit to avoid it whenever possible.
I read somewhere (I think it was Blink) that marriage counselors could tell which marriages would fail by observing those that generalized around their spouses character rather arguing about the issues, ie "You always..."
It's not even about being diplomatic or being less likely to hurt someone's feelings (although you get that for free), it's really just about clarity as to what's being discussed. The most confident, secure person in the world might still get defensive when confronted with "you're wrong", because there's still a whiff of it being about questioning that person's credibility, as opposed to the thing that you think they're wrong about.
That together with the old chestnut "seek first to understand then to be understood" to ensure that you respect and understands their position are real game changers.
Its funny and scary how important these kind of social and interpersonal skills are working in any corporation. Yet often are lacking and leads to a lot of unnecessary friction.
It's something I almost wished was taught in schools, if only so they could recognize the patterns later when they go into working life.
http://www.slate.com/articles/double_x/doublex/2010/03/can_y...
I make mistakes all the time. I probably make mistakes more often than I do things right. Therefore, asking questions rather than making bold claims is usually betting the right way.
This doesn't mean you have to be a pushover. If you don't see something, you can say, "I'm sorry if I'm being a little slow here, but I still don't understand. Can you explain how XYZ works in more detail?" Most people are very happy to help you understand.
Exactly. I pulled in devs from two teams recently to discuss confusing modelling of domain objects on one end of our app vs. the other end, as my team were trying to deal with both. The naming involved was completely contradictory, which always makes fitting a system into your head so much harder when you have to mentally translate.
Turns out that each team had very valid reasons for modelling the entities as they did - the front-end team implemented the entities as understood by the business guys who would be using the GUI to configure them, and the other implemented the entities as understood by the API spec they were ultimately being transmitted over.
The initial response of "this is so dumb" was very easy and very wrong. Much of my personal development as a dev has been learning to suppress that initial dismissive response when encountering 'bad' code, instead asking why the code is as it is.
There's always a bit of a fundamental attribution error[1] in "your code is awful" discussions with devs.
(Although I'd say that this points to the issues that can arise from having two teams implement two separate parts of a business process.)
[1]: http://en.wikipedia.org/wiki/Fundamental_attribution_error
Asking a question leaves open the possibility that you, the person issuing the critique, are wrong. From my experience direct factual critiques are fine as long as they're correct. Some people might mind being told that a loop never terminates (even when that is trivially the case), but those people have their own ego issue to work on.
I feel the issue comes when your critique is either flat out incorrect or when it misses the context of why seemingly incorrect behavior might actually be desirable. Asking it as a question is an implicit exercise of the 'reasonable person principle'. That tiny shift in voice turns an accusation into a conversation that effectively starts with "My expectations have been violated by what I'm reading here. Have I missed something or was this intentional? If it's intentional, can you help me understand why this is desirable behavior?"
Yeah, this is very important. Otherwise, using a question instead of a statement is patronizing.
Me: "should this be documented in the team wiki?" Engineer: "Probably" "should we document it now before we forget?" "Okay" "um, do you want to do it? I could do it for you after I'm done with my tasks if you need help" "okay, you do it"
whoosh hint not taken. It's not rare either since the stereotype of socially awkward literal engineers is not entirely undeserved.
Just tell them, "... You should document this in team wiki before we merge this."
It was good because documentation was tied to the source control and easy to locate and read when you were working on the project.
It's easy that wiki's become neglected and forgotten if there's not someone that "cracks the whip" so to speak so I think any way to lessen the friction and bring it into the coding environment is a good one
Particularly well-explained code shouldn't raise any questions.
Another thread could have modified ‘x’ between when we test the condition and when we take the lock, so we should test that ‘x’ is ‘NULL’ if ‘y’ is true here, and if not, sleep and retry.
I'm not sure how to apply it in all cases though. Frequently the issues I see are coding standard violations... use of exceptions, bad use of virtual or function pointers, ...
How do you say 'we dont use throw here' as a question?
And there are lots of reasons why not to use virtual functions or function pointers, but aside from 'it kills performance if used too much', they're fairly subtle. But really, the issue is typically with something like this the solution is 'rewrite it', which is brutal no matter how you phrase it.
Something like a period of pair programming/mentorship might ease the transition (we only do code reviews on new hires), but it's tough to justify.
If they really need dynamic dispatch, we prefer using an enum because of serialization, efficient sorting by type, code readability (this is debatable), etc., but really even this isn't what we want, because most of the time we don't need dynamic dispatch. Doing this wrong in one place is unlikely to be a huge deal, but if we can't trust them to write code that performs well... it's bad.
If they say yes you could start getting more specific - "does this bit of code match our coding standards for exceptions?"
I would add that it is not only useful to phrase your criticism as a question, it is also useful to try to think through the possible answers, because there may be a logical one.
Doing this can save a lot of embarrassment as well; it can be a rotten feeling to give a harsh assertive criticism, only to find out that you were completely incorrect (not that has ever happened to me!).
> This method should not be static.
I would say
> I think this method should not be static.
I will also follow up with a reason. For example:-
* I think this method should be static as this class is instatiable.
Whether I give a reason or not depends on the experience of the person whose work I am reviewing.
A fellow co-worker taught me by example to try to always phrase each code review comment as a question.
Instead of
> This loop never terminates
Write
> Does this loop terminate?
Instead of
> There's no test for this condition
write
> Is there supposed to be a test for this condition?
I'm probably not thinking of good examples but for some reason, more often than not, the direct comments came across as "you screwed up!" where as the questions instead made it feel like I was discovering my own mistakes rather than have someone tell me I made one.
It's probably subtle and maybe some people will think it's dumb but I really appreciated it. It felt like it went a long way toward me feeling like saw my own mistake and fixed it before I checked it in instead of the direct approach which made me feel stupid and embarrassed.
I've tried to adopt that approach (though it's a struggle to remember to apply it).