← Wszystkie wpisy

Filozofia inżynierii: Linus Torvalds i przypadek szczególny, który znika

Linus Torvalds, twórca Linuksa i git

Najważniejsze wnioski

  • Dobry gust to moment, w którym przypadek szczególny znika. Wystarczy przebudować strukturę danych — wskaźnik na wskaźnik zamiast pojedynczego wskaźnika — a warunkowe if obsługujące przypadek brzegowy nie ma już gdzie istnieć.
  • „Pokaż mi kod” to epistemologia, nie hasło. Projekt jest hipotezą; spór rozstrzyga dopiero działający kod.
  • W git rozproszenie jest konsekwencją struktury danych. Obiekty adresowane treścią sprawiają, że każde repozytorium jest równe, więc „jedyna prawdziwa kopia” nigdy nie istnieje, by trzeba jej było bronić.
  • Zaufanie w skali musi być ustrukturyzowane, a nie zakładane. Torvalds rozwiązał ten problem dwukrotnie — drzewo opiekunów określa, kto ponosi odpowiedzialność, a historia odporna na manipulacje pokazuje, co się wydarzyło.

Zasada

„Chcę, żebyś zrozumiał, że czasem można spojrzeć na problem inaczej i przepisać go tak, by przypadek szczególny zniknął i stał się przypadkiem normalnym — i to właśnie jest dobry kod.” — Linus Torvalds, TED, 20161

Torvalds stał na scenie TED, trzymając obok siebie dwie funkcje w języku C. Obie usuwały element z jednokierunkowej listy. Pierwsza przechodziła listę za pomocą wskaźnika prev, sprawdzała, czy usuwany element jest głową listy, i rozgałęziała się: głowa jako przypadek szczególny, cała reszta jako przypadek ogólny. Dziesięć wierszy, jedno if. Druga funkcja przechodziła listę za pomocą wskaźnika na wskaźnik — **indirect — tak że głowa wcale nie była miejscem szczególnym. Była po prostu pierwszą rzeczą, na którą akurat wskazywał wskaźnik na wskaźnik. Cztery wiersze, żadnego if.1

Mniejsza liczba wierszy nigdy nie była sednem sprawy. Warunek w pierwszej wersji istniał tylko dlatego, że programista wymodelował głowę listy jako coś innego niż jej resztę. Wystarczy wybrać lepszą strukturę danych — wskaźnik na wskaźnik zamiast wskaźnika — a różnica się ulatnia. Przypadek brzegowy nigdy nie był nieodłączną częścią problemu; był artefaktem sposobu, w jaki problem został przedstawiony. Gust w rozumieniu Torvaldsa to dokładnie ten ruch, i jest to to samo przekonanie, które sprawia, że gust jest systemem technicznym, a nie preferencją estetyczną: elegantsza wersja wygrywa nie dlatego, że jest ładniejsza, lecz dlatego, że jest bardziej poprawna — pozostało jej mniej miejsc, w których mogłaby się mylić.

Ten instynkt — wyeliminować przypadek szczególny, by przypadek brzegowy nie miał się gdzie ukryć — przewija się przez wszystko, co Torvalds zbudował. Tłumaczy też, dlaczego jego inne słynne zdanie brzmi mniej jak manifest, a bardziej jak instrukcja: „Gadanie jest tanie. Pokaż mi kod.”2

Dwie wersje usuwania elementu z listy z wystąpienia Torvaldsa na TED: wersja „oczywista" traktuje głowę jako przypadek szczególny z if; wersja „dobrego gustu" używa wskaźnika na wskaźnik, dzięki czemu przypadek szczególny znika całkowicie

Proszę spróbować powyżej: usunąć węzeł ze środka, a następnie usunąć głowę w każdym z trybów. W „sposobie oczywistym” głowa uruchamia gałąź if (!prev); w „dobrym guście” głowa jest po prostu kolejnym połączeniem i obsługuje ją ten sam pojedynczy wiersz.

Kontekst

Linus Benedict Torvalds urodził się w Helsinkach w Finlandii w 1969 roku, w szwedzkojęzycznej rodzinie. Jako student informatyki na Uniwersytecie Helsińskim korzystał z systemu Minix — niewielkiego systemu operacyjnego w stylu Uniksa, napisanego przez holenderskiego profesora Andrew Tanenbauma jako narzędzie dydaktyczne. Minix był pouczający, lecz celowo ograniczony — Tanenbaum utrzymywał jego prostotę, by studenci mogli przeczytać całość. Torvalds chciał więcej, niż mu pozwalano.

