|
| 1 | +## :handshake: Our Partnership |
| 2 | + |
| 3 | +**We're building this together.** You're not just executing tasks - you're helping design and implement the best possible solution. This means: |
| 4 | + |
| 5 | +- Challenge my suggestions when something feels wrong |
| 6 | +- Ask me to explain my reasoning |
| 7 | +- Propose alternative approaches |
| 8 | +- Take time to think through problems |
| 9 | + |
| 10 | +**Quality is non-negotiable.** We'd rather spend an hour designing than 3 hours fixing a rushed implementation. |
| 11 | + |
| 12 | +## :thought_balloon: Before We Code |
| 13 | + |
| 14 | +Always discuss first: |
| 15 | +- What problem are we solving? |
| 16 | +- What's the ideal solution? |
| 17 | +- What tests would prove it works? |
| 18 | +- Are we making the codebase better? |
| 19 | + |
| 20 | +## Strict Task Adherence |
| 21 | + |
| 22 | +**Only do exactly what I ask for - nothing more, nothing less.** |
| 23 | + |
| 24 | +- Do NOT proactively update documentation unless explicitly requested |
| 25 | +- Do NOT add explanatory comments unless asked |
| 26 | +- Do NOT make "improvements" or "clean up" code beyond the specific task |
| 27 | +- Do NOT add features, optimizations, or enhancements I didn't mention |
| 28 | +- If there is something you think should be done, suggest it, but don't do it until asked to |
| 29 | + |
| 30 | +**Red flags that indicate you're going beyond the task:** |
| 31 | +- "Let me also..." |
| 32 | +- "While I'm at it..." |
| 33 | +- "I should also update..." |
| 34 | +- "Let me improve..." |
| 35 | +- "I'll also clean up..." |
| 36 | + |
| 37 | +**If the task is complete, STOP. Don't look for more work to do.** |
| 38 | + |
| 39 | +## :test_tube: Test-Driven Development |
| 40 | + |
| 41 | +TDD isn't optional - it's how we ensure quality: |
| 42 | + |
| 43 | +### The TDD Cycle |
| 44 | +1. **Red** - Write a failing test that defines success |
| 45 | +2. **Green** - Write minimal code to pass |
| 46 | +3. **Refactor** - Make it clean and elegant |
| 47 | + |
| 48 | +### Example TDD Session |
| 49 | +```go |
| 50 | +// Step 1: Write the test first |
| 51 | +func TestConnectionBilateralCleanup(t *testing.T) { |
| 52 | + // Define what success looks like |
| 53 | + client, server := testutils.CreateConnectedTCPPair() |
| 54 | + |
| 55 | + // Test the behavior we want |
| 56 | + client.Close() |
| 57 | + |
| 58 | + // Both sides should be closed |
| 59 | + assert.Eventually(t, func() bool { |
| 60 | + return isConnectionClosed(server) |
| 61 | + }) |
| 62 | +} |
| 63 | + |
| 64 | +// Step 2: See it fail (confirms we're testing the right thing) |
| 65 | +// Step 3: Implement the feature |
| 66 | +// Step 4: See it pass |
| 67 | +// Step 5: Refactor for clarity |
| 68 | +``` |
| 69 | + |
| 70 | +To make sure tests are easy to read, we use testify assertions. Make sure to use assert.Eventually instead of using manual thread.sleep and timeouts. |
| 71 | + |
| 72 | +## :rotating_light: Error Handling Excellence |
| 73 | + |
| 74 | +Error handling is not an afterthought - it's core to reliable software. |
| 75 | + |
| 76 | +### Go Error Patterns |
| 77 | +```go |
| 78 | +// YES - Clear error context |
| 79 | +func ProcessUser(id string) (*User, error) { |
| 80 | + if id == "" { |
| 81 | + return nil, fmt.Errorf("user ID cannot be empty") |
| 82 | + } |
| 83 | + |
| 84 | + user, err := db.GetUser(id) |
| 85 | + if err != nil { |
| 86 | + return nil, fmt.Errorf("failed to get user %s: %w", id, err) |
| 87 | + } |
| 88 | + |
| 89 | + return user, nil |
| 90 | +} |
| 91 | + |
| 92 | +// NO - Swallowing errors |
| 93 | +func ProcessUser(id string) *User { |
| 94 | + user, _ := db.GetUser(id) // What if this fails? |
| 95 | + return user |
| 96 | +} |
| 97 | +``` |
| 98 | + |
| 99 | +### Error Handling Principles |
| 100 | +1. **Wrap errors with context** - Use `fmt.Errorf("context: %w", err)` |
| 101 | +2. **Validate early** - Check inputs before doing work |
| 102 | +3. **Fail fast** - Don't continue with invalid state |
| 103 | +4. **Log appropriately** - Errors at boundaries, debug info internally |
| 104 | +5. **Return structured errors** - Use error types for different handling |
| 105 | + |
| 106 | +### Testing Error Paths |
| 107 | +```go |
| 108 | +func TestProcessUser_InvalidID(t *testing.T) { |
| 109 | + _, err := ProcessUser("") |
| 110 | + assert.ErrorContains(t, err, "cannot be empty") |
| 111 | +} |
| 112 | + |
| 113 | +func TestProcessUser_DatabaseError(t *testing.T) { |
| 114 | + mockDB.EXPECT().GetUser("123").Return(nil, errors.New("db connection failed")) |
| 115 | + |
| 116 | + _, err := ProcessUser("123") |
| 117 | + assert.ErrorContains(t, err, "failed to get user") |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +## :triangular_ruler: Design Principles |
| 122 | + |
| 123 | +### 1. Simple is Better Than Clever |
| 124 | +```go |
| 125 | +// YES - Clear and obvious |
| 126 | +if user.NeedsMigration() { |
| 127 | + return migrate(user) |
| 128 | +} |
| 129 | + |
| 130 | +// NO - Clever but unclear |
| 131 | +return user.NeedsMigration() && migrate(user) || user |
| 132 | +``` |
| 133 | + |
| 134 | +### 2. Explicit is Better Than Implicit |
| 135 | +- Clear function names |
| 136 | +- Obvious parameter types |
| 137 | +- No hidden side effects |
| 138 | + |
| 139 | +### 3. Performance with Clarity |
| 140 | +- Optimize hot paths |
| 141 | +- But keep code readable |
| 142 | +- Document why, not what |
| 143 | + |
| 144 | +### 4. Fail Fast and Clearly |
| 145 | +- Validate inputs early |
| 146 | +- Return clear error messages |
| 147 | +- Help future debugging |
| 148 | + |
| 149 | +### 5. Interfaces Define What You Need, Not What You Provide |
| 150 | +- When you need something from another component, define the interface in your package |
| 151 | +- Don't look at what someone else provides - define exactly what you require |
| 152 | +- This keeps interfaces small, focused, and prevents unnecessary coupling |
| 153 | +- Types and their methods live together. At the top of files, use a single ```type ()``` with all type declarations inside. |
| 154 | + |
| 155 | +### 6. Go-Specific Best Practices |
| 156 | +- **Receiver naming** - Use consistent, short receiver names (e.g., `u *User`, not `user *User`) |
| 157 | +- **Package naming** - Short, descriptive, lowercase without underscores |
| 158 | +- **Interface naming** - Single-method interfaces end in `-er` (Reader, Writer, Handler) |
| 159 | +- **Context first** - Always pass `context.Context` as the first parameter |
| 160 | +- **Channels for coordination** - Use channels to coordinate goroutines, not shared memory |
| 161 | + |
| 162 | +## :mag: Dubugging & Troubleshooting |
| 163 | + |
| 164 | +When things don't work as expected, we debug systematically: |
| 165 | + |
| 166 | +### Debugging Strategy |
| 167 | +1. **Reproduce reliably** - Create a minimal failing case |
| 168 | +2. **Isolate the problem** - Binary search through the system |
| 169 | +3. **Understand the data flow** - Trace inputs and outputs |
| 170 | +4. **Question assumptions** - What did we assume was working? |
| 171 | +5. **Fix the root cause** - Not just the symptoms |
| 172 | + |
| 173 | +### Debugging Tools & Techniques |
| 174 | +```go |
| 175 | +// Use structured logging for debugging |
| 176 | +log.WithFields(log.Fields{ |
| 177 | + "user_id": userID, |
| 178 | + "action": "process_payment", |
| 179 | + "amount": amount, |
| 180 | +}).Debug("Starting payment processing") |
| 181 | + |
| 182 | +// Add strategic debug points |
| 183 | +func processPayment(amount float64) error { |
| 184 | + log.Debugf("processPayment called with amount: %f", amount) |
| 185 | + |
| 186 | + if amount <= 0 { |
| 187 | + return fmt.Errorf("invalid amount: %f", amount) |
| 188 | + } |
| 189 | + |
| 190 | + // More processing... |
| 191 | + log.Debug("Payment validation passed") |
| 192 | + return nil |
| 193 | +} |
| 194 | +``` |
| 195 | + |
| 196 | +### When Stuck |
| 197 | +- Write a test that reproduces the issue |
| 198 | +- Add logging to understand data flow |
| 199 | +- Use the debugger to step through code |
| 200 | +- Rubber duck explain the problem |
| 201 | +- Take a break and come back fresh |
| 202 | + |
| 203 | +## :recycle: Refactoring Legacy Code |
| 204 | + |
| 205 | +When improving existing code, we move carefully and systematically: |
| 206 | + |
| 207 | +### Refactoring Strategy |
| 208 | +1. **Understand first** - Read and comprehend the existing code |
| 209 | +2. **Add tests** - Create safety nets before changing anything |
| 210 | +3. **Small steps** - Make tiny, verifiable improvements |
| 211 | +4. **Preserve behavior** - Keep the same external interface |
| 212 | +5. **Measure improvement** - Verify it's actually better |
| 213 | + |
| 214 | +### Safe Refactoring Process |
| 215 | +```go |
| 216 | +// Step 1: Add characterization tests |
| 217 | +func TestLegacyProcessor_ExistingBehavior(t *testing.T) { |
| 218 | + processor := &LegacyProcessor{} |
| 219 | + |
| 220 | + // Document current behavior, even if it seems wrong |
| 221 | + result := processor.Process("input") |
| 222 | + assert.Equal(t, "weird_legacy_output", result) |
| 223 | +} |
| 224 | + |
| 225 | +// Step 2: Refactor with tests passing |
| 226 | +func (p *LegacyProcessor) Process(input string) string { |
| 227 | + // Improved implementation that maintains the same behavior |
| 228 | + return processWithNewLogic(input) |
| 229 | +} |
| 230 | + |
| 231 | +// Step 3: Now we can safely change the behavior |
| 232 | +func TestProcessor_ImprovedBehavior(t *testing.T) { |
| 233 | + processor := &Processor{} |
| 234 | + |
| 235 | + result := processor.Process("input") |
| 236 | + assert.Equal(t, "expected_output", result) |
| 237 | +} |
| 238 | +``` |
| 239 | + |
| 240 | +## :arrows_counterclockwise: Development Workflow |
| 241 | + |
| 242 | +### Starting a Feature |
| 243 | +1. **Discuss** - "I'm thinking about implementing X. Here's my approach..." |
| 244 | +2. **Design** - Sketch out the API and key components |
| 245 | +3. **Test** - Write tests that define the behavior |
| 246 | +4. **Implement** - Make the tests pass |
| 247 | +5. **Review** - "Does this make sense? Any concerns?" |
| 248 | + |
| 249 | +### Making Changes |
| 250 | +1. **Small PRs** - Easier to review and less risky |
| 251 | +2. **Incremental** - Build features piece by piece |
| 252 | +3. **Always tested** - No exceptions |
| 253 | +4. **Clear commits** - Each commit should have a clear purpose |
| 254 | + |
| 255 | +### Git and PR Workflow |
| 256 | + |
| 257 | +**CRITICAL: Git commands are ONLY for reading state - NEVER for modifying it.** |
| 258 | +- **NEVER** use git commands that modify the filesystem unless explicitly told to commit |
| 259 | +- You may read git state: `git status`, `git log`, `git diff`, `git branch --show-current` |
| 260 | +- You may NOT: `git commit`, `git add`, `git reset`, `git checkout`, `git restore`, `git rebase`, `git push`, etc. |
| 261 | +- **ONLY commit when explicitly asked to commit** |
| 262 | +- When asked to commit, do it once and stop |
| 263 | +- Only I can modify git state unless you've been given explicit permission to commit |
| 264 | + |
| 265 | +**Once a PR is created, NEVER amend commits or rewrite history.** |
| 266 | +- Always create new commits after PR is created |
| 267 | +- No `git commit --amend` after pushing to a PR branch |
| 268 | +- No `git rebase` that rewrites commits in the PR |
| 269 | +- No force pushes to PR branches |
| 270 | +- This keeps the PR history clean and reviewable |
| 271 | + |
| 272 | +**When asked to write a PR description:** |
| 273 | +1. **Use `gh` CLI** - Always use `gh pr edit <number>` to update PRs |
| 274 | +2. **Update both body and title** - Use `--body` and `--title` flags |
| 275 | +3. **Be informal, humble, and short** - Keep it conversational and to the point |
| 276 | +4. **Credit appropriately** - If Claude Code wrote most of it, mention that |
| 277 | +5. **Example format**: |
| 278 | + ``` |
| 279 | + ## What's this? |
| 280 | + [Brief explanation of the feature/fix] |
| 281 | +
|
| 282 | + ## How it works |
| 283 | + [Key implementation details] |
| 284 | +
|
| 285 | + ## Usage |
| 286 | + [Code examples if relevant] |
| 287 | +
|
| 288 | + --- |
| 289 | + _Most of this was written by Claude Code - I just provided direction._ |
| 290 | + ``` |
| 291 | + |
| 292 | +## :memo: Code Review Mindset |
| 293 | + |
| 294 | +When reviewing code (yours or mine), ask: |
| 295 | +- Is this the simplest solution? |
| 296 | +- Will this make sense in 6 months? |
| 297 | +- Are edge cases handled? |
| 298 | +- Is it well tested? |
| 299 | +- Does it improve the codebase? |
| 300 | + |
| 301 | +## :dart: Common Patterns |
| 302 | + |
| 303 | +### Feature Implementation |
| 304 | +``` |
| 305 | +You: "Let's add feature X" |
| 306 | +Me: "Sounds good! What's the API going to look like? What are the main use cases?" |
| 307 | +[Discussion of design] |
| 308 | +Me: "Let me write some tests to clarify the behavior we want" |
| 309 | +[TDD implementation] |
| 310 | +Me: "Here's what I've got. What do you think?" |
| 311 | +``` |
| 312 | + |
| 313 | +### Bug Fixing |
| 314 | +``` |
| 315 | +You: "We have a bug where X happens" |
| 316 | +Me: "Let's write a test that reproduces it first" |
| 317 | +[Test that fails] |
| 318 | +Me: "Great, now we know exactly what we're fixing" |
| 319 | +[Fix implementation] |
| 320 | +``` |
| 321 | + |
| 322 | +### Performance Work |
| 323 | +``` |
| 324 | +You: "This seems slow" |
| 325 | +Me: "Let's benchmark it first to get a baseline" |
| 326 | +[Benchmark results] |
| 327 | +Me: "Now let's optimize without breaking functionality" |
| 328 | +[Optimization with tests passing] |
| 329 | +``` |
| 330 | + |
| 331 | +## :rocket: Shipping Quality |
| 332 | + |
| 333 | +Before considering any work "done": |
| 334 | +- [ ] Tests pass and cover the feature |
| 335 | +- [ ] Code is clean and readable |
| 336 | +- [ ] Edge cases are handled |
| 337 | +- [ ] Performance is acceptable |
| 338 | +- [ ] Documentation is updated if needed |
| 339 | +- [ ] We're both happy with it |
| 340 | + |
| 341 | +Remember: We're crafting software, not just making it work. Every line of code is an opportunity to make the system better. |
0 commit comments