New Course Website Continued & Algorithms with Go Updates

Most of my work the past week or two is still spent on the new website that will power all of my courses. In this post I’ll try to give you some updates on how that is progressing, examine challenges I am facing, discuss some of the goals of the new UX, and we will get to see some additional screenshots of the course UI.

Oh, and I’ll share a sneak peek of the upcoming Algorithms with Go artwork, but be aware that this isn’t final.

Course Website Updates

As many of you know, the new course website will have a React frontend and a Go API powering it. I’ve mostly been working on the frontend, but as you will see in this update the signup page lead me to start working on the Go backend as well to help explore a few signup flows.

UI/UX

Most of these updates are visual, so let’s just dive right into some screenshots. First up is the course index where you choose a course.

Screenshot of the new courses index page.

Right now this is just showing all courses as if they were signed up for or purchased, but long term I hope to fade out (and still display) other courses I offer that you haven’t purchased or signed up for. My hope is that doing this will help people discover other courses (both free and paid) helping both me and you in the long term 😃

Once you click on a course I might eventually have it go directly to the last lesson you were on (and add a quick link for the course index), but for now clicking “Go To Course” sends you to a course index page that tentatively looks like the screenshot below.

Screenshot of the new course index page.

I’m not really sure how much use this page will get, but I wanted something for people to browse all the lessons in a course.

Oh, and on that note, I’m planning to try to standardize how I split up courses a bit. In the past I had Chapters/Sections in Web Dev with Go, Exercises/Videos in Gophercises, and Sections/Lessons in Test with Go. I might label each differently (eg “Exercise 1: …” as you can see in the course index screenshot for Gophercises), but internally I’ll just be using sections and lessons as the terminology.

A section will be a container with several lessons in it. In Gophercises this is an “Exercise”; in Web Dev w/ Go this is a Chapter.

A lesson will be an individual unit of material. This is typically going to be a video, but it might vary in the future a bit and it could include more (like writeups of the video) in the future.

With that out of the way, below is a slightly tweaked version of the lesson page.

Screenshot of the new course lesson page.

I moved away from the all purple look for a more subtle usage of the color, and I’m considering having a separate color theme for each course. For instance, I might do a lime theme for Web Dev with Go, blue for Test with Go, purple for Gophercises, and so on. The goal here would be to make it easier to differentiate between what course you are viewing in an instant, while not relying on it entirely for those who are color blind.

It isn’t very important and may not ever happen, but it was something I wasted a good 30 minutes with so I thought I’d share 🤣. Below is a blue theme sample.

Screenshot of the new course lesson page with a blue theme.

Lastly, I’ve been spending a lot of time on the signup page. That sounds weird to admit, but the signup page is going to be fairly complex at first because I have people coming from a variety of places and I want to make the experience as smooth as possible.

Developers who purchase a course through Gumroad end up being redirected back to my site with info like their name, email address, and license in the URL as URL query params. Typically the page they want is the signup page, so Gumroad will redirect them there all the time with a URL like:

courses.calhoun.io/signup?name=Jon%20Calhoun&email=jon%40calhoun.io&license=123456-ABCDEF-789012-GHIJKL

In cases like this I want to pre-fill any information I can, but I also want to use that information to make their onboarding process as smooth as possible. That basically means I need to consider at least three use cases:

  1. The user is NOT signed in and there is NOT a user with that email address.
  2. The user is NOT signed in, but I recognize the email address.
  3. The user IS signed in.

I can’t expect Gumroad to know which case the user falls into, so my signup page has to handle each (or redirect the user to the appropriate page at least).