25 sierpnia 1991 roku napisał na grupie dyskusyjnej Usenetu comp.os.minix: „Robię (darmowy) system operacyjny (tylko hobby, nie będzie duży ani profesjonalny jak gnu) dla klonów 386(486) AT.”3 Zastrzeżenie w nawiasie to najczęściej cytowana pomyłka w historii oprogramowania.

Oryginalny wpis Torvaldsa z 25 sierpnia 1991 roku na comp.os.minix, ogłaszający projekt — „tylko hobby, nie będzie duży ani profesjonalny jak gnu"

To hobby stało się, wedle dowolnej miary wdrożenia, najczęściej uruchamianym jądrem na Ziemi — napędza większość serwerów WWW, każdy telefon z Androidem oraz przytłaczającą część infrastruktury chmurowej i superkomputerowej.

Architektura była przedmiotem sporu od samego początku. Na początku 1992 roku Tanenbaum otworzył wątek zatytułowany „LINUX is obsolete”, argumentując, że jądro monolityczne to „gigantyczny krok wstecz, do lat 70.”, a przyszłość należy do mikrojąder — w których system operacyjny jest rozłożony na odizolowane usługi komunikujące się komunikatami.4 Torvalds przyznał, że mikrojądra są lepsze „z punktu widzenia teoretycznego i estetycznego”, po czym dalej budował jądro monolityczne, ponieważ działało, było szybkie i zostało dostarczone. Tę dyskusję pamięta się jako dokument założycielski pewnego temperamentu: teoria przegrywa z systemem, który działa.

Dzieło

Jądro Linuksa (1991–): monolit, który się skalował

Tux, maskotka jądra Linuksa, narysowana przez Larry'ego Ewinga

Linux to jądro monolityczne: planista, menedżer pamięci, systemy plików i sterowniki urządzeń działają w jednej uprzywilejowanej przestrzeni adresowej. Krytyka Tanenbauma nie była w teorii błędna — usterka w monolitycznym sterowniku może położyć cały system w sposób, który mikrojądro potrafi odizolować. Odpowiedź Torvaldsa była empiryczna. Monolit był szybszy, prostszy w pisaniu i mógł być modyfikowany przez tysiące współtwórców bez konieczności, by każdy z nich najpierw poznawał protokół przekazywania komunikatów. Architektura, która przegrała akademicki spór, wygrała wojnę o wdrożenie, ponieważ obniżyła koszt współtworzenia.

Jądro jest dziś jednym z największych wspólnych artefaktów inżynierskich, jakie kiedykolwiek powstały — dziesiątki milionów wierszy, tysiące współtwórców na każde wydanie. Ta skala nie została zaprojektowana z góry. Narastała stopniowo, łatka po łatce, w ramach modelu rozwoju, który Torvalds również musiał wymyślić.

Model opiekuna: zaufanie jako drzewo

Torvalds nie czyta większości kodu trafiającego do Linuksa. Nie może — objętość daleko wykracza poza możliwości jednej osoby. Zamiast tego jądrem rządzi hierarchia zaufania. Opiekunowie podsystemów odpowiadają za swoje obszary. Przeglądają łatki, włączają je do swoich drzew i wysyłają żądania pobrania w górę — do poruczników, a ostatecznie do Torvaldsa, który scala drzewa, którym ufa. Jest życzliwym dyktatorem u korzenia, ale jego prawdziwe zadanie polega na pilnowaniu, komu ufa, a nie na audytowaniu każdego wytworzonego przez nich wiersza.

Drzewo opiekunów to architektura społeczna i mierzy się z tym samym problemem, przed którym staje każdy współczesny łańcuch dostaw oprogramowania: nie da się osobiście zweryfikować wszystkiego, więc zaufanie musi być ustrukturyzowane, a nie zakładane. To dlatego repozytorium nie powinno głosować nad własną wiarygodnością i dlaczego otwarty kod źródłowy nie jest granicą bezpieczeństwa — wiele par oczu pomaga tylko wtedy, gdy ktoś odpowiada za patrzenie. Lista mailingowa, ze swoją słynnie bezceremonialną oceną, jest mechanizmem, który czyni drzewo zaufania czytelnym: decyzje i ich uzasadnienia są publiczne, archiwizowane i przypisywalne.

git (2005): rozproszone zaufanie jako struktura danych

Wynik git log --graph przedstawiający adresowany treścią graf skierowany acykliczny commitów — gałęzie, scalenia i krótkie skróty SHA, bez uprzywilejowanej kopii centralnej

