Archiwa kategorii: Ogólnie o programowaniu

Artykuły na temat programowania, które mogą być czytane przez nieinformatyków

Przy czerwonym winie, o kobietach w informatyce, z kobietami w informatyce

Poznań tej jesieni to obszar objęty epidemią: od jelitówki, przez zwykłą grypę i przedszkolne żółte katary aż po powrót odry. Chorowanie nie sprzyja kreatywności, dlatego dzisiaj odgrzewam starszy tekst, z poprzedniego bloga. Pięć lat temu (!) postanowiłam przepytać kilka koleżanek o ich przygodę z programowaniem.

Czy dużo się od tego czasu zmieniło? Nie wprowadziłam prawie żadnych modyfikacji w treści tego wpisu. Nowe akapity oraz wtrącenia zaznaczam na ciemnozielono.

Zaczęłam rozmowę pytaniem o to, dlaczego dziewczyny wybrały informatykę jako kierunek do studiowania, a także o reakcje otoczenia na ten wybór. Oto, co odpowiedziały:

  • Eliza (programuje w Delphi, C# i JS – dzisiaj w PHP): Tak naprawdę to początkowo chciałam studiować psychologię, ale w trzeciej klasie okazało się, że nie daję sobie rady z biologią. Zawsze lubiłam matematykę, dlatego w końcu wybrałam informatykę. Rodzina nie zareagowała w żaden charakterystyczny sposób. Zawsze lubiłam też grać na komputerze – uwielbiałam Boulder Dash.
  • Ewa (obecnie używa Rails i JS  i Pythona, ale jako właścicielka małej firmy ma osobiste doświadczenia z ASP, C#, PHP i Javą): Komputery pociągały mnie od dziecka. Dużą przyjemność sprawiało mi siedzenie przy komputerze mamy, kopiowanie folderów, tworzenie prostych plików wsadowych… no i gra w Prince of Persia. Oboje rodzice pracują w dziedzinach technicznych (telekomunikacja i programowanie), dlatego cieszyli się z tych zainteresowań, chociaż każde próbowało namówić mnie do wyboru swojej dyscypliny. Jednak przed rozpoczęciem studiów w ogóle nie programowałam, jeśli nie liczyć AC Logo.
  • Magda (Java serwerowa, aplikacje na Androida, aplikacje internetowe w Javie): Mam w rodzinie tradycje matematyczne. Moi rodzice są nauczycielami matematyki, więc mój wybór nie wydawał się dziwny. Miałam zdolności w tym kierunku. Poza tym lubię rozwiązywać abstrakcyjne zagadki, a programowanie dla mnie to jak układanie z klocków!

Pytałam również o rozważane inne kierunki studiów. Eliza wspominała o psychologii. Ewa przez chwilę myślała o polonistyce, jednak ponieważ za naszych czasów można było złożyć papiery tylko w 3 różne miejsca, zarzuciła ten pomysł. Magda ukończyła dwa kierunki: matematykę i informatykę. Początkowo interesowała się matematyką stosowaną, jednak teraz jest zadowolona z tego, że wybrała programowanie.

Eliza mówi, że nie chciałaby, żeby jej dziecko było programistą – „bo to nudne”. Absolutnie się z nią nie zgadzamy, jednak trzeba przyznać, że jest to praca, o której trudno rozmawia się z ludźmi robiącymi coś innego.

W następnej kolejności zadałam pytanie, jaki był stosunek dziewczyn do chłopaków w ich szkole, na studiach i w pracy. Zapłaciłam karę za ten skrót myślowy – Ewa podała mi konkretne liczby, natomiast pierwszą odpowiedzią Elizy było „lubiłyśmy ich”

Liczby:

  • Eliza: 20-10 w liceum (rozszerzony angielski), 14-48 na uczelni, 4-22 w pracy.
  • Ewa: 11-20 w szkole (mat-fiz), 14-48, 3-3 w obecnej pracy (kierownikiem projektu jest kobieta, której zależy na zatrudnianiu kobiet, po części dlatego, że produkt jest związany z modą i faceci mają problemy z identyfikacją z nim; przez wiele dni wyśmiewali się ze słodkiego wielkanocnego zajączka, którego dziewczyny wstawiły na stronę).
  • Magda: 1/3 dziewczyn w liceum („ale to dziewczyny były lepsze”), nie pamięta dokładnych liczb z uczelni, ponieważ każde zajęcia odbywały się w innym składzie. Na pewno chłopaków było więcej. W pracy 3-10.

Kolejne pytanie: Czy Twoim zdaniem kobiety i mężczyzni na kierunku technicznym na studiach są traktowani tak samo? Jeśli nie, czy możesz podać przykłady nierówności (w obie strony)?

Spodziewałam się powodzi żalu,  jednak okazało się, że wcale nie jest tak źle. Oto, co wymieniły dziewczyny:

  • Magda: Panie w dziekanacie zawsze były milsze dla mężczyzn, zwłaszcza tych przystojniejszych Poza tym nie przypominam sobie, więc chyba grubszych spraw nie było.
  • Ewa: Jeden z prowadzących rozmawiał tylko z chłopakami, nawet jeśli mieli bardzo blade pojęcie o wspólnym projekcie, a przy tym ciągle mówił do nas „panowie”.
  • Część naszych kolegów z premedytacją zapisywała się na zajęcia prowadzone przez atrakcyjne dziewczyny, traktując je bardziej jako przyjemność estetyczną niż kompetentnego nauczyciela w istotnej dla nas dziedzinie.

Powtórzyłam to pytanie jeszcze raz, ale w kontekście pracy zawodowej:

  • Ewa opowiedziała nam o paru spotkaniach biznesowych, na których potencjalni klienci rozmawiali tylko z jej wspólnikiem, mimo że w wielku kwestiach to ona ma większą wiedzę. Twierdzi jednak, że mogło tam chodzić o kwestie autoprezentacji i smiałości w kontaktach.
  • Eliza wspomniała historię, w której rozwiązała koledze problem, z którym zmagał się od dłuższego czasu. Kolega pochwalił ją przy szefie. Szef spytał, jak Elizie udało się znaleźć rozwiązanie, a ona odpowiedziała, że wyszukała je w Google. „Aha, czyli miałaś szczęście” nie było raczej adekwatną reakcją.
  • Magda czasami w obecnej pracy spotyka się ze stwierdzeniem ze strony kolegów, że robi coś w inny sposób, bo jest kobietą. „Strasznie mnie to wkurza, bo co ma do rzeczy moja płeć.” We wcześniejszych miejscach pracy nie spotykała się z takimi komentarzami.

Chciałam również poznać opinię dziewczyn na temat liczby kobiet w informatyce. Czy jest naturalna? Czy kobiety nie chcą tego robić, nie potrafią, a może chodzi o coś jeszcze innego? Ostatecznie doszłyśmy do następującego wniosku: zmuszanie kobiet do pracy w tym zawodzie nie ma sensu, jednak zdecydowanie należy je zachęcać. Sam fakt, że programowaniem zajmuje się więcej mężczyzn niż kobiet nie musi być niczym złym ani nienaturalnym, ale aktualne proporcje nie odwzorowują realnego rozkładu umiejętności. Są warunkowane kulturowo: od małego słyszymy, że „chłopcy są lepsi w naukach ścisłych a dziewczynki w humanistycznych” a nawet że „chłopcy są zdolni, ale leniwi, a dziewczynki pracowite, ale przeciętne”.

Stereotypy działają w obie strony. Słyszymy że „tylko brzydkie dziewczyny idą na politechnikę”, „na informatykę laski idą po to, żeby łatwo znaleźć męża”, ale także „jeśli pójdziesz na techniczne studia, faceci będą cię szczypać w tyłek”.

Ewa opowiedziała nam o świeżej frustrującej sytuacji powiązanej z protestowani w sprawie ACTA. Została zaproszona na oficjalną imprezę, na której przedstawiono ją – i jej szwagra –  jednemu z polskich ministrów. Oboje zostali zaprezentowani jako informatycy, z naciskiem na to, że Ewa zajmuje się programowaniem. Minister spytał szwagra, co sądzi o ACTA a gdy ten odparł „nie wiem, nie czytałem” – kompletnie zarzucił temat, nie dając Ewie okazji do wyrażenia swojej rozbudowanej opinii.

Wracając do stosunku liczby kobiet do liczby mężczyzn. Zgodziłyśmy się, że parytety nie mają sensu, jednak więcej dobrych dziewczyn w informatyce to rzecz naprawdę pożądana. Popieramy wszelkie inicjatywy mające na celu zwiększenie udziału kobiet w tym zawodzie, pod warunkiem, że nie prowadzą one do wykluczenia facetów (spójrzmy jednak prawdzie w oczy, od tego jesteśmy jeszcze bardzo daleko).

Pod koniec rozmowy próbowałyśmy odpowiedzieć na pytanie, czy istnieją obszary informatyki, w których my (lub „większość kobiet”) sprawdzamy się lepiej niż mężczyźni (lub „większość mężczyzn”).

Wygląda na to, że większość kobiet ma jednak lepsze umiejętności komunikacyjne niż większość mężczyzn. Obecność paru kobiet w zespole ma bardzo dobry wpływ na atmosferę pracy. Często mamy więcej cierpliwości podczas objaśniania różnych spraw, także osobom spoza naszej dziedziny. Nie nosimy w sobie głębokiej nienawiści do pisania dokumentacji! Chociaż czasami praca ta nie jest odpowiednio doceniana. Być może łatwiej jest nam przyznać, że (jeszcze) czegoś nie wiemy. Obawiam się trochę, że ta cecha wcale nie wychodzi nam na korzyść: inaczej odbierane są osoby, które zaczynają zdania od „uważam, że”, a inaczej te, które mówią „jestem pewien”. Nie potrafimy wskazać żadnych poważniejszych różnic, jeśli chodzi o poziom, sposób czy styl kodowania.

Przy okazji wspomniałyśmy pewnego znanego nammężczyznę, który deklaruje, że nigdy nie zatrudni kobiet, ponieważ nie wie, jak z nimi rozmawiać. Twierdzi, że jeśli skarci pracownika-mężczyznę i powie mu, że powinien robić coś inaczej, ten powie „OK” i weźmie się do pracy. Kobieta, według, niego ”zamknie się na pół dnia w łazience i będzie płakać”. Pomijając już to, że żeby zgłaszać takie obserwacje, trzeba by jednak zatrudnić kobietę – po pierwsze, żadna z nas nie płacze z takiego powodu (dwa razy w życiu płakałam w łazience w pracy, oba razy po konkretnych seksistowskich uwagach kompletnie niezwiązanych z moją pracą). Po drugie, moje doświadczenie uczy, że co prawda wiele osób powie „OK”, co nie zmieni jednak faktu, że spróbują się za to odegrać, gdy nadarzy się okazja.

Zakończę ten radosny wpis cytatem z Magdy:

Wybrałam taki zawód, bo lubię. Chociaż czasami poziom frustracji sięga zenitu! Nie rozumiem natomiast dziewczyn, które w swojej pracy chcą udowodnić, że są lepsze od mężczyzn. Nie o to chyba w życiu chodzi żeby komuś coś udowadniać.

Sama po kilku latach przeczytałam ten tekst z zainteresowaniem. Czy coś zmieniło się w środowisku? Czy zmieniły się moje poglądy? Wypunktuję poniżej kilka luźnych uwag. 

  • Dzisiaj jeszcze bardziej niż wtedy jest dla mnie oczywiste, że za „zachęcanie” kobiet do IT (a jeszcze bardziej za ich niezniechęcanie) trzeba się zabrać bardzo wcześnie. Począwszy od sklepów z zabawkami i zawartości działów „dla chłopców” i „dla dziewczynek” oraz wyboru komplementów, jakimi obdarzamy małe dzieci. 
  • Dziś jeszcze mniej chętnie używam sformułowań „większość kobiet” i „większość mężczyzn”. 
  • Uważam,  że krótkoterminowo i w niektórych sytuacajch parytety mogą mieć sens. 
  • W sektorze IT potrzeba coraz więcej pracowników. Również z tego powodu, kobiet jest więcej niż jeszcze parę lat temu. Pewną nowością są osoby, które nie studiowały informatyki, ale udało im się przekwalifikować.
  • W backendowych zespołach, z którymi obecnie pracuję, nadal nie ma jednak ani jednej programistki (są za to dwie techniczne managerki: ludzi i produktu).
  • Głupie żarciki w pracy jak były, tak są. Wbrew obiegowej opinii, korporacje z reguły radzą sobie z tym tematem lepiej niż „przyjazne” niewielkie firmy. 
  • Wśród kobiet, które twierdzą, że jakakolwiek dyskryminacja w naszej branży jest wyssana z palca, wiele jest informatyczkami w drugim pokoleniu. Moim zdaniem potwierdza to tezę o znaczeniu warunkowania w domu, na najwcześniejszym etapie rozwoju. Jeśli dziewczynka wychodzi z domu rodzinnego przekonana, że może wszystko, jest znacznie mniej podatna na drobne przejawy seksizmu i dyskryminacji.

NLP w pigułce

Mam koleżankę, która jest doświadczoną programistką Javy oraz Scali. Kilkanaście razy w roku występuje na międzynarodowych konferencjach. Z opisu łatwo wydedukować, ze na co dzień nie potrzebuje mojej ekspertyzy technicznej 😊 Jednak kilka dni temu poprosiła mnie o pilne wsparcie. Napisała, że do tej pory traktowała NLP (przetwarzanie języka naturalnego, ang. natural language processing) jako „coś, z czego ludzie robią doktoraty”, a teraz musi sama poprawić kod z tej dziedziny.

Kod okazał się pluginem do Slacka, który pozwala programistom wydawać polecenia w języku naturalnym i w ten sposób zarządzać procesem budowania, testowania i wdrażania aplikacji. Chciała dopisać kilka poleceń, ale wystraszyły ją sformułowania takie jak „tokenizacja” czy „VP”, i inne, bezpośrednio związane z wykorzystywaną tam biblioteką OpenNLP. Poprosiła mnie o praktyczny kurs NLP w pigułce, opisujący kroki niezbędne do zrozumienia, o co użytkownikowi właściwie chodzi.

Oto on.

Pomijam kwestię rozpoznawania mowy, ponieważ niespecjalnie się na niej znam i nie ma ona znaczenia w przypadku pisania pluginów do slacka. Rozpoznawanie mowy to zagadnienie z dziedziny przetwarzania sygnałów, obecnie realizowane niemalże wyłącznie przy użyciu uczenia maszynowego. 

Na początku jest zdanie.

Tak przynajmniej załóżmy. W rzeczywistości zdań może być kilka – wtedy trzeba ja jakoś rozdzielić, co w zależności od języka może sprowadzić się do cięcia po kropkach, albo być super skomplikowanym zadaniem wymagającym wnikania w składnię.

Nietrywialny przykład z języka polskiego:

Poza tym nie wszystko jest zdaniem. Bezpieczniejszy jest termin wypowiedzenie (ang. utterance), który obejmuje również wszelkiego typu równoważniki i pojedyncze słowa.

Załóżmy, że nasze zdanie to „wrzuć wersję 3.1 config na produkcję”.

Zdanie trzeba podzielić na tokeny.

Token to, w przybliżeniu, słowo. W niektórych językach tokenizacja jest prosta. W polskim możemy chcieć rozdzielić np. „jasnozielony” na dwa tokeny: „jasno” i „zielony”. W angielskim zamienić „wanna” na „want to”. Po hiszpańsku „pokaż mi to” pisze się łącznie „muéstramelo”, co, żeby móc przeprowadzić jakąkolwiek analizę, musimy rozbić na trzy tokeny: „muestra” „me” „lo” (i po drodze zgubić akcent).

Normalizacja.

Czasami razem z tokenizacją przeprowadza się normalizację, czyli np. zamienia słowa „jeden”, „jedna” itp. na „1”.

Wszystko to po to, żeby uprościć sobie życie i zmniejszyć rozmiary modelu, w oparciu o który analizujemy tekst.

Dalej musimy rozpoznać byty nazwane (ang. named entities).

Byty nazwane to, w uproszczeniu, byty reprezentowane przez nazwy własne – w odróżnieniu od rzeczowników pospolitych. Ich rozpoznanie nie zawsze jest łatwe. Często zależy od kontekstu. Nierzadko w wyniku takiej analizy dostajemy kilka hipotez. Przykładowo, „house” to po angielsku „dom”, ale może to być również nazwa serialu lub nazwisko jego głównego bohatera.

Po tym kroku analizy powinniśmy wiedzieć, która część naszego wypowiedzenia to byt nazwany, i jakiego typu jest to byt (miejsce, osoba, tytuł, …).

W naszym przykładzie bytem nazwanym może być „config” (jako nazwa aplikacji) oraz „produkcja” (jako nazwa środowiska).

Ujednolicenie form wyrazów: lematyzacja lub stemming.

Etap ten ma różne znaczenie w zależności od języka. Chodzi tu o sprowadzenie różnych form tego samego słowa do wersji uznawanej za podstawową.

  • Stemming to obcięcie wszelkiego rodzaju przedrostków i przyrostków, mające na celu dotarcie do nieodmiennego „rdzenia” reprezentującego wyraz. Sam rdzeń niekoniecznie musi być poprawnym słowem. Algorytm stemmera nie musi być zależny od języka.
  • Lematyzacja to sprowadzenie słowa do jego podstawowej postaci. W przypadku czasownika będzie do bezokolicznik, w przypadku rzeczownika – mianownik liczby pojedynczej. Do wykonania tego zadania potrzebny jest słownik lub rozbudowany zestaw reguł fleksyjnych dla danego języka.

Oczywiście zadanie to jest trudniejsze dla silnie fleksyjnych języków, jak polski.

Rozpoznawanie części mowy.

W końcu powinniśmy się dowiedzieć, z jakimi częściami mowy mamy do czynienia, najlepiej również w jakich odmianach. Z reguły informację te zwraca lematyzator. Tegu typu analiza może być oparta o słownik, ale może również wykorzystywać końcówki fleksyjne (np. jeśli nieznane nam polskie słowo kończy się „zować”, można przyjąć hipotezę, że to czasownik).

Wreszcie dochodzimy do parsowania.

Parsowanie to analiza składniowa, jednak w praktyce już na tym etapie często wydobywa się także informacje semantyczną, czyli znaczenie wypowiedzenia.

Zasadniczo, do znaczenia można dobrać się na jeden z trzech sposobów:

Wyrażenia regularne.

To najprostsza, najbardziej naiwna metoda, jednak w przypadku pluginów do slacka, które mają pozwalać na wykonanie kilku prostych operacji, nierzadko okazuje się wystarczająca.

Możemy napisać:

lub coś odrobinę bardziej skomplikowanego i już dostaniemy wszystkie potrzebne nam informacje.

Gramatyki formalne

Oparte na teorii Chomskiego, gramatyki (tworzone ręcznie lub automatycznie) to zestawy reguł, które definiują, jak może wyglądać poprawne zdanie w danym języku (naturalnym, jak polski, albo sztucznym, jak C++).

Gramatyka może składać się np. z takich reguł:

Wówczas nasza grupa rzeczownikowa (NP) może mieć postać “a cat”, “the cat”, “a dog” i “the dog”.

Gramatykę można zapisać w postaci automatu skończonego.

Uczenie maszynowe

Efekt jest ostatecznie taki sam jak w przypadku gramatyk, tylko zamiast żmudnie definiowanych reguł wykorzystywane są wnioski wyciągnięte podczas trenowania systemu przy użyciu wybranej metody (np. CRF) na dużej ilości odpowiednio opisanego tekstu (na korpusie)

Reprezentacja danych semantycznych.

Ostatecznie powinniśmy otrzymać coś w rodzaju „ramy”, która często przypomina strukturę zdania. W naszym wypadku będzie to mniej więcej coś takiego:

Parsowanie płytkie i głębokie.

Głębokie parsowanie to pełne odtworzenie drzewa składniowego zdania. Parsowanie płytkie (czasami określane terminem chunking) ma na celu wydobycie istotnej informacji, bez potrzeby wyciągania wszystkich zależności składniowych pomiędzy słowami.

Analiza koreferencji.

Na początku napisałam, że punktem wyjścia jest dla nas zdanie (bądź wypowiedzenie), ale w języku naturalnym zdania mogą być ze sobą powiązane w taki sposób, że w celu zrozumienia zdania musimy cofnąć się o jedno lub więcej zdań wstecz.

W analizie koreferencji chodzi przede wszystkim o anaforę. Jeśli użytkownik wyda polecenie „wdróż to”, musimy zrozumieć, do jakiego wcześniej wspomnianego bytu się odnosi.

Przykład: OpenNLP

Istnieje trochę gotowych narzędzi i zasobów do uprawiania NLP: parsery, korpusy tekstów, treebanks (zdania rozbite na drzewa składniowe), biblioteki implementujące algorytmy uczenia maszynowego. Kod, przy którym pracowała Jessica, korzystał z javowej biblioteki OpenNLP, która oferuje trochę gotowych modeli językowych, a także umożliwia trenowanie własnych.

Co możemy od niej dostać?

Np. dla zdania “namiekko.pl is a the coolest site” otrzymamy:

Jak przełożyć to na nasze potrzeby? Musimy stworzyć jakieś mapowanie pomiędzy odnalezionymi grupami a naszą reprezentacją danych. Możemy napisać reguły takiego typu: jeśli czasownik w VP (verb phrase) to „deploy” lub „push”, to chcemy wykonać naszą akcję deploy. Argumentów dla tej akcji należy szukać w następujących elementach drzewa składniowego (…)

Zasoby

Wyrażenia regularne dla nieprogramistów

Wyrażenia regularne wspominałam już w poprzednim wpisie. Jest to narzędzie ukochane przez część programistów i znienawidzone przez innych. Dzisiaj chciałabym podzielić się następującą refleksją: wyrażenia regularne mogą ułatwić życie nie tylko programistom. Przy ich pomocy można uprościć wiele manualnych czynności, wykonywanych na przykład w pracy biurowej.

Czym są wyrażenia regularne?

Teoria raczej nie zachęci początkujących, ale do zastosowań praktycznych wystarczy potraktować je jako wzorce, które umożliwiają przeszukiwanie tekstu i dokonywanie w nim podmian.

Pełna składnia wyrażeń regularnych została opisana na przykład w tej (angielskojęzycznej) ściądze. Poniższa tabelka opisuje kilka najbardziej podstawowych symboli:

Symbol Znaczenie Przykład
. Dowolny znak. k.t pasuje do „kot” i „kat”
+ Powtórzenie poprzedzającego znaku jeden lub więcej razy. kot+ pasuje do „kot”, „kott”, „kott” itp.
* Powtórzenie poprzedzającego znaku zero lub więcej razy. kot* pasuje do „ko”, „kot”, „kott” itp.
{m,n} Powtórzenie poprzedzającego znaku od m do n razy. ko{2,4}t pasuje do „koot”, „kooot” i „kooot”.
^ Początek linii. ^k – literka k zapisana na początku linii
$ Koniec linii k$
[abc] Znaki ze zbioru, wyszczególnione k[ao]t pasuje do „kot” i „kat”.
[a-c] Znaki ze wskazanego przedziału [2-4] to cyfra „2”, „3” lub „4”.
\b Granica słowa .+a\b to dowolne słowo kończące się na literą „a”, np. „torba”.
\d Cyfra \d\d pasuje na przykład do „23”
\s Biały znak k\st pasuje do „k t”
\S Znak niebiały k\St pasuje do „kot”, „kit”, ale nie do „k t”

Zadanie

Wyobraźmy sobie teraz następujący scenariusz z życia biura. Szef firmy, pan Cebuliński, organizuje przedświąteczną galę. W ramach oszczędności poprosił siostrzenicę – studentkę pierwszego roku informatyki – o wydobycie z bazy danych informacji o klientach, którzy terminowo opłacali faktury. Na podstawie przesłanej przez nią listy menedżerka biura, pani Nokturniak, ma przygotować listę gości. Jej zadaniem jest znalezienie stu klientów, na których firma w tym roku zarobiła najwięcej. Dodatkowo, ponieważ prezes Cebuliński rozwodzi się ze swoją żoną Anną, na liście gości nie może znaleźć się ani jedna kobieta o tym imieniu.

Lista ma następującą postać:

1. Borowiak, Kazimierz; 10000 zł; terminowo; kborowiak@example.com
2. Borowiak, Ania B.; 10011 zł; nieterminowo; abborowiak@example.com
3. Nowak, Jan, 9321 zł; terminowo; a@example.com
4. Nowak, Janina, 9322 zł; nieterminowo; ab@example.com
...
9816. Zi łkowski, Andrzej; 100 zł; terminowo; aziolkowski@example.com

Zadania pani Nokturniak prezentują się następująco:

  1. Musi usunąć z listy wszystkie Anie, Anki i Anny.
  2. Zauważyła, że litera „ó” została zamieniona na spację. Musi więc przejrzeć listę prawie 10000 nazwisk i poprawić niektóre z nich.
  3. Musi znaleźć 100 „najdroższych” klientów spośród tych, którzy płacili terminowo, aby wysłać im zaproszenia.

Pani Nokturniak zaplanowała kolejną długą noc przy komputerze. Spróbujmy chociaż trochę ułatwić jej życie.

Potrzebny nam będzie edytor tekstu, który rozumie wyrażenia regularne (albo konsola Linuksa – pokażę w kolejnym wpisie, jak ją do tego wykorzystać). Może to być np. Notepad++. Załóżmy, że pani Nokturniak otworzyła już edytor i przekleiła do niego dane.

Usunięcie Ań

Co wspólnego mają ze sobą łańcuchy znaków „Ania”, „Anka” i „Anna”? Wyglądają prawie tak samo, różnią się jedynie trzecim znakiem. Zgodnie z zamieszczoną powyżej tabelą, kropka (.) to symbol uniwersalny. Do wszystkich trzech słów zostanie dopasowany dopasowany wzorzec:

An.a

Wyrażenie regularne w edytorze Notepad++ dopasowane do słowa w tekście
Wyrażenie regularne w edytorze Notepad++ dopasowane do słowa w tekście

Tu uwaga na drobną pułapkę. Ciąg znaków „Anna” może być częścią dłuższego słowa, np. nazwiska („Annakowski”). Dla pewności zaznaczmy, że interesują nas tylko te wystąpienia, które nie są częścią dłuższego słowa. Użyję do tego symbolu granicy słowa:

\bAn.a\b

Co dalej? Wyczyśćmy wszystkie linie zawierające imię Anna. Wzorzec musi mieć postać: „nieważne co – imię Anna – nieważne co”, czyli:

.*\bAn.a\b.*

albo jeszcze lepiej dodajmy do niego znak początku i końca linii (choć domyślnie wyrażenia regularne i tak działają jedynie w ramach jednej linii, czyli efekt będzie ten sam):

^.*\bAn.a\b.*$.

Każmy edytorowi zastąpić wszystkie takie linie linią pustą.

regex2
Zamiana linii zawierającej którąś z wersji imienia „Anna” na linię pustą.

W tej chwili nasz dokument nie zawiera już danych żadnych Ann.

W podobny sposób możemy od razu usunąć wiersze reprezentujące klientów nieterminowych, których także nie mamy uwzględniać w obliczeniach.

2. Zamiana (niektórych!) spacji na „ó”

Jeśli po prostu zamienię wszystkie spacje na „ó”, efekt nie będzie zadowalający:

Muszę odszukać tylko te spacje, które znajdują się pomiędzy dwiema małymi literami.

Mogę wykorzystać w tym celu przedziały:

[a-z] [a-z]

lub bezpieczniej

[a-zA-ZąśćżńżĄŚĆŻŃŹ] [a-zząśćżńż]

lub najbezpieczniej (z uwzględnieniem wszystkich, nie tylko polskich znaków w nazwiskach, ale nie w każdym edytorze to zadziała) pełną klasę małych liter:

\p{Lu} \p{Lu}

Ok, znaleźliśmy te spacje, tylko jak je teraz zamienić? Jeśli zamienię cały znaleziony łańcuch znaków, Zi łkowski nie zamieni się w Ziółkowskiego, tylko w Zókowskiego (litery dopasowane do [az] również zostaną zamienione). Na pomoc spieszą nam tzw. capturing groups, czyli grupy przechwytujące.

Wszystko, co napiszę w nawiasie, zostanie zapamiętane jako grupa oznaczona kolejnym numerem. Do grup mogę się następnie odnieść w wyrażeniu, którym chcę zastąpić odnaleziony wzorzec. Jak to zrobić? Mogę mój wzorzec zapisać tak:

([a-zA-Z]) ([a-z])

a wyrażenie zastępujące:

\1ó\2

Wówczas każde wystąpienie spacji pomiędzy dwiema literami (przy czym druga z nich musi być mała) zostanie zastąpione literą „ó” otoczoną oryginalnymi dwiema literami (z grupy pierwszej i drugiej).

regex3

3. Odnalezienie „najdroższych” klientów

Do tego zadania można podejść na dwa różne sposoby.

Łatwiej ale z pomocą z zewnątrz

W wersji pierwszej wystarczy sprowadzić dokument do formatu CSV (skrót od Comma-Separated Values, czyli wartości rozdzielane przecinkami, ale czym w rzeczywistości najczęściej są to średniki, a nie przecinki). Format ten jest rozumiany przez większość, jeśli nie wszystkie, programów kalkulacyjnych typu Excel. Następnie można posortować wiersze według kolumny zawierającej poniesione przez klienta koszty.

W obecnej chwili nasze wiersze mają następujący format:
1. Borowiak, Kazimierz; 10000 zł; terminowo; kborowiak@example.com
Wystarczy zamienić pierwszą kropkę na średnik albo usunąć liczbę i kropkę. Na dobrą sprawę moglibyśmy nawet zostawić numer porządkowy jak jest. Nie będzie miał sensu, ale nie przeszkodzi w naszych obliczeniach.

Dla porządku (sic) usuńmy jednak numer porządkowy. Chcemy dopasować się do liczby na początku linii, po której następuje kropka oraz spacja – i całość zastąpić pustym łańcuchem znaków. Czyli:

^\d+\. albo ^\d+. (kropka to symbol uniwersalny, w szczególności dopasuje się do symbolu kropki; jeśli chcemy na pewno złapać tylko kropkę, musimy poprzedzić ją we wzorcu tzw. symbolem ucieczki „\”, który odbiera znakowi jego specjalne znaczenie).

Dokument z liniami postaci:
Borowiak, Kazimierz; 10000 zł; terminowo; kborowiak@example.com

możemy już spokojnie otworzyć w excelu jako plik CSV i tam przeprowadzić sortowanie.

Wersja dla ambitniejszych

Alternatywnie możemy przestawić kwotę na początek linii i w oparciu o nią posortować linie w pliku. Z pomocą znowu przyjdą nam grupy. Plan jest następujący: podzielić każdą linię na 3 grupy: przed kwotą, kwota i za kwotą, następnie zmienić ich kolejność z 123 n 213. Na koniec posortować (w edytorze, jeśli daje taką możliwość, albo w wierszu poleceń dowolnego systemu operacyjnego za pomocą instrukcji sort).

Spróbujmy. Linię pasującą do wzorca

^(.+)(\d+ zł; )(.+)$

zamieńmy na

\2\1\3

W efekcie mamy linie:
10000 zł; 1. Borowiak, Kazimierz; terminowo; kborowiak@example.com
Takie linie możemy już posortować wg wartości liczbowych.

Sortowanie linii według wartości liczbiwych.
Sortowanie linii według wartości liczbiwych.

Możliwy kłopot z sortowaniem

Drobny kłopot: standardowe sortowanie leksykograficzne (czyli według alfabetu) ustawi nam liczby w nieodpowiedniej kolejności, np. 10 przed 9, np.:
1
10
11
2
22
9

Żeby takie sortowanie się udało, liczby muszą być tej samej długości – dopełnione na początku zerami (09 będzie przed 10).
01
02
09
10
11
22

Prawdę mówiąc na szybko nie potrafię podać jednej zamiany, która upora się z wszystkimi przypadkami! Ale można zastosować tę samą zamianę kilka razy, aż przestaniemy widzieć jakiekolwiek zmiany. Załóżmy, że chcemy, żeby wszystkie liczby ostatecznie zajmowały 10 cyfr.

Możemy wtedy zamieniać każdą liczbę na początku linii, która ma mniej niż 10 cyfr:

^(\d{1,9} )

na tę samą liczbę (grupa przechwytująca!) poprzedzoną zerem:

0\1

Kiedy zapis liczby osiągnie długość 10 znaków, wzorzec przestanie się dopasowywać.

Na koniec wreszcie poprawnie sortujemy – i już możemy rozsyłać zaproszenia.

Trwało do trochę krócej niż całą noc, prawda?

Przekwalifikowanie – mrzonka czy realna szansa?

Chociaż nie zawsze da się to rozpoznać po ubiorze bądź stylu życia* i niekoniecznie jest to sprawiedliwe, zarobki w miarę doświadczonych programistów czynią z nich jednych z najlepiej wynagradzanych ludzi w Polsce.

Nie wszyscy zajęli się informatyką z powodu absolutnej pasji. Kodowanie to bardzo przyjemna, satysfakcjonująca i stanowiąca wyzwanie praca – jednak wielu znanych mi programistów do poczucia osobistego spełnienia potrzebuje również samorealizacji w nieco bardziej humanistycznych dyscyplinach.** Być może dlatego nierzadko słyszę kolegów po fachu sarkających na bezrobotnych absolwentów kierunków miękkich. „Po co szedł na takie studia?”, „Wiadomo, że praca jest gdzie indziej”, „Niech się przekwalifikuje, przecież my też co chwilę od podstaw uczymy się czegoś nowego”.

Opinie te bywają powtarzane zdecydowanie i bez zastanowienia. A jednak nie tak dawno byłam świadkiem sytuacji, w której absolwent teatrologii (nie wymyślam tego!) zapytał zaprzyjaźnionego programistę, od czego zacząć przekwalifikowanie się… a programista zbladł. Co innego teoretyzować o zmianie w cudzym życiu, a co kogoś przekonać i przyjąć choć część odpowiedzialności za jego rozwój, a ostatecznie także sukces bądź porażkę.

W tym wpisie postaram się odpowiedzieć na pytanie, czy da się zostać programistą na późniejszym etapie życia i podzielę się wskazówkami na temat tego, jak zacząć.

Warunki konieczne

Skoro popyt jest tak duży, czy programistą może zostać każdy? Skrócona odpowiedź brzmi: absolutnie nie!!! Jednak z powodzeniem może się to udać całkiem sporej grupie osób, które wcześniej nie rozważały tej profesji.

Następujące cechy i umiejętności uważam za konieczne do rozpoczęcia nauki w tym kierunku:

1. Analityczne, uporządkowane myślenie

Programowanie to w dużej mierze praca kreatywna, ale ten rodzaj kreatywności ma niewiele wspólnego z twórczym chaosem. Musisz być w stanie myśleć algorytmicznie: wyraźnie definiować kroki prowadzące do uzyskania wyznaczonego celu. Musisz przykładać uwagę do szczegółów. Musisz przewidywać, co może pójść nie tak, jak niestandardowo może się zachować klient, jakie problemy mogą wystąpić. W dużej mierze sprowadza się to do tego, że programista powinien mieć stosunkowo wysoki iloraz „matematycznej” („tradycyjnej”) inteligencji.

2. Cierpliwość

Materiału do przyswojenia jest dużo. Tworzenie prawdziwych, złożonych aplikacji trwa i wymaga współpracy wielu osób. Co prawda istnieją trendy wytwarzania oprogramowania od strony interfejsu użytkownika, gdzie od razu widać włożony wysiłek, jednak musisz być gotowy na żmudną pracę, która długo nie przynosi widocznych efektów (oprócz przechodzących testów – bo oczywiście będziesz pisać testy).

3. Radość z pisania kodu

Większość znanych mi programistów bardzo wcześnie zaczęła zdradzać smykałkę do kodowania. Sama spędziłam długie godziny nad otrzymanym na komunię Commodore 64, programując quizy i przelatujące przez ekran rakiety ASCII Art (następnie mój rozwój zatrzymał się na lata na tym etapie). Jeśli jednak nie zostałeś odpowiednio zachęcony za młodu, postaraj się możliwie szybko znaleźć odpowiedź na pytanie: „czy sprawia mi to przyjemność?”. Po pierwszym kursie programowania lub po pierwszej przeczytanej książce – spróbuj rozwiązać prosty problem programistyczny (np. na sprawdzarce takiej jak ta: http://acm.timus.ru/). Jak było? Udało Ci się? Co czułeś, kiedy program działał coraz lepiej? Ogromną satysfakcję, a może ulgę, że wreszcie koniec? To bardzo ważne.

4. Znajomość angielskiego

W dzisiejszych czasach nie da się programować bez dobrej (biernej) znajomości (pisanego) angielskiego. Większość kursów (o których zaraz) jest po angielsku. Dokumentacja, którą będziesz czytać jest prawie zawsze po angielsku. Gotowe rozwiązania popularnych problemów są opisane po angielsku, np. na http://stackoverflow.com/. Być może uda Ci się dorwać podręcznik po polsku (warto), ale większość ratujących tyłek, aktualnych treści istnieje jedynie w języku angielskim.

Przydadzą się

Po pierwsze, na pewno przyda Ci się mentor. Życzliwa osoba już pracująca w zawodzie, o którym myślisz, skłonna poświęcić Ci trochę czasu i wskazać kierunki rozwoju. Znasz kogoś takiego? Doskonale. Nie znasz? Jeśli mieszkasz w większym mieście, przejdź się kilka razy na spotkania lokalnych User Groups***. W przeciwnym razie możesz spróbować uzyskać wsparcie w grupach i na forach w Internecie.

Po drugie – czy znasz języki obce? Jeśli tak, to tym lepiej dla Ciebie. Im więcej tym lepiej. Język programowania to też język, który ma swoją składnię i semantykę. Jeśli zdołałeś opanować język obcy (analitycznie, czyli potrafisz narysować drzewo składniowe zdania), w Twoim mózgu powinny już być wydeptane najważniejsze ścieżki umożliwiające korzystanie z języka programowania.

Jak się nauczyć?

O ile znasz angielski, a jak tłumaczyłam powyżej, właściwie musisz go znać, to masz do dyspozycji ogrom wiedzy przedstawionej w portalach MOOC (Massive Open Online Course, czyli masowe otwarte kursy online), takich jak Edx czy Coursera. W większości przypadków kursy składają się z wykładów, ćwiczeń praktycznych (w postaci testów) oraz zadań programistycznych, sprawdzanych albo automatycznie, albo przez innych uczestników kursu. To doskonały punkt startowy.

Oprócz tego są podręczniki, dokumentacje języków programowania, a także warsztaty**** (często darmowe) organizowane przez różne społeczności, np. Geek Girls Carrots.*****

Jaki język?

Uparcie utrzymuję, że najbardziej przyszłościowy (liczba ofert pracy, przeznaczenie) język, którego można się w miarę szybko nauczyć od podstaw, to Python. Ale możesz rozejrzeć się, czego potrzebują i uczą w Twojej okolicy.

Rozmowa o pracę

Są firmy, które nigdy nie zatrudnią początkującego programisty. Są szefowie gotowi pracować tylko z pasjonatami, od podstawówki piszącymi wirusy. W niektórych przypadkach takie wymagania mają sens, w innych niekoniecznie. Uwierz jednak, że istnieje masa firm gotowych podjąć ryzyko przyjęcia kogoś niezbyt doświadczonego i przeszkolenia go.

Nie będę tu powtarzać tradycyjnych porad na temat pisania CV i przygotowania do rozmowy rekrutacyjnej. Najważniejsze: nie ściemniaj! Jeśli jesteś w stanie psychicznie znieść porażkę, po nieudanej rekrutacji dopytaj, czego Ci zabrakło i spróbuj rozwinąć się trochę w tym kierunku.

Warto pamiętać, że informatycy w firmach wytwarzających oprogramowanie to nie tylko programiści. Do branży możesz wejść trochę „od tyłu”, na przykład jako tester. Mimo wszystko zachęcam do rozpoczęcia procesu zmian od przyswojenia jednego przynajmniej języka programowania.

Licz się z tym, że…

1. Będziesz się ciągle uczyć

Taki zawód. Jeśli chcesz coś w nim osiągnąć i mieć pewność zatrudnienia, będziesz co jakiś czas przerabiać nową książkę, nowy blog, nowe kursy. Nawet jeśli w pracy nie będziesz siedzieć po godzinach (rozsądni szefowie wiedzą, że liczba błędów wprowadzonych podczas nadgodzin często niweluje jakąkolwiek płynącą z nich wartość dodaną), ale czasem po pracy,  w prywatnym czasie, będziesz musiał przysiąść nad nową technologią.

2. Twoja głowa będzie stale w pracy

To również wynika ze specyfiki zawodu. Nierozwiązane problemy będą się za Tobą wlekły. Spędzisz wiele wieczorów, zastanawiając się, dlaczego to u licha nie działa. Dobra strona medalu: niejednokrotnie przekonasz się, że Twój mózg pracował, kiedy spałeś, a że niemożliwy do rozwiązania problem następnego dnia okaże się trywialny.

3. Koledzy z pracy nie raz zdziwią się, że czegoś nie wiesz

Nauczyłeś się pierwszego języka programowania. Na trzeciej z rzędu rozmowie rekrutacyjnej napisałeś test na 80%, pokazałeś, że jesteś odpowiedzialnym i zdeterminowanym człowiekiem – i dostałeś pracę. Pierwszego dnia przychodzisz do biura, dostajesz swoje pierwsze zadanie i nagle okazuje się, że kompletnie nie wiesz, jak zacząć. Znasz język, ale co oni mówią o LDAP, kontroli wersji, bazie danych…? W tym momencie wróć do punktu 1. Będziesz się ciągle uczyć. W obliczu nieznanych problemów spróbuj najpierw skorzystać z Google. Jeśli nie dajesz rady – poproś o pomoc. Zadbaj o to, żeby nigdy nie pytać dwa razy o to samo.

Studia informatyczne trwają pięć lat i nie polegają jedynie na nauce programowania. Ich absolwenci często sami nie zdają sobie sprawy, że niektóre zagadnienia nie wchodzą w zakres wiedzy ogólnej i mogą być komuś (bądź co bądź) w branży kompletnie nieznane. Przełknij dumę, uzupełnij luki, znajdź sobie miejsce w organizacji. Będzie dobrze.

4. Na początku możesz zarabiać mniej niż dotychczas

Nie tylko możesz zarabiać mniej niż dotychczas, ale na dodatek może to być mniej, niż zarabia o połowę od Ciebie młodszy dzieciak w sąsiednim kubiku. Nie przejmuj się, to tymczasowe. Nie ma lepszej metody nauki programowania niż w prawdziwej pracy – potraktuj to jako (opłacaną przecież!) inwestycję w siebie.

Uwaga: z awansami i podwyżkami w firmach informatycznych różnie bywa. Czasami jedyną metodą na zauważalną podwyżkę jest przejście do innej firmy.

Czy płeć ma znaczenie?

Serio, nie wiem.

Kobiecie, która chce się przekwalifikować, tak samo jak początkującej praktykantce, paradoksalnie może pomóc stereotyp „damy w opałach”. W zmaskulinizowanym biurze możesz pozwolić otoczyć się mentorską, dżentelmeńską i trochę protekcjonalną opieką, o ile całe Twoje jestestwo nie protestuje przeciwko takiemu stawaniu sprawy. Ostrzegam jednak – takie łatki trudno potem zgubić.

Czy znam ludzi, którym się udało?

Tak!!!

Słowa klucze: odwaga, wytrwałość, inteligencja, ciekawość.

A jeśli się nie uda?

Wysiłek włożony w przyswojenie tych kwestii i tak nie pójdzie na marne. Podstawy programowania będą coraz bardziej potrzebne do wykonywania innych zawodów. Wyraźnie to widać np. w dziedzinie biotechnologii.

Przypisy


* Nie piję tu przesadnie do stereotypu niedomytego informatyka. Uważam się za informatyka domytego, a jednak mam na koncie kuriozalne doświadczenie ze sklepu Zara, gdzie na podstawie nieformalnego i powyciąganego ubioru zostałam potraktowana jak złodziejka.

** Zdaniem wielu, stanie w takim rozkroku jest przepisem na porażkę. Polecam wystąpienie Larry’ego Smitha na TED, zatytułowane „Dlaczego nie zrobisz wielkiej kariery”. Jako świeżo upieczona matka karmiąca mam ostatnio dużo czasu na oglądanie takich wykładów, więc od czasu do czas będę się dzielić perełkami 🙂

*** Od razu ostrzegam, że poziom i kultura lokalnych społeczności programistycznych bywają różne. Niektóre są bardzo przyjazne dla początkujących, inne pielęgnują profesjonalny poziom i zadzierają nosa 😉

**** Odmienne od mojego zdanie na temat szkół programowania ma autor tego artykułu w portalu TechCrunch: Coding Academies Are Nonsense. Wrzucam jako ciekawostkę.

***** Powiem szczerze, że cykliczne spotkania Geek Girls Carrots nieco mnie rozczarowują, ponieważ są dużo bardziej startupowe niż programistyczne. Niezależnie od tego, organizacja tworzy i promuje sporo wartościowych kursów programowania dla początkujących.

Google w gąszczu danych: fotograficzny skandal i uczenie maszynowe dla laików

Dwa tygodnie temu media obiegła wieść o skandalicznej wpadce Google Photos. System automatycznego rozpoznawania twarzy i obiektów na zdjęciach zaklasyfikował dwie czarnoskóre osoby jako „goryle” i utworzył dla nich specjalny album o tym właśnie tytule.

Wśród tłumaczeń Google – a trzeba firmie przyznać, że zareagowała bardzo szybko – najbardziej spodobało mi się wyznanie, że twarze białych osób niejednokrotnie są rozpoznawane i podpisywane jako foki albo psy.

Moją uwagę przykuły komentarze czytelników, którzy domagali się „natychmiastowej zmiany algorytmu”. Pomyślałam, że to dobra okazja, żeby napisać kilka słów o uczeniu maszynowym i wyjaśnić, że za tę wpadkę nie odpowiada algorytm w klasycznym znaczeniu tego słowa.

Algorytm to skończony ciąg jasno zdefiniowanych czynności, koniecznych do wykonania pewnego rodzaju zadań. Ludzie stosują algorytmy w swoim codziennym życiu, mniej lub bardziej świadomie (każdy z nas wie mniej więcej, jakie kroki należy wykonać w celu wymiany  zepsutej żarówki). Jeżeli jednak chcemy skłonić do działania komputer, musimy powiedzieć mu wyraźnie i jednoznacznie, jak ma postąpić w określonej sytuacji.

Jedną z metod zapisu algorytmów są schematy blokowe. Poniższy diagram przedstawia schemat blokowy algorytmu sprzątania po swoim psie w miejscu publicznym.

algorytm-pies
Algorytm sprzątania po swoim psie w miejscu publicznym

Przykład pięknego „poważnego” algorytmu znajdziesz w moim poprzednim wpisie.

Algorytmy można badać i porównywać, dzięki czemu powstają ich coraz szybsze i sprawniejsze wersje. Istnieje jednak grupa problemów, które algorytmom nie poddają się najlepiej. Chodzi albo o zadania bardzo skomplikowane, w których rozpisywanie kroków zajęłoby całe lata, albo o takie, które ludzkie mózgi wykonują bardzo szybko, ale ich nosiciele sami nie są w stanie odpowiedzieć na pytanie, jak to się dzieje. Doskonałymi przykładami są tutaj rozpoznawanie twarzy i rozpoznawanie mowy. Sprawa nie jest trywialna. Wiadomo, że istnieją choroby, które odbierają ludziom wymienione przed chwilą umiejętności, nie zaburzając przy tym zdolności logicznego myślenia.

Problemy z opisanej kategorii można rozwiązywać przy użyciu uczenia maszynowego. Jest to dziedzina, która od lat dziewięćdziesiątych nabiera coraz większego znaczenia, w miarę jak wzrasta moc obliczeniowa komputerów i wraz z dostępnością coraz większej ilości danych w Internecie. Dominują dwa nurty: pierwszy oparty na sieciach neuronowych (mających naśladować budowę ludzkiego mózgu), drugi na statystyce i rachunku prawdopodobieństwa.  Poniżej przedstawię prosty (żeby nie użyć mocniejszego słowa) przykład statystycznego uczenia maszynowego.

Jak to działa? Rozważmy popularne zadanie wykrywania spamu. Jeżeli przeanalizujemy tysiąc maili, z których połowa została przez użytkownika oznaczona jako spam, a połowa to normalne, pożądane treści, będziemy w stanie wyciągnąć jakieś wnioski. Możemy, na przykład, utworzyć listę słów, które pojawiły się w wiadomościach i podliczyć, ile razy dane słowo pojawiło się w wiadomości oznaczonej jako spam, a ile razy w wartościowej wiadomości. W ten sposób dla każdego ze słów wyznaczymy prawdopodobieństwo „bycia spamem”. Kiedy pojawi się nowa wiadomość, możemy, w oparciu o listę słów, wyliczyć całkowite prawdopodobieństwo (ryzyko), że dana wiadomość to spam.

Poniżej przykładowy prosty model i związane z nim wyliczenia. Proszę pod żadnym pozorem nie uczyć się z tego statystyki!!!

Wiadomości otrzymane przez użytkownika, zaklasyfikowane przez niego jako wartościowe treści albo spam:

Treść wiadomości Klasyfikacja
Ciociu, jak będzie okazja, kup mi nad morzem wisiorek z bursztynem. Ok.
Okazja! Tylko dzisiaj kup viagrę za 30 zł! Okazja! Spam.

Analiza słów zawartych w wiadomościach:

Słowo Wystąpień „spam” Wystąpień „ok” Prawdopodobieństwo, że to spam
ciociu 0 1 0
kup 1 1 1/2
okazja 2 1 2/3
viagrę 1 0 1
wisiorek 0 1 0

Próba automatycznego oszacowania, czy nowe wiadomości należy wrzucić do folderu „spam”:

Treść nowej wiadomości Prawdopodobieństwo, że spam?
Ciociu, kup wisiorek. (0+1/2+0)/3 = 1/6 = 16.6%
Ciociu, kup viagrę. (0+1/2+1)/3 = 1/2 = 50%
Kup viagrę. (1/2+1)/2 = 3/4 = 75%

Można spotkać się z terminem „algorytm uczenia maszynowego”, ale należy pamiętać, że najczęściej mamy w tej kategorii do czynienia z matematycznymi metodami, które dadzą kompletnie odmienne wyniki w zależności od tego, na jakim zbiorze danych zostaną wytrenowane.

Jakie są efekty? Raczej dobre. Nie da się jednak dogodzić wszystkim, a już na pewno nie na podstawie jednego, wspólnego zbioru danych. Większość z nas chce, aby reklamy środków na powiększenie penisa automatycznie trafiały do katalogu „spam” lub do kosza, ale ktoś przecież takie środki kupuje i wówczas z pewnością chce się dowiedzieć, kiedy dotrze do niego upragniona przesyłka. Poza tym, zbiór danych użyty do trenowania może okazać się za mały, za duży, błędnie opisany lub niewystarczająco reprezentatywny.

Co dokładnie stało się w przypadku Google? Najprawdopodobniej dane wykorzystane do uczenia nie były wystarczająco reprezentatywne – występowali na nich głównie biali ludzie, więc system uwzględnił jasny kolor skóry jako istotny wyznacznik bycia człowiekiem. Warto dodać, że autor (i obiekt) fotografii, które rozpętały całe to zamieszanie, sam jest programistą i od razu zaznaczał, że wie co się stało. Pytał tylko retorycznie „skąd wzięliście te dane?”. Najbardziej wstydliwa możliwość, choć raczej mało prawdopodobna, jest taka, że podczas trenowania użyte zostały zdjęcia opatrzone rasistowskimi komentarzami, które system potraktował jako pewnik.

Problem nie jest łatwy do naprawienia. Być może firma do końca nie wie, skąd pochodziły dane. Być może trenowanie trwa wiele dni. Zgodnie z aktualnymi doniesieniami, etykieta „gorillas” została na wszelki wypadek kompletnie usunięta z systemu.

Wieża Babel. Skąd tyle języków programowania? (część 3 z 3)

Tekst jest oparty na mojej prezentacji z konferencji Kariera IT. Poprzednia część wpisu jest dostępna tutaj.

To ostatnia (po 1 i 2) część mojego krótkiego przewodnika po językach programowania. Zaczynam ją dwoma dość ekstrawaganckimi przykładami, by wreszcie przejść do podsumowań: który język do czego się nadaje i który może uczynić z Ciebie milionera! Na samym końcu znajdziesz quiz 🙂 – a także listę lektur, na wypadek, gdybyś chciał dalej zgłębiać wiedzę na ten temat.

Języki wyspecjalizowane – R

Do tej pory – w poprzednich dwóch wpisach – koncentrowałam się na językach ogólnego przeznaczenia. Dla równowagi chcę pokazać przynajmniej jeden język programowania z innej, bardziej specjalistycznej grupy.

R to język programowania i środowisko przeznaczone do obliczeń statystycznych i wizualizacji wyników. Oferuje zaawansowane wsparcie w dziedzinach takich jak analiza danych i uczenie maszynowe. R jest interpretowanym językiem proceduralnym. Ma pewne ograniczenia wydajnościowe (np. wszystkie dane przetwarzane przez program są w całości ładowane do pamięci podręcznej komputera). Kod R można łączyć z kodem napisanym w innych językach, takich jak C++.

Skoro zadania wykonywane w R można wykonać w C++, do tego kod w innym języku może działać szybciej, po co w ogóle dotykać R? W poprzednim wpisie z tej serii pojawił się punkt „Wydajność języka a wydajność programisty”. W R implementacja zadań związanych ze statystyką i analizą danych jest nieporównywalnie szybsza niż w językach ogólnego przeznaczenia. Programista nie musi pisać wielu linii, a wszystkie tradycyjnie używane w tej dziedzinie algorytmy (np. regresja liniowa) są od ręki dostępne w postaci funkcji.

Poniższy fragment kodu pochodzi z artykułu Producing Simple Graphs with R. Zobacz, jak łatwo można wyświetlić dane i ocenić, czy zachodzi między nimi korelacja.

Co dostaniemy po uruchomieniu programu (np. w środowisku R Studio)? RJeśli nie podoba Ci się myląca etykietac „samochody” przy osi y, na stronie z oryginalnym przykładem dowiesz się, jak go zmienić.

Nie tylko dla dzieci – programowanie graficzne

Istnieją języki programowania, które bardziej niż tekst w obcym języku przypominają… hieroglify. Programowanie polega nie na wpisywaniu poleceń, ale na przeciąganiu i upuszczaniu na planszy bloków symbolizujących poszczególne instrukcje.

Naturalnym odbiorcą tego typu przyjaznych środowisk są dzieci, co jakiś czas jednak powraca temat „rewolucji” w tworzeniu aplikacji przez (pół)profesjonalnych programistów – ostatnio za sprawą projektu Eve.

Przykład tego typu programu pojawił się w opublikowanym przeze mnie w międzyczasie (pomiędzy kolejnymi częściami serii o językach programowania) wpisie Kup swojemu dziecku sobie robota Lego Mindstorms. Znajdziesz tam kompletny opis „najtańszego programowalnego robota”, którego możesz zbudować z klocków Lego.

Poniżej „fragment kodu” dla takiego robota, którego w akcji możesz zobaczyć tutaj:

nxt-codeCo widać na rysunku? Nieskończoną pętlę, w której raz po raz odczytujemy kolor przesyłany przez czujnik światła (bądź koloru). W zależności od tego, czy robot znajduje się na linii (odczyt czarny) czy nie (odczyt biały) albo jedziemy prosto (obrót obu kół o tyle samo stopni), albo skręcamy w prawo.

Wydaje się to banalne, ale w taki sposób można tworzyć zaskakująco złożone programy, o czym przekonałam się kiedyś podczas zawodów programistycznych dla gimnazjalistów.

Który do czego?

Poniższa tabela zawiera wpisy dla tylko kilku spośród najpopularniejszych języków. Zdecydowanie nie wyczerpuje tematu – spójrz, ile pozycji ma lista języków programowania w Wikipedii.

Język Przeznaczenie (najsilniejsze strony) Paradygmat
C System
Operacje niskopoziomowe
Imperatywny
 C++ System Imperatywny
Obiektowy
Funkcyjny
 C# Szybkie tworzenie aplikacji okienkowych
Aplikacje klient-serwer
Aplikacje internetowe
Imperatywny
Obiektowy
Funkcyjny
 Erlang Aplikacje rozproszone
Telekomunikacja
Funkcyjny
 Haskell Aplikacje desktopowe i internetowe Funkcyjny
 Java Aplikacje serwerowe
Aplikacje mobilne (w tym Android)
Imperatywny
Obiektowy
Funkcyjny
JavaScript Aplikacje internetowe w przeglądarce, po stronie klienta Imperatywny
Obiektowy (prototypy!)
Funkcyjny
 Perl Skrypty
Przetwarzanie tekstu i dokumentów
Imperatywny
Obiektowy
Funkcyjny
 PHP  Aplikacje internetowe Imperatywny
Obiektowy
Proceduralny
 Prolog  Sztuczna inteligencja  Logiczny
 Python  Aplikacje internetowe
Skrypty
Imperatywny
Obiektowy
Funkcyjny
 R  Statystyka Imperatywny
Obiektowy
Funkcyjny
Proceduralny

Który da mi pracę?

Jeśli dopiero zaczynasz programować, jeśli myślisz o przekwalifikowaniu się, jeśli nudzi Cię Twoja obecna (może nawet informatyczna) praca, to pewnie zastanawiasz się, który z języków wybrać. O tym, który język najlepiej nadaje się jak pierwszy dla osoby, która nigdy wcześniej nie programowała, pisałam tutaj (tl;dr: Python).

Co z ofertami pracy? Gdybym miała odpowiedzieć bez namysłu, obserwując ruch na rynku pracy i wśród moich znajomych, powiedziałabym, że w Polsce dominują oferty dla programistów Javy (głównie serwerowej, czyli JEE) i, od niedawna, Pythona.

Na wszelki wypadek sprawdźmy też kilka poważnych źródeł.

A. Ranking RedMonk, oparty na popularności poszczególnych języków w repozytorium GitHub oraz na społecznościowej stronie z pomocą techniczną Stack Overflow (uwaga – prawdopodobnie zaniżona popularność języków używanych w firmach z zamkniętą bazą kodu).

Ranking RedMonk, oparty na danych z GitHub i Stack Overflow

1. JavaScript
2. Java
3. PHP
4. Python
5. C#
5. C++
5. Ruby
8. CSS
9. C
10. Objective-C
11. Perl
11. Shell
13. R
14. Scala
15. Haskell

B. Ranking zarobków programistów poszczególnych języków według Business Insider:

  1. Ruby on Rails
  2. Objective C
  3. Python
  4. JAVA
  5. C++
  6. JavaScript
  7. C
  8. R
  9. C#
  10. Visual Basic
  11. SQL
  12. PERL

C. Ranking na rok 2015 ze strony z konkursami programistycznymi CodeEval, oparty w dużej mierze na informacjach od pracodawców:

  1. Python
  2. Java
  3. C++
  4. C#
  5. Ruby
  6. JavaScript
  7. C
  8. PHP
  9. Go
  10. Perl

Bonus: Quiz!

Dla każdego z poniższych czterech fragmentów kodu spróbuj odpowiedzieć na następujące dwa pytania:

  • Jaki to język?
  • Co robi kod?

1. Na rozgrzewkę:

2. Dla spostrzegawczych:

 3. Na logikę:

4. Przypadek beznadziejny:

Poprawne odpowiedzi znajdziesz na dole strony.

PS.

Wróciłam ostatnio do grania na gitarze i doznałam nieoczekiwanego olśnienia informatycznego. C Sharp (zgodnie z zapisem C#) to po angielsku cis, czyli dźwięk o pół tonu wyższy od c 🙂

Polecane lektury

  1. Siedem języków w siedem tygodni. Praktyczny przewodnik nauki języków programowania (polskie wydanie Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming Languages, polecam z całego serca!)
  2. Seven More Languages in Seven Weeks: Languages That Are Shaping the Future (kontynuacja poprzedniej pozycji, niestety na razie niedostępna w języku polskim)
  3. Programming Languages (kurs w portalu Coursera)
  4. Practical Foundations for Programming Languages (dla zaawansowanych)

Odpowiedzi do quizu

  1. Java, wypisze „dzień dobry”.
  2. C, wypisze liczbę Eulera (e), źródło: International Obfuscated C Code Contest.
  3. Prolog, rozwiązuje Sudoku, źródło: Programmable Life.
  4. Brainfuck, wypisze „Hello World”, źródło: Wikipedia.

Wieża Babel. Skąd tyle języków programowania? (część 2 z 3)

Tekst jest oparty na mojej prezentacji z konferencji Kariera IT. Pierwsza część wpisu jest dostępna tutaj.

Świat staje się coraz mniejszy. Wszyscy uczymy się angielskiego, a lokalne dialekty odchodzą w zapomnienie. Dlaczego wciąż upieramy się, by z komputerem rozmawiać na tyle różnych sposobów? Ile języków powinien znać programista? Od którego zacząć?

To druga część wpisu na temat współczesnych języków programowania i różnic pomiędzy nimi (pierwsza jest dostępna tutaj). W tej części mówię o różnicy pomiędzy językami kompilowanymi i interpretowanymi i tłumaczę, czym są maszyny wirtualne. Na końcu pokazuję, że języki programowania – tak samo jak języki, za pomocą których ludzie komunikują się między sobą – żyją i zmieniają się z czasem.

Kompilować czy interpretować?

Kolejny podział języków programowania opiera się na sposobie przetwarzania napisanego w nich kodu. Języki bywają dzielone na:

  • kompilowane, czyli przed uruchomieniem tłumaczone na kod maszynowy właściwy danej architekturze, zapisywany w osobnym pliku, np. C++, Pascal,
  • interpretowane, czyli uruchamiane bezpośrednio w oparciu o kod źródłowy, często wyposażone w interaktywne konsole, np. Perl, Ruby,
  • interpretowane przez maszynę wirtualną, tj. kompilowane do kodu bajtowego, jak Java, C#.

Warto wiedzieć:

Ten sam język, w zależności od środowiska, może być kompilowany lub uruchamiany.

Potrzeba kompilacji jest nie tyle cechą języka, co środowiska, z którego korzystamy, choć w praktyce konkretne języki są z reguły konsekwentnie przetwarzane w ten sam sposób.

Oba podejścia mają swoje zalety. Kod skompilowany do postaci maszynowej będzie działał optymalnie w architekturze, dla której jest przeznaczony. Kompilator bywa sprzymierzeńcem programisty – potrafi wytknąć błędy (czasami dość złożone), zanim jeszcze uruchomisz program. Z kolei w środowisku interpretowanym (w którym de facto kolejne instrukcje są kompilowane „w locie”) możesz pozwolić sobie na więcej improwizacji i beztroskich prób bez konieczności tworzenia kompletnego, zamkniętego programu.

Skompilowana wersja tego samego programu będzie wyglądała inaczej w systemie o innej architekturze. Program interpretowany wygląda tak samo niezależnie od tego, gdzie chcemy go uruchomić (o ile celowo nie odwołujemy się elementów istniejących jedynie w konkretnym systemie operacyjnym) – to środowisko (interpreter) musi być w stanie porozumieć się z procesorem.

Jeśli popełnisz poważny błąd w linii numer 100, kompilator w ogóle nie utworzy wykonywalnej wersji programu. Środowisko interpretowane prawdopodobnie bez szemrania wykona linie 1-99 i elegancko wyłoży się na linii 100. Zdecyduj sam, która opcja jest lepsza?

Kompromis pomiędzy wspomnianymi dwoma podejściami stanowią maszyny wirtualne.

Maszyny wirtualne

Poniższy rysunek przedstawia schemat działania maszyny wirtualnej (ang. Virtual Machine, VM).

VM
Zasada działania maszyny wirtualnej (na przykładzie JVM)

W przypadku języków z maszyną wirtualną (jak Java, C#) kod jest co prawda kompilowany, ale nie do postaci kodu maszynowego, tylko tzw. kodu bajtowego (ang. bytecode), przeznaczonego dla VM. Dzięki temu skompilowany kod zawsze wygląda tak samo i może być wdrażany w różnych systemach. Maszyna wirtualna właściwa danej architekturze (czyli np. działająca w systemie Windows) jest w stanie w locie tłumaczyć kod bajtowy do postaci kodu maszynowego – instrukcji dla procesora.

Warto wspomnieć, że niektóre maszyny wirtualne (np. JVM, czyli Maszyna Wirtualna Javy) są obecnie tak dojrzałe i wydajne, że twórcy nowych języków (jak w tym wypadku Scala, Clojure) decydują się na kompilowanie tych języków do kodu bajtowego, by skorzystać z optymalizacji wprowadzanych przez daną maszynę wirtualną.

Wydajność języka a wydajność programisty

Być może zwróciłeś uwagę na to, że kilka razy w tym wpisie pojawiły się słowa „wydajny” lub „optymalny”. Języki programowania można porównywać i w ten sposób. Ruby (czytaj: kod napisany w Ruby, uruchomiony w odpowiednim środowisku) działa wolniej niż Java, Java jest wolniejsza od C.

Skoro tak, to dlaczego więc wszyscy nie piszemy w C? Nie wolno zapomnieć o tym, że wydajności języka i wydajność programisty to dwie różne rzeczy.

Program powinien działać szybko, to jasne. Programy są jednak pisane i poprawiane przez ludzi. Ogromne znaczenie mają więc także:

  1. czas potrzebny do stworzenia działającego programu,
  2. czas potrzebny do naprawienia błędu przez autora kodu,
  3. czas potrzebny do naprawienia błędu przez innego programistę.

Jeśli chodzi o szybkość tworzenia programu od zera (1) – w ekstremalnej sytuacji prototyp tworzy się w jednym języku, a – jeśli pomysł chwyci – później w tle przepisuje się kod na inny, wydajniejszy język.

W kwestii naprawiania błędów (2), ale też szybkości kodowania, rozważ proszę następujące dwa fragmenty kodu.

C++

Java

Oba przykłady robią to samo: tworzą tablicę przechowującą 10 elementów typu całkowitego. W przypadku C++ musisz ręcznie zwolnić przydzieloną pamięć. Można uznać to za zaletę – masz pełną kontrolę nad pamięcią. Jeśli wiesz, że obiekt nie będzie już potrzebny, możesz się go natychmiast pozbyć. W Javie pamięć zwolni Odśmiecacz (ang. Garbage Collector) po wykryciu, że do zmiennej nie ma już odwołań. Tyle tylko, że zrobi to, kiedy będzie mu wygodnie… Może wcale.

Z ogromną dozą pewności pozwolę sobie napisać to:

Każdemu programiście języka C++ zdarzyło się co najmniej raz zapomnieć operatora delete.

Przykłady kodu są zabawkowe. Gdyby jednak taki kod znajdował się w pętli, gdyby tablica zawierała obiekty zamiast wartości int – mielibyśmy poważny problem.

Co do poprawiania błędów przez innych developerów (3): znana maksyma głosi, że kod jest czytany dużo częściej niż pisany. Warto zadbać o jego przejrzystość i strukturę. To, czy kod jest czytelny czy nie, nie zależy jedynie od wyboru języka, ale także od stosowania konwencji (nazw, formatu kodu) i abstrakcji (jak wzorce projektowe).

Języki programowania ewoluują!

Wiesz już (niekoniecznie ode mnie), że to, czy język się kompiluje czy interpretuje nie jest rdzenną cechą samego języka, ale środowiska, w którym ma działać Twój kod.

Wiesz, co jeszcze może ulegać zmianom? Sama składnia!

Język naturalny, czyli język, którym ludzie porozumiewają się między sobą, ewoluuje. Pojawiają się nowe słowa, stare zyskują nowe znaczenia. Uparcie powtarzane błędy w końcu wchodzą do kanonu (czy zastanawiałeś się kiedyś, dlaczego w wielu językach najczęściej używane czasowniki odmieniają się nieregularnie?)

Nie inaczej jest w przypadku języków programowania. W nowych wydaniach pojawiają się konstrukcje pozwalające w bardziej zwięzły sposób wyrazić te same treści. Dopuszczane są elementy innych paradygmatów (np. popularne ostatnio wyrażenia lambda, związane z programowaniem funkcyjnym).

Dla ilustracji, dwa fragmenty kodu w języku Java:

Obie wersje tworzą mapę (tablicę asocjacyjną), w której kluczami są łańcuchy znaków, a wartościami – listy zawierające łańcuchy znaków. Czyli, na przykład, na podstawie nazwiska mogę pobrać listę numerów telefonu przypisanych do danej osoby.

Druga, nowsza wersja jest wyraźnie krótsza. Dlaczego? Otóż dlatego, że programiści Javy od lat dostawali białej gorączki przez ostrzeżenia kompilatora na temat nieznanego typu podczas tworzenia kolekcji, mimo że typ można było jednoznacznie wywnioskować na podstawie deklaracji zmiennej. Ich skargi wreszcie dotarły gdzie trzeba, i oto efekt.

Dlaczego podałam numery wersji od 5 w górę? Ponieważ w wersji 4 nie można jeszcze było stosować uogólnień (ang. generics) – w efekcie nie mogłabym w ten sposób określić typu danych przechowywanych w kolekcji.

W następnej części

  • Języki wyspecjalizowane – R
  • Nie tylko dla dzieci – programowanie graficzne
  • Który do czego?
  • Który da mi pracę?
  • Quiz!
  • Polecane lektury

PS. Link dla odważnych

CINT, interpreter kodu C i C++.

Wieża Babel. Skąd tyle języków programowania? (część 1 z 3)

Tekst jest oparty na mojej prezentacji z konferencji Kariera IT

Świat staje się coraz mniejszy. Wszyscy uczymy się angielskiego, a lokalne dialekty odchodzą w zapomnienie. Dlaczego wciąż upieramy się, by z komputerem rozmawiać na tyle różnych sposobów? Ile języków powinien znać programista? Od którego zacząć?

Postaram się krótko opowiedzieć o współczesnych językach programowania i różnicach pomiędzy nimi. Dla porządku zacznę od (króciutkiego!) rysu historycznego. Dalej będzie z górki! 🙂

Pierwszy programista (nie róbmy z tego tajemnicy: chodził w spódnicy)

Jako pierwszego na świecie programistę często wymienia się Adę Lovelace. Ada była córką poety, Lorda Byrona. W latach 1842-1843 (!) przetłumaczyła z francuskiego rozprawę poświęconą „maszynie analitycznej” Charlesa Babbage’a. Tłumaczenie opatrzyła notatkami, w których znalazł się pierwszy na świecie opis algorytmu przeznaczonego do wykonania przez maszynę (algorytm wyznaczał kolejne liczby Bernoulliego). Działający egzemplarz takiej maszyny udało się zbudować dopiero w 1991 roku. Dokonało tego Muzeum Nauki w Londynie, przy użyciu materiałów dostępnych w czasach Babbage’a.

Ada Lovelace: portret

Wyrazami uznania dla pracy Ady Lovelace są między innymi język programowania Ada stworzony na początku lat osiemdziesiątych oraz nagroda Ada Award przyznawana „wybitnym dziewczętom i kobietom w sektorach cyfrowych”.

Odrobina kontekstu: kamienie milowe historii programowania

To nie jest wpis o historii programowania, dlatego wypunktuję tylko kilka przełomowych wydarzeń:

  • 1936: Alan Turing opisuje Maszynę Turinga, hipotetyczny „komputer” złożony z głowicy oraz nieskończonej taśmy, który może wykonywać algorytmy i stanowi teoretyczny model obliczeń.
  • 1943-1945: Powstaje ENIAC, powszechnie uważany za pierwszy komputer.
  • 1940-1960: Dominują języki niskopoziomowe. Na ich tle wWyróżnia się FORTRAN, język wyższego poziomu z własnym kompilatorem.
  • 1960-1970: Powstają stosowane do dzisiaj języki i paradygmaty: język C, Smalltalk (obiektowy), Prolog.
  • 1990-…: Internet staje się ogólnodostępny. Dominuje paradygmat obiektowy. Pojawia się sporo języków funkcyjnych i skryptowych.
  • 2010-…: Zwrot w stronę programowania funkcyjnego, metaprogramowanie i mechanizm refleksji, nacisk na wielowątkowość.

Z głową w chmurach: języki niskiego i wysokiego poziomu

Jeśli – chcąc nauczyć się nowego języka programowania – zaczniesz szukać informacji na jego temat w Internecie, prawie na pewno natkniesz się na informację o tym, że „X to język programowania wysokiego poziomu, który …”. Jeden za drugim, którego byś nie sprawdził, wszystkie są wysokopoziomowe. Co to znaczy?

Spójrz na fragmenty kodu w poniższej tabelce.

Kod maszynowy Asembler C

 

 

Każdy z przedstawionych fragmentów kodu (wzięłam je z Wikipedii; wystarczył mi jeden semestr z Asemblerem żeby wiedzieć, że nigdy więcej nie chcę go dotykać) robi to samo: wyznacza n-ty wyraz ciągu Fibonacciego.

Po lewej mamy kod maszynowy – kolejne liczby (zapisane szesnastkowo) to rozkazy procesora i ich argumenty. Kod taki jest nieprzenośny, tj. zależny od architektury. Przykładowy kod jest przeznaczony dla 32-bitowej maszyny x86. Programowanie w tym języku wymaga zapamiętania numerów poszczególnych instrukcji, lub korzystania z rozbudowanej ściągi (słownika). Jest to kod absolutnie niskopoziomowy.

Środkowa kolumna to Asembler (ang. Assembly language). To również język niskopoziomowy. Wygląda inaczej niż kod maszynowy, jednak w rzeczywistości stanowi odwzorowanie „jeden do jeden” instrukcji procesora, tyle że w sposób łatwiejszy do zrozumienia i zapamiętania przez człowieka. W przykładowym kodzie widać odwołania do rejestrów procesora x86 oraz do stosu.

Po prawej stronie język C. Kod różni się od przykładów po lewej stronie brakiem odwołań do architektury maszyny, na której działa. Wartości będą w końcu pobierane ze stosu, ale nigdzie nie oznaczamy, w jaki sposób ma się to odbyć. Funkcja ma zwrócić wartość, ale nigdzie w kodzie nie określamy mechanizmu jej przekazania. Wprowadzamy własne abstrakcje – zmienne lokalne wewnątrz instrukcji warunkowych oraz pętli – i nie przejmujemy się sposobem ich obsługi na docelowej maszynie.

Na podstawie powyższego możesz logicznie wywnioskować, że C jest językiem wysokiego poziomu. Jednak gdy podzielisz się tą opinią z zaprzyjaźnionymi programistami, większość z nich z niedowierzaniem pokręci głową. Dzisiaj C jest uznawany za, w najlepszym razie, język „średniego poziomu”. Wprowadza sporo użytecznych abstrakcji, ale jednocześnie (czego w naszym przykładzie akurat nie widać) pozwala na bezpośrednie odwołania do pamięci – nie do pomyślenia w większości języków wysokopoziomowych.

Możesz jeszcze natknąć się na określenie super high level language, czyli język bardzo wysokiego poziomu. Tym terminem określa się najczęściej języki dziedzinowe, zwiększające produktywność programisty poruszającego się na co dzień po specyficznym, zamkniętym obszarze. Z reguły są tą jednak tylko (?) nakładki na istniejące języki programowania wysokiego poziomu.

Rozkazuję ci… Języki imperatywne i deklaratywne

Kolejny ważny podział wśród języków programowania to rozróżnienie na paradygmat imperatywny i deklaratywny.

  • Program imperatywny zawiera ciąg instrukcji, zmieniających stan programu. Wydajemy komputerowi „rozkazy”: zwiększ wartość x o 5, zwróć wynik. Przykłady języków imperatywnych to Perl, Python, Java oraz wszystkie języki przedstawione w tabelce w poprzednim podrozdziale.
  • Program deklaratywny nie mówi komputerowi, jakie kroki ten ma wykonać. Zamiast tego, programista opisuje warunki, jakie musi spełniać rozwiązanie. Ważne i pożądane cechy języka deklaratywnego to bezstanowość i determinizm. Te same dane wejściowe zawsze prowadzą do uzyskania tego samego wyniku, nie wpływa na nie żaden wewnętrzny „stan”. Przykłady języków deklaratywnych to Haskell, Erlang i Prolog.

Świat imperatywny: klasy i prototypy

Jeśli chodzi o programowanie imperatywne, od dawna już (co najmniej od początku obecnego wieku) dominuje programowanie obiektowe, które wyparło mniej ustrukturyzowane programowanie proceduralne. W ścisłym ujęciu program obiektowy to program, którego wykonanie sprowadza się do przesyłania komunikatów pomiędzy obiektami. Nie wszyscy jednak wiedzą, że programować obiektowo można w dwóch „smakach”: przy użyciu klas lub paradygmatów.

Sytuację dobrze ilustruje ten oto obrazek (mojego autorstwa, wreszcie mogę się popisać!), inspirowany slajdem z prezentacji na temat zaskakujących elementów języka JavaScript:

Prototypy kontra klasy, ujęcie biologiczne i gratka dla fanów mojej kreski (są tacy!).
Prototypy kontra klasy, ujęcie biologiczne, Gratka dla fanów mojej kreski (są tacy!)

W podejściu klasycznym (nazwa jest tym bardziej odpowiednia, że to podejście dominuje – np. Java, C++) opisujemy świat za pomocą klas. W praktyce klasą może być „Okno Przeglądarki” albo „Ramka”, jednak w zastosowaniu edukacyjnym lepszym przykładem będzie nieśmiertelna klasa „Zwierzę”. Klasa Zwierzę ma pewne atrybuty: liczbę nóg lub umiejętność wydawania pewnego dźwięku. Klasa ta może mieć podklasę, na przykład Słoń. Słoń ma wszystkie atrybuty klasy Zwierzę, ale może definiować własne – na przykład trąba i jej długość 😉

W oparciu o klasy tworzymy obiekty, czyli konkretne instancje (egzemplarze) poszczególnych klas. I tak DumboMamaDumbo to dwa różne obiekty tej samej klasy Słoń. Klasy możemy podzielić na konkretne (które mogą mieć instancje) i abstrakcyjne (bardziej ogólne, pełniące tylko rolę szablonów).

Alternatywą jest podejście prototypowe, dostępne na przykład we wspomnianym już tutaj języku JavaScript. Jeśli programujemy z prototypami, całkowicie wyzbywamy się klas. Wszystko jest obiektem. Zwierzę to obiekt. Słoń to obiekt, dla którego obiekt Zwierzę jest prototypem. Dumbo to kolejny obiekt, wzorowany na Słoniu. Koneserzy tej wersji przekonują, że dopiero przy takim podejściu, gdzie wszystko jest obiektem, możemy mówić o programach prawdziwie obiektowych.

Jaka jest praktyczna różnica? Prototypy, jako obiekty, można modyfikować w czasie wykonania. Klasy są usztywnione – jeśli powiemy, że słoń ma cztery nogi, nie będziemy gotowi do obsłużenia egzemplarza z pięcioma. Ma to jednak swoją cenę. Większość języków prototypowych jest typowana dynamicznie. Oznacza to, że typ obiektu jest określany dopiero w czasie wykonania. Dla takich języków o wiele trudniej jest tworzyć dobre IDE (zintegrowane środowisko programistyczne). W przypadku statycznie definiowanych klas, edytor może nam sporo pomóc: np. podpowiedzieć, jakie funkcje da się wywołać na danym obiekcie.

Ograniczenia wprowadzane przez stosowanie klas stają się jednak coraz mniej uciążliwe z powodu rozbudowanych mechanizmów refleksji (zmiany istniejącego kodu w czasie wykonania) w nowoczesnych językach programowania.

Świat deklaratywny: języki funkcyjne i programowanie w logice

Języki funkcyjne przeżywają obecnie prawdziwy boom popularności. Główną przyczyną tego stanu (sic!) rzeczy jest ich bezstanowość i brak skutków ubocznych – cechy te ułatwiają programowanie współbieżne. Jest to istotne, ponieważ w roku 2014 dobiegamy do kresu prawa Moore’a, wieszczące (w uproszczeniu) wykładniczy wzrost szybkości układów scalonych. Zamiast coraz szybszych procesorów mamy teraz procesory z większą liczbą rdzeni i coś z tym fantem trzeba zrobić.

Program napisany w języku funkcyjnym sprowadza się do wartościowania (ewaluacji) funkcji matematycznych. Unikamy przy tym przechowywania i modyfikowania stanu. Do dyspozycji mamy języki czysto funkcyjne, jak Haskell (z dość dużym progiem wejścia, uwielbiane przez snobistycznych doświadczonych developerów), oraz nieco bardziej przystępne (acz kojarzące się z potworem Frankensteina) języki mieszane, jak Scala, które pozwalają na łamanie części zasad, przy jednoczesnej praktycznej dostępności pewnych silnych stron tego paradygmatu (jak wygodne wykonywanie funkcji na wszystkich elementach kolekcji).

Programowanie funkcyjne to duży temat, któremu zamierzam w przyszłości poświęcić osobny wpis.

Inny rodzaj programowania deklaratywnego to programowanie w logice, szczególnie przydatne przy problemach zahaczających o zagadnienia sztucznej inteligencji (rozumienie języka naturalnego, rozwiązywanie łamigłówek). W tym podejściu, zamiast szukać algorytmów,, musimy zdefiniować zależności i ograniczenia (ang. constraints) obowiązujące w danej dziedzinie. Interpreter języka logicznego, takiego jak Prolog, podejmie następnie próbę rozwiązania problemu „za nas” w oparciu np. o rachunek predykatów pierwszego rzędu.

Pierwsze doświadczenia z programowaniem w logice bywają bolesne. O ile w większości języków możemy napisać coś w stylu

X = 1; X = X + 1;

i spodziewać się odpowiedzi 2, o tyle Prolog w podobnych okolicznościach może zaskoczyć nas krótką i konstruktywną odpowiedzią NIE (X nigdy nie będzie równe X+1). Po co w ogóle pchać się w te cudaczne rejony?

Ano chociażby dlatego, że w Prolog pozwala na rozwiązanie bardzo skomplikowanych problemów (kostka Rubika, Sudoku) w zaskakująco niewielkiej liczbie linii kodu.

Poniżej kompletny kod rozwiązujący Sudoku o rozmiarach 9×9, napisany w Prologu. Program pochodzi z bloga Programmable Life, tam też znajdziesz kompletne objaśnienie.

W następnych częściach

PS. Zdjęcie w nagłówku

Zdjęcie przedstawia kartę perforowaną z zapisem kodu w języku Fortran. Kart perforowanych po raz pierwszy użyto w roku 1725 do sterowania pracą krosna.

W 1889 roku Herman Hollerith opatentował nowoczesną postać karty (oraz taśmy) dziurkowanej do zapisu danych. Zainspirował go system stosowany przez konduktorów amerykańskich kolei, którzy za pomocą dziurek kodowali na biletach wygląd pasażera („wysoki, niebieskie oczy”), który się danym biletem posługuje (żeby pasażerowie nie wymieniali się biletami).

Karty perforowane były szeroko stosowane do zapisu danych i programów aż do lat osiemdziesiątych XX wieku. Ich ostateczny upadek miał miejsce w roku 2000, gdy przez resztki papieru pozostałe w otworach kart nie wszystkie głosy zostały policzone poprawnie i w efekcie trzeba je było zliczyć ręcznie.

Czy każdy musi (na)uczyć się programowania?

Tekst jest oparty na mojej prezentacji z konferencji Polyconf

Zastanawiałam się ostatnio nad tym, kim jest dzisiaj programista. Czy umiejętność programowania przydaje się na co dzień, w normalnym życiu? Czy wszyscy powinni ją w jakimś stopniu opanować?

Mam trochę doświadczenia w uczeniu informatyki. Prowadziłam zajęcia z dziećmi, ze studentami i z seniorami. Ci ostatni co prawda nie zostali programistami, ale część z nich nauczyła się wysyłania grających maili ze slajdami w załącznikach (jeśli dostajecie coś takiego od Waszej babci – z całego serca przepraszam).

W pracy miałam okazję zetknąć się z bardzo dobrymi programistami, którzy skończyli zupełnie nietechniczne studia.

A jednak kroplą, która przepełniła czarę i skłoniła mnie do przygotowania tekstu, było coś zupełnie innego…

Popsuty komputer

Parę tygodni temu popsuł się mój komputer. Pracowałam w domu, nad głową miałam termin. Wyszłam do kuchni po kawę, a po powrocie zastałam w pokoju martwą ciszę – brakowało bzyczenia wentylatora. Komputer nie reagował na nerwowe wciskanie wszystkich po kolei guzików. Sprawdziłam korki, listwę zasilającą i psa (ruszał się, czyli nie przegryzł żadnego kabla), po czym skierowałam podejrzenia na zasilacz. Rozważałam wycieczkę do sklepu po nowy, ale co, jeśli przyczyna jednak tkwi gdzie indziej? Skonsultowałam się z mężem – również programistą („na 90% to zasilacz”). Nie podjęłam ryzyka zmarnowania kilku godzin i zadzwoniłam po profesjonalną pomoc.

Pomoc przybyła po godzinie, w osobie, jak się okazało, studenta Uniwersytetu Przyrodniczego (nie dajcie się zwieść – do niedawna była to Akademia Rolnicza!). Kiedy zawstydzona wyznałam swoją profesję, chłopak podniósł spojrzenie znad sterty śrubek i powiedział: „to mnie nie dziwi, co chwilę naprawiam komputery programistów”.

I to natchnęło mnie do rozważań.

A winowajcą faktycznie był zasilacz.

„Za dziesięć lat programiści nie będą już potrzebni”

Na początek przypomniałam sobie przepowiednie wykładowców z czasów, kiedy byłam studentką. Wtedy nie zdawałam sobie z tego sprawy, ale zaczęłam studia chwilę po tym, jak pękła słynna „bańka internetowa” (dot-com bubble). Nastroje nie były tak dobre, jak teraz, firmy nie wpraszały się na uczelnię, by rekrutować świeży narybek, a część profesorów głosiła nasz rychły koniec. Twierdzili, że narzędzia do wytwarzania programów stają się tak proste w obsłudze i tak dużo robią za nas, że za parę lat programować będzie mógł każdy. Miało to położyć kres zawodowi programisty.

Jakie narzędzia mieli na myśli? Nic innego niż narzędzia typu RAD (Rapid Application Development, czyli „szybkie tworzenie aplikacji”), w których pracę zaczyna się od rozmieszczenia przycisków na formatce. W dalszej kolejności programujemy ich obsługę.

Borland C++ Builder, przykład środowiska typu RAD

Kilkanaście lat później ciągle wiążemy koniec z końcem. Sytuacja na rynku pracy dawno nie była tak korzystna dla programistów. Do tego stopnia, że firmy są gotowe zatrudniać nawet osoby bez studiów, gotowe się przekwalifikować. Pracy jest dużo: w korporacjach, rodzinnych biznesach, start-upach, R&D. Nie brakuje możliwości pracy zdalnej.

Wiedza techniczna nigdy nie była tak łatwo dostępna

Większy popyt na rynku pracy zbiegł się w czasie z udostępnieniem szerszej publiczności zasobów wiedzy, o jakich jeszcze parę lat temu można było jedynie pomarzyć.

Po pierwsze, pojawiły się (i szybko zyskały ogromną popularność) kursy typu MOOC (massive open online courses, czyli masowe otwarte kursy online) . Najpopularniejsze to CourseraedX. Dają możliwość uczestniczenia w zajęciach prowadzonych przez najlepsze światowe uniwersytety i najsłynniejszych profesorów (często autorów znanych podręczników). Kursy najczęściej składają się z zestawu wykładów oraz pytań do nich. W kursach informatycznych często dochodzą jeszcze zadania programistyczne, sprawdzane automatycznie lub na zasadzie peer-review (każdy uczestnik musi ocenić zadania domowe kilku innych osób, żeby otrzymać komplet punktów za dany tydzień).

Po drugie, istnieje kilka ciekawych produktów kierowanych przede wszystkim do dzieci. Jednym z nich są roboty Lego Mindstorms. Napisałam artykuł na ich temat na poprzednim blogu, zamierzam zaktualizować go i wrzucić także tutaj. Mindstorms to zestaw klocków Lego zawierający prosty komputer („kostkę”), kilka silniczków, czujniki (odległości, dźwięku, dotyku, koloru) oraz typowe klocki z serii Lego Technic. Robota można programować na kilka sposobów – za pomocą prostych obrazków wyświetlanych na samej kostce („do przodu”, „wydaj dźwięk”, „powtórz”), w rozbudowanym środowisku graficznym na komputerze (czynności i odczyty robota układamy na dużej planszy, możemy dodawać warunki logiczne oraz pętle) lub w tradycyjnym języku programowania (natywny język zbliżony do C lub, po wymianie oprogramowania, Java). Inny przykład z tej kategorii to KANO – projekt sfinansowany ze środków zgromadzonych przez platformę Kickstarter. Pierwsza partia komputerków opartych na Raspberry Pi oraz Linuksie Ubuntu została już dostarczona do inwestorów. Dzieci najpierw budują komputer z dostarczonych (dużych) elementów. a następnie krok po kroku, przez zabawę, uczą się modyfikować i tworzyć programy.

Warto wspomnieć także o inicjatywach społecznościowych. W większych miastach działają liczne grupy takie jak PyLadies, zachęcające do nauki programowania i prowadzące warsztaty. Często, ale nie zawsze, kierują swoją ofertę do osób reprezentujących mniejszości w świecie IT.

Naprawdę mam się tego uczyć?

Czy każdy powinien nauczyć się programować? Opinie na ten temat są podzielone. Zdaniem twórcy Linuksa, Linusa Torvaldsa:

Nie uważam, że każdy koniecznie powinien podjąć naukę programowania. To dość wyspecjalizowana umiejętność, której nie oczekuje się od większości osób. To nie to samo, co umiejętność czytania i pisania czy wykonywanie prostych rachunków.

Dla kontrastu, oto opinia Marka Guzdiala, profesora na Georgia Tech:

Jesli ktoś planuje karierę pracownika umysłowego, lub zamierza podjąć pracę wymagającą stopnia licenjata, to powinien być w stanie czytać przydatne mu fragmenty kodu i wprowadzać w nich zmiany.

Zdecydowanie bliżej mi do drugiej opinii. Uważam, że każdy powinien nauczyć się programowania – ale w różnym stopniu! Programowanie wymaga określonego zestawu umiejętności, które przy okazji wzmacnia:

  • myślenie logiczne,
  • algorytmika i strukturyzacja,
  • planowanie.

Jest to zestaw bardzo przydatny w „normalnym” życiu. Przygotowując ten tekst przepytywałam znajomych, którzy zajęli się programowaniem na późniejszym etapie życia. Jeden z nich powiedział mi, że frustruje go obserwacja znajomych ze studiów, którzy do ważnych życiowych problemów i decyzji podchodzą w sposób chaotyczny (tzw. algorytm gołębia – jeden krok do przodu, dwa w bok, trzy do tyłu). Jako przykład podał szukanie pracy. Można potraktować to jako problem algorytmiczny: zebranie danych, przygotowanie CV, rozesłanie CV, przygotowanie do rozmowy, wybór najlepszej oferty… A można na oślep wysyłać coraz to inne CV, gdy akurat między prysznicem a zakupami przypomni nam się, że nie mamy pracy.

Dodatkowym plusem nauki programowania jest to, że osoby, które rozumieją, jak działa program komputerowy, automatycznie stają się mniej podatne na różne brzydkie internetowe sztuczki. Być może staranniej zastanowią się, zanim klikną w link w mailu i wprowadzą dane logowania na stronie tylko pozornie należącej do zaufanego banku.

Jestem głęboko przekonana, że pierwsze lekcje programowania należy przeprowadzać jeszcze w szkole podstawowej.

Nauka programowania to nauka myślenia. Oczywiście, w pierwszej fazie powinna odbywać się przez zabawę, jak modyfikowanie kolorów w prostej, zabawnej grze komputerowej. Wczesne wprowadzenie takich zajęć pozwoli dodatkowo na wczesnym etapie wykryć utalentowane osoby, które w innym wypadku mogłyby nigdy nie mieć okazji przekonania się o swoich predyspozycjach do tej dziedziny. Myślę tu głównie o dziewczynkach, często zniechęcanych komentarzami nauczycieli i rodziców do zainteresowania przedmiotami ścisłymi. Być może podczas pierwszych lekcji programowania warto byłoby powstrzymać się od ocen, lub oceniać głównie zaangażowanie (nie próbuje – próbuje – wybitny).

Przy okazji, ostatnio ktoś podesłał mi bardzo ciekawe wystąpienie Stephena Wolframa, który przekonuje, że na wczesnym etapie należy połączyć nauczanie matematyki i informatyki – na czym zyskają obie dziedziny.

Kiedy jest za późno?

Czy na naukę programowania może być za późno? Posłużę się kolejnym cytatem. Jens Skou jest laureatem Nagrody Nobla z chemii. Urodził się w roku 1918, a w roku 1997 powiedział:

W roku 1988 przeszedłem na emeryturę (…) i zacząłem badać za pomocą komputera modele kinetyczne pompy sodowo-potasowej. W tym celu musiałem nauczyć się programować. To ciekawe i wprost niewiarygodne, co można uzyskać przy pomocy komputera, jeśli chodzi o przetwarzanie nawet bardzo złożonych modeli. 

Łatwo policzyć, że w chwili rozpoczęcia nauki programowania profesor miał 70 lat!

Moim zdaniem, nigdy nie jest za późno na naukę programowania. Jeśli jednak myślisz o przekwalifikowaniu się na zawodowego programistę, najpierw odpowiedz sobie na kilka pytań:

  • Czy próbowałeś już programować? Czy sprawiło Ci to przyjemność?
  • Czy jesteś gotów dokształcać się w swoim wolnym czasie?
  • W pracy możesz spotkać osoby znacznie od Ciebie młodsze. Czy jesteś gotów:
    • Pracować z nimi w zespole?
    • Uczyć się od nich?
    • Przyjmować od nich polecenia?
  • Czym się ostatnio zajmowałeś? Jak wygimnastykowany jest Twój mózg? Jak u Ciebie z koncentracją?
  • Czy jesteś w stanie przeżyć parę lat z wynagrodzeniem młodszego programisty?
  • (nieobowiązkowe) Czy znalazłeś sobie mentora?

Od polonisty do programisty – jak i czego uczyć?

Istnieją dziesiątki języków programowania. Niektóre są bardzo ogólne, inne wykorzystuje się tylko w ściśle określonych sytuacjach. Jedne da się zastąpić innymi, inne są obowiązkowe, jeśli chcemy rozwiązać problem z danej dziedziny. Od którego zacząć?

Postuluję, żeby pierwszy język programowania spełniał następujące warunki:

  1. Oferował natychmiastową informację zwrotną. A więc powinien to być język interpretowany, a nie kompilowany. Najlepiej wyposażony w interaktywną konsolę, w której można przetestować proste operacje (np. mnożenie liczb) zanim jeszcze uczeń zda sobie sprawę z tego, że to, co robi, to już programowanie.
  2. Był obiektowy. Programowanie proceduralne jest dobre na sam początek, ale nie wymusza przemyślanej struktury i dobrych praktyk. Programowanie funkcyjne przeżywa dzisiaj renesans, ale może tylko odstraszyć większość początkujących. Kilka osób próbowało mnie przekonać, że wybieram programowanie obiektowe jedynie dlatego, że sama byłam tak uczona (co zresztą nie jest nawet zgodne z prawdą). Jedna z tych osób powiedziała mi „Ja też sądziłem, że programowanie funkcyjne to jakiś koszmar, ale po sześciu miesiącach nauki wiem bez wątpienia, że to najlepszy wybór”. Hm, początkujący programista raczej nie da nam takiego kredytu zaufania. Widziałam również kurs programowania dla początkujących oparty o programowanie sterowane zdarzeniami (zgodnie ze słuszną poniekąd ideą, że dobrze jest szybko pokazywać wyniki nauki, kurs opierał się na programowaniu gier). Zapewniam, że uczestnicy kursu nie mieli bladego pojęcia, kto, skąd i dlaczego do nich strzelają. Programowanie obiektowe ma tę ogromną zaletę, że łatwo przełożyć je na język otaczającego nas świata. Zwierzę to klasa. Pies to podklasa zwierzęcia. Pralka w Twoim domu to obiekt, który ma atrybuty i funkcje. To naprawdę działa.
  3. Pozwalał na programowanie bardzo różnych rzeczy. Kiedy uczysz kogoś programowania, nie masz pewności, czy nie poprzestanie na pierwszym języku, jaki pozna. Dlatego warto pokazać mu język, który daje duże możliwości. Dobrze, żeby pozwalał na tworzenie następujących typów aplikacji:
    • praca w konsoli i operacje na plikach,
    • proste okienka,
    • aplikacje internetowe.

Przykładem języka, który spełnia wymienione tu kryteria, jest Python. Uważam, że to cudowny pierwszy język.

Bonus: czego się spodziewać w pracy z neoprogramistami? Przecież oni imprezowali, kiedy ja liczyłam całki!

Na swojej drodze zawodowej spotkałam kilka osób, które zostały programistami, mimo że skończyły studia humanistyczne. W tej części chciałabym podzielić się z Wami obserwacjami na temat mocnych i słabszych stron takich inżynierów.

Plusy

  • Ogromny entuzjazm! Sama po pracy w miarę możliwości staram się trzymać z daleka od informatyki. Dla osób z tej grupy informatyka to cudowne nowe hobby, które chcą uprawiać i którym chcą się dzielić.
  • Znajomość najnowszych frameworków. Zapytana, deklaruję, że znam C++. Prawda jest jednak taka, że ostatni raz napisałam coś większego w tym języku jeszcze na studiach. Tymczasem jeśli ktoś przychodzi „na świeżo” i nauczył się języka z pasji, to z dużym prawdopodobieństwem będzie miał aktualną wiedzę na temat tego, co dzieje się w języku, jakie panują mody i w którym kierunku dany język zmierza.
  • Wiedza dziedzinowa. Większość programistów nie działa w oderwaniu od rzeczywistego świata. Piszemy aplikacje dla kogoś. Jeśli klientem są księgowi, musimy albo zatrudnić eksperta dziedzinowego, albo ktoś z nas musi nauczyć się podstaw księgowości. Zatrudniając neo-informatyka, w pakiecie dostajemy jego wiedzę z dziedziny, z której wyrósł. To bardzo cenne.
  • Gotowość do wykonywania zadań, którymi starzy wyjadacze gardzą. Trochę powtarzalne, mało rozwojowe? Bezpieczne? Jak najbardziej.

Minusy

  • Brak dobrych praktyk, zwłaszcza w dziedzinie testowania. Oznaczanie jako „zrobionych” zadań, które nie zostały poddane  podstawowym testom. W których nie sprawdzono przewidywalnych warunków brzegowych. Które, co prawda, zapaliły wszystkie lampki w ciągłej integracji na czerwono, ale programista spieszył się do domu, więc nie poczekał na wyniki. Tego obszaru trzeba po prostu starannie dopilnować.
  • Luki w wiedzy matematycznej. To nie koniec świata – większość programowania i tak opiera się na stosowaniu rozwiązań wymyślonych przez kogoś innego (Zajmujesz się uczeniem maszynowym? Rozumiesz dogłębnie zasadę działania SVM?). Największe niebezpieczeństwa czyhają w obszarze złożoności obliczeniowej – tę wiedzę koniecznie należy uzupełnić.

Krótkie podsumowanie

Jeszcze nigdy w (niedługiej, przyznaję) historii zostanie programistą nie było tak proste jak dzisiaj. Mamy dostęp do nieograniczonych zasobów wiedzy technicznej: kursy online, ciekawe produkty uczące przez zabawę, wsparcie lokalnych społeczności. Rynek obfituje w oferty pracy dla programistów.

Początkujący programiści i osoby pochodzące z innych dziedzin nie powinny mieć wielkich kompleksów. Dzisiejsze czasy wymagają specjalizacji. Większość programistów i tak zna na wylot tylko najbliższe sobie działki – tę opinię chciałam przekazać moją przydługą opowieścią o popsutym komputerze.

Czy tak dobra sytuacja się utrzyma? Nie wiadomo…

Patrząc na indeks NASDAQ, nie sposób nie zauważyć, że znajdujemy się w obszarze niebezpiecznie zbliżonym do bańki internetowej z 2000 roku. Globalizacja i centralizacja usług sprawiają, że osoba z dobrym pomysłem może w krótkim czasie zarobić miliony. Z drugiej strony, raz rozwiązany problem jest rozwiązany na dobre, co może pozbawić pracy mnóstwo mniejszych, lokalnych firm.

Pełna historia indeksu NASDAQ

Mimo wszystko, Internet i informatyka odgrywają coraz większą rolę w naszych życiach, więc należy się spodziewać, że ten sektor będzie zatrudniał więcej i więcej osób. Na pewno warto dodać programowanie do programu nauczania szkoły podstawowej – gdzieś obok matematyki i techniki.

Gdybym miała wskazać pierwszy język programowania dla dorosłej osoby, która chce sprawdzić swoje siły w tej dziedzinie, wybrałabym język Python: interaktywny, obiektowy, uniwersalny. Łatwo wyszukać w Internecie kursy dla początkujących – na przykład ten, oferowany przez Uniwersytet Michigan.