Historia programowania zaczęła się znacznie wcześniej, niż powstały współczesne komputery osobiste. Pierwsze pomysły na automatyzację obliczeń, sterowanie maszynami oraz zapisywanie instrukcji w uporządkowanej formie pojawiły się już w XIX wieku. Z czasem przekształciły się w to, co dziś nazywamy oprogramowaniem. Jeśli interesują cię pierwsze programy komputerowe, warto poznać nie tylko ich techniczne aspekty, ale też kontekst naukowy, wojskowy i gospodarczy, który ukształtował ich rozwój. To opowieść o wizjonerach, ogromnych maszynach zajmujących całe sale, ręcznie przełączanych przewodach i stosach kart perforowanych. Zrozumienie, jak powstawały pierwsze algorytmy dla komputerów, pozwala lepiej docenić współczesne języki programowania oraz narzędzia, z których korzystamy na co dzień w pracy i życiu codziennym.

Początki idei programowania: od maszyn tkackich do logiki matematycznej

Historia programowania nie zaczyna się od elektroniki, lecz od pomysłu, że maszyną można sterować za pomocą symbolicznie zapisanych instrukcji. Jednym z pierwszych przykładów była maszyna tkacka Jacquarda z początku XIX wieku. Wzór tkaniny określały w niej dziurki w kartach perforowanych. Każdy rząd kart wyznaczał ruch haczyków z nicią – można to uznać za prymitywny, ale jednak „program”: sekwencję rozkazów dla maszyny. To rozwiązanie zainspirowało wielu konstruktorów, którzy zaczęli myśleć o mechanizmach ogólnego przeznaczenia.

W tym samym stuleciu rozwijała się matematyka, szczególnie logika symboliczna. Prace George’a Boole’a nad algebrą logiki stworzyły podstawy, na których później powstała teoria obliczeń. Logiczne działania na wartościach prawda–fałsz można było zrealizować fizycznie, a każde z nich opisać jako prostą operację na bitach. Choć jeszcze nikt nie budował komputerów elektronicznych, istniała już koncepcja, że obliczenia można ująć w system formalnych reguł. Ten splot mechaniki, algebraicznej logiki i inżynierii był kluczowy dla narodzin pierwszych programów komputerowych.

Ada Lovelace i maszyna analityczna Babbage’a

Jedną z najbardziej znanych prekursorek była Augusta Ada King, hrabina Lovelace. Współpracowała z Charlesem Babbage’em, który zaprojektował tzw. maszynę analityczną – mechaniczny komputer ogólnego przeznaczenia. Choć urządzenie nigdy nie zostało w pełni zbudowane, jego projekt przewidywał jednostkę obliczeniową, pamięć oraz mechanizm sterowania instrukcjami z kart perforowanych. W notatkach Ady Lovelace do artykułu opisującego maszynę znajduje się rozwinięty opis sposobu wykonywania obliczeń, który można uznać za jeden z pierwszych programów.

Najbardziej znany jest jej algorytm do obliczania wartości liczb Bernoulliego. Ada nie tylko opisała kroki obliczeń, ale zastanawiała się też, jak maszyna mogłaby przetwarzać inne typy symboli, na przykład nuty muzyczne. W jej ujęciu urządzenie Babbage’a nie służyło wyłącznie do liczenia, lecz do ogólnego operowania symbolami. To fundamentalne przesunięcie perspektywy – od prostego kalkulatora do uniwersalnej maszyny – czyni z niej często nazywaną pierwszą programistką w historii.

Od maszyn liczących do komputerów: ENIAC, Mark I i spółka

Przełom XX wieku przyniósł rozwój elektromechanicznych maszyn liczących. Konstrukcje takie jak maszyny relacyjne czy kalkulatory biurowe były jeszcze dalekie od współczesnych komputerów, ale umożliwiały coraz bardziej złożone obliczenia. Jednak dopiero okres II wojny światowej stał się impulsem do gwałtownego rozwoju urządzeń automatyzujących przetwarzanie danych. Potrzeby militarne – balistyka, kryptologia, symulacje – wymagały szybszych i bardziej niezawodnych maszyn niż ludzkie zespoły rachmistrzów.

