Categories
Career

That time I did a children’s technology show for Microsoft

I had a lot of fun, surreal moments during my time as a developer evangelist at Microsoft, and among the most surreal and fun was the short-lived time when I had a technology show for kids called Developer Jr.

Hosted on Butterscotch.com, a technology education video site launched by Tucows (a prior employer) in 2008, Developer Jr. was an online video show for children ages 7 through 12. Our goal was to teach kids programming and other creative things they can do with computers and technology (particularly Microsoft technology). It starred me as the host and tutor, and “Junior”, an impish puppet played by Brian Hogg. It was sponsored by Microsoft Canada and produced at Butterscotch.com’s studios in Toronto’s Liberty Village neighborhood in early 2010.

The premiere episode showed how you could use the code-free game development system Kodu (which ran on Windows and the Xbox 360) to make your own videogames:

The follow-up episode covered making your own movies with Windows Live Movie Maker:

There was also this interview with Butterscotch.com’s Matt Harris in which we discussed the making of Developer Jr.:

Unfortunately, Developer Jr. was cancelled after two episodes for financial reasons. There wasn’t a department within Microsoft Canada who had a budget aimed at the 7 – 12 year-old set.

I’m still pretty pleased with the work that we did during that too-short season, and I’d like to thank Brian Hogg, video wizards Sean Carruthers and Matt Harris for making the magic happen, and Andy Walker for getting the whole thing started!

Categories
Programming Reading Material

My Smalltalk-80 literature and monitor stand

A couple of readers noticed my makeshift monitor stand pictured in the article Building a lean and mean (and frugal!) Python development machine with Peppermint OS:

Yup, it’s the holy trinity of books for Smalltalk-80, the definitive release of original recipe Smalltalk. You probably haven’t used Smalltalk, but you probably use a programming language influenced by it: Dart, Go, Java, Kotlin, Objective-C, PHP, Python, Ruby, Swift, and Scala, to name just a few.

They were a lucky find: they were in a banker’s box in a trash pile on the east side of downtown Toronto, sometime in late 1998. It’s probably my best dumpster-dive find, beating out even that still-functional cable modem or e-Machines starter Pentium machine that I would find a few months later. (Boom times make for great dumpster diving.)

The books are historically interesting. They’re written for readers who would spent all their computing time in the command line, and probably had never seen a GUI before, and they most definitely had never used an IDE. That’s why one of the books is devoted to Smalltalk’s interactive environment, and why one of the first illustrations in that book is this one:

A mid-1980s system capable of running the Smalltalk interactive environment, from page 6 of “Smalltalk-80: The Interactive Programming Environment”. Tap the photo to see it at full size.

Here’s a sample from the biggest of the books: Smalltalk-80: The Language and its Implementation. It’s the definition of a class named FinancialHistory:

The “FinancialHistory” class from pages 43 and 44 of “Smalltalk-80: The Language and its Implementation”. Tap the photo to see it at full size.

To a present-day programmer, the syntax may seem a little weird (it’ll be a little less weird to Objective-C and Swift programmers; now you know where that method-calling syntax comes from!), but they’d still find it familiar. To a programmer in 1984, the year the book was published, who probably subsisted on a steady diet of structured programming, this must’ve been positively mindblowing.

For the curious, here’s how you’d create an instance of FinancialHistory named HouseholdFinances with an initial balance of $350:

HouseholdFinances ← FinancialHistory new initialBalance: 350

Once created, we’d record household spending like so:

HouseholdFinances spend: 32.50 for: 'utilities'
HouseholdFinances spend: cost + tax for: 'food'
HouseholdFinances spend: 100 for: 'reasons'

(I just felt a disturbance in the Force, as if millions of Objective-C and Swift programmers cried out, saying “So it’s Smalltalk’s fault!”)

The smallest of the books, Smalltalk-80: Bits of History, Words of Advice, gets deep into the implementation details of Smalltalk-80. And I do mean deep: there’s a whole chapter devoted to an implementation of a Smalltalk garbage collector.

I’ll eventually return these books to their proper place on the bookshelf and replace them with a proper monitor stand, but in the meantime, they’re doing a pretty good job as the basis for my monitor, just as their content did a pretty good job as the basis for the programming languages I use.

do try to take care of these books, as their scarcity has made them a little more expensive than your standard textbook:

