“Wiele zależy od niezależności”

Ostatnio w jednym z projektów, nad którym pracowałem, potrzebowaliśmy wygenerować UUID. Prosta sprawa, na pewno jest od tego biblioteka. Mocno się zdziwiłem, kiedy odkryłem, że mamy już taką w projekcie. Co więcej nie jedną, a siedem i to niektóre w dwóch lub trzech wersjach.

cat go.sum | grep uuid | cut -d " " -f1 | uniq -c
      3 github.com/gobuffalo/uuid
      2 github.com/gofrs/uuid
      3 github.com/google/uuid
      2 github.com/hashicorp/go-uuid
      3 github.com/pborman/uuid
      1 github.com/rogpeppe/fastuuid
      1 github.com/satori/go.uuid

Ta przygoda skłoniła mnie do zadania sobie pytania: Ile zależności ma przeciętny projekt w Go? Co w ogóle jest zależnością, czy to, co definiujemy w pliku go.mod czy go.sum? Według mnie, zależność zależności też jest zależnością, więc przydałoby się policzyć wszystkie wystąpienia w pliku go.sum.

BigQuery

Od jakiegoś czasu publiczne dane z GitHuba są dostępne na Google BigQuery. Pozwala to na szybkie i wygodne przeszukiwanie kodów źródłowych przy pomocy SQLa. Poniżej przedstawiam kod, którym wyciągnąłem dane o zależnościach projektów Go.

#standardSQL
SELECT
  F.repo_name,
  LENGTH(C.content) - LENGTH(REGEXP_REPLACE(C.content, '\n', '')) AS lines
FROM
  `bigquery-public-data`.`github_repos`.files AS F
JOIN
  `bigquery-public-data`.`github_repos`.contents AS C
ON
  F.id = C.id
WHERE
  C.binary = FALSE
  AND F.path = 'go.sum'
  AND F.ref = 'refs/heads/master'

Zliczam tutaj nowe linie w pliku go.sum. Nie jest to najlepsze wyjście, gdyż jeśli zależność ma plik modułów, wtedy pojawi się podwójnie, dlatego w kolejnej iteracji posłużyłem się takim wzorem:

LENGTH(content) - LENGTH(REGEXP_REPLACE(content, 'go.mod h1:', '')) AS lines
https://plot.ly/~janisz/54.embed

Inne języki

Kiedy dostałem odpowiedź na moje pytanie, zacząłem zastanawiać się, jak to jest z innymi językami. Po awanturze z leftpadem podejrzewałem, że projekty JS mają znacznie więcej zależności (za to prawdopodobnie dużo mniejszych). Z drugiej strony Python, język z bardzo rozbudowaną biblioteką standardową, powinien mieć zależności mniej niż Go. 

Policzenie zależności w tych językach nie było trudniejsze niż w Go. Projekty JS posiadają plik packages-lock.json, w którym są wszystkie zależności danego pakietu włącznie z zależnościami przechodnimi, więc wystarczy policzyć wystąpienia resolved i gotowe.

Z Pythonem jest trudniej, gdyż nie ma sformalizowanego formatu nazywania plików zależności. Nie jestem przekonany, czy dane są poprawnie zebrane, gdyż jest to liczba linijek pliku requirements.txt.

Na fali rosnącej popularności Rust myślałem, że uda mi się dodać go do porównania. Wiele słyszałem o menedżerze pakietów cargo, a łatwość wyciągnięcia tych danych dodatkowo potęgowała ciekawość. Niestety poniższe zapytanie zwraca tylko jeden wynik, więc chyba popularność Rust istnieje tylko na Twitterze i HackerNews.

#standardSQL
SELECT
  COUNT(*),
FROM
  `bigquery-public-data`.`github_repos`.files AS F
WHERE
  F.path = 'cargo.lock'
  AND F.ref = 'refs/heads/master'

Jak to pokazać?

Bardzo chciałem wizualnie zaprezentować wyniki. Głównie dlatego, że przeczytałem “Eseje o sztuce wizualizacji danych” i uzbrojony w nowe narzędzia bardzo chciałem ich użyć. Po ściągnięciu danych zaimportowalem je do R i przy pomocy ggplot2 narysowałem wykres wiolinowy z logarytmiczną skalą. Dzięki temu wszystkie istotne dane są pokazane. Myślę, że ciekawa jest przerwa w repozytoriach pythonowych. Nie ma projektów, które miałyby między 4 a 20 zależności. Być może to błąd metody zliczania tych zależności ?.

A co z Javą?

No dobrze, mamy wyniki dla 3 języków, wiemy, że Rust nie istnieje, a co z resztą? Czy popularna opinia, że Maven zaciąga pół internetu jest prawdziwa? Niestety odpowiedź na to pytanie przy pomocy danych z GitHuba jest trudna, jeśli nie niemożliwa. W Javie przechodnie zależności są dołączone do paczki (co czyni ją odporną na problem leftpada), przez co nie mogłaby być porównana z resztą wyników. 

Ile to kosztuje?

Zupełnie nic. Na początku dostajemy $300 ważne przez 12 miesięcy na zabawę z danymi od Googla. Potem trzeba będzie zapłacić. Poniżej wycinek faktury, którą dostałem z Googla

42TB za 788PLN

Warto rozsądnie korzystać z ich narzędzi, bo w przeciwnym wypadku łatwo popłynąć tak jak pewien doktorant i dostać rachunek na ponad $4000. Wszystko jest opisane na StackOverflow razem z poradnikiem jak zmniejszyć te rachunki – najważniejsze nigdy nie zapominać where.

Dalsze badania

Okazuje się, że libraries.io parsuje repozytoria i wyciąga dokładne informacje o zależnościach w teorii również przechodnich. Co więcej, te dane również są publicznie dostępne na BigQuery, więc w teorii dałoby się wyciągnąć wiarygodne statystyki dla każdego z wspieranych języków. 


Leave a Reply