Jedną z najsłynniejszych maszyn tego okresu był ENIAC, powstały w Stanach Zjednoczonych. Uważany za jeden z pierwszych w pełni elektronicznych komputerów ogólnego przeznaczenia, wykorzystywał tysiące lamp elektronowych i zajmował całe pomieszczenia. Programowanie ENIACA polegało pierwotnie na ręcznym przełączaniu kabli i ustawianiu przełączników. Zespół programistek, m.in. Jean Jennings Bartik i inne tzw. ENIAC girls, przygotowywał konfiguracje odpowiadające kolejnym krokom obliczeń. Każda zmiana zadań oznaczała fizyczne przeprogramowanie maszyny, co było żmudne i podatne na błędy.

Równolegle rozwijano inne konstrukcje, jak Harvard Mark I – komputer elektromechaniczny, który odczytywał instrukcje z taśm perforowanych. Tutaj pojawia się słynna Grace Hopper, która uczestniczyła w jego obsłudze i rozwijała wczesne narzędzia programistyczne. Mimo odmiennych technologii wszystkie te maszyny łączyło jedno: program był bezpośrednio związany z fizycznym okablowaniem lub nośnikiem perforowanym, a jego zmiana wymagała wielu godzin pracy specjalistów.

Koncept maszyny Turinga i program jako abstrakcyjny algorytm

Podczas gdy inżynierowie pracowali nad konkretnymi rozwiązaniami technicznymi, matematycy starali się ująć pojęcie obliczeń w ogólniejszych ramach. Alan Turing zaproponował model abstrakcyjnej maszyny, która porusza się po taśmie z symbolami i wykonuje proste operacje w zależności od aktualnego stanu oraz odczytanego znaku. Choć wygląda to bardzo uproszczone, taki model okazał się wystarczający, by opisać dowolny algorytm.

Istota koncepcji Turinga polega na rozdzieleniu części sterującej (programu) od danych. Program to skończony zestaw reguł, które mówią, co maszyna ma zrobić w danej sytuacji. Dane są jedynie sekwencją symboli na taśmie. Ten pomysł stał się teoretycznym fundamentem współczesnych komputerów. Zrozumienie, że algorytm jest niezależny od fizycznej realizacji, pozwoliło na rozwój rozmaitych języków programowania, w których ten sam proces można zapisać na wiele sposobów, zachowując jego logiczną strukturę.

Architektura von Neumanna: program w pamięci

Kluczowym krokiem w stronę tego, co dziś uznajemy za normalne działanie komputera, było sformułowanie architektury przechowywanego programu. John von Neumann opisał koncepcję maszyn, w których zarówno dane, jak i kod programu są umieszczone w tej samej pamięci, a procesor pobiera z niej kolejne instrukcje. To zerwało z wcześniejszą koniecznością przełączania kabli przy każdej zmianie zadania i otworzyło drogę do bardziej elastycznego programowania.

W praktyce oznaczało to, że program mógł być traktowany jak dane: zapisany, skopiowany, zmieniony przez inne programy. Z czasem stało się to podstawą całych systemów operacyjnych, kompilatorów i edytorów. W pierwszych implementacjach tej architektury, takich jak komputer EDVAC, programy były często zapisywane w postaci ciągu rozkazów w kodzie maszynowym. Programista musiał znać szczegółowo zestaw instrukcji danego procesora, jego rejestry oraz sposób adresowania pamięci, żeby ręcznie tworzyć sekwencje poleceń binarnych lub ich skróconych form symbolicznych.

Pierwsze języki niskiego poziomu: kod maszynowy i asembler

Najwcześniejsze programy komputerowe były pisane w postaci bezpośrednich ciągów bitów. Każda instrukcja maszyny miała swój numer, a argumenty określały adresy w pamięci lub stałe liczbowe. Taki sposób pracy był niezwykle podatny na pomyłki. Już niewielka zmiana w jednym bicie mogła sprawić, że program zachowywał się nieprzewidywalnie. Aby ułatwić pracę, wprowadzono asembler – język niskiego poziomu, w którym zamiast liczb używano krótkich mnemoników, np. ADD, MOV, JMP.

Asembler nie uniezależniał programisty od konkretnej architektury, ale sprawiał, że czytanie i pisanie kodu było znacznie prostsze. Wprowadzono etykiety nazwane dla adresów, dyrektywy umożliwiające definiowanie danych oraz komentarze. Program napisany w asemblerze był następnie tłumaczony przez specjalny program – assembler – na właściwy kod maszynowy. To jeden z pierwszych przykładów oprogramowania, które obsługuje inne oprogramowanie, co w kolejnych dekadach doprowadziło do powstania całych narzędziowych ekosystemów.

