Computer Science › Algorithms & Software
Tracking every change to a codebase as a sequence of commits, branching to work on something without disturbing the main line of development, and merging that work back in — the tool that makes collaborative software construction possible at all.
Beyond the mechanics of a single branch and merge — real conventions (feature branches, a shared main line kept always working) that keep a team's history readable instead of a tangle of conflicting changes.
A commit is a unit of communication, not just a save point — small, focused commits with a clear message make a project's history something a future reader (often yourself) can actually use.
Having another person read a change before it's merged — catching bugs, design problems, and unclear code a lone author stops being able to see in their own work.
MIT's own organizing objective for teaching software construction — safe from bugs, easy to understand, ready for change — three lenses this entire discipline keeps returning to.
Writing down precisely what a function promises to its caller — what it requires to be true going in (precondition) and what it guarantees coming out (postcondition) — before a single line of its body is written.
Writing a test case for one function in isolation is only the smallest of three levels — integration testing checks that modules work together, and system testing checks the whole assembled program.
Going beyond the basic isolate-and-fix process already covered — reliably reproducing a bug first, then bisecting the problem space in half repeatedly, the same divide-and-conquer idea applied to finding a fault instead of sorting a list.
Designing test cases from a specification alone, with no look at the implementation (black-box), versus designing them to exercise specific paths through the actual code (white-box) — two different, complementary sources of test cases.
A measurable answer to "how much of my code did my tests actually exercise?" — and why 100% coverage is a floor for confidence, not a ceiling proving the code is correct.
Writing a failing test before the code that makes it pass — a discipline that turns "did I test this?" from an afterthought into the very thing that drives what gets written next.
The design-level reason an ADT's interface is kept separate from its implementation — hiding a decision a caller doesn't need lets that decision change later without breaking anyone who depends on it.
Two dials that measure a module's design quality — how tightly it depends on other modules (coupling, want it low) and how tightly its own responsibilities belong together (cohesion, want it high).
Changing a program's internal structure without changing what it does — made safe specifically by the test suite already covered, which proves external behavior hasn't shifted underneath the redesign.
Five widely-adopted design guidelines, first articulated by Robert C. Martin, aimed directly at keeping coupling low and cohesion high in object-oriented designs specifically.
Named, reusable solutions to problems that recur across many different programs — a shared vocabulary for design decisions, not a library to import.
Zooming out from a single module's design to a whole system's shape — client-server and layered (n-tier) architecture as the two most common styles worth recognizing by name and by trade-off.
Building on an existing library or component instead of writing new code from scratch — and the real cost that comes with it: a dependency you didn't write is a piece of your system you don't fully control.
Practices that scale from one developer to a team don't stay the same size — code review, commit conventions, and shared architecture decisions all matter more, not just proportionally more, once more than one person touches the same code.
Closing the discipline by running every practice covered — specifications, modularity, testing strategy, version control discipline, refactoring — back through the same three lenses it opened with: does this make the code safer, easier to understand, or more ready for change?
Part of the Computer Science curriculum.
Tracking every change to a codebase as a sequence of commits, branching to work on something without disturbing the main line of development, and merging that work back in — the tool that makes collaborative software construction possible at all.
Beyond the mechanics of a single branch and merge — real conventions (feature branches, a shared main line kept always working) that keep a team's history readable instead of a tangle of conflicting changes.
A commit is a unit of communication, not just a save point — small, focused commits with a clear message make a project's history something a future reader (often yourself) can actually use.
Having another person read a change before it's merged — catching bugs, design problems, and unclear code a lone author stops being able to see in their own work.
MIT's own organizing objective for teaching software construction — safe from bugs, easy to understand, ready for change — three lenses this entire discipline keeps returning to.
Writing down precisely what a function promises to its caller — what it requires to be true going in (precondition) and what it guarantees coming out (postcondition) — before a single line of its body is written.
Writing a test case for one function in isolation is only the smallest of three levels — integration testing checks that modules work together, and system testing checks the whole assembled program.
Going beyond the basic isolate-and-fix process already covered — reliably reproducing a bug first, then bisecting the problem space in half repeatedly, the same divide-and-conquer idea applied to finding a fault instead of sorting a list.
Designing test cases from a specification alone, with no look at the implementation (black-box), versus designing them to exercise specific paths through the actual code (white-box) — two different, complementary sources of test cases.
A measurable answer to "how much of my code did my tests actually exercise?" — and why 100% coverage is a floor for confidence, not a ceiling proving the code is correct.
Writing a failing test before the code that makes it pass — a discipline that turns "did I test this?" from an afterthought into the very thing that drives what gets written next.
The design-level reason an ADT's interface is kept separate from its implementation — hiding a decision a caller doesn't need lets that decision change later without breaking anyone who depends on it.
Two dials that measure a module's design quality — how tightly it depends on other modules (coupling, want it low) and how tightly its own responsibilities belong together (cohesion, want it high).
Changing a program's internal structure without changing what it does — made safe specifically by the test suite already covered, which proves external behavior hasn't shifted underneath the redesign.
Five widely-adopted design guidelines, first articulated by Robert C. Martin, aimed directly at keeping coupling low and cohesion high in object-oriented designs specifically.
Named, reusable solutions to problems that recur across many different programs — a shared vocabulary for design decisions, not a library to import.
Zooming out from a single module's design to a whole system's shape — client-server and layered (n-tier) architecture as the two most common styles worth recognizing by name and by trade-off.
Building on an existing library or component instead of writing new code from scratch — and the real cost that comes with it: a dependency you didn't write is a piece of your system you don't fully control.
Practices that scale from one developer to a team don't stay the same size — code review, commit conventions, and shared architecture decisions all matter more, not just proportionally more, once more than one person touches the same code.
Closing the discipline by running every practice covered — specifications, modularity, testing strategy, version control discipline, refactoring — back through the same three lenses it opened with: does this make the code safer, easier to understand, or more ready for change?