The aim of the course is to provide students with the foundations and tools for the design and implementation of distributed systems, both client-server and peer-to-peer. To this end, in the course we will discuss the main issues of distributed systems, such as the detection of failures, deadlocks, the achievement of consensus. For each of these, we will study the appropriate solutions and algorithmic techniques. We will also analyze the main network communication primitives (such as sockets, RPC, message exchange), and languages specifically developed for the implementation of distributed systems (such as Erlang, Scala and Jolie).