Programowanie komputerowe - Computer programming

Programowanie komputerowe to proces projektowania i budowania wykonywalnego programu komputerowego w celu osiągnięcia określonego wyniku obliczeniowego lub wykonania określonego zadania. Programowanie obejmuje takie zadania jak: analiza, generowanie algorytmów , profilowanie dokładności algorytmów i zużycia zasobów oraz implementacja algorytmów w wybranym języku programowania (potocznie nazywane kodowaniem ). Kod źródłowy programu jest napisane w jednym lub kilku językach, które są zrozumiałe dla programistów , zamiast kodu maszynowego , który jest bezpośrednio wykonywane przez jednostki centralnej . Celem programowania jest znalezienie sekwencji instrukcji, które zautomatyzują wykonanie zadania (które może być tak złożone jak system operacyjny ) na komputerze , często w celu rozwiązania danego problemu. Sprawne programowanie często wymaga zatem wiedzy z kilku różnych przedmiotów, w tym znajomości domeny aplikacji , specjalistycznych algorytmów i logiki formalnej .

Zadania towarzyszące i związane z programowaniem to m.in.: testowanie , debugowanie , konserwacja kodu źródłowego , wdrażanie systemów budowania oraz zarządzanie wytworzonymi artefaktami , takimi jak kod maszynowy programów komputerowych. Mogą one być traktowane jako część procesu programowania, ale często termin rozwoju oprogramowania służy do tego większego procesu z terminem programowania , wdrażania , lub kodowanie zarezerwowane dla rzeczywistego pisania kodu. Inżynieria oprogramowania łączy techniki inżynierskie z praktykami tworzenia oprogramowania. Inżynieria odwrotna to powiązany proces używany przez projektantów, analityków i programistów w celu zrozumienia i ponownego tworzenia/ponownego wdrażania.

Historia

Ada Lovelace , której notatki dodane na końcu artykułu Luigi Menabrea zawierały pierwszy algorytm zaprojektowany do przetwarzania przez silnik analityczny . Jest często uznawana za pierwszą w historii programistkę komputerową.

Programowalne urządzenia istnieją od wieków. Już w IX wieku programowalny sekwencer muzyczny został wynaleziony przez perskich braci Banu Musa , którzy opisali automatyczny mechaniczny flecista w Księdze Pomysłowych Urządzeń . W 1206 roku arabski inżynier Al-Dżazari wynalazł programowalny automat perkusyjny, w którym za pomocą kołków i krzywek można było stworzyć muzyczny automat mechaniczny do grania różnych rytmów i wzorów bębnów . W 1801 roku krosno żakardowe mogło wytwarzać zupełnie inne sploty, zmieniając „program” – serię kart kartonowych z dziurkowanymi w nich otworami.

Algorytmy łamania kodów również istnieją od wieków. W IX wieku arabski matematyk Al-Kindi opisał algorytm kryptograficzny do odszyfrowywania zaszyfrowanego kodu w A Manuscript on Deciphering Cryptographic Messages . Podał pierwszy opis kryptoanalizy za pomocą analizy częstotliwości , najwcześniejszego algorytmu łamania kodów.

Pierwszy program komputerowy jest ogólnie datowany na 1843, kiedy matematyk Ada Lovelace opublikował algorytm do obliczania sekwencji liczb Bernoulliego , ma być przeprowadzona przez Charles Babbage „s Analytical silnika .

Dane i instrukcje były kiedyś przechowywane na zewnętrznych kartach perforowanych , które utrzymywano w porządku i układano w talii programów.

W latach 80. XIX wieku Herman Hollerith wymyślił koncepcję przechowywania danych w formie do odczytu maszynowego. Później panel sterowania (płyta z wtyczkami) dodany do jego Tabulatora Typu I z 1906 r. pozwolił na zaprogramowanie go do różnych zadań, a pod koniec lat 40. urządzenia do nagrywania jednostek, takie jak IBM 602 i IBM 604 , były programowane przez panele sterowania w podobny sposób. sposób, podobnie jak pierwsze komputery elektroniczne . Jednak wraz z wprowadzoną w 1949 r. koncepcją komputera z przechowywanymi programami , zarówno programy, jak i dane były przechowywane i manipulowane w ten sam sposób w pamięci komputera .

