35
U NDERSTANDING S OURCE C ODE D IFFERENCES BY S EPARATING R EFACTORING E FFECTS *Sirinut Thangthumachit , Shinpei Hayashi, Motoshi Saeki Tokyo Institute of Technology, Japan

Understanding Source Code Differences by Separating Refactoring Effects

Embed Size (px)

Citation preview

UNDERSTANDING SOURCE CODE DIFFERENCES BY SEPARATING REFACTORING EFFECTS

*Sirinut Thangthumachit, Shinpei Hayashi, Motoshi Saeki Tokyo Institute of Technology, Japan

Motivation • Source code differences

• Comparing and reading the differences of old and new versions of source code

• Refactoring complicates differences[1,2] • Refactoring: the technique to restructuring source code

that will not change program’s behavior •  makes large amount of differences •  shows same differences multiple times •  hides other changes’ differences

2

[1] K. Prete et al, “Template-based reconstruction of complex refactorings” , ICSM2010. [2] Weißgerber et al, “Identifying refactoring from source-code changes” , ASE2006.

Source Code Differences

3

public ThreadPoolRxTaskPool (int …

RED: deleted code BLUE: added code

Apache Tomcat 6.0.4 – 6.0.5

4 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } } protected void setupThread(WorkerThread threadconfigureTask(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task.getClass ().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

5 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

6 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

Delete ‘for-loop’

7 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

Delete ‘for-loop’

Class ‘ThreadPool’ → ‘RxTaskPool’

8 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

Delete ‘for-loop’

Class ‘ThreadPool’ → ‘RxTaskPool’ Parameter ‘maxThreads’ → ‘maxTasks’

9 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

Delete ‘for-loop’

Class ‘ThreadPool’ → ‘RxTaskPool’ Parameter ‘maxThreads’ → ‘maxTasks’

4 more refactorings

10 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCr eator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } }

Delete ‘for-loop’ Refactorings

Apache Tomcat 6.0.4 – 6.0.5

