# Monday, 17 January 2011

One can never know as much as a team knows. Learning from others is a wonderful team and individual trait.

Background

About a year ago our team was working on an intranet project. As the lead developer and I discussed the features needed, we decided to handle some tasks on the front end with jQuery. Neither one of us had much experience with jQuery and we had a tight deadline to meet. 

The Bad & The Ugly

Since we were really under the gun we split up the work and I tackled the client side jQuery. Warning – Avert eyes now if you wish not to see be subjected to ugly code!

var Editor1 = '#Editor1';
var Editor1CountLimit = 5000
var Editor1InfoArea = '#Info';

var WhyThisStratArea = '#txtVchWhyThisStrategicArea';
var WhyThisStratAreaCountLimit = 500;
var WhyThisStratAreaInfoArea = '#txtVchWhyThisStrategicAreaInfo';

var ProgramDescriptionArea = '#txtVchProgramDescription';
var ProgramDescriptionAreaCountLimit = 1000;
var ProgramDescriptionAreaInfoArea = '#txtVchProgramDescriptionInfo';

var Activity = '#txtVchActivity';
var ActivityCountLimit = 3000;
var ActivityInfoArea = '#txtVchActivityInfo';

var OtherInfo = '#txtVchOtherInfo';
var OtherInfoCountLimit = 1000;
var OtherInfoArea = '#txtVchOtherInfoInfo';

var OutcomeMandated = '#txtvchOutcomeMandated';
var OutcomeMandatedCountLimit = 1000;
var OutcomeMandatedArea = '#txtvchOutcomeMandatedInfo';

var ServiceLevelMandated = '#txtVchServiceLevelMandated';
var ServiceLevelMandatedCountLimit = 1000;
var ServiceLevelMandatedArea = '#txtVchServiceLevelMandatedInfo';

var ChangeInLevelofService = '#txtvchChangeInLevelofService';
var ChangeInLevelofServiceCountLimit = 1000;
var ChangeInLevelofServiceArea = '#txtvchChangeInLevelofServiceInfo';


$(document).ready(function() {

    ChangeTextOnKeyUp(Editor1, Editor1CountLimit, Editor1InfoArea);

    //change the length when typed in.
    TrackKeyStrokesForTextArea(WhyThisStratArea, WhyThisStratAreaCountLimit, WhyThisStratAreaInfoArea);
    TrackKeyStrokesForTextArea(ProgramDescriptionArea, ProgramDescriptionAreaCountLimit, ProgramDescriptionAreaInfoArea);
    TrackKeyStrokesForTextArea(Activity, ActivityCountLimit, ActivityInfoArea);
    TrackKeyStrokesForTextArea(OtherInfo, OtherInfoCountLimit, OtherInfoArea);
    TrackKeyStrokesForTextArea(OutcomeMandated, OutcomeMandatedCountLimit, OutcomeMandatedArea);
    TrackKeyStrokesForTextArea(ServiceLevelMandated, ServiceLevelMandatedCountLimit, ServiceLevelMandatedArea);
    TrackKeyStrokesForTextArea(ChangeInLevelofService, ChangeInLevelofServiceCountLimit, ChangeInLevelofServiceArea);

    //setup the initial value for a text area...
    $(WhyThisStratAreaInfoArea).html($(WhyThisStratArea).val().length + ' Characters Used');
    $(ProgramDescriptionAreaInfoArea).html($(ProgramDescriptionArea).val().length + ' Characters Used');
    $(ActivityInfoArea).html($(Activity).val().length + ' Characters Used');
    $(OtherInfoArea).html($(OtherInfo).val().length + ' Characters Used');
    $(OutcomeMandatedArea).html($(OutcomeMandated).val().length + ' Characters Used');
    $(ServiceLevelMandatedArea).html($(ServiceLevelMandated).val().length + ' Characters Used');
    $(ChangeInLevelofServiceArea).html($(ChangeInLevelofService).val().length + ' Characters Used');
});

