Images

clever-visuals-iMwiPZNX3SI-unsplash

Take me there

I love reading, but I don’t have time to “just read” so I tend to consume a lot of written material in “audio” format. This allows me to “read” while I do other things, like walking, driving, cleaning, and cutting the lawn. I “read” a lot of audio books, and follow a short list of podcasts. For the past year or so, I’ve also been experimenting with the latest in neural text-to-speech systems like Amazon Polly for converting blog posts into audio format so that I can listen to them during my walks. The results are surprisingly good. In many cases, I actually prefer the “machine” narration to a human narration. The voice is natural-sounding and consistent.

My favourite type of book (or blog post) is one that tells a true story, especially stories that intersect my personal lived experience. E.g. Stories about the birth of technologies that I use or remember. Insider accounts behind the scenes of movies or TV shows that I have watched. Memoirs of people who experienced certain events that remember living through. The more I “read”, the more specific my “tastes” become. You might say I’ve become more demanding of writers.

One of the most important qualities that I look for in writing is the ability to “take me there”. Books that give a mere account of what happened are barely better than reading a wikipedia article. I want a story to transport me into the time and place in which the described events occurred. I want to feel like a fly on the wall, so that I can imagine what it was like to be living in the story. Memoirs and personal anecdotes have a natural advantage for achieving this level of intimacy because the default is to see the events through the story-teller’s eyes. However, it is still possible to miss the target by focusing too much on sequence of events, and not enough on setting the scene and conveying how it felt to be there.

“The map is not the territory” is a well-known mental model that provides an analogy of what I’m looking for in a story. One way to explain this model is to consider that a map of Paris is not Paris. It is only a map the shows you where things are located from a birds-eye view. It doesn’t provide you with any information about what it feels like to walk the streets of Paris, or experience any of the historical landmarks. When I read a story, I want it to provide me with the territory. I can get the map off of Wikipedia or other reference sources.

My first exposure to this sort of story-telling was Console Wars by Blake J. Harris. It tells the story of the early nineties’ battles between Sega and Nintendo using a technique called as “Scene-based storytelling”. I had never experienced anything quite like it. It felt almost like I was living through a movie, as each bit of history was told through a scene. I don’t know how he was able to put together such a vivid picture the characters and conversations, but however he accomplished it, the end result was magic.

I immediately read his follow-up book History of the Future which uses the same technique to similarly vivid results.

These two books raised the bar for me, and I still have not found anything that quite “takes me there” like they do. I’m always looking, so any recommendations are appreciated.

More recently I’ve started “reading” the Mad Ned Memo, that includes stories from the computer/software industry by a 40-year veteran. His posts are always insightful, and usually combine a theme or timeless truth with some entertaining anecdotes. Not only do his stories “take me there”, they also take me back to my own parallel experiences in my early days of software development. I really wish I could find more content like this.

If you have done any type of software development, or participated in the development of long forgotten projects, I’d love to read about your experiences.

Photo by Clever Visuals on Unsplash

artur-tumasjan-42l3tjsJGyw-unsplash (1)

Star Wars and the Seven Laser Disc Players

Photo by Artur Tumasjan on Unsplash.

This post was inspired by the recent Retroist podcast on LaserDiscs.

A few years ago, I was browsing through the Twitter feed on my phone while waiting for the kettle to boil when I stumbled upon a news story about a community initiative to create a DVD version of the Theatrical Star Wars trilogy. I was momentarily surprised that this was news at all. Surely this has been available for ages now, I thought.

But a little bit of searching reminded me of the conundrum. When George Lucas re-released Star Wars in theatres in 1997, he monkeyed with them. He added scenes and lots of new computer imagery. And he made Greedo shoot first.

Of course, I knew all this, but I assumed that there must be a legit DVD version of the original, unaltered theatrical release available by now.

In fact, there was one version, included on a bonus disc in the limited edition DVD release of episodes IV to VI; but the quality is apparently disappointing because it was sourced from the 1993 LaserDisc release.

Upon reading the word LaserDisc, my mind wandered to the nostalgic realm of yesteryear when my friends and I would frequent the demo rooms at A&B Sound. There we would crank the subwoofer, cue up the T2 LaserDisc, and watch in bliss as Schwarzenegger blazed a trail through the Los Angeles viaduct system on his bad-ass Harley Davidson. LaserDiscs were a high-end luxury item that a kid like me could dream of, but never afford. Even if I could have scrounged up enough to buy a player, I’d quickly go broke from the cost of the discs – I recall that $100 per movie was pretty standard.

As my mind veered back to the present, it skidded over a slick patch, and a terribly wonderful idea was born.

That was like 25 years ago!, I thought to myself. I’ll bet I can pick up a LaserDisc player from Craigslist for almost nothing. And how hard could it be to find a LaserDisc copy of Star Wars?

What if… stay with me here…, I bought a LaserDisc player for the single purpose of playing the original theatrical release of Star Wars? It would be the new jewel of my home theatre – and I would be the envy of the neighbourhood. While all these other suckers were suffering through the lamely modified special editions, or adjusting the tracking on their degraded VHS copy of Star Wars, I would be enjoying the trilogy that started it all on LaserDisc!

The kettle was now boiled, so I poured it into the pot to start the steeping process. Then I resumed my planning for operation LaserDisc.

First stop, Craigslist, where I hoped to find a cheap player. I assumed I’d have to try eBay for the movies themselves. I typed in “LaserDisc” into the search field, pressed the “Search” button. To my amazement, the very first thing that came up was the Star Wars box set on LaserDisc! It was listed as part of a lot of LaserDiscs. Two boxes of them for $50.

The plan was only to get Star Wars. But $50 was well within my cost tolerance for a foolish impulse buy, so if they forced me to take the rest of the discs, then I wasn’t going to complain. I could have that LaserDisc collection that I had always wanted back in ’94.

The tea was finished steeping now, so I poured it into my mug, took a sip, and started plotting my journey to the pawn shop where the discs were being held.

When you are a parent of small children, you can’t just pick up and leave on a whim. You need to negotiate with your wife, first. Depending on the success of the negotiation you may end up with anywhere between zero and three travel companions. Best case scenario, is your wife has your back, and you can just walk out the door and seek your glory. The worst case scenario is that you have some obligation that you forgot about, and you can’t begin the mission at all. The other three possible outcomes are, in decreasing order of goodness are:

  1. You have three travel companions. Two half-lings and a wife.
  2. You have one travel companion.
  3. You have two travel companions.

It is worth noting that option 1, while being preferable to the other two, may involve a more rigorous preparation of rations, and thus it may take longer to get the wagons moving.

On this occasion, it would just be me and my almost-two-year-old apprentice, Apollo.

After finishing my Tea, I packed Apollo into his car seat, and we started off on our fateful journey.

We arrived at our destination about 40 minutes later. It was a small concrete building with barred windows on a fast and wide stretch of King George highway. There were no other cars in the parking lot, but there was a neon “Open” sign in the window, that gave me some assurance that I was in the right place.

Before getting out of the car, I took a quick glance around the neighbourhood, to assess whether there was any way I could pull this off without bringing Apollo in with me. The assortment of Tattoo parlours and questionable-looking passers-by, combined with the mild, but warm temperature forced my hand. Apollo would be joining me.

I unbuckled him, and lifted him out of the seat, then carried him to the door, which was locked. After ringing the door bell, we were buzzed in.

A guy behind the counter asked if he could help me and told him I was there for the Star Wars LaserDisc.

He pulled out two cardboard boxes from the back room and placed them on the counter. I asked if he would be willing to sell just the Star Wars, but he said he couldn’t. I didn’t protest much. I just pulled out my wallet and paid.

