Práticas recomendadas para compartilhar pequenos trechos de código entre projetos

102

Eu sempre tento seguir o princípio DRY estritamente no trabalho; toda vez que repito o código por preguiça, ele volta mais tarde quando preciso manter esse código em dois lugares.

Mas muitas vezes escrevo métodos pequenos (talvez 10 a 15 linhas de código) que precisam ser reutilizados em dois projetos que não podem se referir um ao outro. O método pode ter algo a ver com networking / strings / MVVM, etc. e é geralmente um método útil, não específico ao projeto em que ele se encontra originalmente.

A maneira padrão de reutilizar esse código seria criar um projeto independente para o código reutilizável e referenciar esse projeto quando você precisar. O problema é que acabamos em um dos dois cenários abaixo do ideal:

  1. Acabamos com dezenas / centenas de pequenos projetos - cada um para abrigar as pequenas classes / métodos que precisávamos reutilizar. Vale a pena criar um novo totalmente .DLLsó para um pouquinho de código?
  2. Terminamos com um único projeto que contém uma coleção crescente de métodos e classes não relacionados. Essa abordagem é para o que uma empresa na qual eu costumava trabalhar; eles tinham um projeto nomeado base.commonque tinha pastas para coisas como eu mencionei acima: rede, manipulação de strings, MVVM etc.

Então, minha pergunta é:

Como uma equipe de software melhor reutiliza pequenos pedaços de código entre projetos?

Estou particularmente interessado se alguém trabalhou em uma empresa que possui políticas nessa área ou que se deparou com esse dilema pessoalmente como eu.


note: Meu uso das palavras "Projeto", "Solução" e "Referência" é proveniente de experiência em desenvolvimento .NET no Visual Studio. Mas tenho certeza de que esse problema é independente de idioma e plataforma.

George Powell
fonte
21
+1, embora eu ache que há um elemento de humor em alguém que trabalha com o .NET preocupado em arrastar código irrelevante por meio de uma referência de DLL.
JDB #
2
@ColeJohnson .NET em si é uma referência enorme! Provavelmente muito maior do que as dlls que eu faria.
George Powell
2
Entendi. No entanto, o compilador JIT do .NET carrega apenas os métodos necessários para a RAM (quando eles são chamados)
Cole Johnson
1
Verdadeiro. Embora você ainda precise distribuir toda a estrutura .NET para quem deseja usar seu produto, é difícil gerenciar grandes projetos e soluções complexas.
George Powell

Respostas:

75

Se eles realmente são métodos / classes reutilizáveis, você pode escrevê-los em um pequeno número de bibliotecas 'Swiss Army Knife'. Fazemos isso com bastante frequência na minha empresa; nós os chamamos de bibliotecas de estrutura:

  • Framework.Data - Utilitários para trabalhar com consultas de banco de dados.
  • Framework.ESB - Métodos padrão para interagir com nosso barramento de serviço corporativo
  • Framework.Logging - Sistema de registro unificado
  • Framework.Services - Utilitários para interagir com serviços da web
  • Framework.Strings - Utilitários para manipulação avançada de strings / pesquisa de strings difusos etc.
  • ...

Ao todo, existem cerca de uma dúzia de bibliotecas. Você pode realmente distribuir o código da maneira que achar melhor, para não precisar acabar com centenas ou despejar tudo em um conjunto gigante. Acho que essa abordagem se encaixa porque apenas alguns de nossos projetos precisarão Framework.Datae apenas alguns precisarão Framework.Strings, para que os consumidores possam selecionar apenas as partes da estrutura que são relevantes para seu projeto em particular.

Se eles são realmente apenas trechos, e não métodos / classes reais que podem ser facilmente reutilizados, tente distribuí-los como trechos de código no IDE (por exemplo, trechos de código do Visual Studio ). As equipes com as quais trabalhei anteriormente tinham uma biblioteca de trechos em comum que tornava mais fácil para todos seguir nossas práticas de codificação padrão com código interno também.

pswg
fonte
4
+1 Essa seria minha abordagem também. Interessado em saber como você decidiu onde colocar o código que lida com coisas de dois ou mais aspectos. Por exemplo IPAddressToString. E se você permite que essas bibliotecas se usem. Por exemplo, serviços e dados provavelmente pode se beneficiar muito com o registo ...
Marjan Venema
5
@MarjanVenema Para códigos transversais, depende de quais consumidores acharão o método mais útil. Pois IPAddressToStringé provável que os consumidores que lidam com protocolos de rede tenham que usá-lo, mas os consumidores que brincam muito com cadeias de caracteres podem não se importar com endereços IP. Provavelmente isso acabaria em um pacote de rede Framework.Strings.
Pwg #
@MarjanVenema Tentamos evitar interdependências. Nossos serviços e estruturas de dados são gravados de forma que não façam nenhum log por si mesmos, mas facilitam ao consumidor escrever o código de log adequado. As bibliotecas da estrutura podem fazer referência umas às outras, mas apenas por extensão - por exemplo, Framework.Logging.Gibraltaré um complemento específico para o sistema de registro.
PSWG
5
+1 Você pode pegar essas bibliotecas da estrutura e implantá-las em um repositório interno do NuGet (tão simples quanto uma pasta de rede) e terá uma ótima maneira de gerenciá-lo.
Steven Evers
2
@SteveEvers Na verdade, estou trabalhando agora para configurar isso. : P
pswg 30/03
21

Discordo da resposta aceita por vários motivos.

Na minha experiência, quando vejo bibliotecas "diversas" como a resposta aceita, elas são uma desculpa para reinventar a roda (ou não inventada aqui (NIH) ) - um pecado muito maior do que violar o Dont Repeat Yourself (DRY) .

Às vezes, violar o DRY pode ser um compromisso razoável, é melhor do que introduzir um acoplamento rígido. A reutilização é uma preocupação secundária em comparação com um bom design orientado a objetos. Um pouco (quero dizer, pequena quantidade, aplique a Regra dos Três ) de duplicação é mais fácil de entender do que uma base de código de espaguete.

A abordagem de várias bibliotecas de uso geral é um mau exemplo. Isso leva a uma granularidade fina da montagem e muitas montagens são ruins. Recentemente, reduzi uma empresa internamente de 24 bibliotecas para 6 bibliotecas. Melhorou o tempo de compilação de vários minutos para ~ 20 segundos. O Visual Studio também é mais lento para carregar e menos responsivo com mais montagens. Ter muitas bibliotecas também leva a confusão sobre onde o código deve residir; prefira menos regras mais simples.

Por que as coisas no .Net Framework não são boas o suficiente? A estrutura é bem grande; muitas vezes eu vi código que reimplementa coisas que já existem lá. Certifique-se realmente de que suas estruturas estejam preenchendo lacunas na estrutura .Net e não existam apenas por razões estéticas (por exemplo, "Eu não gosto da estrutura .Net aqui" ou talvez alguma otimização prematura )

A introdução de outra camada em sua arquitetura tem um custo de complexidade significativo. Por que a camada existe? Eu vi uma reutilização falsa, com isso quero dizer que, o código é construído sobre uma estrutura interna. Teria sido muito mais eficiente implementá-lo diretamente sobre as bibliotecas padrão.

O uso de tecnologias padronizadas (como a estrutura .Net e as populares bibliotecas de terceiros / código aberto) tem benefícios que geralmente superam os ganhos tecnológicos comparativos de sua criação. É mais fácil encontrar talentos que conheçam essas tecnologias e seus desenvolvedores existentes investirão mais em aprendê-las.

Minhas recomendações:

  • Não compartilhe esse código.
  • Crie uma nova biblioteca se ela tiver uma finalidade coesa, não use o padrão de design bola de lama .
  • Reutilize bibliotecas de terceiros existentes sempre que possível.
  • Prefira menos assemblies, com regras mais simples sobre onde o código deve residir.
Dave Hillier
fonte
1
Um benefício adicional do uso de bibliotecas de código aberto, quando disponíveis - se você tiver algumas melhorias, poderá compartilhá-las de volta à comunidade! Por exemplo, com .Net MS publicou uma EnterpriseLibrary (agora Open Source), que fornece um bom conjunto de ferramentas para cenários comuns, encontre algo que possa ser melhorado e pronto! Todos se beneficiam!
glenatron
2
Realmente não vejo um desacordo com a resposta aceita aqui :-). "menos assemblies, com regras mais simples sobre onde o código deve residir" não é uma contradição à resposta aceita. A resposta também advoga apenas o uso de tantas assembléias diferentes quanto parecer razoável.
sleske
Cinco anos depois, a orientação da Microservice também convergiu para essa prática: medium.com/standard-bank/…
Dave Hillier
11

Para pequenos pedaços de código - digamos, uma única classe sem dependências -, tendemos a copiar e colar o código nos projetos. Isso soa como uma violação do DRY, e eu admito que às vezes. Mas, a longo prazo, tem sido muito melhor do que ter algum tipo de projeto maciço e de várias cabeças por alguns motivos.

Primeiro, é mais simples ter o código à mão, especialmente ao criar e depurar coisas.

Segundo, invariavelmente você desejará fazer alguns ajustes no código comum desse projeto. Se você tem uma cópia local da fonte, basta fazer o ajuste e chamar um dia. Se houver uma biblioteca compartilhada, você poderá ajustar essa biblioteca e garantir que não interrompa todos os outros aplicativos ou criar um pesadelo de versão.

Portanto, se não for robusto o suficiente para o seu próprio espaço para nome, tenderemos a colocá-lo nos bits apropriados do projeto e chamá-lo por dia.

Wyatt Barnett
fonte
5
Eu não concordo com essa abordagem. Eu aprecio os problemas de manutenção com o gerenciamento de pequenos pedaços de código, mas eu argumentaria que alguma biblioteca comum poderia ser criada a partir de todos eles, como o @psw está sugerindo. Ter cópias duplicadas de código com pequenos ajustes está causando problemas. Suposições serão feitas, correções de erros serão perdidas.
Andrew T Finnell
2
-1 (para a resposta). É certamente mais fácil que todos tenham suas próprias cópias de suas próprias versões de programas. Foi assim que o software foi desenvolvido nos anos 80. Desde então, aprendi que - a longo prazo - isso leva a uma bagunça. É mais difícil fazer a coisa certa e ter uma biblioteca comum, pois as pessoas terão que se comunicar muito mais sobre seu trabalho. Bem, eles deveriam.
Michael Durrant
3
+1 - acho que vale a pena mencionar essa abordagem, mesmo que não seja a que você deseja usar com muita frequência. Alguns trechos são mais parecidos com padrões de design - você os reutilizará, mas um pouco diferente em todos os lugares, e talvez em idiomas diferentes, e talvez queira alterá-los. Além disso, uma biblioteca amplamente reutilizada é inflexível, pois as alterações em sua API são muito arriscadas. Por fim, ter essa abordagem como um substituto aumenta a qualidade das bibliotecas compartilhadas, mantendo o material experimental fora um pouco mais.
Eamon Nerbonne
6

A segunda solução que você descreve não é tão ruim assim. No .NET, você também faz referência a um assembly do GAC, mesmo que apenas use uma única classe dele. "Arrastar código irrelevante" não é um problema que você possa imaginar. Nesse caso, é vital manter pelo menos métodos e classes relacionados organizados de maneira limpa em diferentes espaços para nome. Além disso, boas práticas para o design da API devem ser aplicadas para evitar que essa solução se torne uma bagunça.

Se se trata de bits muito pequenos de código, acho que a seguinte abordagem é um bom complemento para um projeto comum: permita que eles sejam duplicados em diferentes soluções. Lide com eles como práticas recomendadas: documente e comunique-os à equipe.

Theo Lenndorff
fonte
1
Exceto que, para bibliotecas não padrão, isso significa que você precisará enviar um assembly grande apenas por causa de um único (ou poucos) usos. Isso não é um problema para o material padrão, pois está disponível de qualquer maneira, mas eu definitivamente evitaria enviar montagens grandes, mas geralmente não utilizadas, se você puder dividi-las da melhor maneira possível.
cutuca
6

Eu só trabalhei em ambientes "corporativos", onde esse tipo de coisa tem sido um problema e cada vez que é a segunda opção adotada. Na maioria das vezes, funcionou bem, porque não houve nenhuma restrição na área de cobertura do aplicativo.

No entanto, tendo passado a última semana com uma start-up que está executando seu próprio servidor Nuget, estou inclinado a sugerir isso como uma alternativa viável. É claro que os problemas que espero surgir serão em torno da capacidade de descoberta.

Se os projetos são adequadamente granulares e os namespaces são sensatos, posso ver isso se tornando uma abordagem popular em alguns lugares.

Kofi Sarfo
fonte
Em que sentido você espera que eles não sejam descobertos? Usamos um número grande e crescente de pacotes de nuget dessa maneira. O maior problema que temos é com o gerenciamento de versões e dependências.
Pd #
Ah sim. Aqueles também. Por questões relacionadas à capacidade de descoberta, quero dizer que, dado um número suficiente de pequenos pacotes com função específica, talvez se torne mais difícil catalogar (e encontrar) cada um. Por exemplo, como sua equipe sabe quais pacotes contêm várias funções? (mostrando NuGet pesquisa ignorância aqui)
Kofi Sarfo
Ah eu vejo. Sim, você pode definitivamente colocar o que quiser na descrição e isso se torna pesquisável, mas acho que agrupamos os pacotes o suficiente para que isso não pareça um problema.
PDR
@sarfeast Seria bom se você pudesse compartilhar um link para qualquer servidor Nuget e contar um pouco sobre isso.
Hans-Peter Störr
6

Recentemente, eu pensei sobre isso e o que me ocorreu foi uma grande biblioteca de métodos comuns, como foi mencionado até agora, mas com uma reviravolta. O projeto da biblioteca permite que você configure, em tempo de compilação, quais partes são incluídas, como o projeto BusyBox . Com essa abordagem, você pode ter um repositório de biblioteca de estilo de pia de cozinha, mas pegue apenas as ferramentas necessárias ao compilar.

Harvey
fonte
5

O GitHub tem uma ferramenta bastante útil para salvar trechos de código https://gist.github.com/

Ele armazena seus trechos como repositórios git que você pode manter em sigilo ou usar para compartilhar trechos com outras pessoas.

blacksh33p
fonte
3

Dependendo do tamanho da equipe / projeto / empresa, isso será uma tarefa bastante difícil, a menos que já esteja incorporado ao seu ambiente de alguma forma e todas as soluções que você encontrar (se implementá-lo) custarão algum dinheiro. (Isso pode protegê-lo mais, mas você não poderá medir com facilidade). Você terá que verificar se vale o preço. Lembre-se também de que as soluções reutilizáveis ​​tendem a se tornar abstratas e geralmente se ajustam a muitas situações, mas sem serem ótimas.

De qualquer forma, se você quiser fazer isso pelo código produzido por mais de uma pessoa, primeiro precisará ter consciência de todos e cooperação. Isso inclui desenvolvedores e gerentes.

Então, você precisa ter certeza de que conhece o escopo em que deseja fazer isso. Equipe? Projeto? Departamento? Companhia? Dependendo da resposta, o tipo de código que você colocará em tais soluções variará, assim como a granularidade com a qual você adapta as dlls. Depois de decidir sobre isso, alguém (de preferência com algum entusiasmo pela idéia - você?) Deve sentar-se e começar a colocar alguma estrutura nisso.

Apenas criar essas DLLs não será suficiente para fazer o truque. Para torná-los úteis, você precisará divulgá-los (para usuários e colaboradores) e mantê-los como qualquer outro software, o que geralmente significa que você precisa colocar alguém no comando por um longo tempo. Você também precisará de documentação confiável, que também precisará de manutenção. Com um pouco de sorte e cooperação, você pode ter algumas práticas recomendadas, mas também pode evoluir para um projeto próprio, dependendo do tamanho e do número de equipes envolvidas. E para isso você ainda precisará de suporte de gerenciamento.

Thomas
fonte
3

Eu já tive muitos problemas e minha solução preferida é postar o código em um repositório habilitado para web do github / pubic. resolve muitos problemas -

  1. acesso fácil e fácil de compartilhar. cvs / svn / enterprise-repos significa fazer check-out do projeto em vários espaços de trabalho do IDE e, às vezes, ter que trocar de espaços de trabalho ou computadores apenas para se referir a um pequeno trecho de código.
  2. supondo que esses trechos de código não sejam trechos de código proprietários / classificados e sejam variações do conhecimento publicamente disponível, publicá-los em um repositório público como o github significa que outras pessoas o analisam e podem até contribuir.
  3. postar algo em domínio público sob seu nome tem uma pressão adicional de reputação. você irá checar e atualizar as coisas, pois isso reflete em suas habilidades como programador.
  4. atualizações. a coisa sobre a manutenção de trechos de código em um repositório é que, se um trecho não for usado há muito tempo, poderá ficar obsoleto (conter APIs / libs desatualizadas). exemplo - trecho de código java para ler um arquivo. você pode ter descoberto a melhor maneira de fazer isso em 2009, mas em 2014 sai uma nova API de arquivo que muda tudo. seu trecho? ainda está preso em 2009. em um repositório público, as coisas serão atualizadas por você (como marcador 3), seus colegas de equipe ou algum membro da população geral de programadores e, no processo, você pode até receber sugestões para corrigir algo que você pode estar errado há muito tempo.

Uma coisa que eu recomendaria - não importa onde você mantenha seus trechos, sempre pesquise no Google antes de usá-lo. as coisas mudam o tempo todo. os snippets salvos economizam tempo, mas também geram complacência .

Quest Monger
fonte
2

Temos um projeto separado "utilitários", onde armazenamos todos esses pequenos métodos junto com testes.

Quando um projeto precisa de algum utilitário, ele apenas adiciona o arquivo de origem com o método necessário com "add as link".

Isso significa que não há dependências de tempo de execução adicionadas (a menos que o arquivo incluído precise de uma).

O sistema funcionou bem, mas como todos os outros, ele precisa discernir sobre o que é um utilitário. A solicitação de alta cobertura de teste funcionou bem para nós e os testes também são uma boa documentação de uso. A descoberta ainda é um problema não resolvido para nós.

Uma complexidade do projeto de utilidade é decidir o nível de visibilidade dos itens. Uma regra prática é que os métodos devem ser internos e as estruturas de dados públicas.

adrianm
fonte
2

Minha empresa usa serviços da Web locais da intranet. Temos alguns serviços da web configurados como serviços internos da web comuns e, quando outro projeto precisa acessar um dos serviços, ele envia uma solicitação http com uma interface definida. Como está na intranet, hospedada no mesmo farm de servidores, essas solicitações são muito rápidas.

Obviamente, isso funciona apenas com aplicativos da Internet (e funciona apenas em milissegundos quando na mesma rede local), mas possui algumas vantagens muito boas.

Ben Lee
fonte
0

Recentemente, criei este serviço: Snip2Code ( http://www.snip2code.com ).

É uma maneira interessante de compartilhar apenas seus snippets (não inteiramente de bibliotecas) com sua equipe. Ele quebra o ponto usual de criar bibliotecas comuns que devem ser referenciadas em outros projetos e, na minha opinião, essa é uma visão valiosa.

Além disso, existem muitos cenários em que o uso de uma biblioteca comum simplesmente não se aplica: vamos considerar, por exemplo, alguns padrões de design como Singleton, Strategy ou Observer. Você pode criar bibliotecas para suportar esses padrões, mas ainda não há 100% de cobertura.

A real necessidade é ter uma ferramenta para compartilhar práticas comuns entre a equipe. Tentei usar as essência do Github, mas estou preso à pesquisa delas (muito ruim) e ao fato de não poder compartilhá-las apenas entre minha equipe e não com outras ...

(Aviso: sou um dos fundadores do Snip2Code e estava - junto com meus co-fundadores - em sua mesma mentalidade há algum tempo: foi por isso que decidimos iniciar este projeto !!)

Cristiano Ghersi
fonte