Zawodem szczególnie podatnym na zastąpienie przez AI miałby być zawód programisty. Tak przynajmniej można ostatnio usłyszeć i przeczytać w różnych mediach. Zastanówmy się, czy tak naprawdę jest. Bo przecież AI może wygenerować śliczny kod programu na podstawie opisu, co ten program ma robić. Może, prawda? Prawda?
Zacznijmy od tego, że mówimy o kodowaniu, czyli pisaniu tekstu, który po przekształceniu jest wykonywany przez komputer - aktualna AI nie potrafi przecież nic innego niż generowanie tekstów. Tyle że nawet gdyby AI naprawdę wygenerowała nam śliczny i bezbłędny kod, to i tak nie eliminuje to zawodu programisty, a co najwyżej kodera. Programowanie to cały proces, kodowanie to tylko jeden, najmniejszy jego etap. Programowanie z kodowaniem utożsamiają tylko ludzie nie mający o tym pojęcia, co bardziej amatorscy programiści-amatorzy i może jeszcze jakieś dziadowskie firmy programistyczne.
Na przykład u mnie w branży automotive przy tworzeniu oprogramowania obowiązuje norma ISO26262, definiująca proces zwany V-Model. Na obrazku wygląda to tak:
Zauważmy, że w tym modelu kod źródłowy (czyli właśnie kodowanie) jest na samym dole diagramu, i nie przypadkiem jest to V-model (ze szpicem w dół), a nie na przykład Λ-model (ze szpicem w górę). Kodowanie jest po prostu najmniej istotnym elementem procesu. Nawet gdyby udało się je całkowicie wyeliminować, pozostałą większość roboty i tak będzie musiał zrobić no kto? Żywy programista oczywiście.
Teraz drugi problem. Załóżmy, że AI naprawdę wygeneruje nam dobry kod, kiedy jej powiemy co ten kod ma robić. W sumie żywemu programiście też musimy powiedzieć, co ten kod ma robić. I tak typowo to nie mówimy mu tego, tylko piszemy w formie requirementów. I tych requirementów do uwzględnienia zawsze trochę jest. Na szczęście nie musimy specyfikować każdego najdrobniejszego szczegółu, bo ten programista taki całkiem głupi nie jest, i z grubsza będzie rozumiał dlaczego pewne rzeczy mają być zrobione tak, a nie inaczej (bo przecież sam jeździ samochodem), zajrzy do dokumentacji procesora (i do erraty też), będzie znał ograniczenia użytej platformy (albo o to zapyta), itp. itd. Inaczej mówiąc: będzie korzystał ze swojej i innych wiedzy o świecie.
No ale AI, jak już wiemy z poprzedniego odcinka, nie ma wiedzy o świecie. I w związku z tym specyfikacja dla niej musi być o wiele bardziej szczegółowa niż dla programisty. I w którymś momencie to przestanie mieć sens - jeżeli będziemy musieli pokazać AI paluszkiem każdy szczegół, to po jaką cholerę nam takie AI? Szybciej napiszemy to sami, bez kombinowania z tłumaczeniem (nawiasem mówiąc tak samo bywa z żywymi programistami, sytuacja że lepiej napisać samemu niż komuś tłumaczyć nie jest znowu taka rzadka). I jakoś o podobnym przypadku już pisałem przy marzeniu lat 60-tych, czyli "dowodzeniu poprawności programów": Jeżeli wyspecyfikujemy nasz program bardzo dokładnie, to w zasadzie powinno dać się z tego zrobić implementację, nawet bez AI.
Kolejny problem z requirementami jest taki, że tak normalnie to one powinny przychodzić od klienta. Tyle że klient bardzo często:
- Sam nie wie, czego właściwie chce.
- Przekopiował requirementy z wcześniejszego projektu, a tu niezupełnie pasują.
- Nie zauważył sprzeczności w requirementach.
- Nie znał ograniczeń sprzętu.
- Sam nie rozumie, co właściwie napisał.
- itp. itd.
Teoretycznie wszystkie takie problemy powinno dać się wyłapać zanim dojdzie do kodowania, ale to jest naprawdę tylko teoria. Zależności jest zbyt wiele, żeby tak się dało przy rozsądnym nakładzie pracy. W praktyce wcale nie tak rzadko programista przy kodowaniu musi sprawdzać, co poeta miał na myśli na którymś w wyższych etapów V-modelu, i czy na pewno jest pewny. (Dygresja: po niemiecku "poezja" to "Dichtung", tak samo jak "uszczelka", co pozwala konstruować mnóstwo bardzo suchych sucharów na takie tematy). Jakoś nie za bardzo potrafię wyobrazić sobie AI pytające autora inputu o uszczegółowienie albo uściślenie, to tak nie działa, tego ona nie potrafi.
Jest w tym wszystkim kolejny aspekt: To nie jest tak, że napiszemy kod raz a dobrze, i tak on zostanie na wieki. Zawsze wkrótce okazuje się, że coś trzeba tam jednak zrobić inaczej, wcale niekoniecznie dlatego, że nasz kod jest zły. Gdy piszemy ręcznie, poprawiamy te parę linii, aktualizujemy specyfikację tych paru testów, robimy nowe testy zmienionego kawałka i już. Tymczasem przy AI musimy kazać jej wygenerować całość od nowa, a ona jest niedeterministyczna z założenia i wygeneruje nam całkiem nowy kod, całkiem inny niż poprzedni. No i lokalność zmiany szlag trafia, trzeba od nowa robić pełne testy całości, review kodu (full, nie tylko delta), certyfikację, czy co tam jeszcze jest wymagane. Jeżeli norma wymaga pokrycia testami wszystkich branchy w kodzie, to musimy mocno pozmieniać nasze testy. I tak dalej, i tak dalej. Przecież z czymś takim nie da się pracować, to generuje więcej roboty niż było bez tego.
Oczywiście moglibyśmy generować z AI raz, a potem poprawiać w kodzie generowanym. Tyle że to nie za wiele daje - wtedy musimy analizować nie swój kod. I po kilku poprawkach i tak kod będzie w sporym stopniu nasz, nie AI. I wtedy po co nam to AI? Współczesne IDE generują nam szkielety zawartości nowych plików kodu i mogą wtykać snippety kodu w żądane miejsca, i to robić to deterministycznie - na cholerę nam bawić się w analizę intencji AI?
A już całkowicie pomijam fakt, że taki AI generator kodu absolutnie nie da się certyfikować na safety, głównie ze względu na jego indeterminizm. A w szczególności nie da się spełnić wymagań normy ISO26262 dla narzędzi programistycznych. Znaczy każdy safety-relevant kod wygenerowany przez AI musi przejść pełny review.
Teraz napiszę kontrowersyjną rzecz: Cała historia informatyki to historia walki o zastąpienie kodowania przez programistę generacją kodu. Było to tak:
- Na początku komputery programowało się wpisując kody rozkazów do pamięci przy pomocy klawiatury binarnej, a później ósemkowej. Mi też się kiedyś coś podobnego zdarzyło (tyle że bez tej klawiatury), to był prawdziwy hardkor, tak się nie da pracować z kodem dłuższym niż parędziesiąt rozkazów.
- Dlatego wymyślono assembler. Już nie potrzeba było hardkorowego kodera, każdy głupi mógł wpisać tekstowo op-cody rozkazów i program już działał. No ale tu też przy większych programach zaczęły się problemy z ogarnięciem kodu. (Zauważmy, że assembler jest de facto generatorem kodu - na podstawie tekstu generuje kod maszynowy)
- Dlatego do assemblera dodano makra, tworząc makroassembler. Teraz każdy głupi mógł sobie radykalnie skrócić program używając makrosów. No ale tu też przy większych programach zaczęły się problemy z ogarnięciem kodu. (Zauważmy, że warstwa makro jest generatorem kodu - na podstawie tekstu makrosów generuje tekst rozkazów assemblera).
- Dlatego powstał język wysokiego poziomu nazwany COBOL. Teraz każdy user mógł sobie napisać program w języku naturalnym, a komputer zrobił wszystko, czego ten user chciał. Przynajmniej jeżeli chciał zrobić jakieś operacje na bazie danych. No ale nie wszystko robi się na bazie danych. No i ta "naturalność" języka była dość relatywna. (I oczywiście taki kompilator jest generatorem kodu maszynowego).
- Dlatego powstały inne języki programowania, na przykład FORTRAN, Algol 60, Algol 68, Pascal czy C. Teraz każdy głupi mógł sobie łatwo napisać program. (Zauważmy, że każdy kompilator czy interpreter jest też generatorem kodu, a do dziś wiele kompilatorów nie generuje wprost kodu maszynowego tylko kod źródłowy w assemblerze. A pierwsza faza kompilacji programu w C to preprocesor, czyli ewidentny generator kodu).
- Potem zmniejszać ilość kodu miała koncepcja modularności / obiektowości (Modula2, C++, Java, ...). Jakościową zmianą w generacji kodu były na przykład Templates w C++.
- Dalej pojawiły się pierwsze próby z low-code: wszystkie te języki Visual-XXX (Basic, C++, ...). Tu użytkownik miał po prostu narysować aplikację GUI, i napisać tylko troszeczkę kodu w callbackach. Resztę robił generator. To nawet jakoś działało.
- Następna próba była - moim zdaniem - najbardziej obiecująca ze wszystkich: Model Driven Development. Kod miał być wygenerowany z modelu, co potencjalnie mogło zintegrować generację w cały proces tworzenia oprogramowania. To nawet działało (BTDT), ale nie było pozbawione wad i nie było dla każdego.
- Po opadnięciu hype na MDD poszło to wszystko raczej w stronę konfiguracji w jakimś narzędziu i generacji kodu z templates tekstowych albo czysto programowej. Tak działa cały ten AUTOSAR i to jest mix no-code z low-code.
- Do niedawna na topie było właśnie low-code i no-code, ale to są głównie scamy - przychodzi jakiś akwizytor, na pokazie w parę minut wyklikuje działającą aplikację, i managerstwo się na to łapie. A potem się okazuje, że wyklikać da się tylko to, co producent wbudował do środka, a zrobienie w tym czegoś więcej jest od cholernie trudnego do niemożliwego.
- Od dłuższego już czasu IDE wrzuca szkielety kodu do nowo tworzonych plików, albo ma jakiś katalog snippetów do różnych zadań. To też jest forma generatora kodu. No i zawsze można przekopiować coś ze StackOverflow albo z jakiegoś starego projektu.
- No i teraz wchodzi, cała na biało, generacja kodu przez AI. No i tak serio serio to ma być wreszcie to ultymatywne rozwiązanie, żeby już nic nie kodować? Przecież to już chyba ósma dekada tego eliminowania kodowania, że już-tylko-chwila i programiści staną się niepotrzebni. Prawie jak z tą syntezą termojądrową.
Podsumowanie: Jak na razie nie ma się czym ekscytować (no chyba że przez cały czas kodujesz maski do aplikacji bankowych, ale wtedy i bez AI lepiej się trochę przebranżowić). Jak będzie dalej? Moja prognoza w następnym odcinku.