January 16, 2008

Baseball cards as objects - The rest of the checklist

Yesterday I started creating an object model for baseball cards. I started with just the 1968 Topps set, going through the checklist to see how the model holds up. Each time it failed I made a change to the model to fix it.

The first mistake I made was not defining a use case for the baseball card objects. I think it was subtly implied, but as we all know, bugs feed on implications. So, at Kevin and Bob's suggestion, I'll actually define the use case I had in my mind as I worked on yesterday's entry. I'll use a simplified template for my use cases, more of a "user story" type format.

The use case

Name: Add baseball cards from 1968 Topps set
Goal: Allow the user to add baseball card definitions to a database of the 1968 Topps set.
Story: The user would like to add a card to the database for the 1968 Topps baseball card set. If the card is a duplicate it notifies the user and allows him to overwrite the existing card. Alternatively, if the duplicate is a variation on the existing card, the user can describe the variation which will show up as a different card on any generated reports.

Just like in any project, a use case or story sometimes needs fine tuning. I appreciate any comments or suggestions on the above use case. As this series of entries continues, there will be higher level stories introduced. Right now I have an overarching vision of what I want to do with my baseball card database, but I'm going to artificially limit the stories until later.

Bob blogged about my last entry and brought up a couple of other interesting points. First of all, he's mirroring the code in Ruby. Hopefully when I end up sticking a database behind the code, he'll show how to do it with a Rails application.

Bob's first question is related to the use case. He asks whether I will be searching through stats, or just searching for cards. Initially, I just want to search for cards. If stats were the goal, it would probably be easier to link the players to their entry at baseball-reference.com. Having said that, there are possible future use cases for wanting to look up some meta-statistics related to the text on the cards. I'll touch on some of this later when I talk about card misprints and their representation. So, the simple answer right now is that I want to be able to identify each card in the set uniquely so we can ignore any statistical information for now.

The second thing Bob did in his Ruby implementation was subclass the Batting Leaders card. I would be the "Domain Expert" here, and I can see in the future that subclassing each card type based on its subject matter might not be the best approach. It's probably a too narrow approach. For instance, in the 1968 set there are only two "Batting Leaders" cards, one for the National League and one for the American League. There are ten total "Leaders" type cards that follow the same template as the "Batting Leaders" cards (e.g., "RBI Leaders", "Home Run Leaders", etc.). As we go down the checklist further we'll find that there are other templates to consider, and I think they all may fit into the object model we ended with yesterday, but we'll go through that in a sec.

One last thing that I notice that Bob did was include the year as a field within the card class. I was going to go over this when we were satisfied that our model would accommodate the 1968 set, and then move on to another set. So, I'm going to defer considering this and other things like the manufacturer's name until later.

Besides the use case, another thing that I haven't done is write test cases for the code, or use JUnit Factory to generate tests for me. Once I get through the 1968 checklist, I'll generate the tests and go over the results.

We've made it through the first ten cards, and found a few problems with our original assertions about the model for a baseball card. Let's go through the rest of the checklist and see if we can spot anything else that doesn't fit our current model.

The next card type that looks slightly different than what we've seen before is card #16, the Cleveland Indians Rookies card that has Lou Piniella and Richie Scheinblum. It resembles the "Leaders" type cards we discussed last time. On the front are two players. At the top of the card is a circle with their team name in it, and the text "1968 Rookie Stars". On the back are the card number, some text that says "1968 Indians Rookie Stars", then some trivia text about each player and their stat line for the year. So, the "Rookie" cards fit fine in the model we've currently constructed. We can attach each of the players to the card object and use the description field to hold the "1968 Rookie Stars" text.

1968_16.jpg

We get all the way to card #67 before we see a new card type, a checklist. In 1968, Topps released the set in seven different series. Each series had a checklist of the players contained in it. The front of the checklist has "Topps Baseball" across the top. There's a picture of a selected player in a circle under that, and next to the picture is text identifying which series it's a checklist for. The rest of the card is covered with the names of all the players in that series with checkboxes next to them.

1968_67_front.jpg

Again, this seems to fit in the model. We can associate the player in the picture with the card, and use the text describing the series this is a checklist for in the description. If we wanted to, we could also associate all of the players on the checklist to the card.

We're about 1/10th of the way through the set, and we're feeling pretty comfortable with the minimal object model we've set up for our 1968 Topps set. There are a few more different card types coming up, and I want to talk about the trade-offs involved with using the description field as a catch-all for the different types we're encountering.

This entry is getting pretty long, so I'm going to stop here for now. Tomorrow, I'll talk about testing the code we've got, and try to get through some more of the checklist.

Comments closed due to comment spam Posted by Rob at January 16, 2008 08:37 PM
Comments

Rob, I'd suggest giving at least one of your higher level use cases so that you have a reason to be adding cards to a unique collection. The "add a card" use case is clearly a sub-use case of some other... and I'm very curious to learn what! :)

Posted by: Jeffrey Fredrick at January 17, 2008 06:01 AM

There needs to be a book called 'Classic Mistakes in Agile Planning'. The first chapter would be 'Why "put all the data in the database" is not a story'.

Rob - when we spoke yesterday, you mentioned 'I want to compare my cards with my buddy and see if you have any duplicates'. That would be a much better story.

Here's a stab at generalizing that story a little and making it actionable:

Given: I have a large collection of baseball cards.
When: Someone gives me a new card,
Then: I want to see if I already have it.

Posted by: Kevin at January 17, 2008 12:10 PM