The trek back to the car was a multi-trip affair, holding Apollo in one arm and a box of LaserDiscs in the other. The two boxes fit nicely in the back of the car. Sometimes that “hatch-back” comes in handy.

And so the first act of our adventure was complete. We had secured our treasure. Now we just needed to acquire the player.

Sitting in the parking lot of the Pawn shop, I browsed through the Craigslist ads to see if there were any listings on my way home. There was one that was conveniently located in Cloverdale, about half way to home. The ad said he had seven laser disc players, and a whole bunch of movies. All I needed was one player. Perhaps he would be willing to do me a solid and break up the band for me.

“Which one do you want?”, he asked.

“Which one is the best?”, I replied.

“It depends”, he said. “One or two of them may not work – I don’t remember.”

I asked him to send me the model numbers so I could do a little bit of research. He sent me the list and I went to work trying to figure out which one would be best. Unfortunately, LaserDisc largely pre-dates the internet so finding specs on these models was difficult.

After a rather unfruitful ten minute rapid-fire Google session, I decided to just drive there and see what he had.

When we arrived at the guy’s house, he came out and met us.

“Let me show you what I have”, he said.

He opened the door to a storage room adjacent to the house. Inside there were boxes stacked floor to ceiling, and a smattering of electronics.

“Hold on”, he said as he forged a path through the stacks.

I followed him to the back of the room where he had two towers of LaserDisc players. Some of the units looked like they cater more to Karaoke, as they had microphone inputs, volume knobs, and Japanese writing on them. Others were more familiar (Pioneer) and looked like they were more appropriate for movie watching.

“Can you give me any indication of which one is the best one?”, I asked. I knew we had been over this ground earlier by text, but I thought that it was worth a shot to try again, now that we were face to face. Perhaps his body language would provide that extra bit of insight that would help me to decide.

He hummed and hawed a little.

“It’s really hard to say”, he said. “It has been so long since I’ve had them hooked up. I just can’t remember which ones work and which ones don’t”.

“I’ll tell you what”, he said. “Why don’t I just give you the whole lot for, say, $100?”

“Is that just the players, or for all the movies too?”.

I think he had been asking $250 for the lot in the ad – and he mentioned there were hundreds of movies and karaoke discs.

“The movies too”, he replied.

I thought about it for a moment. My gut said, hell yes! I want it all!. But my sober, responsible, self-aware inner adult wondered if this was, for lack of a better word, hoarding. I thought about the original, minimal vision that I had constructed for this project only 3 hours earlier, waiting for my tea to steep. “One LaserDisc player, and one box set… That’s it. That’s all I need”, I had told myself.

“Sounds good! I’ll take it all”. My hoarding inner child won the argument decisively.

Apollo sat patiently in his rear-facing car seat as cardboard boxes began to grow around him. Unfortunately the car reached maximum capacity prematurely, so we had to unload some of it and strategize ways to pack it in more efficiently. LaserDiscs abhor a vacuum, and we did their bidding by filling every possible space in that car. You’d be lucky to fit a baseball card in that car by the time were were done.

You’ll be relieved to know that I didn’t pile anything on top of Apollo. Beside, behind, underneath, but not on top. Though it did cross my mind.

“Don’t look at me, I’m hideous!”

That’s the first thing I said to my wife when I arrived home with a weighed-down car, bursting at the seams with obsolete analog media.

I had returned from the sanctum sanctorum with the ultimate boon: LaserDiscs with the original theatrical release of Star Wars, and a laser disc player.. And a few hundred other discs, and six more players.

Surely one of them must work, right? Right??

Stay tuned for the next instalment, where I test each player, disqualifying the ones that emitted bad smells and demonic sounds to settle on the one that almost worked perfectly. Then got it repaired for twice the cost of the entire rest of this adventure. And then bought two copies of Rocky III on eBay.

IMG_9578 (1)

Photo of me, by my wife.

Maven2iOS

Video: Building a Codename One Project for iOS

This is the third video in my series about our new online tool, Codename One initializr, which allows you to generate a Maven starter project for a native mobile app in one click. The first video showed how to generate the starter project, and run it in the Codename One simulator. The second video showed how to build and deploy the project on an Android device. In this video I show how to build and deploy the project on an iOS device.

TLDW (Too Long Didn’t Watch):

This video starts out with my Codename One project already opened in IntelliJ. See this post for steps on how to generate this project.

In the video I demonstrate two different approaches for building the iOS app.

  1. Locally (0:55-2:45) – Requires a Mac with Xcode Installed.
  2. Using Build Server (6:45-8:35) – Can be built on Windows, Linux, or Mac. With no special requirements beyond Maven and the JDK. You just need a free Codename One account.

NOTE: I also show how to generate your iOS certificates and provisioning profiles using the Certificate Wizard (2:45-6:45), as this is required to build apps for iOS.

Building Locally

The local build option generates an Xcode project, which we then open and build using Xcode.

To trigger this build, select “Local Builds” > “Xcode iOS Project”:

Screen Shot 2021-04-06 at 5.51.41 AM

Then press the “Run” button.

It takes the ParparVM compiler a minute or two to do its thing, but when it’s done, it opens the generated Xcode project in Xcode.

Screen Shot 2021-04-06 at 5.55.03 AM

Once opened, I press the “Run” button on the Xcode toolbar and wait while it compiles the project. When it is done, it opens the iOS simulator with my app running in it.

Screen Shot 2021-04-06 at 5.58.05 AM

Building with the Build Server

One of the nice things about Codename One is that it provides a build server with all of the native build tools installed and up-to-date. This simplifies the process of building native apps greatly. You can build your project for iOS, Android, Mac Desktop, Windows Desktop, Windows UWP, and Javascript without requiring any special build tools installed beyond the JDK. Building for any of these targets is as simple as pressing a button, or running a Maven goal.

Generating Certificates

Building for iOS requires that you have an Apple developer account. Additionally, Apple requires you to generate certificates and provisioning profiles for your apps. This is by far the most painful part of app development. To help ease the pain, Codename One provides a certificate wizard to help generate these. Before I can submit my first iOS build, I need to walk through the certificate wizard to generate these certificates. The certificate wizard process starts at approx 2:45 in the video, and runs until 6:45.

To access the certificate wizard, I need to open Codename One Settings. I do this by selecting “Tools” > “Codename One Settings” from IntelliJ’s configuration menu, then pressing the “Run” button.

Screen Shot 2021-04-06 at 6.11.27 AM

This will open The Control Center (aka Codename One Settings, aka Codename One Preferences):

Screen Shot 2021-04-06 at 6.12.53 AM

Once there, I select “Device Settings” > “iOS” > “Certificate Wizard” from the navigation menu on the left.

Screen Shot 2021-04-06 at 6.13.55 AM

This displays the login form for the certificate wizard:

Screen Shot 2021-04-06 at 6.15.40 AM

IMPORTANT: You need to use your Apple Developer account to login to this form. NOT your Codename One account.

In the video I spliced out some of the waiting time. The login can take a little while, so be patient. Once logged in, it shows me a list of my registered development devices, and I can select which ones I want to be able to deploy this app to for testing and debugging.

Screen Shot 2021-04-06 at 6.17.06 AM

The above screenshot has all of the rows greyed out. When you log in, you’ll see device names and UDIDs listed on this form.

Generally I select all of them. If this is your first time building an iOS app, then you may not have any devices listed yet, and you’ll need to click on the “Manage Devices” button and follow the instructions there.

Next, it asks me to confirm that I want to regenerate my certificates, as it has detected that I already have certificates generated in my Apple account. In my case, I say “yes”, I’d like to regenerate them, but in most cases, you would select “no”, to just use your existing certificates.

