Jakie są sposoby utrzymywania baz kodu napisanych w dwóch językach, które implementują tę samą logikę?

10

Mam algorytm intensywnie logiczny, który muszę kodować w dwóch językach (właściwie ukończyłem go w jednym języku zadowalająco i mam zamiar zacząć kodować w innym języku). Przez intensywną logikę rozumiem, że algorytm nie jest trywialny, wymaga starannego zrozumienia i, co ważne, może zawierać błędy (z powodu złożoności i nieostrożności, wiesz), które będą musiały zostać załatane w przyszłości.

Chcę też upewnić się, że kiedy ten kod zmieni ręce, ostatecznie nie może przytłoczyć nowych programistów.

Biorąc pod uwagę ten scenariusz, jakie są sposoby na utrzymanie baz kodowych i synchronizację? Rozumiem przez to narzędzia programowe, najlepsze praktyki itp.

FYI dwa języki to C ++ i Java. C ++ dla Windows / Linux i Java dla „wszystkiego innego”, w tym Androida.

vin
źródło
3
Czy naprawdę musisz to zaimplementować w innym języku? Dlaczego nie użyć tylko Java?
Oleksi
@Oleksi Kod jest najlepszy, gdy działa natywnie, więc Java była tylko kompromisem, w którym nie można używać C ++.
vin
13
Po prostu upewnij się, że potrzebujesz tej wydajności. Utrzymanie dwóch wersji programu (szczególnie tej złożonej) jest ogromnym wysiłkiem. Upewnij się, że absolutnie musisz to zrobić w C ++, ponieważ będziesz musiał ponieść ogromny koszt czasu i wysiłku, aby to zrobić w dwóch językach.
Oleksi
9
Jak powiedział @Oleksi - jeśli działa poprawnie w Javie na Driod, nie mogę sobie wyobrazić, że skoro PC potrzebuje (prawdopodobnie marginalnych) ulepszeń, które da C ++. Ponieważ nie powiedziałeś, że przeprowadziłeś testy wydajności, zakładam, że nie, w którym to przypadku śmierdzi przedwczesna optymalizacja. Pisz w Javie, uruchamiaj testy wydajności, optymalizuj Javę. Tylko wtedy rozważ przepisanie w C ++ - zaoszczędzony czas na utrzymanie jednej bazy kodu, zamiast tego zoptymalizowanej, prawie na pewno wykona utrzymanie dwóch baz kodu, dwóch zestawów wszystkiego (oprócz wymagań).
mattnz
@ thePrivateProject-Define działa najlepiej , w obu przypadkach (C ++ lub Java) dobrze napisany kod powinien być przenośny .

Odpowiedzi:

16

Krótka odpowiedź: nie rób tego, chyba że jest absolutnie zmuszony.

Jeśli musisz użyć C ++, możesz rozważyć użycie NDK do zbudowania algorytmu dla Androida w C ++, a następnie dodanie cienkiego opakowania Java dla interfejsu użytkownika. Zauważ, że użycie NDK oznacza, że ​​Twój kod jest znacznie mniej przenośny dla różnego rodzaju sprzętu. Nie jest to zdecydowanie lepsze niż używanie Javy wszędzie, ale lepsze niż posiadanie dwóch baz kodu.

Jeśli absolutnie nie możesz tego zrobić i musisz mieć dwie bazy kodu, oto trzy sugestie:

1) Poszukaj narzędzia takiego jak Unity ukierunkowanego na oprogramowanie przenośne.

2) Spróbuj wciągnąć złożone fragmenty kodu do danych lub innego języka skryptowego. Jeśli potrafisz napisać dość ogólny kod, aby poradzić sobie z językiem skryptowym, łatwiej jest go przetestować i uzyskać poprawność dwa razy. (Zwłaszcza jeśli jest to standardowy język stworzony przez kogoś innego.) Następnie możesz mieć jedną bazę kodu dla złożonych bitów. (Możesz wypróbować Luę, która jest nastawiona na osadzanie).

3) Jak wynika z drugiej odpowiedzi, utwórz zestaw testowy, aby sprawdzić poprawność obu zestawów kodów. Zauważ, że naprawdę trudno to naprawić. Po wykonaniu dokładnie tego mogę powiedzieć, że wymaga to wielu debat na temat tego, która wersja jest „odpowiednia”, szczególnie w przypadkach błędów.

(2) i (3) mogą być używane razem.

Gort the Robot
źródło
4
Słuszne uwagi. Inną rzeczą do przemyślenia jest napisanie jednego zestawu testów regresji i przetestowanie z nim obu implementacji (np. Przez SWIG).
James Youngman
15

Zbuduj pojedynczy zewnętrzny zestaw testów, który zapewni, że obie bazy kodu zachowają się w ten sam sposób. Kładę szczególny nacisk na słowo „singiel”, ponieważ w przeciwnym razie będziesz musiał zachować dwa zestawy testów, które mogą różnić się pod względem twierdzeń. Nie mam żadnych sugestii, jak to zrobić, ale wydaje się, że jest to jeden ze sposobów na zachowanie rozsądku (i przyszłych programistów) podczas pracy z tego rodzaju bazą kodu.

