Index
Elsewhere
Navigation
Wednesday
May052010

Blogging again

I stopped blogging last year for two reasons:

 

  1. I'd started a new job and I had no time
  2. I was utterly sick of handling the spam comments. I was getting 1000+ spam comments a day and I just couldn't be bothered moderating them any more.

 

I've now moved my blog over to squarespace.com where the moderation tools are even worse, but the spammers are less likely to be able to get to me (hopefully).

Wish me luck.

 

R.

Friday
Aug212009

The Costa Coffee on the A91 to Stirling irks me greatly

Most mornings, on the way to work I stop off at the Cost Coffee on the A91 services. Most mornings I have a large latte. Some mornings, particularly if I had a heavy exercise session the night before and I'm feeling dehydrated, I'll order a large tea. This is where things go down hill.

Costa seem to not want to sell me a large cup of tea. They have cups, they have tea, they have water, I have money. But for some reason it is an issue.

When I order a large tea, a random selection from the following list will happen:


  1. I get it.

  2. They refuse to give me a large cup, telling me I can only have a medium or a small.

  3. The ignore my request for a large cup of tea and give me a medium cup.



Number one makes me happy, although my enjoyment of the tea is spoiled because of the tension from not knowing if it is going to be a hassle getting it.

Number two annoys the hell out of me, so much that I'd rather not have gone in.

Number three makes me really, really mad. You're deliberately giving me something that isn't what I asked for.

This morning was a #3 day and I lost my patience. As she was pouring water into a medium cup I turned and walked away. Walking away, never to return. I will not ever purchase anything from any Costa Coffee again.

I did a quick calculation, and I was on track to spending - between beverages and breakfast - close to £1000/year with them. That's enough money that, I finding the idea of not giving it to them satisfying. The fires of my wrath will warm me where their tea has failed.
Friday
Aug212009

I am Rob: Hear me roar!

...or at least talk. I'm appearing at the Epicenter conference in Dublin next week. I've got two sessions lined up:


  • Next Generation Languages for the JVM

  • Lean, Kanban and Theory of Constraints for Managers



Thursday
Aug202009

Something Cool, Something Not : Media Companies, Barcelona & Scrofula

I just stumbled across this very cool video. Irrespective of how you feel about aquariums, you have to admit it is pretty.

I really liked the song and, since there was a link on the page, I decided to buy it. But of course, Apple and the record company have decided that they don't want to sell it to me because I live in the UK.

If this was the first time I'd had such a problem, I would write it off as an aberration. But it isn't, it happens all the time and it really pisses me off.