The current Amazon prices for the two hardcover Smalltalk-80 books.
Categories
Current Events Players

Robert Blacklidge and the Feeding the Future hackathon: This weekend, online

Robert Blacklidge

Robert Blacklidge on a bus full of Startup Bus hackers
Robert Blacklidge at Startup Bus 2017.

You can’t talk about the Tampa Bay startup scene for long before the name “Robert Blacklidge” comes up. You’ll often see him at Tampa Bay tech and entrepreneur events, and when he’s not organizing or facilitating hackathons, he’s winning at them. One of his creations, Course Align, made it all the way to finals at Startup Bus 2017 (be sure to check out Gimlet Media’s Startup podcast episodes where they follow the Bus, including the creation of Course Align).

He’s also been bringing tech events and amenities to his home, Lakeland (about 35 miles east of Tampa). Thanks to his work, Lakeland has its editions of 1 Million Cups, Startup Grind, and Techstars Startup Weekend. He also co-founded CO.STARTERS, a 9-week program that teaches entrepreneurs to achieve their long-term goals.

This weekend, he’ll be a mentor at the Feeding the Future online hackathon.

Feeding the Future: A FoodTech hackathon

The world’s food chain supply chains have been greatly disrupted by COVID-19 and its cascading effects. Most of these disruptions will have unpredictable long-term lasting effects on our food systems. The Feeding the Future hackathon’s challenges are all centered around solutions to address and counter these disruptions.

The challenges are:

  1. Sustainable farm-to-fork solutions. How can we use digital technologies to build a more resilient and agile food supply chain for local producers and farmers after CoVid-19 using sustainable farm2fork solutions and further increase e-commerce and home delivery services? How can we apply dynamic models to support seasonal trade and preparation tools for all parts in the food chain?
  2. Reducing carbon “food”prints. The importance of food within cities and urban design is central from several angles. There is a need to transform our urban food systems with a focus on sustainability and resilience.
  3. Make a new and tasty fish product. Baltic Herring is a tasty, small fish found in abundance in the Baltic Sea. Increasing it’s consumption can help lower our carbon footprint. What kind of food product(s) can we create using the Baltic Herring to increase consumption?
  4. Increase Finnish/African food trade. (The hackathon is being organized from Finland.) Africa is an untapped potential market. Finland is known for its world class research in food engineering. What kind of product or services can be utilized to help increase the quality and quantity of food export between Finland and Africa?

Feeding the Future’s kickoff/orientation session happens tomorrow (Thursday, June 25th) at 9:00 a.m. Eastern.

Here’s how you can join in:

  • Join as a
  • As a
  • As a
  • As a

NOTE: You can only compete in the Hackathon as a TEAM of two or more members. If you don’t have yet a team, join the hackathon’s Discord community to find one.

Categories
Hardware Process Programming

Building a lean and mean (and frugal!) Python development machine with Peppermint OS

I always keep an old computer or two around “just in case,” and it often turns out that they’re useful for all sorts of things. In an age when online access is a necessity and in a line of work where being able to put together a quick web page, application, or server is important, a spare computer — even one that’s a little bit backward by today’s standard — can be a handy resource.

Enter “tinymint,” a Compaq 610 laptop that Anitra got from her old workplace a couple of years back for $50. (You should be able to find a used one, or one with similar specs, for about $100.) We originally got it to give to her parents so that they’d have a half-decent machine on which to surf the web, but we’ve since replaced it with a Chromebook, which requires less maintenance. They gave the Compaq back to us, and I’ve since boosted its RAM to the maximum: A whopping 4 GB, which was pretty respectable in the Windows Vista era when it was manufactured.

Diagram showing the parts of the Compaq 610 laptop as viewed from the front and left sides.
An excerpt from the QuickSpecs manual for the Compaq 610.

