GitHub Copilot: AI Pair Programming Arrives

June 28, 2021

GitHub just announced Copilot, an AI-powered code completion tool that goes far beyond traditional autocomplete. Built on OpenAI’s Codex model (trained on billions of lines of public code), it suggests entire functions, writes tests, and seems to understand context in remarkable ways.

I got access to the technical preview. Here’s what I’ve learned.

What Copilot Does

Beyond Autocomplete

Traditional autocomplete suggests variable names and method signatures. Copilot suggests entire implementations:

# Traditional autocomplete:
# Type "def calculate_" → suggests "calculate_total"

# Copilot:
# Type comment "# function to calculate compound interest"
# Copilot suggests:

def calculate_compound_interest(principal, rate, time, n):
    """
    Calculate compound interest.

    Args:
        principal: Initial amount
        rate: Annual interest rate (as decimal)
        time: Time period in years
        n: Number of times interest compounds per year

    Returns:
        Final amount after compound interest
    """
    return principal * (1 + rate/n) ** (n * time)

Context Awareness

Copilot reads your open file and understands patterns:

// Given this context in a file
type User struct {
    ID        string
    Email     string
    Name      string
    CreatedAt time.Time
}

type UserRepository interface {
    Create(user User) error
    GetByID(id string) (User, error)
    // Copilot suggests:
    GetByEmail(email string) (User, error)
    Update(user User) error
    Delete(id string) error
    List(limit, offset int) ([]User, error)
}

// Start typing implementation
func (r *PostgresUserRepository) GetByID(id string) (User, error) {
    // Copilot completes with appropriate SQL and scanning
}

Test Generation

Comment your intent, get tests:

// test for user authentication
describe('UserAuthentication', () => {
  // Copilot suggests entire test suites

  it('should authenticate valid user', async () => {
    const user = { email: 'test@example.com', password: 'password123' };
    const result = await auth.authenticate(user);
    expect(result.success).toBe(true);
    expect(result.token).toBeDefined();
  });

  it('should reject invalid password', async () => {
    const user = { email: 'test@example.com', password: 'wrong' };
    const result = await auth.authenticate(user);
    expect(result.success).toBe(false);
    expect(result.error).toBe('Invalid credentials');
  });

  it('should reject non-existent user', async () => {
    const user = { email: 'nonexistent@example.com', password: 'password' };
    const result = await auth.authenticate(user);
    expect(result.success).toBe(false);
  });
});

Where It Excels

Boilerplate Code

Copilot eliminates tedious boilerplate:

// JSON marshaling, error handling, HTTP handlers
func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
    // Type the function signature, Copilot suggests the rest:
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    user, err := h.service.CreateUser(r.Context(), req)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(user)
}

Common Algorithms

Standard algorithms appear almost instantly:

# binary search implementation
def binary_search(arr, target):
    left, right = 0, len(arr) - 1

    while left <= right:
        mid = (left + right) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    return -1

API Integration

If you’re using a popular API, Copilot knows patterns:

# Send message with Twilio
from twilio.rest import Client

def send_sms(to_number, message):
    client = Client(
        os.environ['TWILIO_ACCOUNT_SID'],
        os.environ['TWILIO_AUTH_TOKEN']
    )

    message = client.messages.create(
        body=message,
        from_=os.environ['TWILIO_PHONE_NUMBER'],
        to=to_number
    )

    return message.sid

Where It Struggles

Domain-Specific Logic

Copilot doesn’t understand your business:

# This won't work well:
# "calculate customer discount based on our loyalty program"

# Copilot might suggest generic logic, but your actual rules
# (10% for gold members, 15% for platinum, 5% for orders > $100)
# require human specification

Complex Algorithms

Novel or complex algorithms need human design:

# Copilot can implement quicksort from scratch
# But won't design your custom distributed consensus algorithm

Security-Sensitive Code

Be cautious:

# Copilot might suggest:
password = request.args.get('password')  # Query param for password - bad
cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")  # SQL injection

# Always review security implications

Practical Usage

Workflow Integration

copilot_workflow:
  good_for:
    - Starting new functions (write comment first)
    - Generating boilerplate
    - Writing tests for existing code
    - Learning API patterns
    - Converting between formats

  not_good_for:
    - Designing architecture
    - Security review
    - Understanding existing code
    - Domain-specific logic

Tips for Better Suggestions

better_suggestions:
  write_good_comments:
    - Clear, specific descriptions
    - Include input/output types
    - Mention edge cases

  name_things_well:
    - Descriptive function names
    - Clear variable names
    - Copilot uses these as context

  provide_context:
    - Keep related code in same file
    - Import statements help
    - Type definitions matter

  iterate:
    - Tab to accept
    - Ctrl+] for next suggestion
    - Edit and let Copilot re-suggest

Concerns and Considerations

Code Licensing

Copilot is trained on public GitHub code:

licensing_questions:
  - What about copyleft licenses (GPL)?
  - Is suggested code derivative work?
  - Who owns Copilot-generated code?
  - GitHub's ToS vs code licenses

# Currently unclear, watch for legal developments

Code Quality

Copilot suggests patterns from training data:

quality_considerations:
  good:
    - Common patterns well-represented
    - Popular libraries covered
    - Multiple suggestion options

  bad:
    - May suggest outdated patterns
    - Security anti-patterns in training data
    - Copy-paste bugs propagated

  mitigation:
    - Always review suggestions
    - Run tests and linters
    - Treat as junior developer's code

Learning Impact

Will developers learn less?

learning_considerations:
  concerns:
    - Juniors may not understand suggested code
    - Less practice writing from scratch
    - Pattern recognition atrophies

  counterpoints:
    - Frees time for higher-level thinking
    - Exposure to many patterns
    - Still need to understand to modify

  recommendation:
    - Turn off occasionally
    - Understand before accepting
    - Use for learning patterns

The Bigger Picture

What This Signals

ai_assisted_development:
  current:
    - Code completion (Copilot)
    - Bug detection (DeepCode)
    - Code review assistance

  coming:
    - Natural language to code
    - Automated refactoring
    - Architecture suggestions
    - Full feature generation

  human_role:
    - Architecture and design
    - Requirements understanding
    - Review and quality
    - Domain expertise

My Take

After a week with Copilot:

assessment:
  productivity_impact:
    - Significant for boilerplate
    - Moderate for general coding
    - None for complex problems

  quality_impact:
    - Depends entirely on review
    - Don't blindly accept
    - Test everything

  recommendation:
    - Try it
    - Use thoughtfully
    - Stay critical

Key Takeaways

This is the beginning of a significant shift. AI won’t write all our code, but it will increasingly write the boring parts. The question is what we do with the time we save.