👥 Developer Cookbook - FASE 8: Liderazgo y Mentoría
Code reviews constructivos, pair programming, mentoría y gestión de conflictos técnicos
Receta 8.5: Code Reviews Constructivos
¿Qué es? Revisar código de otros de forma que ayude al equipo a mejorar, no solo encontrar errores.
Goals de un code review:
- Catch bugs antes de producción
- Mantener code quality
- Compartir conocimiento
- Mejorar habilidades del team
- NOT: Demostrar que eres más inteligente
Framework de code review:
class CodeReviewGuidelines:
"""Guidelines para code reviews efectivos"""
@staticmethod
def what_to_review():
"""Qué revisar en orden de importancia"""
checklist = """
CODE REVIEW CHECKLIST
=====================
Priority 1: CORRECTNESS (Must fix)
- Does it work?
- Are there bugs?
- Edge cases handled?
- Error handling present?
Priority 2: SECURITY (Must fix)
- SQL injection risks?
- XSS vulnerabilities?
- Auth/authorization correct?
- Secrets hardcoded?
- Input validation?
Priority 3: PERFORMANCE (Fix if significant)
- N+1 queries?
- Unnecessary loops?
- Memory leaks?
- Blocking operations?
Priority 4: READABILITY (Suggest improvements)
- Clear variable names?
- Functions < 50 lines?
- Comments for complex logic?
- Consistent style?
Priority 5: DESIGN (Suggest if major issue)
- Follows SOLID principles?
- Appropriate abstraction?
- Code duplication?
- Testable?
Priority 6: NITPICKS (Optional)
- Formatting (let linter handle)
- Naming preferences
- Minor refactors
What NOT to review:
- Personal style preferences
- Things the linter catches
- Entire architecture (that's ADR territory)
- Unrelated code in the same file
"""
print(checklist)
@staticmethod
def how_to_give_feedback():
"""Cómo dar feedback constructivo"""
# 1. BE SPECIFIC, NOT VAGUE
# BAD: "This function is bad"
# GOOD: "This function does 3 things. Consider splitting into:
# validateInput(), processData(), saveToDatabase()"
#
# 2. EXPLAIN WHY, NOT JUST WHAT
# BAD: "Use const instead of let"
# GOOD: "Use const instead of let. This prevents accidental
# reassignment and makes the code more predictable."
#
# 3. ASK QUESTIONS, DON'T DEMAND
# BAD: "Change this to use a Set"
# GOOD: "Have you considered using a Set? It would be O(1)
# lookup instead of O(n) with an array."
#
# 4. OFFER SOLUTIONS, NOT JUST PROBLEMS
# BAD: "This has a memory leak"
# GOOD: "This has a memory leak because we're not clearing
# the interval. Add: clearInterval(intervalId)"
#
# 5. PRAISE GOOD CODE
# "Nice! This error handling is very thorough."
# "Good catch on the edge case with empty strings."
pass
@staticmethod
def severity_labels():
"""Usar labels para severidad"""
# BLOCKING - Must fix before merge
# "🔴 [BLOCKING] SQL injection vulnerability. Use parameterized queries."
#
# SUGGESTION - Nice to have, not required
# "🟡 [SUGGESTION] Consider extracting this to a helper function."
#
# QUESTION - Asking for clarification
# "💡 [QUESTION] Why are we using a timeout here?"
#
# NITPICK - Purely stylistic
# "🎨 [NITPICK] Extra whitespace (but linter should catch this)"
pass
@staticmethod
def how_to_receive_feedback():
"""Cómo recibir feedback (for the author)"""
guidelines = """
HOW TO RECEIVE FEEDBACK
=======================
1. DON'T TAKE IT PERSONALLY
- Code review != personal attack
- Everyone's code can improve
- Reviewers are helping you
2. ASK CLARIFYING QUESTIONS
- "Can you explain what you mean by 'this won't scale'?"
- "I'm not familiar with that pattern. Can you link to docs?"
- "Is this a blocker or a nice-to-have?"
3. EXPLAIN YOUR REASONING (if you disagree)
BAD: "No, this is fine"
GOOD: "I chose this approach because we're only dealing
with <100 items. The O(n^2) complexity isn't an issue
here. Happy to optimize if we see it in profiling though."
4. SAY THANKS
- "Good catch! Fixed."
- "Thanks for the suggestion. Refactored."
- "I didn't know about that pattern. Learned something new!"
5. MARK COMMENTS AS RESOLVED after addressing them
6. DON'T GET DEFENSIVE
BAD: "This is how we always do it"
BAD: "It works, doesn't it?"
GOOD: "Interesting point. Let me think about this."
GOOD: "Good question. Let me clarify the requirements with the PM."
"""
print(guidelines)
CodeReviewGuidelines.what_to_review()
Template de Pull Request:
## What
[One sentence describing what this PR does]
## Why
[Why are we making this change? Link to issue/ticket]
## How
[High-level explanation of approach]
## Testing
- [ ] Unit tests added
- [ ] Integration tests added
- [ ] Manually tested on staging
- [ ] Edge cases covered
## Screenshots (if UI change)
Before: [screenshot]
After: [screenshot]
## Checklist
- [ ] Code follows style guide
- [ ] Self-reviewed
- [ ] Commented complex logic
- [ ] Documentation updated
- [ ] No breaking changes (or documented)
## Deployment notes
[Any special steps needed for deployment?]
[Database migrations? Feature flags?]
## Related PRs
- #123 (dependency)
- #456 (follow-up work)
Code review examples:
# EXAMPLE 1: Security issue - GOOD REVIEW
"""
🔴 [BLOCKING] SQL Injection vulnerability
Current code:
query = f"SELECT * FROM users WHERE id = {user_id}"
db.execute(query)
Problem: If user_id = "1 OR 1=1", this returns all users.
Fix: Use parameterized queries
query = "SELECT * FROM users WHERE id = ?"
db.execute(query, (user_id,))
Reference: https://owasp.org/www-community/attacks/SQL_Injection
"""
# EXAMPLE 2: Performance issue - GOOD REVIEW
"""
🟡 [SUGGESTION] N+1 query problem
Current code makes 1 query + N queries:
posts = Post.all() # 1 query
for post in posts:
author = post.author # N queries (one per post)
With 100 posts, this is 101 queries.
Suggested fix (1 query total):
posts = Post.select_related('author').all()
for post in posts:
author = post.author # No additional query
If this endpoint isn't heavily used, we can defer optimization.
What do you think?
"""
# EXAMPLE 3: Praise
"""
Nice work! A few highlights:
1. Error handling is thorough (lines 45-60)
2. Clear function names (getUserByEmail, validatePassword)
3. Good test coverage (90%+)
4. Edge cases handled (null, empty string, special chars)
One minor suggestion below, but overall this is solid code.
"""
Receta 8.6: Pair Programming & Mob Programming
¿Qué es?
- Pair Programming: 2 personas, 1 computadora. Driver (escribe) + Navigator (revisa)
- Mob Programming: Todo el equipo trabaja en el mismo problema al mismo tiempo
Cuándo usar:
class CollaborativeCoding:
"""Guía para pair/mob programming"""
@staticmethod
def when_to_pair():
"""Cuándo hacer pair programming"""
good_use_cases = [
"Onboarding nuevo team member (pair con senior dev, aprende codebase)",
"Complex problem solving (algoritmos, arquitectura, debugging tricky bugs)",
"High-risk changes (seguridad, pagos, data migrations)",
"Knowledge sharing (senior enseña a junior, domain expert comparte contexto)",
"Unblocking someone (stuck >1 hora, necesita perspectiva nueva)"
]
when_not_to_pair = [
"Trivial tasks (formatting, typos)",
"Well-understood CRUD operations",
"Research/exploration (do solo, then share findings)",
"When both people are in deep work flow",
"When remote with poor connection"
]
# ROI: Pair programming costs 2x engineering time but:
# - 15% fewer bugs (less debugging later)
# - 50% faster code reviews
# - Better knowledge distribution
# - Higher code quality
# Net: Often breaks even or saves time long-term
return good_use_cases, when_not_to_pair
@staticmethod
def roles_and_rotation():
"""Roles en pair programming"""
# DRIVER (has keyboard)
# - Writes the code, focuses on tactical details
# - Verbalizes what they're doing
# - Asks questions when stuck
#
# NAVIGATOR (no keyboard)
# - Reviews code as it's written, thinks strategically
# - Catches mistakes, suggests improvements
# - Researches docs/Stack Overflow
# - Does NOT micromanage every character
#
# ROTATION: Switch roles every 15-30 min (Pomodoro)
# 9:00-9:25 Alice drives, Bob navigates
# 9:25-9:30 5-min break
# 9:30-9:55 Bob drives, Alice navigates
# ...repeat...
pass
@staticmethod
def remote_pairing_tools():
"""Tools para pair programming remoto"""
tools = {
"VS Code Live Share": [
"Both can type simultaneously, each has own cursor",
"Shared terminal and debugging session",
"Voice chat built-in",
"Best option for remote pairing"
],
"Tuple": "Made specifically for pairing, low latency",
"Replit": "Web-based, instant setup, zero config",
"Gitpod": "Cloud dev environments",
}
remote_tips = [
"Use high-quality microphone (not laptop mic)",
"Minimize screen share lag (close other apps)",
"Take breaks every 25-30 minutes",
"Overcommunicate (can't see body language)",
"Use 'I'm going to...' before big changes"
]
return tools, remote_tips
@staticmethod
def mob_programming():
"""Mob programming (whole team codes together)"""
# Roles: 1 Driver (rotates every 5-10 min) + N Navigators + 1 Facilitator
#
# When to mob:
# - Architectural decisions
# - Complex algorithm design
# - Learning new technology as team
# - Critical bug affecting everyone
#
# Rules:
# 1. "For an idea to go from your head to the computer,
# it must go through someone else's hands"
# 2. Driver only types what navigators say
# 3. Be kind, respectful, considerate
# 4. Everyone contributes, no side conversations
#
# Pros: Shared understanding, no knowledge silos,
# fewer meetings, higher quality, learning opportunity
# Cons: Expensive (N engineers on 1 task), can be tiring,
# needs strong facilitation
pass
CollaborativeCoding.when_to_pair()
Receta 8.7: Mentoría y Delegación
¿Qué es? Ayudar a otros a crecer técnicamente mientras liberas tu tiempo para trabajo de mayor impacto.
Framework de mentoría:
from dataclasses import dataclass
from typing import List
from enum import Enum
class SkillLevel(Enum):
"""Niveles de habilidad"""
NOVICE = 1 # No sabe qué no sabe
BEGINNER = 2 # Sabe qué no sabe
INTERMEDIATE = 3 # Puede trabajar con supervisión
ADVANCED = 4 # Puede trabajar independiente
EXPERT = 5 # Puede enseñar a otros
@dataclass
class MentorshipGoal:
"""Goal de mentoría para un mentee"""
skill: str
current_level: SkillLevel
target_level: SkillLevel
timeline_weeks: int
milestones: List[str]
def create_learning_plan(self) -> dict:
"""Crear plan de aprendizaje"""
plan = {
'skill': self.skill,
'current': self.current_level.name,
'target': self.target_level.name,
'duration': f"{self.timeline_weeks} weeks",
'weekly_activities': []
}
# Novice -> Beginner
if self.current_level == SkillLevel.NOVICE:
plan['weekly_activities'] = [
"Week 1-2: Read fundamental concepts (docs, tutorials)",
"Week 3-4: Complete guided exercises",
"Week 5-6: Build small project with code reviews",
"Week 7-8: Pair program with mentor on real tasks"
]
# Beginner -> Intermediate
elif self.current_level == SkillLevel.BEGINNER:
plan['weekly_activities'] = [
"Week 1-3: Take ownership of small features",
"Week 4-6: Fix bugs independently",
"Week 7-9: Code reviews (reviewing others' code)",
"Week 10-12: Lead small project end-to-end"
]
# Intermediate -> Advanced
elif self.current_level == SkillLevel.INTERMEDIATE:
plan['weekly_activities'] = [
"Week 1-4: Design architecture for new features",
"Week 5-8: Mentor junior developers",
"Week 9-12: Lead technical discussions",
"Week 13-16: Own large project with minimal guidance"
]
return plan
# Ejemplo de uso
goal = MentorshipGoal(
skill="Backend API Development",
current_level=SkillLevel.BEGINNER,
target_level=SkillLevel.INTERMEDIATE,
timeline_weeks=12,
milestones=[
"Build CRUD API independently",
"Understand authentication/authorization",
"Write integration tests",
"Deploy to staging",
"Handle production incident"
]
)
plan = goal.create_learning_plan()
print(f"Mentorship Plan: {plan['skill']}")
print(f"Current: {plan['current']} -> Target: {plan['target']}")
for activity in plan['weekly_activities']:
print(f" - {activity}")
Delegation framework:
class DelegationMatrix:
"""Decidir qué delegar y a quién"""
@staticmethod
def delegation_quadrant():
"""
DELEGATION MATRIX
High Complexity
|
III | IV
Challenge & | DON'T
Support | Delegate
------------------+-----------------
I | II High
Delegate | Stretch Stakes
Completely | Assignment
|
Low Complexity
Quadrant I (Low complexity, Low stakes): DELEGATE COMPLETELY
- Examples: Update docs, fix typos, add logging, run tests
- To: Junior developers
Quadrant II (High complexity, Low stakes): STRETCH ASSIGNMENT
- Examples: Build internal tool, refactor module, POC with new tech
- To: Intermediate developers (growth opportunity)
Quadrant III (Low complexity, High stakes): CHALLENGE & SUPPORT
- Examples: Deploy to production (well-documented), hotfix (simple)
- To: Intermediate/Advanced with close oversight
Quadrant IV (High complexity, High stakes): DON'T DELEGATE
- Examples: Redesign auth, DB migration (100M+ records), payment bugs
- To: Yourself or senior engineer
"""
pass
@staticmethod
def delegation_checklist():
"""Checklist al delegar"""
before = [
"Define success criteria: 'Task is done when X, Y, Z are complete'",
"Estimate time required: 'This should take 2-3 days'",
"Identify dependencies: 'You'll need access to X, approval from Y'",
"Set deadline: 'Need this by Friday EOD'",
"Choose right person: Match task complexity to skill level",
"Explain WHY (not just WHAT): 'We need this because...'",
"Provide resources: 'Check docs at X, example in Y'"
]
during = [
"Set check-in schedule: 'Let's sync daily at 2pm'",
"Be available for questions (not: 'Figure it out yourself')",
"Monitor progress (don't micromanage)",
"Unblock proactively: if stuck, jump in"
]
after = [
"Review work: code review, test, validate",
"Give specific feedback: 'This was great because...' / 'Next time, consider...'",
"Recognize effort: public praise in team channel",
"Document learnings: 'What would you do differently?'"
]
return before, during, after
@staticmethod
def mentorship_1on1_template():
"""Template para 1-on-1s de mentoría (30-45 min, weekly/bi-weekly)"""
# AGENDA:
# 1. How are you? (5 min) - genuine check-in, not work talk
# 2. Progress on goals (10 min)
# - "What did you accomplish this week?"
# - "What challenged you?"
# - "What did you learn?"
# 3. Current work (10 min)
# - "Walk me through your solution"
# - "What other approaches did you consider?"
# 4. Learning & growth (10 min)
# - "What do you want to learn next?"
# 5. Career discussion (5 min)
# - "Where do you see yourself in 1 year?"
# 6. Action items (5 min)
#
# NOTES:
# - Let mentee drive conversation
# - Ask open-ended questions
# - Listen more than talk (70/30 rule)
# - Take notes for continuity
# - Follow up on action items
pass
DelegationMatrix.delegation_quadrant()
Receta 8.8: Gestión de Conflictos Técnicos
¿Qué es? Resolver desacuerdos técnicos de forma productiva, no destructiva.
Tipos de conflictos:
class TechnicalConflictResolution:
"""Framework para resolver conflictos técnicos"""
@staticmethod
def types_of_conflicts():
"""Tipos comunes de conflictos técnicos"""
types = {
"Technology Choice": {
"example": "React vs Vue, PostgreSQL vs MongoDB",
"root_cause": "Different preferences/experiences",
"resolution": "Define objective criteria, POC with both options"
},
"Architecture Pattern": {
"example": "Microservices vs Monolith",
"root_cause": "Different trade-off priorities",
"resolution": "List pros/cons, write ADR, align on what we optimize for"
},
"Code Style": {
"example": "Tabs vs spaces, naming conventions",
"root_cause": "Personal preference",
"resolution": "Adopt team style guide, use linter/formatter (automate it)"
},
"Priority Disagreement": {
"example": "Fix tech debt vs ship features",
"root_cause": "Different perspectives (engineering vs product)",
"resolution": "Quantify impact, escalate to stakeholder, compromise"
},
"Implementation Approach": {
"example": "How to implement feature X",
"root_cause": "Different mental models",
"resolution": "Whiteboard both approaches, discuss trade-offs, experiment"
}
}
return types
@staticmethod
def resolution_framework():
"""Framework paso a paso para resolver conflictos"""
steps = [
"STEP 1: UNDERSTAND THE DISAGREEMENT",
" - What exactly do we disagree on?",
" - What are we each proposing?",
" - What problem are we trying to solve?",
"",
"STEP 2: IDENTIFY COMMON GROUND",
" - What do we agree on? (find shared values)",
"",
"STEP 3: ARTICULATE DIFFERENCES",
" - What trade-offs are we making? List pros/cons objectively.",
"",
"STEP 4: DEFINE DECISION CRITERIA",
" - Rank what matters most (e.g., speed, learning curve, cost)",
"",
"STEP 5: EVALUATE OPTIONS OBJECTIVELY",
" - Score each option against criteria with weights",
"",
"STEP 6: MAKE DECISION & COMMIT",
" - 'Disagree and commit': have strong opinions, debate,",
" but once decided, everyone commits 100%",
"",
"STEP 7: DOCUMENT & MOVE FORWARD",
" - Write ADR: what we decided, why, alternatives, trade-offs",
" - Set review point: 'Let's revisit in 6 months with data'"
]
return steps
@staticmethod
def anti_patterns():
"""Anti-patterns en resolución de conflictos"""
# 1. "I'M THE SENIOR, SO WE DO IT MY WAY"
# -> Kills discussion, juniors stop contributing
# Better: "In my experience Y happened. What are your thoughts?"
#
# 2. ANALYSIS PARALYSIS (debating forever)
# -> Time-box decision: "We'll decide by Friday"
# Or: Build POC with both, evaluate concrete code
#
# 3. APPEAL TO AUTHORITY
# "Google uses X, so we should too"
# -> "Google uses X because [specific reason]. Same constraint?"
#
# 4. BIKE-SHEDDING
# Spending 2 hours on variable names, ignoring architecture
# -> "Let's defer style to the linter. Hard question is: monolith vs microservices?"
#
# 5. MAKING IT PERSONAL
# "You always push for complex solutions"
# -> Focus on code/approach, not person
# "I'm worried this approach might be complex. Can we discuss trade-offs?"
#
# 6. SECRET DECISION (private, no buy-in)
# -> Public discussion (Slack, RFC), everyone gets to weigh in
#
# 7. NO DECISION ("Let's each do it our own way")
# -> Make a decision, even imperfect. Document it. Move forward.
pass
@staticmethod
def weighted_decision_example():
"""Ejemplo de evaluación objetiva con pesos"""
# Ejemplo: React vs Vue
criteria = [
("Time to ship", 5),
("Learning curve", 4),
("Hiring", 3),
("Ecosystem", 3),
("Maintainability", 4),
]
scores = {
"React": [3, 2, 5, 5, 4], # scores per criteria
"Vue": [4, 5, 3, 3, 4],
}
results = {}
for option, option_scores in scores.items():
total = sum(weight * score for (_, weight), score
in zip(criteria, option_scores))
results[option] = total
# React: 5*3 + 4*2 + 3*5 + 3*5 + 4*4 = 69
# Vue: 5*4 + 4*5 + 3*3 + 3*3 + 4*4 = 74
# -> Vue wins on OUR criteria
return results
TechnicalConflictResolution.resolution_framework()