This class introduces students to techniques used to program parallel and distributed systems. We consider algorithms for both the message-passing and shared message paradigms. We categorize the types of problems that lend themselves to practical parallel solutions and reinforce the concepts with real-world examples. These examples demonstrate the use of each technique that we introduce. The speedup, efficiency, and overhead of each algorithm are considered. Topics include load balancing, partitioning, synchronization, and pipelining.