function ChangeTextOnKeyUp(ctl, limit, info) {

    var editor = $(ctl).contents().find('iframe').eq(1);

    $(editor).load(function() {

        //initial load, set value....
        var txt = $(this).contents().find('body').text();
        $(info).html(txt.length + ' Characters Used');

        //watch cut and paste
        $(this).contents().find('body').bind('cut paste', function(e) {
            var el = $(this);
            setTimeout(function() {
                //use a delay to wait for the text to update....
                var txt = $(el).text();
                if (txt.length > limit) {
                    $(info).html(txt.length + ' Characters Used').css("color", "red");
                }
                else {
                    $(info).html(txt.length + ' Characters Used').css("color", "");
                }
            }, 150);
        });

        //watch key up
        $(this).contents().keyup(function() {

            var txt = $(this).contents().find('body').text();

            if (txt.length > limit) {
                $(info).html(txt.length + ' Characters Used').css("color", "red");
            }
            else {
                $(info).html(txt.length + ' Characters Used').css("color", "");
            }
        });

    });

}

function TrackKeyStrokesForTextArea(ctl, limit, info) {
    $(ctl).keyup(function() {
        var txt = $(ctl).val();
        if (txt.length > limit)
            $(info).html(txt.length + ' Characters Used').css("color", "red");
        else
            $(info).html(txt.length + ' Characters Used').css("color", "");
    });

    $(ctl).bind('cut paste', function(e) {
        var el = $(this);
        setTimeout(function() {

            var txt = $(el).val();
            if (txt.length > limit) {
                $(info).html(txt.length + ' Characters Used').css("color", "red");
            }
            else {
                $(info).html(txt.length + ' Characters Used').css("color", "");
            }
        }, 150);
    });
}

function ValidateEditor1Length(source, args) {
    var editor = $(Editor1).contents().find('iframe').eq(1);
    var txt = editor.contents().find('body').text();
    var isValid = txt.length > 0 && txt.length <= Editor1CountLimit;
    args.IsValid = isValid;
}

function ValidateWhyThisStratAreaLength(source, args) {
    var txt = $(WhyThisStratArea).val();
    var isValid = txt.length > 0 && txt.length <= WhyThisStratAreaCountLimit;
    args.IsValid = isValid;
    /*if (!isValid)
        Spellcheck();*/
        
}

function ValidateProgramDescriptionLength(source, args) {
    var txt = $(ProgramDescriptionArea).val();
    var isValid = txt.length > 0 && txt.length <= ProgramDescriptionAreaCountLimit;
    args.IsValid = isValid;
}

function ValidateActivityLength(source, args) {
    var txt = $(Activity).val();
    var isValid = txt.length > 0 && txt.length <= ActivityCountLimit;
    args.IsValid = isValid;
}
function ValidateOtherInfoLength(source, args) {
    var txt = $(OtherInfo).val();
    var isValid = txt.length > 0 && txt.length <= OtherInfoCountLimit;
    args.IsValid = isValid;
}
function ValidateOutcomeMandatedLength(source, args) {
    var txt = $(OutcomeMandated).val();
    var isValid = txt.length > 0 && txt.length <= OutcomeMandatedCountLimit;
    args.IsValid = isValid;
}
function ValidateServiceLevelMandatedLength(source, args) {
    var txt = $(ServiceLevelMandated).val();
    var isValid = txt.length > 0 && txt.length <= ServiceLevelMandatedCountLimit;
    args.IsValid = isValid;
}
function ValidateChangeInLevelofServiceLength(source, args) {
    var txt = $(ChangeInLevelofService).val();
    var isValid = txt.length > 0 && txt.length <= ChangeInLevelofServiceCountLimit;
    args.IsValid = isValid;
}

Ugly!  Oh ya, we’ve all seen it and we’ve all most assuredly done it at least once. :-)

TheBadAndUgly

So what is all this code doing? Basically only three things. It’s setting and tracking the max length allowed in a text area, updating the number of characters typed and showing a message/validating when an entry goes over it’s maximum length.

Why do all this when we can do this with validator controls? We wanted the UI to be more responsive and interactive for the users. We wanted the number of characters along with a warning to the user when they go over the limit before they try to save their work.

