Reformatação e controle de versão

23

A formatação de código é importante. Mesmo o recuo é importante . E a consistência é mais importante que pequenas melhorias. Mas os projetos geralmente não têm um guia de estilo claro, completo, verificável e aplicado desde o primeiro dia, e grandes melhorias podem chegar a qualquer dia. Talvez você ache isso

SELECT id, name, address
FROM persons JOIN addresses ON persons.id = addresses.person_id;

poderia ser melhor escrito como / é melhor escrito do que

SELECT persons.id,
       persons.name,
       addresses.address
  FROM persons
  JOIN addresses ON persons.id = addresses.person_id;

enquanto trabalhava na adição de mais colunas à consulta. Talvez essa seja a mais complexa das quatro consultas em seu código ou uma consulta trivial entre milhares. Não importa quão difícil seja a transição, você decide que vale a pena. Mas como você controla as alterações de código nas principais alterações de formatação? Você pode simplesmente desistir e dizer "este é o ponto em que começamos novamente" ou pode reformatar todas as consultas em todo o histórico do repositório.

Se você estiver usando um sistema de controle de versão distribuído como o Git, poderá reverter para o primeiro commit de todos os tempos e reformatar o caminho para o estado atual. Mas é muito trabalho, e todo mundo teria que interromper o trabalho (ou estar preparado para a mãe de todas as fusões) enquanto isso acontecia. Existe uma maneira melhor de alterar o histórico que oferece o melhor de todos os resultados:

  • Mesmo estilo em todas as confirmações
  • Trabalho de mesclagem mínima

?

Para esclarecer, não se trata de práticas recomendadas ao iniciar o projeto, mas o que deve ser feito quando uma grande refatoração for considerada uma Boa Coisa ™, mas você ainda deseja um histórico rastreável? Nunca reescrever o histórico é ótimo se for a única maneira de garantir que suas versões sempre funcionem da mesma forma, mas e os benefícios do desenvolvedor de uma reescrita limpa? Especialmente se você tiver maneiras (testes, definições de sintaxe ou um binário idêntico após a compilação) para garantir que a versão reescrita funcione exatamente da mesma maneira que a original?

l0b0
fonte
24
Por que você gostaria de reescrever a história? Isso anula o objetivo do controle de versão. Você deseja garantir que o aplicativo enviado há 3 meses corresponda à revisão xxxxxx sem a menor dúvida. Mesmo reformatação trivial é inaceitável.
Simon Bergot
5
Eu gostaria de comentar que eu faço isso com a tag "Reformatar. Nenhuma mudança funcional"
Rig
3
Em um tópico não relacionado, parece que você estava sugerindo reescrever o histórico do Git reformatando todo o código. Não dê idéia às pessoas, reescrever o histórico do Git é ruim para 99,9% dos casos. A reformatação não é o caso da borda de 0,1%.
Andrew T Finnell
4
Em algumas línguas (estou olhando para você, Python), a reformatação pode alterar o funcionamento lógico do código. Você precisaria analisar todos os idiomas armazenados no seu VCS para rastrear e ignorar as reformatações com segurança.
Joris Timmermans
3
Reformas são alterações de código e devem ser confirmadas como tal.
precisa

Respostas:

26

Faça a reformatação como confirmações separadas. Isso interferirá minimamente no histórico, e você poderá ver rapidamente quais confirmações estão apenas reformatando e que realmente alteram o código. Poderia distorcer git blamee semelhante, mas se apontar para um commit somente de reformatação, é bastante simples procurar a alteração anterior antes disso.

harald
fonte
Vi projetos descarrilados há semanas, porque um dos desenvolvedores achou que era uma boa ideia. Se você fizer isso, entenda os riscos com antecedência e decida exatamente até onde irá a formatação. Eu acho que o mjfgates tem a resposta certa.
Johntron 18/01/16
1
Parece que a equipe em questão tem problemas maiores que a formatação de código. Mas sim, eu não recomendo fazer isso, a menos que você precise. Se você quiser reformatar as alterações, ainda assim, seria melhor fazê-las como confirmações separadas do que misturadas com alterações funcionais.
harald
Sim, muitos problemas: o PI só quer alertar os novos desenvolvedores de que não é tão simples quanto parece. As ferramentas de reformatação em massa são arriscadas (especialmente se você construí-lo com regex - pelo menos usa o AST), e se você se preocupa com a revisão de código e o rastreamento de erros, ele pode realmente atrapalhar seu processo. Pessoalmente, escrevo meu código para ser consistente com o estilo de cada arquivo, embora não me importe em revisar códigos quando algumas funções são reformatadas. Muitos desenvolvedores ficam presos no estilo do código e negligenciam os problemas maiores como arquitetura, processo, ferramentas etc.
Johntron
Na programação, nada é tão simples como parece :)
harald
13

Não reescreva a história do VCS: é contra os princípios do VCS.

Não tente automatizar a correção da formatação: está tratando os sintomas, não o problema real (= desenvolvedores que não seguem os padrões de codificação).

Defina o padrão de codificação e as melhores práticas de formatação em um documento comum e peça a todos os desenvolvedores que concordem.

Você menciona o Git, o que é ótimo, porque é distribuído. Com um DVCS, é muito fácil aplicar as melhores práticas por meio do fluxo de trabalho do gatekeeper . Os gatekeepers rejeitam propostas de mesclagem (= solicitações de recebimento no Git) que não estão em conformidade com as diretrizes comuns. E quero dizer rejeitar , em negrito, caso contrário, o codificador violado não se preocupará em seguir as regras e continuar repetindo os mesmos erros.

Essa técnica funciona bem para mim. Os programadores desejam que seu trabalho seja mesclado; portanto, após alguns erros no começo, eles começam a seguir as regras.

De acordo com a correção da base de código existente ... eu recomendo fazer isso gradualmente, talvez módulo por módulo, ou como faz sentido para o seu projeto. Teste com cuidado em cada etapa. Pode parecer estúpido, mas erros acontecem mesmo com mudanças triviais, como apenas a formatação, portanto, esteja preparado para alguns pequenos inchaços na estrada.

janos
fonte
1
Voto negativo, porque o autor afirma claramente que isso ocorre no contexto de projetos que não começaram com "... um guia de estilo claro, completo, verificável e aplicado desde o primeiro dia". Ele não pode tratar o problema real, porque já aconteceu. Eu concordo com você embora :)
Johntron
2
rejeitar significa que haverá uma luta entre os humanos e o robô. Esteve lá. Mais cedo ou mais tarde, o robô exigirá que um código realmente complexo seja formatado de maneira ilegível. Exemplos: uma string Java é de fato uma instrução SQL, mas o robô não sabe disso; o espaço em branco antes do fechamento de parênteses pode conter informações sobre a estrutura do código para humanos, mas não para o robô; parâmetros da função obter dividido em várias linhas da forma mais sem sentido ...
18446744073709551615
9

A resposta para sua pergunta real é: "Você não". Não conheço nenhuma ferramenta SCM atual que possa rastrear alterações na lógica do código formatado de uma maneira, através de uma grande alteração de formatação e de outras alterações após o código ser formatado da nova maneira. E, você sabe disso, perder o histórico de um pedaço de código não é bom.

Consequentemente, vou contradizer um pouco sua primeira frase. Código formatação não importa que muito. Pretty é legal, mas não é para isso que estamos aqui. Eu entendo, assim como qualquer pessoa, que ser despejado no antigo código variante K&R de alguém com os dois espaços recuados é uma porcaria (1), mas ... a formatação não é realmente um obstáculo para entender o que está acontecendo, a menos que seja algo excepcionalmente patológico. E, nesse caso, você terá problemas para alterar o código de qualquer maneira e não deve incomodá-lo.

Portanto, não vale a pena fazer alterações no código estabelecido estritamente para reformatá-lo. Mudando os nomes das variáveis, dividindo funções longas, todas as coisas boas de refatoração que alteram o conteúdo, sim, mas não APENAS reformatando.

1) - Eu já possuía o Windows Clipboard Viewer por um tempo. A coisa toda era um módulo C de 150k. Encontrei um local em que diferentes pessoas usaram, penso eu, cinco estilos de aparelhos diferentes, a trinta linhas uma da outra. Mas essa seção de coisas funcionou. Eu carreguei uma impressão desse pedaço de código por dez anos, mas não o cutuquei porque esse histórico importava, e esse código estava em pelo menos três árvores de origem (Windows 3.x, NT, futuro 95) que viviam em diferentes edifícios.

mjfgates
fonte
No passado, usando hg, descobri que a mesclagem por peças é uma ferramenta inestimável para lidar com mesclas complicadas de re-fatores . Normalmente, o que eu faria é mesclar as confirmações antes do grande re-fator, depois mesclar o grande re-fator e, finalmente, mesclar as confirmações desde o re-fator. Cada uma dessas três fusões por conta própria é muito mais fácil do que tentar desembaraçar a bagunça resultante de todas as fusões de uma só vez.
Mark Booth
Eu concordo totalmente! Além disso, já vi muitos desenvolvedores exagerarem (uma versão mais nova de mim mesmo) na reformatação e no estilo de código, e eles acabam apresentando defeitos. Uma vírgula / ponto-e-vírgula ausente aqui, declarações de variáveis ​​movidas para o topo das funções, loops de for alterados para for-each's - todos podem introduzir erros sutis. É necessária uma quantidade enganosa de habilidade para fazer essas alterações com segurança.
Johntron 18/01/16
4

Mas como você controla as alterações de código nas principais alterações de formatação?

Alterações de formatação são alterações de código; trate-os como faria com qualquer outra alteração no seu código. Qualquer um que tenha trabalhado em um projeto significativo provavelmente já viu bugs e outros problemas criados quando alguém decidiu "apenas" reformatar algum código.

Mas é muito trabalho, e todo mundo teria que interromper o trabalho (ou estar preparado para a mãe de todas as fusões) enquanto isso acontecia.

Por que você tem que reformatar tudo ao mesmo tempo? Especialmente se a reformatação não alterar o significado do código, você poderá reformatar os arquivos individualmente e registrá-los à medida que avança. Melhor, peça a todos da equipe que concordem com um estilo (caso contrário, não há sentido em reformatar de qualquer maneira) e peça a todos que cuidem da reformatação no decorrer de seus outros trabalhos. Depois de um tempo, você terá coberto a maior parte do código sem interromper o restante do projeto.

Caleb
fonte
1

Existem duas abordagens viáveis ​​que eu já vi para isso.

1. Reformate o código no commit-hook

Embora inicialmente seja arrepiante alterar o código após o envio , se o procedimento de reformatação (por exemplo, astyle ) não prejudicar o código, será uma operação segura. Com o tempo, toda a equipe perceberá que todo o código parece o mesmo. Claramente, ter testes abrangentes de unidade / automatizados garantirá que nada ocorra.

2. Reformatação única de todo o código

Isso é mais perigoso na minha experiência e dificulta os problemas de rastreamento no big bang, mas é possível. A execução de todos os testes depois é essencial. Para o estilo de codificação, a maioria das diferenças gira em torno do uso de espaço em branco - recuo ou novas linhas. Uma ferramenta de mesclagem decente deve poder ser instruída a ignorar todas as diferenças de espaço em branco, portanto, isso ajudará nas mesclagens.

JBRWilkinson
fonte
1
A opção um não ativaria o ripple em grande parte da base de código, resultando rapidamente no mesmo big bang de alterar cada arquivo?
Sinal
@Sign: Exatamente o que quero dizer - Quando o gancho de confirmação muda, seu histórico pode se deteriorar para algo quase inútil. A formatação que não altera a funcionalidade não deve ser uma confirmação, deve ser transplantada ao longo do histórico do código.
L0b0
1
Se o IDE o suportar, também haverá 3) o formato automático do IDE salvo. Em seguida, basta usar as mesmas configurações em todos os lugares - isso é mais fácil se você usar o padrão com o IDE.
Eu fiz essas duas abordagens. A primeira abordagem é muito intrusiva, pois haverá várias alterações sempre que um novo arquivo for confirmado pela primeira vez. A segunda abordagem é melhor para a equipe, como arrancar uma bandaid rapidamente.
Druska 8/04