MongoDB with Spring Data – Awesome combination for a social game

In my previous post “Considerations for choosing or not choosing MongoDB” I covered some pros and cons of choosing MongoDB as a primary storage for your project. Today I’m going to demonstrate how MongoDB and Spring Data can be applied to development of a social game, extremely simplifying the development and providing really outstanding results.

Please note, that this article would in fact fit any solution which is similar in data access pattern to a social game. I’ll be discussing more details on this matter in the next section.

What is a social game?

A social game is basically a type of online game where players mostly interact with their own game areas(e.g. player’s farm) and use a social network in order share their achievements and ask friends for help. So the most common data access pattern in the game is retrieving or updating data by some kind of user identifier. Here are the key requirements which any typical social game would have to meet:

  1. Most optimal performance for the common data access operations(players don’t like to wait);
  2. Horizontal scaling is a must because you will need to get quite a lot of users before your game starts making profit;
  3. At some point you would definitely need add some analytics and more sophisticated features(e.g. showing top 5 players in the neighbourhood);
  4. Rapid prototype development and ability to add new features quickly(i.e. minimizing time to market and applying “fail fast” principal).

Domain Model

Any program written in object oriented language contains domain model classes which represent the domain of the problem the application is meant to solve. In our particular case we are going to review the domain model of our social game. Here is the class diagram build by IntelijjIDEA:

social_game_classes_diagramAs far as you can see, the root of our class hierarchy is UserModel which in addition to its fields-primitives contains a list of Achievements and a reference to UserFarm object. A instance of UserFarm would then contain a reference to its coordinates, a list of buildings and some other fields. The last detail worth noticing is that UserFarm contains a list Building objects which might be both instances of Building as well as instances of CropsBuilding.

You can find the exact classes by the following link in a GitHub repo.

How it might look in the relational world.

Before I show you how MongoDB and SpringData can be used for persistence of our domain model, let’s dive into the world of relational databases, and see how our ER diagram would look like. Here it goes:

social_game_er_diagramAs far as you can see, there are 6 tables in this model. Whenever a new user registers you will need to fill them with new rows, and then select all the data on each user’s visit and then update certain rows after game activities. Even having ORM and caching in place won’t protect you from possible performance/scalability issues, and all the time you would spend fighting for performance and re-designing your ER schema could be spent on new features and user experience improvements.

Spring Data and MongoDB in Action

Setting up Spring Data for MongoDB in your project is quite simple and can be done as follows:

1) Add dependencies on Spring, Mongo Java Driver and Spring Data MongoDB into your project. (See the sample pom.xml)

2) Create your DAO interface and extend Spring Data’s CrudRepository interface. You won’t even need to implement your DAO because Spring will generate an implementation in runtime.

3) Add a Spring configuration class looking like this:

@Configuration
@EnableMongoRepositories(basePackages = "org.simple.farm.dao")
@ComponentScan("org.simple.farm.dao")
public class SimpleFarmConfiguration {

    @Bean
    public MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(new Mongo(), "farm");
    }

    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
        return mongoTemplate;

    }
}

Now you are ready to save/find your data in MongoDB. Here is some code which would insert a new user into DB:

final String username = "testUserName";
UserFarm userFarm = UserFarmBuilder.createFarmBuilder("Test Farm", 15, 15).
        setResources(90, 130, 150).addCropsBuilding(1, 0, 0, new Date()).
        addSimpleBuilding(Building.BuildingType.SCARE_CROW, 1, 1, 1).build();
userDao.save(UserModelBuilder.createUserBuilder(username, "a password", new Date())
        .setFarm(userFarm).setExperience(0).addAchievement(Achievement.AchievementType.BUILDER, 1)
        .build());

The result of execution can be verified from the Mongo Shell:


> db.userModel.findOne()
{
	"_id" : ObjectId("513b6e1c84ae21612fafe599"),
	"_class" : "org.simple.farm.model.UserModel",
	"login" : "testUserName",
	"password" : "a password",
	"registered" : ISODate("2013-03-09T17:15:08.515Z"),
	"achievements" : [
		{
			"type" : "BUILDER",
			"level" : 1
		}
	],
	"experience" : NumberLong(0),
	"farm" : {
		"name" : "Test Farm",
		"location" : {
			"x" : 15,
			"y" : 15
		},
		"level" : 1,
		"food" : 90,
		"stone" : 130,
		"wood" : 150,
		"buildings" : [
			{
				"lastHarvest" : ISODate("2013-03-09T17:15:08.513Z"),
				"inFarmLocation" : {
					"x" : 0,
					"y" : 0
				},
				"level" : 1,
				"type" : "CROPS",
				"_class" : "org.simple.farm.model.embedded.CropsBuilding"
			},
			{
				"inFarmLocation" : {
					"x" : 1,
					"y" : 1
				},
				"level" : 1,
				"type" : "SCARE_CROW"
			}
		]
	}
}

Full source code of this example can be found in the GitHub repo.

As far as you can see, the persistence of your domain model has never been so easy. Nested arrays and objects fit perfectly into Mongo and Spring Data removes any need in manually creating DBObjects and allows to focus on your business requirements in the first place.

Other advantages of MongoDB

Besides easiness in development of simple CRUD operations for your domain objects, there are certain features of MongoDB which can turn out to be quite handy:

  1. Easy schema migrations. Since your objects are not just arrays of bytes to DB, you can use the power of MongoDB querying facility while writing DB-migration scripts.
  2. Geospatial Idexes can be quite useful in order to find neighbours of a player.
  3. Aggregation Framework is nice for ad-hoc analytics which otherwise would require setting up an RDBMS to run your queries on.

Summary

If you have read this far you can see why I said that Spring Data and MongoDB can be an awesome combination for certain types of applications. Hope you enjoyed the reading!

One thought on “MongoDB with Spring Data – Awesome combination for a social game

  1. Pingback: Java ORMs for MongoDB | Tech Realm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s