Files

149 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Script: A Trick for Designing Friendly APIs in Go
---
### The Hook (The Pain)
**[VISUAL: Face Camera]**
"There is nothing worse than opening a codebase, finding a constructor, and seeing a list of magic numbers and boolean flags."
"You know the ones. `NewServer(true, 30, false)`."
"What is true? What is 30? Is false good or bad? You have to go read the definition just to understand the call site. Its a bad developer experience."
---
### The Problem
**[VISUAL: Slide 2 - The Optional Configuration Problem]**
"This is the problem we are trying to solve. The 'Optional Configuration' problem."
"Go doesn't support method overloading like C# or Java. So when you write a constructor like `NewServer`, youre stuck with that signature."
"If you have optional parameters—like a timeout or a verbose flag—you end up forcing the user to pass `0` or `nil` or `true` just to satisfy the compiler."
---
### The Breaking Change
**[VISUAL: Slide 3 - "We need to add a TLS parameter"]**
"And it gets worse when requirements change. Let's say six months later, you need to add TLS support."
"If you just add a parameter to the function, you have now broken every single place in your application where `NewServer` was called. You have to go refactor the entire world just to add one optional setting."
---
### The "Okay" Alternative
**[VISUAL: Slide 4 - "Just use a struct"]**
"Now, the common response is: 'Just use a config struct.'"
"And honestly? This is fine. It's better than magic numbers. But it has a flaw: Ambiguity around zero values."
"If I pass `Port: 0` in that config... do I mean 'Please bind to a random available port'? Or do I mean 'I forgot to set this, please use the default port 80'?"
"Distinguishing between 'default' and 'intentionally zero' is annoying with structs."
---
### The Solution
**[VISUAL: Slide 5 - "Nah bro, functional options"]**
"So, the Go community settled on a better pattern. Functional Options."
"It looks a little scary at first because it uses closures, but once you get it, youll never go back."
---
### Step 1: The Type
**[VISUAL: Slide 6 - 1. Define the option]**
"Step one: We define our Server struct, but we keep the fields unexported."
"Then, we define a type—let's call it `Option`. An `Option` is just a function that takes a pointer to your Server and modifies it. It returns nothing."
---
### Step 2: The Closures
**[VISUAL: Slide 7 - 2. Create closures]**
"Step two: We create 'Constructor' functions that return that `Option` type."
"This is where the magic happens. Look at `WithPort`. It takes an integer, and it returns a closure that *captures* that integer."
"When that inner function eventually runs, it will apply that specific port to the server."
---
### 2:45 - Step 3: The Variadic Constructor
**[VISUAL: Slide 8 - 3. Get variadic]**
"Step three: The Constructor."
"Instead of taking a fixed list of arguments, we take a variadic slice of our `Option` type."
**[CLICK to reveal the implementation]**
"Inside the constructor, we do three things:"
1. "We initialize the server with sensible **defaults**. (Host is localhost, Port is 80)."
2. "We loop through the provided options and execute them. This overwrites the defaults with whatever the user provided."
3. "We return the server."
---
### The Result
**[VISUAL: Slide 9 - Almost as good as C#]**
"The result is a beautiful API usage."
"For my C# friends out there, this feels a lot like Named Parameters. It reads like a sentence: `NewServer, WithHost, WithPort`."
"I don't need to know what the default timeout is. I don't need to pass `nil` for things I don't care about. I just declare what I want to change."
---
### Extensibility
**[VISUAL: Slide 10 - Extensibility? We got you.]**
"But the killer feature is extensibility."
**[CLICK to reveal WithTLS]**
"Let's go back to that TLS requirement. I can add a `WithTLS` option function..."
**[CLICK to reveal usage]**
"...and I don't break a single existing line of code. `srv` (the first one) still compiles perfectly. `srv2` uses the new feature. Backward compatibility is preserved."
---
### Summary
**[VISUAL: Slide 11 - So why use this pattern?]**
"To recap, why should you use this?"
**[CLICK]** "1. Defaults are easy. You define them once in the constructor, and the user never has to think about them."
**[CLICK]** "2. It's self-documenting. No more `true, false, 30`."
**[CLICK]** "3. It's future-proof. You can add new options forever without breaking your consumers."
---
### Outro
**[VISUAL: Slide 12 - Go forth...]**
"This is the standard for a reason. If you're building a library or a package in Go, treat your users nicely. Use Functional Options."
"I'll see you in the next one."