2

Then it came the moment to implement some sort of achievement in our web application. I had an idea more or less like the hierarcy described in this question How to implement an achievement system in RoR .

The application we are working on is a software as a service intended to be managed externally without software developers. The thing is it should be possible to create new kinds of achievements runtime by the software administrator via the web interface. The hierarcy then becomes a wall.

I have read somewhere it is possible to implement this situation through finite state machines, but at this time i don't have enough informations about that topic.

Edit: specific question

I thought about modeling an achievement class with a list of conditions to be met. This basic class Achievement would have a boolean which recursively checks all the conditions to be valid. The conditions then could be hardcoded classes. The system admin then creates new kind of achievements with combinations of the atomic conditions.

My fear is the growing number of classes for the atomic conditions. I dont want to have 30+ condition classes in the project. Any advise is really appreciated.

Edit: more details about the implementation

From SpyrosP response, it seems a good idea to build the described DSL. In some way achievements then must be saved in the database. Keeping the same example:

comments :less_than => 10
check_comments
comments :more_or_equal => 100
award_hundred_comments_badge 

In order to dinamically create achievements there should be a table that stores the condition(s) to be checked:

Achievement
| id | name                |
| 1  | "Houndred Comments" |

Condition
| achievement_id | expression             |  
| 1              | some sort of condition |
Community
  • 1
  • 1
Andrea
  • 436
  • 1
  • 5
  • 12
  • StackOverflow is for specific programming questions with a clear answer. This one is pretty subjective. – Almo Feb 27 '12 at 16:23

1 Answers1

1

I've been interested in the same idea and was reading different stuff some time ago. Probably the best way to do such a thing is by using observers. An observer is like a standard filter(before_filter and the likes), but with some differences, like how the return value is handled and so on.

That said, if your system is really really complex, you may want to use a state machine plugin like https://github.com/pluginaweek/state_machine . However, i feel that this is too much for an Achievements functionality.

If i had to face complex Achiement scenarios, i would probably create a simple DSL that defines the behavior of an achievement. Something like :

for_achievement :hundred_comments do
  before_achievement :status => Comment, :lower_than => 100
  after_achievement :status => Comment, :more_or_equals => 100
end

You get the idea. This would be a way to fully describe an achievement. Your observers would then be able to use your achievement.rb class scenarios, in order to make out whether an achievement was reached. Think of it the way CanCan works. This could also be a nice way for your administrators to write simple achievement requirements through an even simpler DSL than what i presented in my example above.

Hope that helps a bit, or at least gives you some ideas :)

EDIT : Simpler DSL

A DSL can be really simple and expressive, so that people may even like to write scenarios with. Something like :

comments :less_than => 10
check_comments
comments :more_or_equal => 100
award_hundred_comments_badge

This can easily be formed to be a valid scenario of achieving 100 comments. Let's think of a scenario where the user gets a badge if he has invited exactly 10 people who are women in gender.

invites :less_than => 10, gender :female
check_invites
invites :equals => 10, gender :female
award_women_invitations_badge

Now, i think that this is very simple to write even for admins who have no clue about ruby, if you explain to them basic stuff about the DSL. But if you do not want them to go into that, you can create a form like :

Action Dropdown => [Comment, Invite, Post, ....]
Condition => [Equal, Less Than, More Than, ....]
Condition_Value => (TextBox to write value to)
CheckCondition => [Check Invitation Count, Check Messages Count, ....]
Spyros
  • 46,820
  • 25
  • 86
  • 129
  • Thank you for your answer. I really like your idea and I think it is a fantastic way to express standard achievements. I dont think they are viable to be created via the web interface though, what do you think? – Andrea Feb 27 '12 at 17:11
  • That mostly depends on the way you create the DSL for it. Since the administrators don't have a clue about ruby, you can either make the DSL very close to plain english, or even better, generate the code for them via a simple form. Think of it like having a dropdown list for requirements in english and when your admin selects the requirements, you just pile it up and create the DSL scenario. I edit my question, to present an even simpler DSL that your admins may even find amusing to write :) – Spyros Feb 27 '12 at 17:26
  • I was unable to access the internet, sorry for the missed response. I think the DSL is a great way to help the developers express these acheivements. I am still wondering about the implementation of this idea. These new achievements, e.g. created from a web interface, are going to be stored into the db. Which is the best way to achieve that in your opinion? I mean, in some way, database columns needs to be saved. I am editing again my question to be more clear – Andrea Feb 28 '12 at 11:18
  • I still have an opaque idea of the implementation of the "condition" columns. it should have some sort of reflection to other models. Do you have any idea about this? – Andrea Feb 28 '12 at 11:32
  • What i would do is directly correlate a condition column with a specific property of my program. For instance, the condition 'Check Invitation Count' directly refers to Invitation.count, in rails terms. – Spyros Feb 28 '12 at 15:05
  • Ok. As im quite newbie in ruby dev, im asking you something about the possible implementation of the DSL. Shall I start writing a module? Can you suggest some good practices to start this? I had a look to other gems implementations but i still don't catch the clue. Thank you very much Spyros – Andrea Feb 29 '12 at 09:55
  • It's actually quite amusing and pretty easy and a nice way to dive into some metaprogramming as well. A module would best suit this yes. For some nice information, please take a look here http://drasticcode.com/2009/8/3/writing-domain-specific-languages-dsls-with-ruby and here http://rubylearning.com/blog/2011/10/02/do-you-know-how-to-write-an-internal-dsl-in-ruby/ – Spyros Feb 29 '12 at 17:03