Quando seu código foi compartilhado: uma história da abertura ao final do jogo





“Me deixe em paz, por favor, eu sou um criador! Deixe-me criar! ”- o programador Gennady, pela terceira vez à noite, profere este mantra em sua cabeça. No entanto, ele ainda não escreveu uma única linha de código, porque outra solicitação pull chegou à biblioteca que ele está tentando desenvolver. E, de acordo com a política da empresa, a revisão do código deve ocorrer com atrasos mínimos. Agora Gennady está pensando no que fazer: sem olhar para aceitar as mudanças, sem olhar para rejeitá-las, ou ainda gastar um tempo precioso para entender sua essência. Afinal, quem senão ele? Ele escreveu este código, ele o seguirá. E todas as mudanças são possíveis apenas com seu consentimento pessoal, porque esta é a Biblioteca do Juízo Final. 



Enquanto isso, literalmente atrás da parede, uma equipe chamada "Cedar Beavers" redistribui os pedidos entre si de modo que a carga ao vê-los caia mais ou menos uniformemente. Sim, eles não lidam com a Biblioteca do Juízo Final, mas fazem outras tarefas que exigem mudanças rápidas de código e processos mais rápidos.



Não existe uma solução única para todos os casos: para alguns, a agilidade e a velocidade dos processos são importantes, em algum lugar pode ser necessário ter mão firme e controle total. Além disso, em diferentes estágios do desenvolvimento do mesmo produto, diferentes abordagens podem ser necessárias para se substituir. Cada um deles tem seus prós e contras e, com base neles, chegamos onde estamos agora.



Então, para onde fomos no Wrike?



Que opções escolhemos nossa própria maneira de possuir o código?



Estritamente pessoal. Nós nem mesmo consideramos isso. Agora, se Gennady proíbe a criação de solicitações pull para sua biblioteca e faz todas as alterações pessoalmente, você obtém uma abordagem estritamente pessoal. Certamente Gennady começou assim.



As desvantagens óbvias dessa abordagem é simplesmente o totalitarismo no mundo do desenvolvimento. Gennady é sem exagero a única pessoa na Terra que conhece completamente o código, tem (ou não) planos para o seu desenvolvimento e pode alterá-lo. O mesmo ônibus, que é o "fator baixo", já saiu da esquina. Se Gennady pegar um resfriado, então, provavelmente, o projeto irá desmoronar com ele. Outro desenvolvedor terá que fazer um fork, haverá muitos deles e o caos completo ocorrerá.



Essa abordagem tem uma vantagem - uma abordagem totalmente consolidada para o desenvolvimento. Uma pessoa toma todas as decisões sobre arquitetura, estilo de código e resolve pessoalmente qualquer problema. Sem sobrecarga de comunicação.



Condicionalmente pessoal. Isso é exatamente o que Gennady não quer fazer: assistir todos os MRs, dar a oportunidade de alterar o código de sua biblioteca para outras pessoas, mas ter total controle sobre as alterações e direito de veto. Os prós e contras são os mesmos do último parágrafo, mas agora eles são um pouco atenuados pela capacidade de enviar uma solicitação de pull para desenvolvedores de terceiros diretamente para o repositório, e não desenhar uma tarefa técnica para a implementação de alguns recursos.



Coletivocomo Cedar Beavers. Nesse caso, toda a equipe é responsável pelo código, e seus próprios membros decidem quem vai acompanhar cada solicitação.



Dentre as vantagens, pode-se destacar a alta agilidade na revisão da revisão, a distribuição de expertise entre os membros da equipe e a diminuição do fator ônibus. Claro, também existem desvantagens. Nas discussões na Internet, muitas pessoas mencionam a falta de responsabilidade caso seja "espalhada" entre várias pessoas. Mas depende da estrutura da equipe e da cultura dos desenvolvedores: o Desenvolvedor Sênior ou o líder da equipe pode ser o responsável pela equipe, então ele será o ponto de entrada para as dúvidas. E MR e escrever novos recursos podem ser divididos de acordo com o nível de treinamento do desenvolvedor. Afinal, seria errado dar a um novato que está apenas começando a entender a arquitetura do aplicativo a refatoração do código.





No Wrike, adotamos uma abordagem colaborativa para a propriedade do código, com o líder da equipe como a principal responsabilidade. Essa pessoa tem mais experiência no código, sabe qual dos desenvolvedores é competente na revisão de uma complexidade específica e é totalmente responsável pela qualidade do código da equipe.



Mas o caminho para a implementação técnica desta solução não foi o mais fácil. Sim, em palavras, tudo parece muito fácil: aqui está um recurso, aqui está um comando. A equipe sabe pelo que é responsável, o que significa que vai monitorá-la.



Esses acordos podem funcionar como um contrato verbal se o número de comandos for menor que o número de dedos da mão. E, em nosso caso, são mais de trinta comandos e milhões de linhas de código. Além disso, muitas vezes os limites de um recurso não podem ser designados por um repositório: há integrações bastante próximas de alguns recursos em outros.



O painel de filtro à direita é o mesmo para todas as visualizações. Esta é uma característica da equipe "A". Além disso, todas as visualizações são recursos das outras três



equipes.O exemplo mais óbvio são os filtros. Eles se parecem e se comportam da mesma forma em todas as visualizações possíveis, enquanto as próprias visualizações podem diferir em funcionalidade. Isso significa que a visualização pertence a uma equipe e o painel de filtro único pertence a outra. E assim, dezenas de repositórios, milhares de arquivos de código diferente. Quem você deve consultar com a revisão se precisar fazer alterações em um arquivo específico?



A princípio tentamos resolver esse problema com um arquivo JSON simples que estava na raiz do repositório. Havia uma descrição da funcionalidade e os nomes dos responsáveis. Eles podem ser contatados para obter uma revisão de sua solicitação pull.



É um pouco como um modelo de propriedade de código pessoal condicional. A única exceção é que nenhuma pessoa é listada como responsável, mas duas ou três. Mas essa abordagem nunca nos serviu: as pessoas se mudaram para outras equipes, adoeceram, saíram de férias, pediram demissão e, a cada vez, tínhamos que primeiro procurar alguém que substituísse o proprietário especificado e, em seguida, dizer aos proprietários para alterar manualmente o nome e realizar as alterações.



Mais tarde, eles passaram de pessoas específicas para especificar comandos.No entanto, tudo está no mesmo arquivo JSON. Não ficou muito melhor, porque agora era necessário encontrar membros da equipe para os quais o código pudesse ser enviado para revisão. E nós temos centenas (um pouco astutos, quase 70) desenvolvedores front-end, e não foi fácil encontrar todos os participantes naquela época. O sistema de propriedade já se tornou coletivo, mas encontrar as pessoas certas às vezes não era mais fácil do que procurar um vice-proprietário da versão anterior. Além disso, o problema com o código, no qual vários recursos poderiam se cruzar, ainda não pôde ser resolvido.



Portanto, era fundamental resolver duas questões: como atribuir recursos individuais a uma determinada equipe dentro do repositório de outra equipe e como tornar as informações simples e acessíveis para todas as equipes que podem possuir o código.



Por que as ferramentas prontas não serviam para nós. Existem ferramentas no mercado para designar pessoas para revisões e associar indivíduos específicos a um código. Ao usá-los, você não precisa recorrer à criação de arquivos com os nomes das pessoas a quem você precisa executar em caso de revisões, bugs, refatorações complexas.



No Azure DevOps Services tem funcionalidade - inclui automaticamente o revisor de código. O nome fala por si, e um ex-colega meu diz que eles usam essa ferramenta em sua empresa com muito sucesso. Não trabalhamos com o Azure, então seria ótimo ouvir dos leitores como as coisas estão com o autoreviewer.



Usamos o GitLab, portanto, seria lógico olhar para os proprietários de código do GitLab. Mas o princípio de funcionamento desta ferramenta não nos agradava: a funcionalidade do GitLab é um monte de caminhos no repositório (arquivos e pastas) e pessoas através de suas contas no GitLab. Este pacote é gravado em um arquivo especial - codeowners.md. Precisávamos de um monte de caminhos e recursos. Além disso, nossos recursos estão contidos em um dicionário especial, onde são atribuídos ao comando. Isso permite que você marque recursos complexos que podem existir em mais de um repositório, ser desenvolvido por várias equipes e, novamente, não estar vinculado a nomes específicos. Além disso, tínhamos planos de usar essas informações para criar um diretório conveniente de equipes, recursos relacionados e todos os membros da equipe.



Como resultado, decidimos criar nosso próprio sistema de controle de propriedade de código. A implementação da primeira versão do nosso sistema baseou-se nas capacidades do Dart SDK , pois a princípio foi lançado para os repositórios front-end do departamento e apenas para arquivos Dart. Usamos nossas próprias meta tags (felizmente, isso é suportado no nível do idioma), depois executamos todos os arquivos de origem com um analisador estático e fizemos algo como uma tabela: Arquivo / Recurso - Comando do proprietário. Você pode marcar arquivos individuais e caminhos inteiros com várias pastas.



Depois de algum tempo, a marcação com recursos tornou-se disponível para código em Dart, JS e Java, e esta é toda a base do código: o front-end e o back-end. Para obter informações sobre os proprietários, é utilizado um analisador estático. Mas, é claro, não é o mesmo da primeira versão e funcionava apenas com o código Dart. Por exemplo, para arquivos Java, a biblioteca javaparser é usada . Esses analisadores funcionam dentro do cronograma e coletam todas as informações relevantes em um único registro.



Além de vincular determinado código às equipes proprietárias, construímos uma integração com o serviço de coleta de erros na produção e postamos todas as informações úteis sobre as equipes e recursos em um recurso interno. Agora, qualquer funcionário pode ver a quem recorrer se, repentinamente, tiver dúvidas em um determinado modo de exibição. Também tornamos automático a criação de tarefas para os responsáveis ​​em caso de algumas mudanças globais, como a mudança para uma nova versão do Dart ou Angular.



Ao clicar no comando, você pode ver todos os recursos, todos os membros da equipe, quais recursos são puramente técnicos e quais são produtos



Como resultado, obtivemos não apenas um sistema bastante flexível para vincular recursos com equipes, mas também uma infraestrutura completa que ajuda, a partir do código, a encontrar um recurso relacionado, uma equipe com todos os participantes, um product owner de um recurso e relatórios de bug.



Entre as desvantagens estão a necessidade de monitorar de perto a marcação de recursos ao refatorar e transferir o código de um lugar para outro, e a necessidade de poder adicional para coletar todas as informações sobre a marcação.



Como você resolve o problema de possuir seu código? E há algum problema relacionado e, o mais importante, sua solução?



All Articles