TIP: If your certificates were generated by the certificate wizard, then a copy of them has been stored inside the $HOME/.codenameone/iosCerts directory, and the wizard will use them automatically. If they weren’t generated by the certificate wizard, and you choose not to regenerate them, then you may need to specify the location of your certificates in the iOS Settings section.

Screen Shot 2021-04-06 at 6.25.52 AM

Next, it asks whether we want to generate push certificates. In this case, since this is just a basic Hello World app, we don’t need push, so I leave these options OFF.

Screen Shot 2021-04-06 at 6.27.38 AM

After clicking next, it will churn for a bit, and if all goes well, it will show us the message that our certificates were generated and installed successfully.

Just to be sure that my settings are saved. I click on the hamburger menu in the upper right, and select “Save”.

Screen Shot 2021-04-06 at 6.29.40 AM

Sending the Build

Now that the certificates are generated, we can send the build. Back in IntelliJ, I select “Build Server” > “iOS Debug Build”

Screen Shot 2021-04-06 at 6.32.38 AM

NOTE: If this is your first time building with the build server, you may be prompted for your Codename One username and password.

I then follow the progress of the build on the Codename One website.

When it’s finished, I get a set of links to do things like download the .ipa, or install the app on device.

Screen Shot 2021-04-06 at 6.34.32 AM

Get Started

Getting started with your own native app is really easy. Just go to the Codename One initializr, enter your app details, and press “Download”.

For more information about Codename One, see the Codename One website.

domenico-loia-1000x667

Deploying Apps on Multiple Form-Factors

Photo by Domenico Loia on Unsplash

The other day I stumbled across this post whose title seemed to suggest that Flutter is not a cross-platform framework.

Screen Shot 2021-04-06 at 10.08.33 AM

The thrust of his article is that, even though Flutter allows you to build your app for 6 platforms, that doesn’t mean that you should:

Yes, you can deploy your app on 6 platforms, but honestly, I am not planning to do so. Basically, because YOU SHOULD use different design patterns depending on the platform. I can’t imagine deploying my apps on a different platform.

At first glance, he appears to be arguing for writing separate apps for each platform (e.g. Android, iOS, Mac, Windows, etc…). This idea that you need to write a separate app for each platform using the platform’s native UI toolkit is widespread in the developer community. “Native Widget Maximalists”, as I call them, believe that using cross-platform UI libraries will result in a sub-par, “non-native” experience, and will, therefore, be rejected by the user. Generally, adherents to this philosophy are fine with sharing “business logic”, but the user interface must use the native UI widgets. Much of this dogma is based on dated observations of clunky, cross-platform, desktop apps of the mid to late nineties – many of them developed by novices using early incarnations of Swing.

Since that time, cross-platform toolkits have matured, and platforms have converged on some common UI design patterns. This is especially the case on mobile, where many popular native apps look nearly identical on Android and iOS. Mobile developers have realized that it is more important to create a nice, consistent design than it is to try to “look native”. Yes, there are differences between iOS and Android, but the differences are the exception – not the rule. In my opinion it is overkill to maintain two separate codebases for the 2% of the UI where they diverge. Better to provide abstractions that allow that 2% delta to be satisfied in platform-specific ways.

If you read further into the article, you’ll see that the author actually isn’t a “native widget maximalist”. I.e. He isn’t arguing that you should build separate apps for iOS and Android using their native SDKs. He isn’t even arguing that you need to write separate apps for iOS and Android.

Usually what works on mobile won’t work on desktop and the other way around.

What he’s saying is that you shouldn’t deploy the same app on desktop as you do on mobile, because the form factor is too different. If this is his thesis, then I agree with him… with some caveats.

Strategies for targeting multiple form factors

Disclaimer: I work for Codename One.

Two of the best cross-platform development tools for mobile development are Codename One and Flutter. They approach the problem of cross-platform development in very similar ways. Both provide 100% code reuse across platforms. Both provide a rich set of UI components and API abstractions for the underlying device capabilities, and both can be deployed to iOS and Android (and other platforms), as native apps. Codename One apps are developed in Java and/or Kotlin. Flutter, in Dart.

Both Codename One and Flutter also allow you to deploy your app as a desktop app. However, if you don’t tweak your UI for the larger screen-size, and desktop usage patterns, the result probably won’t be very good. Even using mobile apps on tablet feels forced if you haven’t customized the UI for the larger screen-size. There are four strategies I use when building a multi-form-factor app (i.e. an app that runs on mobile and desktop):

1. Responsive UI

Screen Shot 2021-04-06 at 10.26.54 AM

This is where the app logic is essentially the same across both form-factors, but the layout manager, and styles are “form-factor”-aware. E.g. On tablet/desktop they use different styles, and the layout managers position elements differently. (E.g. Instead of a hamburger button that reveals a side-menu sliding out over top of the form, the side menu is always visible).

2. Component-level abstraction

Screen Shot 2021-04-06 at 10.47.10 AM

This is where most of the app’s control flow is the same, but certain parts of each form are abstracted to allow for different implementations on desktop, tablet and mobile. This may involve using a different widget for editing some field, displaying some extra sections on desktop that aren’t visible on mobile. This is very similar to Responsive UI, and there is certainly overlap. The distinction is that with Responsive UI, you are keeping all of the same UI elements – you’re just rendering them differently. With component-level abstraction, the UI form may actually include different UI components with different logic on desktop than it does on mobile.

3. Alternate views

Screen Shot 2021-04-06 at 10.57.34 AM

This is where the app’s control flow is the same, but you create entirely different views on mobile than on tablet. If you are very careful with the design of your views, you may be able to reuse your controller classes, as long as the views share common APIs, and fire compatible events. Keeping them in sync can be challenging, so quite often you would also write separate controllers as well.

4. Separate control-flow

Screen Shot 2021-04-06 at 10.58.55 AM

This is where you are basically implementing two separate apps. You can reuse business logic, but the UI layer is written separately for tablet/desktop and mobile.

5. Separate apps

Screen Shot 2021-04-06 at 11.01.43 AM

If you are already implementing your app with separate control flow, then creating separate apps is just one small additional step. Generally you would still share all of your business logic between the apps. You would just provide alternate entry points for the different apps. With Codename One, this can be achieved either by moving all of the code into a shared library (cn1lib), or by simply providing an alternate configuration file (codenameone_settings.properties) that specifies a different main class. Most build targets use Proguard, or equivalent, to strip out unused code, so the app size isn’t impacted by the code-sharing.

Best choice?

It appears that the author of the article is arguing for option #5 – Separate apps. His preference, he says, is informed by his experience working on large enterprise systems where there would be different teams working on the apps for different platforms, and keeping it all in the same app would lead to toes being stepped on. Option #4 (Separate flow control) should adequately address his concern as well, since each form-factor would have its own package, likely, and developers wouldn’t need to tread on anyone else’s garden.

My preference is to use the lowest number on that scale that I can get away with, and progress up the ladder as required. IntelliJ makes refactoring from one strategy to another mostly painless, and the less fragmentation there is in the code-base, the easier it will be to maintain – generally. Obviously adding team members, or splitting the project into multiple teams changes that maintenance calculation.

Still prefer a cross-platform development tool

Suppose your team decides to implement separate apps for each form-factor (Mobile, Tablet, and Desktop). Let’s even go a step further and suppose that you decide to implement separate apps for each platform (Android Mobile, Android Tablet, iPhone, iPad, Mac, Windows, Linux). Then is there still any benefit using a cross-platform toolkit like Codename One or Flutter? Since you’re doing separate apps, wouldn’t it be just as well to just use the native APIs?

Unless you have an unlimited supply of time, developers, and money, then the answer is “no”. You would be much worse off by choosing to use separate native SDKs for each platform. Even if you manage to write some shared modules that you were able to share between the projects, the complexity involved in maintaining separate codebases is staggering. Everything is 7x more difficult. Every bug is fixed 7 times, and testing gets ridiculously complex. In addition, keeping up with the latest on all of these platforms and APIs takes dedication. You would likely need to bring in separate teams for each platform – and very little of the work can be shared between the teams.

