Czy Go jest szybszy od Javy? Nie to jest najważniejsze!
Często zdarza mi się trafiać na artykuły porównujące Javę z Go. Prawie zawsze w centrum uwagi jest szybkość wykonania, albo obecność lub brak konkretnych funkcji (są to zazwyczaj rzeczy nieobecne w Go, a powszechnie używane w Javie). A więc jeśli ktoś pisze, że Go jest świetne, to automatycznie wywołuje lawinę komentarzy na temat wyższości Javy - “według tego i tego testu porównawczego, Java jest o wiele szybsza (a poza tym ma typy ogólne oraz try-catch).
Potem przeglądasz "benchmark", który pokazuje, że Java jest szybsza, niż Go i widzisz ścianę komentarzy, w który ludzie krzyczą, że jest na odwrót. Zaraz zrobi nam się tutaj kolejna wojna religijna.
Zatrzymajmy się jednak na chwilę. Czy można ocenić, który język przyniesie więcej korzyści danej organizacji, produktowi czy projektowi?
Łatwość developmentu i utrzymania standardowych aplikacji biznesowych jest najważniejszym aspektem, jaki powinniśmy wziąć pod uwagę przy takim porównaniu. Oznacza to porównywanie na podstawie czegoś, co naprawdę się liczy - czyli jak wydajne jest tworzenie i utrzymywanie standardowego kodu aplikacji biznesowych.
Bo development i utrzymanie takich apek generuje większość kosztów. A więc to, jak łatwo się w czymś programuje i utrzymuje, powinno być w centrum każdej dyskusji na temat wyższości jednego języka nad innym.
Zacznijmy od faktów
Są takie rzeczy, które można spokojnie uznać za fakty, a nie opinie. Oto lista kilku z nich:
Fakt: Go tworzy mniejsze pliki wykonywalne i zużywa mniej pamięci
Obrazy Dockera, które zawierają pliki wykonywalne Go, są zazwyczaj mniejsze od ich odpowiedników w Javie. To istotne, jeśli w grę wchodzą optymalizacja zasobów infrastruktury, czy zmniejszenie czasu rozgrzewki, co ma znaczenie dla modelu FaaS.
Fakt: Go może utrzymywać wyższy poziom współbieżności
Go może z łatwością dostarczyć setki tysięcy goroutines, a wątki Javy mają o wiele większe ograniczenia. Jest to niezwykle ważne, jeśli chcemy jak najwięcej wycisnąć z naszych procesorów, zwłaszcza w kontekście pracy ograniczonej przez I/O.
Fakt: Java ma biblioteki, które można połączyć ze wszystkim
Aspekt ten w niektórych przypadkach może być decydujący. Jeśli chcesz połączyć się z menedżerami transakcji, takimi jak CICS albo TxSeries, to Java pozostaje jedyną opcją, jaką mamy. W Go nie ma do tego pakietów.
Fakt: więcej jest jednak programistów Javy
I tyle.
Fakt: Go ma prostszą składnię
Specyfikacja Go ma 86 stron, wliczając w to przykłady. W roku 2000 specyfikacja Javy miała już 250 stron, a od tamtego momentu rzeczy nie stawały się prostsze.
Fakt: hasło “write once run everywhere” nie ma już takiego znaczenia
Wraz ze zwiększającą się popularnością kontenerów, możesz dopisać tutaj jakikolwiek język i uruchomić go na Dockerze w dowolnym miejscu.
Fakt: Go zapewnia szybsze budowanie
Czy widzieliście kiedyś symbol ładowania na ekranie programisty Javy, który właśnie zaczął wykonanie zestawu testowego? Jeśli tak, to musicie wiedzieć, że nie zdarza się to raczej w przypadku Go.
Istnieją również fakty mniej oczywiste, które uważamy za opinie
Niestety (lub stety) życie nie jest czarno białe - są również odcienie szarości. Oto takie, które są istotne dla naszej dyskusji.
Opinia: Go ma zbyt duże ograniczenia dla poważnego developmentu aplikacji
W Go nie ma typów ogólnych oraz try-catch. Można się spotkać z opinią, że nie napiszesz poważnego kodu aplikacji biznesowej bez powyższych funkcji. Kończy się to niestety powtarzaniem ciągle tego samego kodu.
Opinia: Java stała się zbyt złożona
Kontrargument: w Javie masz obiektowość, programowanie aspektowe dzięki adnotacjom, programowanie funkcyjne (nawet jeśli wygląda trochę niechlujnie) oraz takie frameworki jak Spring.
Niektórzy twierdzą, że to, jak rozwiniesz swoją logikę, zależy od Twojego porannego nastroju. Możesz używać różnych stylów i namieszać w kodzie, sprawiając, że aplikacja będzie o wiele cięższa do utrzymania.
Opinia: Go jest do programowania systemowego
Prawdą jest, że Go jest raczej wykorzystywane przy tworzeniu np. Dockera, czy Kubernetesa. Nie ma jednak wyraźnego powodu, dla którego musimy z tego języka rezygnować w przy budowaniu apek biznesowych. No, chyba że znowu zaczniemy przytaczać argumenty z typami ogólnymi i try-catch.
Właściwie to trzeba tutaj zapytać, w którym języku wydajniej się programuje i łatwiej utrzymuje rzeczy
Każdy z tych języków ma swoje wady i zalety. Decyzja wymaga jednak kontekstu. Mamy taki scenariusz: jakaś firma rozwija takie rozwiązania biznesowe, jak aplikacje bankowe lub inne systemy zarządzania.
W takich przypadkach dwa elementy, które najbardziej przyczyniają się do wzrostu kosztów, to nakład pracy związany z developmentem i utrzymaniem. W niektórych przypadkach możemy też brać pod uwagę koszty wymaganej infrastruktury.
Oto więc elementy, które należy rozważyć, chcąc podjąć racjonalną decyzję co do technologii, której będziemy używać.
Nakład pracy związany z developmentem i utrzymaniem
To w większości przypadków najważniejszy czynnik. Czy mniej kosztuje development i utrzymanie aplikacji, którą piszemy w Go, czy w Javie?
Ograniczenie początkowej inwestycji
Zacznijmy od początku. Jeśli jesteśmy firmą, w której dominującą technologią jest Java (tak jak w większości), to myślimy tak: znasz Javę, więc będziesz bardziej wydajny/wydajna w Javie”. Z drugiej jednak strony, prostota Go mocno się przydaje.
Prostota oznacza, że łatwo się czegoś nauczyć. Jeśli umiemy kodować, to w kilka dni będziemy w stanie pisać kod produkcyjny w Go. Nie będzie on jakoś bardzo złożony, ale będzie wystarczająco dobry.
Rozumując w ten sam sposób, możemy powiedzieć, że nie umiejąc kodować, to i tak mamy duży problem, niezależnie od języka.
Podsumowując, ze względu na swoją prostotę, możesz tutaj użyć Go, nawet jeśli głównie używasz Javy.
Czy Go jest proste, czy liche?
Go jest proste, ale można też je postrzegać jako dość liche. Już wspominaliśmy, że nie ma tam typów ogólnych, a obsługa błędów może być rozwlekła. Nie ma tam klas jako takich oraz dziedziczenia - można stwierdzić, że brak tych funkcji zmniejsza produktywność.
Z drugiej jednak strony, Go nie jest zbyt elastyczne - jedną rzecz zrobisz tylko w jeden sposób. Twórcy Go określają to mianem ortogonalności. Jeśli istnieje tylko jeden sposób na rozwiązanie problemu, to nie musimy myśleć jakiego stylu użyć. Jeśli mamy tylko jeden sposób na rozwiązanie problemu, to łatwiej będzie czytać kod napisany przez kogoś innego.
Są badania, które wskazują na to, że więcej czasu spędzamy, czytając kod (nasz lub kogoś innego) niż pisząc go. Jeśli to prawda, to prostota jest tutaj kluczowa dla zoptymalizowania wydajności.
Warto jest poeksperymentować z Go
Jeśli Go jest taki prosty, to dlaczego nie zainwestować w jego użycie?
Jeśli Go jest prosty i niezbyt rozbudowany, to development i utrzymanie aplikacji biznesowej przy jego użyciu może być prostsze i bardziej wydajne. Jeśli cykle budowania i testów przebiegają szybciej, to developerzy nie będą już musieli ciągle patrzeć, jak coś się godzinami ładuje.
Jeśli obsługa współbieżności w Go jest taka dobra, to będziemy mogli znacznie więcej wyciągnąć z naszej infrastruktury, zwłaszcza w scenariuszach, gdzie ogranicza nas I/O.
Podsumowując, jest możliwe, że tworzenie aplikacji biznesowych za pomocą Go może przynieść znaczną poprawę w zakresie ogólnej wydajności funkcji IT.
Wszystko oczywiście zależy od kontekstu, ale korzyści wynikające z przeniesienia się na Go są bardzo prawdopodobne. Powiedziałbym, że warto z tym językiem poeksperymentować. Musimy tylko wybrać odpowiedniego kandydata do projektu, stworzyć zespół, podszkolić się trochę i sprawdzić, czy skutki są pozytywne.
To inwestycja i, jak każda inwestycja, wiąże się to z pewnym ryzykiem, ale może również przynieść korzyści. Śledź wyniki i zdecyduj, czy kontynuować, czy może lepiej przestać.
Jaką decyzję powinniśmy więc podjąć?
Czy warto spróbować z Go w kontekście biznesowym? Podsumujmy cały artykuł jednym algorytmem, który napiszemy oczywiście w Go:
func DecideIfTryGo() Outcomes {
// check for showstoppers (g.g. CICS integration) in my environment
showstopper := os.Getenv("SHOWSTOPPERS")
// if there are showstoppers there is no point to try Go
if showstopper != "" {
return errors.New(showstopper)
}
// find a good candidate project considering Go characteristics
project := FindProject("concurrent", "IOBound", "InfraEfficiency")
// create a team
team := NewTeam(project)
// do a bit of training
TrainTeam(team)
// launch the project with a timeout
ctx, cancel = context.WithTimeout(context.Background(), timeout)
outcomes := Launch(ctx, project)
// return the outcomes
return outcomes
}
Podsumowanie
Artykuł ten skupia się na Go i Javie, ale powyższe rozważania można dopasować do każdej technologii. Można więc wstawić tutaj dowolne języki, o ile porównujemy je na podstawie tego, co naprawdę ma znaczenie. Warto też sobie uświadomić, że kontekst naprawdę ma znaczenie.
Oryginał tekstu w języku angielskim przeczytasz tutaj.