Project 1: The "Keyboard Warrior" Refactoring Kata
Project 1: The “Keyboard Warrior” Refactoring Kata
Project Overview
| Attribute | Value |
|---|---|
| Difficulty | Beginner |
| Time Estimate | Weekend |
| Main Language | Text / Regex |
| Knowledge Area | Editor Navigation / Multi-cursor Editing |
| Prerequisites | Basic understanding of any programming language |
Learning Objectives
By completing this project, you will:
- Master multi-cursor editing for simultaneous text manipulation
- Internalize keyboard shortcuts for navigation, selection, and refactoring
- Understand the difference between text-based find/replace and semantic refactoring
- Build muscle memory for flow-state coding without mouse interruption
- Learn VS Code’s command system and the Command Palette
The Core Question
“How can I refactor code at the speed of thought without breaking my flow state?”
Deep Theoretical Foundation
Why Keyboard-First Development Matters
The mouse is a productivity killer. Research on human-computer interaction shows that every time you move your hand from the keyboard to the mouse, you lose 0.5-1 second. Over a day of coding, that adds up to 30+ minutes of wasted time. But the real cost isn’t time—it’s cognitive context switching.
When you reach for the mouse, you break your mental model of the code. Your brain shifts from “thinking about logic” to “thinking about cursor position.” This micro-interruption compounds. Studies on programmer productivity show that it takes 10-15 minutes to regain deep focus after an interruption. The mouse creates dozens of tiny interruptions per hour.
The Command Palette: Universal Interface
VS Code’s architecture is built around commands. Every action—formatting, refactoring, git operations, navigation—is a command with a unique identifier. The Command Palette (Cmd+Shift+P / Ctrl+Shift+P) is a fuzzy-searchable list of ALL registered commands.
User types: "git commit"
↓
Command Palette searches ALL registered commands
↓
Matches: "git.commit", "git.commitAll", "git.commitStaged"
↓
User selects one
↓
VS Code executes: vscode.commands.executeCommand('git.commit')
↓
The Git extension's handler function runs
Key Insight: If you don’t know the shortcut for something, the Command Palette is your escape hatch. Type what you want to do in plain English—VS Code will find it.
Multi-Cursor Editing: Parallel Text Manipulation
VS Code allows multiple cursors to be active simultaneously. Each cursor acts independently—when you type, delete, or paste, it happens at ALL cursor positions at once.
Core Multi-Cursor Commands:
Cmd+D(macOS) /Ctrl+D(Windows/Linux): Add next occurrence of selection to cursorsCmd+Shift+L/Ctrl+Shift+L: Select ALL occurrences of current selectionOption+Click/Alt+Click: Add cursor at clicked positionOption+Cmd+Up/Down/Ctrl+Alt+Up/Down: Add cursor above/below
When to use multi-cursor vs refactoring:
- Multi-cursor: Simple, mechanical edits (adding quotes, changing syntax)
- Refactoring (
F2): Semantic changes (renaming variables, extracting functions)
The difference is scope-awareness. Cmd+D selects text that looks the same. F2 rename understands meaning—it won’t rename a variable user inside a string "user" or in an unrelated scope.
Symbol Navigation: Thinking in Structure
VS Code understands code structure through the Language Server Protocol. Instead of scrolling through a 2000-line file, you can jump directly to symbols.
Navigation Commands:
Cmd+T/Ctrl+T: Go to Symbol in Workspace (searches all files)Cmd+Shift+O/Ctrl+Shift+O: Go to Symbol in File (outline view)F12: Go to DefinitionShift+F12: Find All ReferencesOption+F12/Alt+F12: Peek Definition (inline preview)Cmd+G/Ctrl+G: Go to Line Number
Selection Expansion: Smart Selection
Instead of manually selecting characters or words, use Expand Selection to grow the selection to the next logical boundary.
Ctrl+Shift+Cmd+Right Arrow (macOS) or Shift+Alt+Right Arrow (Windows/Linux)
Expansion sequence:
- Word → 2. Expression → 3. Statement → 4. Block → 5. Function
Example: Cursor inside calculateTotal(a, b, c):
- Press 1x: selects
calculateTotal - Press 2x: selects
calculateTotal(a, b, c) - Press 3x: selects the full statement including
const result = ...
Project Specification
What You’re Building
A complete refactoring workflow documentation using ONLY keyboard shortcuts. You will take a messy codebase, refactor it without touching the mouse, and document every shortcut used.
Deliverables
- Refactored Code: A JavaScript/TypeScript file transformed from messy to clean
- Shortcut Log: Document every keyboard shortcut used during the refactoring
- Personal Cheat Sheet: A markdown file with YOUR most-used shortcuts
- Timing Comparison: Before/after timing of a refactoring task with and without keyboard-only workflow
Success Criteria
- Complete a refactoring session without using the mouse
- Use at least 10 different keyboard shortcuts
- Successfully rename a variable using
F2(scope-aware) - Extract a function using
Cmd+.code actions - Navigate to a symbol in another file using
Cmd+T - Use multi-cursor to edit 5+ locations simultaneously
Solution Architecture
Conceptual Design
Your refactoring workflow should follow this mental model:
┌─────────────────────────────────────────────────────────────┐
│ KEYBOARD-FIRST WORKFLOW │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. NAVIGATION (Finding what to change) │
│ ├── Cmd+P: Open file by name │
│ ├── Cmd+T: Go to symbol in workspace │
│ ├── Cmd+Shift+O: Go to symbol in file │
│ └── F12: Jump to definition │
│ │
│ 2. SELECTION (Choosing what to change) │
│ ├── Cmd+D: Select next occurrence │
│ ├── Cmd+Shift+L: Select all occurrences │
│ └── Expand Selection: Smart boundary selection │
│ │
│ 3. TRANSFORMATION (Making the change) │
│ ├── F2: Rename symbol (scope-aware) │
│ ├── Cmd+.: Quick fix / code actions │
│ ├── Multi-cursor typing: Parallel edits │
│ └── Cmd+Shift+K: Delete entire line │
│ │
│ 4. VERIFICATION (Confirming the change) │
│ ├── Shift+F12: Find all references │
│ ├── Cmd+Shift+M: Open problems panel │
│ └── Ctrl+-: Navigate back to previous location │
│ │
└─────────────────────────────────────────────────────────────┘
Workflow Phases
Phase 1: Navigation
Before changing code, you need to find it. Use file search (Cmd+P), symbol search (Cmd+T), and definition jumping (F12) to locate targets.
Phase 2: Selection
Select the text to change. Use Cmd+D for incremental selection, Cmd+Shift+L for bulk selection, or Expand Selection for structural selection.
Phase 3: Transformation
Apply the change. Use F2 for renames, Cmd+. for code actions, or simply type (all cursors receive the input).
Phase 4: Verification
Confirm the change worked. Use Shift+F12 to see all references, Cmd+Shift+M to check for problems.
Phased Implementation Guide
Phase 1: Environment Setup (30 minutes)
Goal: Prepare your practice environment.
-
Install the “Learn VS Code Shortcuts” extension (optional but helpful—shows shortcuts as you use commands)
-
Create a practice file with intentionally messy code:
// practice.js - Intentionally messy code for refactoring practice
function processUser(u) {
console.log(u.name);
console.log(u.email);
let result = u.age > 18 ? "adult" : "minor";
console.log(result);
return result;
}
function handleData(d) {
console.log("Processing data...");
for (var i = 0; i < d.length; i++) {
console.log("Item: " + d[i]);
var x = d[i] * 2;
console.log("Doubled: " + x);
}
console.log("Done!");
}
function calculate(a, b, c) {
var sum = a + b + c;
var avg = sum / 3;
var max = a > b ? (a > c ? a : c) : (b > c ? b : c);
return {sum: sum, avg: avg, max: max};
}
- Print the VS Code keyboard shortcut cheatsheet for your OS from the official site
Phase 2: Basic Navigation Mastery (1 hour)
Goal: Navigate without scrolling or clicking.
Exercises:
- File Navigation
- Press
Cmd+P, type “practice”, press Enter - Time yourself: Can you open any file in under 2 seconds?
- Press
- Line Navigation
- Press
Cmd+G, type “15”, press Enter - Practice jumping to specific lines
- Press
- Symbol Navigation
- Press
Cmd+Shift+Oto see file outline - Jump between functions using the outline
- Press
- Definition Jumping
- In line 2, place cursor on
u.name - Press
F12(would jump to definition ifuwere defined elsewhere) - Press
Ctrl+-to go back
- In line 2, place cursor on
Checkpoint: You should be able to navigate a 500-line file without touching the scrollbar.
Phase 3: Multi-Cursor Editing (1 hour)
Goal: Edit multiple locations simultaneously.
Exercises:
- Select Next Occurrence
- Select the word
consolein the file - Press
Cmd+Drepeatedly to add each occurrence - Type
loggerto replace all at once
- Select the word
- Select All Occurrences
- Select
var - Press
Cmd+Shift+Lto select ALL - Type
const(will replace all if variables aren’t reassigned—some will be errors!)
- Select
- Add Cursors Manually
- Hold
Optionand click at the end of lines 2, 3, 4 - Type
;at all three positions simultaneously
- Hold
- Column Selection
- Select multiple lines
- Press
Shift+Option+Ito add cursors at the END of each line
Checkpoint: You should be able to rename a variable across 10 occurrences in under 5 seconds.
Phase 4: Semantic Refactoring (1 hour)
Goal: Use language-aware refactoring tools.
Exercises:
- Rename Symbol
- Place cursor on
uinprocessUser - Press
F2 - Type
user - Press Enter
- Observe: Only
uparameters are renamed, not otheruvariables
- Place cursor on
- Extract Function
- Select lines 2-3 (the console.log calls)
- Press
Cmd+. - Choose “Extract to function in module scope”
- Name it
logUserInfo
- Extract Variable
- Select the ternary expression
u.age > 18 ? "adult" : "minor" - Press
Cmd+. - Choose “Extract to constant in enclosing scope”
- Name it
ageCategory
- Select the ternary expression
- Quick Fixes
- Add
// @ts-checkat the top of the file - Notice TypeScript errors appear
- Press
Cmd+.on errors to see available fixes
- Add
Checkpoint: You should be able to extract a function and rename variables without typing the name more than once.
Phase 5: Complete Refactoring Kata (2 hours)
Goal: Refactor the entire practice file using only keyboard.
Starting Code (same as Phase 1):
function processUser(u) {
console.log(u.name);
console.log(u.email);
let result = u.age > 18 ? "adult" : "minor";
console.log(result);
return result;
}
Target Code (what you’re aiming for):
function processUser(user) {
logUserInfo(user);
const ageCategory = categorizeAge(user.age);
console.log(ageCategory);
return ageCategory;
}
function logUserInfo(user) {
console.log(user.name);
console.log(user.email);
}
function categorizeAge(age) {
return age > 18 ? "adult" : "minor";
}
Step-by-Step Keyboard Sequence:
F2onu→ typeuser→ Enter (rename parameter)- Select lines 2-3 →
Cmd+.→ Extract to function → typelogUserInfo - Select ternary expression →
Cmd+.→ Extract to constant → typeageCategory Cmd+.onageCategory→ Extract to function → typecategorizeAgeF2onresult→ typeageCategory
Testing Strategy
Manual Testing Checklist
- Can navigate to any function in under 2 seconds
- Can select all occurrences of a word in under 1 second
- Rename symbol changes all semantic occurrences, not string literals
- Extract function creates properly scoped helper function
- No mouse usage during entire refactoring session
Performance Benchmarks
| Task | With Mouse | Keyboard-Only | Target |
|---|---|---|---|
| Open specific file | 3-5 sec | <1 sec | <1 sec |
| Jump to function | 5-10 sec | <2 sec | <2 sec |
| Rename variable (5 occurrences) | 15-30 sec | <5 sec | <5 sec |
| Extract function | 60+ sec | <10 sec | <10 sec |
Common Pitfalls and Debugging
Pitfall 1: Using Cmd+D Instead of F2 for Renaming
Problem: You select all occurrences of user with Cmd+D and type a new name. But it also changes "user" inside strings and comments.
Solution: Use F2 for semantic renaming. It understands scope and won’t touch strings or comments.
Pitfall 2: Forgetting to Go Back
Problem: You jump to a definition with F12, but can’t find your way back.
Solution: Use Ctrl+- (macOS) or Alt+Left Arrow (Windows) to navigate back through your cursor history.
Pitfall 3: Multi-Cursor Chaos
Problem: You have 20 cursors and make a typo—now there are 20 typos.
Solution: Press Escape to exit multi-cursor mode. Use Cmd+Z to undo (undoes ALL cursor edits).
Pitfall 4: Selection Expansion Goes Too Far
Problem: Expand Selection selected the entire file when you wanted just a statement.
Solution: Use Ctrl+Shift+Cmd+Left Arrow (Shrink Selection) to go back one level.
Extensions and Challenges
Extension 1: Custom Keybindings
Create a keybindings.json entry for a shortcut you use frequently but doesn’t have a binding:
{
"key": "cmd+shift+r",
"command": "editor.action.refactor",
"when": "editorTextFocus"
}
Extension 2: Macro-Style Editing
Install the “Multi-Command” extension and create a macro that:
- Selects the current line
- Cuts it
- Moves to the previous line
- Pastes (effectively moving the line up)
Extension 3: No-Mouse Challenge
Unplug your mouse for an entire coding session. Document every moment you got stuck and find the keyboard solution.
Real-World Connections
Code Review Efficiency
When reviewing a PR with 500+ lines:
Cmd+Shift+Fto search for patternsCmd+Dto select all instances of a problematic variableShift+F12to see all references before suggesting a rename
Pair Programming
When pair programming, keyboard-only navigation is faster to dictate:
- “Go to the processUser function” → partner presses
Cmd+T, typesprocessUser - “Select all uses of
result” → partner pressesCmd+Drepeatedly
Technical Interviews
Interviewers notice keyboard fluency. It demonstrates:
- Deep tool knowledge
- Focus on efficiency
- Professional-level development skills
Interview Questions
-
“How do you refactor code efficiently without introducing bugs?”
Answer: “I use language-aware refactoring tools like VS Code’s
F2rename andCmd+.extract method. These use the Language Server Protocol to understand scope, so they don’t accidentally rename unrelated variables. For mechanical transformations, I use multi-cursor editing.” -
“What’s the difference between Find-Replace and Refactoring?”
Answer: “Find-Replace is text-based and doesn’t understand code structure. Refactoring is syntax-aware. If I rename a function parameter with Find-Replace, it might change string literals or comments that happen to have the same text. Refactoring only changes the actual symbol.”
-
“How do you navigate a large codebase without relying on a mouse?”
Answer: “I use
Cmd+Tto search for symbols across the workspace,Cmd+Pto open files by name, andF12to jump to definitions. For exploring code, I useShift+F12to see all references. For file-level navigation,Cmd+Shift+Oshows an outline.”
Resources
Essential Reading
| Book | Author | Relevant Chapters |
|---|---|---|
| Visual Studio Code: End-to-End Editing and Debugging Tools | Bruce Johnson | Ch 2 (Command Palette), Ch 3 (Editing), Ch 4 (Navigation) |
| Visual Studio Code Distilled | Alessandro Del Sole | Ch 3 (Editing Code), Ch 4 (Multi-cursor Editing) |
| Refactoring: Improving the Design of Existing Code | Martin Fowler | Ch 1 (Refactoring Principles), Ch 6 (Extract Function) |
| The Pragmatic Programmer | David Thomas, Andrew Hunt | Tip 22 (Use a Single Editor Well) |
Official Documentation
Self-Assessment Checklist
Before considering this project complete, verify:
- I can navigate to any file/symbol without using the mouse
- I understand the difference between
Cmd+DandF2 - I can use Expand Selection to select logical code blocks
- I can extract a function using code actions
- I have documented my personal shortcut cheat sheet
- I can complete a full refactoring session keyboard-only
- I know how to customize keybindings for my workflow
Next Project: P02-time-travel-debugger-configuration.md