Using a technology like Flutter – even if you are building 7 separate apps, would be far easier. Sharing code between projects is much easier, and every developer can work on every project without facing barriers to entry imposed by the idiosyncrasies of each native API.

Summary

Just because you can deploy your app to 8 different platforms, doesn’t mean that you should. Deploying to multiple platforms within the same form factor (e.g. phones) is a solid approach with a proven track record – with countless popular apps on the iOS and Android app stores currently developed with cross-platform tools like Codename One and Flutter. However, deploying to multiple form-factors (e.g. phone and desktop) is more difficult, as what works on one form-factor, may not work well on another. You may be better served by creating separate projects for each form factor, and sharing business logic between them. This doesn’t mean that you should drop your cross-platform development tool (e.g. Flutter/Codename One). Using such a tool is still a benefit as it reduces the combined project complexity, and makes it easier to share code and developers between the projects.

Maven2Android

Codename One Project -> Build Android App

In my last post I showed off the new Codename One initializr online tool, generating a Maven project, and opened it in IntelliJ.

In this video I demonstrate how to build an Android app with this project.

TLDW (Too Long Didn’t Watch):

Here’s the gist of the video. There are two different build options for Android:

  1. Build Server > Android
  2. Local Builds > Android Gradle Project

In this video, I start with option 2, “Android Gradle Project”. This option does NOT require a Codename One account, and performs all of the build on your local machine. It does require that you have Android Studio installed.

I select “Local Builds” > “Android Gradle Project” from the Configuration menu of IntelliJ, and then press “Run”.

Screen Shot 2021-03-30 at 9.25.41 AM

This generates an Android Studio project, and automatically opens it in Android studio.

Screen Shot 2021-03-30 at 9.27.42 AM

I then press “Run” in the Android Studio, and wait while it builds and installs the app on my Android Emulator.

Screen Shot 2021-03-30 at 9.29.25 AM

In the second part of this video, I use the “Build Server” > “Android” build option, which is much simpler, and doesn’t require you to install Android Studio. All you need is IntelliJ (Actually you don’t even need IntelliJ, as you could just build the project using Maven), and it will use the Codename One build server to generate the Android app.

After selecting “Build Server” > “Android” from the configuration menu, I press “Run” to start the build.

Screen Shot 2021-03-30 at 9.30.39 AM

It then redirects me to the Codename One dashboard where I can monitor the build progress and, download the app when it’s done.

Screen Shot 2021-03-30 at 9.31.37 AM

More Background

When we decided to migrate to Maven, we also made the choice to add official local build targets so that developers are no longer reliant on the build server to build their Android and iOS apps. Building locally has always been an option, but it was difficult, and we didn’t provide support for it. By adding an official local build option, we are hoping that developers who balked at Codename One because they didn’t want to be reliant on us for their builds will give us another look.

If you haven’t heard of Codename One yet, I encourage you to check us out. In my biased opinion, we are the best game in town, if you’re looking to build native mobile apps in Java or Kotlin.

It only takes a minute to create and build your first project using Codename One initializr.

Screen Shot 2021-03-30 at 6.45.27 AM

Preview: Online Tool to Generate iOS/Android app starter project

The Codename One initializr is an online tool for generating a Codename One starter project. You can select either Kotlin or Java, then you can download the project and open it in your local IDE.

In this 5-minute video I use the initializr to generate a bare-bones Java project, which I open and run in IntelliJ. I also give a brief tour of the project structure and build targets.

TLDW (Too Long Didn’t Watch):

Here’s the gist. Go to Codename One initializr, select either the “Java Bare-bones Project” or “Kotlin Bare-bones Project” from the “Template” select box, and press “Download”

Screen Shot 2021-03-30 at 6.36.39 AM

Extract the resulting project, and open it in IntelliJ (or your preferred IDE).

Screen Shot 2021-03-30 at 6.39.27 AM

Press “Run” and wait while Maven downloads the build dependencies. It will open the Codename One simulator with the simple “Hello World” app running.

Screen Shot 2021-03-30 at 6.41.00 AM

The project is a Maven project, with the following build targets:

  • iOS
  • Android
  • Mac Desktop
  • Windows Desktop
  • Javascript App
  • Windows UWP App,
  • JavaSE Desktop App
  • Xcode Project
  • Android Studio Project

In the video, I also demonstrate how to add a Button that, when clicked, opens a dialog. This is achieved by opening the common/src/main/java/com/example/myapp/MyApp.java file, and adding the following to the start() method:

Button btn = new Button("Click Me");
btn.addActionListener(evt->{
    Dialog.show("Hello World", "You Clicked Me", "OK", null);
});
hi.add(btn);

I’ll soon be posting some follow-up videos to demonstrate how to build and deploy the project to iOS and Android devices, so watch the RSS feed or follow me (wherever you receive my posts), to be notified when these are posted.

More Background

I’ve been working hard over the past several months to migrate Codename One from Ant to Maven. That process is now complete, and it has enabled us to introduce a new, simpler workflow for creating Codename One projects. The Codename One initializr uses our Codename One App Project maven archetype to generate a starter project. Right now we just have two starter templates: Bare-bones projects for Java or Kotlin. We will be adding more templates soon, including some templates for full-featured apps that you can take and customize.

I’ve very proud of this work, and I’m excited about some of the new things that it will enable.

If you’re a Java or Kotlin developer and you’re interested in making cross-platform native mobile apps, you should give Codename One a try. You just might be surprised at how pleasant the experience is.

Farewell-TenFourFox

Farewell to TenFourFox

I was saddened by the news that development on TenFourFox, the Firefox port for Mac OS X 10.4, will be ending with its upcoming release.

I keep several old Power Macs running 10.4 (which is the last version that will run Classic), and the TenFourFox browser is a staple of my “bootstrap” CD. I don’t use it much, as browsing the web on these old Machines is pretty slow, but it gave me joy just knowing that somewhere out there, someone was keeping the flame of these old computers alive. I liken this feeling to knowing that my childhood home is still lived in by my parents – the feeling that if I returned to visit, everything would be there as I left it, and I could, if only for a brief moment, be a child again.

To the developer behind TenFourFox, I’d like to wish you the best in your retirement. Thank you for your service all these years.

1586687737_889e0df3d8_b

The Water Fight

This is my account of the epic indoor water fight of 1989 that laid waste to Mr. Galvin’s grade 4 classroom. Enjoy

Our classroom looked like an exhibit at the BC history museum. The north wall was covered with a landscape showing the exploration of the “new world” by Europeans like Jacques Cartier. This mural was constructed using an adaptation of the Bob Ross method, whereby we staple the background elements (land, ocean, and sky) to the wall first, and then proceed to add the foreground details, including lots of happy little trees. First and backmost was a layer of light-blue wallpaper representing the sky, which stretched all the way to the ceiling. Covering the bottom half of the mural was darker blue paper representing the Atlantic ocean. Its top edge was cut into waves, and it was book-ended by two brown landmasses resembling the foothills of mountains rising out of the ocean. These brown mountains represented Canada on the left and Europe on the right.

Mr. Galvin had set up the background on his own, but he left it to the class to populate it with happy little trees and the like. The mural was littered with cut-out drawings of ships, forts, people, buildings, tee-pees, bears, and just about anything else that could possibly spawn from the imagination of a nine-year-old when provided with such a juicy blank canvas. Mr. Galvin didn’t tell us what to draw, or how to draw them. The only rule was that it had to be “appropriate”. Drawings were colored using paint, crayons, pencil crayon, and felt marker. A drawing, once approved, would be stapled to the mural by Mr. Galvin.

