I've been working on a badges system. I'm beginning to realize that it's possible to create fairly complex rules around badges. Any particular system is likely to implement a small sub-set of possible badge types. I want to keep an open mind on how different types of badges behave, but don't want to build complexity that won't be used. This post serves to document ideas that I may or may not build out in code.
Simple badge -- Represents an achievement and does not have any special rules. When unearned, the user gets to see a gray version of the badge and the description of how to earn the badge. You can only earn a simple badge once.
Stacked badge -- A badge that you can earn multiple times. I'm not sure why this might be useful. See Leveled badge.
Mystery badge -- When unearned, the user gets to see an obscured placeholder indicating that they need to explore the system to discover how to earn the mystery badge.
Surprise badge -- When unearned, the user does not see that the badge exists. These are create for user delight, rather to encourage specific behavior. An example might be a "Night Owl" badge earned when the user does something between midnight and 4:00 am. Showing this badge as unearned would ruin the surprise.
Progressed Badge -- A badge that requires X number of events to earn. Earners see a visual indication of progress as they get closer to earning the badge.
Leveled badge -- A badge that requires a task to be performed multiple times. When unearned, the user sees their progress. An example might be to access the system for 5 consecutive days, 10 consecutive days, and 25 consecutive days. Potentially, leveled badge could also be mystery badges or surprise badges. If this is the case, progress would be tracked, but not shown when the badge is unearned. When viewing earned badges, high level badges would replace low level badges.
Locked badge -- A badge that doesn't appear as unearned until the user earns a badge that acts acts as prerequisite. The purpose is to avoid cluttering an earner's list of unearned badges. Leveled badges could be locked badges. In this case, the earner would only see the next unearned leveled badge, and would not see how many levels exist.
Forked & Locked badge -- A locked badge where unlocking opens up multiple paths. For example, if a learning system has flash cards, earning the flash card badge could unlock badges for repetition, for speed and accuracy, and for exploring a number of card decks.
Meta badge -- Behaves like a simple badge, except that it is earned by earning a specific combination or number of other badges.
Scored badge -- A badge with a point value. Easy badges would be worth a low number of points, and more difficult badges would have a higher point value. Scored badges are intended to encourage behavior that requires more commitment from the user.
Some kind of badge type that I didn't think of? -- I don't know what this would be.
Saturday, February 9, 2013
Monday, January 28, 2013
Processing Images with Imagemagick, Scala, and Heroku
Imagemagick is a popular and powerful image processing tool. You can use it from any JVM language such as Java and Scala by using im4java. The im4java library is not a pure Java library. Rather, it wraps the command-line Imagemagick program. Fortunately, Imagemagick is popular enough to be available through cloud computing platforms such as Heroku.
I'm working on a badges application. I have two image processing requirements:
I'm working on a badges application. I have two image processing requirements:
- Resize an uploaded badge to small, meduim, and large with conversion to PNG
- Create gray versions of badges in each size to represent unearned badges
My requirements are simple, but it's nice that Imagemagick gives me a lot of headroom should more complex requirements come down the pipeline in the future.
These features were easy to implement in Scala using the following code:
object BadgeImageProcessor {
def resize(originalImage: BufferedImage, size: Int): BufferedImage = {
val cmd = new ConvertCmd
val s2b = new Stream2BufferedImage()
cmd.setOutputConsumer(s2b)
def createResizeCommands(): IMOperation = {
val op = new IMOperation()
op.addImage()
op.resize(size, size)
op.addImage("png:-")
return op
}
cmd.run(createResizeCommands, originalImage)
s2b.getImage()
}
def grayscale(originalImage: BufferedImage): BufferedImage = {
val cmd = new ConvertCmd
val s2b = new Stream2BufferedImage()
cmd.setOutputConsumer(s2b)
def createGrayScaleCommands(): IMOperation = {
val op = new IMOperation()
op.addImage()
op.colorspace("gray")
op.addImage("png:-")
return op
}
cmd.run(createGrayScaleCommands, originalImage)
s2b.getImage()
}
}
The program flow is straight-forward:
Functional programming allows you to pass a function into another function. The method "processImageMagick(...)" takes two parameters; the image to process and a function that takes an IMOperation and returns nothing special (Unit). The magic is the ability to specify a placeholder (the underscore character) to represent the undefined IMOperation, allowing processImageMagick(...) to define the IMOperation and call the "toGray(_)" or toNewSize(_)" methods.
Since I'm only performing one ImageMagick operation in each of my methods (resize and grayscale), I can further simplify the code by in-lining the closures:
def resize(originalImage: BufferedImage, size: Int): BufferedImage = {
processImageMagick(originalImage, _.resize(size, size))
}
def grayscale(originalImage: BufferedImage): BufferedImage = {
processImageMagick(originalImage, _.colorspace("gray"))
}
...I could probably eliminate the need for closures altogether by allowing processImageMagick(...) to take any number of commands, but I'll save that for another day.
The next step is to move the method "processImageMagick(...)" to a utility object, but hopefully you get the idea on how to use higher-order functions to eliminate repetitive boilerplate code without introducing object patterns.
The program flow is straight-forward:
- Create an imageMagick comand that outputs a BufferedImage from a reponse stream
- Define a closure to apply operations to the original buffered image and output the response as a PNG BufferedImage
- Run the operations against the original image, and return the resulting BufferedImage
The program is straight-forward, but the code is repetitive. If I was using Java, I would eliminate the repetition by creating an abstract image processor taking polymorphic processing commands. With Scala, I use higher-order functions. This results in less coding and avoids object abstraction:
object BadgeImageProcessor {
def resize(originalImage: BufferedImage, size: Int): BufferedImage = {
def toNewSize(op: IMOperation, size: Int) = {
op.resize(size, size)
}
processImageMagick(originalImage, toNewSize(_, size))
}
def grayscale(originalImage: BufferedImage): BufferedImage = {
def toGray(op: IMOperation) = {
op.colorspace("gray")
}
processImageMagick(originalImage, toGray(_))
}
private def processImageMagick(originalImage: BufferedImage, commands: IMOperation => Unit): BufferedImage = {
val cmd = new ConvertCmd
val s2b = new Stream2BufferedImage()
cmd.setOutputConsumer(s2b)
def createGrayScaleCommands(): IMOperation = {
val op = new IMOperation()
op.addImage()
commands(op)
op.addImage("png:-")
return op
}
cmd.run(createGrayScaleCommands, originalImage)
s2b.getImage()
}
}
Functional programming allows you to pass a function into another function. The method "processImageMagick(...)" takes two parameters; the image to process and a function that takes an IMOperation and returns nothing special (Unit). The magic is the ability to specify a placeholder (the underscore character) to represent the undefined IMOperation, allowing processImageMagick(...) to define the IMOperation and call the "toGray(_)" or toNewSize(_)" methods.
Since I'm only performing one ImageMagick operation in each of my methods (resize and grayscale), I can further simplify the code by in-lining the closures:
def resize(originalImage: BufferedImage, size: Int): BufferedImage = {
processImageMagick(originalImage, _.resize(size, size))
}
def grayscale(originalImage: BufferedImage): BufferedImage = {
processImageMagick(originalImage, _.colorspace("gray"))
}
...I could probably eliminate the need for closures altogether by allowing processImageMagick(...) to take any number of commands, but I'll save that for another day.
The next step is to move the method "processImageMagick(...)" to a utility object, but hopefully you get the idea on how to use higher-order functions to eliminate repetitive boilerplate code without introducing object patterns.
Thursday, January 3, 2013
Success Using Scala to Create a DSL
Update (March): I've given up on the idea of creating DSL's for every business domain I work in. I've concluded that Scala is not that scalable (at least not yet). The original January post follows:
It took three rounds of making mistakes, but I finally have something elegant.
The primary goal was to represent a route between to airports using natural language. For example, I wanted to be able to write the following line of code:
val routeFromDetroitToPhilly = "DTW" to "PHL"
I also wanted my model code to be pristine. I wanted to separate any syntactic sugar from my model code, and to avoid any circular dependencies between model objects.
Here are my model objects:
case class Airport(code: String)
case class Route(origin: Airport, destination: Airport)
A route links origin and destination Airports. The Airport is only dependent on String. This is good. There was problem introduced, however, when I tried to use the "to" keyword to create a Route from two Airports. You can see the issue if I re-write the desired code in a way that exposes some of the magic:
val routeFromDetroitToPhilly = Airport("DTW").to(Airport("PHL"))
My initial attempts to implement the "to" keyword involved introducing a circular dependency between Airport and Route:
case class Airport(code: String) {
def to(destination: Airport) = Route(this, destination)
}
case class Route(origin: Airport, destination: Airport)
This worked, but is nasty. Route depends on Airport and Airport depends on Route. My first attempt was even worse. I tried adding the "to" method for route creation though inheritance. Not a good idea. I'm too ashamed to publish that failed attempt.
I finally figured out that I could put my syntactic sugar in a model helper class:
object ModelHelper {
class AirportRouteBuilder(origin: Airport) {
def to(destination: Airport): Route = {
Route(origin, destination)
}
}
implicit def stringToAirport(code: String) = Airport(code)
implicit def stringToAirportRouteBuilder(airportCode: String) = new AirportRouteBuilder(Airport(airportCode))
implicit def airportToAirportRouteBuilder(airport: Airport) = new AirportRouteBuilder(airport)
}
Now when I write this code:
val routeFromDetroitToPhilly = "DTW" to "PHL"
...Scala resolves the code as follows:
It took three rounds of making mistakes, but I finally have something elegant.
The primary goal was to represent a route between to airports using natural language. For example, I wanted to be able to write the following line of code:
val routeFromDetroitToPhilly = "DTW" to "PHL"
I also wanted my model code to be pristine. I wanted to separate any syntactic sugar from my model code, and to avoid any circular dependencies between model objects.
Here are my model objects:
case class Airport(code: String)
case class Route(origin: Airport, destination: Airport)
A route links origin and destination Airports. The Airport is only dependent on String. This is good. There was problem introduced, however, when I tried to use the "to" keyword to create a Route from two Airports. You can see the issue if I re-write the desired code in a way that exposes some of the magic:
val routeFromDetroitToPhilly = Airport("DTW").to(Airport("PHL"))
My initial attempts to implement the "to" keyword involved introducing a circular dependency between Airport and Route:
case class Airport(code: String) {
def to(destination: Airport) = Route(this, destination)
}
case class Route(origin: Airport, destination: Airport)
This worked, but is nasty. Route depends on Airport and Airport depends on Route. My first attempt was even worse. I tried adding the "to" method for route creation though inheritance. Not a good idea. I'm too ashamed to publish that failed attempt.
I finally figured out that I could put my syntactic sugar in a model helper class:
object ModelHelper {
class AirportRouteBuilder(origin: Airport) {
def to(destination: Airport): Route = {
Route(origin, destination)
}
}
implicit def stringToAirport(code: String) = Airport(code)
implicit def stringToAirportRouteBuilder(airportCode: String) = new AirportRouteBuilder(Airport(airportCode))
implicit def airportToAirportRouteBuilder(airport: Airport) = new AirportRouteBuilder(airport)
}
Now when I write this code:
val routeFromDetroitToPhilly = "DTW" to "PHL"
- The function "to(...)" is invalid for the String "DTW", but we have an implicit method "stringToAirportRouteBuilder()" that creates an AiportRouteBuilder object that has a "to(...)" method
- Call "stringToAirportRouteBuilder("DTW")" to create an AirportRouteBuilder object
- Call "StringToAirport("PHL")" to create the Airport object needed for "AirportRouteBuilder.to(...)"
- Call the "to()" method on AirportRouteBuilder to construct a new Route object that links the origin and destination airports
This is pretty mind-blowing stuff. It seems too complex and magical, but I believe it's a way of thinking that we can get used to. It's like eating ethnic food for the first time or meeting an ugly person for the first time. After the initial shock, you get used to it if you allow yourself the opportunity to appreciate.
Tuesday, October 30, 2012
Struggling with Scala as a DSL
Scala was created to be a Scaleable Language. I'm trying to figure out how well Scala has delivered on this promise. To me, a language is scalable if it is useful for creating Domain-Specific programming languages (DSL's). I've been going through examples and trying things on my own. Here is a good example: http://debasishg.blogspot.com/2008/05/designing-internal-dsls-in-scala.html
Thursday, October 25, 2012
ScalaTest is Awesome
I've been test-driving Java with JUnit and TestNG for about four years. I've always hated that your test names are dictated by the rules of naming functions. This yields some long and awkward function names such as:
You may ask "Why should we care if a test is pretty or ugly? Our customers are not asking for pretty tests!". The reason is that if you employ software developers, you are paying 80% of their salary for reading and understanding code, and only 20% for writing code. If you have a developer that can type 40 words-per-minute, and they are giving you 8 hours a day writing code at 40 WPM, that's not the developer you want in your shop.
There is much more. Note that ScalaTest can test Java code as well as Scala code. Visit http://scalatest.org/ to learn more.
@Test public void translatingDocumentToSpanishShouldConvertCatToGato() {...}Here is an example using Cucmber-sytle syntax:@Test public void givenTextIsCatAndLangIsSpanish_whenTranslate_thenReturnGato() {...}Since Scala allows you to have anonymous functions and allows you to create Domain-Specific Languages, the makers of ScalaTest have come up with multiple solutions to cleaning up your ugly xUnit test suites.Here is an example using Jasmine-style syntax:describe("Translating from English to Spanish") { it("should translate [Cat] to [Gato]") {...} }
feature("Translate text from English to Spanish") { info("As a student who speaks English as a 2nd language") info("I want to be able to translate English to Spanish") info("So that I can make sure I understand my reading") scenario("translate simple single word") { given("[cat] in my English text") {...} when("I choose to translate to Spanish") {...} then("I see [gato]"){...} } }
You may ask "Why should we care if a test is pretty or ugly? Our customers are not asking for pretty tests!". The reason is that if you employ software developers, you are paying 80% of their salary for reading and understanding code, and only 20% for writing code. If you have a developer that can type 40 words-per-minute, and they are giving you 8 hours a day writing code at 40 WPM, that's not the developer you want in your shop.
There is much more. Note that ScalaTest can test Java code as well as Scala code. Visit http://scalatest.org/ to learn more.
Friday, October 19, 2012
Challenge: One Hour with Mozilla Badges
Challenge: One Hour with Mozilla Badges

Spend one hour (or hopefully less) to learn about Mozilla Badges
Part 1: Earn your first badge
Go to
Mozilla badges at http://openbadges.org/en-US/
Click
"get started" to earn your first badge
Part 2: Earn your first badge on P2PU.org
Go to
p2pu.org
Create an
account (Make sure you confirm your email address so you can post)
Find the
challenge "Introduce Yourself"
Take 30
minutes to an hour to complete the challenge.
Part 3: Send your P2PU badges to your Mozilla backpack
Select
"My Settings" from the drop-down under your name on P2PU.org
Click on
"Share Badges" and click "Send"
Confirm adding
your P2PU badges to your Mozilla backpack
Confirm your
badges at http://openbadges.org/en-US/ (visit your Mozilla Badge Backpack)
Subscribe to:
Posts (Atom)