When the user isn’t signed and I don’t recognize their email address (use case #1) my job is pretty easy. I can use the info in the URL query params to pre-fill whatever I can, then use the rest of the info to lookup anything else that might make the signup process easier. For example, if the user hits this page and I see that the license matches to Test with Go - Lessons Package I could show them a message like this:

This is actually shown in the screenshot below (along with a lime theme I love 🤪)

Screenshot of the new course signup page.

In an ideal world I would imagine the license being applied to their account as soon as they sign up so that they never have to deal with typing in a license key. After all, if they are creating a new account chances are that is where they wanted to apply the license key!

On the other hand, if the email address provided in the URL query params exists but the user IS NOT signed in (use case #2), I probably don’t want to show them a signup page. This could lead to confusion, or people signing up for a new account and having their courses split across several accounts. Yuck! 🤮

Instead, it makes more sense to redirect them to a login page but with a similar message so they understand that the license will be applied as soon as they log in. Again, no typing out a nasty license key while also making it clear what is about to happen (along with a link to create a new account if that is what they want) so we don’t have to fix mistakes later on.

When the user is already logged in (use case #3) I end up with yet another conundrum. I can either (a) add the course to their account immediately using the license, or (b) send them to a page where they enter a license key and pre-fill it with their key. I will likely opt for (b) since this still limits typing on the users part, but avoids any annoyance where a license is auto-applied to the wrong account.

The crazy part is this doesn’t even cover all of the possible ways a user might hit the signup page. Remember that Gophercises course? Yeah… it has its own database and set of users that all sign in with magic links, so I’m going to need to make those either work or redirect the user to a signup page with a link that automatically adds Gophercises to their account (it’s free, but it won’t be added to your account unless you “enroll” in the course).

I wanted to start testing all of these scenarios out, but up until now I’ve been faking most of the data in Javascript. I didn’t want to fake all of this signup logic in Javascript, so this lead me to start working on the course backend a bit.

Go Backend

I already have a course backend over at members.usegolang.com, but that was built in a hurry and is kinda messy. Not awful, but not the best code ever. The biggest issue is probably the tests - there aren’t enough of them. Despite its shortcomings, I do need to keep my new site mostly compatible since I don’t want to do any major database migrations, so this made for a great starting point.

I have only been doing backend updates for a day or so and most of the changes here are boring and hard to illustrate. They mostly include writing http.Handlers that will be used to handle all the JSON API requests. Since most of my backend pieces are already written (eg a UserService and others that I used to interact with my DB) I’m mostly just connecting things together inside the handlers.

As I outlined above, I’m really trying to improve that onboarding flow so I’ll probably need to expand upon a few of my services as I go. For instance, I don’t know if there is a good way to look up a license and get a user-friendly string for it. Licenses are instead mapped to a set of permissions which are less user-friendly (because they were never user-visible before). I haven’t gotten there yet, but suspect changes like that will come this week.

On a positive note, I do think some of my work gave me good inspiration for an article on interface chaining vs requiring functionality! I need to talk with a few other developers to flesh out the idea and see where it goes, but fingers crossed 🤞!

Algorithms with Go Updates!

Last, but definitely not least, are the updates for the upcoming Algorithms with Go course. First let’s take a look at the outline for the first module, then we can look at the expected course format, then finally we can look at the awesome artwork that the course will rock afterwards.

Module 01 Outline

Module 1 is going to focus pretty heavily on just getting people up to speed with the basics. You can almost think of it as an “intro to coding” course, but I won’t be teaching the absolute basics and syntax of Go. Instead, we will start by discussing what algorithms are, why we use them, ways to learn them, ways to improve your algorithm skills (Hint: Practice actually coding the algorithms!), and then finally we will spend the rest of the module going over some simpler algorithms that generally don’t require much prerequisite knowledge to solve. You can check out the outline below, then we will discuss it in more detail.

01 - Intro
02 - What is an algorithm?
03 - How to improve
04 - Determine if a number is in a list [code]
05 - Sum all the numbers in a list [code]
06 - Reverse a string [code]
07 - FizzBuzz [code]
08 - Decimal to another base [code]
09 - Another base to decimal [code]
10 - Any base to any base [code]
11 - Find two that sum [code]
12 - Prime factorization (primes provided) [code]
13 - Fibonacci sequence [code]
14 - Greatest common divisor [code]
15 - stdin and stdout

Some of you might be excited by this outline; others will be let down because they were hoping we would dive right into the meaty algorithms. To those in the latter group, remember that this course is meant to help a wide array of people including people who are self taught and have no experience learning algorithms, new CS students, and more.

This entire first module is designed to help get them ready to excel in the future modules. In fact, that very last lesson - 15 - stdin and stdout - sounds really weird until you realize that this entire lesson focuses on tips for reading input data and writing out correct answers so that anyone taking the course can practice on other websites, like past Google Code Jam problems. Many of us with prior programming experience, especially in a collegiate environment, take stdin and stdout for granted because we were introduced to it in homework assignemnts, but many other developers (and aspiring developers) out there have only interacted with web servers and don’t really know any of the tips and tricks that make it much easier to work with a program that reads and writes from standard input and output.

Now let’s look at the course format, which will help illustrate just how many of these lessons are going to involve coding and practice that you can get your hands dirty with 😉.

Course Format

The course format for this course will be similar to Gophercises, but also very different.

It will be similar in the sense that a large majority of the lessons will consist of coding exercises that you can (and are strongly encouraged to) code on your own before watching me code and explain a solution. It will be different in the sense that I’ll be providing a pretty standard starting point and, as much as I can, I’ll also try to provide some test cases to help you verify that what you are coding is indeed working.

Let’s look at lesson 04 to get a better idea of what I mean. When you start the course you will be able to grab a Go source file that has something like the following:

package module01

import "fmt"

// NumInList returns true if seek is in the
// provided list variable, false otherwise.
func NumInList(list []int, seek int) bool {
	return false
}

This is meant to be a starting point for your code where I have already defined the function, and you just need to implement it. I can’t promise I’ll always do this, but I think this format is going to work well for most lessons.

Along with this starting point, I’ll also try to provide tests that will help you determine if your code is actually working. For instance, this might be the tests for NumInList:

package module01

import (
	"fmt"
	"testing"
)

func TestNumInList(t *testing.T) {
	tests := []struct {
		list []int
		num  int
		want bool
	}{
		{[]int{1, 2, 3, 4, 5}, 1, true},
		{[]int{1, 2, 3, 4, 5}, 2, true},
		{[]int{1, 2, 3, 4, 5}, 3, true},
		{[]int{1, 2, 3, 4, 5}, 4, true},
		{[]int{1, 2, 3, 4, 5}, 5, true},
		{[]int{1, 2, 3, 4, 5}, 0, false},
		{[]int{1, 2, 3, 4, -1}, -1, true},
		{[]int{-1, -1, -1, -1, -1, -1, -1, -1}, -1, true},
		{[]int{-1, -1, -1, -1, -1, -1, -1, -1}, 1, false},
	}
	for _, tc := range tests {
		t.Run(fmt.Sprintf("(%v,%v)", tc.list, tc.num), func(t *testing.T) {
			got := NumInList(tc.list, tc.num)
			if got != tc.want {
				t.Fatalf("NumInList() = %v; want %v", got, tc.want)
			}
		})
	}
}

I’m not really expecting you to understand or even look at this code. You are welcome to if you want, but if you do you should keep in mind that all of my tests are going to focus heavily on making the exercises for each lesson easier to code rather than easier for test.

What I mean by this is some problems might have you writing to stdout via fmt.Printf as this is where many beginners start out, but testing a program that writes to stdout can be tricky. You end up with code kinda like this:

t.Run(fmt.Sprintf("N=%d", tc.n), func(t *testing.T) {
  testStdout, writer, err := os.Pipe()
  if err != nil {
    t.Fatalf("os.Pipe() err = %v; want %v", err, nil)
  }
  osStdout := os.Stdout // keep backup of the real stdout
  os.Stdout = writer
  defer func() {
    // Undo what we changed when this test is done.
    os.Stdout = osStdout
  }()

  FizzBuzz(tc.n)
  writer.Close()

  var buf bytes.Buffer
  io.Copy(&buf, testStdout)
  got := buf.String()
  if got != tc.want {
    t.Fatalf("FizzBuzz(%d) = %q; want %q", tc.n, got, tc.want)
  }
})

If I was writing the FizzBuzz function myself I might opt to instead pass in an io.Writer to make this testing much easier, but I don’t want to do that to someone who is just learning FizzBuzz. They are going to look at the io.Writer and think, “WTF is this thing? How do I use it?” I know this because I, an experienced developer, thought this when I first came to Go from Ruby.

Now that I’m familiar with Go it makes complete sense, but it didn’t at first and I found myself trying to use the Write(p []byte) (n int, err error) method directly without ever really realizing that fmt.Fprintf existed and and was probably what I wanted.

Lastly, each problem will have a solution source file. I’ll likely put this in a separate package. Something like module01solutions so you can avoid looking at solutions until you are absolutely ready to. And just like Gophercises, there will be a video of me coding the solution and explaining it as I go.

Who knows what else I’m missing, but if you have questions or thoughts don’t hesitate to reach out - jon@calhoun.io

Awesome Gopher Artwork!

Finally we get to the adorable part of this post; the Gopher artwork!

As many of you know, I like to get new artwork for each course. This started with my Web Development with Go course which just has a simple waving gopher and has grown a little more involved with each project. Gophercises stepped it up a notch with some exercising Gophers, and I even added some animations to give them a little more life. After that came Test with Go’s crash test dummy themed Gophers and an entire backdrop for the website.

Algorithms with Go won’t be any different, as you can see from the mockup of the artwork below.

Algorithms with Go Artwork

I plan to do a deep dive into how the artwork gets designed later, but in the meantime here are the basics:

And that about does it for this progress update. Happy coding everyone!

Learn Web Development with Go!

Sign up for my mailing list and I'll send you a FREE sample from my course - Web Development with Go. The sample includes three chapters from the book, and over 2.5 hours of screencasts.

You will also receive notifications when I release new articles, along with other freebies that I only share with my mailing list.

Avatar of Jon Calhoun
Written by
Jon Calhoun

Jon Calhoun is a full stack web developer who also teaches about Go, web development, algorithms, and anything programming related. He also consults for other companies who have development needs. (If you need some development work done, get in touch!)

Jon is a co-founder of EasyPost, a shipping API that many fortune 500 companies use to power their shipping infrastructure, and prior to founding EasyPost he worked at google as a software engineer.

Spread the word

Did you find this page helpful? Let others know about it!

Vote on Hacker News

Sharing helps me continue to create both free and premium Go resources.

Want to discuss the article?

See something that is wrong, think this article could be improved, or just want to say thanks? I'd love to hear what you have to say!

You can reach me via email or via twitter.

Recent Articles All Articles Mini-Series Progress Updates Tags About Me Go Courses

©2018 Jonathan Calhoun. All rights reserved.