-
-
Notifications
You must be signed in to change notification settings - Fork 708
robot-simulator: add to track #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@jtigger any idea what I might be doing wrong here? Looks like the first run through of the tests on CI passed, but the second run through failed:
|
Yeah, I can see at least part of it. The journey test constructs a local copy of When I tried to run the script locally, I can't even get it to connect properly to |
Okay, my local issue was unrelated. Since this is a issue, I've committed the fix to I'm entirely unhappy with how hacky this first cut is; it introduces connascence of position when it should be doable with less coupling (i.e. matching exactly on the locked version number in the |
assertTrue(actualEndRobotOrientation.equals(expectedEndOrientation)); | ||
} | ||
|
||
private void testInstructions( |
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.
Hmmmmmmmmmmmm.... so, I get the DRYing up of the tests. But I'm personally apprehensive about trading-off any readability from within a given test. I think this Extract Method is okay, I'll need to sleep on it myself.
What do others think? @exercism/java
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.
@stkent @jtigger in general I like the fact that these helper methods are pulled out, but it does make me squint a little when following the tests. There's definitely a school of thought that says tests should be dead simple, even to the point of eschewing any logic to create data objects programmatically for testing. That camp would prefer to see everything spelled out literally.
I don't have a strong feeling about this either way, but we should just consider the audience. The tests contain a considerable amount of the guidance that the users get, we should make sure they're as useful as possible.
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.
Yes, I went back and forth on this myself (at one point, I had similar helper methods extracted to test the "turn"-type logic, but ended up writing those out explicitly). For consistency and the sake of being super-explicit, I'll go ahead and remove this helper method too!
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.
In a production test suite, I'd personally want to remove the duplication. However, in Exercism, the practitioner is digesting these tests one-at-a-time. As such, it is my belief that explicitness is particularly crucial.
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.
What do you both think of the testTurningRight
and testTurningLeft
methods? I've already removed the testInstructions
method locally.
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.
Personally, I'd inline them.
To come to that conclusion I did this little exercise with myself: I pretended I was seeing this exercise for the first time and just myopically walked through the test methods from the top. When I got to testTurningRightCorrectlyChangesOrientation()
, I had to then jump down to the definition of testTurningRight()
which, on examination, didn't include any more "boilerplate" than other test methods... at which point the whiny pedantic voice in my head said, "why not just include that in the test above?"
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.
Roger that; willfix!
this.y = y; | ||
} | ||
|
||
boolean equals(final GridPosition gridPosition) { |
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.
Can you talk about the decision to overload instead of override equals()
? Not saying it's wrong, just want to talk it through.
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.
Here's what a full implementation of equals
and hashCode
looks like:
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final GridPosition that = (GridPosition) o;
if (x != that.x) return false;
return y == that.y;
}
@Override
public int hashCode() {
int result = x;
result = 31 * result + y;
return result;
}
Since this is a class supplied as part of the starter implementation, my thinking was that the above represented a lot of irrelevant detail a user might think they needed to understand in order to proceed with the problem.
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.
Excellent point. Agreed.
We also want to balance that with the principle that Exercism code should be exemplary.
What do you think of some succinct comment above or within equals()
that include a URL to an accessible description of the rationale behind keeping equals()
and hashCode()
in sync, semantically?
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 think your proposal is a good balance, and will take a stab at it locally with the expectation that we might iterate a couple of times to capture all that needs to be said!
Related-ish: are reference solutions ever exposed to users? I ask in light of this comment (my emphasis):
The reference solution is named something with example or Example in the path.
The solution does not need to be particularly great code, it is only used to verify that the exercise is coherent.
I think that exposing users to exemplary reference solutions should be the norm; just wondering where Exercism as a whole stands on that front?
oh yeah! I forgot that PRs will automatically rebase. Once I re-kicked the build with the fix on |
@stkent another fine effort. I hate to be that guy, but I need to raise one concern: I'm a little hesitant about this and Are commenters able to see multiple files in the UI when reviewing someone's submission? I don't even know the answer to that question. My thought is that going in this direction has both benefits and costs, and warrants some discussion and a decision. What do you think @stkent ? @exercism/java ? |
@matthewmorgan definitely a valid concern, thanks for raising it! I will note that there is a slight difference between the cases you mention:
The latter is a pre-existing pattern used in e.g. As additional context: my first run at Requiring implementation in two separate classes (as in
Yet another task that may depend on #142. Thoughts? |
Regarding:
I'm not sure; it's certainly possible to submit multiple files for a problem, as I recently discovered, but I have not yet inspected such a submission from the other side. |
@jtigger thanks for investigating and addressing that failure! |
@matthewmorgan confirmed, reviewers can see multiple files if they are submitted by the user; however, the CLI info page needs an update to let people know that's permitted! Some submissions therefore include the |
@matthewmorgan (being "that guy" 🙄)
@stkent differentiated between exercises that are supplying multiple classes vs. requiring them. I agree, this is an important concern:
the mechanics can be straight-forward:
|
+1 if a multi-class OO solution fits best, we shouldn't be afraid of that! Regarding:
I see what you're getting at with this, @jtigger, but I wonder if the introduction of the interface here would be more confusing than instructive... |
Another thought: could we include an appropriate (multi-file) CLI submit command for multi-file problems in the appropriate |
@jtigger @matthewmorgan updated, and ready for another look! |
@jtigger @stkent I see that in this case we're supplying the classes required-- that's an oversight on my part, I apologize. I think that's just fine. I also have heard @jtigger that sometimes people use more than one class in a Java application, although personally as a super-programmer I always just use one 😈 I guess I'm with @stkent on the thought of introducing an interface, but I could be convinced that it has real value too. Maybe we should deliberately introduce that at some point. If we did, I think a Anyway, as I said, nice work, I would give this PR a 👍 |
Heathens! |
@matthewmorgan said:
I've heard that about you... :) |
My "argument" is based on seeing the I love the notion of making use of the |
Yes! Validation arises as a Responsibility (invoking SRP, again); I can see how it could be the raison d'être of a Value Object. I dig the notion of "validation" being an aspect of later exercises. But I feel they'll be worthwhile/fun when included as needed. And yeah, #142 is just churning up all kinds of fantastic aspects! :) |
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.
Oh yeah... there's a PR in all there isn't there?!? 😉
Personally, I'm digging the more explicit test methods; feels more approachable — thanks for doing the legwork.
A few suggestions in the review.
this.y = y; | ||
} | ||
|
||
/* |
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.
👍
@@ -0,0 +1,5 @@ | |||
final class Robot { |
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.
Should this class be public
?
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.
Don't think it needs to be; the tests are located in the same package, so package-private access is sufficient for the class and it's exposed methods!
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 see whatcha doin' there. Cool!
|
||
final GridPosition actualGridPosition = robot.getGridPosition(); | ||
|
||
assertTrue(actualGridPosition.equals(initialGridPosition)); |
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.
What are your thoughts on using assertEquals()
? This increases the fidelity of signal from the test system: the programmer can know what's wrong just looking at the failure message.
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 think assertEquals
delegates to the Object
-based equals
implementation, so this test (and others) would fail if I used it. I can add an explicit failure message here as an alternative?
|
||
final Orientation actualOrientation = robot.getOrientation(); | ||
|
||
assertTrue(actualOrientation.equals(initialOrientation)); |
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'm wondering if actualOrientation
is carrying its intention-revealing weight, here. How does this compare with:
@Test
public void testRobotIsCreatedWithCorrectInitialOrientation() {
final Orientation initialOrientation = Orientation.NORTH;
final Robot robot = new Robot(new GridPosition(0, 0), initialOrientation);
assertEquals(robot.getOrientation(), initialOrientation);
}
?
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.
Good call; will fix throughout the tests!
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.
Thanks again for both doing such quality work and enduring nitpicky scrutiny. Another great add to the track!
Test data from here. I omitted "negative positions are allowed" since the
GridPosition
implementation is provided as part of the exercise. Otherwise, all common tests should be present.