Friday, March 10, 2017

Essential skills - user experience

I rediscovered all the delightful benefits of mockups all over again on the latest project I'm working on.

To put the story in context:
We're a large team of professionals with a range of different skills. One of our team members was a UX/visual designer person who's responsibility was to conduct workshops with the client to develop a UX story and visual designs for the product we're developing. Her participation on the project was time-boxed and limited by a budget. Of course - nobody has an endless budged for anything. If we did, we could keep tinkering with stuff. To cut the story short, we ran into a couple of issues:
  • The client didn't quite like the first cut of proposed visual designs
  • There was a lot of pushback on the details - don't like the colours, don't like this and that, don't like the icons etc.
  • The branding was kind of done but still a bit in the air when it comes to approval with 100% satisfaction
  • UX/visual designer person ran out of time & budget and we could not use any more of her skills
At the conclusion of the "discovery phase" of the project we ended up with some designs, not enough, and none were fully approved. Ooops, that can be a bit of a problem. The development team typically needs full approved designs for all key pages. Without them it's really difficult to commit to delivering what was promised with any degree of certainty.

There's a gap that the development team needs to fill. So how do we do that? Well none of us is a Photoshop magician and even if we were... producing high definition visual designs takes A LOT OF TIME. Time we never have, skills that take years to perfect. We're only technical people after all, we dream in lines of code, not in pretty pictures.

Mockups come to the rescue. To be more exact - Balsamiq! My god, if I ever loved a product it's got to be Balsamiq. I came across it quite a few years ago when the concept of mockups or lo-fi designs was still not very popular. You'd toss the word "mockup" in the ether and the client would look at you puzzled as to say - what the hell are you talking about? These days, lucky for us, the concept of mockups is firmly established or if the client is truly unfamiliar with mockups they're at least an easy sell. You explain what they are, show them an example and they usually give you the thumbs up without too much hesitation. I usually say they're like wireframes but really simple, they look like hand drawn sketches. If I have to sell the idea I say they're quick to whip up and prevent all the issues associated with subjective liking/disliking for the colours and nitpicking on pixel perfect details. And if they're still not sure I can say if they really want to see what the final product will look like we can ask The Designer to take the mockup and produce a high fidelity design. Sold!

Okay, back to Balsamiq. I could go on and on raving about all the reasons why I love this product. I'm sure there's many similar on the market and if I'm doing something for a hobby or a non-for-profit project I'll typically use Pencil Evolus. Balsamiq was really the first good web based mockup tool I came across and it was so damn good from the start that I never bothered looking for anything else. It is simply the best - it does what it's supposed to do and it does it so brilliantly well. It's web based and works on any web browser I used so far. You can invite your client stakeholders to view the mockups and comment on them and it's dead simple. Perfect, just perfect.

Now back to UX as a skill. As I mentioned earlier I'm a technologist - my bread and butter is to dream up and deliver technical solutions. It pays to be a multiskilled person but reality is that you can never be master of everything. The age old argument of what's better - to be a specialist or a jack of all trades. Well a bit of both is clearly best. Every developer should have the basic understanding of UX or user interface design, at least have a feel for it. There will always be gaps you need to fill. If I had to walk the UX talk I probably wouldn't be able to do so. If you asked me what's the difference between UX and user interface design the best answer I could come up with would be that the former is broader and deals with the big picture and the latter is more focused on the detail. But with years of experience I'm able to compare, understand and distinguish between what I see as bad design versus what I see as good design. I can try out ideas, mock them up and pick the better alternative. I can read up on good UX practices and further educate myself.

Sunday, August 23, 2015

Read Assistant

I took 4 courses as part of my masters degree at university last semester. If I said I had tons of textual material to read I would not be exaggerating. Literally hundreds and hundreds of pages to read each week. Some of the readings were difficult academic articles too. Stuff you can't just read casually, to absorb and understand the material. On top of all the textbook reading I had to read at least two academic articles on the topic of philosophy of science per week. I had to understand these two articles and critique them. If I didn't do that regularly I would fall behind on the readings for that course and it would simply be impossible to complete the readings for the following week. I had to write tons of material too. Writing and editing of documents takes a lot of time too - a lot of rereading of what I wrote.

At times, my mind was at the brink of exploding. My eyes would sting from all the screen time. The will to learn was certainly there but sometimes I felt I was just too physically tired to keep on going and stay focused.