Język maszyny

Kod maszynowy był językiem wczesnych programów, pisanym w zestawie instrukcji danej maszyny, często w notacji binarnej . Wkrótce opracowano języki asemblera, które pozwalały programiście określić instrukcje w formacie tekstowym (np. ADD X, TOTAL), ze skrótami dla każdego kodu operacji i znaczącymi nazwami do określania adresów. Jednakże, ponieważ język asemblerowy jest niewiele więcej niż inną notacją dla języka maszynowego, dowolne dwie maszyny z różnymi zestawami instrukcji również mają różne języki asemblerowe.

Przewodowy panel sterowania dla IBM 402 Accounting Machine .

Języki kompilatora

Języki wysokiego poziomu sprawiły, że proces tworzenia programu był prostszy i bardziej zrozumiały, a także mniej związany z podstawowym sprzętem. Pierwsze narzędzie związane z kompilatorem, system A-0 , zostało opracowane w 1952 roku przez Grace Hopper , która ukuła również termin „kompilator”. FORTRAN , pierwszy powszechnie używany język wysokiego poziomu, który miał funkcjonalną implementację, pojawił się w 1957 r., a wkrótce powstało wiele innych języków — w szczególności COBOL przeznaczony do komercyjnego przetwarzania danych i Lisp do badań komputerowych.

Te skompilowane języki pozwalają programiście na pisanie programów w terminach, które są bogatsze składniowo i bardziej zdolne do abstrakcji kodu, co ułatwia celowanie w różne zestawy instrukcji maszynowych za pomocą deklaracji kompilacji i heurystyki. Kompilatory wykorzystały moc komputerów, aby ułatwić programowanie, umożliwiając programistom określanie obliczeń poprzez wprowadzanie formuły przy użyciu notacji infiksowej .

Wpis kodu źródłowego

Programy były w większości nadal wprowadzane za pomocą kart dziurkowanych lub taśmy papierowej . Pod koniec lat sześćdziesiątych urządzenia do przechowywania danych i terminale komputerowe stały się na tyle tanie, że można było tworzyć programy, wpisując je bezpośrednio na komputerach. Opracowano również edytory tekstu, które umożliwiały wprowadzanie zmian i poprawek znacznie łatwiej niż w przypadku kart dziurkowanych.

Nowoczesne programowanie

Wymagania jakościowe

