Development Environment and Tools

Click here to view the raw lecture video on Panopto (MIT Kerberos login required).
An edited version of this video will be posted after the course is over. Edited lecture videos will be posted to YouTube shortly after the conclusion of the course.

A development environment is a set of tools for developing software. At the heart of a development environment is text editing functionality, along with accompanying features such as syntax highlighting, type checking, code formatting, and autocomplete. Integrated development environments (IDEs) such as VS Code bring together all of this functionality into a single application. Terminal-based development workflows combine tools such as tmux (a terminal multiplexer), Vim (a text editor), Zsh (a shell), and language-specific command-line tools, such as Ruff (a Python linter and code formatter) and Mypy (a Python type checker).

IDEs and terminal-based workflows each have their strengths and weaknesses. For example, graphical IDEs can be easier to learn, and today’s IDEs generally have better out-of-the-box AI integrations like AI autocomplete; on the other hand, terminal-based workflows are lightweight, and they may be your only option in environments where you don’t have a GUI or can’t install software. We recommend you develop basic familiarity with both and develop mastery of at least one. If you don’t already have a preferred IDE, we recommend starting with VS Code.

In this lecture, we’ll cover:

Text editing and Vim

When programming, you spend most of your time navigating through code, reading snippets of code, and making edits to code, rather than writing long streams or reading files top-to-bottom. Vim is a text editor that is optimized for this distribution of tasks.

The philosophy of Vim. Vim has a beautiful idea as its foundation: its interface is itself a programming language, designed for navigating and editing text. Keystrokes (with mnemonic names) are commands, and these commands are composable. Vim avoids the use of the mouse, because it’s too slow; Vim even avoids use of the arrow keys because it requires too much movement. The result: an editor that feels like a brain-computer interface and matches the speed at which you think.

Vim support in other software. You don’t have to use Vim itself to benefit from the ideas at its core. Many programs that involve any kind of text editing support “Vim mode”, either as built-in functionality or as a plugin. For example, VS Code has the VSCodeVim plugin, Zsh has built-in support for Vim emulation, and even Claude Code has built-in support for Vim editor mode. Chances are that any tool you use that involves text editing supports Vim mode in one way or another.

Vim is a modal editor: it has different operating modes for different classes of tasks.

Keystrokes have different meanings in different operating modes. For example, the letter x in Insert mode will just insert a literal character “x”, but in Normal mode, it will delete the character under the cursor, and in Visual mode, it will delete the selection.

In its default configuration, Vim shows the current mode in the bottom left. The initial/default mode is Normal mode. You’ll generally spend most of your time between Normal mode and Insert mode.

You change modes by pressing <ESC> (the escape key) to switch from any mode back to Normal mode. From Normal mode, enter Insert mode with i, Replace mode with R, Visual mode with v, Visual Line mode with V, Visual Block mode with <C-v> (Ctrl-V, sometimes also written ^V), and Command-line mode with :.

You use the <ESC> key a lot when using Vim: consider remapping Caps Lock to Escape (macOS instructions) or create an alternative mapping for <ESC> with a simple key sequence.

Basics: inserting text

From Normal mode, press i to enter Insert mode. Now, Vim behaves like any other text editor, until you press <ESC> to return to Normal mode. This, along with the basics explained above, are all you need to start editing files using Vim (though not particularly efficiently, if you’re spending all your time editing from Insert mode).

Vim’s interface is a programming language

Vim’s interface is a programming language. Keystrokes (with mnemonic names) are commands, and these commands compose. This enables efficient movement and edits, especially once the commands become muscle memory, just like typing becomes super efficient once you’ve learned your keyboard layout.

Movement

You should spend most of your time in Normal mode, using movement commands to navigate the file. Movements in Vim are also called “nouns”, because they refer to chunks of text.

Selection

Visual modes:

Can use movement keys to make selection.

Edits

Everything that you used to do with the mouse, you now do with the keyboard using editing commands that compose with movement commands. Here’s where Vim’s interface starts to look like a programming language. Vim’s editing commands are also called “verbs”, because verbs act on nouns.

Counts

You can combine nouns and verbs with a count, which will perform a given action a number of times.

Modifiers

You can use modifiers to change the meaning of a noun. Some modifiers are i, which means “inner” or “inside”, and a, which means “around”.

Putting it all together

Here is a broken fizz buzz implementation:

def fizz_buzz(limit):
    for i in range(limit):
        if i % 3 == 0:
            print("fizz", end="")
        if i % 5 == 0:
            print("fizz", end="")
        if i % 3 and i % 5:
            print(i, end="")
        print()

def main():
    fizz_buzz(20)

We use the following sequence of commands to fix the issues, beginning in Normal mode:

Learning Vim