Now, I could give every excuse for this horrible looking code. We’ve all been here before.  Not enough time to do it right but we have to get it out the door none-the-less.  I knew the code was bad and could be improved upon.  Still, the code is ugly.

The Good

We had a new team member join our team about four months ago and we happened to be working on this project again.  His jQuery skills brought to bear on this project was just what we needed.

To fix MY monstrosity he created hidden fields tied to the text areas and got rid of the setup variables.  It may sound like we’re swapping one mess for another but it helped greatly in reducing the code needed as well as improved the readability and flow.

<asp:TextBox ID="txtWhyThisStrategicArea" cssClass="spellcheck" runat="server" TextMode="MultiLine"></asp:TextBox>
<input runat="server" type="hidden"  id="txtWhyThisStrategicAreaMaxLength" value="500" />
<input runat="server" type="hidden"  id="txtWhyThisStrategicAreaRequired" value="true" />
// Text field character counter
$('#txtProgramName, #txtWhyThisStrategicArea, #txtContactPerson).each(function () {

    var length = $(this).val().length;
    var limit = $('#' + $(this).attr('id') + 'MaxLength').val();
    var maxInfoArea = $('#' + $(this).attr('id') + 'MaxArea');
    var displayText = ' of ' + limit + '  Characters Used.';

    //set up the initial display
    if (length > limit)
        $(maxInfoArea).html(length + displayText).addClass("warning");
    else
        $(maxInfoArea).html(length + displayText).removeClass("warning");

    //hook the keyup
    $(this).keyup(function () {
        var length = $(this).val().length
        if (length > limit)
            $(maxInfoArea).html(length + displayText).addClass("warning");
        else
            $(maxInfoArea).html(length + displayText).removeClass("warning");
    });

});

169 lines of code down to 24.  Deleting code, it’s a beautiful thing!

Knowledge, Learning and Sharing – Our Biggest Asset. 

Knowledge and learning are perhaps our biggest asset but are we open to receiving it and sharing it?

I am convinced our attitude in this arena is a huge factor of our success. We never think it’s a bad thing to go get lessons from someone better than us for other activities like learning an instrument.  Why wouldn’t we think the same way in our profession. Do we believe it will make us look weak or expose us in such a way that would jeopardize our job? It’s more dangerous to think this way than it is to actively engage with those better than ourselves to improve.

Stock Photo

Learning from others should be embraced by all.  When we close off our mind to being teachable we will suffer and so will the team.  Contributions from all team members is valuable.  Everyone from the Janitor to the CEO can provide valuable insight.  The more an individual and team thinks and acts like this the more likely they are to grow stronger mentally, improve their technical and social skills, and ultimately help produce better solutions for everyone. 

Happy Coding!

Posted 01.17.2011  #    Comments [2]  | 
# Saturday, 06 November 2010

There are a lot of things that can sink an app but none more visible, yet often overlooked, than a poor user experience.sinking

User Experience Matters

Duh, of course!  Something we all know, right? But do we take care of the UI with the same passion as we do with code?  In order to ensure the user experience remains relevant and a pleasant experience requires refactoring as well.  Like code that can erode over time, the user experience can suffer the same fate.

 The Eroding UI Example

Our team has worked on an application that’s used throughout the organization to enter requests for budget.  The application has gone through several heavy revisions over the past few budget cycles and each time we have had a very tight timeline.  It’s always been a mad rush to make the modifications necessary to accommodate the changes in the process. 

Over time, the UI slowly began to mismatch how the users worked.  The UI grew into a large form and required all the fields to be filled in before a user could save any work.  The nature of how the user worked was very different.

The user process is highly iterative and collaborative within business units who are developing requests.  They often work on one section’s wording over and over until they have it just right and then move to the next section. 

Unfortunately, the UI didn’t handle this well.  Fields that required a lot of text (several paragraphs) were forced into a small text area that had to be scrolled to read.  Users would just print a report to see all the text to get around this.  With all fields being required, users entered garbage/placeholder information into fields in order to save their work.

old

 