11 Example

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } } protected void setupThread(WorkerThread threadconfigureTask(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task.getClass ().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

12 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

13 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

Comment Out

14 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

Comment Out

Method ‘setupThread’ → ‘configureTask’

15 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

Comment Out

Method ‘setupThread’ → ‘configureTask’ Parameter ‘thread’ → ‘task’

16 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

Comment Out

Method ‘setupThread’ → ‘configureTask’ Parameter ‘thread’ → ‘task’

2 more refactorings

17 Example

protected void setupThread(WorkerThread threadconfigure Task(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task. getClass().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } }

Comment Out Refactorings

Basic Ideas

• Developer knows refactoring well •  ‘ThreadPool’ was renamed to ‘RxTaskPool’

• → It is no need to read refactorings in source code differences •  ThreadPoolRxTaskPool

• → Extract & Eliminate Refactorings • Source code differences without refactoring

• → Show refactoring information to user

18

Separating Refactorings 19

‘ThreadPool’ → ‘RxTaskPool’ ‘setupThread’ → ‘configureTask’ and 8 more.

public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxTasks; i++) { //temporary fix for thread hand off problem AbstractRxTask thread = creator.createRxTask(); configureTask(thread); idle.add (thread); } } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); try {Thread.wait(500); }catch ( InterruptedException x ) {} } }

Separating Refactorings 20

‘ThreadPool’ → ‘RxTaskPool’ ‘setupThread’ → ‘configureTask’ and 8 more.

public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxTasks; i++) { //temporary fix for thread hand off problem AbstractRxTask thread = creator.createRxTask(); configureTask(thread); idle.add (thread); } } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); try {Thread.wait(500); }catch ( InterruptedException x ) {} } }

public ThreadPool (int maxThreads, int minThreads, ThreadCreatorRxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxThreads = maxThreadsmaxTasks = maxTasks; this.minThreads = minThreadsminTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxThreads; i++) { //temporary fix for thread hand off problem WorkerThread thread = creator.getWorkerThread(); setupThread(thread); idle.add (thread); } } protected void setupThread(WorkerThread threadconfigureTask(AbstractRxTask task) { synchronized (threadtask) { thread.setPooltask.setTaskPool(this); thread.setName(thread// task.setName(task.getClass ().getName() + "[" + inc() + "]"); thread// task.setDaemon(true); thread// task.setPriority(Thread.MAX_PRIORITY); thread// task.start(); try {thread.wait(500); }catch ( InterruptedException x ) {} } } With Refactorings Without Refactorings

Separating Refactorings 21

‘ThreadPool’ → ‘RxTaskPool’ ‘setupThread’ → ‘configureTask’ and 8 more.

public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxTasks; i++) { //temporary fix for thread hand off problem AbstractRxTask thread = creator.createRxTask(); configureTask(thread); idle.add (thread); } } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); try {Thread.wait(500); }catch ( InterruptedException x ) {} } }

Delete 'for-loop'

Separating Refactorings 22

‘ThreadPool’ → ‘RxTaskPool’ ‘setupThread’ → ‘configureTask’ and 8 more.

public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxTasks; i++) { //temporary fix for thread hand off problem AbstractRxTask thread = creator.createRxTask(); configureTask(thread); idle.add (thread); } } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); try {Thread.wait(500); }catch ( InterruptedException x ) {} } }

Delete 'for-loop' Comment out

Separating Refactorings 23

‘ThreadPool’ → ‘RxTaskPool’ ‘setupThread’ → ‘configureTask’ and 8 more.

public RxTaskPool (int maxTasks, int minTasks, TaskCreator creator) throws Exception { // fill up the pool with worker threads this.maxTasks = maxTasks; this.minTasks = minTasks; this.creator = creator; //for (int i = 0; i < minThreads; i++) { for (int i = 0; i < maxTasks; i++) { //temporary fix for thread hand off problem AbstractRxTask thread = creator.createRxTask(); configureTask(thread); idle.add (thread); } } protected void configureTask(AbstractRxTask task) { synchronized (task) { task.setTaskPool(this); // task.setName(task.getClass().getName() + "[" + inc() + "]"); // task.setDaemon(true); // task.setPriority(Thread.MAX_PRIORITY); // task.start(); try {Thread.wait(500); }catch ( InterruptedException x ) {} } }

Delete 'for-loop' Comment out

Delete 'try&catch'

Approach

24

Old New Modified

Old New

Old version of source code New version of source code Source code differences refactoring

New

Old

Overview of the proposed technique

25

Comparing Source Code

Ordered Listof Refactorings

Source Code Differences

without Refactoring

Outputs

New Ver.

Old Ver.

Inputs

Separating Refactorings

Overview of the proposed technique

26

Extracting Refactorings

Ordered List of Refactorings

Output 1

Applying "Refactorings

Output 2

Old Ver.

Input 1

New Ver. Input 2

ModifiedVer.

Overview of the proposed technique

27

Comparing Source Code

Ordered Listof Refactorings

Source Code Differences

without Refactoring

Outputs

New

Old

Inputs

File Class Method"

Field Local Package

28

Supporting tool

Extraction Application

Rename packages, files, classes, interfaces,

enums, methods all elements

Move files, methods files, methods

Extract - methods

• Refactoring Extraction • Automatical extraction • External Input

• Refactoring Application • Automatically apply by using Eclipse Refactoring

Browser

• Application on OSS • Can extracted refactorings be applied? • Can separating refactorings reduce the amount of source

code differences?

• Human Subject Study • With approach, can subjects understand more changes in

the same limited time? • Does the approach satisfy subjects?

29

Evaluations

• Target projects • OW2 Carol 1.0.1-1.8.5 (30 pairs)

• Result •  Tool found refactorings in 5 pairs

•  1.0.1–1.3.0, 1.4.0–1.4.2, 1.5.2–1.5.3, 1.5.6–1.5.7, 1.5.8–1.6.

• Refactorings application

• → All real refactorings were applied successfully 30

Evaluation 1 (Application on OSS)

Found Successfully applied

Detected Refactorings 21 18

False 5 2

True 16 16

• The amount of source code differences

 → Approach reduced more than 21% • Can extracted refactorings be applied?

•  → Yes • Can separating refactorings reduce the amount of source

code differences? •  → Yes

31

Changed lines

WO: without approach 18,721 (100%) A: with approach 14,624 (78.12%) WO - A 4,097 (21.88%)

Evaluation 1

• Procedure •  Let subjects read the source code differences with and

without our approach. • Ask them to answer what was changed between the

versions • Evaluate by time and changes found

• Target Projects • OW2 Carol 1.5.6-1.5.7 • Apache Tomcat 6.0.4-6.0.5

32

Evaluation 2 (Human Subject)

• Subjects

• Result

• → Approach made 32% higher efficiency

Changes found

Time (minute)

Efficiency (changes found/ time)

average w/o Approach 28.3 112.75 0.25 (100%)

Approach 39.25 120 0.33 (132%)

Evaluation 2

Subjects A B C D Carol Approach w/o Approach Approach w/o approach

Tomcat w/o Approach Approach w/o Approach Approach

33

• Questionnaires • All subjects agreed that our approach is useful

•  Especially, renaming class.

• With approach, can subjects understand more changes in the same limited time? •  → Yes

• Does the approach satisfy subjects? •  → Yes

Evaluation 2

34

• Understanding source code differences by separating refactorings effects •  Separating refactorings •  Implemented supporting tool

•  Rename + Move refactorings •  Evaluations

•  Approach is applicable to OSS •  Separating refactorings helps understanding differences

• Future Works • Better tool

•  Support more refactoring types 35

Conclusion