Niezależnie od podejścia do programowania, końcowy program musi spełniać pewne podstawowe właściwości. Do najważniejszych należą następujące właściwości:

  • Niezawodność : jak często wyniki programu są poprawne. Zależy to od konceptualnej poprawności algorytmów i minimalizacji błędów programistycznych, takich jak błędy w zarządzaniu zasobami (np. przepełnienia buforów i wyścigi ) oraz błędy logiczne (takie jak dzielenie przez zero lub błędy typu off-by-one ).
  • Odporność : jak dobrze program przewiduje problemy spowodowane błędami (nie bugami). Obejmuje to sytuacje, takie jak nieprawidłowe, nieodpowiednie lub uszkodzone dane, niedostępność potrzebnych zasobów, takich jak pamięć, usługi systemu operacyjnego i połączenia sieciowe, błędy użytkownika i nieoczekiwane przerwy w dostawie prądu.
  • Użyteczność : ergonomia programu: łatwość, z jaką dana osoba może korzystać z programu zgodnie z jego przeznaczeniem lub w niektórych przypadkach nawet w nieprzewidzianych celach. Takie problemy mogą uczynić lub zepsuć jego sukces, nawet niezależnie od innych problemów. Obejmuje to szeroką gamę elementów tekstowych, graficznych, a czasem sprzętowych, które poprawiają przejrzystość, intuicyjność, spójność i kompletność interfejsu użytkownika programu.
  • Przenośność : zakres sprzętu komputerowego i platform systemu operacyjnego, na których można kompilować / interpretować i uruchamiać kod źródłowy programu . Zależy to od różnic w funkcjach programistycznych udostępnianych przez różne platformy, w tym zasobów sprzętowych i systemu operacyjnego, oczekiwanego zachowania sprzętu i systemu operacyjnego oraz dostępności kompilatorów specyficznych dla platformy (a czasami bibliotek) dla języka kodu źródłowego.
  • Łatwość utrzymania : łatwość, z jaką program może być modyfikowany przez obecnych lub przyszłych programistów w celu wprowadzenia ulepszeń lub dostosowania, naprawiania błędów i luk w zabezpieczeniach lub dostosowywania go do nowych środowisk. Dobre praktyki podczas początkowego rozwoju mają w tym względzie znaczenie. Ta cecha może nie być bezpośrednio widoczna dla użytkownika końcowego, ale może znacząco wpłynąć na los programu w dłuższej perspektywie.
  • Wydajność / wydajność : Miara zasobów systemowych, które program zużywa (czas procesora, miejsce w pamięci, wolne urządzenia, takie jak dyski, przepustowość sieci i do pewnego stopnia nawet interakcja użytkownika): im mniej, tym lepiej. Obejmuje to również staranne zarządzanie zasobami, na przykład czyszczenie plików tymczasowych i eliminowanie wycieków pamięci . Jest to często omawiane w cieniu wybranego języka programowania. Chociaż język z pewnością wpływa na wydajność, nawet wolniejsze języki, takie jak Python , mogą natychmiast wykonywać programy z perspektywy człowieka. Szybkość, zużycie zasobów i wydajność są ważne dla programów, które stanowią wąskie gardło systemu, ale efektywne wykorzystanie czasu programisty jest również ważne i wiąże się z kosztami: więcej sprzętu może być tańsze.

Czytelność kodu źródłowego

W programowaniu komputerowym czytelność odnosi się do łatwości, z jaką czytelnik może zrozumieć cel, przepływ sterowania i działanie kodu źródłowego. Wpływa na powyższe aspekty jakości, w tym przenośność, użyteczność i, co najważniejsze, łatwość utrzymania.

Czytelność jest ważna, ponieważ programiści spędzają większość czasu na czytaniu, próbując zrozumieć i modyfikować istniejący kod źródłowy, zamiast pisać nowy kod źródłowy. Nieczytelny kod często prowadzi do błędów, nieefektywności i powielania kodu . Badanie wykazało, że kilka prostych przekształceń czytelności skróciło kod i drastycznie skróciło czas potrzebny na jego zrozumienie.

Stosowanie spójnego stylu programowania często pomaga w czytelności. Jednak czytelność to coś więcej niż tylko styl programowania. Na czytelność wpływa wiele czynników, które mają niewiele lub nic wspólnego ze zdolnością komputera do wydajnej kompilacji i wykonywania kodu. Niektóre z tych czynników obejmują:

Do prezentacji aspekty (takie jak ten myślnikiem, przerwy linii, koloru podświetlania, i tak dalej) są często obsługiwane przez edytor kodu źródłowego , ale aspekty treści odzwierciedlają talent i umiejętności programatora.

Opracowano również różne wizualne języki programowania w celu rozwiązania problemów z czytelnością poprzez przyjęcie nietradycyjnych podejść do struktury kodu i wyświetlania. Zintegrowane środowiska programistyczne (IDE) mają na celu zintegrowanie całej takiej pomocy. Techniki takie jak refaktoryzacja kodu mogą zwiększyć czytelność.

Złożoność algorytmiczna

Zarówno dziedzina akademicka, jak i inżynierska praktyka programowania komputerów są w dużej mierze związane z odkrywaniem i wdrażaniem najbardziej wydajnych algorytmów dla danej klasy problemów. W tym celu algorytmy są klasyfikowane w zlecenia za pomocą tzw. notacji Big O , która wyraża wykorzystanie zasobów, takie jak czas wykonania lub zużycie pamięci, w kategoriach wielkości danych wejściowych. Zaawansowani programiści są zaznajomieni z różnymi dobrze znanymi algorytmami i ich złożonością i wykorzystują tę wiedzę, aby wybrać algorytmy, które najlepiej pasują do okoliczności.