Przez lata jądro było rozwijane przy użyciu BitKeepera, zastrzeżonego rozproszonego systemu kontroli wersji, którego twórca udzielił projektowi darmowej licencji. W 2005 roku ta umowa rozpadła się w sporze licencyjnym i Torvalds nagle pozostał bez narzędzia zdolnego obsłużyć przepływ pracy jądra.5 Napisał więc własne. Pierwszy commit do git miał miejsce 7 kwietnia 2005 roku; w ciągu mniej więcej dziesięciu dni narzędzie samo się hostowało i zarządzało jądrem.6

To, co czyni git wyrazem tej samej zasady co przykład z listą, to jego rdzenna struktura danych. git nie przechowuje różnic i nie odtwarza z nich stanu. Każda wersja każdego pliku, każde drzewo katalogów, każdy commit są przechowywane jako obiekt nazwany skrótem SHA-1 swojej własnej treści — magazyn adresowany treścią. Torvalds mówi wprost, że haszowanie „nigdy nie chodziło o bezpieczeństwo. Chodziło o wykrywanie uszkodzeń.”6 Tożsamość jest treścią: dwa pliki o tych samych bajtach są automatycznie tym samym obiektem, a pojedynczy przestawiony bit daje inną nazwę i jest wykrywalny. A ponieważ „każde repozytorium jest takie samo i równe”, nie istnieje uprzywilejowany serwer centralny — przypadek szczególny „jedynej prawdziwej kopii” znika w ten sam sposób, w jaki zniknął przypadek szczególny „głowy listy”.6 Rozproszenie nie jest funkcją doczepioną do git; jest konsekwencją wyboru właściwej struktury danych.

Ta ostatnia właściwość — odporny na manipulacje łańcuch commitów adresowanych treścią — sprawia, że graf commitów może nieść znaczenie wykraczające poza kod, i dlatego myślę o sesji jako komunikacie commita: historia jest artefaktem, a nie jego produktem ubocznym.

Metoda

Metoda Torvaldsa to pragmatyzm egzekwowany dowodami. „Gadanie jest tanie. Pokaż mi kod” było dosłowną odpowiedzią na liście mailingowej jądra dla kogoś, kto opisywał, co zrobi jego łatka.2 Projekt jest hipotezą; łatka jest eksperymentem. Dopóki kod nie istnieje i nie działa, spór jest nierozstrzygnięty.

U podstaw tego leży jego najprecyzyjniejsze stwierdzenie, gdzie naprawdę mieszka osąd inżynierski: „Słabi programiści martwią się o kod. Dobrzy programiści martwią się o struktury danych i relacje między nimi.”7 Przykład z listą to właśnie to zdanie ucieleśnione. Jeśli struktura danych jest właściwa, kod, który na niej operuje, jest krótki i ma niewiele rozgałęzień, ponieważ struktura już wchłonęła złożoność. Jeśli struktura danych jest błędna, płaci się za to bez końca w przypadkach szczególnych — w instrukcjach if, które istnieją tylko po to, by zatuszować zły model. Martwienie się o kod to leczenie objawów. Martwienie się o strukturę danych to terapia przyczynowa.

Metoda zarządzania odpowiada metodzie technicznej. Model życzliwego dyktatora i poruczników istnieje nie tyle po to, by skupić ego, ile po to, by decyzja o scaleniu pozostała odpowiedzialna przed jednym gustem, rozkładając jednocześnie pracę nad przeglądem między ludzi najbliższych każdemu podsystemowi. A bezceremonialność jego ocen kodu — która, jak sam później przyznał, czasem przeradzała się w niepotrzebną szorstkość — wyrasta z tego samego korzenia: kod ocenia się według tego, czy jest poprawny, a nie według tego, kto go napisał ani ile wysiłku reprezentuje. Standard jest bezosobowy, nawet gdy sposób jego komunikowania taki nie był.

Łańcuch wpływów

Kto go ukształtował

Andrew Tanenbaum i Minix. Minix był systemem operacyjnym, na którym Torvalds się uczył, i czymś, co próbował przewyższyć. Tanenbaum dał mu czytelny system w stylu Uniksa do studiowania oraz — poprzez debatę „LINUX is obsolete” — przeciwnika dość ostrego, by jasno określić, co Torvalds cenił: system, który zostaje dostarczony, ponad architekturę, która zadowala. (Wpływ formacyjny)4

Unix i narzędzia GNU. Linux jest Uniksem w linii projektowej — procesy, pliki, potoki, abstrakcja „wszystko jest plikiem”. A użyteczny stał się tylko dlatego, że kompilator, powłoka i narzędzia projektu GNU już istniały, by działać na jego wierzchu; Torvalds przeniósł bash i gcc, zanim jądro mogło zrobić cokolwiek znaczącego.3 Zbudował jeden brakujący element — jądro — a resztę pozostawił istniejącym częściom. Zbuduj to, czego potrzebujesz; wykorzystaj ponownie to, co działa. (Wpływ bezpośredni)