I don't know anything about the record companies business model, or the realities of life as an up-and-coming artist - but if your business plan involves artificial market segmentation to the point where people can't buy your products.. you deserve nothing but scorn, poverty and, if all my wishes came true, some sort of painful and inconvenient ( but not necessarily fatal disease. I don't know what Scrofulous is, but it sounded funny when Terry Pratchett used it, so, for now, I'm going to hope for that.

Barcelona, keep up the good work, I hope the Scrofula doesn't get in the way of your singing, nor the poverty and attendant malnourishment distract you from your musical endeavours. I'm sure that the scorn will only aid you in your artistic struggle.
Thursday
Aug202009

Bob was REAL!!!

This intriguing article from Monica Harrington caught me by surprise for two reasons:


  1. Bob was real! I remember seeing MS Bob - way back when, but I genuinely thought it was a gag. I'm both flabbergasted and a little disappointed. For years I've thought kindly about Microsoft because I remember how hard I laughed.. discovering that it wasn't a cunning joke is... oh, my.

  2. There's a lot of wisdom compressed into a short article.



Monday
Jul202009

Estimation

Estimation: "They could say "



(From the genius that is xkcd.com.)

Wednesday
Jul152009

Eating Steak With A Spoon

Ending the Era of Patronizing Language Design



I linked, indirectly, to this article the other day and, after reading it again, I agree completely. Well, I agree completely with the notion that we should stop accepting "we didn't put that feature into the language because you're too stupid to use it" from language designers.

You really should read the comments accompanying the article, some are wise, many are interesting, unsurprisingly many seem to be commenting on a totally different article.

Now, what this doesn't mean is that every language should have every feature, it just means that presumed incompetence isn't an acceptable reason for not having it. Languages need to be designed with taste, discrimination and a desire to facilitate developer productivity.

For too long we have been told by programming language designers that we should eat our steak with a spoon because knives are too dangerous.

What sort of features am I thinking of here? Well, Java is a major culprit of the "you're too stupid" mindset.

Automatic memory management : This isn't the sort of feature I'm talking about. This is an enabling feature, something added to the language to help developers. Does it have drawbacks? Sure it does, there are times when direct-to-the-metal can be useful. But a decision was made here to facilitate in one area and compromise in another.

Operator overloading : Can it be used for evil? Sure. So can talcum-powder.. that doesn't mean we should ban it and force our babies to suffer from trench-nappy-region. There are many cases where operator overloading makes sense and its absence in Java is painful. Exhibit 1 'BigDecimal'.

Immutable Strings : Another case of "not what I'm talking about". Mutable Strings can be useful and powerful, but not having them brings advantages too. This was a conscious decision.

No meta-model : Without a meta model programmers dive into byte code manipulation and magical "doesn't work like anything else in the language" constructs like DynamicProxy. Can meta-programming be hard and weird? Sure, so is physics. Shall we ban that? It isn't the same, I hear you cry. You're damn right it isn't. Those guys created the atom bomb, and we still let/encourage/train/pay people do it. Heck we teach physics to CHILDREN. There are times in this world, when nuclear fission is just plain useful.

The list goes on.

Monday
Jul132009

Sharp vs. Blunt Instruments

Sharp vs. Blunt Instruments: "If you want your team to produce great work and take responsibility for their decisions, give them powerful tools."



(Via Glenn Vanderburg: Blog.)



Hallelujah brother Glen. Everyone say, "praise the power". C'mon now, say it with me, "praise the power".
Thursday
Jul092009

Appleby vs Hacker - Ooh, yeah. Run, don't walk.

As a tribute to Sir Humphrey, indeed the whole of the Ministry of Administrative Affairs, I shall endeavour to deliver this message in a suitably unhelpful format.

Sir Humphrey : "For those of you who've not seen it, and those of you who have - and therefor want to see it again - assuming, that is, the sanity, soundness, fitness, health, quality, control and general 'fit for purpose' utility of your mind, that is your brain, control centre, seat of consciousness etc. The greatest (a word I use not lightly, nor without appropriate consideration, contemplation and cogitation) comedy show of many, most, or indeed, perhaps all decades, including but not limited to those after the invention of television - although, of course, those decades before, preceding, that is, those that are, if you would, antecedent of the years and decades in question, are automatically disqualified on grounds of technical ineligibility which presupposes, induces and creates an inability to compete - has been released via iTunes."

Jim Hacker : "Sorry, what was your point?"

Sir Humphrey : "Yes Minister has been released on iTunes. And you should go and buy it"

Jim Hacker : "Yes Minister?"

Sir Humphrey : "Yes, Minister."
Thursday
Jul092009

Jack Cough : Scala Over Ruby - His Debate Ends - Mine Meanders Conclusion-ward

Jack Cough on Software: Scala over Ruby - My Debate Ends: This article struck a chord with me today.



I spent most of today flipping back and forward between Ruby and Scala. I'm working on a project where I'm writing some Ruby talking over sockets and streams and files and I needed something JVM flavoured on the other end.

The JVM end was just some driver code that was going in the bin. I had IDEA open because I was using it to write the Ruby side ( at which it is fantastic ) and a simple Scala script seemed easiest - that's where my head has been recently so it seemed most natural.

Things did not go so well - the embedded Ruby that I was using was badly mangled and had chunks of the standard libraries missing. I ended up spending the day bashing away at various ways of solving the problem. With each change of direction I had to rework both the Ruby and the Scala side of the solution. I noticed something odd.

Version 1.0 was a bit faster to write on the Ruby side. I'm a better Ruby programmer than I am a Scala programmer, but that aside I feel that it was slightly easier to express the problem than in Scala. But as the day went on the Scala code became easier to work with whilst the Ruby code had good and bad patches. Significant refactorings or changes of approach often led to runtime errors in the Ruby code. This wasn't a problem in the Scala code. The IDE, compiler and type system caught most of the problems well before I got the application running.

Have I abandoned Ruby forever? No, it is near and dear to my heart and it is still better for bashing out scripts for which there will be no version 2. The benefits of Scala didn't become apparent until 4 to 6 hours into the piece.

Some questions come to mind:

How well would the Scala fare long term? I don't know. It is possible that I won't understand it tomorrow and that every day will have a 4 to 6 hour ramp up time. But I don't think so. I think I'd reap more benefits tomorrow than I did today.

How would Java have fared? I worked on a similar problem the day before and I used Java. It was a pain in the patooty in many ways, but I'm not sure if it comes above or below the Ruby version though. Many of the same characteristics that Scala has were apparent in that session too. I am sure that I found the Scala experiment more productive - despite the fact that I'm a much, much better Java programmer than I am a Scala or Ruby programmer.
Thursday
Jul092009

Smart and funny... some people just make you sick

Thursday
Jul092009

Adventures with Scala and Vaadin - Part 6

I've jumped ahead in the book. The next few sections cover a variety of different components where we could use the same sort of tricks with closures and extension methods to make the interactions a little nicer but I don't think there'd be much value to that. I've skipped ahead to page 93 where we encounter forms for the first time.

Forms are interesting because they introduce bean-bindng - automatically associating form fields with properties of Java objects.

I'm a little surprised to find this in here, on one hand it feels like a step towards the 'Naked Objects' approach which I really like but on the other hand, I'm not sure why the Form abstraction is needed in a framework that has such powerful Ajax functionality. I have my suspicions that this is a holdover from an earlier time, a time when Vaadin was more request/response oriented. It is interesting nonetheless, and I'll see where it leads me.

I am expecting to run into some problems here. Scala code doesn't always look the way I'd naively hope from the Java side of the fence.

So, here we go. Version 1. Imagine we were building a Pirate administration tool...


package spike

import com.vaadin.Application
import com.vaadin.data.util.BeanItem
import com.vaadin.ui._

class Pirate {
private var name: String = ""
private var weight: Int = 0

def getName: String = {
return name
}

def setName(newName: String): Unit = {
this.name = newName
}

def getWeight: Int = {
return weight
}

def setWeight(newWeight: Int): Unit = {
this.weight = newWeight
}
}

class SpikeApplication3 extends Application {
override def init: Unit = {
val mainWindow = new Window("And now... a form.")

val form = new Form()
form.setCaption("This be the caption. Yes it be, it do!")
form.setDescription("What we 'ave 'ere is a tool fur the displayin' o' pirates.")

form.setItemDataSource(new BeanItem(new Pirate))

form.setValidationVisible(true)

mainWindow.addComponent(form)
setMainWindow(mainWindow)
}
}


That works pretty well. I defined a Pirate class and adhered to the gnarly Java syntax for defining Bean properties and, hey presto, we have a form with two bean properties nicely represented on it.

The property syntax is just plain fugly though. Let's get to the Scala pimp action.


package spike

import com.vaadin.Application
import com.vaadin.data.util.BeanItem
import com.vaadin.ui._
import reflect.BeanProperty

class Pirate {
@BeanProperty var name: String = ""
@BeanProperty var weight: Int = 0
}

class SpikeApplication3 extends Application {
override def init: Unit = {
val mainWindow = new Window("And now... a form.")

val form = new Form()
form.setCaption("This be the caption. Yes it be, it do!")
form.setDescription("What we 'ave 'ere is a tool fur the displayin' o' pirates.")

form.setItemDataSource(new BeanItem(new Pirate))

form.setValidationVisible(true)

mainWindow.addComponent(form)
setMainWindow(mainWindow)
}
}


That's much better. We've replaced the fuglyness with an annotation. This annotation is interesting. From a Scala perspective, it doesn't really do anything. From a Java perspective there's a world of difference. The annotation tells the scala compiler that the output should include Bean style getters and setters for the this property. In effect the annotation provokes the compiler into doing a chunk more work so that we don't have to.

I'm not happy though. I always hated the Java convention whereby beans should have no-arg constructors. The number of bugs that I've seen stemming from improperly initialised objects is, well, it's too damn many.


class Pirate(@BeanProperty var name: String, @BeanProperty var weight: Int)


There's our Bean class, replete with two arg constructor. I like it.

Another experiment. Scala's BeanDisplayName should be able to be used to change the label placed on the field - assuming the Vadiin developers have gone through the BeanInfo for the class rather than using simple reflection to guess at properties.


class Pirate(@BeanProperty var name: String, @BeanProperty var weight: Int) {
@BeanProperty @BeanDisplayName("Landlubbers put to the sword") var victims: Long = 0
}


Sadly this doesn't work. The field that appears in the form is labelled Victims rather than 'Landlubbers put to the sword'. Whether this is a hole in Vaadin, a problem with Scala, a problem with the Scala to Java integration or just because I screwed up I can't say.
Sunday
Jul052009

Adventures with Scala and Vaadin - Detour 1 "Comments"

In part 4 of the Scala & Vaadin series I threw in the line "I believe that comments are, for the most part, an abomination" without really explaining it.

There are a couple of comments on that post that I think explain my position - and other people's reaction - in more detail.
Sunday
Jul052009

Kanban v's Waterfall - The Craftworld Perspective

I was out shopping with my wife this morning. We popped into a craft store to allow her to pick up a few things for a project she's undertaking.

I noticed this :
IMG_0014.JPG


Which made me chortle a little. The fact that Kanban - Quality As Standard had made it into the realms of hand-crafted gift cards was surprising. Then my jaw dropped at the next card in the rack:

IMG_0016.JPG


Wow! Waterfall and Kanban, right next to each other competing. Then I noticed this:

IMG_0017.JPG


It turns out that nobody is buying Waterfall in the craft world. Nobody is buying it, no matter how it is packaged.

IMG_0019.JPG


IMG_0020.JPG
Friday
Jul032009

Adventures with Scala and Vaadin - Part 5

The next few examples in the book cover adding event handlers in more detail. I think we've beaten the 'closures are definitely the best way to do this' horse until it'd like us to stop so... I'll move farther on.

When we get to Chapter 5 we come across an interesting section on resizing components. All components implement the Sizeable interface. The sizeable interface has methods for setting the height and width of the component. There are two choices for each of these methods - set the value as a float along with a unit of measurement, or set the value using a String with the value and the unit.


component.setWidth(12.5, Sizeable.UNITS_EM);
component.setHeight("23%");


I don't find either of these choices to be that inspiring. Not bad, each is just a little sub-optimal, for my particular sensibilities. I'd rather type something that looks like


component.setWidth(7 pixels)


It is a small change, but one that I think makes the code look a little bit clearer, a little bit more expressive. So how do we make it work? Implicit conversions to the rescue. So what's an implicit conversion? In short, by explicitly importing an implicit conversion into a scope, you give the compiler the ability to transform one specific type into another specific type if it needs to. That's a hard sentence to understand, and it probably isn't even correct ( any Scala boffins that want to correct me, feel free ). In practice it is easier to understand. Here's the code that I've added to VaadinUtils.scala:


class Dimension(private val value: Number) {
def pixels : String = value + "px"

def percent : String = value + "%"
}

object Dimension {
implicit def intToDimension(value: Int): Dimension = new Dimension(value)

implicit def doubleToDimension(value: Double): Dimension = new Dimension(value)
}


And then in the imports at the top of my class I import Dimension._ and, presto, I can now use 21 pixels or 34.5 percent ( or 21.pixels or 21.pixels() ) in my code.

What's really going on? Well, as I understand it, when Scala sees an int with a pixels() method being called on it, it scouts around for an implicit conversion that it could apply that would make the code compile. Now, I'm sure that this sounds scary and dangerous, that's why Scala is very conservative about conversions.

You'll notice that I've had to define an implicit conversion for both Int and Double because Scala won't even perform that conversion automatically. One of the things I like about Scala is that it gives you power whilst trying to minimise risk. Neat.
Thursday
Jul022009

Is wanting to be paid such a crime?

Kent Beck asked some interesting questions around the behaviour of the software community with respect to 'getting paid'.

I've been irked by the behaviour of the community on this subject for quite a while. Personally I blame paranoid ass-hats like this. Harsh but...
Thursday
Jul022009

Clarification

It has come to my attention that people have misinterpreted my last story.

When they told me they wanted me to spend hours in focus group meetings, I laughed at them and walked away. Anyone who didn't would be in the low-wattage light-bulb category.

End of message.
Thursday
Jul022009

Why So Many TV Shows Suck

A few weeks ago I was on holiday in Las Vegas. In one section of the casino I was staying at, there was an area run by one of the big US TV networks where they were testing out TV pilots and newly shot episodes of TV shows.

As you passed by, they would stop you and ask you if you'd like to help them choose the future of TV. I thought it might be amusing, so I took a leaflet and listened to a thirty second pitch. Spending an hour watching a show and giving feedback might be fun - it was near the end of the day and I was tired and footsore from sightseeing.

They started out with "we'll give you $75 to go through our process".. hmm, that made it even more attractive. I can have a seat and a beer and pay for dinner with the proceeds. Then came the kicker. After watching the show, you have to participate in FIVE focus groups, each lasting an hour or so.

It turns out that the reason most TV shows suck is because the people who review them are morons. You're staying in a casino, paying two or three hundred dollars a night for a room, and you're going to give up a whole day to review a TV show for seventy five dollars. Anyone who's not a moron would conclude that this is a pretty bad deal.

Strangely, there were people queueing up to watch the shows... I looked at them, and judged them in the light of the information I had. I stand by my moron theory.
Wednesday
Jul012009

Adventures with Scala and Vaadin - Part 4

Firstly, I'd like to thank all the people who've said nice things about the first three parts - here, on twitter and on various news-groups. Of special note is Mark Harrah, the creator of SBT. Not only did he drop me a nice note, he made a change to SBT so that the issue whereby you couldn't usefully run jetty in batch mode is solved. Now that's service!

I'd also like to apologise to the people who've been reading my blog on the web. I realise that I need to change to a variable width column layout so that you can actually see all of the code. I'll get to it soon... honest.

Last time I promised I'd talk about continuous compilation and deployment. This is pretty complex, so try to keep up.

Normally to compile all the code and run jetty you'd type:


~/code/spike : sbt
> jetty-restart


Or some such. To get continuous compilation and deployment going you need to do this:


~/code/spike : sbt
> ~ jetty-restart


See the tilde on the second line? That's it. That sets up file watchers to watch for changed files/resources and executes the specified action when it detects them

Want to run your tests every time the code changes?


~/code/spike : sbt
> ~ test


I'm sorry if you'd like an XML configuration file or something similar. We're all out of complexity this evening, try again tomorrow.

Back to the Scala & Vaadin.

The next example, from page 40 of the Book of Vaadin is slightly more substantial. I'm hoping that Scala will let us make even bigger improvements to the code because we've more to work with.

The Java code:


public class WindowOpener extends CustomComponent implements Window.CloseListener {
Window mainwindow;
Window mywindow;
Button openbutton;
Button closebutton;
Label explanation;

public WindowOpener(String label, Window main) {
mainwindow = main;
final VerticalLayout layout = new VerticalLayout();
openbutton = new Button("Open Window", this, "openButtonClick");
explanation = new Label("Explanation");
layout.addComponent(openbutton);
layout.addComponent(explanation);
setCompositionRoot(layout);
}

public void openButtonClick(Button.ClickEvent event) {
mywindow = new Window("My Dialog");
mywindow.setPositionX(200);
mywindow.setPositionY(100);
mainwindow.addWindow(mywindow);

mywindow.addListener(this);

mywindow.addComponent(new Label("A text label in the window."));
closebutton = new Button("Close", this, "closeButtonClick");
mywindow.addComponent(closebutton);
openbutton.setEnabled(false);
explanation.setValue("Window opened");
}

public void closeButtonClick(Button.ClickEvent event) {
mainwindow.removeWindow(mywindow);
openbutton.setEnabled(true);
explanation.setValue("Closed with button");
}

public void windowClose(CloseEvent e) {
openbutton.setEnabled(true);
explanation.setValue("Closed with window controls");
}
}

public void init() {
Window main = new Window("The Main Window");
setMainWindow(main);
main.addComponent(new WindowOpener("Window Opener", main));
}


The free floating init() method is supposed to be placed into the Application class.

I've removed the comments and done a little tidying up of the structure: people have suggested that by not tidying the Java code in the earlier examples I was doing Java a disservice. I also removed the comments because I believe that comments are, for the most part, an abomination, a crutch that has removed the need for programmers to support their own weight and write clean code. As with most things, I could be wrong. I doubt it, but it is possible. I'm not egotistical enough to believe I'm never wrong. Just very, very rarely. Honest.

Transliteration:

package spike

import com.vaadin.Application
import com.vaadin.ui._

class WindowOpener(abel: String, main: Window) extends CustomComponent with Window.CloseListener {
var mainwindow: Window = null
var mywindow: Window = null
var openbutton: Button = null
var closebutton: Button = null
var explanation: Label = null
mainwindow = main
val layout = new VerticalLayout()
openbutton = new Button("Open Window", this, "openButtonClick")
explanation = new Label("Explanation")
layout.addComponent(openbutton)
layout.addComponent(explanation)
setCompositionRoot(layout)

def openButtonClick(event: Button#ClickEvent): Unit = {
mywindow = new Window("My Dialog")
mywindow.setPositionX(200)
mywindow.setPositionY(100)
mainwindow.addWindow(mywindow)

mywindow.addListener(this)

mywindow.addComponent(new Label("A text label in the window."))
closebutton = new Button("Close", this, "closeButtonClick")
mywindow.addComponent(closebutton)
openbutton.setEnabled(false)
explanation.setValue("Window opened")
}

def closeButtonClick(event: Button#ClickEvent): Unit = {
mainwindow.removeWindow(mywindow)
openbutton.setEnabled(true)
explanation.setValue("Closed with button")
}

def windowClose(e: Window#CloseEvent): Unit = {
openbutton.setEnabled(true)
explanation.setValue("Closed with window controls")
}
}

class SpikeApplication2 extends Application {
override def init: Unit = {
val main = new Window("The Main Window")
setMainWindow(main)
main.addComponent(new WindowOpener("Window Opener", main))
}
}


I've dropped this into a new file on my system src/main/scala/spike/Application2.scala.

To get it to run, you need to change the web.xml. Change the line:

<param-value>spike.SpikeApplication</param-value>

to:

<param-value>spike.SpikeApplicatio2n</param-value>

Yup, there's a 2 on the end of the class name now. Fire up the app and have a look - we're going to get pimping!

So, what do I want to change first? Well, if you look where the Buttons are instantiated you'll see something that made my skin crawl. In an earlier episode I talked about the ugly anonymous inner class usage, but mentioned that it was probably the best choice. Best of a bad lot in Java as it were. This is one of the other choices. The button is being instantiated with a target object and a method name so that the button can call the method when clicked. I know why people do this, I've done it myself and in Ruby or Smalltalk it'd be idiomatic, people would be prepared for it, and it wouldn't get messed up. In Java having method names as strings is always a bad idea. Amusingly, as if my sub-consience was trying to prove me right, I misspelled one of the method names not once, but twice. And when I ran the app.. it didn't work.

Using method names as Strings and calling them by reflection isn't a good idea. There are so many things that can go wrong - signature changes, misspellings, changes in visibility level, return type changes, exceptions etc. In Java, the belief that static typing protects you from these sort of problems means that developers just aren't prepared for it. Thankfully, the SButton class we created earlier solves this problem in a nice type-safe, statically defined way. Goodbye reflection invocation.

One of the ugly parts about using reflection is that the methods you're calling back to have to be public so that the reflector can see them. This leads to classes with odd "don't call me I'm not what you think" methods.

This class also implements the WindowListener interface because it needs to respond somehow, and some of the class' state is modified as a result of the callback. Implementing this interface here was the expedient thing to do, but it does mean that the class has a broader interface, implements an interface so that it can comply with the demands of its own internal workings and, if it wanted to listen to multiple child windows would need to jump through hoops to figure out which child window it was that was being close. I'm gonna get my closure tools out again.


package spike

import com.vaadin.Application
import com.vaadin.ui._

class SWindowCloseListener(action: Window#CloseEvent => Unit) extends Window.CloseListener {
def windowClose(event: Window#CloseEvent) = {
action(event)
}
}

class WindowOpener(private val mainWindow: Window) extends CustomComponent {
private val openbutton = new SButton("Open Window", _ => createSubWindow)
private val explanation = new Label("Explanation")

private val layout = new VerticalLayout()
layout.addComponent(openbutton)
layout.addComponent(explanation)
setCompositionRoot(layout)

private var subWindow: Window = null

private def createSubWindow: Unit = {
subWindow = new Window("My Dialog")
subWindow.setPositionX(200)
subWindow.setPositionY(100)
subWindow.addComponent(new Label("A text label in the window."))
subWindow.addComponent(new SButton("Close", _ => closeSubWindow))
subWindow.addListener(new SWindowCloseListener(_ => onSubWindowClose))
mainWindow.addWindow(subWindow)

openbutton.setEnabled(false)
explanation.setValue("Window opened")
}

private def closeSubWindow = {
mainWindow.removeWindow(subWindow)
openbutton.setEnabled(true)
explanation.setValue("Closed with button")
}

private def onSubWindowClose = {
openbutton.setEnabled(true)
explanation.setValue("Closed with window controls")
}
}

class SpikeApplication2 extends Application {
override def init = {
val main = new Window("The Main Window")
main.addComponent(new WindowOpener(main))
setMainWindow(main)
}
}


In the tidy up, we've gone from five instance variables down to four ( three of them immutable values), lost a constructor parameter that didn't do anything, created a nice little reusable listener class, removed risky reflection invocation and removed ALL of the new public methods and properties. The interface of our class is now identical to the interface of our super class.
Tuesday
Jun302009

Adventures with Scala and Vaadin - Part 3

Some Vaadin at last.

Download Vaadin from here and unpack it. You only really need the minimal one jar download, but with documentation this well written it'd be a shame not to grab it all.

They have platform specific downloads because some pieces of the underlying GWT toolset use SWT. As far as I can tell, there's no runtime platform specificity and I'm not going to be touching the GWT tools in this series, so don't worry about it.

From the download copy the vaadin-6.0.0.jar file ( hidden inside the WebContent directory if you downloaded the full installation ) into your spike/lib directory.

SBT adds any jars it finds in the lib directory to the classpath. Old-school styling baby!

And now some code.

The first "why don't you follow along at home" example from the Book of Vaadin is on page 24.

You need to configure the Vaadin servlet in the web.xml file. Sorry, back to the XML grindstone.

Insert this into the web-app element:


<display-name>myproject</display-name>
<context-param>
<description>Vaadin production mode</description>
<param-name>productionMode</param-name>
<param-value>false</param-value>
</context-param>
<servlet>
<servlet-name>Spike Application</servlet-name>
<servlet-class>com.vaadin.terminal.gwt.server.ApplicationServlet</servlet-class>
<init-param>
<description>Vaadin application class to start</description>
<param-name>application</param-name>
<param-value>spike.SpikeApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Spike Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>


The web.xml will now route all requests through the Spike Application servlet that's will look for the spike.Application class. I've changed the class and package name from the example to match the project and to keep package hierarchies short-ish.

The original Java code on the first example looks like this:


package com.example.myproject;

import com.vaadin.Application;
import com.vaadin.ui.*;

public class MyprojectApplication extends Application
{
@Override public void init() {
final Window mainWindow = new Window("Myproject Application");
Label label = new Label("Hello Vaadin user");
mainWindow.addComponent(label);
mainWindow.addComponent(
new Button("What is the time?",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
mainWindow.showNotification("The time is " + new Date());
}
}));
setMainWindow(mainWindow);
}
}


