## 4 Methodology
### Data Pre-Processing  
In order to decompose a monolithic application into microservices, we collect three different kinds of data: dependency graph, entrypoint existence matrix, and entrypoint co-existence matrix. The dependency graph is a matrix that shows all the classes that a particular class is dependent upon. In the context of this paper, an entrypoint refers to any class that initiates interaction with the application. In our case, entrypoints can be either an Application Programming Interface (API) endpoint or a message queue listener. The entrypoint existence matrix indicates which classes are present in at least one path initiated by a specific entrypoint. Let us denote the entrypoint existence matrix with \(E\), then \(E_{ij}\) is set to one when _class_\(i\) is present in at least one path initiated by entrypoint \(j\). Finally, the entrypoint co-existence matrix indicates the frequency with which two classes co-exist in the same paths initiated by the same entrypoints. Let us denote the co-existence matrix with \(Co\), then \(Co_{ij}\) refers to the number of paths where _class_\(i\) and _class_\(j\) co-exist in the same entrypoints. By collecting and utilizing these three types of data, we can effectively train the machine learning model to decompose the monolithic application into microservices.  
For the purpose of collecting these data, we first generate an Abstract Syntax Tree (AST) of the monolithic application. After obtaining the AST of our code, we extract important information from it. To create the dependency graph for a specific class, we begin by retrieving a list of all the classes that it had imported. From this list, we then filter out any classes that were imported from external libraries and only include those classes that were within the project's root package. This allows us to generate a more accurate and relevant dependency graph for the class in question. To generate the entrypoint existence matrix (\(E\)) for a particular class \(i\), we use a depth-first search (DFS) algorithm on the dependency graph, starting from entrypoint \(j\) as the root. During the DFS, if we encounter class \(i\) at any point, we mark \(E_{ij}\) as one. Similarly, to generate the entrypoint co-existence matrix (\(Co\)), we perform DFS on the dependency graph and list all the paths that were initiated by the entrypoints. We then check for the existence of both class \(i\) and class \(j\) in these paths and set \(Co_{ij}\) to the number of paths where these classes co-exist. Finally, we create a feature matrix \(\widehat{X}\) as follows:  
\[\widehat{X}=E\odot Co \tag{4}\]  
where \(\odot\) is the concatenation operation. Hence, from \(|P|+|C|\), we know that the size of \(\widehat{X}\) is \(|C|\) where \(C\) is the number of classes and \(P\) is the set of entrypoints. Finally, using the  
Figure 1: Flow of our approach.  
graph convolutional network (GCN), we normalize \(\hat{X}\) according to the adjacency classes in the graph by  
\[X=\tilde{D}^{-\frac{1}{2}}\tilde{A}\tilde{D}^{-\frac{1}{2}}\hat{X} \tag{5}\]  
where \(\tilde{A}=A+I\), \(I\) is the identity matrix, \(\tilde{D}\) is the degree diagonal matrix, and \(\tilde{D}_{ii}=\sum_{j\in\mathbb{C}}\tilde{A}_{ij}\).