Basics Story

Chapter #9 – Tooling

editors, build systems, version control, package managers, debuggers, testing

9.0  Prologue

Software developers spend most of their time not writing new code but reading, navigating, building, testing, and debugging existing code. Knowing which tools solve which problems — and what each tool actually does — is as important as knowing a programming language. This chapter surveys the essential developer toolbox.

9.1  Editors and IDEs

Editors are lightweight, extensible, and language-agnostic:
  • VS Code: free, cross-platform, large extension marketplace, excellent LSP support. The most popular editor in most language communities.
  • Neovim / Vim: terminal-based, highly programmable, preferred by those who work extensively over SSH or value keystroke efficiency.
  • Emacs: extensible via Lisp; can be configured into a full IDE; long-standing favourite in academia and Lisp communities.
IDEs (Integrated Development Environments) bundle deep, language-specific tooling into one application:
  • Visual Studio (Windows): premier C#, C++, and .NET IDE; exceptional debugger and profiler.
  • JetBrains (IntelliJ, CLion, Rider, PyCharm, etc.): best-in-class refactoring, code navigation, and language analysis across many languages.
  • Xcode (macOS): required for iOS/macOS development; includes Interface Builder and Instruments profiler.
The Language Server Protocol (LSP) is the key technology that lets any editor gain IDE-quality features. A language-specific server (e.g., rust-analyzer, clangd, pylsp) runs alongside the editor and answers requests for completions, go-to-definition, hover docs, and diagnostics.

9.2  Compilers and Build Systems

A compiler translates source code to an executable or library. A build system orchestrates the compiler (and linker, code generator, resource compiler, etc.) across a project with many source files and external libraries. Build tools by language/ecosystem:
Language Compiler Build tool
C / C++ GCC, Clang, MSVC CMake + Ninja/Make, Meson
Rust rustc (via LLVM) Cargo (also package manager)
Java / Kotlin javac, kotlinc Maven, Gradle
C# Roslyn (csc) dotnet CLI, MSBuild
Go gc (built-in) go build (built-in)
Python CPython (bytecode) setuptools, Hatch, uv
JavaScript / TypeScript tsc (TypeScript), V8 (JS) Vite, Webpack, esbuild
A minimal CMake workflow for a C++ project: cmake -B build -DCMAKE_BUILD_TYPE=Release # configure cmake --build build # compile + link ./build/my_program # run

9.3  Version Control with Git

Git is the universal standard for version control. It records the full history of every change to every file in a project, lets multiple people work in parallel on branches, and supports merging those branches back together. Core concepts:
  • Repository: a directory tracked by git (contains a .git/ folder).
  • Commit: a snapshot of all tracked files at a point in time.
  • Branch: an independent line of development; lightweight in git (just a pointer to a commit).
  • Merge / rebase: strategies for combining branches.
  • Remote: a shared copy of the repository (GitHub, GitLab, Bitbucket).
  • Pull request / merge request: a proposal to merge a branch, with code review built in.
Essential commands: git init # create a new repository git clone <url> # copy a remote repository git status # show unstaged / staged changes git add <file> # stage a file for the next commit git commit -m "description" # record a snapshot git log --oneline # compact history git branch feature-x # create a branch git switch feature-x # move to that branch git merge feature-x # merge branch into current git push origin main # upload commits to remote git pull # fetch + merge remote changes

9.4  Package Managers

Package managers download, install, and version-manage external libraries so you do not have to copy source into your project manually.
Ecosystem Package manager Lock file
Python pip, uv, Poetry requirements.txt / pyproject.toml
JavaScript / Node npm, yarn, pnpm package-lock.json / yarn.lock
Rust Cargo Cargo.lock
Java Maven, Gradle pom.xml / build.gradle
C# / .NET NuGet packages.lock.json
C / C++ vcpkg, Conan vcpkg.json / conanfile.txt
Best practice: commit the lock file to version control. This records exact dependency versions so every developer and every CI server builds from identical inputs. Without a lock file, npm install today and tomorrow may produce different dependency trees.

9.5  Debuggers and Profilers

A debugger pauses execution at a breakpoint, lets you inspect variables, call stacks, and memory, and step through code line by line.
  • gdb / lldb: command-line debuggers for C, C++, and Rust.
  • VS Code / Visual Studio / IntelliJ: graphical breakpoint/watch/call-stack UI.
  • Chrome DevTools: JavaScript debugging in the browser, including network and performance panels.
A profiler measures where time (or memory) is spent at runtime, identifying hotspots to optimise.
  • perf (Linux), Instruments (macOS), Visual Studio Profiler (Windows): system-wide sampling profilers.
  • py-spy: sampling profiler for Python, attaches to a running process.
  • cargo flamegraph: generates flame graphs for Rust programs.
  • Async profilers (JVM): low-overhead profiling of Java and Kotlin applications.
Rule of thumb: profile before optimising. Guessing where the bottleneck is is usually wrong; profilers reveal the actual hot paths.

9.6  Testing

Types of tests:
  • Unit tests: test a single function or class in isolation, with dependencies replaced by fakes or mocks. Fast; many per project.
  • Integration tests: test how two or more components interact. May hit a real database, file system, or network.
  • End-to-end (E2E) tests: drive the full application through its UI or API as a real user would. Slow but high confidence.
  • Property-based / fuzz tests: generate random inputs and check invariants. Effective at finding edge cases humans miss.
Testing frameworks by language:
Language Framework
Pythonpytest, unittest
JavaJUnit 5, TestNG
JavaScriptJest, Vitest
Rustbuilt-in #[test]
C#xUnit, NUnit, MSTest
C++Google Test, Catch2
Gobuilt-in testing package

9.7  Epilogue

Proficiency with developer tooling multiplies the impact of language knowledge. A well-configured editor, a fast build system, clean git history, and a solid test suite make a team dramatically more productive. The next chapter examines the data structures and algorithms that sit at the heart of most programs.

9.8  References

Pro Git (free online book)
CMake Tutorial
Language Server Protocol specification
pytest documentation