In case you’re curious, here’s a quick rundown of the specs of my particular Compaq 610. Remember, this laptop is almost old enough to get its own YouTube account or Bat/Bar Mitzvah:

  • Chipset: Mobile Intel GME965 Express chipset with ICH8M, 800 MHz front side bus. This chipset is from around 2007.
  • Processor: Core 2 Duo T5870 (2.0 GHz, 2 MB L2 cache, 800 MHz FSB). This is better than the other options: The dual-core Celeron T1500 and the Celeron 560, both of which had the slower 533 MHz bus.
  • RAM: 4 GB. This is the maximum, which isn’t surprising for a 2009-era computer. 32-bit operating systems were the standard then (64-bit OSs were available, but at a premium), and they’re limited to accessing about 3 GB of memory. The machine originally had 2 GB, and I got replacement RAM from NewEgg for about $20.
  • Hard drive: 250 GB. Not all that different from what you’d get with the lowest-end MacBook Pro today.
  • Wireless networking: Intel PRO/Wireless 3945ABG wifi a/b/g
  • Wired networking: Marvell Yukon 88E8042 PCI-E Fast Ethernet Controller
  • Webcam: 2 megapixels, so it’s 1080p.
  • Other goodies marking it as a 2009-era computer:
    • A 56K modem! I don’t think I’ve had dial-up service since 2000. Even during those rare occasions when I need to send a fax, I do it through online fax services.
    • Separate 1/8″ mic and headphone jacks.
    • VGA output. Good thing I hung onto that Acer VGA monitor.

There were a few variants of this machine, and I’m a little surprised that this turned out to be one of the better ones — normally companies go with the bottom-of-the-line configurations, especially for computers whose primary purpose was probably producing cover sheets for TPS reports.

Desk with a Compaq 610 laptop on a wooden box, Acer VGA monitor on a stack of Smalltalk-80 books, an Apple wired keyboard and a Microsoft mouse.
Installing Peppermint Linux on the Compaq 610.

I like to think of “tinymint” as a Raspberry Pi with a built-in monitor, keyboard, and battery (although I need to pick up a replacement battery; this one no longer holds any charge). This means that it’s still got some years left in it, where it could function as a server, a runner of automated tasks, or as a budget Python programming machine.

I’m scheduled to teach an “Intro to programming with Python” course in July, and I may actually use this as my demo machine, just to show what’s possible even on a limited budget.

In order to get the most out of this machine, I replaced the Windows with something considerably more lightweight: Peppermint.

Peppermint is a Linux distribution based on Ubuntu, and it’s designed to run on systems with limited resources. To this end, it uses a desktop environment that’s a mix of LXDE’s lxsession session manager and Xfce’s panel and applications menu. Simply put, it’s not going to look as slick as commercial OSs or even other Linux distros, but it’ll be reasonably good-looking and run quite well.

Since Peppermint is a Linux distro, it has all the command-line goodness that a developer needs. I wanted to make “tinymint” a lean mean Python machine, so immediately after Peppermint finished installing, I installed Anaconda Individual Edition and Visual Studio Code, both of which installed and run without any issues.

I’m going to make regular use of “tinymint” and post the occasional report about my experiences with it. If you’re a developer with an older computer and a limited budget, you should look into Peppermint — you might find that it’s exactly what you need.

The current version is “Peppermint 10 Respin,” which came out in December. It’s based on Ubuntu 18.04 LTS, and if you want to know more about this release, check out their announcement.

Want to know more? Here are a couple of recent video reviews of Peppermint:

Categories
Current Events Tampa Bay

What’s happening in the Tampa Bay tech/entrepreneur/nerd scene (Week of Monday, June 22, 2020)

Greetings, Tampa Bay techies, entrepreneurs, and nerds! Welcome to the June 22, 2020 edition of the list! Here’s this week’s list of online-only events for techies, entrepreneurs, and nerds based in an around the Tampa Bay area. Keep an eye on this post; I update it when I hear about new events, it’s always changing. Stay safe, stay connected, and #MakeItTampaBay!

When will this list include in-person events?

The answer remains, quite emphatically: NOT JUST YET.

Consider the recent spike in cases, as reported in the news:

With this spike in mind, I’m opting to list only those events that I know are online only for the time being.

Monday, June 22

Tuesday, June 23

Wednesday, June 24

Thursday, June 25

Friday, June 26

Saturday, June 27

Sunday, June 28

Do you have an upcoming event that you’d like to see on this list?

If you know of an upcoming event that you think should appear on this list, please let me know!

Join the mailing list!

If you’d like to get this list in your email inbox every week, enter your email address below. You’ll only be emailed once a week, and the email will contain this list, plus links to any interesting news, upcoming events, and tech articles.

Join the Tampa Bay Tech Events list and always be informed of what’s coming up in Tampa Bay!


Categories
Career Programming

Programmer interview challenge 2, part 5: An elegant “watcher”-based FizzBuzz implementation in JavaScript

