1. GitHub Copilot tydzień później - nowe sztuczki i problemy z licencjami 🚀

No cóż, kiedy w zeszłym tygodniu pisaliśmy o Github Copilocie, raczej spodziewalśmy, że temat będzie sobie jeszcze żył. Od zeszłej soboty pojawiło się w tej kwestii kilka bardzo interesujących wątków, więc postanowiliśmy jeszcze raz całości się przyglądnąć.

Zacznijmy od tematu licencji - licencja w IT jest terminem tak magicznym, że wystarczy go tylko wspomnieć, aby zaczął się kafszkwał o przynajmniej średnim nasileniu. W wypadku Github Copilota, główny trzon dyskusji sprowadza się do tak zwanych licencji copy-left, typu GPL-3. Wymaga ona (w małym uproszczeniu), udostępnienie na tej samej licencji każdego kodu źródłowego, który jest “pochodną” użycia oryginalnego kodu na licencji GPL. I to właśnie o słowo czym jest w tym wypadku “pochodna” rozbija się cała dyskusja.

Całość doprowadziła do szerokiej debaty, która świetnie obrazuje, jak w bardzo “szarej strefie” porusza się Microsoft ze swoim nowym produktem. Całość bardzo dobrze podsumowuje post Julii Redy z Europejskiej Partii Piratów, specjalistki od licencji. Próbuje ona w nim udowodnić, że Copilot tak naprawdę nie naruszył ani prawa, ani postanowień licencyjnych - przynajmniej jeśli prawdziwymi są twierdzenia, że jedyne co jest dokonywane to synteza istniejącego kodu. Oczywiście, całość nie sprawia, że społeczność została uspokojona - pojawiają się np. osoby zachęcające do porzucenia z Githuba. Dodatkowym smaczkiem jest też fakt, że niektóre fragmenty generowanego kodu nie wydają sie być syntezą tylko zwykłym copy-pastem (do czego zresztą twórcy Copilota jawnie się przyznają) ….

Mam przeczucie, że skończy się to po prostu nowym typem licencji GPL-NO-ML.‌‌

Tematy licencyjne pewnie będą ciągnąć się jeszcze przez dłuższy czas, ale w międzyczasie warto zobaczyć co tak naprawdę wspomniany Copilot potrafi. W ciągu tygodnia ludzie zdążyli się już nieco pobawić całością, dość szeroko eksperymentując. Jednym z ciekawszych przykładów jest łatwość, z jaką radzi sobie on z problemami z popularnego serwisu LeetCode.

Robi wrażenie, aczkolwiek LeetCode wydaje się być właśnie idealnym miejscem w którym sprawdzi się taki Copilot - jasny input, jasny output, dużo danych treningowych (GitHub jest ich wręcz pełen). Co ciekawe, nie poradził sobie jednak zbyt dobrze z Advent of Code. Udowadnia to tylko, że o ile Copilot naprawdę dobrze sprawdza się w starciu ze stosunkowo prostymi problemami o ograniczonym zakresie, o tyle te nieco bardziej złożone na razie są poza jego zasięgiem. Jestem jednak pewien, że jednym z małych wyzwań, jakie postawią przed sobą uczestnicy tegorocznej edycji Advent of Code będzie właśnie takie pokierowanie Copilotem, żeby wygenerował poprawne rozwiązanie - wspomnicie moje słowa 🎅.

Wracając jednak do LeetCode, może jednym z pozytywów rozwiązania GitHuba będzie fakt, że branża przestanie używać testów algorytmicznych przy rekrutacji (a przynajmniej na pozycje, które są pisaniem CRUDów) - czego sobie i Wam wszystkim życzę 😉

Dla mnie jednak największym WOW jest fakt, że Copilot radzi sobie z pisaniem Regexpów 😱 Jeżeli już nigdy nie będę musiał ręcznie tworzyć rzeczonych, to odpowiedź jest tylko jedna…

… panie Microsoft.

Źródła

2. Trochę #ComputerScience na przykładzie kompilatora Rusta 🖥👨‍🔬

Przyznam się Wam do czegoś - mam trochę problem z szafowaniem nazwą “Software Craftsmanship” w sobotniej edycji naszego newslettera. Są takie dni, kiedy z czystym sumieniem mógłbym nazwać go co najwyżej “Tym żyło IT w zeszłym tygodniu”. Staramy się wybierać co prawda rzeczywiście tylko rzeczy, które z naszej perspektywy pozwalają zapoznać się naszym czytelnikom z “zeitgeistem” branży - nie zawsze jednak dotykając tytułowego “rzemielśnictwem kodu” w jakiś mocny sposób.