Not too bad. Particularly when you consider what it generates - a full page of HTML with a button with a server-side call back that displays the server time on screen in an area that fades out after a few seconds.

Not too bad, but I think Scala can do better. Stage 1 - Transliteration.

Create the application class:


~/code/spike : mkdir src/main/scala/spike
~/code/spike : touch src/main/scala/spike/Application.scala


Then edit the class so that it looks like so:


package spike

import com.vaadin.Application
import com.vaadin.ui._
import java.util.Date

class SpikeApplication extends Application {
override def init(): Unit = {
val mainWindow = new Window("Spike Application")
val label = new Label("Hello Spike Application User!")
mainWindow.addComponent(label)
mainWindow.addComponent(
new Button("What is the time?",
new Button.ClickListener() {
def buttonClick(event: Button#ClickEvent) {
mainWindow.showNotification("The time is " + new Date())
}}))
setMainWindow(mainWindow)
}
}


Start Jetty:

~/code/spike : sbt
>jetty-run

Then navigate to http://localhost:8080

Exciting - not so much. Still, the Scala here is pretty much identical to the Java code. It is nice to know that you can take a piece of Vaadin code and translate it without too much trouble. But if the Scala isn't any better - then Java would be a 'safer' choice.

Let's see if we can pimp this code.

Hmm, I don't like the inner class listener. In Java this is the best choice, in Scala we have more choices. Closures/Blocks/BlockClosures/Anonymous Functions/Lambdas/Anonymous Delegates/whatever you want to call them. to the rescue. We can create a button that takes a closure and never have to write one of those ugly little inner classes again.

