Software is becoming increasingly pervasive and complex. During software development and maintenance, developers often make ad hoc decisions based on local program contexts and their own experience only, which may increase technical debt and raise unknown consequences as software evolves. This dissertation explores several opportunities to guide software development and maintenance by exploiting and visualizing the commonalities and variations among similar programs. Our hypothesis is that unveiling what has and has not been done in other similar program contexts can help developers make more systematic decisions, explore implementation alternatives, and reduce the risk of unknown consequences.
The inherent repetitiveness in software systems provides a solid foundation for identifying and exploiting similar code. This dissertation first presents two approaches that leverage the syntactic similarity and repetitiveness in local codebases to improve code reviews and
software testing. First, in contrast to inspecting local program edits line by line, Critics enables developers to reason about related edits scattered across multiple files by summarizing similar edits and detecting inconsistencies in similar locations. Second, Grafter boosts test coverage by transplanting test cases between similar programs and helps developers discern the behavioral similarity and differences between these programs via differential testing.
This dissertation further extends the idea of systematic software development from local codebases to the open world, by exploiting the large and growing body of successful open-source projects on the Internet. In particular, we present three approaches that analyze a massive number of open-source projects and provide systematic guidance based on software reuse and adaptation patterns in the open-source community. First, ExampleCheck mines common API usage patterns from 380K GitHub projects and contrasts online code examples with these patterns to alert developers about potential API misuse during opportunistic code reuse. Second, to help developers comprehensively understand the variety of API usage at scale, Examplore aligns and super-imposes hundreds of code examples into a single code skeleton with statistical distributions of distinct API usage features among these examples.
Finally, ExampleStack guides developers to adapt a code example to a target project by detecting similar code fragments in GitHub and by illuminating possible variations of this example with respect to its GitHub counterparts.
The viability and usability of these techniques are evaluated by their application to large-scale projects as well as within-subjects user studies. First, in a user study with twelve Java developers, Critics helps developers identify 47% more edit mistakes with 32% less time
than a line-level program diff tool. Second, Grafter transplants test cases in three open-source projects with 94% success rate and improves the statement and branch coverage by 22% and 16% respectively. Third, ExampleCheck reduces the risk of bug propagation by detecting API usage violations in almost one third of code examples in a popular Q&A forum, Stack Overflow. These API usage violations can potentially lead to software anomalies such as program crashes and resource leaks in target programs. Fourth, in a study with sixteen Java developers, Examplore helps developers understand the distribution of API usage patterns and answer common API usage questions accurately with concrete details. Finally, in another study with sixteen Java developers, ExampleStack helps developers identify more adaptation opportunities about code safety and logic customization, rather than shallow adaptations such as variable renaming. These key findings demonstrate that discovering and representing the commonalities and variations in similar contexts helps a developer achieve better program comprehension, discover more design alternatives, and capture more errors in different software development and maintenance tasks.