Quais são algumas maneiras de manter as bases de código escritas em duas linguagens que implementam a mesma lógica?

10

Eu tenho um algoritmo lógico intensivo que preciso codificar em dois idiomas (na verdade, terminei satisfatoriamente em um idioma e estou prestes a começar a codificar no outro idioma). Por lógica intensiva, quero dizer que o algoritmo não é trivial, precisa de compreensão cuidadosa e, o que é mais importante, pode estar tendo bugs (devido à complexidade e descuido, você sabe) que precisariam ser corrigidos no futuro.

Além disso, quero ter certeza de que, quando esse código mudar de mãos, eventualmente, ele não deve sobrecarregar os novos programadores.

Diante desse cenário, de que maneiras algumas ajudariam a manter as bases de código e mantê-las sincronizadas? Por formas, quero dizer ferramentas de software, práticas recomendadas etc.

Para sua informação, as duas linguagens são C ++ e Java. C ++ para Windows / Linux e Java para "tudo o resto", incluindo Android.

vin
fonte
3
Você realmente precisa implementá-lo em outro idioma? Por que não usar apenas Java?
26712 Oleksi
@Oleksi O código é melhor quando executado de forma nativa, então o Java era apenas um compromisso em que o C ++ não pode ser usado.
vin
13
Apenas tenha certeza absoluta de que você precisa desse desempenho. Manter duas versões de um programa (especialmente uma deste complexo) é um esforço colossale. Certifique-se de fazer absolutamente isso em C ++, porque você pagará um custo enorme em tempo e esforço para fazer isso em dois idiomas.
26712 Oleksi
9
Como @Oleksi disse - se for executado de forma aceitável em Java em um Driod, não consigo imaginar que, como o PC precise das melhorias (provavelmente marginais) que o C ++ oferecerá. Como você não declarou que executou testes de desempenho, presumo que não; nesse caso, isso fede a otimização prematura. Escreva em Java, execute testes de desempenho, otimize o Java. Somente então considere uma reescrita em C ++ - o tempo economizado para manter uma base de código, em vez da optimalation, quase certamente manterá duas bases de código, dois conjuntos de tudo (exceto requisitos).
mattnz
A definição @thePrivateProject funciona melhor , em ambos os casos (C ++ ou Java) o código bem escrito deve ser portátil .

Respostas:

16

Resposta curta: não faça isso a menos que seja absolutamente forçado.

Se você precisar usar C ++, considere usar o NDK para criar seu algoritmo para Android em C ++ e, em seguida, adicione um wrapper Java fino para a interface do usuário. Observe que o uso do NDK significa que seu código é muito menos portátil para diferentes tipos de hardware. Definitivamente, não é preferível usar Java em qualquer lugar, mas é melhor do que ter duas bases de código.

Se você absolutamente não pode fazer isso e precisa ter duas bases de código, aqui estão três sugestões:

1) Procure uma ferramenta como o Unity voltada para o software portátil.

2) Tente inserir os bits complexos do código em dados ou em alguma linguagem de script. Se você pode escrever um código bastante genérico para lidar com a linguagem de script, é mais fácil testar e acertar duas vezes. (Especialmente se for um idioma padrão criado por outra pessoa.) Então você pode ter uma base de código para os bits complexos. (Você pode experimentar o Lua, que é voltado para a incorporabilidade.)

3) Como a outra resposta indica, crie um conjunto de testes para validar os dois conjuntos de códigos. Note que isso é realmente difícil de acertar. Tendo feito exatamente isso, posso dizer que isso se deve a muitos debates sobre qual versão é "correta", especialmente em casos de erro.

(2) e (3) podem ser usados ​​juntos.

Gort the Robot
fonte
4
Bons pontos. Outra coisa a se pensar é escrever um conjunto de testes de regressão e testar as duas implementações com ele (por exemplo, via SWIG).
James Youngman
15

Crie um único conjunto de testes externo que garanta que ambas as bases de código se comportem da mesma maneira. Eu coloco uma ênfase extra na palavra "único" porque, caso contrário, você terá que manter dois conjuntos de testes que podem diferir em suas afirmações. Não tenho sugestões de como fazer isso, mas parece ser uma maneira de manter sua sanidade (e de futuros desenvolvedores) ao trabalhar nesse tipo de base de código.

Jeremy Heiler
fonte
4

você pode usar uma linguagem que pode ser compilada em código de máquina e código de byte java, transformando primeiro em java e C ++ ou diretamente. A última vez que verifiquei que o LLVM possui back-ends para ambos

edit: um pouco de navegação wiki me levou ao GCJ, que pode compilar java para código de máquina

catraca arrepiante
fonte
4