We started building this mural in September, and continued to develop it throughout the year. At the end of the school year we were told that they would be transporting it to some other location, like the school district offices, so that it could live on. It represented a significant amount of work, and we were all very proud of it.

On the other side of the class was a science fair exhibit which was a little less grand, but also involved lots of paper-based artwork and diagrams. The class had been split into groups of five or six for this science fair. A section of table had been allocated to each group to display their project. Most of the projects consisted of charts and diagrams glued onto some brightly colored paper. Some exhibits also included three-dimensional visual aids that had been constructed out of materials such as popsicle sticks and egg cartons.

It is relevant to the remainder of this story that neither the mural nor the science exhibits were designed to withstand water damage. It is also relevant that our classroom had a sink.

That night, the school would be hosting the annual Spring Peterson Road Carnival, but it was already set up in the gym, and classes had each been designated a time when they could come down and “preview” the carnival during the day.

It was about to be our turn.

“I expect you all to be on your best behaviour”, said Mr. Galvin with his Liverpool accent. He sounded like one of the Beatles.

After he had finished delivering his pre-carnival “expectations” speech, Mr. Galvin directed us to line up at the classroom door. Then he led us down the stairs to the gym where we were set free.

The perimeter of the gym was lined with attractions that were being operated by aspiring carnies (i.e. grade seven students and parent volunteers). They had the usual stations you would expect to find at a fair, from the fishing exhibit (where you throw your clothespin fishing rod over a sea-themed bulletin board, and hope to catch a prize), to the dunk tank (where a teacher who probably drew the short straw, sits precariously on a plank above a water tank and waits for students to throw balls at a target).

My personal favourite was the floor hockey station so that was my first stop. After a short wait, I was invited to step up to the line that had been taped onto the floor. Then the carnie handed me a plastic hockey stick, and placed a bright orange plastic puck onto the line. I dragged the puck back and forth a few times with the stick to get comfortable and looked toward the net, which was about fifteen feet away. It was blocked by a wooden piece of plywood with a hole cut out of the bottom just big enough for a puck to fit through. I released my first shot, and it thudded off the sieve, about a foot off the mark.

“Oh so close!” said the carnie. “Don’t worry, you get two more tries”. Then he set up another puck.

I don’t recall how many tries it took, but eventually I threaded the needle, and was allowed to claim a prize.

The prize vault was a plastic milk crate filled with an assortment of brightly colored plastic goodies and candies. I quickly scanned over the rings, and plastic spiders before settling on a tiny lime-green water pistol.

I completed the circuit, and then Mr. Galvin directed me to return to class. Our departure from the carnival had been staggered and, for whatever reason, Mr. Galvin was the last one to return to the classroom.

Upon my arrival, I discovered that nearly every boy in the class had also won a water pistol. There we were, a room full of nine-year-olds armed with water pistols, in a classroom that just so happened to have a bottomless supply of munitions. For a few minutes we all sat in our desks, harmless powder-kegs awaiting our teacher’s return. Then, someone lit the fuse. A single boy, I don’t remember who, walked up to the sink, and filled up his water pistol.

Then another boy did the same, and they started squirting at each other.

“They are going to be in so much trouble”, I thought, watching these two fools dueling toward certain doom.

But then another boy joined in. And another. Before long it was full-on war. Boys would be ducking behind the science table, then pop up to squirt their enemies, then duck again to avoid the return fire.

I didn’t participate right away, but every boy has his threshold beyond which the temptation to follow his friends off a cliff is irresistable. I rose from my desk, walked over to the sink, popped the cap off the top of my pistol, and ran the water over it. Once it was filled, I pushed the cap back on, and dried the gun on my pants. Then I found a corner that could be easily defended and engaged in the fire fight.

Streams of water arced through the air, splattering the mural, the chalkboard, the science table, and just about everything else in the room. Boys ran with glee around the perimeter and through the rows of desks with their pistols cocked imagining we were living in an episode of GI Joe. We even made the “pew pew” sound effects to accompany our shots.

This continued for a glorious 2 or 3 minutes before we were rudely interrupted by Mr. Galvin’s booming voice.

“What is going on here!”, he yelled with a ferocity that I had never heard from him before.

Instant silence, except for the shuffling of feet of students trying to quietly return to their desks where they could feign innocence.

“Everyone who was involved in this, come up and stand at the front of the classroom”, he continued, in a stern but more controlled tone.

One or two students rose from their desks and sheepishly walked up to the chalk board and turned around. I resisted this first alter-call, as did most of the other boys.

“That’s all?!!”, he yelled incredulously.

And that’s when the fingers started pointing. The boys who had answered the first call started calling out their co-conspirators, and a few of the conscientious objectors to the great war began reciting what they had witnessed in such great detail that there was no denying the war crimes.

Ultimately there were about fifteen of us standing up in front of the chalk board with our hands in our pockets and heads hanging in shame over what we had done.

“Hands out of pockets and stand up straight!” he ordered.

He then proceeded to admonish us for this episode. Some key themes of his speech were betrayal of trust, destruction of property, lack of respect, and responsibility. It must have been a good speech because I felt ashamed. During his tirade, I looked around the wasteland we had left behind on the battlefield. The full extent of the damage was not yet known since the water had yet to dry, but there were already many cases of felt marker drawings bleeding and smudging.

He ordered us all to detention that afternoon. I don’t think there was a single girl among us.

necessary_roughness

Date Night

Beverly sorted the DVDs in the furnace room a couple of weeks ago, and, as a result, there is a stack of DVD cases sitting on the floor of our basement. Topmost in this stack is “Necessary Roughness”, the 1991 football comedy starring Quantum Leap’s Scott Bakula with a talented supporting cast that included SNL’s Rob Schneider (“Fumblaya, Fumbleroosky!”, Deuce Bigalow, etc…), Sinbad, Jason Bateman (Arrested Development), and lots of other familiar faces from that era. Seeing that case reminds me of the first time I saw the film at Willowbrook 6 cinemas on its opening night, way back in 1991.

Ads featuring the catch phrases and slapstick moments from the film started to blitz the airwaves late in the summer between grade 6 and 7.

“I can’t wait to see that”, I said to Ezra, probably while watching one of its TV commercials. “It looks like Major League, but for football.”

“Sergeant Fumblina Wilkerson fumbles the ball!”, he replied, quoting the film.

We recited a few more of the catch phrases, laughing at each other after each impression.

“You should ask Christina to go”, he suggested.

I paused for a moment to ponder the practicality of this idea. Most people don’t know this, but Christina was my first verified reciprocated crush. In case you’re not familiar with that term, allow me to explain.

To borrow a phrase from the Wonder Years, a “crush” is when you “like like” someone.

A reciprocated crush is when you have a crush on someone, and they also have a crush on you. However, you may not know that they have a crush on you – and they may not know that you have a crush on them.

A verified a reciprocated crush is when you have a reciprocated crush, and both parties of the crush are aware of it.

I had had crushes before Christina, and I may have even had reciprocated crushes (unbeknownst to me), but she was my first verified reciprocated crush.

Our story began four months earlier, in Mr. Wiebe’s grade six class. Christina was new to the school, joining our class mid-way through the year. I was just becoming “interested” in girls for the first time, but I didn’t have any clue how to navigate around the obstacles that were blocking the “friend-zone” exits. Christina, being new, was not afflicted with this complication, which was a big feature. And she was pretty.

I decided to make “my move” one May afternoon after school. I was doing a tour of duty as the desk monitor, so I had to stay behind for a few minutes after class with a clipboard to inspect all of the desks to make sure they weren’t messy. If I encountered a “messy” desk, I was entitled to give them a “ticket”. I don’t recall if I made my quota that day, but by the time I was finished, there was just me and one other student left in the class. This was my chance!

