Introdução
Migrar um projeto para uma nova linguagem de programação pode ser uma tarefa difícil e demorada. O GitHub Copilot pode ajudar você nesse processo explicando as alterações que você precisa fazer e sugerindo código de substituição na nova linguagem.
Princípios da migração de um projeto para uma nova linguagem
Considere estes pontos antes de iniciar um processo de migração:
-
Conhecimento sobre codificação
Certifique-se de ter uma boa compreensão das duas linguagens de programação. Embora o Copilot possa traduzir código, você precisa entender as opções que ele propõe e decidir se deseja usar as sugestões dele ou solicitar uma sugestão alternativa.
-
Conhecimento sobre o sistema que você está migrando
Certifique-se de entender a arquitetura e a lógica do sistema atual, além da funcionalidade e dos recursos que ele fornece aos usuários. Você precisa ser capaz de verificar se o código traduzido executa todas as mesmas operações que o código original e produz os mesmos resultados.
-
Use IA para obter ajuda
Se você não entender uma parte específica do código que está prestes a traduzir, use o recurso "explain" do Copilot, no arquivo inteiro ou em uma parte selecionada do código em um arquivo. Confira Fazendo perguntas ao GitHub Copilot em seu IDE.
-
Reserve tempo para concluir a migração
A conversão é um processo de várias fases. Quanto maior o projeto que estiver convertendo, maior será o número de etapas que você precisará executar. Reserve bastante tempo para concluir todo o processo.
-
Trabalhe iterativamente
Tenha como objetivo converter partes diferentes do projeto separadamente. Certifique-se de ter verificado todas as alterações feitas antes de passar para outra parte do projeto. Escreva testes para as partes individuais do projeto à medida que você prosseguir para confirmar que cada um dos novos componentes funciona conforme o esperado.
-
Evite introduzir complexidade ao processo
Inicialmente, tente fazer uma conversão para algo semelhante. Isso não será possível para todo o código no projeto. No entanto, para evitar adicionar complexidade à tarefa de migração, tente limitar o número de novas alterações introduzidas, além de traduzir o código e usar uma nova estrutura e as dependências apropriadas.
-
Estabeleça um parâmetro de comparação e refatore o código traduzido
Depois de concluir a conversão inicial e ter um sistema em funcionamento, você poderá estabelecer o parâmetro de comparação para comparar os sistemas antigo e novo. Você pode refatorar o código na nova linguagem. Essa é uma oportunidade para otimizar o código e reduzir a dívida técnica.
Usando o Copilot para ajudar você a migrar um projeto para uma nova linguagem
Supondo que você já tenha se familiarizado com o projeto existente, uma boa maneira de iniciar uma migração é abrir um branch do repositório no editor e pedir ajuda ao Copilot.
-
No editor, abra o painel do Copilot Chat. Confira Fazendo perguntas ao GitHub Copilot em seu IDE.
-
Peça para o Copilot descrever as etapas necessárias para migrar o projeto para a nova linguagem.
Por exemplo, para uma migração de PHP para Python, você pode perguntar:
@workspace I want to migrate this project from PHP to Python. Give me a high level overview of the steps I need to take. Don't go into detail at this stage.
Note
O participante do chat
@workspace
define os arquivos no workspace atual como o contexto da pergunta que você faz.O Copilot normalmente retornará uma lista de etapas que você precisa executar para migrar o projeto.
-
Copie e salve a resposta do Copilot em algum lugar para consultá-la durante o processo.
-
Trabalhe em cada etapa do processo, solicitando ajuda detalhada do Copilot conforme necessário.
Considere atentamente cada sugestão do Copilot. Certifique-se de entender o código que ele está sugerindo e avaliar se ele é adequado para seu projeto. Se não tiver certeza, peça que o Copilot explique o código para você.
Se você achar que uma alteração sugerida pelo Copilot não está certa de alguma maneira, peça uma sugestão alternativa.
-
Assim que migrar um componente para um estado que pode ser executado, verifique se ele funciona conforme o esperado. Se ele gerar um erro, copie o erro para a exibição do Copilot Chat e peça que o Copilot ajude a corrigi-lo.
-
Depois de concluir a conversão inicial, use o Copilot para ajudar você a refatorar o código no novo idioma. Para saber mais, confira Refatoração de código com o GitHub Copilot.
Exemplo: migrar um projeto PHP para Python
O exemplo a seguir descreve a migração de um aplicativo Web simples de PHP para Python. Mesmo que essas não sejam as linguagens de programação que você está usando para a migração, talvez seja útil acompanhar as etapas descritas aqui para se familiarizar com uma migração de projeto. As etapas serão semelhantes para migrar outros pequenos projetos de uma linguagem para outra.
Este exemplo pressupõe que:
- Você está trabalhando no Visual Studio Code.
- Você tem as duas linguagens instaladas: PHP e Python versão 3.12 ou posterior.
Migrando um projeto de site simples
Vamos migrar o código neste repositório público no GitHub: docs/simple-php-website.
O repositório é composto pelos arquivos a seguir.
.gitignore
.htaccess
LICENSE
content
├── 404.phtml
├── about-us.phtml
├── contact.phtml
├── home.phtml
└── products.phtml
includes
├── config.php
└── functions.php
index.php
readme.md
template
├── style.css
└── template.php
Este exemplo fornece os prompts que você pode inserir no Copilot Chat para concluir a migração, bem como as respostas que o Copilot retornou para uma instância dessa migração. As respostas do Copilot Chat são não determinísticas, portanto, você receberá respostas ligeiramente diferentes das mostradas aqui.
Durante um processo de migração, é provável que você receba erros que precisa corrigir antes de avançar. O Copilot pode ajudar você a entendê-lo. O exemplo inclui alguns erros e mostra como você pode fazer com que o Copilot ajude a corrigi-los.
Como as respostas que você obterá do Copilot Chat provavelmente serão diferentes das mostradas aqui, você poderá encontrar erros diferentes. Sendo assim, talvez você ache mais fácil percorrer essa migração de exemplo usando as respostas mostradas aqui, em vez das que receber do Copilot.
Depois de concluir esta migração de exemplo, você poderá usar a mesma metodologia em seu projeto.
-
Comece clonando uma cópia do repositório para o computador local.
-
Execute o aplicativo para verificar se ele funciona.
Para fazer isso, em um terminal, navegue até a raiz do repositório clonado e execute o seguinte comando:
Shell php -S localhost:8000
php -S localhost:8000
Em um navegador, acesse: http://localhost:8000.
-
Clique nas opções do site para conhecê-lo melhor, para que você possa verificar se a migração foi bem-sucedida.
-
Crie um branch de trabalho em seu repositório e abra-o como um novo workspace no Visual Studio Code.
-
Familiarize-se com o conteúdo e a arquitetura do projeto existente. O Copilot pode ajudar você com o seguinte:
-
Abra a exibição do Copilot Chat.
-
Insira um prompt, como:
@workspace Describe this project in detail, explaining what the various components do and how they interact.
-
-
Peça ao Copilot uma visão geral de alto nível do processo de migração:
@workspace I want to migrate this project from PHP to Python. Give me a high level overview of the steps I need to take. Don't go into detail at this stage.
O Copilot responderá com instruções como:
To migrate this project from PHP to Python, follow these high-level steps: 1. Set Up Python Environment: - Install Python and set up a virtual environment. - Install necessary packages (e.g., Flask for web framework). 2. Convert Configuration: - Translate the configuration settings from config.php to a Python configuration file. 3. Rewrite Functions: - Convert PHP functions in functions.php to Python functions. 4. Create Flask Application: - Set up a Flask application to handle routing and views. - Map the routes to corresponding views. 5. Convert Templates: - Translate template.php to a Jinja2 template. - Update the CSS file path in the template. 6. Convert Content Pages: - Convert .phtml content files to HTML or Jinja2 templates. 7. Update .htaccess Rules: - Translate .htaccess rewrite rules to Flask route handling. 8. Run and Test: - Run the Flask application and test all routes and functionalities. - Ensure the site works as expected and fix any issues. 9. Documentation: - Update the readme.md with new instructions for running the Python project.
-
Copie e salve a resposta do Copilot em algum lugar para consultá-la durante o restante deste processo. Você trabalhará em cada uma dessas etapas, solicitando ajuda do Copilot à medida que prosseguir.
-
Se você ainda não decidiu qual estrutura do Python deseja usar, poderá pedir orientações do Copilot:
@workspace What Python frameworks can I use for this project once it is migrated to Python? Give me a selection of options, with a brief summary of the pros and cons of each in relation to this website project. Which framework would you recommend?
O Copilot responde com informações sobre várias estruturas e conclui:
For a project like yours - which is a simple, content-driven website - Flask is highly recommended. Its simplicity, flexibility, and ease of use (especially with its templating system that can easily replace your current PHP template structure) make it a great fit.
Vamos seguir o conselho do Copilot e usar o Flask.
-
Voltando à visão geral de alto nível do Copilot, a primeira etapa é configurar um ambiente Python e instalar os pacotes necessários. Para descobrir como fazer isso, no Copilot Chat, insira:
@workspace I want to use Flask. Tell me how to set up a virtual environment and install the necessary packages.
O Copilot responderá com instruções como:
1. Create a virtual environment: - Open a terminal and navigate to your project directory. - Run the following command to create a virtual environment: python3 -m venv venv 2. Activate the virtual environment: - On macOS and Linux: source venv/bin/activate - On Windows: venv\Scripts\activate 3. Install Flask and necessary packages: - With the virtual environment activated, run the following command to install Flask and other necessary packages: pip install Flask 4. Verify the installation: - You can verify that Flask is installed by running: pip list
-
Siga as instruções do Copilot e use
pip list
para verificar se o Flask está instalado. -
Voltando à visão geral do Copilot do processo de migração, a próxima etapa é converter a configuração. Peça ajuda com isso ao Copilot. Por exemplo:
@workspace As the first step in migrating this project from PHP to Python, create a Python configuration file by converting the functions in functions.php to Python functions. Tell me where to locate the Python config file in the project.
O Copilot sugere que você crie um arquivo chamado
config.py
no diretórioincludes
, contendo o código a seguir.Python config = { 'name': 'Simple Python Website', 'site_url': '', 'pretty_uri': False, 'nav_menu': { '': 'Home', 'about-us': 'About Us', 'products': 'Products', 'contact': 'Contact', }, 'template_path': 'template', 'content_path': 'content', 'version': 'v3.1', } def get_config(key=''): return config.get(key, None) def site_name(): return get_config('name') def site_url(): return get_config('site_url') def site_version(): return get_config('version') def nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) def page_title(): page = request.args.get('page', 'Home') return ' '.join(word.capitalize() for word in page.split('-')) def page_content(): page = request.args.get('page', 'home') path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def init(): template_path = os.path.join(get_config('template_path'), 'template.html') with open(template_path, 'r') as file: return file.read()
config = { 'name': 'Simple Python Website', 'site_url': '', 'pretty_uri': False, 'nav_menu': { '': 'Home', 'about-us': 'About Us', 'products': 'Products', 'contact': 'Contact', }, 'template_path': 'template', 'content_path': 'content', 'version': 'v3.1', } def get_config(key=''): return config.get(key, None) def site_name(): return get_config('name') def site_url(): return get_config('site_url') def site_version(): return get_config('version') def nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) def page_title(): page = request.args.get('page', 'Home') return ' '.join(word.capitalize() for word in page.split('-')) def page_content(): page = request.args.get('page', 'home') path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def init(): template_path = os.path.join(get_config('template_path'), 'template.html') with open(template_path, 'r') as file: return file.read()
-
Crie o arquivo
includes/config.py
e exclua o arquivoincludes/config.php
existente. -
Voltando à visão geral novamente, peça ao Copilot para ajudar você a reescrever as funções PHP.
@workspace Continuing the migration of this project from PHP to Python, create Python functions to replace the existing PHP functions. Tell me where to locate the Python functions in the project.
O Copilot sugere que você crie um arquivo chamado
functions.py
no diretórioincludes
, contendo o código a seguir.Python import os from flask import request from .config import get_config def site_name(): return get_config('name') def site_url(): return get_config('site_url') def site_version(): return get_config('version') def nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) def page_title(): page = request.args.get('page', 'Home') return ' '.join(word.capitalize() for word in page.split('-')) def page_content(): page = request.args.get('page', 'home') path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def init(): template_path = os.path.join(get_config('template_path'), 'template.html') with open(template_path, 'r') as file: return file.read()
import os from flask import request from .config import get_config def site_name(): return get_config('name') def site_url(): return get_config('site_url') def site_version(): return get_config('version') def nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) def page_title(): page = request.args.get('page', 'Home') return ' '.join(word.capitalize() for word in page.split('-')) def page_content(): page = request.args.get('page', 'home') path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def init(): template_path = os.path.join(get_config('template_path'), 'template.html') with open(template_path, 'r') as file: return file.read()
-
Crie o arquivo
includes/functions.py
e exclua o arquivoincludes/functions.php
existente. -
Continuando com a visão geral, a próxima etapa é criar um aplicativo Flask. Peça para o Copilot ajudar você com o seguinte:
@workspace Set up a Flask application to handle routing and views, and map the routes to corresponding views. Tell me the location of any files that need to be created or changed.
O Copilot sugere que você crie um arquivo chamado
app.py
na raiz do projeto, contendo o código a seguir.Python from flask import Flask, render_template, request import os app = Flask(__name__) config = { 'name': 'Simple Python Website', 'site_url': '', 'pretty_uri': False, 'nav_menu': { '': 'Home', 'about-us': 'About Us', 'products': 'Products', 'contact': 'Contact', }, 'template_path': 'template', 'content_path': 'content', 'version': 'v3.1', } def get_config(key=''): return config.get(key, None) @app.route('/') @app.route('/<page>') def index(page='home'): page_content = get_page_content(page) page_title = get_page_title(page) nav_menu = get_nav_menu() return render_template('template.html', page_title=page_title, page_content=page_content, nav_menu=nav_menu) def get_page_title(page): return ' '.join(word.capitalize() for word in page.split('-')) def get_page_content(page): path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def get_nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) if __name__ == '__main__': app.run(debug=True)
from flask import Flask, render_template, request import os app = Flask(__name__) config = { 'name': 'Simple Python Website', 'site_url': '', 'pretty_uri': False, 'nav_menu': { '': 'Home', 'about-us': 'About Us', 'products': 'Products', 'contact': 'Contact', }, 'template_path': 'template', 'content_path': 'content', 'version': 'v3.1', } def get_config(key=''): return config.get(key, None) @app.route('/') @app.route('/<page>') def index(page='home'): page_content = get_page_content(page) page_title = get_page_title(page) nav_menu = get_nav_menu() return render_template('template.html', page_title=page_title, page_content=page_content, nav_menu=nav_menu) def get_page_title(page): return ' '.join(word.capitalize() for word in page.split('-')) def get_page_content(page): path = os.path.join(os.getcwd(), get_config('content_path'), f'{page}.phtml') if not os.path.exists(path): path = os.path.join(os.getcwd(), get_config('content_path'), '404.phtml') with open(path, 'r') as file: return file.read() def get_nav_menu(sep=' | '): nav_menu = '' nav_items = get_config('nav_menu') for uri, name in nav_items.items(): query_string = request.args.get('page', '') class_active = ' active' if query_string == uri else '' url = f"{get_config('site_url')}/{'' if get_config('pretty_uri') or uri == '' else '?page='}{uri}" nav_menu += f'<a href="{url}" title="{name}" class="item{class_active}">{name}</a>{sep}' return nav_menu.strip(sep) if __name__ == '__main__': app.run(debug=True)
O Copilot também sugere renomear
template/template.php
comotemplate/template.html
e atualizar o arquivo para usar a sintaxe de modelagem Jinja2:HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="x-ua-compatible" content="ie=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> <title>{{ page_title }} | {{ get_config('name') }}</title> <link href="{{ get_config('site_url') }}/template/style.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="wrap"> <header> <h1>{{ get_config('name') }}</h1> <nav class="menu"> {{ nav_menu|safe }} </nav> </header> <article> <h2>{{ page_title }}</h2> {{ page_content|safe }} </article> <footer> <small>©{{ get_config('version') }} {{ get_config('name') }}.<br>{{ get_config('version') }}</small> </footer> </div> </body> </html>
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta http-equiv="x-ua-compatible" content="ie=edge"/> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/> <title>{{ page_title }} | {{ get_config('name') }}</title> <link href="{{ get_config('site_url') }}/template/style.css" rel="stylesheet" type="text/css" /> </head> <body> <div class="wrap"> <header> <h1>{{ get_config('name') }}</h1> <nav class="menu"> {{ nav_menu|safe }} </nav> </header> <article> <h2>{{ page_title }}</h2> {{ page_content|safe }} </article> <footer> <small>©{{ get_config('version') }} {{ get_config('name') }}.<br>{{ get_config('version') }}</small> </footer> </div> </body> </html>
-
Crie os arquivos
app.py
etemplate/template.html
conforme sugerido. -
O Copilot também pode sugerir que, tendo criado esses arquivos, agora você execute
python app.py
no terminal, na raiz do repositório e, em seguida, navegue até http://127.0.0.1:5000.Note
Dependendo de como o Python está instalado em seu computador, talvez seja necessário usar o comando
python3 app.py
em vez depython app.py
para garantir que a versão correta do Python seja usada.Ao fazer isso, você verá mensagens de erro no navegador.
-
Copie a mensagem de erro
TemplateNotFound
inicial para a exibição do Copilot Chat e pergunte como você pode corrigir isso. Por exemplo:@workspace When I run `python3 app.py`, I get the following error in the browser: `jinja2.exceptions.TemplateNotFound: template.html`. How can I fix this?
O Copilot responde que o erro indica que o Flask não consegue localizar o arquivo
template.html
.Ele informa que, por padrão, o Flask procura modelos em uma pasta chamada
templates
no diretório raiz do projeto. No entanto, seu arquivotemplate.html
está localizado no diretóriotemplate
. Para corrigir isso, você precisa especificar a pasta do modelo correta ao criar o aplicativo Flask. Ele aconselha você a atualizar seu arquivoapp.py
, alterando a atribuiçãoapp = Flask(__name__)
para incluir o parâmetrotemplate_folder
:Python app = Flask(__name__, template_folder='template')
app = Flask(__name__, template_folder='template')
-
Supondo que o servidor de desenvolvimento do Flask ainda esteja em execução, se você atualizar a página do navegador em http://127.0.0.1:5000/, verá um novo erro relacionado à função
get_config
.Copie essa mensagem de erro para a exibição do Copilot Chat e peça ajuda.
@workspace When I run `python3 app.py`, I get the following error in the browser: `jinja2.exceptions.UndefinedError: 'get_config' is undefined.` How can I fix this?
O Copilot responde que o erro ocorre porque o
get_config
não está disponível no contexto do modelo Jinja2. Ele aconselha você a adicionar o seguinte código ao arquivoapp.py
, diretamente antes da linha@app.route('/')
:Python app.jinja_env.globals.update(get_config=get_config)
app.jinja_env.globals.update(get_config=get_config)
-
Atualize o navegador e provavelmente agora você verá o site.
No entanto, nenhum dos estilos CSS está sendo aplicado. Corrigiremos isso em seguida.
-
Pergunte ao Copilot:
@workspace The deployed website does not use the CSS styles. How can I fix this?
O Copilot informa que o Flask espera que seu arquivo CSS esteja em um diretório chamado
static
. Ele sugere mover o arquivostyle.css
existente do diretóriotemplate
para um novo diretóriostatic
e atualizar o caminho para o arquivostyle.css
dentro da partehead
do arquivotemplate.html
. Altere para:HTML <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
Quando você atualiza o navegador, o site agora deverá ser renderizado corretamente.
Para concluir a migração inicial, continue trabalhando nas etapas da visão geral de alto nível que o Copilot forneceu, solicitando ajuda conforme necessário.
Concluindo a migração
O trabalho adicional para concluir com êxito o processo de migração envolveria:
- Verificar a migração inicial minuciosamente.
- Corrigir bugs. Por exemplo, no momento, no exemplo descrito aqui, os links de página só funcionarão se você definir
pretty_uri
comoTrue
na seçãoconfig
do arquivoapp.py
. Se você quiser a opção de usar parâmetros de cadeia de caracteres de consulta nas URLs da página ou quiser remover essa opção do código, poderá solicitar que o Copilot ajude a fazer isso. - Escrever testes para o projeto migrado.
- Limpar o projeto removendo todos os arquivos que não são mais necessários.
- Refatorar o código na nova linguagem. O processo de migração resultou em um projeto Python cuja arquitetura é baseada na do projeto PHP original. Tendo feito a migração inicial, agora você pode refatorar o código para fazer o melhor uso dos recursos da linguagem Python e da estrutura Flask.
- Atualizar a documentação. O arquivo
readme.md
está desatualizado e precisa ser reescrito.