Na minha opinião, a regra mais importante para um programador é "Não se repita". O que você sugere é uma clara violação desta regra.

Eu seriamente sugiro que você encontre uma maneira de implementar o algoritmo apenas uma vez. Atualmente, posso pensar em duas abordagens diferentes.

  • Use um idioma específico do domínio. Talvez o algoritmo possa ser melhor expresso em uma linguagem diferente, por exemplo, uma linguagem de script, para a qual possa existir um analisador em todas as plataformas em que você espera executar o aplicativo ou gerar código C ++ / Java com base no código DSL.

  • Escreva tudo em C ++. O C ++ pode ser compilado em praticamente qualquer plataforma. Se em algumas plataformas você precisar que o aplicativo principal seja escrito em Java, acho que é possível chamar uma biblioteca nativa (não tenho muito conhecimento em Java, mas presumo que isso possa ser feito).

Manter o mesmo algoritmo em duas plataformas diferentes só pode causar problemas e problemas.

Pete
fonte
Suponho que por sua opinião deve haver um sistema operacional, no terno de produtividade de escritório, um vídeo pacote de software jogador ........
mattnz
11
@mattnz - Você entendeu completamente meu argumento. Estou me referindo ao princípio de programação de "DRY". Esse princípio de forma alguma sugere que deve haver apenas um sistema operacional, suíte de escritório etc. Você pode produzir facilmente um produto para várias plataformas enquanto adere ao DRY.
Pete
2

Além do excelente conselho para usar um conjunto de testes externo comum, convém analisar a programação alfabética . As ferramentas de programação alfabetizadas permitem produzir vários arquivos a partir de um único arquivo de origem.

O uso tradicional do LP é permitir intercalar a documentação com o código de uma maneira que permita manter a documentação muito próxima do código-fonte. Um único arquivo noweb (por exemplo) pode ser usado para gerar um arquivo de documentação que pode ser compilado em um documento maior usando (digamos) LaTex, e produzir um arquivo .cppe .hque pode ser compilado em seu aplicativo.

No seu caso, pode permitir que você mantenha as bases de código e a documentação juntas, produzindo um .javaarquivo também.

Manter as versões de código de documentação e diferentes juntos em um único arquivo, divididos em seções logicamente equivalentes, deve torná-lo muito mais fácil para mantê-los todos em sincronia uns com os outros.

Mark Booth
fonte
2

Este é um bom exemplo de onde os testes podem ser úteis.

Gostaria de sugerir ter um único conjunto de testes que tanto a sua base de código executado contra. Então você sabe que suas bases de código estão em conformidade com a mesma especificação!

(e, tenha uma boa cobertura de teste!)


fonte
1

Considere o código que gera C ++ e Java a partir de alguma outra linguagem

Nick Keighley
fonte
0

aviso Legal

Como mencionado nas postagens anteriores, se você realmente não tem outra opção, então.

Responda

Várias sugestões práticas, em vez de uma única resposta:

(1) Use estruturas comuns, mesmo, se as mesmas coisas puderem ser diferentes.

Exemplo: eu precisava ter o mesmo código em "Object Pascal" e "C ++", onde a sentença "if" existe em ambos, o parêntese em "C ++" é necessário, mas não no "objeto Pascal".

// Object Pascal
...
if MyBollExpression
begin
  ...
end;
...

// C++
...
if (MyBollExpression)
{
  ...
}
...

Alterado para:

// Object Pascal
...
if (MyBollExpression)
begin
  ...
end;
...

// C++
...
if (MyBollExpression)
{
  ...
}
...

Parênteses adicionados aos dois idiomas. Outro caso serão os namespaces opcionais versus os namespaces necessários ("pacotes").

(3) Mantenha nomes de identificadores, distinção entre maiúsculas e minúsculas, especialmente tipos, similares, use aliases, subclassificação e empacotamento:

// Java
// 
import java.io.*;

...
System.out("Hello World\n");
...

// C++
// 
include <iostream>

...
cout << "Hello World\n";
...

Para dentro:

// Java
// 
import java.io.*;

static class ConsoleOut
{
   void Out(string Msg)
   {
     System.out("Hello World\n");
   }
}

...
ConsoleOut MyConsole = new ConsoleOut();
...
MyConsole.out("Hello World\n");
...

// C++
// 
include <iostream>

public class ConsoleOut
{
   void Out(string Msg)
   {
     cout << "Hello World\n";
   }
}

...
ConsoleOut MyConsole = new ConsoleOut();
...
MyConsole.out("Hello World\n");

...

Sumário

Normalmente, tenho que trabalhar com várias linguagens de programação e existem algumas bibliotecas "principais" personalizadas, que mantenho em várias linguagens de programação.

Boa sorte.

umlcat
fonte