Software understanding takes up a large share of the total cost of a software system. The high costs attributed to software understanding activities are caused by the size and complexity of software systems, by the continuous evolution that these systems are subject to, and by the lack of physical presence which makes software intangible. Reverse engineering helps practitioners deal with the intrinsic complexity of software, by providing a broad range of patterns and techniques. One of these techniques is software visualization, which makes software more tangible, by providing visible representations of software systems. Interpreting a visualization is by no means trivial and requires knowledge about the visual language of the visualization. One means to ease the learning of a new visualization's language are metaphors, which allow the interpretation of new data representations by analogy. Possibly one of the most popular metaphors for software visualization is the city metaphor, which has been explored in the past by a number of researchers. However, in spite of the efforts, the value of this metaphor for reverse engineering has never been taken beyond anecdotical evidence. In this dissertation, we demonstrate the value of the city metaphor for reverse engineering along two directions. On the one hand, we show that the metaphor is versatile enough to allow the representation of different facets of software. On the other hand, we show that the city metaphor enables the creation of software visualizations which efficiently and effectively support reverse engineering activities. Our interpretation of the city metaphor at its core depicts the system as a city, the packages as districts, and the classes as buildings. The resulting "code city" visualization provides a structural overview of the software system, enriched with contextual data. To be able to perform analyses of real systems using our approach, we implemented a tool called CodeCity. We demonstrate the versatility of the metaphor, by using it in three different analysis contexts, \ie program comprehension, software evolution analysis, and software design quality assessment. For each of the contexts, we describe the visualization techniques we employ to encode the contextual data in the visualization and we illustrate the application by means of case studies. The insights gained in the three analysis contexts are complementary to each other, leading to an increasingly more complete "big picture" of the systems. We then demonstrate how the visualizations built on top of our city metaphor effectively and efficiently support reverse engineering activities, by means of an extensive controlled experiment. The design of our experiment is based on a list of desiderata that we extracted from our survey of the current body of research. We conducted the experiment over a period of six months, in four sites located in three countries, with a heterogeneous sample of subjects composed of fair shares of both academics and industry practitioners. The main result of our experiment was that, overall, our approach outperforms the state- of-practice in supporting users solve reverse engineering tasks, in terms of both correctness and completion time