Czasem jednak przychodzi tydzień, gdy jednym z najczęściej dyskutowanych tematów w społeczności była NP-trudność procesu kompilacji Rusta - i wreszcie można sobie trochę to opisywanie procesów sądowych “FANG vs każdy” zrekompensować odrobinką dobrego computer science, zahaczającego o kompilatory i systemy typów.

Aczkolwiek nie kłammy się - Rust przebił się tylko i wyłącznie dlatego, że sezon ogórkowy trwa w najlepsze.‌‌

Zanim przejdziemy do clue dzisiejszego artykułu - zacznijmy od odrobiny kontekstu. Tak zwany “wyczerpujący pattern matching” jest jednym z tych funkcjonalności, które są jednymi z ciekawszych konceptów w dzisiejszym programowaniu. Dla niektórych wręcz odróżniają języki, które nadają się do pisania kodu, od “podjęzyków” które się nie nadają (pozdrawiam Mateusza - jeśli czytasz, to wiesz, że to o Tobie). Jest ku temu ekstremizmowi pewien powód - jedną z najczęściej występujących kategorii błędów w programowaniu jest brak pokrycia wszystkich dostępnych wariantów przy okazji np. switchy.

Łatwo jest sprawdzić, że każdy wariant np. enuma został pokryty:

fun checkState(state: State): Unit = when (state) {
	State.Loading -> {}
	State.Done -> {}
	State.None -> {}
}

// 'when' expression must be exhaustive, add necessary 'Error' branch or 'else' branch instead.
Przykład w Kotlinie, ale myślę że nawet dla nieznających języka dobrze obrazuje o co chodzi.

Jednak w wypadku wspomnianego pattern matchingu, sytuacja jest nieporównywalnie bardziej skomplikowana.

Przejdźmy wreszcie do głównego artykułu. Otóż autor (co ciekawe Polak, specjalista od Cybersecurity) analizuje złożoność podobnego procesu dla pattern matchingu:

match todo!() {
	(false, _) => {} // A
	(_, false) => {} // B
	(false, false) => {} // A B
	(true, true) => {} // !A !B 
 }
Dla nieznających składni - "_" oznacza "dowolna wartość"

i porównuje go do teoretycznego problemu problemu spełnialności (Boolean satisfiability, znanego również jako SAT). Autor rozkłada go na czynniki pierwsze, pokazując, że wspomniany pattern matching można sprowadzić właśnie do prostych operacji na arytmetyce boolowskiej. Problem spełnialności zaś, w swoich bardziej zaawansowanych przypadkach, należy do problemów o złożoności wielomianowej i należących do klasy tak zwanej NP-kompletnej.

Co każdy mający choćby wprowadzenie do algorytmów wie, że oznacza same problemy. Aczkolwiek w 2020 wszyscy staliśmy się specjalistami od wzrostu wykładniczego 😅

Podobne wyzwanie występuje również w innych językach programowania posiadających “exhaustive pattern matching” jak np. Haskell, F# czy OCaml (ten ostatni ze swoim state-of-the-art inferowaniem typów to dopiero musi być wrzodem do kompilowania). Ogólnie jeśli ktoś chciałbym temat zgłędbić, to prawdopodobnie można by na nim zrobić niejedną publikacje czy doktorat - jeśli interesuje Was fajna analiza tematu z punktu widzenia Haskella, zapraszam do lektury.

Jest to kolejny już przypadek, gdy korzystając na dyskusji rustowego “community” jesteśmy w stanie wyciągnąć trochę bardziej ogólne wnioski, łatwo przenaszalne na reszte branży. Po pierwsze - nasze kompilatory robią naprawdę trudną robotę - radzą sobie wielokrotnie z problemami, które nie posiadającymi (nawet w teorii) optymalnego rozwiązania. Po drugie - to, że coś jest NP-kompletne, nie oznacza wcale, że w skali “przemysłowej” nie jesteśmy sobie w stanie z tym poradzić. Po trzecie - dodatkowe możliwości języka przychodzą z pewnym kosztem, i czasem trzeba ten koszt dobrze wyważyć.

Dlatego, jeśli czasem zdarzy nam się zakląć na długość procesu kompilacji języka albo na brak jakiejś konkretniej opcji w języku - pamiętajcie: to wszystko jest jakaś forma kompromisu.

Źródła


‌Pamiętajcie, żeby spróbować Vived, jeśli chcesz otrzymywać tego typu treści spersonalizowane pod Ciebie!