Kogo ukształtował

Cały świat otwartego oprogramowania. Linux udowodnił, że globalnie rozproszona, ochotniczo-korporacyjna hybryda potrafi przewyższyć inżynierią zespoły komercyjne w największej skali, a model opiekuna stał się szablonem prowadzenia dużych projektów otwartych.

Każdy rozproszony system kontroli wersji po nim. git nie tylko wygrał — stał się podłożem. GitHub, GitLab i nowoczesny przepływ pracy oparty na żądaniach pobrania są zbudowane na adresowanym treścią, rozproszonym modelu, który Torvalds wybrał w ciągu tych dziesięciu dni. Struktura danych przetrwała sytuację awaryjną, która ją zrodziła.

Nić przewodnia

John Carmack i Torvalds docierają w to samo miejsce z przeciwnych specjalności. Carmack ściska problem, aż algorytm i sprzęt złożą się ze sobą tak, że nic się nie marnuje; Torvalds przekształca problem, aż struktura danych sprawi, że przypadek szczególny znika. Obaj traktują wydajność i elegancję jako tę samą właściwość widzianą z różnych stron i obaj odmawiają pozwolenia, by teoria przeważyła nad rzeczą, która dowodnie działa. Dobry gust w całej tej serii nigdy nie oznacza ozdoby; oznacza poprawność, którą da się wyczuć. (Pomost serii)

Co z tego biorę

Lekcja z listy to ta, po którą sięgam najczęściej. Gdy w kodzie wyrasta if, by obsłużyć „ten pierwszy”, „przypadek pusty” albo „użytkownika administratora”, ta gałąź jest zwykle wyznaniem, że model danych jest odrobinę błędny. Naprawą rzadko bywa lepsze if. Jest nią lepsza reprezentacja, po której gałąź przestaje być potrzebna, bo przypadek, przed którym chroniła, nie może już zaistnieć. To najtańsza możliwa obrona: przypadek brzegowy, który nie może istnieć, nie potrzebuje żadnego kodu do obsługi.

Druga lekcja dotyczy zaufania w skali i ma największe znaczenie w świecie, w którym teraz buduję — systemach agentowych, gdzie orkiestruje się pracę, której nie napisało się wiersz po wierszu. Torvalds rozwiązał ten sam problem dwukrotnie: społecznie, drzewem opiekunów, które strukturyzuje, kto ponosi odpowiedzialność, oraz technicznie, adresowaną treścią historią git, która czyni to, co się wydarzyło, odpornym na manipulacje. Nie da się przeczytać wszystkiego, co wytwarza agent, tak samo jak Torvalds nie może przeczytać każdej łatki jądra. Robi się więc to, co on — czyni zaufanie strukturalnym, a historię weryfikowalną — i właśnie dlatego traktuję gust jako infrastrukturę oraz łańcuch dostaw jako powierzchnię ataku. Dyscyplina, która zbudowała jądro z hobby, jest tą samą dyscypliną, która pozwala bazie kodu przyspieszać, zamiast się rozkładać: wystarczy poprawnie ustawić strukturę, a przypadki szczególne przestają się mnożyć.

FAQ

Jak Linus Torvalds definiuje „dobry gust” w kodzie?

W wywiadzie dla TED z 2016 roku Torvalds zdefiniował dobry gust na przykładzie dwóch implementacji usuwania elementu z listy jednokierunkowej. Wersja, którą nazwał pozbawioną gustu, używała instrukcji if, by potraktować usunięcie głowy listy jako przypadek szczególny; wersja, którą nazwał dobrym kodem, używała wskaźnika na wskaźnik, dzięki czemu głowa nie była już wcale przypadkiem szczególnym. Jego podsumowanie: „czasem można spojrzeć na problem inaczej i przepisać go tak, by przypadek szczególny zniknął i stał się przypadkiem normalnym — i to właśnie jest dobry kod.”1

Co stworzył Linus Torvalds?

Torvalds stworzył jądro Linuksa, które po raz pierwszy ogłosił na grupie comp.os.minix 25 sierpnia 1991 roku, a które jest dziś najpowszechniej wdrożonym jądrem systemu operacyjnego na świecie. W 2005 roku stworzył również git, rozproszony system kontroli wersji, po tym jak projekt Linux utracił dostęp do zastrzeżonego narzędzia BitKeeper. Pozostaje głównym opiekunem jądra Linuksa.35

