-
Notifications
You must be signed in to change notification settings - Fork 19
Java: add guidelines for using assertions #37 #38
Conversation
86176ba
to
e14f5b1
Compare
v1@damithc submitted v1 for review. Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/1/head:BRANCHNAME where |
@@ -0,0 +1,98 @@ | |||
# Additional Guidelines - Java | |||
|
|||
## Argument validation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find a good reference for this section, so had to cook up my own guidelines. Do review with a very critical mind.
``` | ||
|
||
Furthermore, place the argument validation code immediately above the first line of code it tries to defend, so that | ||
the reader can easily deduce the reason for argument validation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always thought to validate early, if at all, to avoid unnecessary processing if it's gonna fail anyway.
Surprisingly, despite searching for the past half hour or so, I couldn't find an authoritative guide.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed @acjh , validating arguments upfront seems like the natural thing to do and I used to do it that way too. However, now that the decision to validate depends on a specific circumstances in the code, it seems safer to put the validation near the 'reason for validation' so that if the 'reason for validation' changes, the validation code too can be changed accordingly. For example, if the 'reason for validation' code is extracted to another method, the validation code can go with it. But I don't feel strongly about it; it's just something I cooked up (and yes, I too could not find a good reference to derive from).
Sorry for the delay. I'll give a review by tomorrow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just two minor items.
There are a handful of coding style violations though, all revolving missing whitespace:
- Between
)
and{
- Between
if
and(
``` | ||
|
||
In the example below, `key` need not be validated against `null` because a `null` value is going to create a | ||
detectable failure (i.e. a `NullPointerException`) anyway. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this may be accurate,
NullPointerException
is a special case; most developers would try their best to avoid this at all costs rather than "letting it happen and catching it somewhere".- It also depends on the method signature; if the method is designed to "return null/false if the argument is null", then this explanation will not apply anymore.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NullPointerException is a special case; most developers would try their best to avoid this at all costs rather than "letting it happen and catching it somewhere".
That's true. I think 'avoid the NPE at all costs' aspect is addressed by the new Optional
feature to some extent. Assuming asserts are being used to identify programmer errors while testing (i.e. they are not enabled in production -- java doesn't have a way to enable asserts when run from an executable jar file), our objective is to identify programmer errors and the choice in this example is between an assertion failure and an NPE. Assertion failure cost us an extra line of code and (i.e. assert key != null
) and tells us precisely what parameter is null. NPE happens in the same method, but slightly harder to trace back to the offending parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our objective is to identify programmer errors and the choice in this example is between an assertion failure and an NPE. Assertion failure cost us an extra line of code and (i.e. assert key != null) and tells us precisely what parameter is null. NPE happens in the same method, but slightly harder to trace back to the offending parameter.
Java 7 and above actually has an Objects::requireNonNull()
method which might be useful in this regard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Java 7 and above actually has an Objects::requireNonNull() method which might be useful in this regard.
Didn't know such a thing existed :-p But it's not a replacement for assert? Probably it's more useful when we want to have argument checking in public APIs where asserts are not recommended.
Another related feature that might be relevant is annotations https://blogs.oracle.com/java-platform-group/entry/java_8_s_new_type Unfortunately, it's not supported in the standard jdk though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just realized my comments above are not correct. I mixed up assertions (covered in a different guideline) with argument validation covered in this section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@damithc what is the standard for this case if I want to throw a NullPointerException
with a custom error message (to help debugging)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@damithc what is the standard for this case if I want to throw a NullPointerException with a custom error message (to help debugging)?
In that case we can use something like Objects#requireNonNull(Object o, String message)
?
|
||
```java | ||
void setName(String name){ | ||
this.saveName(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not directly related to the guideline, but do we have an agreement on usage of this
? I always thought that unless absolutely necessary (like this.name = name;
), this
should always be dropped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll create a separate issue for it. Will remove this.
from here.
e14f5b1
to
8f78d58
Compare
v2@damithc submitted v2 for review. (📚 Archive) (📈 Interdiff between v1 and v2) Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/2/head:BRANCHNAME where |
Please ignore v2. I missed some review comments. |
8f78d58
to
0d0a027
Compare
v3@damithc submitted v3 for review. (📚 Archive) (📈 Interdiff between v2 and v3) Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/3/head:BRANCHNAME where |
V2+V3:
|
The use of asserts in the validation of parameters will result in a generic AssertionError whenever an invalid parameter is passed in. This is not desirable as assertions should not be used for parameter validation. It should be enforced by explict checks that throw specific exceptions. Let's modify all methods in the Commons package that uses exception to follow this new rule See: oss-generic/process#38
The use of asserts in the validation of parameters will result in a generic AssertionError whenever an invalid parameter is passed in. This is not desirable as assertions should not be used for parameter validation. It should be enforced by explict checks that throw specific exceptions. Let's modify all methods in the Commons package that uses exception to follow this new rule See: oss-generic/process#38
The use of asserts in the validation of parameters will result in a generic AssertionError whenever an invalid parameter is passed in. This is not desirable as assertions should not be used for parameter validation. It should be enforced by explict checks that throw specific exceptions. Let's modify all methods in the Commons package that uses exception to follow this new rule See: oss-generic/process#38
0d0a027
to
91d71d9
Compare
v4@damithc submitted v4 for review. (📚 Archive) (📈 Interdiff between v3 and v4) Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/4/head:BRANCHNAME where |
v4: Removed guidelines on argument validation as they are not stable yet. Assertion guidelines are more stable and can be merged sooner. Argument validation is to be discussed in #71 |
Any more comments about this? If not, i'll be merging soon. |
|
||
Refer the article | ||
_[Programming With Assertions](http://docs.oracle.com/javase/7/docs/technotes/guides/language/assert.html)_ | ||
(from Oracle) for more details on the three general guidelines below. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- "Refer
to
the article" - Should we be linking .../javase/
8
/docs/... instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will update as suggested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@damithc The first point not corrected in v5?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, missed that. Will correct in next iteration.
@@ -0,0 +1,44 @@ | |||
# Additional Guidelines - Java | |||
|
|||
## Using assertions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on this which we are going to adopt soon, headings should be sentence case. Keep this in sentence case and revise coding standards docs later to match the guideline?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
91d71d9
to
b6fdb40
Compare
v5@damithc submitted v5 for review. (📚 Archive) (📈 Interdiff between v4 and v5) Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/5/head:BRANCHNAME where |
v5: changed link from java 7 documentation to java 8 documentation |
We have a Java coding standard to specify syntax level guidelines. Higher level guidelines such as when to use assertions are not documented. Let's add a document to specify those additional guidelines for Java. Include in that document guidelines for using assertions.
b6fdb40
to
2eff23e
Compare
v6@damithc submitted v6 for review. (📚 Archive) (📈 Interdiff between v5 and v6) Checkout this PR version locallygit fetch https://github.com/oss-generic/process.git refs/pr/38/6/head:BRANCHNAME where |
Going to merge soon. cc: @pyokagan |
Fixes #37
Fixes #19