Learning Reactive Programming

2016-05-14

After a few months without writing in my blog, this post will be in English. I remember that Peter Kofler suggested me to do so in order to improve my English level. So, today I am writing my first post that is not in Spanish. I know that I will make a lot of mistakes, so If you detect them, please add a comment to give me some feedback ;)

The last few weeks I have been trying Reactive Extensions in .NET. Reactive extensions is a library that matches the LINQ library with the Observer and Observable interfaces. We are able to use the collection’s management operations in observables. I started with this paradigm as a recommendation from my mentor Modesto, because I wanted to discover new ways to solve problems. So, studying unknown paradigms (for me) is great way to get that.

The problem I decided to practise was the RPGCombatKata from Daniel Ojeda. Here is my solution. In my first steps, it was hard for me thinking about events rather than collections. I had already worked with events but I associated filter or concat methods to collections. This confusion made me write a lot of logic in my Character class, having an Observable as if it was a collection of characters (enemies). A complete mess.

After having a code review with Modesto, it seems to be more clear in my head. So, I refactored all my code to have an event oriented implementation. After my talk with Modesto, I have a basic knowledge about how Reactive Extension works. Basically we have the Observable interface but thinking about it as a Stream of T. Mixing streams and observables allows us to subscribe an observer only for an sequence of objects that is the result of applying some LINQ operations in the original one. Let’s imagine we have an Observable. The ProductAdded is an event that contains a Product. We can filter that sequence to add to the shopping car (observer) only those products that are in our Stock (resulting observable).

RPGCOMBAT KATA

Before showing the solution of the RPGCombat Kata itself, this is the EventBus we used:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
namespace RPGCombatKata
{
public static class EventBus
{
private static readonly Subject<object> messageSubject = new Subject<object>();
public static void Send<T>(T message)
{
messageSubject.OnNext(message);
}
public static IObservable<T> AsObservable<T>() {
return messageSubject.OfType<T>();
}
}
}

Having a Subject(A class provided by Reactive Extensions that implements the Observer and Observable interfaces) we can manage messages of any type. With the OnNext method we are calling our subscribers that satisfied the conditions we have defined before for the message object. Our EventBus interface allows us to raise events calling the Send method. We also have the AsObservable method that allows us to filter EventBus’ events by event type with the OfType LINQ’s method.

Let’s see an example of its usage in the GameEngine:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
namespace RPGCombatKata
{
public class GameEngine
{
private readonly RangeCalculator rangeCalculator;
public GameEngine(RangeCalculator rangeCalculator)
{
this.rangeCalculator = rangeCalculator;
SubscribeToAttacks();
SubscribeToHeals();
}
private void SubscribeToHeals()
{
EventBus.AsObservable()
.Where(CharactersArePartners)
.Subscribe(SendLifeIncrement);
}
private void SubscribeToAttacks()
{
EventBus.AsObservable()
.Where(IsInRange)
.Where(IsNotASelfAttack)
.Where(CanSourceAttackToTarget)
.Subscribe(SendDamage);
}
public bool IsASelfHeal(Heal heal)
{
return heal.Target == heal.Healer;
}
public bool CharactersArePartners(Heal heal)
{
return heal.ArePartnersTheInvolvedCharacters();
}
private static void SendLifeIncrement(Heal heal)
{
new LifeIncrement(points: heal.Points, target: heal.Target).Raise();
}
private static bool CanSourceAttackToTarget(Attack attack)
{
return attack.CanSourceAttackToTarget();
}
private bool IsInRange(Attack attack)
{
var distance = ObtainDistanceBetween(attack.Source, attack.Target);
return attack.IsInRange(distance);
}
private int ObtainDistanceBetween(Character attacker, Attackable victim)
{
return rangeCalculator
.CalculateDistanceBetween(attacker, victim);
}
private static bool IsNotASelfAttack(Attack a)
{
return a.Source != a.Target;
}
private static void SendDamage(Attack attack)
{
EventBus.Send(new Damage(attack.Damage, attack.Target));
}
}
}

This solution consists in having a GameEngine that has the base rules of how attacks and heals apply. For example, in the case of attacks we can see that its damage is applied when the victim is within the attacker range, it is not a self attack and the involved characters are enemies. When all of previous conditions are satisfied, the Game Engine will send the damage with another event called Damage. That Damage will be caught by the Attackable type:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
namespace RPGCombatKata
{
public abstract class Attackable
{
private const int InitialLevel = 1;
public decimal Life { get; protected set; }
public decimal Level { get; protected set; }
protected Attackable(decimal life)
{
Life = life;
Level = InitialLevel;
EventBus.AsObservable<Damage>()
.Where(damage => IsItMe(damage.Target))
.Subscribe(damage => ReceiveDamage(damage.Value));
}
protected bool IsItMe(Attackable character)
{
return character == this;
}
public abstract bool IsAttackableBy(Character source);
protected void ReceiveDamage(decimal damage)
{
Life -= damage;
if (NoLife()) Unsubscribe();
}
protected bool NoLife()
{
return Life <= 0;
}
protected virtual void Unsubscribe() {}
}
}

Each attackable object will ask to each raised Damage event if he is the victim. In that case, he will receive that Damage. Really simple! We have two overridable methods here. The IsAttackableBy method is implemented in two different ways. Characters can only be attacked by enemies and houses can be attacked by any character (they are neutral objects in this game). The Unsubscribe method exists because when an attackable has no life, it should not receive more events. For example, a dead character can not be healed. Another advantage of Reactive Extensions is that when you subscribe to an event, the subscribe method returns a Disposable object. So, when you don’t want to receive events, it is as simple as calling the Dispose method. This is my Unsubscribe method for the Character class:

1
2
3
4
protected override void Unsubscribe()
{
healSubscription.Dispose();
}

CONCLUSION

I enjoyed a lot solving this kata with Reactive Programming. Iterations were really simple because events are really scalable. The most attractive thing of this paradigm for me is that you can practically read the rules of your business in a really semantic lines of code. Events allow us to decouple our code because we can execute behaviour reacting to events without establishing a relation between the involved objects. Introducing the kata’s requirements consisted in moving out the subscription to another object or adding a new filter.

I found a problem with the tests because of asynchronous reasons. The problem was that if I create a GameEngine in each test, these instances react to the events raised in other tests too. To fix that I had to have a shared game instance in my tests to react to events only once. I don’t like it, but other solutions make me modify my domain code. I will be really grateful if you share more solutions to this problem ;)

I will study more about this paradigm with other coding katas. For now, I like it very much :D

RESOURCES

Reactive Extensions tutorials