I placed my clipboard on Mr. Wiebe’s desk, then proceeded to the cloak-room, where I slowly placed a few things into my bag and donned my jacket. I paced myself so as to exit the classroom at approximately the same time as the other student. We descended the steps outside the door and continued to walk together towards the bike racks at the front of the school.

And that’s when I made my move.

“What do you think of Christina?”, I asked Ben (the other student).

Sure, I could have just talked to Christina directly, but that would have been risky! (What if she said “no”, I just don’t think I could take that kind of rejection! — George McFly, 1955)

I call this move “planting the seed”. It didn’t come from any playbook. I was freestyling.

“Why? Do you like her?”, he replied in an “oooh” tone as if he had a script.

I made a dramatic pause, to make it seem like I was reluctant to divulge this information. Then I responded with “Maybe”.

“Oooh. That means that you do like her.”, he gently teased.

“Well I guess so”, I confirmed. “But don’t tell anyone”.

Mission accomplished! Now all I had to do was sit back and wait until, inevitably, Ben divulged my secret to someone.

Amazingly, things unfolded exactly as planned. Approximately one week later, I was approached by a couple of girls on the football field with tidings of great joy.

“Do you like Christina?”, they asked. “Because she likes you, and she thought that you liked her”.

That was good enough for me. I confirmed to them that I, indeed, liked Christina, and they were free to share this information with her.

Messengers dispatched with my seal, I was free to resume the lunch-time football game that was underway.

Now, if my “playbook” were a physical book, this is the point where I would turn the page only to discover that the next page is blank. Then I would fan through the remaining pages until I reached the back cover, to confirm to my horror, that there were no more plays in this book. I didn’t think I would get this far, and now I was something of a victim of my own success, as I didn’t have any idea how to proceed.

“Should I go talk to her?”, I thought to myself. That would be too eager. Eventually I would have to talk to her, but for now, I reasoned, it was much better to limit communication to smiles and waves. That way I couldn’t say anything wrong. I mean, I might as well stick to the fundamentals that got me this far. I would let my football do the talking. Surely she would notice all of the touchdowns I was scoring during lunchtime games, and that would impress her.

I basked in the glow of this new world for the next couple of weeks. Everything was going smoothly. I still liked Christina, and, as far as I knew, she still liked me, and that was good enough for me. I planned to wait until the perfect moment to spring my first conversation on her. That moment came during the school field trip to Stardust roller rink. I waited until the day was almost over, then I rolled up beside her and asked if she wanted to skate. She said yes.

I held out my left hand, and we began to skate together under the disco lights. Finally the time was right for our first conversation to occur.

I looked at her and said “I don’t really like this song”. And she looked back into my eyes and said “What??!, I can’t hear you”.

I replied with “nevermind”.

With the pleasantries out of the way we proceeded to skate around the oval, as if we were the only two skaters on the floor. I learned later that Ezra and Stephanie were skating behind us for the whole song laughing (secretly) at us.

After the song ended, we went our separate ways.

I learned a few weeks later, through the grapevine, that she didn’t like me anymore. When I inquired why, I was told that she had said that “we had nothing in common”.

“How could she possibly know that we had nothing in common?”, I thought to myself, in dismay. “We had never even really talked.”

I made a mental list of the things that I knew about her to see if I could identify any common interests. I knew that she liked horses. At least I think that she liked horses. I didn’t really care for horses. Didn’t hate them, mind you; I just wouldn’t call myself a horse person.

“Well”, I thought, “maybe she’s right. Maybe we are just too different.” This was a bitter pill, but I had no choice but to swallow it.

Now that you’re up to speed on the “Christina” back-story, I’ll return to Ezra’s suggestion that I should ask her on a date.

“That would be too weird”, I said to Ezra. “My dad will ask who I’m going to the movie with, and if he finds out it’s a girl, he’ll make fun. Why don’t we do a double date thing? You can ask Suzanne or Stephanie, or someone else to go with you, and then we’ll all go together.”

Making it a double date would accomplish multiple things. Firstly, it could be presented in a more casual light, so I wouldn’t have to stand on the precipice of rejection. Second, it was possible that Ezra could open the negotiations, and save me the agony of having to “ask” entirely. And finally, it would make the experience on the date less stressful, as I wouldn’t be relied upon to participate in every conversation. I could chime in when I felt comfortable, but I wouldn’t bear responsibility for long awkward silences.

Ezra agreed, and we put the plan into action. The next day at lunch time, Ezra informed me that he had talked to a few girls, and that the movie was on. Only, it wasn’t going to be a double date as we had originally planned. Four or five girls in the class had already expressed interest. It was just a matter of finding the right matches, since this was going to be a “date night”. Over the next few days matches started to form, and before I knew it, our little double date had grown into double digits, with 5 or 6 couples pledging to attend.

This little idea had transformed into something like a highschool dance with boys trying to summon the courage to ask a girl, and girls patiently waiting to be asked.

A week before the big day, I still hadn’t asked Christina. I’m not sure what I was waiting for. Perhaps I was waiting for a message from the heavens to assure me that the time was right. Unfortunately, when the message finally came it was different than I expected.

“Steven, you better hurry and ask Christina”, Ezra warned me during recess. “I heard that Rob just asked her, and that they are going together.”

“What?!!” I exclaimed, experiencing a small amount of genuine shock. This was my fault. I had waited too long. Part of me was relieved as I was now absolved of my obligation to ask her myself. No rejection required, and I didn’t technically “chicken” out. It was out of my hands. Oh well.

But then, at lunch time, opportunity reared its ugly head. I was warming up in the gym for lunch-time floor hockey, when Rob approached me.

“Steve, can I talk to you”, he asked.

“Yeah, sure, what’s up”, I pretended to not know what this was about.

“I heard you wanted to go to the movie with Christina”, he said. “If I had known that you wanted to go with her, I never would have asked.”

“That’s OK”, I assured him. “I was just too late”.

“If you want, I can cancel with her, so that you guys can go”, he offered.

I had already made peace with my loss, but this offer seemed like it was too good to pass up.

“Wow! You’d do that?”, I replied. “Thanks man”

That set the stage for my second conversation with Christina. That afternoon, she pulled me aside in the back of class. “Can I talk to you for sec”, she asked.

“Sure”, I replied.

For a brief instant I thought that this would be the magical moment when we would, once again, profess our mutual affection for each other, and make it official that we would be attending the movie as a couple.

I was wrong.

“How dare you make a deal behind my back!”, she said sternly. “I am not some piece of property that you can trade.”

She said other stuff too, along the same lines.

The gist of her monologue was that we weren’t going to be going to the movie together. She would be going with Rob per the original plan.

I handled this rejection with grace, since I had already previously accepted this the first time I heard it. And, I could see her point. But now I faced a new challenge. With only 4 days to go until the movie, I still didn’t have a date, and now I didn’t even have any prospects. I suppose I could have just gone by myself, but that would have gone against the entire concept of a “date night”. Everyone had to have a date.

Luckily, on Tuesday, the universe intervened. Suzanne suggested that I should go with Gail because she also didn’t have a date. Gail was nice and pretty, so that sounded fine to me.

Friday was movie night. My dad dropped Ezra and I off at the Willowbrook 6 box office for the early show (7pm-ish). Once inside the door, we saw Suzanne, and a couple of other kids from our group standing watch in the lobby.

“Necessary Roughness is full”, she informed us. “Only half of us can fit in there. So some of us are going to watch City Slickers”.

To paraphrase the late great Hannibal Smith, I hate it when a plan falls apart. I had seen City Slickers a few weeks prior. It was a good movie, but I didn’t want to see it again.

