출처: https://docs.github.com/ko/copilot/using-github-copilot/example-use-cases/refactoring-code-with-github-copilot 

(DeepL 번역)

Copilot 인공 지능을 활용하여 코드를 빠르고 효과적으로 리팩터링하세요.

이 문서의 내용

소개

코드 리팩터링은 기존 코드의 동작을 변경하지 않고 재구성하는 프로세스입니다. 리팩터링의 장점은 코드 가독성 향상, 복잡성 감소, 코드 유지 관리 용이성, 새로운 기능 추가 용이성 등을 들 수 있습니다.

이 문서에서는 Copilot을 사용하여 IDE에서 코드를 리팩터링 하는 몇 가지 아이디어를 제공합니다.

참고

이 문서에는 예시 응답이 포함되어 있습니다. GitHub Copilot Chat에서는 여기에 표시된 것과 다른 응답을 받을 수 있습니다.

코드 이해하기

기존 코드를 수정하기 전에 그 코드의 목적과 현재 작동 방식을 이해해야 합니다. 코파일럿이 이를 도와드릴 수 있습니다.

비효율적인 코드 최적화하기

Copilot은 코드를 더 빠르게 실행하는 등 코드를 최적화하는 데 도움을 줄 수 있습니다.

예시 코드

아래 두 섹션에서는 다음 예제 bash 스크립트를 사용하여 비효율적인 코드를 최적화하는 방법을 보여 드리겠습니다:

#!/bin/bash

#
 Find all .txt files and count lines in each
for file in $(find . -type f -name "*.txt"); do
   wc -l "$file"
done

코파일럿 채팅 패널 사용

Copilot은 예제 bash 스크립트와 같은 코드가 최적화될 수 있는지 여부를 알려줍니다.

코파일럿 인라인 채팅 사용

또는 예제 bash 스크립트와 같은 기존 코드가 비효율적이라는 것을 이미 알고 있는 경우:

모든 Copilot 제안과 마찬가지로 수정된 코드가 오류 없이 실행되고 올바른 결과를 생성하는지 항상 확인해야 합니다.

반복되는 코드 정리하기

반복을 피하면 코드를 수정하고 디버깅하기가 더 쉬워집니다. 예를 들어 파일 내 여러 위치에서 동일한 계산이 두 번 이상 수행되는 경우 계산을 함수로 옮길 수 있습니다.

다음의 매우 간단한 JavaScript 예제에서는 동일한 계산(아이템 가격에 판매된 아이템 수를 곱한 값)이 두 위치에서 수행됩니다.

let totalSales = 0;

let applePrice = 3;
let applesSold = 100;

totalSales += applePrice * applesSold;
let orangePrice = 5;

let orangesSold = 50;
totalSales += orangePrice * orangesSold;
console.log(`Total: ${totalSales}`);

Copilot에 반복 계산을 함수로 이동하도록 요청할 수 있습니다.

유형:  반복 계산을 함수로 이동 이라고 하고 입력을 누릅니다.
코파일럿이 수정된 코드를 제안합니다. 예를 들어

function calculateSales(price, quantity) {
 
return price * quantity;
}

let totalSales = 0;

let applePrice = 3;
let applesSold = 100;
totalSales += calculateSales(applePrice, applesSold);

let orangePrice = 5;
let orangesSold = 50;
totalSales += calculateSales(orangePrice, orangesSold);

console.log(`Total: ${totalSales}`);


모든 Copilot 제안과 마찬가지로 수정된 코드가 오류 없이 실행되고 올바른 결과를 생성하는지 항상 확인해야 합니다.

코드를 더 간결하게 만들기

코드가 불필요하게 장황하면 읽고 유지 관리하기 어려울 수 있습니다. 코파일럿은 선택한 코드의 보다 간결한 버전을 제안할 수 있습니다.

다음 예제에서는 직사각형과 원의 면적을 출력하는 Python 코드이지만 더 간결하게 작성할 수 있습니다:

def calculate_area_of_rectangle(length, width):

    area = length * width

    return area

def calculate_area_of_circle(radius):

    import math

    area = math.pi * (radius ** 2)

    return area

length_of_rectangle = 10

width_of_rectangle = 5

area_of_rectangle = calculate_area_of_rectangle(length_of_rectangle, width_of_rectangle)

print(f"Area of rectangle: {area_of_rectangle}")

radius_of_circle = 7

area_of_circle = calculate_area_of_circle(radius_of_circle)

print(f"Area of circle: {area_of_circle}")

입력합니다: 더 간결하게 작성 이라고 하고 입력을 누릅니다.

코파일럿이 수정된 코드를 제안합니다. 예를 들어

import math

def calculate_area_of_rectangle(length, width):
 
return length * width

def calculate_area_of_circle(radius):
 
return math.pi * (radius ** 2)

print(
f"Area of rectangle: {calculate_area_of_rectangle(10, 5)}")
print(
f"Area of circle: {calculate_area_of_circle(7)}")


Copilot의 제안을 평가하고 변경에 동의하면 수락합니다:

모든 Copilot 제안과 마찬가지로 수정된 코드가 오류 없이 실행되고 올바른 결과를 생성하는지 항상 확인해야 합니다.

복잡한 코드 단위 나누기

여러 작업을 수행하는 큰 메서드나 함수는 특정 작업 수행에 초점을 맞춘 작고 단순한 함수보다 재사용 기회가 적을 가능성이 높습니다. 또한 이해하고 디버깅하기가 더 어려울 수도 있습니다.

코파일럿을 사용하면 복잡한 코드 블록을 재사용하기에 더 적합한 작은 단위로 분할할 수 있습니다.

다음 Python 코드는 매우 간단한 예시이지만 단일 함수를 특정 작업을 수행하는 두 개의 함수로 분할하는 원리를 보여줍니다.

import pandas as pd
from pandas.io.formats.style import Styler

def process_data(item, price):
   
# Cleanse data
   item = item.strip()  
# Strip whitespace from item
   price = price.strip()  
# Strip whitespace from price
   price = float(price)
# Convert price to a float
   
# More cleansing operations here

   
# Create and print a DataFrame
   data = {
'Item': [item], 'Price': [price]}
   df = pd.DataFrame(data)
   print(df.to_string(index=
False))

# Example usage
item =
"   Apple "
price =
" 1.25"
process_data(item, price)

process_data 함수를 분할하려면 다음과 같이 하세요:

유형: 데이터 정리용과 인쇄용의 두 가지 기능으로 분리 라고 하고 입력을 누릅니다.

코파일럿이 수정된 코드를 제안합니다. 예를 들어

def cleanse_data(item, price):
 
# Cleanse data
 item = item.strip()  
# Strip whitespace from item
 price = price.strip()  
# Strip whitespace from price
 price = float(price)  
# Convert price to a float
 
return item, price

def print_data(item, price):
 
# Create and print a DataFrame
 data = {
'Item': [item], 'Price': [price]}
 df = pd.DataFrame(data)
 print(df.to_string(index=
False))

def process_data(item, price):
 item, price = cleanse_data(item, price)
 print_data(item, price)

Copilot의 제안을 평가하고 변경에 동의하는 경우 다음과 같이 변경하세요:

모든 Copilot 제안과 마찬가지로 수정된 코드가 오류 없이 실행되고 올바른 결과를 생성하는지 항상 확인해야 합니다.

가독성을 높이기 위해 조건부 코드 다시 작성하기

다양한 조건에 따라 실행되거나 실행되지 않는 코드를 작성하는 방법에는 여러 가지가 있습니다. 일부 조건 구조는 특정 사용 사례에 다른 조건 구조보다 더 적합하며, 대체 조건 구조를 선택하면 코드를 더 쉽게 읽을 수 있는 경우도 있습니다.

이 Java 메서드는 일련의 if 및 else if 문을 사용하여 수행해야 할 연산을 결정합니다:

public String getSound(String animal) {
 
if (animal == null) {
     System.out.println(
"Oops! A null animal?");
 }
else if (animal.equalsIgnoreCase("Dog")) {
     
return "Bark";
 }
else if ( animal.equalsIgnoreCase("Cat")) {
     
return "Meow";
 }
else if ( animal.equalsIgnoreCase("Bird")) {
     
return "Tweet";
 }
 
return "Unknown";
}

동일한 로직을 적용하려면 switch 문을 사용하는 것이 더 나은 방법일 수 있습니다.

코파일럿이 수정된 코드를 제안합니다. 예를 들어

/**
* Retrieves the sound made by a given animal.
*
* @param animal The name of the animal.
* @
return The sound made by the animal, or "Unknown" if the animal is not recognized.
*/
public String getAnimalSound(String animal) {
   
return switch (animal) {
       case null -> {
           System.out.println(
"Oops! A null animal?");
           
yield "Unknown";
       }
       case String a when a.equalsIgnoreCase(
"Dog") -> "Bark";
       case String a when a.equalsIgnoreCase(
"Cat") -> "Meow";
       case String a when a.equalsIgnoreCase(
"Bird") -> "Tweet";
       default ->
"Unknown";
   };
}

다른 구조를 사용하도록 코드 서식 변경

JavaScript에 이 함수가 있다고 가정해 보겠습니다:

function listRepos(o, p) {
return fetch(`https://api.github.com/orgs/${o}/repos?per_page=${parseInt(p)}`)
  .then((response) => response.json())
  .then( (data) => data);
}

코딩 표준에 따라 함수에 화살표 표기법을 사용하고 매개변수에 설명이 포함된 이름을 사용해야 하는 경우 Copilot을 사용하여 이러한 변경을 수행할 수 있습니다.

const listRepos = (org, perPage) => {
 
return fetch(`https://api.github.com/orgs/${org}/repos?per_page=${parseInt(perPage)}`)
   .then(response => response.json())
   .then(data => data);
};

심볼 이름 개선하기

참고

이름을 잘 선택하면 코드를 더 쉽게 유지 관리할 수 있습니다. VS Code 및 Visual Studio의 Copilot은 변수나 함수 등의 심볼에 대한 대체 이름을 제안할 수 있습니다.