Will Billingsley
I teach technology design (particularly, software engineering, human-computer interaction, Scala, mobile, and web development) at the University of New England. I do research in how we can design smart useful systems and make sure that reasoning machines aren't unreasonable machines. Especially in technology education and education technology. I also re-invent far too many of my own wheels.
Wednesday, 1 January 2020
New Year's Tentations
On the last day of last year, I hastily scribbled down my new year's resolutions. This time, I tried to keep it down to a few I might reasonably actually do. But what of the ones I'm really not so committed to?
Blogging a little more (to keep in the habit of writing) is something I'd kind of like to do, but not if it turns out to drain too much time from the things I do need to do. Especially as many of my blog posts are "thinking aloud" - thoughts I'm not especially committed to but seemed worth exploring (or at least getting out of my head) by writing down.
What do we call those little things we don't expect to stick to like glue but would like to try?
So, after thinking about antonyms for "resolute" I decided "tentative" seemed the most appropriate. And it so happens that "tentations" has a meaning too.
Apparently, in 1877, the Astronomer Royal George Airy had a method for adjusting ship's compasses that involved experimentally placing boxes of iron chain and magnets, and adjusting them until they cancelled out the magnetic influence of the ship's hull. (via the Practical Dictionary of Mechanics 1877, via the OED).
So, in honour of the tentative nature of the commitment (and George Airy's experimental method), one of my New Year's Tentations is to blog a little more.
Even if what I'm putting out there isn't much more sophisticated than hulking iron chains (and with much less direction than a ship's compass!)
Tuesday, 26 March 2019
Compromise
Once upon a time there was a family that happened to run a country.
"Let's go for a walk along the north bank of the river. It's just down the road," said David.
"No", said Boris, "Let's cross the river and go for a walk along the south bank."
"I insist we compromise," said Theresa, "and walk down the middle."
Two years later, having discovered that the compromise plan did not involve walking on top of the water after all, the country looked bemusedly at the assorted wetsuits, oxygen tanks, and weighted shoes they were being asked to wear to keep themselves on the firm bed of the river for their walk.
"Theresa," piped up one from the back, "I'm wondering if this might not be the best idea? I don't even have a diving mask and won't be able to see underwater."
"Oh for goodness sakes," replied Theresa. "You said you wanted to go for a walk, so we're going. Stop shilly-shallying, jump in, and I promise Michel will turn on your oxygen tank after you're underwater."
Friday, 22 March 2019
The Pogo Stick Strategy and other stories
Once upon a time, there was an office outing. Some people in the office wanted to go to Brighton, and some people wanted to go to Skegness. The manager said he really doesn't like Brighton, but he'll put it to a vote. He lost and said he couldn't really organise a trip somewhere he doesn't want to go.
"Who's going to lead us to Brighton?" the office staff asked. The Skegnessers scowled across the room at the Brightonites, still angry at the tone they'd taken in the debate.
"I'll lead us to Brighton," said one of the directors, who'd originally wanted to go to Skegness, "so long as you let me decide how we get there." The office murmured a bit, but as it sounded like a good compromise to let her lead them to Brighton they agreed.
"Right," said the director, pulling out a bullwhip and opening a cupboard. "Everyone take a pogo stick and lets get hopping down the road. No arguments at the back."
Two miles down the road, amidst a crowd of scraped knees, twisted ankles, and battered pogo sticks, one office staff member turns to the other and says "I told you going to Brighton was a bad idea."
Saturday, 14 April 2018
JavaFX out of Java 11
In somewhat recent news Oracle has moved JavaFX out of the standard Java install from Java 11. There is a certain fun that Donald Smith describes this as "making JavaFX easier to adopt by making the technology available as a separate download" — don't you always find having to download two things instead of one makes things easier... but that's not really what I want to chat about here.
I teach a couple of university courses that have usually used JavaFX: one in distributed software development, and another in functional programming in Scala. Not because we're particularly teaching UI programming, but because there are plenty of occasions where you're not teaching UI programming but still want students to be able to put something on the screen easily. It's in that context I'd like to say a little about JavaFX — the good, the bad, and the ugly.
I should perhaps also mention that I think that realm — just being so much easier — was Java's best route to being a relevant client technology again. I have this thing I need to knock up, do I set up npm, bower, etc, to do it in Electron -- nah, it's just a small thing at the moment, I'll just whip it up in JavaFX. And then just having a smooth progression where there just isn't a point where it feels uncomfortable to write your program in this toolkit. This is also where JavaFX didn't quite get it right.
Ok, enough rabbiting about the space I'd like Java UIs to sit in. How did JavaFX fare in my experience?
The good
The scene graph in JavaFX managed simplicity very well. I have a fairly common little demo that I write live in front of students for showing the concept of threads (as their Java unit doesn't always cover it). I put a spinning rectangle above a button, and have the button's action listener put the thread to sleep for 10 seconds. Instant frozen rectangle. Then we move the task onto a background thread, and the UI doesn't freeze. Five minutes, about twenty lines of code, gets the point across pretty well.
Hidden in there, of course, I'm doing some things Swing never really let you do. Mixing a shape primitive in a scene graph with controls (buttons). And as the rectangle spins its dimensions change but I don't have to worry about its drawing being clipped by its bounds. And the VBox I put them in just goes into the component graph, I don't have to deal with setting layout managers.
The bad
There's two places I think JavaFX fell down:
- Both times they created it (the old JavaFX 1 in JavaFX Script, and JavaFX 2), they had far too particular a model for how you'd do your UI. JavaFX 1 dictated what language you worked in. JavaFX 2 didn't, but see below with the observable lists, it very much packaged the programming model into the controls. It didn't have the neat separation that HTML5 does -- that the scene graph just does displaying the scene graph, and you can chop and change different frameworks for how you tie your data model to that.
- It tried to be too deep. Style your UI with CSS! Underlying every control there's a complex region model that lets you style multiple regions in every control! While this looked fun if you were really very interested in JavaFX, it meant that if you opened up the API documentation there was just so much of it. Separating what you could ignore from what you couldn't became a task for the reader, and it just looked scarily big for students that just wanted to whack some buttons, a canvas, and a graph on the screen.
The ugly
The part my students really found awkward was the controls. In 2017, I set the Scala students an assignment of writing a particle swarm optimiser. So that they could see it working, I also asked them to show various properties of the swarm at each frame of the simulation. That was supposed to be just a little prod in the assignment so students could easily see what was happening -- but it turned out they found writing the UI much harder than writing the particle swarm. Let's just highlight that for a moment:
A functional programming assignment, in Scala (a famously large language for students to get to grips with), and it turns out the fiddliest part is getting the UI to show some simple graphs on-screen. Hmm...
I think the issue there was that JavaFX's controls model is quite so deeply married to its observable lists. For students who are quite happy calling map on a sequence of values, to update them in one fell swoop, having to deal with code that says:
series.getData().add(new XYChart.Data(1, 23));
starts to looks weird. No, I don't want to get the data, I want to add a datapoint.... It's not that it's a lot of code, it's just that JavaFX imposes an opinionated mental model for how data in a UI should be updated, and if that's different to how you write the rest of your code then it's asking you to jump mindsets when you touch the UI parts of your code.
Where too next?
From outside Oracle, it does look like JavaFX has been put out to pasture. I used to have a cynical saying that when companies and governments fund projects, one of the things they really like about open source is that "we've released it to the open source community" sounds so much more successful end to a project than "we've dropped it like a stone".
Which is unfortunate, as in reverting to just supporting Swing until 2026, we've lost the simpler parts of JavaFX. The scene graph that just let you chuck shapes into VBoxes. Letting you paint outside your control's bounds if you want, so you can do things like have a row of buttons, but highlight one for some help text by circling it or making it wiggle. The slightly neater animation classes too. We've fallen back in time ten years to when the toolkit still got in the way for the simple but visually interesting stuff.
So what I'd like to see happen with JavaFX is for it to be modularised, rather than it being a big fat module put out to grass. For Oracle to back the scene graph to the hilt, and make sure you can add one dependency in gradle, and you'll get a really simple toolkit for putting together attractive little UIs, with the elementary controls such as buttons and text fields. Put the complex controls out to libraries, but putting some buttons and a canvas on screen, and making a button do a little dance so you can draw attention to it shouldn't be hard.
And, as seems to work for html, the frameworks can deal with different ways of tying data to code. The react-like ones that let your code appear relatively pure, and then do a diff on what's in the code. Or the reactive ones that treat every property like an observable that automatically updates its controls when you do. Or the d3.js like ones that treat it as sets of data that are new, changed, or removed. etc.
Tuesday, 10 September 2013
Building an assessment app in 2+ɛ days -- dealing with Heroku's slow Scala build times
(This post is retrospective -- students started using it yesterday.)
While Impressory is just running on an AWS instance, I put Assessory for our class on Heroku so that it would get an https address immediately *, and there wouldn't be a delay while I waited for DNS settings for a new domain name to propagate.
Heroku is a Platform-as-a-Service provider that uses a push to deploy mechanism. Add Heroku as a remote to the git repository, and then…
git push heroku master
…and Heroku will build and deploy your code.
This works for a number of platforms, including Scala Play apps such as this one.
In theory.
In practice, Heroku can be very slow building a Scala Play app, even one as simple as this, and it would regularly take longer than the 15 minute maximum that Heroku allows. In which case, Heroku would reject the push, and even though the update might only have been seconds away from going live, I'd be frustratingly bunted back to starting the deployment again.
The modular nature of the app, while great for keeping the code tidy, also seemed to slow down Heroku's builds as it has to go through an update cycle (resolving dependencies) for each of the modules as it compiles them. These seem to take a bit of time on Heroku.
Avoiding Heroku's long build times
The short answer to avoiding Heroku taking an age to compile an app (and often having to compile the compiler interface before it starts), it turns out, is this: don't let it compile it at all.
There's two ways of "not letting it".
Apparently there's an alternative build mechanism for Heroku called Anvil.
This uses Heroku's build packs on some other AWS servers. It seems to get around the timeout but still takes some time.
To be honest, I didn't get time to look at it until later, as I needed to get an update up quickly. When I did try it out, while writing this post, it did work -- though it took its merry time too.
The other is a hacky little workaround that involves almost no set-up, and is very much faster.
Don't push the Play app itself to Heroku. Instead, publish it as a JAR file to a Maven or Ivy repository. Play apps can be published as JAR files just by running this from sbt:
+ publish
This tends to be very fast because you've already compiled your code locally before you decide you want to upload it. (And your development machine is probably quicker than the AWS machines that Heroku builds on.)
Then we create a second, essentially empty Play app that has our real app as its only dependency. We're treating our app as a library that's used by a trivial wrapper app. (We include only a very few files that we need to be a valid Play app: application.conf, plugins.sbt, build.properties. Perhaps one or two others, but they are straight copies of the files in our "real" app.)
We push our wrapper app to Heroku, and Heroku will happily fetch our application code -- already compiled and packaged -- from the repository when it does its dependency resolution, as it would any other library. HTTP calls to the almost-empty outer app be served by the code in our JAR file -- including requests for the minified Javascript. Bingo, our app is up and running. Deployments take less than a minute because there is nothing for Heroku to compile.
If you're not keen on pushing your code to a public Maven or Ivy repository, then you can push it to a local repository that you include in the almost-empty Heroku app.
This second approach feels like cheating, but in practice the only downside I've noticed so far is that public assets (images) from our "real" app would now be served out of the JAR file -- which is slower than serving them straight from a file if the app wasn't packaged up as library.
But in Assessory there are only three images that get served anyway -- the cartoon drawings on the NotFound, Forbidden, and InternalServerError screens. (And as it happens I messed up the URL so they're not appearing in the dependent-JAR-file version because of a double // in the path. The image below is from the un-JARed version in a previous post.)
So I think for a while, I'm just going to put my few static images up somewhere else on the web -- perhaps in Cloudinary, and keep using this dependent app trick to make Assessory deployments fast.
* If a user accesses a site using http rather than https on a passwordless WiFi network (such as UQ's visitor WiFi), then it's possible to intercept their session key over the air. This is fairly well-known, and it's why Facebook, Google and others have moved to https only. For Assessory, where students are marking each other, I'd like to ensure that an https URL is available.
Monday, 9 September 2013
Building an assessment app in 2+ɛ days -- students started using it yesterday. (Going retrospective)
Students started using the app to critique each others' projects yesterday, as planned. Though I hadn't done a demo in the previous lecture as I'd hoped. So it wasn't two days, but it got there in time to be useful.
The screenshot below is from the form for editing the questionnaire -- as I was struggling to find screenshots that wouldn't reveal student data I should keep hidden.
For instance, if I clicked on "Allocations" I'd get a neet little list of which students are allocated to review which groups, whether they've logged in and linked their GitHub accounts, and which reviews they've started writing. But I don't want students knowing who is reviewing them, so I can't publish a picture of that to the web!
I guess another one I can show you is this:
Those pictures down the bottom are the GitHub avatars of users in those groups who have logged in (and the pre-enrol system has spotted them and automatically added them to their groups). The pictures are funny blocky images because these ones have been generated by GitHub for users who haven't set their avatar picture.
Most of the groups appear to be empty. This just means I took the picture less than a day after advertising the app to students. The pre-enrol system means that students are automatically added into their groups when they visit the course page. When I took the picture, 23 students had already logged in, but I cropped the image just before the first student who had uploaded an avatar (to avoid publishing people's photos or drawings on my blog.)
Going retrospective
Anyway, the next few posts will be retrospective -- looking back on the app that's been built rather than blogging as I go.
Friday, 6 September 2013
Building an assessment app in 2+ɛ days -- refining the concepts
The nineteenth commit is up, but it's high time I started discussing the design of the app itself.
(I think I've been through all the technical odds and ends. There's also support for server-sent events and websockets, but I'm not putting that in this app.)
Screenshot at latest commit
Trying to keep it simple, the app centres around Groups and Tasks in a course. So that's what students will see on the course's Assessory page.
It turns out there are some interesting relationships between tasks and groups.
The first task
The first task I'm going to need to write is the group peer critique task.
Students are in two kinds of group:
A Tutorial Group
There are two tutorial sessions, with approximately half the
class in eachA Project Group
Each project group has 3 to 5 students in it
(These categories correspond to "Group Sets" in Assessory.)
Groups are going to be presenting their work in the tutorial on Monday. That means that the critique task has to care about both group sets -- it has to allocate each student to review another project from the same tutorial.
If it allocated them the same project group, well you can't assess yourself; and if it allocated them a group from the other tutorial, they wouldn't be there to see the presentation.
The second task
When students critique each other's work, they also get to critique the critique.
The second task we want is for each student to read the critiques their group has received, and mark whether or not they were constructive and useful.
So back to it...
So, now all the course and group pre-enrolments are in and working, it's time to get these tasks written.