Nauka programowania

Uwaga - jest to wersja robocza tekstu

Mawia się, że informatyka jest nauką o komputerach w takim samym stopniu, w jakim astronomia jest nauką o teleskopach. Z tym skądinąd mądrym twierdzeniem nie da się nie zgodzić. Nauka ta rozpoczęła swoje życie jako jeden z działów królowej nauk, matematyki, ale szybko rozwinęła się do tego stopnia, że nie ma chyba na świecie osoby, która byłaby w stanie przyzwoicie ogarnąć wszystkie możliwe działy, dziedziny i zakresy jej wykorzystania. Mimo silnego zaczepienia w teorii, ciężko być jest obecnie informatykiem, który nie ma do czynienia z komputerami, a co gorsza - nie zna się na programowaniu. Dlatego prędzej czy później staniesz przed problemem, jak tejże sztuki programowania się nauczyć. Ten poradnik powstał, by Ci w tym pomóc.

Programowanie i komputery

Programowanie to szeroko rozumiany proces tworzenia programów i aplikacji dla urządzeń elektronicznych, a w szczególności - komputerów.

Początki

Wybór języka programowania

Jedna z pierwszych decyzji początkującego programisty to wybór swojego pierwszego języka programowania. To na nim zdobędziesz swe pierwsze szlify, nauczysz się specyficznego sposobu myślenia oraz technik programistycznych. Gdy opanujesz już jeden język, nauka kolejnych będzie dużo prostsza i dużo szybsza. Poszczególne języki różnią się możliwościami, zakresem zastosowań oraz stopniem trudności, który niestety często jest wprost proporcjonalny do ich przydatności. Wiele osób zniechęca się do programowania i informatyki w ogóle, gdyż próbują zacząć swoją przygodę od jakiegoś kosmicznego hardkoru i okazuje się, że ilość problemów, którymi witani są "na dzień dobry" zwyczajnie ich przerasta.

Przy wybieraniu języka programowania spotkamy się zapewne ze stwierdzeniami typu "język strukturalny" czy "język funkcyjny". Określają one ogólny sposób tworzenia programów oraz środki, jakie w tym języku się stosuje. Fachowo takie sposoby nazywa się paradygmatami programowania, a dany język może oferować programiście nawet kilka dostępnych paradygmatów. Podstawowe paradygmaty, jakie warto znać, to:

  1. Programowanie imperatywne - jest zbliżone do fizycznego schematu pracy komputera. Program zapisuje się jako ciąg poleceń do wykonania, jednak w przeciwieństwie do assemblerów i kodu maszynowego, programista ma do dyspozycji kilka eleganckich narzędzi pozwalających np. na warunkowe wykonanie jakichś poleceń, albo powtarzanie ich w kółko do czasu zajścia określonego warunku. Programowanie imperatywne uchodzi za proste do nauczenia się i obecnie większość aplikacji komputerowych powstaje właśnie w językach imperatywnych. Językami imperatywnymi są np. Pascal, C, C++, PHP, Java czy Python.
  2. Programowanie funkcyjne - jest bardziej zbliżone do matematycznego zapisu, ma dobre podstawy teoretyczne i bazuje na matematycznym pojęciu funkcji. Programy napisane w języku funkcyjnym uchodzą za łatwiejsze do analizy i bardziej niezawodne, zaś jeśli chodzi o stopień trudności dla początkującego programisty, są dwie sprzeczne opinie. Większość ludzi uważa, że jest ono przeznaczone dla ludzi, którzy mają już pewne doświadczenie w programowaniu, ale niektórzy informatycy twierdzą, że to właśnie od niego jest lepiej zacząć naukę, gdyż uczy systematycznego i logicznego myślenia, a przejście z programowania funkcyjnego na imperatywne jest dużo prostsze, niż w drugą stronę. Językiem funkcyjnym jest np. Ocaml.

Języki możemy też podzielić według innego kryterium:

  1. Programowanie proceduralne - program dzieli się na procedury i funkcje (nie mylić z matematycznymi), które zawierają po prostu sekwencje instrukcji do wykonania realizujące jakąś czynność. Mając pewien zbiór takich procedur i funkcji, możemy z nich budować w sposób hierarchiczny coraz bardziej złożone procedury realizujące coraz trudniejsze zadania, aż w końcu powstanie nam program. Programowanie proceduralne jest dobre do mniejszych aplikacji, aczkolwiek istnieją też duże systemy zrealizowane w ten sposób (np. jądro systemu Linux). Co więcej, jest proste do opanowania.
  2. Programowanie obiektowe - program składa się z obiektów, które współdziałają ze sobą. Koncepcja jest zbliżona do naturalnego sposobu postrzegania świata przez człowieka, ale (zapewne ze względu na dużo większą liczbę oferowanych mechanizmów i zależności) jego opanowanie i zrozumienie jego poprawnego stosowania wielu programistom sprawia na początku kłopoty. Dlatego nauki programowania obiektowego nie polecałbym na początek.