A lesser man might have lost composure upon hearing this news – screamed, cursed, pushed over a popcorn wagon. But I somehow managed to keep it together, while Suzanne continued to brief us on the situation.

“… We have a row blocked off in Necessary Roughness”, she continued, “and there are two seats left….”

“Hallelujah!”, my inner voice screamed. “It’s too bad we have to split up, but at least I can still watch the movie I came to see.”, I thought. This was a silver lining I could hang my hat on.

But then, the boom dropped.

“Gail is already in City Slickers.”, Suzanne added. “She’s saving a seat for you”.

There is a scene in Good Will Hunting where Robin Williams’ character is telling Matt Damon’s character how he met his wife. He had been entering the gates of Fenway park for the historic game 6 of the 1975 world series, when the most beautiful woman he’d ever seen caught his eye as she was walking away from the stadium. It was love at first sight for him, so he relinquished his ticket, and went after her. Damon’s character, astounded by this, asks if he ever regrets this decision. “Not even when she (eventually) died of cancer”, he responds. (Or something to that effect).

Good Will Hunting didn’t come out until 1997, so it was not available to my decision-making algorithm on this 1991 Friday night. Had it come out ten years earlier, perhaps it would have granted me the perspective to see beyond my immediate desire to watch Necessary Roughness. Perhaps I would have chosen to join my date in City Slickers, and it would be such a life changing decision that I would never have any regrets about what I had sacrificed to sit with her. But it didn’t, so I was wholly unprepared for this dilemma.

I could hear the trailers start to play, so I knew I had to make my decision quickly. I mean, I guess I was sort of obligated to sit with my date…. But on the other hand, it didn’t seem fair to ask a man to suffer through a movie that he had already watched when could be watching a new movie – one that he really wanted to see. Furthermore, I continued to rationalize, it wasn’t really like a “date date”. We were all together as a group. Surely Gail wouldn’t mind if we watched separate movies.

In the end, the decision itself wasn’t that hard for me. The hard part was telling Suzanne.

“Since I’ve already seen City Slickers….”, I began. “I’m going to watch Necessary Roughness. Can you tell Gail?”.

Phew! That was awkward. But it felt good to have all of the obstacles cleared. I could now proceed straight to my seat and enjoy the movie with a clear conscience.

Necessary Roughness is more than a movie to me now. It is a time capsule that transports me back to that Friday night in 1991 when we were still kids, but were beginning to explore the waters of the next frontier for the first time.

basketball

The Rivalry

The following is my account of one of the greatest rivalries in elementary sports history. It retells the infamous showdown at the 1992 Langley Grade Seven Boys Basketball Championships between Peterson Road’s heroic grade seven team, and the evil grade six team.

Okay, they weren’t evil ;). Enjoy


“Did you hear that Mr. Page entered the grade sixes into the grade seven tournament?”, John declared. There were four of five of us kids gathered in a cluster outside the grade seven entrance of Peterson Road waiting for the morning bell.

“What?!!”, I said in a surprised tone. “Can he do that?”

“Well, he did it”, John replied.

“Hah. We’re going to kick their asses”, a few others chimed in.

I had to take a minute to process this information. My first reaction was one of dismay. “The audacity!”, I thought. “These upstart grade sixes thought they could challenge us?!! Who did they think they were?!”.

Surely this broke some law. I mean, we had dutifully followed the unwritten protocol of “wait your turn” through seven years of elementary school. My mind went back to the dispute we had with some grade-three kids, when we were in grade one, about who got to play on the soccer field. Our case was dismissed with prejudice by the noon-hour supervisor on the grounds that the grade threes were older. As a part of that ruling, we were assured that, when we were in grade three, we could use the soccer field. This dispute was not alone in its affirmation of the protocol that the needs of the older outweighed the wants of the younger.

We had paid our dues, and now it was our turn to be sovereign. These upstart grade sixes thought they could buck this sacred law skip to the top of the food chain. This insolence could not go unpunished.

My second thought was that this was unprecedented! To my knowledge, no grade six team had ever, in the history of elementary school sports, been allowed to compete in the grade seven tournament. At least not of the school already had a grade seven team.

Better fact-check that, I thought, as my historical knowledge of elementary sports was limited to the past three years and spanned only a couple of schools.

“Has a grade six team ever been allowed into a grade seven tournament before?”, I asked the wikipedia of the day (aka John, Steve, Ezra, and Pat).

“Nope”, they said.

It was confirmed. Unprecedented in the history of sports. Which leads me back to my first thought again. “The Gall!”

If I’m honest with myself, however, the most unsettling aspect of this news was that the grade sixes were pretty good. “What if they beat us?”, I thought. I’m sure this same thought crossed the other boys’ minds as well, but none were foolish enough to express it.

I had been teammates with most of the grade six boys at one time or another. Several of them had been on my baseball teams throughout elementary school. A few of them lived in my neighbourhood, so we would often play street hockey and tennis together. During lunch-time football, we would frequently scrimmage against them, and one of them even played on our (grade seven) team when we were low on players.

They were fast and athletic so I wasn’t immediately confident that we would beat them in a head-to-head matchup.

As a thought experiment, I imagined a pick-up game combining both grades, where I got to “draft” my team. Who would I pick?

Well, my first pick would probably be Quinn, as he was our best player. Quinn was tall and lanky, with a shoe size that hinted that he was going to grow a lot taller. He could jump, dribble equally well with both hands, and make highlight-reel lay-ups from both sides of the hoop. His dad was very tall, and had coached several of our basketball teams throughout elementary school. If he wasn’t on the courting shooting hoops, he was probably carrying a basketball en route to a court.

Having chosen a grade seven as first pick in this fantasy draft, I felt a little bit better, but the subsequent picks weren’t going to be as easy. We had a good crew. We had played together for years in multiple sports, and we knew each others’ strengths and weaknesses well. I could think of four or five good choices for the second pick. Pat, Chad, the other Steve, John, Ezra, Chris. All were good players who I trusted with the ball. But…. I can also think of one or two grade sixes who, If I’m honest, deserved the second pick over my trusted mates, and an additional four or five who would be solid third picks. So it is conceivable that four of the five starting spots in the “dream team” would be filled by grade sixes.

“But we have a height advantage”, I tried to convince myself, “and the experience”. Our sheer will to win would be the difference. We got this.

As far as I recall, the grade six boys were gracious about the situation. They were all good kids, and we got along well with each other. I suspect that if the roles were reversed, we wouldn’t have been as respectful. But they didn’t need to say it out loud – the threat was palpable, and the stakes were high, but asymmetrical. They had nothing to lose. We, on the other hand, had everything to lose. If we allowed to the grade sixes to come into our tournament, and beat us, it would have been demoralizing.

On the first day of the tournament, we arrived in the DW Poppy Secondary gymnasium as a team. The schedule was posted on a portable bulletin board, the kind with wheels and a chalkboard on the back. There were about ten schools listed. I overheard some players from other schools wondering out loud about the fact that Peterson Road had two teams. I thought about explaining it to them, but decided not to. Better to leave them guessing. Information is power!

We had played against most of these schools during the regular season, and I felt confident about our chances. In my mind, only two teams mattered. Langley Central had a kid named John MacDonald who was, hands-down, the best player there. He was five foot ten, and, like Quinn, could dribble equally well with both hands. He didn’t need to jump at all when shooting free-throws, and his three-point percentage was better than most boys’ layup percentage. He was a complete player, who could have been playing senior ball. Because of him, Langley Central was the team to beat.

The other team that mattered was, of course, the grade six squad. In our eyes, it was the only game that mattered. If we managed to run the board against all the other schools, win the championship, appear on TSN for interviews, and be congratulated by the Queen for our achievement, but lose to the grade sixes, we would feel obliged to retreat to a dark corner and curl up into the fetal position, never to be seen again. Yes, it was that important.