That's when I discovered that I can keep on going even when I felt all I can do is just lie down and rest my eyes. If I used text-to-speech functionality built into the PDF reader I was using. It wasn't a perfect solution. It would only read text from the current page onwards or from the beginning of the document. It didn't highlight the sections it was reading so I still had to put and effort into following what was being read. I then tried another piece of free software that would read any content pasted into the clipboard. I copied small chunks of text from the PDF document and the program would read them out to me. Still not ideal.

I wanted an app that would read and highlight the PDF or Word documents for me. Highlighting of the sections of text that were currently read out would help me read actively. Synergy - that's what I needed. Other usability characteristics too. For example, ability to use the software on my surface which is a touch device. Ever tried copy-pasting text on a touch device? It can be a pain. Buttons would have to be large, the user interface would have to have high contrast. It should be functional in sub-optimal conditions, such as when you're on public transport with background noise or outdoors with bright light which makes it more difficult to read from a screen even at full brightness setting. It should not require copy-pasting but instead be able to open documents in a variety of formats. It should read naturally, not like a mindless machine.

Where there's a need, there's a way! I decided I'll make it my hobby project and I started tinkering away. I do bit by bit, an hour of work here and there where I can squeeze it in. This week I finally made a breakthrough progress and got the app to a stage where I can actually show it to someone else.

Here's a short demo of my minimum viable product:

Thursday, August 20, 2015

Finding and highlighting a section of text in WPF RichTextBox

I'm working on a hobby project and I was stumped by this seemingly simple task. RichTextBox class does not implement a straightforward way to do this out of the box. I found several useful snippets of code on StackOverflow but none worked perfectly with formatted text I was displaying in my RichTextBox.

Text spread over multiple paragraphs, spans and containing embedded elements proved to be particularly problematic.  I figured out that I need to somehow use TextPointer class to find the section of the text I wanted to highlight. The main problem I had was finding the text within the document and then correctly obtaining the absolute character positions for the start of the section and the end of the section. If the document contained multiple paragraphs and the text I was trying to highlight spanned over multiple lines of text, the built-in methods would return character positions which were slightly off.

My final solution was to implement TextPointer class extensions which account and adjust for new lines and embedded elements to return position pointers which then allowed me to apply styling to desired sections of text.

You can use the TextPointer extensions like this:
   //NOTE: RtbEditor is the RichTextBox control I'm using to display text

   // Create a new TextRange that takes the entire FlowDocument as the current selection.
   var searchRange = new TextRange(RtbEditor.Document.ContentStart, RtbEditor.Document.ContentEnd);

   // Find the section of text
   var foundRange = searchRange.FindTextInRange("The brown fox jumped over the lazy dog");
   if (foundRange != null)
   {
    foundRange.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
   }

And the TextPointerExtensions class you need to include in your project:
 public static class TextPointerExtensions
 {
  public static TextRange FindTextInRange(this TextRange searchRange, string searchText)
  {
   int offset = searchRange.Text.IndexOf(searchText, StringComparison.OrdinalIgnoreCase);
   if (offset < 0)
    return null;  // Not found

   var start = GetTextPositionAtOffset(searchRange.Start, offset);
   var end = GetTextPositionAtOffset(start, searchText.Length);
   var result = new TextRange(start, end);

   return result;
  }

  private static TextPointer GetTextPositionAtOffset(this TextPointer position, int offset)
  {
   while (position != null)
   {
    if (position.GetPointerContext(LogicalDirection.Forward) == TextPointerContext.Text)
    {
     int count = position.GetTextRunLength(LogicalDirection.Forward);
     if (offset <= count)
     {
      return position.GetPositionAtOffset(offset);
     }
     offset -= count;
    }

    var nextContextPosition = position.GetNextContextPosition(LogicalDirection.Forward);
    if (nextContextPosition == null)
     return position;

    position = nextContextPosition;
    switch (nextContextPosition.GetPointerContext(LogicalDirection.Forward))
    {
     case TextPointerContext.ElementEnd:
      //adjust for line breaks if current element is an end element and the next element is a paragraph
      if (nextContextPosition.GetAdjacentElement(LogicalDirection.Forward) is Paragraph)
      {
       offset -= Environment.NewLine.Length;
      }
      break;
     case TextPointerContext.EmbeddedElement:
      //TODO: may need to adjust offset for embedded elements too
      //needs further testing to ensure it works correctly in a variety of scenarios
      offset--;
      break;
     default:
      break;

    }
   }

   return position;
  }
 }