Grace Hopper i idea języka wysokiego poziomu

Choć asembler był dużym ułatwieniem w porównaniu z surowym kodem binarnym, wciąż wymagał myślenia w kategoriach rejestrów, skoków i konkretnych instrukcji procesora. Grace Hopper, pracując nad systemami dla amerykańskiej marynarki wojennej, uznała, że programiści powinni móc używać bardziej zrozumiałych konstrukcji. Zamiast myśleć o przesuwaniu danych między rejestrami, powinni opisywać operacje zbliżone do naturalnego języka lub notacji matematycznej.

Hopper była jedną z inicjatorek tworzenia kompilatorów – programów tłumaczących kod napisany w języku bardziej zrozumiałym dla człowieka na język maszynowy. W jej wizji komputer miał obsługiwać użytkownika, a nie odwrotnie. To podejście zaowocowało powstaniem pierwszych języków wysokiego poziomu, które w znacznej mierze odseparowały programistę od szczegółów sprzętowych. Choć początkowo sceptycy twierdzili, że takie abstrakcje będą nieefektywne, szybko okazało się, że korzyści z łatwiejszego tworzenia oprogramowania przewyższają straty wydajności.

FORTRAN, COBOL i narodziny programowania biznesowego oraz naukowego

W latach 50. powstały języki, które na długie dekady zdominowały świat programowania. FORTRAN, stworzony przez zespół Johna Backusa w IBM, został zaprojektowany z myślą o zastosowaniach naukowych i inżynieryjnych. Umożliwiał zapisywanie obliczeń w formie zbliżonej do standardowej notacji matematycznej, obsługiwał pętle, instrukcje warunkowe i operacje na tablicach. Dla fizyków czy inżynierów mechanicznych był ogromnym krokiem naprzód w stosunku do ręcznego kodowania w asemblerze.

COBOL, w którego tworzeniu uczestniczyła Grace Hopper, odpowiadał na inne potrzeby – przetwarzanie danych biznesowych, księgowość, raportowanie. Jego składnia była zbliżona do języka naturalnego i kładła nacisk na czytelność. Struktury danych, takie jak rekordy, doskonale nadawały się do odzwierciedlania dokumentów biurowych. W ten sposób wyraźnie zarysował się podział ról: FORTRAN stał się fundamentem programowania naukowego, COBOL – komercyjnego. Oba języki, razem z powstającymi w tym samym czasie systemami operacyjnymi, ukształtowały krajobraz pierwszych dużych instalacji komputerowych w firmach i instytutach badawczych.

Algol, strukturalizacja i początki teorii języków programowania

Kolejnym ważnym etapem był rozwój języka Algol, który wprowadził pojęcia bardzo wpływowe z punktu widzenia współczesnego programowania. W Algolu jasno definiowano zakresy zmiennych, blokową strukturę programu oraz formalną notację składni (tzw. BNF). Stał się on wzorcem dla wielu późniejszych języków, w tym Pascalu, C, a pośrednio także współczesnych rozwiązań.

Wraz z Algolem rozwijała się refleksja teoretyczna nad językami programowania. Zaczęto badać ich własności, projektować systemy typów oraz formułować reguły optymalizacji. Program przestał być tylko zestawem instrukcji dla konkretnych maszyn, a stał się obiektem badań samym w sobie. Na tym gruncie narodziły się także koncepcje programowania strukturalnego, postulujące ograniczenie użycia skoków bezwarunkowych i stosowanie przejrzystych struktur, takich jak pętle i instrukcje warunkowe. To miało poprawić czytelność i niezawodność kodu – cechy bardzo ważne w miarę wzrostu złożoności oprogramowania.

Nośniki programów: od kart perforowanych do taśm magnetycznych

Nie można opowiadać o pierwszych programach komputerowych, pomijając fizyczne nośniki, na których je zapisywano. Przez długi czas dominowały karty perforowane. Każda karta zawierała jeden rekord danych lub fragment instrukcji. Program składał się więc ze stosu kart, które należało uporządkować i przechowywać bardzo ostrożnie. Zgubienie lub pomieszanie kart mogło sprawić, że uruchomienie zadania stało się niemożliwe. Programiści dosłownie nosili swoje aplikacje w pudełkach.