Przejrzyjmy teraz kilka języków programowania:

  1. C++ - jest to jeden z najpowszechniej stosowanych języków programowania na świecie, używa go też wiele osób startujących w konkursach programistycznych. Popularność oraz duże możliwości zdają się przemawiać za tym, by to właśnie od niego zacząć przygodę z programowaniem, ale moim zdaniem jest to największy błąd, jaki można na początku zrobić. Język C++ jest ekstremalnie skomplikowany. Jest skomplikowany do tego stopnia, że do dziś, w prawie 25 lat od powstania nie udało się stworzyć kompilatora w pełni zgodnego ze standardem. Pełno w nim nieścisłości, niejednoznaczności i dziwnych rozwiązań, które często ciężko jest dobrze zrozumieć nawet dobrym programistom, a co dopiero początkującym. Pamiętaj! Na początku masz w ogóle nauczyć się programować; nie myśl, że w dwa dni po napisaniu Hello world zaczniesz tworzyć Quake'a, więc te wszystkie możliwości nie tylko nie są Ci potrzebne, ale będą wręcz przeszkadzać. Spotkałem już zbyt wiele osób, które C++ od programowania odrzucił, więc mam nadzieję, że nie rzucam teraz słów na wiatr. Ucz się programować, na C++ jeszcze przyjdzie pora (a może i nie - ja osobiście za nim nie przepadam :)).
  2. C - C++ jest silnie rozbudowanym C. Ilość mechanizmów tworzących język C jest dużo mniejsza, niż w C++ i wystarcza w sam raz, by dało się w nim coś sensownego napisać, a przy tym nie być przytłoczonym ogromem niezrozumiałych rzeczy. Dla początkujących pewnym wyzwaniem może być niskopoziomowość języka, który jest dość ściśle związany ze sprzętem. Podczas nauki na pewno nie unikniesz konieczności zrozumienia pewnych aspektów działania komputera, aby wiedzieć, dlaczego masz coś robić właśnie tak, a nie inaczej.
  3. Pascal - w ostatnim dziesięcioleciu język ten niemal kompletnie wyszedł z użycia w normalnych zastosowaniach, lecz wciąż jest szeroko spotykany w edukacji. Jego składnia jest dużo bardziej przyjazna dla początkujących programistów, niż C/C++, a i sama nauka nie wymaga aż tak dobrej znajomości działania sprzętu komputerowego, jak w przypadku C. Osobiście nie uważam, by zaczynanie od tego właśnie języka było hańbą/ujmą dla programisty. Sam wychowałem się właśnie na Pascalu i nie uważam, by był to czas zmarnowany. Myślę, że będzie to dobry język do nauki podstaw algorytmiki i poznawania innych języków.
  4. Python - w przeciwieństwie do dotychczasowych języków, Python nie jest kompilowany do kodu maszynowego komputera, lecz wykonywany przez specjalny program zwany maszyną wirtualną. Oczywiście nie pozostaje to bez wpływu na wydajność, ale Python znajduje we współczesnej informatyce całkiem sporo zastosowań (np. tworzenie stron internetowych). Jest on prosty do nauczenia, a z zalet dydaktycznych istotną cechą jest to, że wręcz wymusza on na programiście tworzenie eleganckiego kodu. Również mogę polecić na początek tym bardziej, że w przeciwieństwie do Pascala można w nim od razu zacząć robić coś przydatnego.
  5. Java - jest to obiektowy język programowania silnie wzorowany na C. Ma elegancką składnię i duże możliwości (ostatecznie jest to najpowszechniej stosowany język programowania świata), ale z powodu tego, że w całości opiera się na programowaniu obiektowym, nie zalecałbym go początkującym programistom.
  6. Ocaml - jest to odpowiednik Pascala, ale dla języków funkcyjnych, dlatego często jest wykorzystywany w celach edukacyjnych. Niemniej, stosuje się go również w praktyce. Jeśli chcesz swoją przygodę zacząć od programowania funkcyjnego, albo chciałbyś się tego paradygmatu nauczyć, będzie to dobry język do startu.

Podręcznik czy Internet?

Nauka algorytmiki

Nauka technik programowania

Aspekty programowania

Czytelność kodu

Wielu młodych programistów śmieje się często, gdy słyszy, że na uczelni wykładowca opowiada, że program nie ma działać, program ma być ładny (powiedzenie jednego z moich wykładowców z 1-go roku studiów) i myśli sobie "rany, co za dziwna uczelnia". Cóż, gdy byłem młodszy, też tak myślałem… dopóki nie stworzyłem swojego pierwszego naprawdę dużego programu. To fakt - dopóki nie zaczniemy programować na naprawdę dużą skalę, bagatelizujemy takie rzeczy, jak czytelność kodu czy jego zrozumiałość, a później płaczemy, gdy próbujemy po roku odczytać nasze wypociny, albo - co gorsza - musimy się ukrywać, bo nasz współpracownik biega z siekierą za to, że musiał nasz kod poprawiać.

