6.005 | Spring 2016 | Undergraduate

Software Construction

Readings

Example code for some readings can be found on the 6.005 Github page.

Reading Topics
1: Static Checking

  • Types
  • Static Checking vs Dynamic Checking
  • Arrays and Collections
  • Iterating
  • Methods
  • Mutating Variables vs Reassigning Variables
  • Documenting Assumptions
2: Basic Java

  • Snapshot Diagrams
  • Java Collections
  • Java API Documentation
3: Testing

  • Validation
  • Test-first Programming
  • Choosing Test Cases by Partitioning
  • Blackbox and Whitebox Testing
  • Documenting Testing Strategies
  • Coverage
  • Unit Testing and Stubs
  • Automated Testing and Regression Testing
4: Code Review

  • Don’t Repeat Yourself
  • Comments Where Needed
  • Fail Fast
  • Avoid Magic Numbers
  • One Purpose for Each Variable
  • Use Good Names
  • Use Whitespace to Help the Reader
  • Don’t Use Global Variables
  • Methods Should Return Results, Not Print Them
5: Version Control

  • Inventing Version Control
  • Git: Copy, Commit, Pull, Push, Merge
6: Specifications

  • Why Specifications?
  • Behavioral Equivalence
  • Specification Structure
  • Null References
  • What a Specification May Talk About
  • Testing and Specifications
  • Specifications for Mutating Methods
  • Exceptions for Signaling Bugs
  • Exceptions for Special Results
  • Checked and Unchecked Exceptions
  • Throwable Hierarchy
  • Exception Design Considerations
  • Abuse of Exceptions
7: Designing Specifications

  • Deterministic vs Undertermined Specs
  • Declarative vs Operational Specs
  • Stronger vs Weaker Specs
  • Diagramming Specifications
  • Designing Good Specifications
  • Precondition or Postcondition?
  • About Access Control
  • About Static vs Instance Methods
8: Avoiding Debugging

  • First Defense: Making Bugs Impossible
  • Second Defense: Localizing Bugs
  • Assertions
  • What to Assert
  • What Not to Assert
  • Incremental Development
  • Modularity and Encapsulation
9: Mutability and Immutability

  • Mutability
  • Risks of Mutation
  • Aliasing is What Makes Mutation Risky
  • Specifications for Mutating Methods
  • Iterating Over Arrays and Lists
  • Mutation Undermines an Iterator
  • Mutation and Contracts
  • Useful Implementation Types
10: Recursion

  • Choosing the Right Decomposition For a Problem
  • Structure of Recursive Implementations
  • Helper Methods
  • Choosing the Right Recursive Subproblem
  • Recursive Problem vs Recursive Data
  • Reentrant Code
  • When to Use Recursion Rather Than Iteration
  • Common Mistakes in Recursive Implementations
11: Debugging

  • Reproduce the Bug
  • Understand the Location and Cause of the Bug
  • Fix the Bug
12: Abstract Data Types

  • What Abstraction Means
  • Classifying Types and Operations
  • Designing Abstract Type
  • Representation Independence
  • Realizing ADT Concepts in Java
  • Testing and Abstract Data Type
13: Abstraction Functions and Rep Invariants

  • Invariants
  • Rep Invariant and Abstraction Function
  • Documenting the AF, RI, and Safety from Rep Exposure
  • ADT Invariants Replace Preconditions
14: Interfaces

  • Interfaces
  • Subtypes
  • Example: MyString
  • Example: Set
  • Generic Interfaces
  • Why Interfaces?
  • Realizing ADT Concepts in Java, Part II
15: Equality

  • Three Ways to Regard Equality
  • == vs. equals()
  • Equality of Immutable Types
  • The Object Contract
  • Equality of Mutable Types
  • The Final Rule for Equals() and hashCode()
16: Recursive Data Types

  • Recursive Functions
  • Immutable Lists
  • Recursive Datatype Definitions
  • Functions Over Recursive Datatypes
  • Tuning the Rep
  • Null vs Empty
  • Declared Type vs Actual Type
  • Example: Boolean Formulas
  • Writing a Program with ADTs
  • Recipes for Programming with ADTs
  • Example: Matrix Multiplication
17: Regular Expressions and Grammars

  • Grammars
  • Regular Expressions
18: Parser Generators

  • Parser Generators
  • An Antlr Grammar
  • Generating the Parser
  • Calling the Parser
  • Traversing the Parse Tree
  • Constructing an Abstract Syntax Tree
  • Handling Errors
19: Concurrency

  • Two Models for Concurrent Programming
  • Processes, Threads, Time-Slicing
  • Example: Shared Memory
  • Interleaving
  • Race Condition
  • Tweaking the Code Won’t Help
  • Reordering
  • Example: Message Passing
  • Concurrency is Hard to Test and Debug
20: Thread Saftey

  • What Threadsafe Means
  • Strategy 1: Confinement
  • Strategy 2: Immutability
  • Strategy 3: Using Threadsafe Data Types
  • How to Make A Safety Argument
21: Sockets and Networking

  • Client/Server Design Pattern
  • Network Sockets
  • I/O
  • Blocking
  • Using Network Sockets
  • Wire Protocols
  • Testing Client/Server Code
22: Queues and Message-Passing

  • Two Models for Concurrency
  • Message Passing with Threads
  • Implementing Message Passing with Queues
  • Stopping
  • Thread Safety Arguments with Message Passing
23: Locks and Synchronization

  • Synchronization
  • Deadlock
  • Developing a ThreadSafe Abstract Data Type
  • Locking
  • Monitor Pattern
  • Thread Safety Argument with Synchronization
  • Atomic Operations
  • Designing a Data Type for Concurrency
  • Deadlock Rears its Ugly Head
  • Goals of Concurrent Program Design
  • Concurrency in Practice
24: Graphical User Interfaces

  • View Tree
  • How the View Tree is Used
  • Input Handling
  • Separating Frontend from Backend
  • Background Processing in Graphical User Interfaces
25: Map, Filter, Reduce

  • Abstracting Out Control Flow
  • Map
  • Functions as Values
  • Filter
  • Reduce
  • Benefits of Abstracting Out Control
  • First-class Functions in Java
  • Map/Filter/Reduce in Java
  • Higher-order Functions in Java
26: Little Languages

  • Representing Code as Data
  • Building Languages to Solve Problems
  • Music Language
27: Team Version Control

  • Git Workflow
  • Viewing Commit History
  • Graph of Commits
  • Using Version Control as a Team

Course Info

As Taught In
Spring 2016
Learning Resource Types
Problem Sets
Exams with Solutions
Online Textbook
Programming Assignments