Jeremy Heiler
źródło
4

możesz użyć języka, który można skompilować w kod maszynowy i kod bajtu java, najpierw przekształcając w java i C ++ lub bezpośrednio. Ostatnio sprawdziłem, że LLVM ma back-endy dla obu

edycja: trochę surfowania po wiki doprowadziło mnie do GCJ, który może skompilować java do kodu maszynowego

maniak zapadkowy
źródło
4

Moim zdaniem najważniejszą zasadą dla programisty jest „Don't Repeat Yourself”. Sugerujesz wyraźne naruszenie tej zasady.

Poważnie sugerowałbym, aby znaleźć sposób na wdrożenie algorytmu tylko raz. Obecnie mogę wymyślić dwa różne podejścia.

  • Użyj języka specyficznego dla domeny. Być może algorytm można lepiej wyrazić w innym języku, np. Języku skryptowym, dla którego analizator składni mógłby istnieć na wszystkich platformach, na których spodziewasz się uruchomić aplikację, lub wygenerować kod C ++ / Java na podstawie kodu DSL.

  • Napisz wszystko w C ++. C ++ można skompilować na praktycznie każdej platformie. Jeśli na niektórych platformach wymagasz, aby główna aplikacja była napisana w Javie, zgaduję, że można wywołać rodzimą bibliotekę (nie znam się na Javie, ale zakładam, że da się to zrobić).

Utrzymanie tego samego algorytmu na dwóch różnych platformach może prowadzić tylko do bólu i błędów.

Pete
źródło
Sądzę, że według ciebie powinien istnieć jeden system operacyjny, na biurowym kombinezonie produkcyjnym, jeden pakiet oprogramowania odtwarzacza wideo ........
Mattnz
1
@mattnz - Całkowicie źle zrozumiałeś mój punkt widzenia. Mam na myśli zasadę programowania „DRY”. Ta zasada w żaden sposób nie sugeruje, że powinien istnieć tylko jeden system operacyjny, pakiet biurowy itp. Możesz łatwo stworzyć produkt dla wielu platform, pozostając przy DRY.
Pete
2

Oprócz doskonałej porady dotyczącej korzystania ze wspólnego zewnętrznego zestawu testów , warto przyjrzeć się umiejętności programowania . Kompetentne narzędzia programistyczne dają możliwość tworzenia wielu plików z jednego pliku źródłowego.

Tradycyjnym zastosowaniem LP jest umożliwienie przeplatania dokumentacji z kodem w sposób, który pozwala zachować dokumentację bardzo blisko kodu źródłowego. Pojedynczy plik noweb (na przykład) może zostać wykorzystany do wygenerowania pliku dokumentacji, który można skompilować do większego dokumentu przy użyciu (powiedzmy) LaTex, i wygenerować plik .cppand .h, który mógłby zostać skompilowany do twojej aplikacji.

W twoim przypadku może to pozwolić zachować razem zarówno podstawy kodu, jak i dokumentację, tworząc również .javaplik.

Utrzymanie dokumentacji i różnych wersji kodu w jednym pliku, podzielonym na logicznie równoważne sekcje, powinno znacznie ułatwić synchronizację ich wszystkich.

Mark Booth
źródło
2

To dobry przykład tego, gdzie testy mogą być pomocne.

Proponuję o pojedynczy zestaw testów, które zarówno baza kodu uruchomić przeciw. Wtedy wiesz, że obie bazy kodu są zgodne z tą samą specyfikacją!

(i, mieć dobry zasięg testu!)


źródło
1

Rozważ kod generujący C ++ i Java z innego języka

Nick Keighley
źródło
0

Zrzeczenie się

Jak wspomniano w poprzednich postach, jeśli tak naprawdę nie masz innego wyboru, to.

Odpowiedź

Kilka praktycznych sugestii zamiast jednej odpowiedzi:

(1) Użyj wspólnych struktur, nawet jeśli te same rzeczy można zrobić inaczej.

Przykład: Musiałem mieć ten sam kod w „Object Pascal” i „C ++”, gdzie zdanie „if” istnieje w obu przypadkach, wymagany jest nawias w „C ++”, ale nie w „object Pascal”.

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

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

Zmienić na:

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

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

Dodano nawias do obu języków. Innym przypadkiem będą opcjonalne przestrzenie nazw kontra wymagane przestrzenie nazw („pakiety”).

(3) Zachowaj nazwy identyfikatorów, rozróżniaj wielkość liter, typy specjalne, podobne, używaj aliasów, podklasy, zawijania:

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

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

// C++
// 
include <iostream>

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

W:

// 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");

...

Podsumowanie

Zwykle muszę pracować z kilkoma językami programowania i istnieje kilka niestandardowych bibliotek „podstawowych”, które przechowuję w kilku językach programowania.

Powodzenia.

umlcat
źródło