integrating translators to the robocode engine

In my latest robocode series I've been exploring a decision making bounded context and have fused together many elements to make this happen. Here's what I've done so far:

  • written acceptance testing and statistics writing for assertions
  • introduced IObservable<IEvent<T>> into my robocode design
  • recognised that I have multiple contexts that I hope can have their own dialect
  • introduced a world state
  • created a decision making bounded context with a state keeper and updater
  • created observer(s) to watch this decision state
  • created a context translator to push world state updates into the decision dialect

It has been quite a lot of code in a few posts (but that's what my blog is mostly about - the finer details of development and shaping code).

I'm now ready to hook the whole thing up and I need my robot engine to activate the context translators when a world state update occurs.
As usual I start with specifications for this class and I'm going to add two new ones into an existing specification:

    public class when_told_to_ensure_the_world_state_is_up_to_date : with_a_robot_engine
    {
        Establish context = () =>
        {
            robotEngine.Initialise(robot);
            expectedGunTemperature = 222;
            worldStateUpdate = w => w.GunTemperature = expectedGunTemperature;
            robotEngine.PublishToTheWorldState(worldStateUpdate);
        };

        Because of = () => robotEngine.EnsureTheWorldStateIsUpToDate();

        It should_update_the_world_state_accordingly = () =>
            worldState.GunTemperature.ShouldEqual(expectedGunTemperature);

        It should_have_no_pending_world_state_updates_left = () =>
            robotEngine.PendingWorldStateUpdates.Count.ShouldEqual(0);

-->     It should_inform_the_first_translator_of_the_world_state_change = () =>
            firstContextTranslator.AssertWasCalled(x => x.PublishAStateChange(worldState));

-->     It should_inform_the_second_translator_of_the_world_state_change = () =>
            secondContextTranslator.AssertWasCalled(x => x.PublishAStateChange(worldState));

        static Action<IWorldState> worldStateUpdate;
        static int expectedGunTemperature;
    }

I've now introduced two new context translators into the specification and when the world state is to be updated I want them informed of this world state change.
The change in the constructor of the robocode engine in my specification is as follows:

        firstContextTranslator = MockRepository.GenerateStub<IContextTranslator>();
        secondContextTranslator = MockRepository.GenerateStub<IContextTranslator>();
        var contextTranslators = new List<IContextTranslator> {firstContextTranslator, 
                                                        secondContextTranslator};
        robotEngine = new RobotEngine(worldState, contextTranslators, statisticsManager);

To implement this there is a new loop in this method in the robot engine:

        public void EnsureTheWorldStateIsUpToDate()
        {
            foreach(var makeAnUpdateTo in pendingWorldStateUpdates)
            {
                makeAnUpdateTo(worldState);
            }
            pendingWorldStateUpdates.RemoveAll(a => true);

            foreach (var contextTranslator in contextTranslators)
            {
                contextTranslator.PublishAStateChange(worldState);
            }
        }

I'm happy with the code so far, but this method above doesn't necessarily scan right and I think this needs addressing.

I'm a huge fan of the Clean Code book by Bob Martin and I'm a proud wearer of the green wristband, (seeking "craftsmanship over crap"!) and at every opportunity I look to make my code intuitive and readable. So with a few simple method extractions I think the above can be made simpler so that when I read it back at a later date, the code is intention revealing.
As you can see I believe this applies as much to experimentation and personal projects as it does to professional code bases in every day work

Here's the end result:

        public void EnsureTheWorldStateIsUpToDate()
        {
            ConsumePendingUpdatesByUpdatingTheWorldState();

            PublishTheWorldStateToTheContextTranslators();
        }

        void ConsumePendingUpdatesByUpdatingTheWorldState()
        {
            foreach(var makeAnUpdateTo in pendingWorldStateUpdates)
            {
                makeAnUpdateTo(worldState);
            }
            pendingWorldStateUpdates.RemoveAll(a => true);
        }

        void PublishTheWorldStateToTheContextTranslators()
        {
            foreach (var contextTranslator in contextTranslators)
            {
                contextTranslator.PublishAStateChange(worldState);
            }
        }

So I'm now ready to run my acceptance tests which will run some battles and ensure that my implementation does what I think it should. The next post will cover this acceptance and debugging exercise.



0 comments: