Monthly Archives: August 2011

UX Resources for Beginners

User experience design (UX) matters a lot to us at Cantina. A great user experience will magnify a successful technology implementation, while a bad user experience can turn success into disappointment.

As one of Cantina’s UX experts I am often asked about learning resources for those who are starting out or wanting to learn more about UX design and development. I will cover some of my favorites for each below.

If you want to learn more about UX design, then my first bit of advice would be to attend a conference like An Event Apart. Also, attending art / graphic design related classes at a local college would prove to be beneficial for learning things like typography and color theory.

A lot of good books have been published focusing on UX design. Some of my favorites are:

Some UX design related websites are:

For UX development, you can find a lot of information online, but some books I consider to be bibles of UX development. They are:

Also, you should read every article on A List Apart.

And here are a few other things you should check out for UX development:

That should get you started!

If you know about other UX resources that you’d like to recommend then please post them in the comments below.

A great user experience will magnify a successful technology implementation, while a bad user experience can turn success into disappointment.

Web vs. Native App Conundrum – The Debate Goes On

Perusing my news feeds today, I came across an article entitled, Could Mobile Apps Be Evolutionary Dead End? by Steve Rubel of Ad Age Digital.  Steve posits that ‘Marketers May Find New Breed of Web Apps Preferable to Multiple Platform’.  The article goes on to discuss the fragmentation of the global marketplace, the leverage and distribution advantages inherent in building HTML5 web-based apps, the easing of Apple’s restrictive posture, the proliferation of Google’s Android Marketplace and discoverability through search, and the benefit for advertisers.

I believe the article’s assertion is right, namely that ‘marketers may decide it’s more cost effective to develop a strong web application and control the experience end-to-end, rather than support hundreds of phone and tablet formats’.

Back in May, I posted a blog on the topic of designing apps for multi-channel experiences and the need for analysis and planning to capture the value of the development investment.  There are compelling reasons to entertain web app approaches vs. native app development, and Cantina has assisted many clients with this strategic decision.

Cantina is hosting a roundtable discussion at our Newton offices on September 29th to discuss the exact topics debated in Steve’s article.  The forum will assist B2B and B2C mobile leaders compare approaches and discuss solutions that address the challenges of designing mobile applications.

There are compelling reasons to entertain web app approaches vs. native app development, and Cantina has assisted many clients with this decision.

Super-fast Tour of the Scala Programming Language

In an effort to learn Scala (or at least to a reasonable degree) I put together a Scala script that illustrates the primary language features especially as someone with Java/Groovy/Ruby knowledge. The hope here is to quickly give you a feel for the language while diving deeper into some specific features.

The tour includes:

  • val vs var and defining variables
  • Strings and string interpolation
  • Operators and defining new ones
  • Functions
  • Lists, Maps, and other collection-isms
  • Case classes and pattern matching
  • Traits
  • Implicit type conversion
  • Ternary operator (or lack thereof and the Scala equivalent)
  • DSLs (a simple one)
  • Generics
  • Lazy variables
  • XML literals
  • Exception handling
  • Tuples
  • Regular expressions and case matching
Let me know if I’ve left anything out super-important and I’ll loop back and include it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
/*
* var vs val and defining variables
*/
var changeMe = 1 // variable assignment
val dontChangeMe = 2 // constant assignment
 
changeMe = 3
assert(changeMe == 3)
 
// this causes the error: reassignment to val
//dontChangeMe = 4
 
// you can still change the contents of values that are objects
val constArray = Array(1)
assert(constArray(0) == 1)
constArray.update(0, 10)
assert(constArray(0) == 10)
 
var s = "foo" // type is implied
var s2:String = "3" // full version
assert(s.getClass.getSimpleName == "String")
 
// this would cause an error as it's statically typed
// s2 = 3
assert(s2 != 3)
assert(s2.toInt == 3)
 
/*
* Strings
*/
 
assert("foo".isInstanceOf[String])
assert('f'.isInstanceOf[Char])
 
// multiline string
assert("""
this
is \my
string
""" == "\nthis\nis \\my\nstring\n")
 
// string interpolation as in ${...} or #{...} is not supported. it's +..+ in scala.
assert("a"+1+"c" == "a1c") // recommended way in scala. shorter and concise.
assert("%d+%d=%d".format(1,2,3) == "1+2=3")
 
// see StringBuilder for enhanced string manipulation
 
/*
* Operators are just methods
*/
// note: class not ideal. just for illustration.
class SimpleValue(private var _value:Int) {
def value:Int = _value // getter
// def value_=(v:Int) { value = v } // setter (note the _)
def +(v:Int) = new SimpleValue(value + v)
def times(n:Int) = new SimpleValue(value * n) // methods are operators too
def unary_! = new SimpleValue(-value)
def -:(v:Int) = new SimpleValue(value - v)
}
 
var v = new SimpleValue(1)
assert(v.value == 1)
assert((v.+(3)).value == 4)
var v2 = v + 3
assert(v2.value == 4)
v2 = v2 times 2
assert(v2.value == 8)
v2 = !v
assert(v2.value == -1)
v2 = 8 -: v
assert(v2.value == -7)
 
/*
* Functions
*/
 
// shows different ways to define functions
 
def one = 1 // can you guess what this does?
def self(a:Int) = a // does nothing but return a
def add(a:Int, b:Int) = a+b // implicit return type
 
assert(one == 1)
assert(self(1) == 1)
assert(add(1, 2) == 3)
 
// more Java-style definition. With this format you must specify return type otherwise it defaults to Unit
def subtract(a:Int, b:Int):Int = {
return a - b // "return" is optional here
}
assert(subtract(3, 2) == 1)
 
// this method doesn't need the = or parentheses
def printSomething {
println("something")
}
printSomething
 
// functions are objects no we can pass them around
def reduce(f: (Int, Int) => Int, a:Int, b:Int, c:Int) = f(f(a, b), c)
 
assert(reduce(add, 1, 2, 3) == 6)
assert(reduce(subtract, 3, 2, 1) == 0)
 
// Anonymous functions let you define them without a name (ie closures)
assert(reduce((a:Int, b:Int) => a*b, 4, 3, 2) == 24)
 
// Currying lets us bind some of the parameters and define a new function
// We'll do this to a normal function and function designed for currying
def multiply(a:Int, b:Int) = a*b
def multiplyCurry(a:Int)(b:Int) = a*b
 
assert(multiply(2,3) == 6)
// multiplyCurry(2,3) // throws an error about too many arguments
assert(multiplyCurry(2)(3) == 6)
// multiply(2)(3) // you can't do this: throws an error about missing arguments
 
var double = multiplyCurry(2) _ // the _ means this is a partially applied function
var triple = multiplyCurry(3) _
assert(double(6) == 12)
assert(triple(6) == 18)
 
// we can convert normal functions to curryable
double = multiply(2, _:Int)
assert(double(6) == 12)
 
// another way to do the same thing by first making the function curryable
double = (multiply _ curried)(2)
assert(double(6) == 12)
 
/*
* Lists
*/
 
// lists are typed and use generics (the type can be infered)
var l1:List[String] = List("foo", "bar", "baz")
var l2 = List("foo", "bar", "baz")
// operators ending in ':' operated and the right value. :: is a method on the list.
var l3 = "foo" :: "bar" :: "baz" :: Nil
assert(l1 == l2)
assert(l2 == l3)
assert(Nil == List())
assert(l3 == Nil.::("baz").::("bar").::("foo"))
assert(l1 == "foo" :: List("bar", "baz"))
 
// basic list operations
assert(!l1.isEmpty)
assert(l1.nonEmpty)
assert(l1.length == 3)
assert(l1.head == "foo")
assert(l1.tail == List("bar", "baz")) // not the last element. everything except the head.
assert(l1.last == "baz")
assert(l1.apply(0) == "foo")
assert(l1(0) == "foo")
assert(l1.take(2) == List("foo", "bar"))
assert(l1.drop(2) == List("baz"))
assert(l1.dropRight(1) == List("foo", "bar"))
assert(List(1,2,3,4).dropWhile(_ < 3) == List(3,4))
assert(List(1, 2, 3, 4).drop(1).take(2) == List(2, 3)) // getting a sub list
assert(l1.startsWith(List("foo")))
assert(l1.endsWith(List("baz")))
 
assert(List(1, 2) ::: List(3, 4) == List(1, 2, 3, 4)) // concatenating lists
assert(List(1, 2) ++ List(3, 4) == List(1,2,3,4))
assert(List(1, 2) ++: List(3, 4) == List(1,2,3,4))
assert(1 +: List(2,3) == List(1,2,3))
assert(List(1,2) :+ 3 == List(1,2,3))
 
assert(List(2, 1) == List(1, 2).reverse)
 
assert(List(2, 4, 6) == List(1,2,3).map(_*2))
assert(List(2, 4, 6) == List(1,2,3).collect {case i:Int => i*2}) // TODO WHY?
assert(List(1,2,3).fold(0)((x,y) => x+y) == 6)
assert(List(1,2,3).reduce((x,y) => x+y) == 6)
assert(("" /: List("a","b","c"))((x,y) => x+y) == "abc") //reduces starting with "" left to right
assert((List("a","b","c") :\ "")((x,y) => x+y) == "abc")
assert( List(1,2,3).corresponds(List(2,4,6))((x,y) => y == x*2) )
assert( List(1,2,3).diff(List(2,3,4)) == List(1) )
assert(List(1,1,2,3).distinct == List(1,2,3))
assert(List(1,2,3,4).find(_>2) == Some(3))
assert(List(1,2,3,4).forall(_<5))
assert(List(1,2,3,4).groupBy(_ % 2 == 0) == Map(false -> List(1, 3), true -> List(2, 4)))
assert( List(1,2,3,4).partition(_ % 2 == 0) == (List(2, 4),List(1, 3)) )
assert(List(1,2,3,4).min == 1)
assert(List(1,2,3,4).max == 4)
 
var total = 0
List(1,2,3).foreach(total += _)
assert(total == 6)
 
assert(List(3,4) == List(1,2,3,4).filter(_>2))
 
// for comprehensions allow filtering and mapping in a concise syntax
l1 = for(x <- List(1,2,3,4) if x > 2) yield x.toString
assert(List("3", "4") == l1)
 
/*
* Maps
*/
 
var m1 = scala.collection.mutable.Map("a" -> 1, "b" -> 2)
m1 += "c" -> 3
assert(m1 == Map("a" -> 1, "b" -> 2, "c" -> 3))
assert(m1("b") == 2)
assert(Map("a" -> 1) + ("b" -> 2) == Map("a" -> 1, "b" -> 2))
assert(Map("a" -> 1, "b" -> 2) - "b" == Map("a" -> 1))
// many of the same functions exist as with lists
 
/*
* Case classes and pattern matching
*/
 
abstract class Expr
case class Number(n:Int) extends Expr
case class Multiply(e1:Expr, e2:Expr) extends Expr
case class Add(e1:Expr, e2:Expr) extends Expr
 
// These class are like creating an immutable class in Java with a parameterized constructor, hashCode, equals, toString, getters, and a static method for easier construction
var number = Number(1)
assert(number.n == 1)
assert(number == Number(1))
assert(number != Number(2))
assert(Add(Number(1), Number(1)) == Add(Number(1), Number(1)))
assert(List(number).contains(Number(1)))
assert(number.toString == "Number(1)")
 
// Pattern matching is like short-hand for lots of if's and instanceof's
def eval(e:Expr):Int = e match{
case Number(n) => n
case Multiply(l,r) => eval(l) * eval(r)
case Add(l,r) => eval(l) + eval(r)
}
 
assert(eval( Multiply(Number(2), Add(Number(3), Number(1))) ) == 8)
 
def otherCases(v:Any):String = v match {
case Add(Number(n1), Number(n2)) => n1.toString + " + " + n2 // more complex pattern
case "foo" => "bar" // constant matching
case _ => "default" // the default
}
assert(otherCases("foo") == "bar")
assert(otherCases(3.14) == "default")
assert(otherCases(Add(Number(1), Number(2))) == "1 + 2")
assert(otherCases(Multiply(Number(1), Number(2))) == "default")
 
/*
* Traits
*/
 
trait Commentable {
var comments = List[String]()
def comment(s:String) { comments = comments :+ s }
}
 
trait Likeable {
var likes = 0
def like { likes += 1 }
}
 
class Article(title:String)
class BlogPost(title:String) extends Article(title) with Commentable with Likeable
 
// 2 different ways to use the traits
List(
new BlogPost("my post"),
new Article("special article") with Commentable with Likeable ).foreach
{ bp =>
bp.comment("this is great!")
bp.comment("nice post")
bp.like
 
assert(bp.comments.length == 2)
assert(bp.likes == 1)
}
 
/*
* Implicit type conversion
*/
// wrap objects to provide additional functionality
class IntWrapper(i:Int) {
def squared = i*i
}
 
implicit def wrapInt(i:Int) = new IntWrapper(i)
 
assert(4.squared == 16)
 