Algorytmy szachowe jako przykład

„Programowanie komputera do gry w szachy” to artykuł z 1950 roku, w którym oceniano algorytm „minimaksowy” , który jest częścią historii złożoności algorytmicznej; kurs IBM Deep Blue (komputer szachowy) jest częścią programu nauczania informatyki na Uniwersytecie Stanforda .

Metodologie

Pierwszym krokiem w większości formalnych procesów tworzenia oprogramowania jest analiza wymagań , po której następuje testowanie w celu określenia modelowania wartości, implementacji i eliminacji awarii (debugowanie). Istnieje wiele różnych podejść do każdego z tych zadań. Jednym z popularnych podejść do analizy wymagań jest analiza przypadków użycia . Wielu programistów korzysta z form rozwoju oprogramowania Agile, w których różne etapy formalnego tworzenia oprogramowania są bardziej zintegrowane w krótkie cykle, które trwają kilka tygodni, a nie lat. Istnieje wiele podejść do procesu tworzenia oprogramowania.

Popularne techniki modelowania obejmują analizę i projektowanie zorientowane obiektowo ( OOAD ) oraz architekturę opartą na modelu ( MDA ). Unified Modeling Language ( UML ) to notacja używana zarówno dla OOAD, jak i MDA.

Podobną techniką używaną do projektowania bazy danych jest modelowanie relacji encji ( Modelowanie ER ).

Techniki implementacji obejmują języki imperatywne ( obiektowe lub proceduralne ), języki funkcjonalne i języki logiczne .

Pomiar użycia języka

Bardzo trudno jest określić, jakie są najpopularniejsze współczesne języki programowania. Metody pomiaru popularności języka programowania obejmują: zliczanie ogłoszeń o pracę, które wymieniają język, liczbę sprzedanych książek i kursów uczących języka (to przecenia znaczenie nowszych języków) oraz oszacowanie liczby istniejących linii kodu napisanego w języku (to zaniża liczbę użytkowników języków biznesowych, takich jak COBOL).

Niektóre języki są bardzo popularne w przypadku określonych rodzajów aplikacji, podczas gdy niektóre języki są regularnie używane do pisania wielu różnych rodzajów aplikacji. Na przykład COBOL jest nadal silny w korporacyjnych centrach danych, często na dużych komputerach typu mainframe , Fortran w aplikacjach inżynierskich, językach skryptowych w tworzeniu stron internetowych i C w oprogramowaniu wbudowanym . Wiele aplikacji używa kombinacji kilku języków w ich konstrukcji i użyciu. Nowe języki są zazwyczaj projektowane wokół składni poprzedniego języka z dodaną nową funkcjonalnością (na przykład C++ dodaje orientację obiektową do C, a Java dodaje zarządzanie pamięcią i kod bajtowy do C++, ale w rezultacie traci wydajność i zdolność do -poziom manipulacji).

Debugowanie

Pierwszym znanym rzeczywistym błędem powodującym problem w komputerze była ćma uwięziona w komputerze mainframe Harvardu, zarejestrowana we wpisie dziennika z dnia 9 września 1947 roku. .

Debugowanie jest bardzo ważnym zadaniem w procesie tworzenia oprogramowania, ponieważ defekty w programie mogą mieć poważne konsekwencje dla jego użytkowników. Niektóre języki są bardziej podatne na pewne rodzaje błędów, ponieważ ich specyfikacja nie wymaga od kompilatorów wykonywania tak wielu kontroli, jak inne języki. Użycie narzędzia do statycznej analizy kodu może pomóc w wykryciu niektórych możliwych problemów. Zwykle pierwszym krokiem debugowania jest próba odtworzenia problemu. Może to być nietrywialne zadanie, na przykład w przypadku procesów równoległych lub niektórych nietypowych błędów oprogramowania. Ponadto specyficzne środowisko użytkownika i historia użytkowania mogą utrudnić odtworzenie problemu.