New ideas were introduced into the process and the application grew.  A few more forms were added.  The flow was changed so that the user was required to enter this information and save it as a separate step from the main form.  The items were required but very much felt like a bolt on and not as important.

 

An Aside…

Who’s fault is this?  Mine.  It’s the job of the team leader to remove barriers to success and help foster and create situations that lead to success.  It took me a few tries to get us to the point where the team could work their magic properly instead of being hamstrung by constraints that could have been better managed by yours truly. 

 Redesign

This year we took the time to give the application some tender loving care.  The vision was to create logical sections of information.  Maximize space utilization for the sections and move away from strict validation to a routine that would allow saving work anytime while quickly showing what is left to be completed.

The team took the vision and ran with it.

Navigation

nav

The team created a new navigation section that is very pleasing on the eyes and more visible.  The team nearly eliminated the need to scroll vertically on the page. When scrolling does occur the team floated the navigation so that it will always be at the top of the screen.  The save and cancel operation work on the entire record, versus several forms that required saving separately.  Additionally, the user can save at anytime and reduced the number of absolutely required fields down to two.

Layout

tabs

The team created tabs to group similar information into sections.  The tabs have an icon representing if that section has been completed or not. 

Additional information is in each tab to help the user.  When a tab has a green check mark the tab includes a message stating it’s complete.

tabGreen

If the tab is incomplete, represented by the yellow warning sign, a message is shown stating what is needed and each element on the form that needs attention has the same warning icon and it’s own message.

incomplete

With “softer” validation in place the user is able to work on a request in whatever order they need to and with a glance see what is incomplete.  They can also save their work in whatever state they want.  This lends itself well to the iterative drafting process of the initial budget development cycle.

Handling large text needs was simplified by giving them their very own tab.

largeText

More obtrusive (yet nice) messaging was added to the system to help ensure the user doesn’t accidently/inadvertently do something.

delete

The real test - What are the users saying?

In the users tests we’ve conducted we received rave reviews.  We have a few weeks to go to finalize the application and go live with the entire user community.  It’s exciting!

It’s coming along great and I am extremely pleased with the team’s redesign and the large undertaking to replace the strict validation with a softer/gentler validation technique to serve the users better.  Kudos to the team!

Conclusion 

The UI is not immune to change and requires the same level of care that code does.  The need to develop changes can erode the UI just like code.  The UI requires our attention and needs refactoring as well to stay relevant.

Happy Coding!

Posted 11.06.2010  #    Comments [0]  | 
# Saturday, 26 June 2010

I had the misfortune and pleasure earlier this week to work in an Emergency Operations Center view from my home.  Fire is about 1 mile away.(EOC).  Early Sunday morning the Schultz wildfire broke out and moved extremely quickly towards several communities.  I was amongst 1,000 residents evacuated.  

On Monday, I was called into the EOC to help with information flow to the website and twitter.  Over the next three days I worked a little over 40 hours.  It was exhausting but it was amazing and I am proud to have been of service. 

View from friend's home.  Fire is about 1/2 mile away.

 

 

The EOC was a great example of agile even though the team responsible for the EOC didn’t plan with the agile movement in mind.  It reinforced to me that many of the principles in agile can be applied almost anywhere.

 

 

Manifesto:EOC

Individuals and interactions over processes and tools.
Working software over comprehensive documentation.
Customer collaboration over contract negotiation.
Responding to change over following a plan.

The EOC exemplified the manifesto.  The amount of teamwork and information flow in the room was astounding.  Emergencies rarely follow a plan and as such responding to change is paramount to a great EOC.  This EOC was incredible at adapting versus the blind following of a plan.  Wildfire can be incredibly unpredictable.  Even though the EOC had comprehensive documentation and plans for handling emergencies it clearly valued interactions, collaboration and change over processes, documentation/plans and allowed for teams and individuals to improve upon tasks and adapt to needs quickly.

Principles:

Our highest priority is to satisfy the customer….

