Polyglot Developer Patterns
Senior developer who learns new languages efficiently, reviews code across unfamiliar languages, translates idioms between paradigms, and builds long-term multi-language fluency without burning context-switching bandwidth.
TL;DR Checklist
When to Use
Use this skill when:
- Starting work in a programming language you have not used recently or at all
- Reading or reviewing code written in a language outside your primary expertise
- Translating an implementation from one language to another (e.g., Go service to Rust)
- Coaching or mentoring someone learning a new language
- Deciding which language is appropriate for a new microservice or module
- Building a personal study plan to achieve fluency in a second or third language
When NOT to Use
Avoid this skill for:
- Cross-language system architecture decisions — use
polyglot-development instead (gRPC, Protobuf, monorepo structure)
- Choosing technologies for an organization's tech stack — use
framework-selection instead
- Migrating a codebase between major versions of the same language — use
version-migration instead
- Setting up CI/CD pipelines that must compile multiple languages — that is infrastructure, not developer patterns
Core Workflow
Map the Language's Mental Model — Identify the paradigm, type system, memory model, and error-handling philosophy. Checkpoint: Write a one-paragraph summary in your own words: "This language treats X like Y because of Z."
Anchor to Known Concepts — List 5 concepts from your strongest language and write how they map in the target language. Checkpoint: If you cannot find equivalents for type safety, error handling, and concurrency, flag this as a learning priority.
Write a Rosetta Script — Implement a small but complete program that exercises core features: I/O, control flow, error handling, and one advanced feature (generics, traits, async). Checkpoint: The script should run without warnings under the language's strictest lint mode.
Read Real Examples — Study 2-3 examples from the standard library or well-maintained OSS projects. Focus on how experts handle the features you are learning. Checkpoint: Identify one idiomatic pattern that surprised you and note why it works better than what you would have written.
Translate a Pattern — Take a function or module from your known language and rewrite it in the target language, prioritizing idiomatic style over direct equivalence. Checkpoint: Compare your translation to a native speaker's approach (from step 4) and adjust at least one pattern.
Batch Context Switches — Schedule focused blocks of 2+ hours per language. Keep a running "language cheat sheet" for each active project. Checkpoint: Before switching languages, write down the current mental model state so resumption costs are minimal.
Learning Strategies
The 48-Hour Rule
Within 48 hours of first encountering a new language, you should be able to:
- Read and understand moderately complex source code
- Write a program that reads input, transforms it, and produces output
- Handle errors without crashing (no silent failures)
This is not fluency — it is the minimum threshold for productive collaboration. Anything less means you cannot contribute meaningfully until your study catches up.
The Translation Ladder
Build proficiency through staged translations of increasing difficulty:
| Stage |
Task |
Expected Time to Completion |
| 1 |
Copy a known algorithm (e.g., binary search) verbatim |
30 minutes — syntax lookup only |
| 2 |
Rewrite the same algorithm idiomatically |
60 minutes — must research standard library patterns |
| 3 |
Translate a small but real function from your codebase |
2-4 hours — includes design decisions, not just syntax |
| 4 |
Build a new feature in the target language using only its idioms |
1-2 days — requires paradigm-level thinking |
Do not jump past Stage 2. Skipping to Stage 3 with shallow knowledge produces fragile code and frustration.
The Error-Handling First Rule
Error handling reveals a language's philosophy more than anything else. Study it first:
- Does the language use exceptions, result types, error codes, or a combination?
- Are errors values you must handle explicitly, or does the runtime catch them?
- What is the convention for wrapping errors with context?
// Go: explicit error handling — every call must check err
func readFile(path string) ([]byte, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("read %s: %w", path, err) // wrap with context
}
return data, nil
}
// Rust: Result type forces explicit handling at call site
fn read_file(path: &str) -> Result<Vec<u8>, io::Error> {
let data = std::fs::read(path)
.map_err(|e| io::Error::new(io::ErrorKind::PermissionDenied, e))?; // ? propagates errors
Ok(data)
}
// Python: exceptions are control flow — use try/except blocks
def read_file(path: str) -> bytes:
try:
with open(path, "rb") as f:
return f.read()
except FileNotFoundError:
raise RuntimeError(f"File not found: {path}") from None // suppress internal chain for clarity
Code Review in Unfamiliar Languages
When reviewing code in a language you do not know well, shift your focus from style to substance. Your goal is to validate correctness and architecture, not to nitpick formatting conventions you cannot judge fairly.
Review Priority Matrix
| Concern |
Confidence Level |
Action |
| Logic correctness (off-by-one, null handling) |
High — logic is language-agnostic |
Deep review required |
| API design and public interface shape |
Medium — concepts transfer across languages |
Review with caution |
| Error handling patterns |
Low in unfamiliar language |
Flag for native developer |
| Performance characteristics (algorithms, data structures) |
Medium if you know the domain well |
Review algorithm choice, defer implementation details |
| Idiomatic style (naming conventions, standard library usage) |
Low unless language is familiar |
Skip or note as "check with local expert" |
Concrete Review Technique: The Abstraction Pass
First pass — ignore syntax. Read the code as pseudocode. Trace the data flow manually. If you cannot follow the logic, the code needs comments regardless of language.
Second pass — identify language-specific patterns. Look for error handling, resource management (RAII, goroutines, try-with-resources), and concurrency primitives. These are often where bugs hide in unfamiliar languages.
Third pass — flag idiomatic concerns. If you spot something that looks suspiciously like a pattern from your home language translated literally, flag it as "may not be idiomatic" without claiming authority on correctness.
Pattern Translation Guide
OOP to Functional: Polymorphism via Traits/Interfaces
When moving from class-based polymorphism (Java, C#) to functional or trait-based systems (Rust, Go), the translation is about behavior contracts rather than inheritance hierarchies.
// ❌ BAD: Translating Java-style interface directly into Go with unnecessary abstraction
type Shape interface {
Area() float64
Perimeter() float64
}
// Then forcing every shape through this interface even for single-use functions
func totalArea(shapes []Shape) float64 { ... } // Over-engineered for simple aggregation
// ✅ GOOD: Use Go's structural typing — no explicit interface needed
type Rectangle struct { Width, Height float64 }
type Circle struct { Radius float64 }
// Functions accept structs directly; the compiler checks compatibility implicitly
func (r Rectangle) Area() float64 { return r.Width * r.Height }
func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }
func totalArea(shapes ...interface{ Area() float64 }) float64 { // Go 1.18+ type sets for simple cases
var total float64
for _, s := range shapes {
total += s.Area()
}
return total
}
// Even better: use generics when you need a collection of anything with an Area method
func sumAreas[S interface{ Area() float64 ](items []S) float64 {
var total float64
for _, item := range items {
total += item.Area()
}
return total
}
// Usage — no wrapper types, no explicit interface declarations
rects := []Rectangle{{5, 3}, {10, 2}}
circles := []Circle{{1.0}, {2.5}}
fmt.Println(sumAreas(rects) + sumAreas(circles)) // 37.85...
Error Handling Across Paradigms: Try/Catch vs Result Types vs Panics
// ❌ BAD: Using unwrap() on external data — panics in production, hides errors
fn get_user_config(path: &str) -> String {
let file = std::fs::read_to_string(path).unwrap(); // Panics if file missing!
parse_config(&file)
}
// ✅ GOOD: Result type forces callers to handle the error
fn get_user_config(path: &str) -> Result<String, ConfigError> {
let file = std::fs::read_to_string(path)
.map_err(|e| ConfigError::ReadFailed { path: path.to_string(), source: e })?;
parse_config(&file).map_err(ConfigError::ParseFailed)
}
// ✅ GOOD (when panic is justified): unwrap only for programmer errors, not data errors
fn get_default_config() -> String {
std::fs::read_to_string(DEFAULT_CONFIG_PATH)
.expect("default config must exist — this is a deployment issue, not user input")
}
// Python equivalent: explicit error handling with proper chaining
def get_user_config(path: str) -> dict:
try:
with open(path) as f:
return parse_config(f.read())
except FileNotFoundError as e:
raise ConfigError(f"Could not read config at {path}") from e // preserves stack trace
except json.JSONDecodeError as e:
raise ConfigError(f"Invalid config format in {path}: {e}") from e
Concurrency Primitives Across Languages
Understanding how a language handles concurrency is critical for polyglot development. The mental model varies dramatically.
// Go: goroutines + channels — light-weight threads with explicit communication
func fetchResults(urls []string) <-chan Result {
ch := make(chan Result, len(urls)) // buffered channel
for _, url := range urls {
go func(u string) { // anonymous goroutine
res, err := httpGet(u)
if err != nil {
ch <- Result{URL: u, Error: err}
} else {
ch <- Result{URL: u, Data: res}
}
}(url)
}
return ch // caller reads from channel until closed
}
// Python: asyncio — cooperative multitasking with event loop
async def fetch_results(urls: list[str]) -> list[Result]:
async with aiohttp.ClientSession() as session:
tasks = [fetch_single(session, url) for url in urls]
results = await asyncio.gather(*tasks) // runs all concurrently
return results
// Rust: tokio + async/await — zero-cost async with explicit ownership
async fn fetch_results(urls: Vec<String>) -> Result<Vec<Result>, Error> {
let client = reqwest::Client::new();
let mut handles = vec![];
for url in urls {
handles.push(tokio::spawn(async move {
match client.get(&url).send().await {
Ok(resp) => Ok(Result { url, data: resp.bytes().await? }),
Err(e) => Err(e.into()),
}
}));
}
let results = futures::future::join_all(handles).await;
results.into_iter().collect::<Result<Vec<_>, _>>()
}
Building Long-Term Fluency
The 80/20 Language Study Plan
For each new language, prioritize learning in this order:
- Week 1 — Syntax & I/O: Hello world, file read/write, basic types, control flow
- Week 2 — Error Handling & Standard Library: How errors work, what the stdlib provides for common tasks (HTTP, JSON, filesystem)
- Week 3 — Concurrency Model: Goroutines/channels, threads/processes, async/await, or whatever the language offers
- Week 4 — Ecosystem & Tooling: Package manager, test framework, linter, debugger — the tools that make daily development possible
By Week 4 you should be able to build and deploy a small service in the new language. Fluency (comfort reading others' code quickly) takes 6-12 months of occasional use.
The Language Journal Pattern
Keep a running document for each active language with:
- One idiomatic example per major concept (error handling, concurrency, collections)
- Common gotchas you have encountered and fixed
- Your personal translation notes ("In Go, I do X; in Python, equivalent is Y")
# Example: A compact Language Journal entry for Rust (stored as markdown/notes)
#
# === RUST NOTES ===
# Error handling: use ? operator to propagate, Result<T, E> for fallible ops
# Ownership: every value has exactly one owner; move vs copy semantics
# Lifetimes: compiler enforces borrow rules — if you hit 'static errors,
# usually means you need a struct instead of borrowing a local variable
# Common gotcha: Vec<&str> borrowed from function scope — must use String or return owned data
#
# Go equivalent patterns:
# - Rust Result -> Go error interface (check after every call)
# - Rust ? operator -> Go if err != nil { return err }
# - Rust lifetimes -> Go pointers + garbage collection (no explicit lifetime management)
The "One Language Per Sprint" Rule
When learning multiple new languages simultaneously, context collision becomes severe. Limit yourself to one primary language in active study per sprint (2-week cycle). Keep others in "maintenance mode" with occasional review of existing code — this preserves enough familiarity without the overhead of active learning.
Context-Switching Management
The Resumption Cost Model
Context switching between languages incurs measurable costs:
- Syntax recall: 15-30 minutes to remember idiomatic syntax patterns
- Mental model shift: OOP vs functional, garbage collected vs ownership-based
- Tool familiarity: Package managers, linters, debuggers differ per language
Mitigation strategy: Create a "launch file" for each project — a single README-style document at the top of every codebase that answers:
- What language? Version? (e.g., Rust 1.78+)
- How to build? (
cargo build)
- How to test? (
cargo test --all)
- One idiomatic code sample from the project
- Known gotchas specific to this repo
This document reduces resumption cost from ~30 minutes to ~3 minutes.
The Parallel Project Rule
When maintaining two language ecosystems simultaneously:
- Time-box each language — e.g., mornings in Go, afternoons in Rust
- Never switch mid-task — finish the current function or bug fix before switching contexts
- Write a 3-line status note before switching: "What I was doing, what blocked me, what to try next"
Constraints
MUST DO
- Always map error handling patterns first when entering an unfamiliar language — this reveals the paradigm immediately
- Write a Rosetta script (Stage 2 translation) before attempting Stage 3 real-world translations
- Read at least two standard library examples per new language concept before writing production code
- Keep language cheat sheets for every active project to minimize resumption costs
- Review unfamiliar-language PRs by tracing data flow first, flagging idiomatic concerns second
- Batch context switches into blocks of at least 2 hours per language
- Use the Abstraction Pass technique when reviewing code in languages you do not know well
MUST NOT DO
- Translate code literally from your home language without checking if the target language has a standard library alternative
- Assume that identical syntax means identical semantics (e.g., Rust
= is move, not copy)
- Review style nitpicks in unfamiliar languages when you could validate logic correctness instead
- Study multiple new languages simultaneously beyond Stage 1 (syntax basics) — context collision is real and harmful
- Skip error handling study — it is the single best indicator of a language's design philosophy
- Use
unwrap() or panic! equivalents on external data in production code — that is the primary source of runtime crashes across all languages
Output Template
When applying this skill to help a developer, produce:
- Language Profile Summary — Paradigm, type system, error handling style, concurrency model (one paragraph each)
- Translation Map — 3-5 key concepts mapped from the developer's home language to the target language with code examples
- Rosetta Script — A complete, runnable program that exercises core language features
- Review Notes — For PR review: logic correctness findings + idiomatic suggestions (clearly labeled as such)
- Next Steps — Specific study tasks for the next sprint based on gaps identified
Related Skills
| Skill |
Purpose |
polyglot-development |
Cross-language system architecture (gRPC, Protobuf, monorepo) — for architects and team leads |
framework-selection |
Choosing technologies and frameworks — when you need to decide which language to learn next |
version-migration |
Migrating codebases between major language versions — when the language itself is the same but the version changed |
single-letter-variables |
Readability anti-patterns — relevant because polyglot developers sometimes carry bad naming habits across languages |
Live References
Authoritative documentation and learning resources for polyglot development. These links provide official, up-to-date guidance on language paradigms, idioms, and best practices.
1---2name: polyglot-developer-patterns3description: Equips individual developers with learning strategies, code review techniques, and pattern translation methods to build fluency across multiple programming languages without losing productivity.4license: MIT5---678910# Polyglot Developer Patterns1112Senior developer who learns new languages efficiently, reviews code across unfamiliar languages, translates idioms between paradigms, and builds long-term multi-language fluency without burning context-switching bandwidth.1314## TL;DR Checklist1516- [ ] Identify language paradigm (OOP, functional, procedural, data-oriented) before reading code17- [ ] Map core concepts: type system, memory model, error handling, concurrency primitives18- [ ] Write a "Rosetta script" in the new language to exercise its idioms directly19- [ ] Use existing knowledge as an anchor — translate patterns from your strongest language first20- [ ] Read real-world examples (stdlib, popular OSS) before writing production code21- [ ] Batch context switches — spend at least 2 hours in one language before switching22- [ ] Review unfamiliar-language PRs by focusing on logic correctness over style nitpicks2324---2526## When to Use2728Use this skill when:2930- Starting work in a programming language you have not used recently or at all31- Reading or reviewing code written in a language outside your primary expertise32- Translating an implementation from one language to another (e.g., Go service to Rust)33- Coaching or mentoring someone learning a new language34- Deciding which language is appropriate for a new microservice or module35- Building a personal study plan to achieve fluency in a second or third language3637---3839## When NOT to Use4041Avoid this skill for:4243- Cross-language system architecture decisions — use `polyglot-development` instead (gRPC, Protobuf, monorepo structure)44- Choosing technologies for an organization's tech stack — use `framework-selection` instead45- Migrating a codebase between major versions of the same language — use `version-migration` instead46- Setting up CI/CD pipelines that must compile multiple languages — that is infrastructure, not developer patterns4748---4950## Core Workflow51521. **Map the Language's Mental Model** — Identify the paradigm, type system, memory model, and error-handling philosophy. **Checkpoint:** Write a one-paragraph summary in your own words: "This language treats X like Y because of Z."53542. **Anchor to Known Concepts** — List 5 concepts from your strongest language and write how they map in the target language. **Checkpoint:** If you cannot find equivalents for type safety, error handling, and concurrency, flag this as a learning priority.55563. **Write a Rosetta Script** — Implement a small but complete program that exercises core features: I/O, control flow, error handling, and one advanced feature (generics, traits, async). **Checkpoint:** The script should run without warnings under the language's strictest lint mode.57584. **Read Real Examples** — Study 2-3 examples from the standard library or well-maintained OSS projects. Focus on how experts handle the features you are learning. **Checkpoint:** Identify one idiomatic pattern that surprised you and note why it works better than what you would have written.59605. **Translate a Pattern** — Take a function or module from your known language and rewrite it in the target language, prioritizing idiomatic style over direct equivalence. **Checkpoint:** Compare your translation to a native speaker's approach (from step 4) and adjust at least one pattern.61626. **Batch Context Switches** — Schedule focused blocks of 2+ hours per language. Keep a running "language cheat sheet" for each active project. **Checkpoint:** Before switching languages, write down the current mental model state so resumption costs are minimal.6364---6566## Learning Strategies6768### The 48-Hour Rule6970Within 48 hours of first encountering a new language, you should be able to:71- Read and understand moderately complex source code72- Write a program that reads input, transforms it, and produces output73- Handle errors without crashing (no silent failures)7475This is not fluency — it is the minimum threshold for productive collaboration. Anything less means you cannot contribute meaningfully until your study catches up.7677### The Translation Ladder7879Build proficiency through staged translations of increasing difficulty:8081| Stage | Task | Expected Time to Completion |82|-------|------|----------------------------|83| 1 | Copy a known algorithm (e.g., binary search) verbatim | 30 minutes — syntax lookup only |84| 2 | Rewrite the same algorithm idiomatically | 60 minutes — must research standard library patterns |85| 3 | Translate a small but real function from your codebase | 2-4 hours — includes design decisions, not just syntax |86| 4 | Build a new feature in the target language using only its idioms | 1-2 days — requires paradigm-level thinking |8788Do not jump past Stage 2. Skipping to Stage 3 with shallow knowledge produces fragile code and frustration.8990### The Error-Handling First Rule9192Error handling reveals a language's philosophy more than anything else. Study it first:93- Does the language use exceptions, result types, error codes, or a combination?94- Are errors values you must handle explicitly, or does the runtime catch them?95- What is the convention for wrapping errors with context?9697```go98// Go: explicit error handling — every call must check err99func readFile(path string) ([]byte, error) {100 data, err := os.ReadFile(path)101 if err != nil {102 return nil, fmt.Errorf("read %s: %w", path, err) // wrap with context103 }104 return data, nil105}106107// Rust: Result type forces explicit handling at call site108fn read_file(path: &str) -> Result<Vec<u8>, io::Error> {109 let data = std::fs::read(path)110 .map_err(|e| io::Error::new(io::ErrorKind::PermissionDenied, e))?; // ? propagates errors111 Ok(data)112}113114// Python: exceptions are control flow — use try/except blocks115def read_file(path: str) -> bytes:116 try:117 with open(path, "rb") as f:118 return f.read()119 except FileNotFoundError:120 raise RuntimeError(f"File not found: {path}") from None // suppress internal chain for clarity121```122123---124125## Code Review in Unfamiliar Languages126127When reviewing code in a language you do not know well, shift your focus from style to substance. Your goal is to validate correctness and architecture, not to nitpick formatting conventions you cannot judge fairly.128129### Review Priority Matrix130131| Concern | Confidence Level | Action |132|---------|-----------------|--------|133| Logic correctness (off-by-one, null handling) | High — logic is language-agnostic | Deep review required |134| API design and public interface shape | Medium — concepts transfer across languages | Review with caution |135| Error handling patterns | Low in unfamiliar language | Flag for native developer |136| Performance characteristics (algorithms, data structures) | Medium if you know the domain well | Review algorithm choice, defer implementation details |137| Idiomatic style (naming conventions, standard library usage) | Low unless language is familiar | Skip or note as "check with local expert" |138139### Concrete Review Technique: The Abstraction Pass1401411. **First pass — ignore syntax.** Read the code as pseudocode. Trace the data flow manually. If you cannot follow the logic, the code needs comments regardless of language.1421432. **Second pass — identify language-specific patterns.** Look for error handling, resource management (RAII, goroutines, try-with-resources), and concurrency primitives. These are often where bugs hide in unfamiliar languages.1441453. **Third pass — flag idiomatic concerns.** If you spot something that looks suspiciously like a pattern from your home language translated literally, flag it as "may not be idiomatic" without claiming authority on correctness.146147---148149## Pattern Translation Guide150151### OOP to Functional: Polymorphism via Traits/Interfaces152153When moving from class-based polymorphism (Java, C#) to functional or trait-based systems (Rust, Go), the translation is about behavior contracts rather than inheritance hierarchies.154155```go156// ❌ BAD: Translating Java-style interface directly into Go with unnecessary abstraction157type Shape interface {158 Area() float64159 Perimeter() float64160}161162// Then forcing every shape through this interface even for single-use functions163func totalArea(shapes []Shape) float64 { ... } // Over-engineered for simple aggregation164165// ✅ GOOD: Use Go's structural typing — no explicit interface needed166type Rectangle struct { Width, Height float64 }167type Circle struct { Radius float64 }168169// Functions accept structs directly; the compiler checks compatibility implicitly170func (r Rectangle) Area() float64 { return r.Width * r.Height }171func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }172173func totalArea(shapes ...interface{ Area() float64 }) float64 { // Go 1.18+ type sets for simple cases174 var total float64175 for _, s := range shapes {176 total += s.Area()177 }178 return total179}180181// Even better: use generics when you need a collection of anything with an Area method182func sumAreas[S interface{ Area() float64 ](items []S) float64 {183 var total float64184 for _, item := range items {185 total += item.Area()186 }187 return total188}189190// Usage — no wrapper types, no explicit interface declarations191rects := []Rectangle{{5, 3}, {10, 2}}192circles := []Circle{{1.0}, {2.5}}193fmt.Println(sumAreas(rects) + sumAreas(circles)) // 37.85...194```195196### Error Handling Across Paradigms: Try/Catch vs Result Types vs Panics197198```rust199// ❌ BAD: Using unwrap() on external data — panics in production, hides errors200fn get_user_config(path: &str) -> String {201 let file = std::fs::read_to_string(path).unwrap(); // Panics if file missing!202 parse_config(&file)203}204205// ✅ GOOD: Result type forces callers to handle the error206fn get_user_config(path: &str) -> Result<String, ConfigError> {207 let file = std::fs::read_to_string(path)208 .map_err(|e| ConfigError::ReadFailed { path: path.to_string(), source: e })?;209 parse_config(&file).map_err(ConfigError::ParseFailed)210}211212// ✅ GOOD (when panic is justified): unwrap only for programmer errors, not data errors213fn get_default_config() -> String {214 std::fs::read_to_string(DEFAULT_CONFIG_PATH)215 .expect("default config must exist — this is a deployment issue, not user input")216}217218// Python equivalent: explicit error handling with proper chaining219def get_user_config(path: str) -> dict:220 try:221 with open(path) as f:222 return parse_config(f.read())223 except FileNotFoundError as e:224 raise ConfigError(f"Could not read config at {path}") from e // preserves stack trace225 except json.JSONDecodeError as e:226 raise ConfigError(f"Invalid config format in {path}: {e}") from e227```228229### Concurrency Primitives Across Languages230231Understanding how a language handles concurrency is critical for polyglot development. The mental model varies dramatically.232233```go234// Go: goroutines + channels — light-weight threads with explicit communication235func fetchResults(urls []string) <-chan Result {236 ch := make(chan Result, len(urls)) // buffered channel237 for _, url := range urls {238 go func(u string) { // anonymous goroutine239 res, err := httpGet(u)240 if err != nil {241 ch <- Result{URL: u, Error: err}242 } else {243 ch <- Result{URL: u, Data: res}244 }245 }(url)246 }247 return ch // caller reads from channel until closed248}249250// Python: asyncio — cooperative multitasking with event loop251async def fetch_results(urls: list[str]) -> list[Result]:252 async with aiohttp.ClientSession() as session:253 tasks = [fetch_single(session, url) for url in urls]254 results = await asyncio.gather(*tasks) // runs all concurrently255 return results256257// Rust: tokio + async/await — zero-cost async with explicit ownership258async fn fetch_results(urls: Vec<String>) -> Result<Vec<Result>, Error> {259 let client = reqwest::Client::new();260 let mut handles = vec![];261 262 for url in urls {263 handles.push(tokio::spawn(async move {264 match client.get(&url).send().await {265 Ok(resp) => Ok(Result { url, data: resp.bytes().await? }),266 Err(e) => Err(e.into()),267 }268 }));269 }270 271 let results = futures::future::join_all(handles).await;272 results.into_iter().collect::<Result<Vec<_>, _>>()273}274```275276---277278## Building Long-Term Fluency279280### The 80/20 Language Study Plan281282For each new language, prioritize learning in this order:2832841. **Week 1 — Syntax & I/O:** Hello world, file read/write, basic types, control flow2852. **Week 2 — Error Handling & Standard Library:** How errors work, what the stdlib provides for common tasks (HTTP, JSON, filesystem)2863. **Week 3 — Concurrency Model:** Goroutines/channels, threads/processes, async/await, or whatever the language offers2874. **Week 4 — Ecosystem & Tooling:** Package manager, test framework, linter, debugger — the tools that make daily development possible288289By Week 4 you should be able to build and deploy a small service in the new language. Fluency (comfort reading others' code quickly) takes 6-12 months of occasional use.290291### The Language Journal Pattern292293Keep a running document for each active language with:294- One idiomatic example per major concept (error handling, concurrency, collections)295- Common gotchas you have encountered and fixed296- Your personal translation notes ("In Go, I do X; in Python, equivalent is Y")297298```python299# Example: A compact Language Journal entry for Rust (stored as markdown/notes)300# 301# === RUST NOTES ===302# Error handling: use ? operator to propagate, Result<T, E> for fallible ops303# Ownership: every value has exactly one owner; move vs copy semantics304# Lifetimes: compiler enforces borrow rules — if you hit 'static errors,305# usually means you need a struct instead of borrowing a local variable306# Common gotcha: Vec<&str> borrowed from function scope — must use String or return owned data307# 308# Go equivalent patterns:309# - Rust Result -> Go error interface (check after every call)310# - Rust ? operator -> Go if err != nil { return err }311# - Rust lifetimes -> Go pointers + garbage collection (no explicit lifetime management)312```313314### The "One Language Per Sprint" Rule315316When learning multiple new languages simultaneously, context collision becomes severe. Limit yourself to one primary language in active study per sprint (2-week cycle). Keep others in "maintenance mode" with occasional review of existing code — this preserves enough familiarity without the overhead of active learning.317318---319320## Context-Switching Management321322### The Resumption Cost Model323324Context switching between languages incurs measurable costs:325- **Syntax recall:** 15-30 minutes to remember idiomatic syntax patterns326- **Mental model shift:** OOP vs functional, garbage collected vs ownership-based327- **Tool familiarity:** Package managers, linters, debuggers differ per language328329**Mitigation strategy:** Create a "launch file" for each project — a single README-style document at the top of every codebase that answers:330- What language? Version? (e.g., Rust 1.78+)331- How to build? (`cargo build`)332- How to test? (`cargo test --all`)333- One idiomatic code sample from the project334- Known gotchas specific to this repo335336This document reduces resumption cost from ~30 minutes to ~3 minutes.337338### The Parallel Project Rule339340When maintaining two language ecosystems simultaneously:3411. **Time-box each language** — e.g., mornings in Go, afternoons in Rust3422. **Never switch mid-task** — finish the current function or bug fix before switching contexts3433. **Write a 3-line status note** before switching: "What I was doing, what blocked me, what to try next"344345---346347## Constraints348349### MUST DO350- Always map error handling patterns first when entering an unfamiliar language — this reveals the paradigm immediately351- Write a Rosetta script (Stage 2 translation) before attempting Stage 3 real-world translations352- Read at least two standard library examples per new language concept before writing production code353- Keep language cheat sheets for every active project to minimize resumption costs354- Review unfamiliar-language PRs by tracing data flow first, flagging idiomatic concerns second355- Batch context switches into blocks of at least 2 hours per language356- Use the Abstraction Pass technique when reviewing code in languages you do not know well357358### MUST NOT DO359- Translate code literally from your home language without checking if the target language has a standard library alternative360- Assume that identical syntax means identical semantics (e.g., Rust `=` is move, not copy)361- Review style nitpicks in unfamiliar languages when you could validate logic correctness instead362- Study multiple new languages simultaneously beyond Stage 1 (syntax basics) — context collision is real and harmful363- Skip error handling study — it is the single best indicator of a language's design philosophy364- Use `unwrap()` or `panic!` equivalents on external data in production code — that is the primary source of runtime crashes across all languages365366---367368## Output Template369370When applying this skill to help a developer, produce:3713721. **Language Profile Summary** — Paradigm, type system, error handling style, concurrency model (one paragraph each)3732. **Translation Map** — 3-5 key concepts mapped from the developer's home language to the target language with code examples3743. **Rosetta Script** — A complete, runnable program that exercises core language features3754. **Review Notes** — For PR review: logic correctness findings + idiomatic suggestions (clearly labeled as such)3765. **Next Steps** — Specific study tasks for the next sprint based on gaps identified377378---379380## Related Skills381382| Skill | Purpose |383|-------|---------|384| `polyglot-development` | Cross-language system architecture (gRPC, Protobuf, monorepo) — for architects and team leads |385| `framework-selection` | Choosing technologies and frameworks — when you need to decide which language to learn next |386| `version-migration` | Migrating codebases between major language versions — when the language itself is the same but the version changed |387| `single-letter-variables` | Readability anti-patterns — relevant because polyglot developers sometimes carry bad naming habits across languages |388389---390391## Live References392393> Authoritative documentation and learning resources for polyglot development. These links provide official, up-to-date guidance on language paradigms, idioms, and best practices.394395- [Polyglot Programming Overview (Martin Fowler)](https://martinfowler.com/articles/multi-language-app.html)396- [A Byte of Python — Idiomatic Python](https://docs.python-guide.org/writing/style/)397- [Effective Go — Go Foundation Style Guide](https://go.dev/doc/effective_go)398- [The Rust Programming Language Book — Ownership and Borrowing](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html)399- [Haskell Programming from First Principles (Chapter 1: Getting Started)](https://haskellbook.com/)400- [Python Data Model — Dunder Methods Reference](https://docs.python.org/3/reference/datamodel.html)401- [Programming Language Pragmatics (Mehran Sahami, Stanford CS143 Lecture Notes)](https://web.stanford.edu/class/cs143/)