Za kilka dni pojawi się nowa wersja Javy. Opatrzona numerkiem 21 i literkami LTS, jak Lej Te Setkie. Można świętować. Z tej okazji przypomniał mi się pewien ciekawy problem z jakim miałem do czynienia pewien czas temu. Uważam, że LLM nie odbiorą nam pracy. Wręcz tej pracy będzie więcej. Modele takie jak GPT3-4 potrafią robić za żółtą kaczuszkę. To ważna umiejętność. W dodatku robią to za darmo (no karmimy je kodem, ale to inna sprawa), więc jest taniej niż junior z aktywnym efektem D-K. Do brzegu jednak.

Kod, który napisałem

Był ok.

Listing 1. Proste przepisywanie strumieni

tuple->{
		int readLen;
		byte[] readBuffer = new byte[4096];
		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		while ((readLen = tuple._1().read(readBuffer)) != -1) {
		    outputStream.write(readBuffer, 0, readLen);
		}
		String content = outputStream.toString();
		outputStream.close();
		fileContentMap.put(tuple._2().getFileName().replace("dist/", ""), content);
		return tuple._2().getFileName();
    }

Mamy jakąś krotkę, w której siedzi sobie (Zip)InputStream i String. Chcemy ten plik wrzucić do mapy, w taki sposób, że nazwa pliku jest kluczem, a treść pliku jako String to wartość. Wrzuciłem powyższy kawałeczek kodu do ChatGPT i poprosiłem o optymalizację.

Listing 2. Wersja od ChatGPT z babolem

tuple->{
		try (InputStream inputStream = tuple._1();
		    ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
		    byte[] buffer = new byte[4096];
		    int bytesRead;
		    while ((bytesRead = inputStream.read(buffer)) != -1) {
		        outputStream.write(buffer, 0, bytesRead);
		    }
		    String content = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
		    fileContentMap.put(tuple._2().getFileName().replace("dist/", ""), content);
		    return tuple._2().getFileName();
		} catch (IOException e) {
		    // Handle the exception if needed
		    e.printStackTrace();
		    return null;
		}
    }

IMO, nie jest to idealne. Co prawda nie dałem mu szerszego kontekstu (zamykam to w vavrowski Try), ale nawet po poprawkach (wywalenie catch) wyglądało to średnio w kierunku kiepsko. W dodatku Chat wprowadził dość wrednego buga, który nie jest widoczny na pierwszy rzut oka, ale po porównaniu fragmentów kodu powinno być to jasne. Nie jest? Podpowiem, że w pierwszym przypadku nie zamykaliśmy IS, bo było to robiona później. Chat zamyka IS i później to się sypie.

Ale tutaj coś mnie tknęło. Nie jest możliwe, żeby kopiowanie strumieni wymagało napisania aż takiej ilości kodu. Zacząłem grzebać w dokumentacji IS i nagle okazało się, że można napisać „jednolinijkowca”:

Listing 3. Jednolinijkowiec

tuple->{
		try(ByteArrayOutputStream outputStream=new ByteArrayOutputStream()){
    		tuple._1().transferTo(outputStream);
	    	String content=new String(outputStream.toByteArray(),StandardCharsets.UTF_8);
		    fileContentMap.put(tuple._2().getFileName().replace("dist/",""),content);
		    return tuple._2().getFileName();
		}
    }

InputStream ma metodę transferTo, która robi wszystko, co potrzeba. Dla spokoju ducha odpaliłem testy i było OK. Plik skopiowany, strumień otwarty, zero potrzeb. Z ciekawości zapytałem Chat, czy potrafi zamienić pętle na stream API. Wynik był zaskakujący, bo zamiast mapowania i filtrowania dostałem kod podobny do powyższego. Oczywiście z bugiem. Po zwróceniu uwagi, dostałem „poprawiony kod”… dalej z bugiem. Ale to dopiero wstęp.

Aktualizacja wiedzy jest trudna

Pierwotny kod napisałem „z głowy”. Robiłem to kilka razy w życiu w różnych językach, ale mechanika była zawsze podobna. Wejście, tablica tymczasowa, wyjście, powtarzać do osiągnięcia EOF. Tak nauczyli mnie w szkole , tak pisałem w FORTRANie, tak to się pisało dawno temu w C, tak pisało się w Javie. Istnienie metody transferTo kołatało się raczej na zasadzie „to musi być prostsze” niż pewności „jest coś takiego”. W dodatku metoda została dodana już dawno temu. W Javie 9.

Wniosek 1

Ciężko jest aktualizować wiedzę na bieżąco. Ciężko też jest pamiętać o wszystkich zmianach, które zostały wdrożone po tym, jak zakończyłeś intensywną naukę. I nie jest to jakiś odkrywczy wniosek. Młodzi lekarze-radiolodzy lepiej rozpoznają zmiany na zdjęciach niż starsi koledzy. Po prostu są świeżo po praktykach i egzaminach, więc mają dużo większy „współczynnik przerobionego materiału”.

Wniosek 2

Używaj LLM do rozwoju swojego kodu. Każ mu robić code review, ale nie wierz ślepo w wyniki. Analizuj to co podpowie, bo może okazać się, że co prawda nie działa, ale zawiera wartościowe elementy.

Na koniec jeszcze jedno. Pamiętaj, że korporacje dostają sraczki, cholery, wścieklizny i pierdolca na raz, gdy chcesz użyć AI. Dlatego, zanim wrzucisz kod, to się zastanów. Bycie DOBRYM inżynierem jest cenniejsze niż użeranie się z jakimś idiotą, ale może być stresujące.