This document compares different approaches to concurrency and distributed computing, including threads with locks, executors, software transactional memory (STM), futures, actors, dataflow, asynchronous programming, reactive programming, and functional reactive programming (FRP). For each approach, it outlines the good qualities, potential bad qualities, and ugly issues to watch out for. In the conclusion, it recommends picking approaches tailored to each problem domain and system requirements.