Tworzenia eleganckiego kodu powinieneś uczyć się od samego początku, wraz z rozwojem umiejętności programistycznych. Robienie wcięć czy komentarzy to nie są żadne akademickie wymysły, tylko sprawdzone w praktyce wynalazki, które naprawdę ułatwiają życie. Szczególnie dobry jest tutaj język Python, który wręcz wymusza na programiście tworzenie poprawnych, czytelnych wcięć i komentowanie kodu, gdyż inaczej program się zwyczajnie nie uruchomi. Porównaj sobie następujące kawałki kodu. Pierwszy z nich napisał początkujący programista:

BufferedReader czytaj=new BufferedReader(new InputStreamReader(System.in));
int powtorzenia;
String znaki="0";
int tab[]=new int[100000];
try {
znaki=czytaj.readLine();
}catch(Exception wyjatek){}
powtorzenia=Integer.parseInt(znaki);
for (int a=0; a<powtorzenia; a++)
{
    int liczba;
    try {
    znaki=czytaj.readLine();
    }catch(Exception wyjatek){}
    tab[a]=Integer.parseInt(znaki);
}

Co Ci się wygodniej czyta? Taką zbitkę czy coś takiego:

// Glowne zmienne
int repetitions;
int foundNumbers[] = new int[100000];
BufferedReader input=new BufferedReader(new InputStreamReader(System.in));

// Liczniki, itd.
int a;

try
{
    // Wczytaj ilosc liczb do wczytania
    repetitions = Integer.parseInt(input.readLine());

    // Wczytaj okreslona ilosc liczb
    for(a = 0; a < repetitions; a++)
    {
        foundNumbers[a] = Integer.parseInt(czytaj.readLine());
    }
}
catch(Exception exception)
{
   handleException(exception);
}

Drugi kod robi praktycznie to samo, ale jest o niebo lepszy. Ludzki mózg źle radzi sobie z natłokiem informacji. Gdy spoglądamy na pierwszy kod, intuicyjnie traktujemy spory jego kawałek jako szum informacyjny i musimy się nieźle skupić, by znaleźć interesujący nas fragment. W drugim przypadku jest zupełnie inaczej. Ponieważ zadaliśmy sobie trochę trudu, aby wszystko było logicznie poukładane, porobiliśmy puste linie oddzielające kolejne logiczne bloki niczym akapity w tekście, kod jest bardziej przejrzysty i po prostu wygodniejszy w czytaniu, a komentarze pomogą nam zrozumieć, co i jak robi nawet gdy będziemy musieli wrócić do niego po rocznej przerwie.

Wypracowanie jednolitego stylu kodowania zajmie trochę czasu - warto tutaj po prostu oglądać listingi różnych aplikacji open-source. Większe aplikacje mają często przyjęty jednolity standard kodowania, którego trzymają się wszyscy programiści pracujący nad projektem, a poszczególne standardy są do siebie dość podobne. Poniżej wymieniona jest lista rzeczy, na które warto zwrócić uwagę.

  1. Nazewnictwo zmiennych, funkcji, itd. - czy używamy nazw polskich, angielskich czy jeszcze innych? Zasadniczo wszystko powinno być utrzymane w jednym języku. Jeśli aplikację chcesz wydać, a kod upublicznić, najlepszym wyborem będzie konsekwentne stosowanie języka angielskiego. Moim zdaniem, mimo iż na co dzień walczę z anglicyzmami i szanuję polską mowę, akurat w tym wypadku popieram wybór właśnie tego języka, gdyż polskie nazwy wymieszane z angielskimi słowami kluczowymi i odwołaniami do bibliotek tworzą niepotrzebny chaos.
  2. Styl formatowania nazw. Dwa konkurencyjne to styl_z_podkresleniami oraz tzw. camelCase, gdzie poszczególne słowa wchodzące w skład nazwy rozpoczynamy dużą literą (z wyjątkiem pierwszego słowa). Mieszanie stylów w ramach jednego programu jest uznawane za przykład niechlujstwa i niestaranności. Najlepiej przyjrzyj się standardowi zalecanemu przez język programowania, którego używasz.
  3. Formatowanie bloków kodu - programu nie powinno się pisać jednym ciągiem, sformatowanym do jednej kolumny. Wykorzystaj spacje i tabulacje do tego, aby zagnieżdżone kawałki kodu przesunąć bardziej w prawo. W ten sposób już podczas czytania kodu będziesz dokładnie widzieć, gdzie co się kończy, a gdzie zaczyna. Jak spojrzysz na przykładowy listing zamieszczony wyżej, zauważysz, że zawartość każdego bloku objętego klamerkami jest pisana o jedno wcięcie bardziej w prawo, niż reszta, a otwieranie kolejnych poziomów generuje kolejne wcięcia. Początkowe klamerki można pisać albo w tej samej linijce, co instrukcja, albo w nowej.

Przeglądaj listingi, analizuj, jak piszą kod inni programiści i staraj się ich naśladować. To, że Tobie dany kod wydaje się czytelny nie znaczy, że tak jest w istocie; często jest tak dlatego, że nie znasz po prostu sposobu na jego jeszcze czytelniejsze zapisanie.

O ile nie zaznaczono inaczej, treść tej strony objęta jest licencją Creative Commons Attribution-ShareAlike 3.0 License