Another thing that bothers me is that call to setMainWindow. Inheritance like this makes testing and TDD harder because I'm tied into the way the Application class works. I don't like that. That's not a game I'm going to play. I've an idea of how to extract us from that hole using abstract traits. But that can wait until I try writing tests.

After removing the inner class, slight blemishes in the rest of the code became more obvious so I've done a spot of in-lining and removed a few extraneous braces. I often find that once you can't see the little pimples until you've removed the massive warts. Anyway, the code now looks like this:


package spike

import com.vaadin.Application
import com.vaadin.ui._
import java.util.Date

class SButtonClickListener(action: Button#ClickEvent => Unit) extends Button.ClickListener {
def buttonClick(event: Button#ClickEvent): Unit = {
action(event)
}
}

class SButton(text: String, action: Button#ClickEvent => Unit) extends Button(text, new SButtonClickListener(action))

class SpikeApplication extends Application {
override def init: Unit = {
val mainWindow = new Window("Spike Application")
mainWindow.addComponent(new Label("Hello Spike Application User!"))
mainWindow.addComponent(
new SButton("What is the time?", _ => mainWindow.showNotification("The time is " + new Date)))
setMainWindow(mainWindow)
}
}


But, but, but, that's longer I hear you cry. Yes it is. But the first two classes can be pulled out and stored away somewhere and you're free of inner class event handlers for every button hence-forth.

The important part is the init method, isn't that much cleaner than before? You create a window, add a couple of components and pass it on.

For my money, this is a win.

Swap this code into place, execute a:

>jetty-restart

and take a look to make sure it hasn't changed.

Next time - continuous build and deploy and on to the next example.