Silhouette of a little black dress on a dress form
Ask someone who follows fashion what they think of when the word “elegant” comes up, and they’ll often come up with the Little Black Dress.

In the previous article in this series, I put out a call for alternate implementations of the “watcher”-based FizzBuzz solution. Frank Quednau answered the call with this elegant bit of JavaScript:

const wordWatcher = (interval, word) => {
  let count = 0;
  return () => {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}

const fizzWatcher = wordWatcher(3, "Fizz");
const buzzWatcher = wordWatcher(5, "Buzz");

for (number of Array(100).keys()) {
  const potentialFizzBuzz = `${fizzWatcher()}${buzzWatcher()}`;
  console.log(potentialFizzBuzz ? potentialFizzBuzz : number + 1);
};

Let’s take a closer look at the code for the watcher, which is assigned a word and keeps track of when to say it:

const wordWatcher = (interval, word) => {
  let count = 0;
  return () => {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}
  • wordWatcher has two parameters:
    • interval: The x in “Every xth number”
    • word: The word to be output
  • It uses those parameters to customize the function that it returns: a function that when called, does two things:
    • It increments its internal counter count, and
    • returns either word (if it’s time to say the word) or an empty string.

If you find yourself writing a lot of similar code with only minor differences — or worse, cutting and pasting code, followed by typing in those minor differences — you may be looking at an opportunity to use a function like this.

If you prefer to have your functions marked with the keyword function, you can change out the arrow notation and the code will still work:

function wordWatcher(interval, word) {
  let count = 0;
  return function() {
    count++;
    if (count === interval) {
      count = 0;
      return word;
    }
    return "";
  }
}

With wordWatcher defined, creating watchers for Fizz and Buzz is easy:

const fizzWatcher = wordWatcher(3, "Fizz");
const buzzWatcher = wordWatcher(5, "Buzz");

And here’s the loop that provides the output:

for (number of Array(100).keys()) {
  const potentialFizzBuzz = `${fizzWatcher()}${buzzWatcher()}`;
  console.log(potentialFizzBuzz ? potentialFizzBuzz : number + 1);
};
  • If it’s time to say FizzBuzz, or FizzBuzz, potentialFizzBuzz will contain that string. The calls to fizzWatcher() and buzzWatcher() will also increment their internal counters.
  • If potentialFizzBuzz contains anything, its contents will be printed to the console; otherwise, the current number — which has 1 added to it because array indexes start at 0 and the FizzBuzz game starts at 1 — is printed instead.

You should check out the rest of Frank’s Gist, Fizzbuzzes in many colours, which looks at FizzBuzz solutions written in several languages.

What does it mean for code to be “elegant”, anyway?

In ordinary everyday use, elegant means “pleasingly graceful and stylish in appearance or manner.” The term has been adapted by people in problem-solving fields — science, mathematics, and yes, programming — to mean “pleasingly ingenious and simple”.

And that’s what elegant code is: pleasingly ingenious and simple. This FizzBuzz implementation is elegant because it solves the problem in just over a dozen lines, is simple and concise, and even provides some new insight into programming (the use of custom-generated functions to avoid repetition).

Here’s a good list of qualities of elegant code, courtesy of Christopher Diggins article, What is the Definition of Elegant Code?:

  • It is succinct
  • It is easy to understand
  • Each function does one well-defined task
  • It conveys the programmer’s intent
  • It reflects the problem domain
  • It is easy to modify and reuse
  • If it fails, it is easy to identify that it is has failed, where it has failed, and why it has failed.
  • Its behavior (in good and bad conditions) is easy to predict

Check out the following articles — sooner or later, you’ll be interviewed by a programmer who’ll want to know if you’ve given some thought to some of programming’s more philosophical questions, and “What does it mean for code to be elegant?” is one of them:

What’s next

FizzBuzzBazz! (or: Making FizzBuzz harder).

Previously, in the “Programmer interview challenge” series

 

Categories
Career Programming

Programmer interview challenge 2, part 4: Using “watchers” to play FizzBuzz “properly”

The Marvel Comics character known as “The Watcher” - “I am known as The WATCHER. My sworn task is to observe and chronicle great events within this sector of the universe. My curse is to always witness and never participate. I must be true to this duty, even to the brink of Armageddon!”
Marvel Comics’ Watcher. His people are sworn to observe, but not interfere in, everything that happens in the universe.

After reading the previous article on FizzBuzz solutions, Reginald “raganwald” Braithwaite, whom I know from my days as part of the Toronto tech scene, tweeted this:

JenniferPlusPlus agrees:

They both make a good point. If you’re playing the FizzBuzz game as the original children’s game and not as an exercise to prove that you can actually write a program, you’d do it like this:

  • Players sit in a circle, not unlike “the circle” in That ’70s Show.(Players don’t have to be high, unless it helps.)
  • The player designated to go first says the number 1, and each player afterwards counts one number in turn. The next player in the circle says 2, and so on.
  • However, for every third number, instead of calling out the number, the player whose turn it is should say “Fizz”.
  • …and for every fifth number, instead of calling out the number, the player whose turn it is should say “Buzz”.
  • The “Fizz” and “Buzz” rules, as the kids would say, stack. In other words, for every number that is both the third and fifth, the player needs to say “Fizz” followed by “Buzz”, or “FizzBuzz”.

So in the spirit of the original game, I’ve put together a FizzBuzz solution that uses “watchers” to keep track of  “every xth number”, with one watcher to keep track of when it’s time to say “Fizz”, and another for when it’s time to say “Buzz”. When it’s time to say “FizzBuzz”, they’ll work in tandem.

I created a class called WordWatcher, which can be summarized as shown below:

Here’s its code:

class WordWatcher:

  def __init__(self, interval, word):
    self.counter = 0
    self.time_for_word = False
    self.interval = interval
    self.word = word

  def observe_next_turn(self):
    self.counter += 1
    if self.counter == self.interval:
      self.counter = 0
      self.time_for_word = True
    else:
      self.time_for_word = False

  def speak(self):
    if self.time_for_word:
      return self.word
    else:
      return ""

Some notes about this code:

    • For those of you who aren’t familiar with Python’s approach to class methods, the first parameter for every method in a class is self. It’s the one parameter you don’t fill when calling a method, because Python calls it implicitly (seemingly in violation of Python’s general guideline that explicit is better than implicit). There’s a reason behind this, and it’s explained in this article: Understanding self in Python.
    • Also note that instance variables are declared and defined in the initializer method, __init__(), and any reference to them is always preceded by self.
    • The observe_next_turn() method is meant to be called as the fizzBuzz method proceeds to each new number. It updates the watcher’s internal counter and sets the time_for_word flag accordingly.
    • The speak() method outputs the watcher’s word if it’s time to say the word, or an empty string otherwise.

For FizzBuzz, we’ll need to create two watchers:

  1. One to keep watch for every third turn, at which point it should say “Fizz”, and
  2. one to keep watch for every third turn, at which point it should say “Buzz”.

With the WordWatcher class defined, we can create these two watchers like so:

fizz_watcher = WordWatcher(3, "Fizz")
buzz_watcher = WordWatcher(5, "Buzz")

It will become handy to have these two watchers in the same place. Since the “ha ha only serious” joke about Python is that everything is a list, let’s put them into a list:

word_watchers = [fizz_watcher, buzz_watcher]

Let’s define a fizzBuzz() function that makes use of this list of word watchers:

def fizzBuzz(word_watchers = [], first = 1, last = 100):
  final_result = ""

  for number in range(1, 101):
    current_result = ""

    if len(word_watchers) > 0:
      # This part might need some explaining
      _ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
      words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
      current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
    
    if current_result == "":
      current_result = str(number)

    final_result += current_result

    if number < last:
      final_result += ", "
    else:
      final_result += "."

  return final_result

If you’ve been following the FizzBuzz series of articles, most of this code will be familiar. The part that might need explaining is the part with the comment “This part might need some explaining”.

Explaining the part that needs explaining

Let’s look at the first of the three lines of code in that part:

_ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
  • The _ on the left side of the = sign is a throwaway variable. It says “I don’t care about what you do on the other side of the = sign; only that you do something on the other side of the = sign”.
  • On the right side of the= sign is a list comprehension, which is Python’s “show, don’t tell” way of building lists. This list comprehension simply says “call the observe_next_turn() method of every object in the list”.

Let’s look at the next line:

words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
  • This line creates a map that converts the watchers in the list into the words they should say for this turn. If the current turn means that it’s time for any one of them to speak, the watcher will be mapped to the word it’s supposed to say. Otherwise, it will be mapped to an empty string.

And now, the final line:

current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
  • For some reason, map() comes built into Python, but you have to import the functools library in order to use map()’s partner in crime, reduce(). Remember reduce() is a functional programming thingy that takes a collection of items, performs some kind of calculation on that collection, and returns a single value (which you might call a reduction of the collection).
  • The first argument that I’ve provided to reduce() is a lambda — a small function that isn’t given a name — that simply takes the current item in the list and adds it to the previous collected items. Applied over the entire list, it builds a “total”, which in this case is all the words output by the watchers’ speak() methods concatenated together.
  • The second argument is the words map converted into a list. This is the list that the reduce() method will operate on.

At the end of those three lines, current_result will contain one of the following:

  • The empty string
  • Fizz
  • Buzz
  • FizzBuzz

If current_result is still empty at this point, it means that it’s not time for any of the watchers’ words. If this is the case, the string version of the current number is concatenated to current_result:

if current_result == "":
      current_result += str(number)

Here’s the code in its entirety:

import functools

class WordWatcher:

  def __init__(self, interval, word):
    self.counter = 0
    self.time_for_word = False
    self.interval = interval
    self.word = word

  def observe_next_turn(self):
    self.counter += 1
    if self.counter == self.interval:
      self.counter = 0
      self.time_for_word = True
    else:
      self.time_for_word = False

  def speak(self):
    if self.time_for_word:
      return self.word
    else:
      return ""


def fizzBuzz(word_watchers = [], first = 1, last = 100):
  final_result = ""

  for number in range(1, 101):
    current_result = ""

    if len(word_watchers) > 0:
      _ = [word_watcher.observe_next_turn() for word_watcher in word_watchers]
      words = map(lambda word_watcher : word_watcher.speak(), word_watchers)
      current_result += functools.reduce(lambda total, next_element : total + next_element, list(words))
    
    if current_result == "":
      current_result += str(number)

    final_result += current_result

    if number < last:
      final_result += ", "
    else:
      final_result += "."

  return final_result

fizz_watcher = WordWatcher(3, "Fizz")
buzz_watcher = WordWatcher(5, "Buzz")
word_watchers = [fizz_watcher, buzz_watcher]
print(fizzBuzz(word_watchers))

And for completeness’ sake, here’s the test file:

import pytest
from fizzbuzz_with_watchers import fizzBuzz, WordWatcher

plain_1_to_100_result = "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100."
fizzBuzz_1_to_100_result = "1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz."

def test_fizzBuzz_null():
  result = fizzBuzz()
  assert result == plain_1_to_100_result, f"The watcher solution returned the wrong result:\nExpected: {plain_1_to_100_result}\nActual: {result}."

def test_fizzBuzz_fizz_and_buzz():
  fizz_watcher = WordWatcher(3, "Fizz")
  buzz_watcher = WordWatcher(5, "Buzz")
  word_watchers = [fizz_watcher, buzz_watcher]
  result = fizzBuzz([fizz_watcher, buzz_watcher])
  assert result == fizzBuzz_1_to_100_result, f"The watcher solution returned the wrong result:\nExpected: {fizzBuzz1To100Result}\nActual: {result}."

You can download fizzbuzz_with_watchers.py and test_fizzbuzz_with_watchers.py here (2KB, zipped folder with 2 Python files).

That’s a lot of fuss for Fizzbuzz. Why did you do all that?

  1. Reginald asked me to, and I’ve known and respected him for ages, and JenniferPlusPlus seconded the request.
  2. Wait until you see what customers ask you to do.

Did any of this stuff fly over your head?

  1. Don’t feel bad. I had the same trouble when I first learned functional programming, and that was back in 1991, when the computers that ran functional language interpreters were in labs. I spent a lot of time in Queen’s University’s DEClab, which was full of machines that were cutting edge at the time made by a vendor that no longer exists. Computer time, as well as info on any kind of programming, never mind functional programming, was a lot harder to come by. (In case you were wondering, the language we learned was Miranda.)
  2. If you’ve never worked in Python, some of it can be quite weird. It does eventually make sense.
  3. Let me know, either via email or in the comments, if there’s anything you’d like me to cover in greater detail.

Do you have an alternate solution?

I’ve love to hear about it and present it here! Again, let me know via email or in the comments.

What’s next

An elegant JavaScript implementation.

Previously, in the “Programmer interview challenge” series