class Thing1(n:String) {
def name = n
}
class Thing2(n:String) {
def name = n
}
 
def thing2Name(thing:Thing2) { assert(thing.name == "bar") }
 
// wrather than wrapping we just do type coercion
implicit def thing2Converter(thing:Thing1) = new Thing2(thing.name)
implicit def thingConverter(s:String) = new Thing2(s)
 
thing2Name(new Thing1("bar"))
thing2Name("bar")
 
/*
* Ternary operator
*/
 
// this does not work in Scala: if (true ? "foo" : "bar")
assert((if (true) "foo" else "bar") == "foo")
 
/*
* DSLs. A simple example putting together implicit conversion and operators
*/
 
case class BooleanWrapper(b:Boolean) {
def and(that:Boolean) = b && that
def or(that:Boolean) = b || that
}
 
implicit def wrapBoolean(b:Boolean) = new BooleanWrapper(b)
assert(true and true or false == true)
 
/*
* Generics
*/
case class MyTuple[A,B](a:A, b:B) {
// equivalent to: def aList:List[A] = List[A](a)
def aList = List(a)
}
 
var t1 = new MyTuple(1, "foo") // generic types are infered
assert(t1.a == 1)
assert(t1.b == "foo")
assert(t1.aList.apply(0) == 1)
 
// TODO covariant subtyping
 
/*
* Lazy variables
*/
 
class Counter() {
lazy val a = System.currentTimeMillis
val b = System.currentTimeMillis
 
def doSomething {
lazy val c = System.currentTimeMillis
val d = System.currentTimeMillis
Thread.sleep(100) // c will be initialized after d when it's used
assert(d < c)
}
}
 
val counter = new Counter
counter.doSomething
assert(counter.b < counter.a) // a not initialized till now
 
/*
* XML literals
*/
 
val author = "John Doe"
val title = "My Poem"
var poem =
<poem>
<title length="{title.size}" foo="bar">{title}</title>
<author>{author}</author>
<content><line>this is my poem</line></content>
</poem>;
 
assert(poem.isInstanceOf[scala.xml.Elem])
assert((poem \ "content" \ "line").text == "this is my poem")
assert((poem \\ "line").text == "this is my poem")
assert((poem \ "title" \ "@length").text == "{title.size}") // no interpolation for attributes
assert((poem \\ "@foo" find { _.text == "bar" }).get.text == "bar")
 
// pattern matching lets you campare elements. note we get back a NodeSeq but need to match on a Node
var elementValue:String = null
(poem \ "author")(0) match {
case <author>{ text }</author> => elementValue = text.text
case <title>{ text }</title> => elementValue = "wrongvalue"
}
assert(elementValue == "John Doe")
 
/*
* Exception handling
*/
 
// simple try/catch
try {
throw new IllegalStateException("demo")
} catch {
case e => println(e) // defined as Throwable
}
 
// try/catch using pattern matching
try {
throw new IllegalStateException("demo")
} catch {
// you can do multi-catch too!
case e:NullPointerException => println("null")
case e @ (_:IllegalStateException | _:IllegalArgumentException) => println("state or argument")
case _:java.util.zip.ZipException | _:java.io.EOFException => println("threw away my object")
case e => println("anything else")
} finally {
println("I'm always printed")
}
 
/*
* Tuples
*/
 
var t = (1, "foo") // a Tuple2
assert(t._1 == 1)
assert(t._2 == "foo")
val (x,y) = t // assiging multiple values from a tuple
assert(x == 1)
assert(y == "foo")
var t2 = 1->"foo" // used in defining Map key/values
assert(t == t2)
 
/*
* Regular expressions and case matching (normal Java stuff omitted)
*/
 
val email = """(\w+)@(\w+).([a-zA-Z]{1,3})""".r
val name = """(\w+)\s+(\w+)""".r
def printMatch(s:String) {
s match {
case email(user, domain, tld) => println("user: "+user+" domain: "+domain+" tld: "+tld)
case name(first, last) => println("first: "+first+" last: "+last)
}
}
printMatch("foo@example.com")
printMatch("Hubert Farnsworth")
var name(first, last) = "Bender Rodrigez"
assert(first == "Bender")
assert(last == "Rodrigez")
view raw examples.scala hosted with ❤ by GitHub

 

[Read more on Dan’s blog at http://mrdanadams.com]

The hope here is to quickly give you a feel for the language while diving deeper into some specific features.