Black Friday Sale!
Save 50% on Web Development with Go and Test with Go until Dec 3.
Both courses have lifetime access, a 30-day money back guarantee, and free updates. This is also the biggest discount I offer on the courses, and I only do it once a year around Black Friday.
Thank you for your continued support and happy coding!
Jon Calhoun
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.
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.
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.
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.
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.
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.
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:
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:
Test with Go - Lessons Package will be added to your account using the license key 123456-ABCDEF-789012-GHIJKL after you sign up.
If you want to add this key to an existing account, please log in and then add the course using your license key.
This is actually shown in the screenshot below (along with a lime theme I love 🤪)
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.
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.Handler
s 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 🤞!
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 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
Anything with a [code]
tag will have a coding portion that is discussed below in the course format section.
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 😉.
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
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.
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!
This article is a progress update. View other progress updates.
Sign up for my mailing list and I'll send you a FREE sample from my course - Web Development with Go. The sample includes 19 screencasts and the first few chapters from the book.
You will also receive emails from me about Go coding techniques, upcoming courses (including FREE ones), and course discounts.
Jon Calhoun is a full stack web developer who teaches about Go, web development, algorithms, and anything programming. If you haven't already, you should totally check out his Go courses.
Previously, Jon worked at several statups including co-founding EasyPost, a shipping API used by several fortune 500 companies. Prior to that Jon worked at Google, competed at world finals in programming competitions, and has been programming since he was a child.
Spread the word
Did you find this page helpful? Let others know about it!
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.
©2018 Jonathan Calhoun. All rights reserved.