Wraz z rozwojem technologii pojawiły się taśmy perforowane, a później taśmy magnetyczne i dyski. Pozwoliło to na bardziej elastyczne zarządzanie kodem oraz danymi. Można było przechowywać większe programy, tworzyć kopie zapasowe i przenosić je między maszynami. Wczesne systemy operacyjne oferowały proste narzędzia do ładowania programów z nośników i uruchamiania ich na sprzęcie głównym. Ten fizyczny aspekt historii pokazuje, jak bardzo różniło się wówczas doświadczenie pracy programisty od dzisiejszej, niemal w pełni wirtualnej rzeczywistości.

Programowanie systemowe i narodziny systemów operacyjnych

W miarę jak komputery stawały się coraz mocniejsze, pojawiła się potrzeba zarządzania wieloma zadaniami i użytkownikami. Tak powstały pierwsze systemy operacyjne – programy nadrzędne, które kontrolowały przydział pamięci, obsługę urządzeń wejścia-wyjścia oraz harmonogramowanie prac. Wczesne systemy operacyjne były pisane głównie w asemblerze, ponieważ wymagały bardzo bliskiego kontaktu ze sprzętem.

Rozwój tych systemów doprowadził do wprowadzenia trybu wsadowego, a następnie pracy wielodostępnej, w której kilku użytkowników mogło korzystać z jednego komputera. Tworzenie kompilatorów, asemblerów, bibliotek standardowych i narzędzi diagnostycznych stało się odrębną dziedziną – programowanie systemowe. To właśnie wtedy zaczęły się krystalizować pojęcia takie jak proces, plik, urządzenie wirtualne, które dziś uznajemy za oczywiste. Pierwsze programy komputerowe wyewoluowały w cały ekosystem oprogramowania współdzielonego przez różnych użytkowników.

Od mainframe’ów do komputerów osobistych: zmiana skali i roli programisty

Początkowe komputery były ogromne, drogie i dostępne tylko dla dużych organizacji. Programiści pracowali często w wydzielonych działach, a dostęp do maszyny był ściśle kontrolowany. Sytuacja zaczęła się zmieniać wraz z pojawieniem się minikomputerów, a później komputerów osobistych. W latach 70. i 80. programowanie zaczęło trafiać do laboratoriów, małych firm, a w końcu do domów pasjonatów.

Języki takie jak BASIC umożliwiały pisanie prostych programów bez głębokiej wiedzy o sprzęcie. Pojawiły się pierwsze środowiska zintegrowane, edytory ekranowe i debuggery. Programowanie przestało być domeną wyłącznie wyspecjalizowanych zespołów w instytucjach rządowych czy korporacjach. Zaczęło funkcjonować jako hobby, narzędzie edukacyjne i sposób na tworzenie gier oraz prostych aplikacji użytkowych. Zmiana skali sprzętu pociągnęła za sobą zmianę roli programisty: z operatora wielkiej maszyny w bardziej niezależnego twórcę.

Znaczenie pierwszych programów dla współczesności

Dzisiejsze języki programowania, środowiska deweloperskie i narzędzia automatyzujące testy czy wdrożenia wydają się odległe od kart perforowanych, mechanicznych przekładni i lamp elektronowych. Jednak wiele podstawowych idei pozostaje niezmiennych. Wciąż korzystamy z koncepcji algorytmu, wciąż odwołujemy się do abstrakcyjnego modelu maszyny obliczeniowej i wciąż potrzebujemy jasnej struktury kodu, by utrzymać złożone projekty. Nawet jeśli piszemy w językach bardzo wysokiego poziomu, takich jak te używane w aplikacjach webowych, pod spodem działają procesory z zestawami instrukcji, pamięcią i systemami operacyjnymi wywodzącymi się bezpośrednio z rozwiązań opracowanych kilkadziesiąt lat temu.

Zrozumienie historii pierwszych programów komputerowych pozwala spojrzeć krytycznie na współczesne trendy. Widzimy, że wiele z dzisiejszych „nowości” ma źródła w dawnych koncepcjach, tylko przystosowanych do innych realiów sprzętowych i biznesowych. Od maszyn Babbage’a i notatek Ady Lovelace, przez lampowe kolosy ery wojennej, aż po narodziny języków wysokiego poziomu – każda epoka dodawała nowe warstwy abstrakcji, które ułatwiały wykorzystanie komputerów. Dzisiejszy rozwój sztucznej inteligencji, chmur obliczeniowych i systemów rozproszonych jest kolejnym etapem tej ewolucji, zakorzenionym głęboko w historii pierwszych programów.