Instant PlanningPoker on socket.io

    Motivation


    Once, during the freezing winter season, during the next planning meeting at work, where everyone used his own voting tool - paper cards, all kinds of phone applications , etc - I was struck by the thought - why should everyone sit in the same room when planning can be done from their workers places, or even from home.

    So the idea is to make a remote planning service using the Planning Poker technique so popular in the agile world. And also a little better to understand how socket.io and related technologies work.


    Formulation of the problem


    Develop a page by going to which the user enters his name and "room", then one of the users sets the problem under discussion, everyone votes - when the last of the group voted - the cards open.

    The first attempt to implement the protocol


    So having read this article - the first thought: the browser is a thin client, all the logic and state is stored on the server as soon as a new client is connected to a certain room - the server sends everyone a new snapshot of the room’s state. This also happens when customers vote, change the topic of discussion, etc.

    However, this approach requires some kind of storage on the server (I wanted to avoid using the database, since I wanted to host the project as free as possible). As an option, store the state in memory - an array or some complex object, but this is fraught with memory leaks.

    Second and final implementation


    The second approach to solving the problem was to make each individual client responsible for storing their own state and exchanging states with all participants. If we ignore socket.io, then the protocol can be explained as follows - polite people in a dark room:
    • when someone enters join- he announces this and calls his name - in response, all the other people in the room call their names and conditions.
    • when someone calls his (updated) state update, everyone in the room remembers him.
    • when someone leaves the room leave, the server informs all other participants about this and they safely forget about it.

    the last paragraph does not fit into the rules of politeness - since the client cannot notify everyone about his disconnection, this function had to be assigned to the server - it is the server that is responsible for informing others about the departure of one of the participants:

     socket.on('disconnect', function () {
            var rooms = that.__io.sockets.manager.roomClients[socket.id];
            for(var room in rooms) {
              if ((room != '') && (rooms[room])) {
                /*removing a slash*/
                room = room.substring(1);
                that.__io.sockets.in(room).emit('leave', { room : room, id : socket.id });
           }
         }
      });
    


    Separately, it is necessary to mention the support of rooms in socket.io, which is not mentioned on official. site. I got a lot of information from here . By and large, there is a certain logical way to separate all the clients connected to the server.
    You can only enter the room or leave it from the server side, at the same time you can be in several rooms:

    socket.join('room');
    socket.leave('room');
    


    The rest of the north - just proxies messages between clients in the same room. The only "business logic" on the server is the restriction on entry to rooms for up to 12 people. For example, forwarding the update message in the north looks like this:

      /*sending update*/
      socket.on('update', function (data) {
        /*notify everyone*/
        data = that.identify(data, socket);
        that.__io.sockets.in(data.room).emit('update', data);
      });
    


    Client

    All the logic we have is happening on the client. He is responsible for voting the client (card selection), decides when to show the cards of the other participants, discards votes when the topic changes and / or new people come. The client also publishes events - this is done in order to separate the client’s business logic from the actual manipulations with the DOM, etc. It looks like this:

    client.on('reveal', function(){
        $('.flippable').each(function(i, val) {
              setTimeout(function(){
                $(val).addClass('flipped');
            }, i*50);
        });
      });
    


    Conclusion and Demonstration


    In conclusion, I want to say that, although this approach has not proved to be bad, it is not without drawbacks - i.e. it is possible to get into the client’s logic and thus disrupt synchronization by participants. Also, voices arrive immediately as soon as someone voted, they are just not visible until everyone has voted, but with the sly manipulations in Firebug you can peep the voices of others.

    As a development, you can implement the calculation of the maximum, minimum and average values ​​of the cards, as well as implement a simple chat between people in the room - to discuss topics.

    as it turned out at the very last moment Heroku does not support websockets, and I had to roll to long polling - therefore, the demo offered to you- deprived of one important opportunity - the client will not know in time that one of the participants has disconnected, this event does not occur. For a full familiarization, I suggest you clone this repository on Github and run it on the local machine, the server script does a check on Heroku and, not finding it, works as usual with websockets. Also, for full testing you will need 2 or more participants.

    Good luck

    Also popular now: