Eu acho que na verdade são duas perguntas em uma - tentarei responder as duas.
1) Como reduzimos o código duplicado em uma base de código.
Isso ajuda a lembrar o benefício de fazer isso: resulta em menos erros devido à duplicação da lógica de negócios e menos código precisa ser mantido. A melhor maneira de impedir que isso aconteça é através da comunicação - conforme mencionado nas outras respostas. Concordo plenamente com a recomendação de usar as revisões de código com a ressalva de que você deve compartilhar as responsabilidades de revisão de código igualmente para espalhar o conhecimento adequadamente. Você também deve usar stand-ups diários para que os desenvolvedores frequentemente reconheçam quando alguém está tentando resolver um problema para o qual existe um código útil. Você também deve considerar o emparelhamento de código, pois aumenta o compartilhamento de conhecimento e ajuda a manter os programadores disciplinados.
Também recomendo que seus desenvolvedores fiquem o mais próximos possível, de preferência na mesma sala. Com muitos quadros compartilhados e espaço. Depois, envie-os para as refeições juntos. Quanto mais seus desenvolvedores se "vincularem", melhor eles se comunicarão.
Não concordo com a recomendação de usar um wiki ou semelhante ao código do documento. Não importa o quanto os desenvolvedores disciplinados tentem ser a documentação se afastará do código original. Uma abordagem mais eficaz seria o uso da especificação por testes de estilo de exemplo. Eles documentam o código de uma maneira que deixa claro como ele deve ser usado e seus testes falharão se alguém alterar o código sem alterar os exemplos.
Você já possui uma grande base de código com muito código duplicado; portanto, provavelmente deve trabalhar na refatoração disso. Pode ser difícil encontrar código duplicado que não foi recortado e colado. Então, em vez de fazer isso, sugiro que você analise seu histórico de alterações. Procure arquivos que frequentemente mudam ao mesmo tempo. Provavelmente isso indicará problemas com o encapsulamento, se não indicar o código duplicado real e vale a pena limpá-lo de qualquer maneira. Se você também pode analisar seu histórico de correção de bugs com relação às alterações de código, poderá encontrar pontos de acesso específicos, onde as correções são frequentemente necessárias. Analise esses pontos de acesso e provavelmente descobrirá que muitos deles se devem à lógica de negócios duplicada, que um desenvolvedor mudou apenas em um local, sem perceber que precisava mudar duas vezes.
2) Como devemos abordar a criação de widgets, componentes, bibliotecas, etc compartilhados, que podem ser usados em outros projetos ?
Nesse caso, você não deve tentar quebrar a lógica de negócios, mas compartilhar um código de estrutura útil. Esse pode ser um equilíbrio complicado, pois o custo de criação e manutenção de um conjunto de componentes compartilhados pode ser bastante grande e pode ser difícil prever em quais casos vale a pena fazê-lo. A abordagem que eu sugiro aqui é uma regra de três greves. Não se preocupe em escrever um código semelhante duas vezes, mas quando precisar fazê-lo pela terceira vez refatorá-lo em um componente compartilhado. Nesse ponto, você pode ter certeza razoável de que será útil e ter uma boa idéia dos requisitos mais amplos do componente. Obviamente, a comunicação entre desenvolvedores é vital aqui.
Considere criar o maior número possível de código aberto do seu componente compartilhado. Não é uma lógica de negócios, portanto não dará muita vantagem aos seus concorrentes, mas significa que você receberá revisores e mantenedores extras gratuitamente.