Sekretne życie programów - ebook
Sekretne życie programów - ebook
W Sekretnym życiu programów doświadczony inżynier oprogramowania Jonathan E. Steinhart bada – i to dogłębnie – technologie i idee leżące u podstaw maszyn, na których pracujemy. Bada m.in. sprzęt komputerowy, zachowanie oprogramowania na konkretnym sprzęcie, a także sposób, w jaki różni ludzie rozwiązywali w przeszłości różne zawiłe problemy.
Kategoria: | Programowanie |
Zabezpieczenie: |
Watermark
|
ISBN: | 978-83-01-21775-4 |
Rozmiar pliku: | 11 MB |
FRAGMENT KSIĄŻKI
Jonathan E. Steinhart zajmował się inżynierią od lat 60. XX wieku. W szkole średniej zaczął projektować sprzęt komputerowy, a oprogramowanie w college’u. Dzięki tym zainteresowaniom dostał się na praktyki letnie do Bell Telephone Laboratories. W 1977 roku uzyskł tytuł magistra (BSEE) z inżynierii elektronicznej i informatyki na Uniwersytecie w Clarkson. Po zakończeniu studiów pracował dla Tektronix, by potem spróbować szczęścia w startupach. W 1987 roku został konsultantem wyspecjalizowanym w inżynierii systemów wysokiej niezawodności. Wycofał się nieco na początku lat 90. XX wieku, by założyć winnicę Four Winds Vineyard.
O recenzencie technicznym
Aubrey Anderson zdobył tytuł BSEE z inżynierii elektronicznej i informatyki na Uniwersytecie w Tufts. Podczas studiów prowadził zajęcia i pomagał poprawiać programy nauczania dla kursów wstępnych z nauk komputerowych. Zaczął programować w wieku 14 lat i od tego czasu pracował nad wieloma projektami z zakresu robotyki, projektowania systemów i technologii sieciowych. Aubrey aktualnie pracuje w Google jako inżynier oprogramowania.PODZIĘKOWANIA
Wiele osób wpłynęło na mnie w sposób, który przyczynił się do powstania tej książki. Należy zacząć od moich rodziców, Roberta i Rosalyn Steinhart, dzięki którym w ogóle miałam tę możliwość, a także dostałem od nich wsparcie w moim zainteresowaniu nauką – przynajmniej do momentu, gdy zaczęło to ich przerażać. Wówczas sprawę przejęło wielu wspaniałych nauczycieli, w tym Beatrice Seagal, William Mulvahill czy Miller Bugliari. Ogromne podziękowania należą się Paulowi Rubenfieldowi za to, że powiedział mi zarówno o Obronie Cywilnej, jak i Skautach Bell Labs.
Nie sposób dać tutaj wyraz wszystkiemu, co zawdzięczam moim drużynowym ze skautingu: Carlowi Christiansenowi i Heinzowi Lycklamie. Oni zmienili moje życie. Dzięki nim poznałem wielu niesamowitych ludzi pracujących w Bell Laboratories, w tym Joe Condona, Sandy’ego Frasera, Dave’a Hegelbargera, Dicka Hause’a, Jima Kaisera, Hanka McDonalda, Maxa Mathewsa, Dennisa Ritchie, Kena Thompsona i Dave’a Wellera. Od każdego z nich wiele się nauczyłem.
Dziękuję Aubrey Anderson, Clemowi Cole, Lee Jalovec, A.C. Mendiones, Edowi Post i Betsy Zeller – każde z nich przynajmniej raz przeczytało całość. W szczególności podziękowania należą się Aubrey za edycję techniczną.
Dziękuję także Mattowi Blaze, Adamowi Cacchettiemu, Sandy Clark, Tomowi Duff, Natalie Freed, Frankowi Heidt, DV Henkel-Wallacowi (znanemu również jako „Grumby”), Lou Katz, Sarze-Jay Terp i Paulowi Vixie za konsultacje w sprawie poszczególnych rozdziałów.
No i dziękuję wszystkim osobom, które odbierały telefony, gdy dzwoniłem do nich z różnymi pytaniami; wśród nich są Ward Cunningham, John Gilmore, Evelyn Mast, Mike Perry, Alex Polvi, Alan Wirfs-Brock i Mike Zuhl. No i oczywiście specjalne podziękowania dla Rakel Hellberg, dziewczyny na wyciągu narciarskim, za danie mi jednego ze szturchnięć motywujących do skończenia tego projektu.
Powstanie tej książki nie byłoby możliwe bez pomocy i zachęty ze strony różnych środowisk gikowskich, włączając w to AMW, Hackersów i TUHS.
Dziękuję Hanalei Steinhart za skomponowanie utworu pokazanego na rysunku 6.36 oraz Julie Donnelly za szalik z rysunku 11.41.
Dziękuję Antoniemu Kotu za pozwolenie na używanie jego podobizny i za utrzymanie mojej klawiatury w stanie należytego zafutrzenia.WPROWADZENIE
Kilka lat temu jechałem wyciągiem narciarskim z naszą szwedzką studentką z wymiany międzynarodowej. Zapytałem, czy zastanawiała się, co będzie robić po zakończeniu liceum. Powiedziała, że rozważała inżynierię i w poprzedniej klasie uczęszczała na kurs programowania. Zapytałem, czego tam uczyli. Opowiedziała: „Javy”. Odruchowo odpowiedziałem wtedy: „Szkoda”.
Dlaczego tak powiedziałem? Zrozumienie tego zajęło mi trochę czasu. Nie chodzi o to, jakoby Java była złym językiem programowania; tak naprawdę jest całkiem przyzwoitym. Powiedziałem to z powodu sposobu, w jaki teraz Java (i inne języki) używana jest do nauki programowania – tzn. _bez uczenia niczego_ _o_ _komputerach_. Jeśli to wydaje ci się dziwne, to jest to książka dla ciebie.
Język programowania Java został wynaleziony przez Jamesa Goslinga, Mike’a Sheridana i Patryka Naughtona w latach 90. XX wieku w Sun Microsystems. Został on częściowo ukształtowany na wzór języka C, który był w tych czasach w powszechnym użyciu. C nie zawiera automatycznego zarządzania pamięcią, a błędy związane z zarządzaniem pamięcią były wówczas częstą przyczyną bólów głowy. Java z założenia wyeliminowała tę klasę błędów programistycznych; ukryła przed programistą całe zarządzanie pamięcią. To między innymi dlatego Java jest tak dobrym językiem do uczenia początkujących programistów. Aby stworzyć dobrego programistę i dobre programy, potrzeba jednak znacznie więcej niż dobrego języka programowania. Okazało się, że Java wprowadziła nową klasę o wiele trudniejszych do debugowania problemów programistycznych związanych z niską wydajnością wywołaną ukrytym zarządzaniem pamięcią.
Jak można się przekonać, czytając tę książkę, zrozumienie działania pamięci jest kluczową umiejętnością dla programisty. Podczas nauki programowania łatwo wykształcić nawyki, które trudno potem będzie zmienić. Badania wykazały, że dzieci, które w dzieciństwie bawiły się na tzw. „bezpiecznych” placach zabaw, mają potem w życiu większy odsetek kontuzji niż te dzieci, które tak nie robiły. Prawdopodobnie dlatego, że na bezpiecznym placu zabaw trudno się nauczyć, że upadek boli. Programowanie jest sytuacją analogiczną. Bezpieczne środowiska programistyczne czynią start o wiele mniej przerażającym, ale trzeba się prędzej czy później przygotować na wyjście w świat zewnętrzny. Ta książka pomoże w takim przejściu.
Dlaczego dobre programowanie jest ważne
Aby zrozumieć, dlaczego uczenie programowania bez jednoczesnego uczenia o komputerach jest problematyczne, warto uświadomić sobie, jak wszechobecne stały się teraz komputery. Ich cena spadła tak drastycznie, że teraz ich użycie jest najtańszym sposobem wytworzenia wielu rzeczy. Na przykład wykorzystanie komputera do wyświetlenia obrazu zegara wskazówkowego w starym stylu na desce rozdzielczej auta jest teraz tańsze niż użycie zegara mechanicznego. Jest to rezultat aktualnie stosowanego sposobu produkcji podzespołów komputerowych: są one teraz w mniejszym lub większym stopniu drukowane. Nie jest już specjalnie trudnym zadaniem wyprodukowanie chipa z miliardami części: wychodzą one niemal dosłownie spod „stempla”. Należy zauważyć, że mowa tu o cenie samych komputerów, a nie o cenie przedmiotów zawierających te komputery. Ogólnie rzecz biorąc, chipy komputerowe kosztują teraz mniej niż opakowanie, w którym się je przesyła. Ich koszt jednostkowy liczony jest w groszach. Już wkrótce zapewne nadejdzie czas, gdy trudno będzie znaleźć cokolwiek, co nie zawiera komputera.
Wiele komputerów wykonujących wiele zadań oznacza wiele programów komputerowych. Ponieważ komputery są tak wszechobecne, programowanie komputerów stało się dziedziną niezwykle zróżnicowaną. Podobnie jak ma to miejsce na polu medycyny, wielu programistów zostaje specjalistami. Można specjalizować się w grafice, animacjach, stronach internetowych, aplikacjach na telefon, nadzorze przemysłowym, sprzęcie medycznym i tak dalej.
Dziwną rzeczą wyróżniającą programowanie jest to, że inaczej niż w medycynie, łatwo zostać specjalistą, nie będąc wcześniej wszechstronnym programistą. Prawdopodobnie nikt nie chciałby się oddać w ręce kardiochirurga, który nie ma pojęcia o ludzkiej anatomii, ale odpowiednik tej sytuacji stał się w zasadzie normą jeśli chodzi o dzisiejszych programistów. Ale czy rzeczywiście jest to problem? Tak naprawdę istnieje bogaty materiał dowodowy na to, że to nie działa zbyt dobrze, począwszy od niemal codziennych doniesień o naruszeniu bezpieczeństwa, po wycofywanie produktów z rynku. Istnieją zapisy spraw sądowych, w których oskarżeni o prowadzenie po pijanemu kierowcy uzyskiwali prawo do wglądu w kod alkomatu. Okazywało się, że kod jest pełen błędów, a to z kolei doprowadzało do obalenia wyroków. Niedawno program antywirusowy zawiesił sprzęt medyczny w trakcie operacji serca. Ludzie ginęli z powodu problemów z oprogramowaniem w samolocie Boeing 737 MAX. Wielka liczba podobnych wypadków nie wzbudza dużego zaufania.
Nauka programowania to dopiero początek
Częściowym powodem takiego stanu rzeczy jest fakt, że naprawdę nie jest trudno napisać program komputerowy, który _wydaje się_ działać, lub taki, który działa w większości przypadków. Jako analogii użyjmy zmian w muzyce (nie disco!) lat 80. XX wieku. W dawniejszych czasach, by tworzyć muzykę, trzeba było najpierw nauczyć się podstaw. Obejmowało to naukę teorii muzyki i kompozycji, grę na instrumencie, trening słuchu i wiele, wiele praktyki. Wtedy pojawił się standard cyfrowego interfejsu instrumentów muzycznych (_Musical Instrument Digital Interface_), w skrócie MIDI. Opracowany przez Ikutaro Kakehashi z Roland, pozwalał każdemu na tworzenie muzyki na własnym komputerze i nikt nie musiał przy tym „dostawać odcisków”. Uważam, że tylko niewielki procent „muzyki” wytwarzanej komputerowo jest tak naprawdę muzyką – w większości jest to po prostu hałas. _Muzyka_ jest tworzona przez prawdziwych muzyków, którzy mogą, lecz nie muszą korzystać z MIDI, by tworzyć na bazie własnej wiedzy i umiejętności. Programowanie zaczęło ostatnio przypominać używanie MIDI. Nie trzeba już się pocić czy spędzać lat na praktyce, czy nawet nauce teorii, by napisać jakiś program. Ale nie znaczy to, że są to programy, na których można polegać.
Ta sytuacja najprawdopodobniej tylko się pogorszy, przynajmniej w Stanach Zjednoczonych. Bogaci ludzie mający własne interesy, tacy jak na przykład właściciele firm produkujących oprogramowanie, od dawna lobbowali za ustawodawstwem zmuszającym każdego do nauki programowania w szkole. To brzmi świetnie w teorii, ale nie jest dobry pomysł w praktyce, ponieważ nie każdy ma predyspozycje, aby zostać dobrym programistą. Nie każemy wszystkim uczyć się gry w futbol, bo zdajemy sobie sprawę, że nie jest to sport dla każdego. Prawdziwym celem takiej inicjatywy nie jest najprawdopodobniej wykształcenie świetnych programistów, a raczej zwiększenie zysków firm przez zalanie rynku słabymi programistami, co doprowadziłoby do obniżenia płac. Ludzie stojący za tymi działaniami nie dbają zbytnio o jakość kodu, domagają się również wprowadzenia przepisów, które ograniczą ich odpowiedzialność za działanie wadliwych produktów. Oczywiście można sobie programować dla zabawy tak samo, jak można dla zabawy grać w futbol. Nie należy tylko spodziewać się przez to udziału w grze o Super Bowl.
W 2014 roku prezydent Obama stwierdził, że nauczył się kodowania. Poprzesuwał kilka rzeczy w skądinąd doskonałym narzędziu wizualnego programowania Blockly, a nawet napisał jeden wiersz kodu w JavaScripcie (języku programowania całkowicie niezwiązanym z Javą, wynalezionym w Netscape, poprzedniku Mozilla Foundation, na bazie której działa wiele pakietów webowych, w tym przeglądarka internetowa _FireFox_). Kto jednak myśli, że to oznacza, iż on naprawdę nauczył się programowania? Mała podpowiedź: jeśli ktoś uważa, że tak, to oprócz przeczytania tej książki powinien prawdopodobnie popracować nad umiejętnością krytycznego myślenia. Pewnie, mógł może się przyswoić jakiś mały fragment wiedzy o programowaniu, ale nie, _nie nauczył się programować_. Jeśli można by się było nauczyć programować w ciągu mniej więcej godziny, to programowanie musiałoby być na tyle trywialne, że nauczanie go w szkołach byłoby stratą czasu.
Znaczenie podstawowej wiedzy
Interesujący i nieco przeciwny do mojego pogląd na temat tego, jak uczyć programowania, został wyrażony na blogu przez Stephena Wolframa, twórcę programu Mathematica i języka Wolfram, we wpisie zatytułowanym „How to Teach Computational Thinking” (Jak nauczyć myślenia obliczeniowego). Wolfram definiuje myślenie obliczeniowe jako „formułowanie problemów na tyle jasno i systematycznie, by móc dzięki temu powiedzieć komputerowi, jak ma je rozwiązać”. Całkowicie się zgadzam z tą definicją. W rzeczywistości jest to w dużej mierze motywacja do napisania tej książki.
Stanowczo jednak nie zgadzam się ze stanowiskiem Wolframa, że ci, którzy uczą się programować, powinni rozwinąć swoje umiejętności myślenia obliczeniowego za pomocą potężnych narzędzi wysokiego poziomu, podobnych do tych, które on wynalazł, zamiast uczyć się podstawowych technologii. Na przykład na podstawie rosnącego zainteresowania statystyką w stosunku do rachunku różniczkowego, widać wyraźnie, że przekształcanie danych jest rozwijających się obszarem wiedzy. Co jednak się dzieje, gdy ludzie po prostu wrzucają stosy danych w program, z którego działaniem nie są dobrze obeznani?
Jednym z możliwych rezultatów jest generowanie wyników ciekawie wyglądających, lecz albo nieprawidłowych, albo wręcz bezsensownych. Niedawne badania (np. „Gene Name Errors are Widespread in the Scientific Literature” autorstwa Marka Ziemanna, Yotama Erena i Assama El-Osta) wykazały, że jedna piąta opublikowanych artykułów z dziedziny genetyki zawiera błędy powstałe przez nieprawidłowe posługiwanie się arkuszami kalkulacyjnymi. Pomyślmy o możliwych błędach i ich następstwach, gdyby jeszcze potężniejsze narzędzia znalazły się w rękach jeszcze większej liczby ludzi! Dokładne wykonanie jest bardzo ważne tam, gdzie rezultaty wpływają na życie ludzkie.
Zrozumienie podstawowych technologii pozwala wykształcić wyczucie tego, co może pójść źle. Znajomość jedynie narzędzi wysokiego poziomu sprawia, że zadaje się nie te pytania, co trzeba. Warto nauczyć się obsługi młotka, zanim przejdzie się do użycia gwoździarki. Innym powodem, dla którego warto poznać podstawowe systemy, jest fakt, że daje to możliwość budowania nowych narzędzi. Jest to bardzo ważne, ponieważ zawsze istnieje zapotrzebowanie na twórców narzędzi, nawet jeśli to użytkowników jest o wiele więcej. Poznanie budowy komputera na tyle, by zachowanie programu nie było tajemnicą, pozwala na pisanie lepszego kodu.
Kto powinien przeczytać tę książkę?
Ta książka jest dla tych, którzy chcą zostać dobrymi programistami. Co sprawia, że programista jest dobry? Przede wszystkim dobry programista ma wyrobione myślenie krytyczne i zdolność analizy. Do rozwiązywania złożonych problemów niezbędna jest umiejętność oceny, czy dany program rozwiązuje poprawnie dane zagadnienie. To jest o wiele trudniejsze, niż się wydaje. Nie jest niczym niecodziennym, gdy doświadczony programista patrzy na kod kogoś innego i złośliwie komentuje: „To bardzo skomplikowane nierozwiązanie bardzo prostego nieproblemu”.
Czytelnik może być obeznany z klasycznym motywem literatury fantastycznej, gdzie czarnoksiężnik zdobywa władzę magiczną nad przedmiotem przez poznanie jego prawdziwego imienia. Biada wtedy czarnoksiężnikowi, który by zapomniał o jakimś szczególe. Dobry programista jest jak czarnoksiężnik, który może uchwycić swoim umysłem istotę rzeczy bez pomijania szczegółów.
Dobry programista ma w sobie też pierwiastek artyzmu, jak wykwalifikowany rzemieślnik. Nie jest niczym niecodziennym znalezienie kawałka kodu, który jest całkowicie nieczytelny, tak jak wiele osób posługujących się językiem angielskim jest całkowicie zbitych z tropu powieścią Jamesa Joyce’a _Finneganów tren_. Dobry programista pisze kod, który nie tylko działa, ale też jest łatwy do zrozumienia i utrzymania dla innych.
I wreszcie, dobry programista musi dogłębnie rozumieć działanie komputerów. Nie można dobrze rozwiązywać skomplikowanych problemów, posługując się płytką bazą wiedzy. To jest książka dla tych, którzy uczą się programowania, ale są niezadowoleni z braku tej szczegółowej wiedzy. Jest ona również dla tych, którzy już programują, ale chcą czegoś więcej.
Czym jest komputer?
Powszechną odpowiedzią na to pytanie jest, że komputer jest urządzeniem, którego ludzie używają do zadań, takich jak sprawdzanie e-maili, zakupy internetowe, pisanie artykułów, porządkowanie zdjęć i gry komputerowe. Podobne odpowiedzi są rezultatem niedokładnej terminologii, która stała się powszechna wraz z pojawieniem się produktów konsumpcyjnych zawierających komputery. Inną powszechnie spotykaną odpowiedzią na to pytanie jest to, że komputery są mózgami, które pozwalają działać naszym zaawansowanym technicznie zabawkom, takim jak telefony komórkowe czy odtwarzacze muzyki. To już jest bliższe prawdy.
Wysyłanie e-maila czy granie jest możliwe dzięki programom działającym na komputerach. Sam komputer jest jak nowo narodzone dziecko. Nie bardzo wie, co ma robić. Zdecydowanie zbyt rzadko myślimy o podstawowej maszynerii ludzkiej, ponieważ mamy kontakt przeważnie tylko z konkretnymi osobowościami, które działają na tej maszynerii tak, jak programy działają na komputerze. Na przykład gdy przeglądasz stronę internetową, nie robisz tego z użyciem tylko swojego komputera: przeglądasz ją za pomocą programu, który napisał kto inny, a program ten działa na twoim komputerze, na komputerze hostującym stronę internetową i na wszystkich tych komputerach pomiędzy nimi, które sprawiają, że Internet działa.
Czym jest programowanie?
Nauczyciele są ludźmi, którzy trenują podstawową maszynerię ludzką do tego, by wykonywała ona określone zadania. Podobnie, programując, stajemy się nauczycielami komputerów. Programiści uczą komputery robić to, czego chcą.
Wiedza o tym, jak nauczyć czegoś komputery, bywa przydatna, zwłaszcza wtedy, gdy chciałoby się, by robiły coś, czego jeszcze nie umieją robić i gdy nie można po prostu pójść do sklepu i kupić do tego programu, ponieważ nikt jeszcze podobnego programu nie napisał. Na przykład większość czytelników zapewne uważa sieć WWW za coś oczywistego, ale została ona wynaleziona nie tak dawno temu, gdy Sir Tim Bernes-Lee potrzebował bardziej wydajnego sposobu komunikacji między naukowcami Europejskiej Organizacji Badań Jądrowych (Organisation Européenne pour la Recherche Nucléaire, CERN). I otrzymał za to tytuł rycerski2. Nieźle, prawda?
Uczenie komputerów jest skomplikowane, ale mimo wszystko prostsze niż uczenie ludzi. O wiele lepiej znamy funkcjonowanie komputerów niż ludzi. No i komputer raczej na nikogo nie zwymiotuje.
Programowanie komputera to proces dwuetapowy:
1. Zrozum wszechświat.
2. Wyjaśnij go trzylatkowi.
Co to oznacza? Nie można napisać programu komputerowego służącego do robienia rzeczy, których samemu się nie rozumie. Na przykład nie można napisać programu do sprawdzania pisowni, jeśli nie zna się zasad pisowni, i nie można napisać dobrej gry komputerowej, jeśli się nie zna fizyki. Tak więc pierwszym krokiem do pozostania dobrym programistą jest nauczenie jak najwięcej o wszystkim innym . Rozwiązania problemów można znaleźć często w bardzo zaskakujących miejscach, więc nie należy ignorować czegoś tylko dlatego, że nie od razu wydaje się istotne.
Drugi etap procesu wymaga wyjaśnienia tego, co się wie, maszynie, która ma, tak jak małe dzieci, bardzo sztywne spojrzenie na świat. Ta sztywność u dzieci jest naprawdę oczywista, gdy mają one około trzech lat. Powiedzmy, że próbujesz wyjść z dzieckiem na dwór. Pytasz go: „Gdzie są twoje buty?”, a ono odpowiada: „Tam”. Odpowiedziało przecież na pytanie. Problem polega na tym, że nie rozumie ono, że tak naprawdę mówisz mu, żeby założyło buty, byście oboje mogli wyjść z domu i pójść gdzieś. Elastyczność i zdolność do wyciągania wniosków to umiejętności, których dzieci nabywają w miarę dorastania. Ale komputery są jak Piotruś Pan: nigdy nie dorastają.
Komputery przypominają małe dzieci pod jeszcze jednym względem: nie potrafią generalizować. Są oczywiście bardzo pożyteczne, bo gdy już wykombinuje się, jak przekazać im jakieś instrukcje, będą to robić bardzo szybko i bez znużenia, choć same nie mają ani trochę zdrowego rozsądku. Komputer bez znużenia będzie wykonywał zadaną czynność bez wnikania w to, czy jest to właściwe zadanie – tak jak zaczarowana miotła z _Ucznia czarnoksiężnika_, fragmentu filmu _Fantazja_ z 1940 roku. Proszenie komputera o zrobienie czegoś jest jak proszenie dżina z magicznej lampy (tylko nie w wersji FBI) o spełnienie życzenia. Trzeba być naprawdę ostrożnym w wyborze życzenia!
Możesz wątpić z to, co tu mówią, gdyż komputery wydają się o wiele bardziej zdolne niż rzeczywiście są. Kiedy używa się komputera, może on wiedzieć na przykład, jak rysować rysunki, poprawiać czyjąś pisownię, rozumieć wypowiadane słowa, odtwarzać muzykę i tak dalej. Należy jednak pamiętać, że to nie komputer – to skomplikowany zbiór programów komputerowych, które ktoś wcześniej napisał, a które pozwalają komputerowi wykonywać te wszystkie zadania. Komputery należy oddzielić od programów, które na nich są wykonywane.
To trochę jak obserwowanie samochodu na drodze. Wydaje się, że samochód całkiem nieźle się zatrzymuje i rusza w odpowiednich momentach, unika przeszkód, dociera do celu, je, gdy jest głodny i tak dalej. Ale to nie jest tylko samochód. To samochód i kierowca zapakowane razem. Komputery są jak samochody, a programy są jak kierowcy. Nie mając wiedzy, nie można orzec, która czynność wykonywana jest przez kierowcę, a która przez samochód (patrz wiersz autorstwa May Swenson, _Southbound on the Freeway_. Odpowiedź na ostatnie pytanie postawione w tym wierszu może zmieniać się z wiekiem czytającego).
Podsumowując, programowanie komputerowe wymaga nauczenia się tego, co jest potrzebne, by rozwiązać zadany problem, a potem wytłumaczyć to małemu dziecku. Ponieważ istnieje wiele sposobów na rozwiązanie problemu, programowanie w równym stopniu jest sztuką i nauką. Polega ono na znajdowaniu eleganckiego rozwiązania w przeciwieństwie do siłowego rozwiązywania problemów. Tak, _można_ wyjść z domu, robiąc dziurę w ścianie, ale zapewne łatwiej jednak wyjść drzwiami. Wiele osób potrafi napisać coś takiego jak _HealthCare.org_ w milionach wierszy kodu, ale potrzeba umiejętności, by zmieścić to w tysiącach wierszy.
Zanim jednak można cokolwiek wytłumaczyć trzylatkowi, trzeba się nieco nauczyć na temat trzylatków oraz tego, co mogą zrozumieć. I nie jest to jakiś zwykły trzylatek – to obca forma życia. Komputer nie gra według tych samych zasad co my. Zapewne wielu z was słyszało o sztucznej inteligencji (AI), która stara się, by komputery zachowywały się bardziej jak ludzie. Postęp w tej dziedzinie zachodzi o wiele wolniej, niż to z początku przewidywano. Głównie dlatego, że tak naprawdę w większości nie rozumiemy problemu: nie wiemy dostatecznie wiele na temat tego, jak myśli człowiek. Tak jak można sobie wyobrazić, nie jest łatwo nauczyć ufoludka myśleć tak jak my, jeśli my sami mamy niewielkie pojęcie o tym, jak to dokładnie się odbywa.
Ludzki mózg pozwala nam robić rzeczy bez konieczności świadomego myślenia o nich. Nasze mózgi są na początku czystym, niezapisanym sprzętem, który następnie jest programowany. Na przykład uczymy się poruszać palcami, by następnie nauczyć się chwytać przedmioty. Po odpowiedniej praktyce można po prostu złapać jakąś rzecz, nie myśląc o każdym ruchu, jaki w tym celu trzeba wykonać. Tacy filozofowie, jak Jean Piaget (1898–1980, francuski psycholog) czy Noam Chomsky (ur. 1928, amerykański lingwista) opracowali różne teorie na temat tego, jak odbywa się ten proces uczenia się. Czy mózg jest w miarę jednorodną maszyną ogólnego przeznaczenia, czy też ma specjalny sprzęt do takich funkcji jak język? Ta kwestia nadal jest badana.
Nasza niezwykła zdolność do nieświadomego wykonywania czynności sprawia, że nauka programowania jest trudna, ponieważ programowanie wymaga, by każde zadanie rozłożyć na części składowe, na kroki, które komputer jest w stanie wykonać. Na przykład większość czytelników najprawdopodobniej wie, jak grać w kółko i krzyżyk. Dla eksperymentu warto zebrać razem grupę ludzi i niech każdy niezależnie wypisze ruchy, jakie powinien wykonać gracz w zależności od sytuacji na planszy (z pewnością można znaleźć w Internecie pełną listę ruchów, ale nie warto psuć sobie zabawy). Gdy już każdy zakończy swoją listę, zróbcie zawody. Dowiecie się, czyje reguły wygrywają! Jak dobre były twoje reguły? Czego w nich zabrakło? Czy wiedziałeś, co tak naprawdę robisz, gdy grasz w tę grę? Najprawdopodobniej części czynników zabrakło w spisie, ponieważ gracz rozumie je intuicyjnie i zapomniał je wypisać.
Na wypadek, jeśli jeszcze nie jest to oczywiste: pierwszy krok, zrozumienie wszechświata, jest o wiele ważniejszy niż ten drugi, wyjaśnienie wszystkiego trzylatkowi. Wystarczy chwilę pomyśleć: jaki jest pożytek z wiedzy o sposobie mówienia, skoro się nie wie, co powiedzieć? Mimo to aktualnie nauczanie programowania skupia się na drugim kroku. Dzieje się tak dlatego, że o wiele łatwiej nauczać i oceniać mechaniczne aspekty zadania niż jego aspekty kreatywne. Po części również dlatego, że nauczyciele przeważnie nie mają doświadczenia w przedmiocie, który wykładają i korzystają z programów nauczania opracowanych gdzie indziej. Ta książka jednak skupia się na pierwszym kroku. Chociaż nie może ona obejmować opisu całego wszechświata, skupia się ona na opisie problemów i ich rozwiązań w świecie komputerów, zamiast zajmować się dokładną składnią programowania potrzebnego do implementacji tych rozwiązań.
Kodowanie, programowanie, inżynieria i informatyka
Do opisu prac nad oprogramowaniem używa się szeregu różnych terminów. Nie mają one oficjalnych definicji, chociaż z czasem nabrały dość określonego znaczenia.
_Kodowanie_ jest względnie nowym terminem, spopularyzowanym jako część ruchu „uczenia się kodowania” – może być ono rozumiane jako mechaniczna praca tłumaczenia. Porównajmy kodowanie komputerowe do kodowania medycznego. Podczas wizyty u lekarza postawienie diagnozy to łatwa część. Trudną częścią zadania jest przetłumaczenie diagnozy na jeden z ponad stu tysięcy kodów składających się na najnowszy standard ICD (w czasie, kiedy to piszę, jest to standard ICD-10). Certyfikowany koder zawodowy, który nauczył się wszystkich tych kodów na pamięć, wie, że jeśli doktor wymyśli diagnozę „uderzony przez krowę”, trzeba będzie przypisać choremu kod W55.2XA. To jest tak naprawdę trudniejsze niż większość kodowania w branży programistycznej, chociażby z powodu ilości dostępnych kodów. Sam jednak proces jest podobny do tego, co dzieje się, gdy poinstruujemy kodera, by „pogrubił ten tekst” na stronie internetowej – koder wie, jakiego kodu użyć, by to się stało.
Standard ICD-10 jest tak skomplikowany, że niewielu jest koderów, którzy znają go w całej rozciągłości. Koderzy medyczni certyfikują się zamiast tego w obszarach specjalizacji, na przykład „choroby układu nerwowego” czy „zaburzenia mentalne i behawioralne”. Podobnie programista może być biegły w konkretnym języku, takim jak HTML czy JavaScript.
Ale _programowanie_ – tzn. bycie programistą – oznacza zna się na czymś więcej niż tylko jednena czy dwa obszary specjalizacji. W naszej analogii odpowiednikiem programisty jest lekarz. Stawia on diagnozę przez zbadanie pacjenta. To zadanie może być bardzo skomplikowane. Na przykład, jeśli pacjent ma poparzenia i jest przemoczony, to czy jest to przypadek „dziwacznego wyglądu osobistego” (R46.1), czy też „poparzenia w wyniku pierwszego zetknięcia z płonącymi nartami wodnymi” (V91.07XA)? Gdy już lekarz wystawi diagnozę, można opracować plan leczenia. Plan musi być skuteczny, lekarz prawdopodobnie nie chciałby zobaczyć tego samego pacjenta ponownie, tym razem jako ofiary ostrego przypadku „nadopiekuńczości rodzicielskiej” (Z62.1).
Tak jak czyni to lekarz, programista ocenia problem i określa rozwiązanie. Istnieje, być może, potrzeba utworzenia strony internetowej, na której użytkownicy mogliby tworzyć ranking najbardziej niemądrych kodów ICD-10. Programista jest w stanie określić najlepszy algorytm przechowywania danych i operowania na nich, strukturę komunikacji klienta z serwerem, interfejs użytkownika i tak dalej. To nie jest proste „wklejanie kodu”.
_Inżynieria_ to kolejny krok w kierunku złożoności. Ogólnie rzecz biorąc, inżynieria to sztuka zastosowania posiadanej wiedzy do wykonywania jakichś zadań. Można uznać stworzenie standardu ICD za przykład inżynierii: wzięto ogromny obszar diagnozy lekarskiej i zredukowano go do zestawu kodów, które można o wiele łatwiej śledzić i analizować niż notatki lekarskie. Jest kwestią opinii, czy system tak bardzo skomplikowany jest przykładem _dobrej_ inżynierii. Jako przykład inżynierii komputerowej, wiele lat temu pracowałem w projekcie mającym na celu wyprodukowanie tanich monitorów medycznych, takich jakie widać niekiedy w szpitalach. Moim zadaniem było opracowanie systemu, który doktor albo pielęgniarka mogliby rozgryźć w pięć minut bez pomocy dokumentacji. Jak można sobie wyobrazić, zadanie wymagało o wiele więcej niż tylko wiedzy dotyczącej programowania. Ja wykonałem zadanie nawet lepiej – moje rozwiązanie wymaga mniej więcej 30-sekundowej nauki.
Programowanie jest często mylone z informatyką. Choć wielu informatyków programuje, większość programistów nie jest informatykami. _Informatyka_ jest nauką o obliczeniach. Odkrycia z zakresu informatyki wykorzystywane są zarówno przez inżynierów oprogramowania, jak i przez programistów.
Kodowanie, programowanie, inżynieria programowania i informatyka są oddzielnymi, choć powiązanymi ze sobą dyscyplinami. Różnią się od siebie rodzajem i ilością wiedzy, jakiej wymagają. Bycie informatykiem, inżynierem oprogramowania lub koderem nie czyni nikogo automatycznie dobrym programistą. Ta książka daje jakieś pojęcie o tym, jak myślą inżynierowie i informatycy, ale nikogo nie uczyni ani jednym, ani drugim. To wymaga kierunkowego wykształcenia połączonego ze zdobyciem doświadczenia. Inżynieria i programowanie podobne są muzyki lub malarstwa – to po części umiejętności, a po części sztuka. Przedstawienie obu tych aspektów w tej książce powinno pomóc każdemu w rozwoju jego umiejętności programistycznych.
Krajobraz
Projektowanie i programowanie komputerów jest ogromną dziedziną wiedzy, której nie będę mógł tutaj umówić w pełni. Można ją sobie wyobrazić w postaci warstw, tak jak to pokazano na rysunku 1.
_Rysunek 1. Krajobraz komputerowy_
Należy pamiętać o tym, że rysunek 1 jest uproszczeniem i że linie oddzielające od siebie poszczególne warstwy w rzeczywistości nie są aż tak wyraźne.
Większość ludzi jest _użytkownikami_ systemów komputerowych. Czytelnicy tej książki zapewne są teraz w tej grupie. Istnieje wydzielony rodzaj wyspecjalizowanych użytkowników nazywanych _administratorami systemu_, których zadaniem jest utrzymanie nieprzerwanego działania systemu. To oni instalują oprogramowanie, zarządzają kontami użytkowników, robią kopie zapasowe i tak dalej. Zazwyczaj mają specjalne uprawnienia, których nie nadaje się zwykłym użytkownikom.
Ludzi, którzy piszą programy, takie jak strony internetowe, aplikacje na smartfony, czy odtwarzacze muzyki, nazywamy _programistami aplikacji_. Tworzą oni oprogramowanie, którego użytkownicy używają do interakcji z komputerami. Korzystają przy tym z bloków utworzonych przez innych. Programowania aplikacji uczy się na większości kursów w stylu „naucz się kodować”, tak jakby wszyscy programiści musieli się nauczyć, jak importować te czy inne bloki składowe i skleić je razem. Chociaż w większości przypadków wystarcza to do wykonania zadania, o wiele lepiej poznać zarówno te bloki, jak i klej, którego się używa.
Programy aplikacyjne nie rozmawiają bezpośrednio z sprzętem komputerowym – to tutaj _programowanie systemowe_ wchodzi do gry. Programiści systemowi budują bloki używane przez programistów aplikacji. Muszą oni znać budowę sprzętu, ponieważ ich kod się z nim komunikuje. Jednym z celów tej książki jest nauczenie czytelnika rzeczy, które trzeba wiedzieć, by być dobrym programistą systemowym.
Sprzęt komputerowy (_hardware_) zawiera nie tylko część wykonującą właściwe obliczenia, lecz także określa, jak ta część komunikuje się ze światem zewnętrznym. Sprzęt jest wyrażony poprzez _układy logiczne_. Układy logiczne stanowią fizyczne wcielenie tej samej logiki, która jest używana do pisania programów komputerowych i jest kluczowa do zrozumienia pracy komputera. Układy logiczne są zbudowane z różnego rodzaju _obwodów_ elektronicznych. Projektowanie obwodów wykracza poza zakres tej książki, ale można się wiele się o nich dowiedzieć, studiując elektrotechnikę. Jeśli chcesz rządzić światem, rozważ podwójny dyplom: z elektrotechniki i informatyki.
Oczywiście u podstaw tego wszystkiego kryją się nauki podstawowe, które dają nam wszystko – od zrozumienia elektryczności po wiedzę chemiczną niezbędną do budowy mikroprocesorów.
Tak jak to pokazano na rysunku 1, każdy poziom bazuje na tym, co znajduje się pod nim. Oznacza to, że błędy lub nieoptymalne wybory na niższych poziomach będą wpływały na wszystko powyżej. Błąd projektanta w procesorach Intel Pentium około 1994 roku sprawił, że niektóre operacje dzielenia dawały niedokładne wyniki. To miało wpływ na całe oprogramowanie, które korzystało z dzielenia zmiennoprzecinkowego wykonywanego na tych procesorach.
Jak widać, programowanie systemowe znajduje się na dole hierarchii oprogramowania. Jest ono podobne do infrastruktury, takiej jak drogi, elektryczność, woda. Zawsze jest ważne, żeby być dobrym programistą, ale jest to tym ważniejsze, jeśli jesteś programistą systemowym, ponieważ inni opierają swą pracę na zbudowanej przez ciebie infrastrukturze. Widać również, że programowanie systemowe jest umieszczone między programowaniem aplikacji a sprzętem komputerowym, co oznacza, że programista systemowy musi sporo wiedzieć o jednym i o drugim. Słowo „joga” w sanskrycie tłumaczy się jako „jedność”, i tak jak praktykujący jogę poszukują zjednoczenia swojego umysłu i ciała, programiści systemowi są techno-joginami, którzy jednoczą sprzęt z oprogramowaniem.
Nie trzeba uczyć się programowania systemowego, by pracować na którymś z pozostałych poziomów. Ale jeśli się tego nie nauczymy, będziemy zdani na pomoc innej osoby w rozwiązaniu problemów spoza własnej dziedziny, zamiast po prostu rozwiązać je samemu. Rozumienie istotnych technologii prowadzi również do lepszego wyboru rozwiązań na wyższym poziomie. To nie jest jedynie moja opinia: zachęcam do przeczytania postu z 2014 roku: „The Resource Leak Bug of Our Civilisation” („Błąd wycieku zasobów naszej cywilizacji”) autorstwa Ville-Matias Heikkila.
Celem tej książki jest także opisanie wielu historii retro. Większość programistów nie uczy się historii własnego rzemiosła, ponieważ i bez tego jest mnóstwo materiału do opanowania. W rezultacie większość ludzi popełnia te same błędy, które już wielokrotnie były popełnianie w przeszłości. Poznanie nieco historii programowania umożliwia przynajmniej robienie nowych i „lepszych” błędów zamiast powtarzania starych. Należy też pamiętać, że nowe, pionierskie technologie ery dzisiejszej bardzo szybko staną się technologiami retro dla jutra.
Skoro już mowa o historii, w książce tej pełno jest interesujących technologii i nazwisk ich wynalazców. Warto poświęcić nieco czasu, aby dowiedzieć się czegoś więcej zarówno na temat technologii, jak i ludzi. Większość z wymienionych tu osób rozwiązała w życiu przynajmniej jeden interesujący problem i warto dowiedzieć się, jak postrzegali oni swój świat i w jaki sposób podchodzili do problemów i je rozwiązywali. W powieści Neala Stephensona z 2008 roku _Anatema_ znajduje się świetna wymiana zdań:
– Nasz przeciwnik to statek kosmiczny obcych wypchany bombami atomowymi. My dysponujemy kątomierzem.
– Dobrze. Pójdę do domu i zobaczę, czy uda mi się znaleźć linijkę i kawałek sznurka.
Zwróćmy uwagę na to opieranie się na rzeczach podstawowych. Żadnego „zobaczmy w Wikipedii, jak to zrobić” czy „zamieszczę zapytanie na Stack Overflow”, czy też „znajdę jakiś pakiet na GitHubie”. Nauczenie się rozwiązywania problemów, których jeszcze nikt przed nami nie rozwiązał, jest kluczową umiejętnością programisty.
Wiele przykładów umieszczonych w tej książce opiera się na starych technologiach, takich jak komputery 16-bitowe. A to dlatego, że na ich podstawie można nauczyć się niemal wszystkiego, co jest potrzebne, a jednocześnie łatwiej zmieścić je na stronie.
Co się znajduje w tej książce
Książka ta jest konceptualnie podzielona na trzy części. Pierwsza z nich omawia sprzęt komputerowy – zarówno to, czym on jest, jak i jego budowę. Druga część opisuje zachowanie oprogramowania działającego na tym sprzęcie. Ostatnia część omawia sztukę programowania – współpracy z innymi w celu wytworzenia dobrego oprogramowania.
ROZDZIAŁ 1: JĘZYK WEWNĘTRZNY KOMPUTERÓW
W tym rozdziale zaczynamy przyglądać się mentalności trzylatka. Komputery to gracze bitowi; ich zawód to hodowla bitów. Nauczysz się, czym są bity i co można z nimi zrobić. Zabawimy się w udawanie, aby nadać znaczenie bitom i zbiorom bitów.
ROZDZIAŁ 2: UKŁADY KOMBINACYJNE
W tym rozdziale poznasz powody, dla których używa się bitów zamiast cyfr i przeanalizujemy uzasadnienie dla komputerów cyfrowych. Rozważania te obejmują omówienie jednej z najstarszych technologii, jakie przetarły ścieżki dla tych, których obecnie używamy. Poznasz podstawy układów kombinacyjnych. Nauczysz się, jak budować bardziej skomplikowane funkcjonalności z bitów i układów.
ROZDZIAŁ 3: UKŁADY SEKWENCYJNE
Tutaj dowiesz się, jak użyć układów logicznych do zbudowania pamięci. Obejmuje to zagadnienie wytworzenia czasu, gdyż pamięć jest niczym innym jak stanem, który utrzymuje się w czasie. W tym rozdziale poznasz podstawy układów sekwencyjnych i omówimy różne technologie pamięci.
ROZDZIAŁ 4: ANATOMIA KOMPUTERA
W tym rozdziale dowiesz się, w jaki sposób komputery zbudowane są z układów logicznych i elementów pamięci omawianych we wcześniejszych rozdziałach. Przeanalizujemy kilka różnych metodologii implementacyjnych.
ROZDZIAŁ 5: ARCHITEKTURA KOMPUTERA
W tym rozdziale zajmiemy się z kilkoma dodatkami do prostego komputera, jaki widzieliśmy w rozdziale 4. Dowiesz się, w jaki sposób zapewniają one istotne funkcjonalności i wydajność.
ROZDZIAŁ 6: ROZKŁAD KOMUNIKACJI
Komputery powinny komunikować się ze światem zewnętrznym. W tym rozdziale poznasz urządzenia wejścia i wyjścia. Przeanalizujemy też różnicę między tym, co cyfrowe a tym, co analogowe i zastanowimy się, jak cyfrowe komputery mogą działać w świecie analogowym.
ROZDZIAŁ 7: ORGANIZACJA DANYCH
Gdy już wiesz, jak działają komputery, zobaczymy, jak z nich efektywnie korzystać. Programy komputerowe operują na danych w pamięci, jest więc istotne, by odwzorować sposób korzystania z pamięci na problem, jaki chcemy rozwiązać.
ROZDZIAŁ 8: PRZETWARZANIE JĘZYKA
Języki (programowania) wynaleziono po to, by ułatwić ludziom programowanie komputerów. W tym rozdziale przyjrzymy się procesowi przemiany języków w coś, co naprawdę działa na komputerze.
ROZDZIAŁ 9: PRZEGLĄDARKI INTERNETOWE
Wiele prac programistycznych wykonuje się na potrzeby przeglądarek internetowych. W tym rozdziale przyjrzymy się sposobowi działania przeglądarki internetowej oraz jej głównym częściom składowym.
ROZDZIAŁ 10: PROGRAMOWANIE APLIKACYJNE I SYSTEMOWE
W tym rozdziale utworzymy dwie różne wersje programu, które działają na dwóch poziomach z rysunku 1. W ten sposób pokażemy główne różnice między programowaniem aplikacyjnym a systemowym.
ROZDZIAŁ 11: SKRÓTY I PRZYBLIŻENIA
Bardzo ważne, aby tworzyć wydajne programy. W tym rozdziale przyjrzymy się niektórym sposobom na to, by programy były bardziej wydajne i nie wykonywały niepotrzebnej pracy.
ROZDZIAŁ 12: ZAKLESZCZENIA I WYŚCIGI
Wiele systemów składa się z więcej niż jednego komputera. W tym rozdziale poznasz kilka problemów, które mogą wystąpić, gdy staramy się zmusić komputery do współpracy.
ROZDZIAŁ 13: BEZPIECZEŃSTWO
Bezpieczeństwo komputerowe to zaawansowany temat. W tym rozdziale przedstawiamy podstawy tego zagadnienia, unikając przy tym ciężkiej matematyki.
ROZDZIAŁ 14: SZTUCZNA INTELIGENCJA
W tym rozdziale znów zmierzymy się ze skomplikowanym zagadnieniem. Z połączenia wielkich danych, sztucznej inteligencji i uczenia się maszyn powstają nowe aplikacje – od prowadzenia samochodu aż po doprowadzenie wszystkich do załamania nerwowego za pomocą reklam.
ROZDZIAŁ 15: ŚWIAT REALNY
Programowanie jest procesem bardzo metodycznym i logicznym. Jednak w określanie co i jak programować zaangażowani są również ludzie, a ludziom często brakuje logiki. W tym rozdziale omówiono kilka zagadnień dotyczących programowania w świecie rzeczywistym.
Podczas lektury książki warto pamiętać, że wiele spośród wyjaśnień jest uproszczonych, a przez to mogą nie być prawidłowe we wszystkich szczegółach. Dalsze udoskonalenie tych wyjaśnień wymagałoby jednak zbyt wielu rozpraszających szczegółów. Jeśli w miarę postępów nauki zaczniesz odkrywać takie nieścisłości, nie bądź tym zaskoczony. Można uznać tę książkę za skrótową broszurę biura podróży reklamującą wycieczkę do krainy komputerów. Nie jest możliwe, aby zawierała wszystko w najdrobniejszych szczegółach, a gdy już się tam wybierzesz, odkryjesz wiele subtelnych różnic między broszurą a rzeczywistością.PRZYPISY
1 Nauka, technologia, inżyniera, matematyka (Science, Technology, Engineering, Mathematics, STEM) – przyp. tłum.
2 Dokładnie tytuł Rycerza Orderu Imperium Brytyjskiego (przyp. red.).
3 „Duck, duck, goose” jest w języku angielskim nazwą znanej zabawy dziecięcej, która może budzić w odbiorcy podobne skojarzenia co w języku polskim np. słowa „chodzi lisek koło drogi” (przyp. tłum).
4 Autor posługuje się tu najwyraźniej bardzo nieformalnymi pojęciami „prostoty” i „złożoności”, według których dany operator jest prosty, jeśli da się go wyrazić za pomocą jednego spójnika z języka naturalnego, jest zaś złożony, jeśli da się go wyrazić tylko za pomocą dwóch lub więcej spójników z języka naturalnego. Ten warunek akurat nie zachodzi dla języka polskiego, w którym alternatywa rozłączna ma intuicyjny odpowiednik w spójniku „albo”, odróżniany od spójnika „lub” (przyp. tłum).
5 TLA to Three Letter Acronym, czyli trzyliterowy skrót (przyp. tłum).