Software design is the process which translates requirements into a detailed design representation of a software system. It is argued that good software design is the key to reliable and understandable software. Important techniques for software design, including architectural and detailed design stages, are surveyed. Recent advances in distributed software system design methodologies are also reviewed. To ensure software quality, various design verification and validation techniques are discussed. In addition, current software metrics and error-resistant software design methodologies are considered. Future research in software design is considered.