Latest Tweets

 

Guava’s hashing abstractions compared to Crinch’s

Guava recently introduced a new hashing package and I’ve spent the evening benchmarking my hash library implementation against Guava’s. I’m interested in whether I can abandon my com.tomgibara.crinch.hashing package for com.google.guava.hash.

It’s been fascinating to closely inspect an alternative abstraction of the same (fairly fundamental) concept; especially since I’ve never really liked my own.

Unsurprisingly, though class names obviously differ (Guava’s are far better in my opinion — more consistent and intelligible), there are a number of similarities, but I’ve chosen to highlight some of the differences below, with my initial observations on them.

The intention is absolutely not to knock Guava or to say whether it’s better or worse than my own library — they operate in quite different contexts — it’s simply to explore the trade-offs made in their design (as I see them).

Here are my initial observations:

  • One fundamental difference between the approach of the libraries is that Guava sees hashing (executed by HashFunctions) always as an operation on a byte array. This is something I consciously avoided in Crinch. The equivalent class (Hash) operates directly on objects to be hashed, even if objects may be collapsed to bytes internally. I felt this design choice was important because some applications may need to provide an alternative hash implementation that can’t be easily or efficiently expressed at a byte level. The Guava abstraction is cleaner but may not be as flexible.
  • Guava converts objects into bytes using a Funnel abstraction that ‘puts’ bytes into a Sink which is fluent and appears to be strongly influenced by Java’s ByteBuffer class. Conversely Crinch uses a HashSource (a truly terrible class name) to ‘write’ object bytes into a WriteStream which is loosely based on Java’s DataOutputStream class. This write/put distinction has almost no implications at a code level, but hints at different mental models. One difference that does affect the relative usability of the APIs is that Sink is fluent (as are many of Guava’s interfaces) whereas WriteStream is not. I always hesitate when faced with the decision to employ a fluent interface that may be used in performance critical sections of code; I always worry that there may be a performance hit - even though I have no evidence that this is the case; it may be irrationality on my part.
  • Guava doesn’t appear to provide an object that combines a Funnel with a HashFunction. This means that, at least in little coding I’ve so far done with Guava’s hash package, I frequently have to push both objects around myself. It’s a small niggle, but one that Crinch avoids.
  • To accommodate hash values that are larger than a Java primitive, Guava uses a HashCode interface that gives access to the hash as an int, long or byte[]. Crinch on the other hand uses Java’s BigInteger class for the same purpose and I think this benefits the developer in terms of familiarity, definiteness and usefulness. Obviously Guava’s use of an interface here provides for important performance benefits when implementing specific HashFunctions, but this is not such an issue in Crinch because intermediate object creation can generally be avoided (see next comment).
  • Most of the Crinch code has been designed to avoid unnecessary garbage; it’s designed to handle large collections of objects and as such even small amounts of garbage build up quickly. This often works against producing simpler APIs, and here is one such case. Guava exposes a single hash() method that returns a HashCode object, but Crinch has three methods hashAsInt(), hashAsLong() and hashAsBigInt(). Intermediate object creation can be avoided at the expense of a more ugly API.
  • Guava only allows hash sizes to be specified in terms of bit size, but Crinch is more specific: hashes can be specified to lie within a range of values. This distinction can be important because many interesting data structures (such as Bloom filters and compact approximators) may rely on hash codes that lie over certain ranges and there exist specific modes of hashing that can match those ranges with little bias compared to simply using mod with more bits. But whether this would ever be a practical matter for developers using the Guava libraries is debatable.
  • Crinch exposes an extended Hash abstraction for generating multiple hash values for a single object called MultiHash. Guava performs a similar task within its BloomFilter implementation but entirely hides the implementation. I think this may turn out to be unfortunate because there are several different data structures that use multiple hashes (eg. cuckoo hash tables), and it seems artificial to accumulate them in the hash package without exposing a core abstraction on which they depend.
  • Guava provides clean and useful abstract base classes for implementing new HashFunctions in the form of AbstractNonStreamingHashFunction and AbstractStreamingHashFunction the use of a ByteBuffer in the latter is a particularly good fit. Crinch provides nothing half as useful, though it should.

On measure, I think Guava certainly provides a cleaner API, whether it’s more effective from the perspective of a developer writing an application is less certain. The important question for my applications is: does the cleaner API come at an unavoidable cost in performance?

I don’t know yet and I’m not implying it does; it could take a long while to find out.

This post turned out longer than I anticipated so finishing the preliminary benchmarking will have to wait until tomorrow.

Maybe, because mechanical engineering isn’t my area, I’m easily impressed by the elegant solutions to mechanical design problems that I find in everyday products.

This is a yo-yo (won by my daughter in a talent competition) that lights-up when it spins. No complex intertial sensors are necessary, just a spring that naturally flexes away from the centre of rotation.