Dlaczego Linus Torvalds zbudował git i jak długo to trwało?

Projekt Linux korzystał z BitKeepera, zastrzeżonego rozproszonego systemu kontroli wersji, dopóki spór licencyjny w 2005 roku nie zakończył darmowego dostępu projektu. Torvalds napisał git jako zamiennik — pierwszy commit miał miejsce 7 kwietnia 2005 roku, a narzędzie zarządzało jądrem w ciągu około dziesięciu dni, choć sam zaznacza, że wcześniej spędził miesiące, przemyśliwując projekt.56

Co oznacza zdanie „Gadanie jest tanie. Pokaż mi kod.”?

Torvalds zamieścił to zdanie na liście mailingowej jądra Linuksa 25 sierpnia 2000 roku jako bezpośrednią odpowiedź w dyskusji o tym, co miałby robić pewien kod.2 Oddaje ono jego pragmatyzm: opis podejścia to tylko hipoteza, a spór nie jest rozstrzygnięty, dopóki nie istnieje działający kod, który można uruchomić i przetestować. (Uwaga: pokrewne zdanie „przy dostatecznej liczbie par oczu wszystkie błędy są płytkie” to Prawo Linusa w sformułowaniu Erica Raymonda, a nie cytat z samego Torvaldsa.8)

Źródła


  1. Linus Torvalds, „The mind behind Linux”, wywiad TED z Chrisem Andersonem, 2016 (fragment o dobrym guście / liście jednokierunkowej, ok. 14:10). Ponieważ transkrypcja TED renderuje się po stronie klienta, cytat i technika wskaźnika na wskaźnik są w pełni potwierdzone przez opatrzony komentarzami przegląd źródła pod adresem mkirchner/linked-list-good-taste, który odtwarza dokładne sformułowanie i znacznik czasu z wystąpienia. 

  2. Linus Torvalds, „Talk is cheap. Show me the code”, wiadomość na liście mailingowej jądra Linuksa, 25 sierpnia 2000. Zdanie jest skatalogowane z tą dokładną datą i źródłem pod adresem Wikiquote: Linus Torvalds oraz zarchiwizowane w wątku LKML pod adresem lkml.org/lkml/2000/8/25/132

  3. Linus Torvalds, „What would you like to see most in minix?”, grupa dyskusyjna Usenetu comp.os.minix, 25 sierpnia 1991. Ogłoszenie „tylko hobby, nie będzie duży ani profesjonalny jak gnu”. Kontekst: Tom’s Hardware, „Linux is 34 years old today.” 

  4. „Tanenbaum–Torvalds debate”, Wikipedia. Wątek „LINUX is obsolete”, 1992; „gigantyczny krok wstecz, do lat 70.”; mikrojądro a jądro monolityczne; ustępstwo Torvaldsa o aspekcie „teoretycznym i estetycznym”. 

  5. „A Git Origin Story”, Linux Journal. Rozpad licencji BitKeepera w 2005 roku i powstanie git; pierwszy commit 7 kwietnia 2005. 

  6. „Git turns 20: A Q&A with Linus Torvalds”, The GitHub Blog, 2025. „Każde repozytorium jest takie samo i równe”; „Skróty SHA-1 nigdy nie chodziły o bezpieczeństwo. Chodziło o wykrywanie uszkodzeń”; oś czasowa ~10 dni. 

  7. Linus Torvalds, „Bad programmers worry about the code. Good programmers worry about data structures and their relationships”, lista mailingowa jądra Linuksa, 27 czerwca 2006. 

  8. Eric S. Raymond, „The Cathedral and the Bazaar”, 1997. Raymond ukuł i nazwał „Prawo Linusa” — „przy dostatecznej liczbie par oczu wszystkie błędy są płytkie” — jako własne sformułowanie, przypisując Torvaldsowi leżący u podstaw model rozwoju, a nie samo brzmienie. 

Powiązane artykuły

Filozofia inżynierska: Mark Shuttleworth

Mark Shuttleworth zbudował Ubuntu wokół jednej idei -- Linux dla ludzi, wolne oprogramowanie dla każdego -- zakorzenione…

19 min czytania

Filozofia inżynierii: Thompson i Ritchie, rób jedną rzecz dobrze

Thompson i Ritchie zbudowali Uniksa i język C z małych, ostrych narzędzi łączonych przez jeden uniwersalny interfejs: st…

15 min czytania

The Shader Gallery That Lied: Debugging 216 WebGL Presets

A user said the shader playground looked broken. Pixel-readback testing found 30 dead presets, 11 that never compiled, a…

11 min czytania