live courses, 64 across 2 languages
Backends, written down to the bit.
Bitwrite teaches backend development in Go and Rust: live, in a room of 8, with someone who runs them in production for a living. You learn what your code does to the machine, then you write code that means it.
Magnetic core memory: each ring is one bit, and it flips only where two wires cross. The rings are ferrite, which is mostly iron oxide. So, more or less, rust.
- In the room
- 8 people
- Each week
- 2 × 90 min
- Refund
- 30 days
- From
- £9.64
who frees this?
Both languages give you a heap. They disagree about who cleans it.
One workload, two heaps. Every ring is a block of memory: solid while it's in use, hollow once it's dead and waiting to be handed back.
Gothe collector
- In use
- 201
- Garbage
- 89
- Collections
- 6
You never say when. Dead memory waits for a collection cycle to sweep it up, and GOGC sets how much waiting you'll pay for. It's memory headroom instead of your time.
Rustthe owner
- In use
- 201
- Garbage
- 0
Every value has one owner, and when the owner leaves scope the value is freed, at a brace you can point to. Nothing ever waits. The bill arrives at compile time instead.
100
Go's one real dial. Higher means fewer collections and more memory held. Rust has no such dial, because it has no collector.
func handle(w http.ResponseWriter, r *http.Request) {
order := loadOrder(r.PathValue("id"))
if err := json.NewEncoder(w).Encode(order); err != nil {
slog.Error("encoding order", "err", err)
}
} // order is garbage now. The collector comes later.
fn handle(id: &str, out: &mut impl Write) -> io::Result<()> {
let order = load_order(id);
write!(out, "{} {:?}", order.id, order.lines)
} // order is freed here, at this brace.
A teaching model, not a benchmark. Both listings compile, and Go's escape analysis confirms that order is on the heap. Neither language is free: you pay in memory or you pay in effort, and the courses are about knowing which bill you can afford.
one bug, two catches
Go catches it running. Rust won't build it.
A thousand concurrent increments of one integer. The answer should be 1000. Nothing here is made up: this is the code, and this is what the tools printed.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
hits := 0
for range 1000 {
wg.Go(func() {
hits++
})
}
wg.Wait()
fmt.Println(hits)
}
It compiles and it runs. Five runs printed 943, 964, 962, 954, 970, and none of them crashed. Then the race detector, which ships with Go:
==================
WARNING: DATA RACE
Read at 0x00c000012198 by goroutine 10:
main.main.func1()
main.go:14 +0x2c
Previous write at 0x00c000012198 by goroutine 7:
main.main.func1()
main.go:14 +0x3c
…
900
Found 2 data race(s)
exit status 66use std::thread;
fn main() {
let mut hits = 0;
thread::scope(|scope| {
for _ in 0..1000 {
scope.spawn(|| hits += 1);
}
});
println!("{hits}");
}
There's no wrong answer to print, because there's no program. The same mistake is a compile error, and the bug never reaches a machine:
error[E0499]: cannot borrow `hits` as mutable more than once at a time
--> main.rs:8:25
|
6 | thread::scope(|scope| {
| ----- has type `&'1 Scope<'1, '_>`
7 | for _ in 0..1000 {
8 | scope.spawn(|| hits += 1);
| ------------^^-----------
| | | |
| | | borrows occur due to use of `hits` in closure
| | `hits` was mutably borrowed here in the previous iteration of the loop
| argument requires that `hits` is borrowed for `'1`
|
…
error: aborting due to 1 previous errorthe planes
Sixty-four courses, one for every bit in a word.
A bit lives where two wires cross, and so does every course here. The same eight subjects run down both planes, and each column goes deeper, from a way in to a deep dive. Pick a ring.
Go
Rust
how a course runs
Read. Write. Verify.
The cycle a machine runs on every bit is also how every course here runs, on both planes. Nobody leaves having only watched.
Before
1. The call
Thirty minutes with the tutor before anything is paid, about what you build and where it keeps going wrong. If another course would suit you better, or none of ours would, you'll hear it then.
Week one
2. Read
You start in real code, not slides. The tutor opens the source of the tool you're about to use,
net/httpor Tokio or the runtime itself, and follows one call all the way down while you interrupt.Then
3. Write
You write the small version yourself: a router in forty lines, a connection pool in sixty, an executor in a hundred. It's the fastest way we know of to stop a tool being magic.
Midway
4. Verify
Then you prove it.
go test -race, fuzzing, Miri, loom and load tests, plus breaking things on purpose: kill the worker, fill the pool, pull the database away. Working isn't the same as right.Final week
5. Ship
Your work goes into a pull request against a real service, and the tutor reviews it line by line. With 8 of you at most, that review covers all of your code, not a sample of it.
what's included
The datasheet.
Every course, at every price, comes with the same 7 things. Nothing extra is sold once you're in.
| Parameter | Value | Conditions |
|---|---|---|
| Teaching | ||
| Live sessionsEach week, in UK time. Cameras optional, questions expected. | 2 × 90 min | Each week, in UK time. Cameras optional, questions expected. |
| People in the roomFew enough that the tutor knows what each of you is building by week two. | 8 max | Few enough that the tutor knows what each of you is building by week two. |
| Source sessionsA session inside the tool's own code, reading what yours runs through. | 1 | A session inside the tool's own code, reading what yours runs through. |
| Support | ||
| Office hourDrop in with whatever broke between sessions. Nobody presents anything. | 1 a week | Drop in with whatever broke between sessions. Nobody presents anything. |
| Written reviewLine by line on your final pull request, ending with what to change first. | 1 | Line by line on your final pull request, ending with what to change first. |
| Yours to keep | ||
| Course repositoryA branch for each person, with the tutor's commits beside yours. | 1 | A branch for each person, with the tutor's commits beside yours. |
| Recordings and notesStill there after the course ends. Nothing gets locked away. | All | Still there after the course ends. Nothing gets locked away. |
questions
Asked before the first session.
Can't find yours? Write to us. The tutors on both planes read the inbox themselves.
Go or Rust?
What does a week on a course look like?
What happens after I ask for a seat?
I write Python or JavaScript. Where do I start?
Is Rust too hard for backend work?
I've written Go or Rust for years. Is there anything here for me?
What do I need on my computer?
What are the rings?
Why does every price end in 64p?
int64 in Go, i64 in Rust. It's the one number both languages agree on, and it's how many courses we teach.Can my employer pay?
Can I join from outside the UK?
Is Bitwrite connected to Go or Rust?
How do refunds work?
start here
Write it in Go.
Small, plain and fast to ship. A runtime schedules your goroutines and collects your garbage, and you learn exactly what that costs.
or here
Write it in Rust.
No collector and no data races, enforced before the program runs. The compiler argues with you, and you learn what it's protecting.
Not sure which? Write to us about what you're building and where it hurts: [email protected]