From 1192345b396c5b26713c1420d6825997cb67cc21 Mon Sep 17 00:00:00 2001 From: Anton Date: Thu, 30 Jul 2020 21:11:16 +0300 Subject: [PATCH] white paper update (#581) --- wp/how_it_works_diagram_5.jpg | Bin 0 -> 71972 bytes wp/references.bib | 421 ++++++++++++++++++++++++-- wp/sections/appendix.tex | 425 +++++++++++++++++++++++++++ wp/sections/available_data.tex | 36 --- wp/sections/conclusion.tex | 28 ++ wp/sections/considered.tex | 126 -------- wp/sections/empirical_results.tex | 13 - wp/sections/how_aibolit_works.tex | 235 +++++++++++++++ wp/sections/implementation.tex | 0 wp/sections/introduction.tex | 91 ++++-- wp/sections/motivation.tex | 1 + wp/sections/notes.tex | 39 --- wp/sections/pattern_emp_analysis.tex | 124 ++++++++ wp/sections/related_work.tex | 158 +++++----- wp/sections/risks.tex | 26 -- wp/sections/saved.tex | 63 ---- wp/sections/selected_task.tex | 84 ------ wp/sections/selection_criteria.tex | 83 ------ wp/sections/threats_to_validity.tex | 4 + wp/sections/usage_scenarios.tex | 68 +++++ wp/wp.tex | 146 +++++---- 21 files changed, 1508 insertions(+), 663 deletions(-) create mode 100644 wp/how_it_works_diagram_5.jpg create mode 100644 wp/sections/appendix.tex delete mode 100644 wp/sections/available_data.tex create mode 100644 wp/sections/conclusion.tex delete mode 100644 wp/sections/considered.tex delete mode 100644 wp/sections/empirical_results.tex create mode 100644 wp/sections/how_aibolit_works.tex delete mode 100644 wp/sections/implementation.tex create mode 100644 wp/sections/motivation.tex delete mode 100644 wp/sections/notes.tex create mode 100644 wp/sections/pattern_emp_analysis.tex delete mode 100644 wp/sections/risks.tex delete mode 100644 wp/sections/saved.tex delete mode 100644 wp/sections/selected_task.tex delete mode 100644 wp/sections/selection_criteria.tex create mode 100644 wp/sections/threats_to_validity.tex create mode 100644 wp/sections/usage_scenarios.tex diff --git a/wp/how_it_works_diagram_5.jpg b/wp/how_it_works_diagram_5.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6d82d145d831ee1e7b3179e7cbc34f787d93d4d7 GIT binary patch literal 71972 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℞6D*+iCuO)h+#4NIZ3xD#eQ3#;Qtqf?DWc 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 z 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 { + private final AnimatableFloatValue animatableXDimension; + private final AnimatableFloatValue animatableYDimension; + + public AnimatableSplitDimensionPathValue( + AnimatableFloatValue animatableXDimension, + AnimatableFloatValue animatableYDimension) { + this.animatableXDimension = animatableXDimension; + this.animatableYDimension = animatableYDimension; + } +} +\end{lstlisting} +\begin{lstlisting}[language=Java] +public class a implements A, B { +} +\end{lstlisting} + + \item \pattern{Using \texttt{instanceof} operator}{P8}{ Using of \texttt{instanceof} operator considered as pattern.} +{\it Examples:} + \begin{lstlisting}[language=Java] +public static void main(String[] args) { + Child obj = new Child(); + if (obj instanceof String) + System.out.println("obj is instance of Child"); +} +\end{lstlisting} +\begin{lstlisting}[language=Java] +class Test +{ + public static void main(String[] args) + { + Child cobj = new Child(); + System.out.println(b.getClass().isInstance(c)); + } +} +\end{lstlisting} + + \item \pattern{Many primary ctors}{P9}{If there is more than one primary constructors in a class, it is considered a pattern.} + {\it Example:} +\begin{lstlisting}[language=Java] +class Book { + + private final int a; + Book(int x) { // first primary ctor + this.a = x; + } + Book() { // second + this.a = 0; + } +} +\end{lstlisting} + + \item \pattern{Usage of method chaining more than one time}{P10}{If we use more than one method chaining invocation.} +{\it Example:} +\begin{lstlisting}[language=Java] +// here we use method chaining 4 times +public void start() { + MyObject.Start() + .SpecifySomeParameter() + .SpecifySomeOtherParameter() + .Execute(); +} +\end{lstlisting} + + \item \pattern{Multiple Try}{P11}{Once we see more than one try in a single method, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void bar() { + try { + // some code + } catch (IOException ex) { + // do something + } + // some other code + try { // here! + // some code + } catch (IOException ex) { + // do something + } + } +} +\end{lstlisting} + + \item \pattern{Non final attributes}{P12}{Once we see a mutable attribute (without final modifier), it's considered a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private int id; + // something else +} +\end{lstlisting} + + \item \pattern{Null checks}{P13}{If we check that something equals (or not equals) null (except in constructor) it is considered a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + private String z; + void x() { + if (this.z == null) { // here! + throw new RuntimeException("oops"); + } + } +} +\end{lstlisting} + + \item \pattern{Partial synchronized}{P14}{Here, the synchronized block doesn't include all statements of the method. Something stays out of the block.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private int a; + void foo() { + synchronized (this.a) { + this.a = 2; + } + this.a = 1; // here! + } +} +\end{lstlisting} + + \item \pattern{Redundant catch}{P15}{Here, the method \texttt{foo()} throws IOException, but we catch it inside the method.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + void foo() throws IOException { + try { + Files.readAllBytes(); + } catch (IOException e) { // here + // do something + } + } +} +\end{lstlisting} + + \item \pattern{Return null}{P16}{When we return null, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + String foo() { + return null; + } +} +\end{lstlisting} + + \item \pattern{String concatenation using \texttt{+} operator}{P17}{Any usage string concatenation using \texttt{+} operator is considered as pattern match.} +{\it Example:} +\begin{lstlisting}[language=Java] +public void start() { + // this line is match the pattern + System.out.println("test" + str1 + "34234" + str2); + list = new ArrayList<>(); + for (int i = 0; i < 10; i++) + list.add(Boolean.FALSE); +} +\end{lstlisting} + + \item \pattern{Override method calls parent method}{P18}{If we call parent method from override class method it is considered as the pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +@Override +public void method1() { + System.out.println("subclass method1"); + super.method1(); +} +\end{lstlisting} + + \item \pattern{Class constructor except \texttt{this} contains other code}{P19}{The first constructor has this() and some other statements. This is the ``hybrid constructor'' pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private int id; + Book() { + this(1); + int a = 1; // here + } + Book(int i) { + this.id = I; + } +} +\end{lstlisting} + + \item \pattern{Line distance between variable declaration and first usage greater then threshold}{P20\_5, P20\_7, P20\_11}{If line distance between variable declaration and first usage exceeds some threshold we consider it as the pattern. We calculate only non-empty lines. P20\_5 means that distance is 5.} +{\it Example:} +\begin{lstlisting}[language=Java] +// variable a declared and used with 2 lines distance +static void myMethod() { + string path1 = '/tmp/test1'; + int a = 4; + + string path2 = '/tmp/test2'; + string path3 = '/tmp/test3'; + a = a + 4; +} +\end{lstlisting} + + \item \pattern{Variable is declared in the middle of the method body}{P21}{All variable we need have to be declared at the beginning of its scope. If variable declared inside the scope following after logical blocks we consider that this is the pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +// The declaration of variable list is match pattern. +static void myMethod2() { + int b = 4; + b = b + 6; + List list = new List(); +} +\end{lstlisting} + + \item \pattern{Array as argument}{P22}{If we pass an array as an argument, it's a pattern. It's better to use objects, instead of arrays.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void bar(int[] x) { + } +} +\end{lstlisting} + + \item \pattern{Joined Validation}{P23}{Once you see a validation (if with a single throw inside) and its condition contains more than one condition joined with OR -- it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + void print(int x, int y) { + if (x == 1 || y == 1) { // here! + throw new Exception("Oops"); + } + } +} +\end{lstlisting} + + \item \pattern{Class declaration must always be \texttt{final}}{P24}{Once you see a non \texttt{final} method, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private static void foo() { + } +} +\end{lstlisting} + + \item \pattern{Private static method}{P25}{Once you see a \texttt{private static} method, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private static void foo() { + //something + } +} +\end{lstlisting} + + \item \pattern{Public static method}{P26}{Once you see a \texttt{public static} method, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + private static void foo() { + //something + } +} +\end{lstlisting} + + \item \pattern{Var siblings}{P27}{Here fileSize and fileDate are ``siblings'' because they both have file as first part of their compound names. It's better to rename them to size and date.\\ + file and fileSize are NOT siblings.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void bar() { + int fileSize = 10; + Date fileDate = new Date(); + } +} +\end{lstlisting} + + \item \pattern{Assign null}{P28}{Once we see \texttt{= null}, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void bar() { + String a = null; // here + } +} +\end{lstlisting} + + \item \pattern{Multiple \texttt{while} pattern}{P29}{Once you see two or more \texttt{while} statements in a method body, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Book { + void foo() { + while (true) { + } + // something + while (true) { + } + } +} +\end{lstlisting} + + \item \pattern{Protected method}{P30}{Once we find a protected method in a class, it's a pattern.} + + \item \pattern{Send \texttt{null}}{P31}{Once we see that \texttt{null} is being given as an argument to some method, it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void bar() { + FileUtils.doIt(null); // here + } +} +\end{lstlisting} + + \item \pattern{Nested loop}{P32}{Once we find a loop (\texttt{for} / \texttt{while}) inside another loop it's a pattern.} +{\it Example:} +\begin{lstlisting}[language=Java] +class Foo { + void foo() { + white (true) { + for (;;) { // here + } + } + } +} +\end{lstlisting} + +\end{itemize} \ No newline at end of file diff --git a/wp/sections/available_data.tex b/wp/sections/available_data.tex deleted file mode 100644 index 7f1eb922..00000000 --- a/wp/sections/available_data.tex +++ /dev/null @@ -1,36 +0,0 @@ -We considered available data in some open sources -related to the defect detection problem. Some datasets -have only code samples and labels, while others have -calculated some code metrics. - -ETH JavaScript Dataset\footnote{\url{https://www.sri.inf.ethz.ch/js150}} -includes 150,000 JavaScript code samples represented as AST trees. -The dataset has been used in a binary classification task. -Target positive examples were extracted from the code -and negative examples were generated using -Negative Sampling techique. The dataset -was used by~\citet{DeepBugs} in an attempt to find the following defects: -swapped arguments, wrong binary operator, and wrong binary operand. - -NASA Dataset\footnote{\url{http://promise.site.uottawa.ca/SERepository/datasets-page.html}} -includes 20 small-sized datasets (20 to 2000 samples in each one) of NASA projects. -It does not contain code itself but only code metrics. The data -was previously used for defect prediction, cost estimation, successful reuse, and requirements tracing. - -Defects4j Dataset\footnote{\url{https://github.com/rjust/defects4j/tree/additional-projects-4}} -includes code samples from different projects, -where each one has 52 defects of different -type. The datasets was built by scrapping bug reports and commits -that fixed them. This dataset does not have labels. - -BugLocalization Dataset:\footnote{\url{https://github.com/yanxiao6/BugLocalization-dataset/tree/master/dataset}} -has 18,500 Java defect report samples from five GitHub-hosted projects. -Each sample consists of defect description, a commit to fix the defect -and a link to GitHub source code file. - -CodeSearchNet dataset:\footnote{\url{https://github.com/github/CodeSearchNet}} -is a large dataset of over two million rows of code -collected from open source libraries. The dataset contains -Python, Javascript, Ruby, Go, Java, and PHP languages. -Each sample consists of a function code and a comment related -to the function. The dataset is built for a semantic code search task. diff --git a/wp/sections/conclusion.tex b/wp/sections/conclusion.tex new file mode 100644 index 00000000..e9b59f5a --- /dev/null +++ b/wp/sections/conclusion.tex @@ -0,0 +1,28 @@ +Aibolit is a recommender system that helps improve the quality of Java classes. +The recommendations are learned from OSS Java projects using ML methods. +Aibolit provides ranked recommendations for each specific Java class, +which differs Aibolit from others style checkers and makes it unique. + +Aibolit is an extendable system, allowing anyone to add new patterns and to +increase the training dataset and thus improve the precision and usefulness +of recommendations. Aibolit can also be used as a framework for analysis of +patterns and to decide whether any pattern, however subjective it is, is an anti- or a pro-pattern +with respect to a particular quality metric. As a complementary result, +we contribute a 100K+ dataset of patterns and metrics calculated for Java classes. + +The first version of Aibolit is relatively simple and there is room +for improvement. If the anti-pattern has found, we recommend to fix all instances +of the pattern in the code. Instead, we may consider each specific occurrence of the pattern. +We may exploit its relative position in the structure of the code, rather than just count +the frequency. Moreover, Aibolit inspects each Java class independently. But +we might consider the relations between classes in the future. Furthermore, +Aibolit's prediction model relies on patterns only. In order to improve the model, +we have to think about additional features, for example, information about +project domain or used frameworks. + +Aibolit is a firm step toward the next generation of tools to control +and improve software quality. It is a complementary tool for +product owners who already use tools to manage software quality. + + + diff --git a/wp/sections/considered.tex b/wp/sections/considered.tex deleted file mode 100644 index 087aad36..00000000 --- a/wp/sections/considered.tex +++ /dev/null @@ -1,126 +0,0 @@ -Even though detecting defects is an important task in any software project, -existing studies differ in their definition of the parameters and objectives -of this task, -partially due to the ambiguity of the definition of the software defect. -Among others, there are many methods of defect detection, which utilize ML. -Below we classify them from a few different perspectives, -in order to justify the selection made later in this document. - -\subsection{By the Origin of Data} - -As suggested by~\citet{10.1007/s10462-017-9563-5} -the model can be built using the data -\begin{enumerate*}[label=\arabic*)] -\item from the same release of a software module (\emph{intra-release}), -\item from a few different releases of the same module (\emph{inter-release}), or -\item from different software modules (\emph{cross-project prediction}). -\end{enumerate*} -It seems that this classification was not possible earlier, -when analytical data was kept proprietary and was not available -for the community of researchers, only until NASA released a large -evidential dataset in 2004~\citep{Sayyad-Shirabad+Menzies:2005}. - -It it interesting to mention that -in early 2000s most authors assumed that ``distributions'' in both -training and testing datasets were similar~\citep{Turhan2009} (\emph{intra-release}), which -mislead them because the assumption was wrong. - -Later,~\citet{5609530} introduced ``ensemble techniques,'' which made the analysis -possible in situations when software modules do not have similar -distributions in their training and testing datasets (\emph{inter-release}). - -Recently,~\citet{Better_cross} demonstrated that defect detection may work across -different software modules, using their historical data (\emph{cross-project release}). - -\subsection{By the Output} - -ML-based defect detection methods can be classified by the type of the output they produce: - -First, the output could be \emph{binary}, which means that -software modules (like classes, methods, packages, etc.) are classified -either as faulty or non-faulty ones, as done by~\citet{Gokhale97regressiontree, Menzies04assessingpredictors}. - -Second, \emph{defect density} or the \emph{number of defects} -may be reported per module, demonstrating the degree of their defectiveness, -as suggested by~\citet{Predicting_Fault, JANES20063711, 7510216}. - -Third, \emph{defect severity prediction} may be reported per module, demonstrating -the impact of defects found in the module to the end-user experience, -as suggested by~\citet{7510216, SHATNAWI20081868, 1717471}. - -Fourth, the output could contain information about a specific location -of the defect inside the source code (the line of code with a defect), -as suggested by~\citet{vasic2019neural}. - -\subsection{By the Input} - -\textbf{Software metrics} can be used as an input. -They can be obtained from the source code, -and can belong to one of the following categories: - -\begin{itemize} -\item \emph{Product metrics} are generally used to check -whether software follows~\citep{InternationalStandardOrganization}, -as it was mentioned by~\citet{10.1007/s10462-017-9563-5}, -and can be classified as suggested by~\citet{10.5555/540137}: -\begin{enumerate*}[label=\arabic*)] -\item \emph{Traditional} metrics may include size, -system complexity~\citep{1702388}, and others; -\item \emph{Object-oriented} metrics may include coupling, -cohesion and others specifically related to object-oriented -methodology, as suggested by~\citet{979986, Incorporating_transitive}; -\item \emph{Dynamic} metrics are gathered from a running -program and demonstrate the behavior of a software component -during its execution~\citep{MITCHELL20064}. -\end{enumerate*} - -\item \emph{Process metrics} such as number of modules changed for a bug-fix, - work products delivered, and so on may also be used - as an input~\citep{The_IT_Measurement_Compendium, 10.1109/ISSRE.2010.25}. -\end{itemize} - -\textbf{AST} can also be used -as an input, which is a represention of the syntax of a -software code snippet as a tree-like structure. -E.g.,~\citet{6676914} computes the set of AST changes between two source -code files using algorithm, published by~\citet{4339230}. - -\subsection{By the ML Model} - -There are plenty of studies for bug detection problem -in which ML methods are used. ML methods -for solving defect detection problem can be classified into the following groups: - -\begin{enumerate}[label=\arabic*)] -\item \emph{Unsupervised learning} is a learning model which uses unlabeled data. -The goal of unsupervised methods is to uncover unknown patterns in the data. -Unsupervised learning for solving defect detection problem includes such algorithms -as K-Means clustering cleaning approach~\citep{8952192}, KNN~\citep{8777507}. - -\item \emph{Supervised learning} uses labeled data to produces a function, -which maps unseen data to labels. Supervised methods for defect detection includes -\citep{10.1145/1137983.1138012}, Naive Bayes~\citep{4027145}, Random forest -\citep{1383136, 7476673}, nearest neighbor -\citep{10.1145/2786805.2786813}, SVM~\citep{ELISH2008649, 10_1007}, -neural network~\citep{THWIN2005147THWIN2005147},~\citep{1033229, 10.1145/3360588} and ensemble techniques~\citep{Ensemble_Techniques}. -Some authors tried to combine different machine learning techniques -(Linear Regression, Neural Network for continuous goal field, Naive Bayes, etc.) -with statistical techniques, such as PCA~\citep{1544801}. - -\item \emph{Semi-supervised learning} uses both labeled and unlabeled data and -is a combination of supervised and unsupervised methods. -It can help unsupervised methods to obtain better-defined clusters, -as explained by~\citet{semi_supervised_learning, 7965301, Zhang2017}. - -\item \emph{Deep learning} is a class of ML algorithms, which extracts -features from lower layers in order to use them in higher ones. -Textual information (for example, English bug reports -or source files comments and names of variables) can be used in deep learning. -Using this information, deep learning -can achieve better performance than many state-of-the-art approaches. -For example,~\citet{8616596} proposed a different method based -on Long Short-Term Memory (LSTM) networks -and~\citet{XIAO201917} suggested to use -convolutional Neural Network together -with word-embedding and feature-detecting techniques. -\end{enumerate} diff --git a/wp/sections/empirical_results.tex b/wp/sections/empirical_results.tex deleted file mode 100644 index 0536dd4b..00000000 --- a/wp/sections/empirical_results.tex +++ /dev/null @@ -1,13 +0,0 @@ -In our first experiment we collected dataset of Java classes and calculated -metrics and patterns for them. We calculated the readability using open-source -tool. Then we estimate the impact features to readability and conclude that -\emph{ncss\_method\_avg}, \emph{halstead\_volume}, and \emph{right\_spaces\_var} are -most important features. The more details you can find in \emph{Report 1}. - -In second experiment we figured out non-zero correlation between the -non-structural patterns and the code complexity metrics like \emph{Cyclomatic Complexity} -and \emph{NPath}. We observe that \emph{var\_in\_the\_middle} shows -highest impact on complexity. We explain it by the fact that the more complex -programs will tend to have more variable and some of them declared in the middle -of the method body. The more details you can find in \emph{Report 2}. - diff --git a/wp/sections/how_aibolit_works.tex b/wp/sections/how_aibolit_works.tex new file mode 100644 index 00000000..940f3607 --- /dev/null +++ b/wp/sections/how_aibolit_works.tex @@ -0,0 +1,235 @@ +\subsection{The Idea} + +The main purpose of Aibolit is to help developers identify patterns in their +code that may cause maintainability issues. From the user perspective, it works +by outputting a list of patterns recommended to remove, given a Java class. The +Aibolit engine is comprised of two parts: an ML regression model and a +recommendation algorithm. The regression model predicts maintainability of any +Java class. The recommendation algorithm uses the regression model to decide +which pattern is better to avoid by considering different various modifications +of the input Java class. + +\begin{figure}[t] +\includegraphics[width=13cm]{how_it_works_diagram_5.jpg} +\centering +\vspace{1 cm} +\caption{How Aibolit works: (1) Inspect the source code for patterns. +(2) Count the pattern occurrences and put them in a vector representation. +Compute the maintainability metric value for the vector. +(3) Consider changes to the vector representation by subtracting pattern counts. +Predict the corresponding maintainbility metric score. +(4) Rank all the alternative vectors wrt to how much they improve the original +maintainability score. Recommend changes that gave the most improvement.} +\label{fig:aibolit_graphic} +\end{figure} + +Figure~\ref{fig:aibolit_graphic} represents the Aibolit recommendation proceduce on high level. +In the remaining subsections we provide a more detailed +description of each of Aibolit's components. + +\subsection{Patterns \& Quality metrics} +\label{sec:aibolit_patterns_metrics} + +\subsubsection*{Patterns} + +As discussed above (Section~\ref{sec:related}), +software engineering researchers and practitioners often associate +good and bad code design with specific patterns. We follow this tradition and +build a predictive system to reason about observed patterns in code in terms of their effect on quality. +In the current release of Aibolit, the model is built on top of 34 +commonly used manually designed patterns as input features. See Appendix +for the complete list and detailed descriptions. Note that users of Aibolit +can arbitrarily extend the model by implementing and integrating their patterns +of choice. + +\subsubsection*{Metrics} + +The ultimate goal behind Aibolit's approach is to +learn to identify maintainability-affecting patterns in code and recommend them +to the user. However, as discussed above, maintainability quantification is +still an open problem, and most of the metrics proposed so far typically +describe only a narrow aspect of software maintainability. We recognize it as +the major challenge of our approach and plan to research this problem in the +future. + +In the current release of Aibolit, we use Cognitive Complexity \citep{10.1145/3194164.3194186} as +the maintainability metric. We refer to it as the maintainability metric or just +metric in the remainder of the text. + +\subsection{Maintainability prediction model} + +\label{sec:maint_pred_model} + +\subsubsection*{Dataset} + +\label{sec:dataset} + +To train our prediction model, we mined training data +from Github open source repositories. We chose repositories written in Java +as the main language. We filtered out all non-Java files and all software +testing files. To make sure our data is +representative of good software engineering standards, we only extracted +repositories with at least 100 starts and at least six collaborators. + +Aibolit is currently designed to do predictions and recommendations at class +level. For simplicity, we only consider files that contain exactly one +non-abstract Java class. +%We chose this level of granularity because it is intuitive and because we +%wanted to narrow down our scope for the first stage of development. Thus one +%datapoint in our dataset is one Java class. +We filtered out classes with fewer than 50 and more than 300 lines of code. +The resulting filtered dataset consists of 124 repositories and +29,065 classes. Before filtering, we split the dataset into a test and train sets randomy by files with +approximately 0.7:0.3 ratio. The filtered train set contains 20,049 classes, +the filtered test contains 9,016. +%More detailed statistics can be found in Table~\todo. -- keep this for research paper +The complete list of mined repositories and the train/test split is provided in Aibolit +project folder. +%(\todo link to file with repository URLs). + +\subsubsection*{Feature and target preprocessing} + +Each Java class gets +associated with a vector of numerical features. We use scaled pattern counts as +features. For each pattern from the fixed set +(see Appendix), we count its occurrences in the +class and divide it by the number of non-commented lines in the class (NCSS). +The target value for each datapoint is the maintainability metric value for the +class (Section~\ref{sec:aibolit_patterns_metrics}), also divided by the NCSS. +%(\ref{eq:feat_vector}) and (\ref{eq:targ_val}) summarize feature and target +%value computation (where $f_p^C$ is the feature value for pattern $p$ and code +%$C$, $t^C$ is the target value for code $C$ ). +Table~\ref{tab:features_example} +gives an illustration of how a dataset looks like after the this procedure. + + +%\vspace{0.2in} +% +%\begin{minipage}{.4\linewidth} \begin{equation} \label{eq:feat_vector} f_p^C = +%\frac{\textit{count}(p, C)}{\textit{NCSS}(C)}\end{equation} \end{minipage}% +%\begin{minipage}{.55\linewidth} \begin{equation} \label{eq:targ_val} t^C = +%\frac{\textit{Metric}(C)}{\textit{NCSS}(C)} \end{equation} \end{minipage} +% +%\vspace{0.2in} + + +We apply NCSS scaling because we observed that our maintainability metric +(Cognitive Complexity) is highly correlated with code size. The scaling +stimulates the model to find more implicit dependencies between patterns and +complexity. + +\begin{table}[H] \begin{center} \begin{tabular}{|r|rrrr|r|} \hline \textbf{class +id} & \textbf{P16} & \textbf{P11} & \textbf{P13} & \dots & \textbf{CogC} +(target metric) \\ \hline \hline class 1 & 0.008695 & 0. & 0.026086 & +\dots& 0.417391 \\ class 2 & 0. & 0.05 & 0.116667 & \dots& +0.466667 \\ class 3 & 0.009909 & 0. & 0.009909 & \dots & 0.732673 \\ +\hline \end{tabular} \end{center} \caption{Example of a training dataset with +preprocessed feature values. \textbf{P16}: {\em Return null}, \textbf{P11}: {\em +Multiple Try}, \textbf{P13}: {\em Null checks}).} \label{tab:features_example} +\end{table} + + + +\subsubsection*{Training} +We train a gradient boosting regression model \citep{Friedman2001GreedyFA}. +We use the implementation of CatBoost \citep{Dorogush2018CatBoostGB} with the RMSE loss function. +For hyperparameter selection, we do a 3-fold crossvalidation. + + +\subsection{Recommendation algorithm} +\label{sec:recommendation_algorithm} +Our recommendation algorithm ranks +patterns observed in the user's source class according to their individual +impact on the code's maintainability metric value. It then outputs a pattern +with the \textit{most negative impact} as a recommendation to the user to remove +it from their code. + +For each pattern $p$ we compute the \textbf{impact factor} $I_{\textit{neg}}(p, C)$ +on code $C$, which is intended to capture the \textit{negative +influence} of $p$ on $C$. It is the difference between the quality metric value +of the original code $C$ and the version of $C$ where the count of $p$ has been +decreased (Eq.~\ref{eq:impact_factor}): + +\begin{equation} \label{eq:impact_factor} I_{\textit{neg}}(p_i, C) = M(F(C)) - +M(F_{p_{i} - 1}(C)), \end{equation} + +where $M$ is a quality metric, $F(C)$ is the feature vector $\langle f^C_{p_1}, +..., f^C_{p_n} \rangle$, $F_{p_{i} - 1}(C)$ is the feature vector with the count +of $p_i$ decreased by $1$.%: $\langle f^C_{p_1}, ..., f^C_{p_i - 1}, ..., +%f^C_{p_n} \rangle$. With $f^C_{p_i - 1}$ computed as:\footnote{We chose to +%subtract 1, but in principle it is a hyperparameter of our model and we plan to +%experiment with other values.} + +%\begin{equation} \label{eq:feature_count_min_1} f_{p_i - 1}^C = +%\frac{\textit{count}(p_i, C) - 1}{\textit{NCSS}(C)} \end{equation} + +Under the ``lower metric is better'' convention (i.e., lower value of quality metric +means better quality), lower values of $I_{\textit{neg}}$ correspond to patterns +that contribute more to the deterioration of the code's quality. We rank pattern +according to their $I_{\textit{neg}}$ and output patterns with lowest values as +recommendations. + +Note that at the moment of recommendation we do not observe code with a +decreased pattern count, so we cannot compute the maintainability metric +directly. This is why we resort to a predictive maintainability model +(Section~\ref{sec:maint_pred_model}), which helps estimate maintainability of a +hypothetical code. + + + +\textbf{Algorithm}~\ref{fig:recsys_alg} summarizes how we do recommendations. +For each pattern from the set of patterns used at training, we +precompute feature values and compute the metric value of the source code +(lines~\ref{line:init_F}-\ref{line:compute_m_source}). Then we compute the +impact factor $I_p$ of each pattern $p$ on the source code maintainability +(lines~\ref{line:init_I}-\ref{line:impact}). Under ``lower is better'' +convention of maintainability metric, low values of $I_p$ indicate that removal +of $p$ lead to improvement of the metric score. We collect the $K$ most +negatively impacting patterns and output them as recommendations. Thus, we + pick patterns $p$ for which $I_p$ are the highest +(lines~\ref{line:topK}-\ref{line:return}). + +\begin{algorithm}[t] +\caption{Aibolit recommendation algorithm} +\hspace{\algorithmicindent} +\textbf{Input:} $\mathsf{M}$: pretrained +maintainability model); $C$: class source code; \\ +\hspace{\algorithmicindent} $P$: array of patterns used for training $\mathsf{M}$\\ + +\begin{algorithmic}[1] +\State $F = [ ]$ \label{line:init_F} +\For{\texttt{i = 1, $|P|$}} +\State $F[i] =\frac{\textit{count}(P[i], C)}{\textit{NCSS}(C)}$% (Eq.~\ref{eq:feat_vector}) +\EndFor \State $M_{\textit{observed}} = \mathsf{M}(F)$ \label{line:compute_m_source} +\State $I = [ ]$ \label{line:init_I} +\For{\texttt{i = 1, $|P|$}} + +\State $F^{\prime} = F$ +\State $F^{\prime}[i] = F[i] - \frac{1}{\textit{NCSS}(C)}$ \label{line:f_prime} %(Eq.~\ref{eq:feature_count_min_1}) +\State $I[i] = M_{\textit{observed}} - \mathsf{M}(F^{\prime})$ \label{line:impact} % (Eq.~\ref{eq:impact_factor}) +\EndFor +\State $I_{\textit{worst}} = \texttt{topK}_{i \in [1,...,|P|]} (-I[i])$ \label{line:topK} +\State \textbf{return} $\{P[i]~|~i \in I_{\textit{worst}}\}$ \label{line:return} + +\end{algorithmic} +\centering +\label{fig:recsys_alg} +\end{algorithm} + + +% \subsection{How to customize Aibolit} label{sec:customizing_aibolit} + +% By design, Aibolit is easily adjustable and extendable. It gives an end user +% the opportunity to adapt the tool to their own requirements and preferences. +% Aibolit's core mechanism is ML-driven, therefore, as the user adds new +% patterns to the system, there is no need to manually specify how the pattern +% should be used by the tool. The interactions between patterns are discovered +% automatically by the learning algorithm. + +% In order to modify the set of patterns, the user should provide an +% implementation of a pattern extractor for source code file and modify the +% configuration file (\verb|aibolit/config.py|) accordingly. See full +% instructions in \todo (shouldn't we add them in README?) + +% In order to change the quality metric for training the prediction model, ??? +% \todo. diff --git a/wp/sections/implementation.tex b/wp/sections/implementation.tex deleted file mode 100644 index e69de29b..00000000 diff --git a/wp/sections/introduction.tex b/wp/sections/introduction.tex index c9505f08..d3643efa 100644 --- a/wp/sections/introduction.tex +++ b/wp/sections/introduction.tex @@ -1,39 +1,74 @@ -% What is quality of code and why it's important? -% What is static analysis? +Insufficient software quality may result in increased development costs and +negatively affect customer satisfaction ~\citep{The_Economics_of_Software_Quality}. +\textit{Static code analysis} develops techniques to help detect software quality +issues prior to program execution. It has its practical application in various developer's tools. There are both open source\footnote{PMD: \url{http://pmd.sourceforge.net/}, Rubocop: \url{https://github.com/rubocop-hq/rubocop}, +PHPCS: \url{https://github.com/squizlabs/PHP_CodeSniffer} +FindSecBugs: \url{https://find-sec-bugs.github.io/}, ESLint: \url{https://eslint.org/}, Checkstyle: \url{https://checkstyle.sourceforge.io/}.} +(PMD, Rubocop, PHPCS, FindSecBugs, ESLint, Checkstyle, to name a few) and commercial\footnote{IBM Security AppScan: \url{https://www.hcltechsw.com/wps/portal/products/appscan}, +PVS-Studio: \url{https://www.viva64.com/en/pvs-studio/}, +SonarQube: \url{https://www.sonarqube.org/}, +Parasoft: \url{https://www.parasoft.com/}} +(IBM Security AppScan, PVS-Studio, SonarQube, Parasoft) static analyzers +on the market. -% What is ML? +Static code analysis can be applied to improve an \textit{internal} and an +\textit{external} quality of software \citep{Ilyas2016StaticCA}. External +quality is related to defects encountered by the end user of the software +product. Within internal quality, two important subcategories are +\textit{functional quality} and \textit{maintainability}. Functional quality is +about code correctness and compliance with the functional software +specifications \citep{Farhan}. Code maintainability is about how easy it is to +analyze, modify and adapt given software \citep{Mohammadi2013AnAO}. -% What is the objective of using ML for defect detection? +Functional quality aspects are typically quite susceptible to formal definition +and quantification. +% (\todo: examples!!). +Functional quality is also an essential +requirement in any domain of software development. On the other hand, +maintainability is a lot less straightforward to formally specify or quantify. +%\todo: refs. +Also, in certain applications it appears less important than +functional correctness, although in business domain it is recognized as an +essential property. +% (\todo: ref). +As a result, there are currently a lot more +research and practical tools addressing functional quality aspects of code than +maintainability \citep{Overview_Static_Code_Analysis_in_Software_Development}. +Another aspect of static analysis tools that may have hindered their application +to maintainability, is that they are predominantly rule-based. Since there has +not yet been a consensus on how to formalize maintainability, it is challenging +to devise a set of formal rules to detect it. -% What is the structure of this document? +We designed our new tool Aibolit to help developers identify patterns in their +code that may cause maintainability issues. It is a next generation static +analysis tool that uses a machine learning (ML) model as an underlying quality +prediction mechanism. From the perspective of ML, our product is a recommender +system. For a given class file, it gives suggestions to the developer to alter +their code. The recommendations come in the form of \textit{code patterns} that +are detected in the code and advised to be removed. + +Our choice to design Aibolit as a ML-based system alleviates some important +shortcomings of rule-based static analyzers. By design, ML algorithms capture +statistical relations in the external world (data). Therefore, they can be a +good way to model imprecisely and subjectively defined properties of code, such +as its maintainability. Moreover, rule-based system are known to not scale well +to the diversity of empirically observed cases, and they tend to get very hard +to extend and maintain \citep{LenatFeigenbaum1987}. The ML +approach does not require +manual system adaptation as new observations or new features (patterns) come +along. In fact, Aibolit provides an easy way for developers to integrate a code +pattern of their liking into the recommender system and to analyze the pattern`s +impact on code quality. -Last years we see that the number of papers, which are trying to apply ML to source -code analysis, is growing. The researchers, encouraged by the success -of ML, deep learning, and Natural Language Processing (NLP), -are trying to adopt similar approaches to the code analysis. -In our new tool we make an attempt to automatically detect defects -in a software source code using ML and existing source code metrics, -such as Cyclomatic Complexity, cohesion, Number of Incoming Invocations, -and others. -In Section~\ref{sec:related} we analyze existing tools and methods -of static analysis and identify the most important issues currently -present in modern instruments. -In Section~\ref{sec:categories} we classify existing ML-based -static analysis ideas by the type of input they expect, by the output -they produce, and some other qualities. -In Section~\ref{sec:data} we make an attempt to summarize the situation -with data availability on the market and give a few examples of the -most notable datasets freely available for researchers. -In Section~\ref{sec:criteria} we identify the most important criteria -for the selection of the method and the tool for ML-based static analysis. -In Section~\ref{sec:method} we introduce our own method of detecting -defects in the source code using ML and software code metrics. +% This document explains how Aibolit works and what makes it novel and +% different from other static analyzers (Section~\ref{sec:method}). +% We further show how Aibolit can be extended +% with custom patterns and metrics. We discuss the current shortcomings and the way +% they can be addressed in future work (Section~\ref{sec:conclusion}). -In Section~\ref{sec:risks} we identify a number of risks we forecast -for the project and expect to mitigate. \ No newline at end of file diff --git a/wp/sections/motivation.tex b/wp/sections/motivation.tex new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/wp/sections/motivation.tex @@ -0,0 +1 @@ + diff --git a/wp/sections/notes.tex b/wp/sections/notes.tex deleted file mode 100644 index 2734b441..00000000 --- a/wp/sections/notes.tex +++ /dev/null @@ -1,39 +0,0 @@ -Code readability is closely related to defect detection problem. There are plenty of -studies where the problem of code readability is considered -\citep{8651396, xxx66666444, 10.1145/1985441.1985454}. At the moment, it is -still the issue since the problem is too subjective. - -It is interesting that \citet{10.1109/ICPC.2019.00014} tried to evaluate -the models for code readbility problem. The authors extracted 548 commits -from 63 engineered Java software projects. The authors identified a commit as a readability commit -when the message of the commit directly indicated it. E.g., -the authors searched such words of the commit as ``readable'', -``readability'', ``easier to read'', ``understand'', etc. -Several state of the art readability models were reviewed by \citet{10.1109/ICPC.2019.00014} -and it was discovered, that the models failed to capture readability improvements. -The authors also suggested several metrics which were not considered in the reviewed state-of-art papers. -The authors believe that those metrics for code readability can be used to detect readabilty -changes more efficiently. - -It is important to notice that code readabilty also can have a correlation -with complexity of the code. \citet{10.1109/TSE.2009.70} compared code readability -and software complexity. They used tools, published by \citet{xxx66666444, Readabil74:online}, to -compute metrics for code readability like \emph{The Automated Readability Index}, -\emph{The Simple Measure of Gobbledygook}, \emph{Flesch-Kincaid Readability Index} -\emph{The Gunning's Fog Index}, \emph{Coleman-Liau Index and Buse Readability Score}. -Also, they computed complexity software metrics, such as \emph{Halstead Complexity Volume}, -\emph{McCabe's Cyclomatic Complexity}. The authors found out that there was a -negative correlation between the readability and complexity metrics. -It means that low readability increases program complexity and vice versa. -The authors also mentioned that the languages constructions as comments, spacing, -while loop, meaningful names and do-while loop affects the code readiblity the most. -The authors also published a dataset with Java code which can help to detect defects. - -\citet{10.1007/978-3-319-95171-3_32} proposed a model which quantitatively measures the readability -of source code. The first idea is the using metrics (\emph{LOC, ProgramVolume, Entropy}) -as the key indicators which affect the source code readability. The second -idea is that the authors introduced the equation for quantitative measure -the source code readability in real time. This measure can demonstrate -how small changes in the code affect the readability of the code. -The authors also tried to optimize the model and they reached about -74.59\% of explanatory power. diff --git a/wp/sections/pattern_emp_analysis.tex b/wp/sections/pattern_emp_analysis.tex new file mode 100644 index 00000000..5438f084 --- /dev/null +++ b/wp/sections/pattern_emp_analysis.tex @@ -0,0 +1,124 @@ +\subsection{Empirical analysis of patterns} + +As a by-product of Aibolit's ML and recommendation +engine, we get a tool for empirically analysing different patterns' impacts on the target quality metric. Just +like in the main recommendation algorithm (Algorith~\ref{fig:recsys_alg}, Section~\ref{sec:recommendation_algorithm}), we can estimate whether a particular pattern has a positive or negative impact on the quality metric by considering modifications of source code where pattern count is decreased or increased. We perform such a procedure on a heldout set, which allows to estimate the average impact of a particular pattern on quality. + +In Table~\ref{tab:pattern_analysis} we present a case study of the 34 patterns used at training of Aibolit (see Appendix for the pattern descriptions). On a separate test set (see details in Section~\ref{sec:dataset}), for each pattern, we considered increasing and decreasing the pattern's count by 1. We used the pretrained Aibolit's regression model to predict the corresponding change in quality metric. + + +\begin{table}[ht] +\footnotesize +\begin{tabular}{lllllll} +patterns & p- m- & p+ m+ & p- m+ & p+ m- & p- m= & p+ m= \\ +\\ \hline +Asserts & 92 & 61 & 186 & 219 & 5 & 3 \\ +Setters & 245 & 160 & 901 & 976 & 21 & 31 \\ +Empty Rethrow & 77 & 65 & 25 & 36 & 0 & 1 \\ +Prohibited class name & 617 & 311 & 218 & 522 & 0 & 2 \\ +Force Type Casting & 2363 & 2313 & 1742 & 1790 & 14 & 16 \\ +Count If Return & 969 & 883 & 214 & 298 & 0 & 2 \\ +Implements Multi & 459 & 320 & 264 & 403 & 0 & 0 \\ +Instance of & 1396 & 1374 & 151 & 173 & 6 & 6 \\ +Many primary constructors & 19 & 19 & 604 & 605 & 2 & 1 \\ +Method chain & 573 & 574 & 2217 & 2214 & 43 & 45 \\ +Multiple try & 371 & 239 & 259 & 391 & 0 & 0 \\ +Non final attribute & 1249 & 1185 & 5835 & 5839 & 127 & 187 \\ +Null check & 5863 & 5978 & 575 & 457 & 9 & 12 \\ +Partial synchronized & 46 & 49 & 155 & 149 & 0 & 3 \\ +Redundant catch & 84 & 46 & 38 & 79 & 4 & 1 \\ +Return null & 1290 & 813 & 926 & 1401 & 4 & 6 \\ +String concat & 1596 & 2089 & 1506 & 1012 & 23 & 24 \\ +Super Method & 212 & 275 & 1012 & 949 & 10 & 10 \\ +This in constructor & 15 & 42 & 72 & 45 & 0 & 0 \\ +Var declaration distance for 5 lines & 1976 & 1464 & 738 & 1244 & 19 & 25 \\ +Var declaration distance for 7 lines & 1190 & 959 & 733 & 949 & 16 & 31 \\ +Var declaration distance for 11 lines & 703 & 603 & 365 & 466 & 10 & 9 \\ +Var in the middle & 3372 & 3117 & 2799 & 3046 & 37 & 45 \\ +Array as function argument & 882 & 768 & 351 & 464 & 1 & 2 \\ +Joined validation & 232 & 226 & 14 & 26 & 8 & 2 \\ +Non final class & 7141 & 3201 & 3723 & 7663 & 0 & 0 \\ +Private static method & 529 & 541 & 667 & 648 & 2 & 9 \\ +Public static method & 1166 & 1212 & 1142 & 1088 & 4 & 12 \\ +Null Assignment & 1245 & 803 & 717 & 1150 & 6 & 15 \\ +Multiple While & 120 & 97 & 16 & 39 & 0 & 0 \\ +Protected Method & 868 & 402 & 1147 & 1613 & 7 & 7 \\ +Send Null & 556 & 325 & 1510 & 1733 & 5 & 13 \\ +Nested Loop & 580 & 527 & 29 & 81 & 1 & 2 \\ +\hline +\end{tabular} +\centering +\caption{Empirical analysis of patterns. For each source code in the test set, we consider encreasing (\textbf{p+}) and decreasing (\textbf{p-}) pattern count by 1. And we recorded whether the maintainability metric increased (\textbf{m+}) or decreased (\textbf{m-}) as a result of that (where lower is better). In some cases the metric did no change (\textbf{m=}). The values in the cells are counts of cases.} +\label{tab:pattern_analysis} +\captionsetup{font=scriptsize} +% \caption*{ +% We use the following notation into named columns: +% ($p-$): decrease pattern by $\frac{1}{ncss}$; +% ($p+$): increase pattern by $\frac{1}{ncss}$; +% ($c-$): complexity has been decreased; $c+$: complexity has been increased; +% ($c=$): complexity has been not changed; +% (\emph{-1(top1)}): decreasing of pattern shows best \emph{CogC} improvement; +% (\emph{+1(top1)}): increasing of pattern shows best \emph{CogC} improvement. +% } +% \caption*{ +% We use the following notation into named columns: \\ +% \\ +% \centering +% \begin{tabular}{rl} +% $p-$ & decrease pattern by $\frac{1}{ncss}$ \\ +% $p+$ & increase pattern by $\frac{1}{ncss}$ \\ +% $c-$ & complexity has been decreased \\ +% $c+$ & complexity has been increased \\ +% $c=$ & complexity has been not changed \\ +% \emph{-1(top1)} & decreasing of pattern shows best \emph{CogC} improvement \\ +% \emph{+1(top1)} & increasing of pattern shows best \emph{CogC} improvement \\ +% \end{tabular} +% } +\end{table} + +Based on the statistics in Table~\ref{tab:pattern_analysis}, it appears that \emph{Prohibited class name}, \emph{Count If Return}, \emph{Instance of}, \emph{Null check}, \emph{Nested Loop}, +\emph{Array as function argument}, \emph{Joined validation} are \textbf{anti-patterns}, since their count decrease tends to improve the metric. Another group of patterns are \emph{Setters}, \emph{Many primary constructors}, \emph{Method chain}, \emph{Non final attribute}, \emph{Super Method}, \emph{Send Null patterns}: for them we observe that decresing them causes the metric to deteriorate, and increasing causes the metric to improve. We consider them \textbf{pro-patterns}. The third group (the rest of the patterns) can both improve and deteriorate the metric. We restrain oursevles from calling them either anti- or pro-patterns. + +Attempting to interpret the results, we observe that ``true'' anti-patterns usually have \emph{if/else condition} or cycle in their definition. +E.g., \emph{Null check} always checks for a null, \emph{Count If Return}, \emph{Instance of}, +\emph{Joined validation} have always \emph{if condition}, \emph{Nested Loop} has always at least 1 loop inside. Given that so far we have worked with the Cognitive Complexity metric, it is no surprise that those patterns affect it (\emph{if/else condition} or cycle are the main contributors into \emph{CogC}). Despite this limitation of the present analysis, we believe the proposed \textit{method} itself can be very useful in software engineering practice and research. + + + + +% ORIG TABLE: +% patterns & -1(top1) & +1(top1) & p- m- & p+ m+ & p- m+ & p+ m- & p- m= & p+ m= \\ +% \\ \hline +% Asserts & 0 & 100 & 92 & 61 & 186 & 219 & 5 & 3 \\ +% Setters & 1 & 113 & 245 & 160 & 901 & 976 & 21 & 31 \\ +% Empty Rethrow & 1 & 4 & 77 & 65 & 25 & 36 & 0 & 1 \\ +% Prohibited class name & 80 & 24 & 617 & 311 & 218 & 522 & 0 & 2 \\ +% Force Type Casting & 69 & 24 & 2363 & 2313 & 1742 & 1790 & 14 & 16 \\ +% Count If Return & 311 & 26 & 969 & 883 & 214 & 298 & 0 & 2 \\ +% Implements Multi & 24 & 244 & 459 & 320 & 264 & 403 & 0 & 0 \\ +% Instance of & 211 & 6 & 1396 & 1374 & 151 & 173 & 6 & 6 \\ +% Many primary constructors & 0 & 343 & 19 & 19 & 604 & 605 & 2 & 1 \\ +% Method chain & 3 & 203 & 573 & 574 & 2217 & 2214 & 43 & 45 \\ +% Multiple try & 156 & 180 & 371 & 239 & 259 & 391 & 0 & 0 \\ +% Non final attribute & 34 & 485 & 1249 & 1185 & 5835 & 5839 & 127 & 187 \\ +% Null check & 1573 & 14 & 5863 & 5978 & 575 & 457 & 9 & 12 \\ +% Partial synchronized & 1 & 93 & 46 & 49 & 155 & 149 & 0 & 3 \\ +% Redundant catch & 6 & 2 & 84 & 46 & 38 & 79 & 4 & 1 \\ +% Return null & 104 & 40 & 1290 & 813 & 926 & 1401 & 4 & 6 \\ +% String concat & 43 & 126 & 1596 & 2089 & 1506 & 1012 & 23 & 24 \\ +% Super Method & 1 & 174 & 212 & 275 & 1012 & 949 & 10 & 10 \\ +% This in constructor & 2 & 891 & 15 & 42 & 72 & 45 & 0 & 0 \\ +% Var declaration distance for 5 lines & 396 & 14 & 1976 & 1464 & 738 & 1244 & 19 & 25 \\ +% Var declaration distance for 7 lines & 25 & 95 & 1190 & 959 & 733 & 949 & 16 & 31 \\ +% Var declaration distance for 11 lines & 16 & 686 & 703 & 603 & 365 & 466 & 10 & 9 \\ +% Var in the middle & 118 & 50 & 3372 & 3117 & 2799 & 3046 & 37 & 45 \\ +% Array as function argument & 86 & 25 & 882 & 768 & 351 & 464 & 1 & 2 \\ +% Joined validation & 63 & 2 & 232 & 226 & 14 & 26 & 8 & 2 \\ +% Non final class & 1056 & 2370 & 7141 & 3201 & 3723 & 7663 & 0 & 0 \\ +% Private static method & 35 & 133 & 529 & 541 & 667 & 648 & 2 & 9 \\ +% Public static method & 37 & 408 & 1166 & 1212 & 1142 & 1088 & 4 & 12 \\ +% Null Assignment & 103 & 35 & 1245 & 803 & 717 & 1150 & 6 & 15 \\ +% Multiple While & 65 & 7 & 120 & 97 & 16 & 39 & 0 & 0 \\ +% Protected Method & 71 & 151 & 868 & 402 & 1147 & 1613 & 7 & 7 \\ +% Send Null & 13 & 109 & 556 & 325 & 1510 & 1733 & 5 & 13 \\ +% Nested Loop & 412 & 35 & 580 & 527 & 29 & 81 & 1 & 2 \\ \ No newline at end of file diff --git a/wp/sections/related_work.tex b/wp/sections/related_work.tex index d0f22f6d..f8ce4101 100644 --- a/wp/sections/related_work.tex +++ b/wp/sections/related_work.tex @@ -1,89 +1,85 @@ -There are many definitions of a defect. -\citet{5989519} says that defect is ``a fault, bug, inaccuracy or lack of expected -functionality in a project artifact.'' -\citet{Assurance} says that it is ``a problem -(synonym of fault) which, if not corrected, -could cause an application to either fail or to produce incorrect results.'' +\subsection{Quality and quality metrics} +IEEE Standards define software quality as the array of features of +a software product that represent its capability to satisfy +specific needs \citep{Youness2013ComparativeSO}. +Software quality is the extent to which a process, +component, or system fulfills customers' needs or expectations +through product or service features, thus providing customer +satisfaction \citep{Iacob_Constantinescu}. -Defects and software quality are directly related. There are multiple studies -of defect types, their impact, complexity, -root causse and other characteristics,~\citet[e.g.][]{10.1145/69605.2085, -10.5555/256664.256773, 10.1145/390016.808455, Glass1981PersistentSE, -10.1145/1353535.1346323, 10.1007/s10664-013-9258-8, catolino2019bugs}. -There are a few common preventive ways to deal with defects, like -static code analyzers, testing software, or peer code review. +Functional and structural qualities are the key aspects of software +quality \citep{Liu2006AnIE}. \citet{Farhan} describe +functional quality as the capability of the software +to properly perform its tasks according to user needs and +intended objectives. Structural quality refers to +the resilient structure of the code itself and is difficult to test +compared to functional quality. The main difficulty is that this +notion is quite subjective. -Static code analyzer -is a tool that helps find defects before a program is executed. -Such an analyzer inspects various program representations, for example -Abstract Syntax Tree (AST), Control Flow Graphs (CFG), or -Program Dependency Graph (PDG), -and search for handcrafted defect patterns. -These tools are popular among developers and are often embedded into -Integrated Development Environments (IDE) such as IntelliJ IDEA or NetBeans. -There are more than 40 static analyzers currently on the market, including -very famouns open source projects, such as -PMD, Rubocop, PHPCS, Sparse, CLion, cpplint, FindSecBugs, ESLint, and Checkstyle. -There are also many commercial tools, like -IBM Security AppScan, PVS-Studio, SonarQube, and Parasoft. -Software companies like Google and Facebook have their own open source -static analyzers: Error Prone~\citep{10.1109/SCAM.2012.28} and -Infer~\citep{10.1007/978-3-319-17524-9_1} respectively. -Static code analyzer may vary in supported languages, -supported defect types, and their integration workflow. +In general, structural code quality is a multi-faceted concept, which covers +different attributes of software engineering, for example, maintainability and +readability \citep{Mohammadi2013AnAO}. To evaluate them, various metrics of +software structure were proposed. For instance, McCabe’s software complexity +metrics \citep{McCabe1976ACM} and cognitive complexity metric +\citep{Cognitive}, which are intended to measure readability aspects of the +code. Also, for object-oriented systems, a popular set of metrics is the CK +suite \citep{Chidamber1994AMS}. Many approaches apply such metrics suite to +distinguish parts of the source code with good or bad quality +\citet{Fil2015ACO}, \citet{Shatnawi2010FindingSM} or to identify code smells +(problematic properties and anti-patterns of code) +\citet{Ouni2011MaintainabilityDD}. However, in general, the software engineering +community has not yet reached a consensus as to what exactly structural quality +or maintainability is \citep{Broy2006DemystifyingM}. +% (\todo: this is quite an old reference...). -Usually static code analyzers are rule-based. -In order to detect a new kind of defect their developers have to -design a new pattern. To address this extensibility problem -there were attempts to learn pattern -from data, as explained by~\citet{bielik2016learning, wang2019learning}. -Recent empirical study by~\citet{10.1145/3238147.3238213} demonstrates that -state-of-the-art code analyzers miss more than 90\% of defects. Most of those missed -defects are inconsistencies with the specification or programmer's intent. -In order to catch such defects it is necessary to reason about -possible behavior depending on the input data, -which is difficult or impossible for the rule-based approach. -Such defects are known as \emph{semantic} defects. -It has been demonstrated by~\citet{10.1007/s10664-013-9258-8} -that semantic defects are the dominant root cause for the majoirity of security issues, -when attacker may get unauthorized access to some resources. +\subsection{Software patterns and code smells} -Another issue of most static analyzers is their high -percent of ``false-positives,'' when they find a defect, which -in reality is not a defect. The amount of these false signals grows -when the size and complexity of the project increases. -This leads to developers loosing trust to the tool and stop -using it. +We understand the term \textit{software patterns} in the most general and +abstract way, namely, as any observed code subtructures and software solutions. +Patterns can be of different scale (from variable and method-level to project +level). The term \textit{designed patterns} refers to patterns that are +recommended solutions to commonly occurring programming goals and problems +\citep{gamma1995design}. Despite their popularity, there is much controversy about the +usefulness and universality of such recommended ways of implementation +\citep{mcconnell2004code}. The software engineering community +also identifies patterns that are detrimental to the resulting code. Such +patterns are often called \textit{code smells}. These are parts of the +source code that contain violations of fundamental design principles +and negatively impacts maintainability in terms of the +ability of the product to evolve, quality of end-product, and developer +productivity \citet{Reeshti2019MeasuringCS}. \citet{Din2012AntipatternsDA} +identified 22 types of code smells in object-oriented +design. \citet{Kessentini2019UnderstandingTC} found strong correlation between +several code smells and software bugs. -The efficiency of static analyzers is yet another problem. It was -empirically shown by~\citet{10.1145/3188720} that -a better performance metric for a static analyzer -is the amount of fixed, rather than found defects. -Static analyzers must provide the right information -at the right time doing everything possible to not annoy -software developers. +For the latter reason, a lot of tools and methods have been designed to avoid +code smells. \citet{Kreimer2005AdaptiveDO} proposes a decision tree based +approach to identify code smells, e.g, long method and large class. +\citet{Vaucher2009TrackingDS} apply Bayesian networks to detect God class. +\citet{Palomba2015MiningVH} propose to consider changes of repository history +as an input to the code smell detector for computing the list of code +components affected by the smell. \citet{Liu2019DeepLB} propose a deep learning +based approach to detect code smells. -Usually, static code analyzers use fixed in time code versions as their -input. However, one can also use the history of code changes and -the information from the Issue Tracking System (ITS) -to enhance the quality of prediction, as done by~\citet{Gupta2018IntelligentCR, kapur2018estimating}. +Code smell detection has been integrated into code inspection tools. +\citet{MurphyHill2010AnIA} integrate software metrics visualization with a +source code view. SonarQube\footnote{https://www.sonarqube.org/} controls and +manages the code quality in several ways, such as continuous inspection and +issue detection. The platform shows issues like code smells, bugs, using +lightweight visualizations. +%It also helps developers to collaborate with a +%shared vision of code quality. +Checkstyle\footnote{https://checkstyle.sourceforge.io/} and +PMD\footnote{https://pmd.github.io/} work similarly to SonarQube. -There are studies trying to use ML in order to detect defects. -For example, \citet{Dam2018ADT} first trained vector representations of -an AST in an unsupervised manner and then used it as a feature vector -to train the binary classifier. -\citet{kapur2018estimating} -combined the information extracted from the code programming style and ITS -and built a predictor to estimate the defectiveness of an input source code -file. Using an idea that the names of identifiers (variables, classes, functions) -convey useful information, which might be used to understand programmer's -intent, -\citet{Pradel2018DeepBugsAL} proposed a method that first learned -vector representation of identifiers -and obtained a fixed length vector for a code snippet to train a binary classifier -with feed-forward neural network. -\citet{vasic2019neural} used pointer-network to do joint prediction of -both the location and the possible fix for variable misuse bugs. -\citet{briem2019using} used attention-based neural network to model binary -classifier to detect off-by-one defects. +%iPlasma +%evaluate the quality of %object-oriented programs. It can be used %to calculate +%different metrics and to identify the most %critical points that can be improved +%through code smell %detection. + +All in all, there is no uniform agreement about which patterns are good and +which are bad. We made it our ideology while developing Aibolit: we do not +decide what is good or useful \textit{a priori} but let it be inferred from +data. By customizing the dataset, quality metric and pattern set, the end user +of Aibolit is able infer which patterns are good for his own end goals. diff --git a/wp/sections/risks.tex b/wp/sections/risks.tex deleted file mode 100644 index fffe210e..00000000 --- a/wp/sections/risks.tex +++ /dev/null @@ -1,26 +0,0 @@ -There is a number of risks we identified and expect to mitigate. - -\textbf{Survey Validity}. -While designing the survey procedure we have to -consider the following threats to its validity: -\begin{enumerate*}[label=\arabic*)] - \item Set of interviewers must be representive. - Will the results be different if we take a different set of interviewers? - \item Set of code snippets must be representive. - Will the results be different if we take a different set of code snippets? - \item How to identify bad interviewers? - Some interviewers may give answers that are not correlated with actual readability. -\end{enumerate*} -To mitigate this risk we have to think about the diversity of interviewers, -for example by age, skills, experience, education, and so on. We have to select code snippets -that vary in length and project domain. The more data we collect the better. -We have to preprocess survey results to exclude outliers. - -\textbf{Feature Limits}. -To predict the readability we are going to use features -calculated with static code analysis tools. -These features mainly reflect the structure, the syntax and -size properties of a particular code snippet. -However, we are not considering semantic properties of the code. -In the future, we can design semantic related features and -add them to our dataset. \ No newline at end of file diff --git a/wp/sections/saved.tex b/wp/sections/saved.tex deleted file mode 100644 index af50cd7f..00000000 --- a/wp/sections/saved.tex +++ /dev/null @@ -1,63 +0,0 @@ -% The refactoring recommendation -% is a pointer to specific line code with description what to do to improve code readability. -% To do this we studied a relationships between the code readability and mannualy designed AST patterns usually -% encountered in the code. Knowing that the pattern presented in code and has negative impact on readability -% we do our recommendations, pointing to code line where this pattern presented in the code. - -% In our work we created a dataset of Java code snipets features. The features may be devided into -% three groups: code metrics, AST patterns and code readability. The code metrics calculated using existing -% tools: CheckStyle, RefactoringMiner, ChangeDistiller, and SourceMeter. The AST patterns are manually designed -% features that reflect a presense of some syntax structures or other static code preperties, for example -% number of nested FOR loops of length 2 or number ternary operators. To obtain the code readability we conducted -% a survey that described in the next section. - -% \subsection{Dataset} - -% Next, we enriched each pair with metrics calculated -% based on static code, for example \acrfull{sloc}, \acrfull{cyclo}. Eventually we -% have the dataset, where for each snippet of code there are readability score and the set of metrics. - - -% % \begin{itemize} -% % \item Is it possible to predict code readability using static metrics of code? -% % \item Which metrics do have more importance to predict code readability? -% % \item Which ML model predict code readability better? -% % \item Is it possible to recommend particular code refactoring to improve code readability? -% % \end{itemize} - -% \subsection{Methodology} - -% We split our work into two parts. The first one is readability score prediction. -% The second part is code refactoring recommendations to improve code readability. - -% \subsubsection{Readability prediction} - -% Having unseen code snippet we have to estimate its readability score, because we are -% not going to give recomendation if the readability score is acceptable. -% We train a \acrshort{ml} model using gathered dataset. -% We stated the problem as a regression problem of predicting the readability score: - -% $$ -% r_{i} = f(X_{i}, \theta) + e_{i} -% $$ - -% where $i$ is the index of rows in our dataset, $r$ is the readability score, $X$ is -% the set of the code snippet's metrics, $e$ is some error or noise. And our goal is to choose -% the parametric function $f$ and finds its parameters $\theta$. - -% We tested a set of well-known regression models, like Linear Regression, \acrfull{cart}, -% to predict readability. We selected the best model among -% the considered set. - -% \subsubsection{Refactoring recommendations} - -% We measured a features importance with respect to readability score and made an ordered -% list of all features by importance. -% Having unseen code snippet with unacceptable readability score we do our refactoring recomendations. -% We rank our recommendations based on feature importance list. For AST related features we are able -% to point to specific place in the code. - - -% We formulate our business goal following way: having code snippet we want -% get list of refactoring recommendations indicating line and what to do to improve code quality. -% List should be ordered by refactoring impact on quality. \ No newline at end of file diff --git a/wp/sections/selected_task.tex b/wp/sections/selected_task.tex deleted file mode 100644 index 141e82fd..00000000 --- a/wp/sections/selected_task.tex +++ /dev/null @@ -1,84 +0,0 @@ -%Here will be paragraph linking previous sections with "Code Readability". - -%The research question is the following: is it possible, using static code analysis to do -%a code refactoring recommendations to improve a code readability? - -We are looking for an answer to the following research question: -Is it possible, -combining static code analysis and ML, -to detect defects in a Java class and -to give specific recommendations for its refactoring? - -To answer this question we are doing the following research: -\begin{enumerate*}[label={\alph*)}] - \item We take a set of Java \emph{classes}; - \item We collect a number of static analysis \emph{metrics} per each class; - \item We locate \emph{code patterns} inside each class; - \item We ask volunteer programmers to review - each class to estimate their \emph{readability}; - \item We put collected data together into a \emph{dataset}; - \item We find \emph{relations} between metrics and patterns in the dataset; - \item We take an unseen Java class and \emph{locate code patterns}, which impact the quality more then others. -\end{enumerate*} - -\textbf{Classes}. -We parse Java projects from GitHub to obtain training Java classes. -All parsed projects must have more than 100 stars, and more than five collaborators. -Collected Java classes must have more than 50 lines of code and less than 300. - -\textbf{Metrics}. -The code metrics are calculated using existing open-source -tools like CheckStyle and SourceMeter. Examples of metrics are Lines of Code (LoC), -Cyclomatic Complexity (CC), and Number of Incoming Invocations (NII). - -\textbf{Code Patterns}. -AST patterns are the features that reflect the presence -of some syntax structures in the code, -for example number of nested \texttt{FOR} loops -or the amount of ternary operators. The AST patterns are manually designed -and always point to a specific place in the code. - -\textbf{Readability}. -To gather readability characteristics we conduct -a survey, where volunteering programmers are asked to estimate -the readability of training Java classes, giving answers on a $[0..9]$ scale, -where 0 means not readable at all and 9 means perfectly readable. -Each programmer is asked to review some snippets from -the entire training dataset, which means that each -snippet is reviewed by a few programmers. The readability ``score'' per -snippet is a mean of all answers collected. - -\textbf{Dataset}. -We combine and put the data into the single dataset. -In the \autoref{tab:table1} you can see the example how dataset looks -(here CC, CBO, LCOM, and NMD are acronyms for software metrics, -while RS is the Readability Score collected from volunteers). - -\begin{table}[H] -\begin{center} -\begin{tabular}{rrrrrr} -\hline -CC & CBO & LCOM & NMD & \dots & RS \\ -\hline -3 & 6 & 34 & 2 & \dots & 4.3 \\ -4 & 5 & 55 & 1 & \dots & 2.4 \\ -3 & 5 & 22 & 0 & \dots & 5.2 \\ -\hline -\end{tabular} -\end{center} -\caption{Example of collected dataset} -\label{tab:table1} -\end{table} - -\textbf{Relations}. -Using ML methods we are going to learn how code metrics, -AST patterns and readability are related. -We are planning to use ML techniques to investigate the importance of features -with respect to the readability and find combinations that have stronger impact. - -\textbf{Locate Code Patterns}. -Finally, for an unseen Java class we can calculate all features except the readability. -Using known features and the knowledge about relations between features we are planning -to give refactoring recommendations and provide links to the lines of code -where most problematic patterns are located. - diff --git a/wp/sections/selection_criteria.tex b/wp/sections/selection_criteria.tex deleted file mode 100644 index abfea3af..00000000 --- a/wp/sections/selection_criteria.tex +++ /dev/null @@ -1,83 +0,0 @@ -There is a number of crucial expectations we have for the -method and the tool under design: - -\textbf{Novelty} is crucial and has a few important aspects: -\begin{enumerate*} -\item -Novelty of the \emph{method} is one the most important values of novelty. -E.g.,~\citet{Akiyama1971AnEO} was the first who -tried to solve defect detection problem using -linear regression as it was mentioned by~\citet{7476771}. -Sometimes authors can use some new idea in the -algorithm, e.g,~\citet{XIAO201917} used convolutional neural network -together with word-embedding and feature-detecting techniques. - -\item -The \emph{effectiveness} of the model is another important -value of novelty. If authors published new model which -is more effective, it means that we can solve a problem -much better. All evaluation measures can be described later. - -\item -Collecting new dataset is one of the most important and hard work in Data Science. -Main results can vary depending on method used when gathering a dataset. -It is necessary to do it in a correct way, since there are many issues related -to data problems like \emph{Outliers}, \emph{Class Imbalance}, \emph{Data shift Problem}, -\emph{High Dimensionality of Data}, etc. mentioned by~\citet{10.1007/s10462-017-9563-5}. -Also, \emph{granularity} is another problem in the -defect detection problem. Defect can be found in a module, -function, line of the code, etc. That is why seems -it is not an easy task to compare the models with a -different level of granularity. -E.g,~\citet{6464273} analyzed five papers published by -IEEE and mentioned that there are some data -quality issues in these papers. -\end{enumerate*} - -\textbf{Evaluation} is the essential of ML. It is impossible -to say whether a model is good or bad, not evaluating it. -A lot of model performance evaluation measures were used -for defects detection, but we can -classify them the following way \citep{10.1007/s10462-017-9563-5, Jiang2008}: -\begin{enumerate*}[label=\arabic*)] -\item \emph{Numeric} performance evaluation measures -are mostly used for defect detection models~\citep{Jiang2008}. -They can include accuracy, F1-score, G-means, specificity, -f-measure, and so on. E.g., they are used by~\citet{6349519}. -\item \emph{Graphical} measures are graphs derived from -the confusion matrix~\citep{Jiang2008}. -They can include ROC curve, precision-recall curve, cost curve etc. -E.g., they are used by~\citet{SHATNAWI20081868}. -\end{enumerate*} - -\textbf{Performance} is another important value for defect detection model. -The selection of the best performance evaluation measure -is not a trivial task. -For example,~\citet{Jiang2008} compared different alternatives -and demonstrated that no single performance evaluation measure is able to evaluate the -performance of a defect prediction model fair enough. The authors also added -that it is better not only to measure model classification performance -(like accuracy, recall, etc.), but to minimize the misclassification cost. -\citet{ARISHOLM20102} also compared different types of measures -and mentioned that it is hard to draw general conclusions about the -best performance evaluation measure. - -Since the tool will be actively used with Continuous Integration (CI), -it must have a reasonable performance: it must predict in a few seconds. -If calculation takes a lot of time, a developer may stop using it. -\citet{humble2010continuous} also mentioned that speed -is very important for CI. The sooner you release the software, -the sooner you get a return on your investment. -Performance is also important because it is necessary -to know whether bugfixes are useful. That is why -we need to minimize the delay between the releases and -thus, accelerate the feedback, as explained by~\citet{humble2010continuous}. - -State-of-the-art papers use Neural Networks (NN) for defect -detection problem since it can give better results~\citep{XIAO201917,10.1145/3360588}. -Training takes a lot of time and demands TPU or GPU resources if we use NN. -Word embedding and other feature-detecting techniques can only increase training time. -E.g., \citet{10.1145/3360588, 8616596} noticed that -the training time matters for defect detection problem and -demonstrates the training time of their models. - diff --git a/wp/sections/threats_to_validity.tex b/wp/sections/threats_to_validity.tex new file mode 100644 index 00000000..ac2bd907 --- /dev/null +++ b/wp/sections/threats_to_validity.tex @@ -0,0 +1,4 @@ +% consider only frequencies not inter location +% not consider context +% top OSS datasets +% quality metrics \ No newline at end of file diff --git a/wp/sections/usage_scenarios.tex b/wp/sections/usage_scenarios.tex new file mode 100644 index 00000000..f3317d06 --- /dev/null +++ b/wp/sections/usage_scenarios.tex @@ -0,0 +1,68 @@ +\subsection{Aibolit Index} + +In addition to the recommendation functionality, we designed a feature to measure the overall quality of developer's source code, \textit{Aibolit Index}. +It is is a single number, with following properties: +\begin{itemize} +\item[(i)] the more patterns are suggested to fix, the higher Aibolit Index; +\item[(ii)] the higher negative impact factor (see Section \ref{sec:recommendation_algorithm}) +of detected patterns the higher Aibolit Index. +\end{itemize} +Therefore, the lower Abolit Index the better the project's code from the point +of view of Aibolit. + +Let $P(C)$ be a set of all patterns Aibolit recommends to fix for Java class $C$. +% As we know from the section ~\ref{sec:recommendation_algorithm}, each +% recommended anti-pattern $p \in P(C)$ has an associated impact factor $I_{p}$ and a count $count(p, C)$. +We define the Aibolit Index $A(C)$ of Java class $C$ as a sum of the products of +impact factors $I_{p}$ and scaled counts $count(p, C)$ for all of the +patterns occurring in the class (Eq.~\ref{eq:aibolit_index}). We use log-scaling for smoothing purposes, because some patterns are a lot more common than others. + + +\begin{equation} + A(C) = \sum_{p \in P(C)} { I_{p}(C) \cdot \ln{(count(p, C) + 1)} } \label{eq:aibolit_index} +\end{equation} + + +The Aibolit Index of a project is defined as average Aibolit Index +across all Java classes in the project. In Table~\ref{table:aibolit_index_repos} +you can see a calculated Aibolit Index of some GitHub Java repositories with +more than 4500 stars. Aibolit Index is supposed to be a convenient instrument +to get a first estimate of the project code's quality. + +\begin{table}[t] +\footnotesize + \begin{tabular}{|l|l|l|l|l|l|l|} + \hline + Repository & Aibolit Index & Total files & Total NCSS & GitHub stars \\ + \hline + ReactiveX\textbackslash RxJava& 6.66& 1493& 25270 & 42972 \\ + bumptech\textbackslash glide& 5.81& 465& 5078 & 29364 \\ + JakeWharton\textbackslash butterknife& 6.31& 74& 935 & 25347 \\ + greenrobot\textbackslash EventBus& 7.48& 51& 651 & 22637 \\ + skylot\textbackslash jadx& 6.69& 602& 12658 & 22602 \\ + alibaba\textbackslash fastjson & 9.97& 144& 20175 & 21891 \\ + alibaba\textbackslash druid & 6.36& 822& 28852 & 21581 \\ + Netflix\textbackslash Hystrix& 6.74& 292& 2920 & 19888 \\ + ReactiveX\textbackslash RxAndroid& 5.47& 9& 59 & 19010 \\ + google\textbackslash gson& 6.87& 160& 2941 & 18084 \\ + square\textbackslash picasso& 6.21& 26& 687 & 17514 \\ + libgdx\textbackslash libgdx & 5.02 & 1981 & 46409 & 17105 \\ + nostra13\textbackslash Android-Universal-Image-Loader& 7.84& 62& 1059 & 16722 \\ + qiurunze123\textbackslash miaosha& 3.57& 197& 841 & 16224 \\ + wuyouzhuguli\textbackslash SpringAll& 13.41& 467& 463 & 15221 \\ + justauth\textbackslash JustAuth& 4.36& 46& 241 & 8916 \\ + heibaiying\textbackslash BigData-Notes& 11.17& 54& 204 & 7166 \\ + crossoverJie\textbackslash cim & 6.70& 96& 574 & 5841 \\ + wildfirechat\textbackslash server& 6.51& 285& 4671 & 5140 \\ + febsteam\textbackslash FEBS-Shiro & 5.66& 90& 453 & 4777 \\ + \hline + \end{tabular} + \centering +\caption{Aibolit Index of some popular Java repositories. \label{table:aibolit_index_repos}} +\end{table} + + + + + + diff --git a/wp/wp.tex b/wp/wp.tex index aa6fcea9..93c1d040 100644 --- a/wp/wp.tex +++ b/wp/wp.tex @@ -1,8 +1,7 @@ -\documentclass[12pt]{article} +\documentclass[10pt]{article} \usepackage{natbib} \usepackage{pgf} - \bibliographystyle{plainnat} - \setcitestyle{citesep={,},aysep={}} +\setcitestyle{citesep={,},aysep={}} \usepackage[colorlinks,citecolor=blue,linkcolor=black,bookmarks=false,hypertexnames=true]{hyperref} \usepackage{url} \usepackage[inline]{enumitem} @@ -12,9 +11,55 @@ \usepackage{graphicx} \usepackage{xcolor} \usepackage{setspace} - \usepackage{enumitem} +\usepackage{caption} +%\usepackage[margin=1.3in]{geometry} +\usepackage{xcolor} +\usepackage[top=1.3in, left=1.4in, includefoot]{geometry} \setlist{nosep} +\usepackage{xcolor} +\usepackage{algorithm} +\usepackage{algpseudocode} +\usepackage{multicol} +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} +\usepackage{charter} +\usepackage{listings} +\usepackage{authblk} + +\definecolor{codegreen}{rgb}{0,0.6,0} +\definecolor{codegray}{rgb}{0.5,0.5,0.5} +\definecolor{codepurple}{rgb}{0.58,0,0.82} +\definecolor{backcolour}{rgb}{0.95,0.95,0.92} + +\lstdefinestyle{mystyle}{ + backgroundcolor=\color{backcolour}, + commentstyle=\color{codegreen}, + keywordstyle=\color{magenta}, + numberstyle=\tiny\color{codegray}, + stringstyle=\color{codepurple}, + basicstyle=\sffamily\footnotesize, + breakatwhitespace=false, + breaklines=true, + captionpos=b, + keepspaces=true, + numbers=left, + numbersep=5pt, + showspaces=false, + showstringspaces=false, + showtabs=false, + tabsize=2 +} + +\lstset{style=mystyle} + + +\newcommand{\pattern}[3]{ + {\bf #2. #1} \\ + {\it Description:} #3 \\ +} + +\newcommand{\todo}{\textcolor{red}{\textbf{TODO}}} \setstretch{1.1} \setlength{\bibsep}{0.0pt} @@ -30,88 +75,65 @@ \renewcommand*{\bibfont}{\footnotesize} \title{ - \includegraphics[height=48pt]{logo}\\ - \textsc{Aibolit}:\\ - Style Checking\\ + \includegraphics[height=100pt]{logo.png}\\ + \vspace{10pt} + \textsc{Aibolit:}\\ + Static Analysis Using Machine Learning} +\author{Yegor Bugayenko, Anton Cheshkov, Ekaterina Garmash, Andrey Gusev, Yaroslav Kishchenko, Pavel Lukyanov, Evgeny Maslov, Vitaly Protasov} +\affil{Huawei Technologies \\ + System Programming Lab, Russian Research Institute, Moscow} + \begin{document} \maketitle +\pagebreak + \begin{abstract} -Quality of code is crucial for the stability and robustness -of software systems. Defect detection at early stages of -software development lifecycle is the cheapest and the easiest -way to increase the quality of code. There are well-known -instruments such as static analyzers and linters, which are -actively used by programmers. However, none of them use Machine -Learning (ML) to detect defects more effectively. -We managed to create such an instrument and empirically demonstrate -its effectiveness\footnote{This is statement is yet to be confirmed}. + +Aibolit is a next generation static analyzer powered by machine learning. +Aibolit gives recommendations to developers to avoid specific software patterns +in order to improve quality of the source code. Aibolit can be extended by adding +custom patterns and quality metrics of choice. In this paper, we explain +how Aibolit works and how it differs from other static analyzers. + + \end{abstract} \pagebreak \section{Introduction} +\label{sec:intro} \input{sections/introduction} -\section{Related Work} + +\section{Software quality and patterns} \label{sec:related} \input{sections/related_work} -\section{Categories of Methods} -\label{sec:categories} -\input{sections/considered} - -\section{Available data} -\label{sec:data} -\input{sections/available_data} - -\section{Selection Criteria} -\label{sec:criteria} -\input{sections/selection_criteria} - -\section{The Method} -\label{sec:method} -\input{sections/selected_task} - -\section{Risks} -\label{sec:risks} -\input{sections/risks} +\section{How the Aibolit recommender works} +\label{sec:how_aibolit_works} +\input{sections/how_aibolit_works} -% \section{Implementation Details} -% \label{sec:implementation} -% \input{sections/implementation} +\section{Other usage scenarios} +\label{sec:usage_scenarios} +\input{sections/pattern_emp_analysis} +\input{sections/usage_scenarios} -\section{Empirical Results} -\label{sec:results} -\input{sections/empirical_results} +\section{Conclusion \& Future Work} +\label{sec:conclusion} +\input{sections/conclusion} -\section{Conclusion} -We will write this section later. -\section{Future Work} -We will write this later. - -\section{Acknowledgements} -The tool was designed in System Programming Lab. Many thanks -to the contribution of (in alphabetic order of the last name): -Yegor Bugayenko, -Anton Cheshkov, -Vadim Chibiriev, -Lu Jianhua, -Evgeny Maslov, -Yu Jiayuan, -Alexey Zorchenkov. - -%\section{Notes} -%\input{sections/notes} +\section{Appendix} +\label{sec:appendix} +\input{sections/appendix} +\bibliographystyle{apa} \bibliography{references} - - \end{document}