As with any tournament, it was possible that we wouldn’t end up playing the grade sixes at all. They could have been placed into a different pool, and then we would only play if we both made it to the finals.

“We play Langley Central second! On the main court”, Chad shouted, looking over his shoulder with his index finger on the schedule, “and then the grade sixes, in the small gym”.

So it was official. Game On!

After winning our first game, we assembled on the main court to start our warm ups for the game against Langley Central. We started with layup drills.

This gym had a completely different feel than the elementary school gyms we were used to. The hardwood floor was a little bit less bouncy than the linoleum I was used to, and the plexiglass backboards were a bit more bouncy than the wooden ones we had. The gym was two to three times the size of Peterson Road’s. It had actual stands where spectators could watch, and a large electronic scoreboard mounted near the ceiling. This was the big time.

After our warm-ups, we returned to the bench where our coach picked a starting lineup. The chosen five stayed on the court, and the rest of the team took their place on the bench. The five included Chris and I sharing guard duty, Quinn in the middle, and Pat and John on the wings.

In professional basketball, they usually have a starting five players, and individual players may be substituted out in the course of the game when a starter needs a rest, or runs into foul trouble. The coach may also make a substitution if they want a particular match-up. In elementary school, however, our substitutions worked more like line-changes in hockey. The starting five would play a few series before being replaced by the second line, followed by the third line, etc..

This made for some dramatic momentum swings in games, as the skill-level of different lines vary wildly.

Quinn lined up against John MacDonald for the tip off to start the game. They won the jump ball, MacDonald tipping it back to their point guard, who took a couple of dribbles before passing it back to MacDonald. A couple more passes, then back to MacDonald under the hoop, who dropped in an easy lay-up.

Not a great start. But now it was our turn.

Chris in-bounded the ball to me and I took it up the court. I saw John open on the right side just inside the three point line, so I bounced it over to him. He gave a quick head fake to the defender then took it to the hoop, where MacDonald was waiting for him. A little fake to the left and then an underhand layup made it up to the rim. After a couple of rattles around the rim it dropped for a basket and we tied at two. We got this.

A few minutes later, with the score seven to two, Langley Central did a line change, and their star player was replaced by a new squad. I found it puzzling that they didn’t just have him play the entire game. With him on the bench, we clawed our way back into the game. A few minutes later, with our team up now ten to nine (or thereabouts), their top line was back on the court, and momentum changed again.

This pattern continued throughout the game. Their top line would run up the score, and then we would inch our way back against their second line. When the final buzzer sounded, though the score was close, we were a couple of baskets shy.

This loss didn’t phase us terribly. We knew what we were up against and the score was close enough to make us feel like we could turn it around the next time, which we assumed would be in the finals.

On to the main event – the only game that mattered – in the small gym.

This gym felt more comfortable than the main gym, as its size was closer to what we were used to. It still had a hardwood floor, plexiglass backboards, and an electronic scoreboard. But it was a newer gym (about 3 years old), and the floor felt a little bouncier. The lighting was also a little brighter than the dull lights of the main gym.

After the pre-game warmups and rituals, both teams assembled on the court for the tip off. Our team wore the white side of the school’s invertible jerseys, the grade sixes were wearing grey and burgundy T-shirts. A moment of calm before the storm as the referee prepared to toss up the ball to start the game. Our height advantage secured an easy victory on that first jump ball – and on most of the subsequent ones.

Unlike the Langley Central game, which was a series of momentum shifts, this game was see-saw. Back and forth. They would score, then we would score. We would stop them, then they would stop us. We went into halftime in a virtual tie – which was too close for comfort. Things were a little bit tense. Players who made mistakes were informed of them by certain other team-mates – just in case they weren’t aware that they weren’t supposed to miss that last layup.

This pattern continued into the second half, while intensity continued to rise. With under thirty seconds to go, we were down by a point. I was watching from the bench as Chad dribbled the ball up the court and the team set up the offence. The sixes were playing tight defence with everything on the line. We passed the ball around the perimeter but couldn’t find an opening. Twenty seconds left. Finally someone got an open shot. Fifteen seconds… the ball arced through the air, our hopes attached to it … 13 seconds… It went off script and bounced off the front edge of the rim and returned to flight, back into the court. 11 seconds. Luckily the rebound found its way into Pat’s hands near the free-throw line. Pat, who was one of our most reliable shooters, made no mistake with it. He stepped forward and released a shot that resulted in a swish.

We all cheered loudly. Everyone on the bench was on their feet, with arms in the air celebrating what was looking like a sure victory. I glanced up at the scoreboard for some assurance. 8 seconds, 7 seconds.

The game was not over yet. They passed the ball in, and started down the court with urgency. With only a few seconds remaining they knew it was all or nothing here. The guard threw up a “hail mary” to their forward near our freethrow line. I watched in horror as the pass was completed, and their player (I don’t remember who), turned to the hoop, and started his attack run. Two dribbles, a step and a half, and he was going up for a lay-up, but at the last second, Chad, dove in from behind and got a piece of his arm just before releasing it.

“Foul!” yelled the ref.

And so, with the score thirty-nine to thirty-eight, for us, and three seconds left on the clock, a grade six was going to the line for two free-throws.

The coach decided to substitute in all of our tallest players at this point to make sure we got the rebounds, so Chad was out, as he was one of the shorter players. I could see tears running down his face as he sat down.

“What’s wrong?”, I asked.

“I lost the game for us”, he said frantically. “It was my foul. If he sinks these, it’s my fault!”.

He was too agitated to sit, so he started pacing the sidelines.

“Hold on a minute”, I said. “If you didn’t foul him, he would have sunk it for sure, and then we would have lost already. This way we still have a chance.”

That seemed to calm him down, and our attention shifted to the court where everyone lined up for the first shot. We watched as the ball traveled toward the hoop, and… bounced out.

An eruption from our bench. Everyone was already on their feet, but now we were jumping and screaming. We had evaded the immediate danger of losing, but they still had a chance to force the game into overtime.

The referee bounced the ball back to the grade six’s hands. The gym got silent. You could cut the air with a knife. Everything was now riding on this one young boy’s shoulders (I really wish I remember the name of the boy – if anyone reading this knows, please share). He bent his knees and raised the ball up to shooting position, then launched it toward the hoop. This time, after bouncing around the rim for a second, the ball decided to drop through the hoop, and just like that, we were going to overtime.

Having been one shot away from victory, I could taste disappointment in my cocktail of emotions. But it was a new game now, and we were going to come out guns blazing.

The electronic scoreboard was updated to read “5:00”, and the ref called the game to order again.

This overtime frame followed the same pattern as the rest of the game, with back and forth action. However, we managed to go up by a couple of baskets early, and we retained the lead throughout. Truth be told, I don’t remember very much about overtime, as the real and memorable drama had already played itself out in regulation time. When the final buzzer sounded with us ahead on the scoreboard, we all rushed the floor to celebrate.

We recounted the memorable moments of the game to each other in between hugs and high fives. “Thank God”, I confided to Ezra, “I did not want to lose that game”.

“I won the game for us!”, I overheard Chad say during the celebration. “If I hadn’t fouled him, they would have won.”

After a short celebration, we lined up for the customary show of sportsmanship to shake hands with our fallen foes – our friends. The optimists among them threw in a “See you in the finals” along with the usual “good game”, but I could see the disappointment in their eyes. The emotion was still raw.

We didn’t end up winning the championship that year. We lost our semi-final game against Wix Brown the next day, which relegated us to a fourth place finish in the tournament. Disappointing as that was, it didn’t really matter that much. We had accomplished the most important feat and could return to Peterson Road with our heads held high and our rightful dominance still intact.