Welcome to the second installment of my "Real Coding" series, in which I'm aiming to develop an "enterprise" ranking application in about two weeks, working only for one Pomodoro per day. If you want to read more about the requirements or my motivation for writing this series, make sure to check out the first part of the series.

Where We Left Off

I will do my best to keep each of the posts as separate from the others as possible so that you don't have to read everything way back to get a grasp of what's happening. Having said that, let's take a look at the code that was left after the previous Pomodoro:

To give you some context, this was all written in the last 5 minutes of the previous Pomodoro, so it was not really thought through. Rather, I wanted to get to a starting point for further work.

The design idea that I decided to go with is that all rankings in the application will be aggregates that keep track of the match history and players' ratings.

More Analysis!

Instead of getting straight back to code, I started this Pomodoro by writing down all the application's functionality necessary for making any productive use of the application. The purpose of this little "exercise" is to increase both my and your awareness of what's about to happen next in the project and to get a better perspective on the emerging domain model. In the end, I came up with the following few points:

Log in: Obviously, you can't do much without that.

Join a ranking: Since last time, I decided that you need to "join" a ranking to be able to play matches. It seemed like a better choice if the application was to be used outside of a single company.

Add a match result: Rankings without games make no sense.

Confirm/change the match result: As said before, the players should confirm their wins/losses before any ranking adjustments are made.

View the current standings: I guess that's the whole point of the application.

Whoops, I Coded "For the Future"!

Having already done some extra analysis, I had around 20 minutes left to finally do some "real coding". I started off by removing the MatchIDand PlayerIDclasses, as nicely suggested in a comment by Robert Brautigam. (Thanks, Robert!) Here's an important rule of programming that even the most experienced programmers seem to break fairly often: Do not introduce things that you do not need yet, especially if they are addressing purely technical concerns, like identity in a database.

Too Trivial or Not Too Trivial?

The next thing I set my eyes on was the joinmethod of the Ranking class. I considered testing that for a short while, but eventually, I decided not to. This method seemed to be doing the job and the implementation is trivial, so why bother? Well, just as I was writing that sentence a few seconds ago, I realized that it doesn't do the job well because it doesn't handle the case when someone is already ranked in a given ranking. This method would reset the player's score! I guess I'll start the next Pomodoro by fixing that bug.

Adding a Match. Trivial, Again?

Being entirely convinced that the joining functionality is ready, I set my eyes on adding a match to the ranking. I started off with the simplest possible implementation:

fun addMatch(match: Match) {
matches.add(match)
}

Ha, trivial again! Well, that changed a bit a few minutes later when I realized a possible case of adding a match between players that are not in a given ranking. This made the implementation evolve to:

Since we've got an if statement, with a negation and exception in here, I decided to write a little test for this functionality, especially given that I messed this up a while before. (To be entirely precise, the test was the last thing that I wrote in this Pomodoro, but this order makes more sense from the article's perspective).

If you're not familiar with the assertThrowssyntax, I highly recommend you getting to know JUnit 5, as it's about to become the new standard in Java testing soonish!

Confirming a Result

The last thing that I got a chance to put my hands on during this Pomodoro was the possibility of confirming a previously submitted match result. Obviously, I started off by specifying what the possible results are:

I'm not entirely sure whether this enum is the best way to represent the final score, but it was the first thing that came to my mind, so I went for it. Right now, I'm thinking about changing this to some kind of a numerical score. We'll see.

Also, I decided to ignore the requirement of supporting both solo and team games for now. I'll try to get the application working for solo players and only then focus on supporting teams.

The next step to be taken was to actually mark the match result as confirmed. For this reason, I introduced yet another enum:

To be honest, I hate using enums like this for some reason. It just doesn't feel right. At the same time, there's only so much that can be done in 25 minutes, and this seems to be just good enough for the purpose. Anyway, suggestions for improvement will be highly appreciated!

The last thing that I managed to do in this matter was actually setting the confirmed status of the match. This required me to invent some way of uniquely identifying a match. A natural ID for a match in the application would be the players that participate in the match and the date when the match has taken place. And so I decided to add the dateTimefield to the Match class:

At this point, I could have written a confirmation method that recognizes a match by the three first fields, but I decided not to. My intuition suggested that for some reason, using an artificial identifier will yield a less cumbersome API than passing these three objects everywhere I want to refer to a single match. And so the MatchIDclass was reintroduced:

Final Words

Basically, that's the point when I ran out of time for this session, so that's the code — at least until tomorrow. If you see anymore lurking bugs, missing requirements, or design flaws, please feel free to mention it in the comments. If I don't change my mind and all goes well, the next installment should be pretty exciting, as we're about to recalculate the player ratings after confirming a match result. Stay tuned!

P.S. I uploaded the project to GitHub if anybody's interested in seeing the two source files in their entirety!