Monday, June 25, 2012

Creating a real-time, collaborative, responsive retrospective app for agile teams in 30 minutes


Responsive web design term is related to the concept of developing a website design in a manner, that helps the lay out to get changed according to the user’s computer screen resolution. More precisely, the concept allows for an advanced 4 column layout 1292 pixels wide, on a 1025 pixel  width screen, that auto-simplifies into 2 columns. Also it suitably fixes on the smartphone and computer tablet screen.

SignalR is an Async library for .NET to help build real-time, multi-user interactive web applications
LESS extends CSS with dynamic behavior such as variables, mixins, operations and functions. LESS runs on both the client-side (Chrome, Safari, Firefox) and server-side, with Node.js and Rhino.
In this article, we’ll create a simple retrospective app using Responsive web design techniques, CSS3, LESS and SignalR that will allow multiple collaborators to review the same article in real-time.
1. Creating the html page.
Use the Less stylesheet language for creating the CSS for the website. you can download the less.js files from http://lesscss.org/ that is used in this article. You can define variables and classes using Less and then use them in the CSS files as:
@backgroundColor: #E6E6E6;
body {
       background-color: @backgroundColor;
}
.shadow(@borderColor)
{
       -moz-box-shadow: 3px 3px 4px @borderColor;
       -webkit-box-shadow: 3px 3px 4px @borderColor;
       box-shadow: 3px 3px 4px @borderColor;
}

.goodDataContent
{
       .dataContent;
       .shadow(@goodBorderColor);
       background-color: @goodDataBackgroundColor;
       margin-left: 50px;
}

2. Using media queries to render CSS based on screen preferences
Media queries are an excellent way to deliver different styles to different devices, providing the best experience for each type of user. A part of the CSS3 specification, media queries expand the role of the media attribute that controls how your styles are applied. For .e.g. in our app I have defined the image size and size of the contents by using media-queries as given below.
@media all and (max-width: 700), (max-height: 500)
{
       .goodImageContent
       {
              .imageContent(72);
              background-image:url(Images/good_78x78.png);
       }

       .badImageContent
       {
              .imageContent(72);
              background-image:url(Images/bad_72x72.png);
       }

       .betterImageContent
       {
              .imageContent(72);
              background-image:url(Images/idea_72x72.png);
       }

}

3. Creating the Retrospective manger Hub.
Hubs provide a higher level RPC framework over a PersistentConnection. If you have different types of messages that you want to send between server and client then hubs is recommended so you don't have to do your own dispatching.
To get started using Hubs, create a class that derives from Hub.
[HubName("retrospectiveManager")]
public class RetrospectiveManager : Hub
{
    [HubMethodName("newCharEntry")]
    public void RegisterNewChar(string data, string content, string teamId, string browserIp)
    {
        switch (content)
        {
            case "Good":
                Clients.addGood(data, teamId, browserIp);
                break;
            case "Bad":
                Clients.addBad(data, teamId, browserIp);
                break;
            case "Better":
                Clients.addBetter(data, teamId, browserIp);
                break;
            default:
                Clients.addMessage(data, teamId, browserIp);
                break;
        }
    }
}

Our hub receives messages via the RegisterNewChar method and broadcasts the data to addGood, addBad methods.
4. Using connections
Create a connection between the client and the server. When the connection has been started, we want to call the join method on the server.
retro = $.connection.retrospectiveManager;

$.connection.hub.start({ transport: 'auto' }, null);

retro.addGood = function (data, team, id) {
    if (browserId != id && teamId == team) {
        $('#goodDataContentDiv').html(data);
    }
};

5. HTML for the page
<div>
    <div class="sectionContent">
        <div class="goodImageContent">
        div>
        <div class="goodDataContent" contenteditable="true" accesskey="G" id="goodDataContentDiv"
            onkeyup="sendGoodChar()">
            What went well in this sprint?
            <br />
            1. 
        div>
    div>
    <div class="sectionContent">
        <div class="badImageContent">
        div>
        <div class="badDataContent" contenteditable="true" accesskey="B" id="badDataContentDiv"
            onkeyup="sendBadChar()">
            What didn't go well in this sprint?
            <br />
            1. 
        div>
    div>
    <div class="sectionContent">
        <div class="betterImageContent">
        div>
        <div class="betterDataContent" contenteditable="true" accesskey="I" id="betterDataContentDiv"
            onkeyup="sendBetterChar()">
            What can we do better next time?
            <br />
            1. 
        div>
    div>
div>

I have provided the app as free for distributed teams to use. You can use the app from the URL http://freeapps.agilecockpit.com/Retrospective.aspx. Use the teamId as the querystring for similar teams so that the teams with the same id can view data from other team members.
For e.g. you can use any number as a team id and share it with other team members and start using it like http://freeapps.agilecockpit.com/Retrospective.aspx?teamId=22

Screen shots:

2 comments:

vikram kapoor said...

Great! Put it up on Cockpit!

Seabiscuit said...

Great App Prajeesh.....