Co dają studia i co warto umieć?

Kiedy zapisywałem się na algorytmikę, wyobrażałem sobie, że wydajność i poprawność programów jest wybitnie ważna i przy każdym kroku powinienem rozpisywać jak coś zrobić optymalnie oraz obsługując wszystkie możliwe błędy. Po studiach spodziewałem się, że mnie tego nauczą, zaś w pracy oczekiwałem używać umiejętności ze studiów. Takiego wała.

Gdzieś w okolicach pierwszego tygodnia pracy człowiek dowie się, że na dłuższą metę to warto, żeby system dało się jakoś konserwować. Jeśli coś może działać wystarczająco szybko, ale umożliwiać rozwój systemu przez następne 10 lat, to jest to lepsza opcja niż super-szybkie rozwiązanie, którego szybkość nikomu nie jest potrzebna i którego nikt nie będzie umiał zmodyfikować, jeśli przyjdzie taka potrzeba.

A czy możemy w sumie przewidywać wydajność? Nie ma łatwo. Kilkanaście lat temu zakładał[e/a]ś, że jak pobranie liczby z pamięci RAM zajmowało ci X to pobranie drugiej liczny zajmie ci też X. Od tego czasu sporo się zmieniło. (Ostrzegam: nudne pierdolenie, można pominąć). Wprowadzono kilkupoziomowy cache do procesora: jeśli twoje dane są tuż obok w pamięci, dostęp jest niemal natychmiastowy (0.5ns). Ciutkę bardziej oddalone? Trzeba je ściągnąć do cache L1 z cache L2 - zakładając, że dane już tam są - 7ns. Wciąganie do L2 prosto z RAM? 100ns. Do tego dochodzi tzw. branch prediction - 5ns więcej, jeśli procesor źle zgadnie, którą z 2 ścieżek pójdzie program. Przy maszynach wirtualnych i/lub kompilatorach dochodzą jeszcze dewirtualizacja, analiza ucieczki, inlinowanie, zaś przy językach z pamięcią zarządzaną w ogóle, kwestie z nieprzewidywalnością garbadge collectora. Do tego dojdą różnie inne optymalizacje, o których w tym momencie nie pamiętam. Już to wystarczy, żeby niemożliwe było zgadywanie jak zachowa się program w praktyce.

Do tego dochodzi fakt, że kierowanie się tzw. złożonością obliczeniową algorytmów ma sens przy większej ilości danych, niekoniecznie przy małych danych, z jakimi mamy często do czynienia. Złożoność mówi nam jak bardzo zwiększanie się rozmiaru danych, wpłynie na zwiększenie się czasu wykonywania programu. Ale działa z oczekiwaniami tylko dla dużych wartości: algorytm najlepszy dla danych powyżej 10TB, może być stosunkowo słaby, jeśli pracujemy na 10 elementach na krzyż. W efekcie nasze szacunki odnośnie wydajności to tylko pobożne życzenia: dopóki nie zmierzymy, jak program się zachowa dla prawdziwych danych, nic nie możemy powiedzieć na pewno. Prawie na pewno za to będziemy źle obstawiać, gdzie wystąpi wąskie gardło.

Może w takim razie poprawność? Case’y, które analizujesz w różnego rodzaju pejperach nie uwzględniają, że: komputer ma skończoną pamięć, liczby zazwyczaj mają ograniczoną pojemność, dostęp do pamięci w dowolnym miejscu nie zawsze jest tani, a komputery się wypieprzają, urywa się połączenie internetowe, a danie nie zawsze spełniają nasze idealistyczne oczekiwania. W praktyce, rozpiska co może pójść źle jest zazwyczaj ciut bardziej złożona, niż w radosnym świecie doskonałych abstrakcji.

Można by powiedzieć, że w sumie to całe studia można wywalić do kosza i nie być niczego stratnym, prawda? No, niekoniecznie.

Są pewne działki matematyki, które się na bank przydadzą.

Logika i teoria zbiorów na pewno. Biorąc pod uwagę jak dużo będzie instrukcji warunkowych w kodzie, warto, żebyśmy rozumieli takie np. prawa de Morgana. Przy przetwarzaniu danych będziemy często coś porównywać, szukać elementów wspólnych, wybierać jakieś szczególnie nas interesujące elementy… Warto, żebyśmy mieli jakieś intuicje dotyczące tych operacji. Nie mówiąc już o tym, że dobrze byłoby rozumieć czym matematycznie jest funkcja i co można z nimi robić. Szczególnie, że programowanie funkcyjne zdobywa popularność, a tam różne cuda się odprawia. A pracując w języku z systemem typów, przyda się mieć intuicje co to jest typ (tłumaczenie, że to w sumie coś jak zbiór, działa lepiej, kiedy wiesz czym są zbiory ( ͡° ͜ʖ ͡°)).

Pewne podstawy teorii grafów też się przydadzą. Modelując dane często będziesz tworzyć i przeszukiwać drzewa i warto sobie z tego zdawać sprawę.

Poza wiedzą ogólną jest też ta nieco bardziej specjalistyczna.

Przy grafice komputerowej (a także programowaniu funkcyjnym, obliczeniach numerycznych, …) algebra to podstawa. Elektronicy muszą umieć analizę matematyczną (transformata Fouriera), zaś każda osoba pracująca nad jakimkolwiek parserem powinna znać podstawy języków formalnych. Złożoność obliczeniowa i teoria obliczeń nie będzie czymś, do czego zaglądamy na co dzień, ale zaczyna mieć sens, kiedy naszą aplikację musimy w końcu zoptymalizować. Ew. kiedy wypadałoby zauważyć, że wymagania biznesowe żądają od nas rozwiązania problemu stopu, szybkiego obliczenia problemu NP-zupełnego, albo innej misji niemożliwej.

W sumie, o ile naszą ambicją nie jest wyłączne klepanie formatek w HTMLu i CSSie, oraz mało ambitne łączenie ze sobą bibliotek (> 90% zadań w korpo), to w którymś momencie matma nam się zacznie przydawać. Ba! Będziemy zadowoleni, że możemy się dla odmiany pogłowić!

No i są też ludzie. Na studiach możemy złapać kontakty, staże i pierwsze oferty pracy. Bez studiów też da radę, ale trzeba będzie się nachodzić na meetupy, konferencje i dni pracy.

Koniec końców to jednak kwestia tego w którą stronę chcemy iść. Połowę web-deweloperki można pociągnąć po matmie maks na poziomie gimnazjum. Można też liznąć parę koncepcji i odkryć, że czasami pomysły jajogłowych ułatwiają życie. Najlepiej samemu się przekonać rozwój w którą stronę najbardziej nas jara, bo do rozpoczęcia doktorat nie jest wymagany.