The EOC has many customers, everyone from the public to the people on the ground responding.  The central theme of the EOC was to keep the accurate and timely flow of information at peak performance.  It accomplished this with co-location of personnel, frequent and short team meetings and a constant emphasis on informal communications and information sharing.

Welcome changing requirements, even late in development….

While the EOC has practiced, ran drills, created plans and procedures for execution of an EOC, the ability to adapt was embraced over absolute following of the training and plans.

Deliver working software frequently….

In this case the EOC is delivering information and logistics.  The EOC worked on a constant cycle of information gathering and dissemination.  The EOC every few hours had a short briefing where all of the table/section leaders gave a report to the team and in between there was constant information flow.

Business people and developers must work together daily….

EOCThe EOC was staffed with expertise in each section that focused mainly on their tasks.  Also in the room were sections for leaders who would be the face for the media and citizens.  Additionally, the call center staff were only yards away from the EOC staff.  This allowed for a constant stream of communication at all levels.

The most efficient and effective method of conveying information to and within a development team is face-to-face conversation.

This was perhaps one of the most impressive executions I found in the EOC.  The EOC was staffed EOCwith seven sections, each section was staffed with at least a couple people and as much as six.  Each section was responsible for a general task such as Public Information, Logistics, Operations, Finance, etc.  Each section had a team leader that was responsible for that section.  The interaction between sections was high.  Flip charts, whiteboards abounded along with three projectors displaying relevant but different information.   

At regular intervals, the team reflects on how to become more effective, then tunes and adjusts its behavior accordingly.

The EOC was extremely concerned with identifying weaknesses and improving them ASAP.  For items that we knew would take longer to correct than the EOC’s existence, the issues and ideas for correction were captured electronically and have been given to staff to work on.

Parting Thoughts:

During the height of operations there were around fifty people in the room.  The energy in the room was high which aided everyone in pushing through long hours and helped keep the room charged.  The dull roar that existed in the room was hardly a distraction as each team was so intent on doing their job well.  Ideas such as co-location and transparent information flow were key to the EOC’s success much like agile proposes.  The organization of each team was self-governing and while overall leadership was provided this leadership did not get in the way of the sections.  The leadership guided and aided in keeping the teams marching forward.

My experience with the EOC was nothing short of amazing.  I feel extremely proud of how the operation center worked and found that many of the ideas and principles held by agile were key in the EOC’s strong success.

Agile | Process | Teams
Posted 06.26.2010  #    Comments [0]  | 
# Wednesday, 25 November 2009

I believe strongly in teams being families.  We spend eight hours a day, five days a week with each other.  A great team is able to take everyone’s ups and downs, pluses and minuses, strengths and weaknesses with dignity, respect and healthy doses of humor.  A great team is a team that isn’t all alike and embraces and remains open to diversity of ideas, backgrounds and ways of thinking even when it’s hard for them to do so.

Lindy White was one of the most unique team members I have had the pleasure to work with and go on to lead.  His candor was unmatched and so was his personality.  His tenacity and intensity for development was infectious.  He was an extremely valuable team member.  He made us all better.

Many years back we moved our website to a CMS system.  Over the years, the site grew to have around eighty content liaisons (users who could write content).  Unfortunately, strewn throughout the website were email addresses.  Our website was responsible for a large amount of email cherry picking by bots.  The team discussed how we could handle this and Lindy was given the lead to develop the solution.

As time went on, Lindy being Lindy was unsatisfied with the solution being developed and struck out to find a better way.  What he came up with was pure gold.  He wrote an HTTP Module that intercepted the outgoing HTML and converted all email addresses to a format bots could not use/read. With zero changes to our end users and next to zero maintenance on our part the web bots can no longer steal email addresses from the website.  I nominated him for an IT Pro Hero award through Windows IT Pro magazine.  Here’s the article:

http://windowsitpro.com/article/articleid/100073/lock-out-spambots.html

Lindy knew of the award but sadly he passed away before he could see the article with his own eyes. 

It’s been a little over a year since he left us and I still think about him all the time.  Lindy, I miss you and you will always have a special place in my heart.  Thanks for the memories!

Posted 11.25.2009  #    Comments [0]  |