Cheap, reliable and easily calibrated.

Another Metaglow icon effort

Since two people have made the same comment, I have to take it seriously, but I’m still having difficulty seeing the similarity to M&Ms. Yes, it’s an M in a circle - but so is the sign for the Paris Metro.

M&M'S.

This is a video of an effect I’ve developed for an android application I’m developing that will augment some of my existing applications. This is all done by combining the powerful 2D libraries with the flexible view APIs.

The video quality is poor - I still haven’t worked out how to film a mobile phone.

(Source: youtube.com)

A basic logo design combined with some genetically generated textures.

A basic logo design combined with some genetically generated textures.

I’ve given up at trying to get Blender running under Ubuntu (no number of window manager tweaks seem to have worked), so I’ve resorted to POV-Ray! We need to make those new hi-res android icons somehow right?

What’s great about POV-Ray for programmers is that it’s a very familiar environment: code, compile and run; and you get the full benefit of version control on your icon resources too.

It’s certainly not for everyone though. That I can realize a design using constructive geometry and a text editor just as comfortably as I can drag control points around in a vector graphics package, says something about me; I’m just not sure what.

I’ve given up at trying to get Blender running under Ubuntu (no number of window manager tweaks seem to have worked), so I’ve resorted to POV-Ray! We need to make those new hi-res android icons somehow right?

What’s great about POV-Ray for programmers is that it’s a very familiar environment: code, compile and run; and you get the full benefit of version control on your icon resources too.

It’s certainly not for everyone though. That I can realize a design using constructive geometry and a text editor just as comfortably as I can drag control points around in a vector graphics package, says something about me; I’m just not sure what.

Wireframing an Android App with Pencil

I’m mostly a pencil-and-paper kind of person for sketching out application ideas and wireframes; it’s as though my thumb, index finger and middle finger close together to form a supplementary neural network. So I have a lot of inertia to overcome when I try to use wireframing applications.

A couple of months ago Roman Nurik published some Android UI prototyping stencils and a few days ago I finally got round to trying them out. They are in the form of “collections” for Pencil a Firefox add-on for doing GUI prototyping. After a bit of messing around getting Pencil to import Roman’s collections on Ubuntu I started using it to wireframe a small app I that I’m building as a tool for my other apps.

After a couple of hours spent wireframing the application, I’ve been really surprised by how productive it’s been. Tools like Pencil are still not my kind of thing, but the prefab’ed controls make things very quick.

One problem with sketching out designs by hand is that it’s easy to make small errors of scale which cause you to waste time coding-up designs that look feasible but that just don’t work. Mocking-up the designs with correctly scale components avoids that (though nothing will remove the mental reasoning needed to evaluate designs in the context of varying devices).

Here are a couple of images. The first one is the wireframe I produced using Pencil, and the second one is the progress I’ve made towards implementing it. I’m fairly confident that things are going to work out well for this activity.

PencilAndroid

Efficient use of space in Android UIs

When I’m tussling with the design of a UI for an Android application, it’s often the case that I’m struggling to find some extra screen-space in at least one activity. So I’m always on the lookout for how other designers and developers have tackled the problem in their applications. Here are three interesting adaptations that I’ve noted as I’ve used my phone.

Music

I use the stock music player to listen to music, audio books and other recordings. I always get a little satisfaction from noticing how the application neatly switches the “Now Playing” control from being a button in portrait orientation into an extra tab in landscape, where vertical screen-space is always at a premium (also - nice attention to detail: gently separating the extra tab from the other standard ones).

Music portrait

Music landscape

StreamFurious

I’m a very occasional user of the StreamFurious streaming audio application. But I’ve used it enough to discover this gem.

Audio applications (like the Music app above) that play tracks into which you can ‘seek’, can elide “Stop” and “Pause” since there is no difference in how the track will be resumed: the application will just seek to the position at which play stopped/paused and start playing.

But applications that stream live radio can’t do this as easily. Pausing implies that the application needs to continue running, constantly buffering data from the stream until the user resumes play. Stopping, on the other hand, is generally taken as an indication that the application should cease reading the stream.

StreamFurious

StreamFurious avoids having two buttons (one for “Pause” and one for “Stop”) by retaining the regular Play/Pause button and using a long-press during play to fully stop the stream. Perhaps this is a common idiom, but it’s new to me and I find it elegant and intuitive.

GMail

Guessing from the approach taken, the developers of the GMail application on Android have particular difficulties with implementing a UI for it. Preserving GMail’s distinctive conversation view has resulted in HTML controls that masquerade as native Android components (I guess a list of web views was just too problematic).

In recent versions of the application, to make it easier for users to follow which email is currently being viewed within a conversation, the email header pops-up over the conversation below at exactly the point where the information would have been hidden by scrolling, and scrolls away at exactly the point where the email message ends. This is an efficient use of space, because the design ensures that the header is only occupying space on-screen at the same time as the email message it relates to (which is also the only thing it ever obscures).