The best way to learn Vim is to learn the fundamentals (what we’ve covered so far) and then just enable Vim mode in all your software and start using it in practice. Avoid the temptation to use the mouse or the arrow keys; in some editors, you can unbind the arrow keys to force yourself to build good habits.

Additional resources

Code intelligence and language servers

IDEs generally offer language-specific support that requires semantic understanding of the code through IDE extensions that connect to language servers that implement Language Server Protocol. For example, the Python extension for VS Code relies on Pylance, and the Go extension for VS Code relies on the first-party gopls. By installing the extension and language server for the languages you work with, you can enable many language-specific features in your IDE, such as:

Configuring language servers

For some languages, all you need to do is install the extension and language server, and you’ll be all set. For others, to get the maximum benefit from the language server, you need to tell the IDE about your environment. For example, pointing VS Code to your Python environment will enable the language server to see your installed packages. Environments are covered in more depth in our lecture on packaging and shipping code.

Depending on the language, there might be some settings you can configure for your language server. For example, using the Python support in VS Code, you can disable static type checking for projects that don’t make use of Python’s optional type annotations.

AI-powered development

Since the introduction of GitHub Copilot using OpenAI’s Codex model in mid 2021, LLMs have become widely adopted in software engineering. There are three main form factors in use right now: autocomplete, inline chat, and coding agents.

Autocomplete

AI-powered autocomplete has the same form factor as traditional autocomplete in your IDE, suggesting completions at your cursor position as you type. Sometimes, it’s used as a passive feature that “just works”. Beyond that, AI autocomplete is generally prompted using code comments.

For example, let’s write a script to download the contents of these lecture notes and extract all the links. We can start with:

import requests

def download_contents(url: str) -> str:

The model will autocomplete the body of the function:

    response = requests.get(url)
    return response.text

We can further guide completions using comments. For example, if we start writing a function to extract all Markdown links, but doesn’t have a particularly descriptive name:

def extract(contents: str) -> list[str]:

The model will autocomplete something like this:

    lines = contents.splitlines()
    return [line for line in lines if line.strip()]

We can guide the completion through code comments:

def extract(content: str) -> list[str]:
    # extract all Markdown links from the content

This time, the model gives a better completion:

    import re
    pattern = r'\[.*?\]\((.*?)\)'
    return re.findall(pattern, content)

Here, we see one downside of this AI coding tool: it can only provide completions at the cursor. In this case, it would be better practice to put the import re at the module level, rather than inside the function.

The example above used a poorly-named function to demonstrate how code completion can be steered using comments; in practice, you’d want to write code with functions named more descriptively, like extract_links, and you’d want to write docstrings (and based on this, the model should generate a completion analogous to the one above).

For demonstration purposes, we can complete the script:

print(extract(download_contents("https://raw.githubusercontent.com/missing-semester/missing-semester/refs/heads/master/_2026/development-environment.md")))

Inline chat

Inline chat lets you select a line or block and then directly prompt the AI model to propose an edit. In this interaction mode, the model can make changes to existing code (which differs from autocomplete, which only completes code beyond the cursor).

Continuing the example from above, supposed we decided not to use the third-party requests library. We could select the relevant three lines of code, invoke inline chat, and say something like:

use built-in libraries instead

The model proposes:

from urllib.request import urlopen

def download_contents(url: str) -> str:
    with urlopen(url) as response:
        return response.read().decode('utf-8')

Coding agents

Coding agents are covered in depth in the Agentic Coding lecture.

Some popular AI IDEs are VS Code with the GitHub Copilot extension and Cursor. GitHub Copilot is currently available for free for students, teachers, and maintainers of popular open source projects. This is a rapidly evolving space. Many of the leading products have roughly equivalent functionality.

Extensions and other IDE functionality

IDEs are powerful tools, made even more powerful by extensions. We can’t cover all of these features in a single lecture, but here we provide some pointers to a couple popular extensions. We encourage you to explore this space on your own; there are many lists of popular IDE extensions available online, such as Vim Awesome for Vim plugins and VS Code extensions sorted by popularity.

Exercises

  1. Enable Vim mode in all the software you use that supports it, such as your editor and your shell, and use Vim mode for all your text editing for the next month. Whenever something seems inefficient, or when you think “there must be a better way”, try Googling it, there probably is a better way.
  2. Complete a challenge from VimGolf.
  3. Configure an IDE extension and language server for a project that you’re working on. Ensure that all the expected functionality, such as jump-to-definition for library dependencies, works as expected. If you don’t have code that you can use for this exercise, you can use some open-source project from GitHub (such as this one).
  4. Browse a list of IDE extensions and install one that seems useful to you.

Edit this page.

Licensed under CC BY-NC-SA.