Po odtworzeniu błędu może być konieczne uproszczenie danych wejściowych programu, aby ułatwić debugowanie. Na przykład, gdy błąd w kompilatorze może spowodować jego awarię podczas parsowania dużego pliku źródłowego, uproszczenie przypadku testowego, które skutkuje tylko kilkoma wierszami z oryginalnego pliku źródłowego, może wystarczyć do odtworzenia tej samej awarii. Potrzebne są próby i błędy/dziel i rządź: programista spróbuje usunąć niektóre części oryginalnego przypadku testowego i sprawdzi, czy problem nadal istnieje. Podczas debugowania problemu w GUI, programista może spróbować pominąć niektóre interakcje użytkownika z oryginalnego opisu problemu i sprawdzić, czy pozostałe działania są wystarczające, aby pojawiły się błędy. Częścią tego procesu jest również tworzenie skryptów i wskazywanie przerw .

Debugowanie jest często wykonywane za pomocą IDE . Używane są również samodzielne debuggery, takie jak GDB , które często zapewniają mniej wizualne środowisko, zwykle używając wiersza poleceń . Niektóre edytory tekstu, takie jak Emacs, umożliwiają wywoływanie GDB za ich pośrednictwem, aby zapewnić środowisko wizualne.

Języki programowania

Różne języki programowania obsługują różne style programowania (tzw. paradygmaty programowania ). Wybór używanego języka zależy od wielu czynników, takich jak polityka firmy, przydatność do zadania, dostępność pakietów stron trzecich lub indywidualne preferencje. W idealnym przypadku zostanie wybrany język programowania najlepiej dopasowany do danego zadania. Kompromisy z tego ideału obejmują znalezienie wystarczającej liczby programistów, którzy znają język, aby zbudować zespół, dostępność kompilatorów dla tego języka oraz wydajność, z jaką działają programy napisane w danym języku. Języki tworzą przybliżone spektrum od „niskiego poziomu” do „wysokiego poziomu”; Języki „niskiego poziomu” są zazwyczaj bardziej zorientowane na maszynę i szybsze do wykonania, podczas gdy języki „wysokiego poziomu” są bardziej abstrakcyjne i łatwiejsze w użyciu, ale wykonują się wolniej. Zazwyczaj łatwiej jest kodować w językach „wysokich” niż w „niskopoziomowych”.

Allen Downey w swojej książce How To Think Like A Computer Scientist pisze:

Szczegóły wyglądają inaczej w różnych językach, ale kilka podstawowych instrukcji pojawia się w prawie każdym języku:
  • Wejście: Zbierz dane z klawiatury, pliku lub innego urządzenia.
  • Wyjście: Wyświetlaj dane na ekranie lub wysyłaj dane do pliku lub innego urządzenia.
  • Arytmetyka: Wykonuj podstawowe operacje arytmetyczne, takie jak dodawanie i mnożenie.
  • Wykonanie warunkowe: Sprawdź określone warunki i wykonaj odpowiednią sekwencję instrukcji.
  • Powtórzenie: Powtarzaj jakąś czynność, zwykle z pewną odmianą.

Wiele języków komputerowych zapewnia mechanizm wywoływania funkcji udostępnianych przez biblioteki współdzielone . Jeśli funkcje w bibliotece są zgodne z odpowiednimi konwencjami czasu wykonywania (np. metoda przekazywania argumentów ), to funkcje te mogą być napisane w dowolnym innym języku.

Programiści

Programiści komputerowi to ci, którzy piszą oprogramowanie komputerowe. Ich praca zazwyczaj obejmuje:

Chociaż programowanie jest przedstawiane w mediach jako przedmiot poniekąd matematyczny, niektóre badania pokazują, że dobrzy programiści mają duże umiejętności w posługiwaniu się naturalnymi językami ludzkimi, a nauka kodowania jest podobna do nauki języka obcego .

Zobacz też

Bibliografia

Źródła

Dalsza lektura

Zewnętrzne linki