Header in-situ

Header overlay

I think this is a really nice touch, and demonstrates the effort that has gone into producing some of these UIs, especially since I have a hunch that the overlay is produced using Android widgets and not HTML, which presumably means careful tweaking of both the HTML and the layout XML to make the switch between both seamless.

The Android Market has its deficiencies. I don’t think anyone would deny that. One of the niggles is that there’s no place to list the changes between application versions.

I think this is very important in Android applications because the limited screen space often necessitates moving access to core application functions into the menu. Users who are already familiar with an application may never discover a new feature that has been added to a menu that they opened once and never since.

Instead of lamenting the Android Market’s inability to display my application changes to users, I decided that the information was important enough to move in-app; in the past I’ve simply logged changes on my website. The design I settled on was to introduce a small notification at the top of my main application activity - about the size of a mobile ad - that appears if there is change information to present to the user. The user can tap the notification to read details about the changes in the latest version.

Not all updates will need explanations, so the user may not receive a notification on every update, and users can cancel a notification without bothering to read it. Accidentally dismissing the notification isn’t much of a concern since on the next update the user can page backwards and see the descriptions of previous changes.

This functionality will be included in the next release of Daisy Garden. I think it works well and I hope users like it; the use of animations to show and hide the notification adds extra bit of polish. And I’ve implemented it as a library project, so I’ll be able to introduce it into my other Android projects.

I think every developer should consider adding something similar to their applications.

ADC Judging

I’ve been meaning to post something about the Android Developer Challenge for a good while, but I’ve been so busy recently (architecting a multi-faceted e-commerce system at the moment) that I’ve had no time for anything else. In fact, I was so busy that the results almost passed me by.

Daisy Garden didn’t win. This was not surprising since I’d had an opportunity to judge a number of the applications in entertainment category. It’s not that I felt there were lots of significantly ‘better’ applications, but that so many of the applications were more suited to the challenge. Congratulations to all the winning entrants. My prediction had been for a music app 1,2,3 in my category and I was almost correct (it was a music app 2,3 instead).

But the results aren’t what prompted this post; I’ve been more interested in how the voting has been structured in both challenges, and I’ve had the opportunity to think about it: my entry into the first ADC flopped, then I joined a team that went on to win, this time round my entry made it to the shortlist but didn’t win - so I’ve pretty much run the gamut of possibilities.

I was mildly critical about the structure of the voting after the first ADC. In my opinion, it pretty much amounted to a map-reduce algorithm in which apps were distributed over judges. The ADC2 was essentially similar and introduced bucketing (perhaps ensure variety?) and pre-filtering with a public vote (to ensure the expert judges had a manageable task, I’m sure).

My basic criticism was, and remains, that such a voting scheme hampers people’s capacity to reach a good judgement because it doesn’t provide a medium through which they can influence each other’s evaluations. The judging process essentially atomizes the judges and fails to take advantage of their human strengths. And I think that understanding this has implications for my field of endeavour: creating software.

I think I’m paraphrasing Bjarne Stroustrup here when I say that software design involves balancing lots of subtle and complex considerations, and the best place to do that is inside the brain of a programmer. If one accepts this, there is an implicit assumption that all of the necessary considerations are known (and will fit into one brain*). I believe this perspective explains a lot about why ‘design by committee’ fails: a team of human’s can’t compete with synapses at transmitting and evaluating ideas. It also explains why ‘elite solo programmers’ may often fail: they can form good judgements but usually don’t have all the necessary data.

In trying to avoid the worst weaknesses of these two extremes, I look to encourage good design by:

  • encouraging everyone to share their ideas about what they think is the best design
  • observing which person best manages to keep all of the competing perspectives in their head
  • tasking that individual to come up with the design
  • validating the design by presenting it back to the team

With this approach I try both to preserve the clarity that solo-design frequently provides and avoid the narrowness that often accompanies it.

Back to the ADC judging. Forming an unqualified analogy between designing software and judging is application is clearly absurd, but there are similarities, and I think that a panel of judges who freely discussed their opinion about each application before recording individual ratings would provide fairer judgements than may have been the case in the Android Developer Challenge. For example, if there were five judges, and one judge knew that the application under consideration was a direct copy of an existing application, he could share that information with the other judges who could factor it into their rating. Without that exchange of information, the more knowledgeable contribution becomes marginalized.

The point is to target two human strengths: information sharing and individual decision making. Of course, the curse is that this approach doesn’t scale, but I’d love to find one that does, because I’m sure I’d learn a lot about designing software from it.

Thanks to Google for hosting and funding the Android Developer Challenges, it’s been fun.


(*) I think this is the simplest gauge of whether a software project will be successful: If the requirements can’t simultaneously fit into one brain then problems are unavoidable.