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

Doktorat z informatyki – warto?

Rozmawiałam ostatnio z kolegą, który zakończył edukację na etapie licencjatu. Uznał, że pozostałych przydatnych rzeczy szybciej i lepiej nauczy się w pracy. Taka decyzja wydaje mi się egzotyczna, pewnie dlatego, że za moich czasów studia trwały całe pięć lat.  (Chyba że ktoś bardzo się starał i do każdego semestru analizy matematycznej podchodził po dwa razy). Kolega i ja pracujemy w tej samej firmie. Dla niego równie zaskakujący był mój dyplom doktorski.

Kilka lat od opuszczenia progów Alma Mater, dzielę się swoimi przemyśleniami na temat tego, kiedy warto zdecydować się na ten krok.

TAK, doktorat to dobry pomysł, jeśli:

1. rozważasz pracę na uczelni
Doktorat jest warunkiem koniecznym do pracy naukowo-dydaktycznej na dobrej uczelni, więc jeśli czujesz, że to właśnie jest Twoim życiowym powołaniem… Nie ma nad czym się zastanawiać. Pamiętaj tylko, że pracownik polskiej uczelni (na świecie niekoniecznie tak jest) jest zobowiązany habilitować się w ciągu 8 lat od rozpoczęcia pracy – nie da się osiąść na laurach.

2. rozważasz pracę w R&D
R&D, czyli Research and Development (prace badawczo-rozwojowe), to trochę nadużywany termin określający pracę i zagadnienia na styku nauki i nowych technologii. Jeśli nie interesuje Cię stworzenie kolejnego sklepu internetowego albo aplikacji dla banku, możesz spróbować zatrudnić się w centrum R&D – państwowym (jak poznański PCSS) albo należącym do wielkiej korporacji. Tu doktorat się przydaje. Wiele projektów wymaga publikowania, występowania na konferencjach, poprawnego mierzenia i opisywania wyników oraz ogólnej naukowej wiarygodności.

3. znajdziesz super ciekawy zespół
Większość spraw w życiu sprowadza się do znalezienia odpowiednich ludzi. Jeśli możesz dołączyć do istniejącego, sprawnie działającego, zmieniającego status quo zespołu zajmującego się interesującą Cię dziedziną – nie ma się co wahać.

4. nie chcesz czuć presji wyników finansowych
Doktorat to nie wakacje. Od terminów nie uciekniesz: sprawdzanie prac, terminy wysłania artykułów, oceny roczne, warunki grantów. Mimo wszystko masz o wiele większą dowolność niż w jakiejkolwiek firmie. Możesz eksperymentować bez obawy o to, że wprowadzone przez Ciebie rozwiązanie wystraszy klientów i doprowadzi firmę do ruiny. W najgorszym razie napiszesz artykuł o tym, co poszło nie tak… 😉

5. chcesz przyczynić się do rozwoju nauki
Doktorat nie jest do tego konieczny, ale jeśli dobrze wybierzesz, poznasz warsztat niezbędny do „uprawiania nauki”.

NIE, nie rób tego, jeśli:

1. chcesz się rozwinąć i możliwie dużo nauczyć
Do tego nie trzeba uczelni. Zwłaszcza w informatyce, w odpowiednich warunkach, znacznie więcej zyskasz na pracy w ciekawej, nowoczesnej firmie, niż w kazamatach uczelni.

2. nie lubisz prowadzić zajęć (albo w ogóle nie lubisz ludzi)
Prowadzenie zajęć jest obowiązkowe dla pracowników naukowych na uniwersytetach. Istnieje pewna furtka – niektóre instytuty (np. należące do Polskiej Akademii Nauk, jak IPI PAN) umożliwiają pracę naukową bez dydaktyki. Na uczelni jednak nie ma ucieczki. O ile mi wiadomo, co jakiś czas wraca dyskusja o rozdzieleniu pracowników na naukowych i dydaktycznych. Ci pierwsi mieliby niedużo zajęć, ci drudzy nie musieliby przejmować się habilitacją. Póki co jednak nic się w tym temacie nie dzieje.

3. chcesz tylko przedłużyć studiowanie
Od doktoratu zabawniejszy będzie drugi kierunek.

4. zależy Ci na statusie
Doktorant na większości polskich uczelni plasuje się w połowie drogi pomiędzy pracownikiem a studentem. Pracownikiem jest wtedy, kiedy trzeba przypilnować rekrutacji albo na ostatnią chwilę napisać artykuł. Studentem, kiedy mowa o zarobkach albo przydziale miejsc w gabinetach.

5. Chcesz spełnić czyjeś marzenia
To zawsze bardzo zły pomysł.

Na co zwrócić uwagę, jeśli decydujesz się studia doktoranckie?

1. Starannie wybierz promotora
Na podstawie przygód własnych oraz moich przyjaciół wiem, że całokształt wrażeń, samopoczucia i wyników osiągniętych podczas studiów w Polsce jest w przeważającej mierze definiowany przez promotora. Ten może być wspierający, inspirujący i opiekuńczy, może też być egoistycznym tyranem rzucającym ochłapy i żerującym na wynikach podwładnych. Na większości uczelni nikt tego nie kontroluje! Jak sobie pościelisz, tak się wyśpisz.

Co zrobić, żeby nie wpakować się w tarapaty? Przejdź się na prowadzony przez potencjalnego promotora wykład. Podpytaj obecnych doktorantów o to, jak im się pracuje. Sprawdź, ilu spośród doktorantów danego profesora uzyskało tytuł i ile im to zajęło czasu.

2. Dowiedz się, jakie są możliwości wyjazdów i współpracy z innymi ośrodkami
Moim zdaniem każdy student i doktorant powinien spędzić przynajmniej semestr na innej uczelni, najlepiej za granicą, chociażby dla porównania.

3. Dowiedz się, co finansuje uczelnia
W informatyce częściej niż w innych dziedzinach artykuły publikuje się tomach pokonferencyjnych, a nie w czasopismach. Wyjazd na konferencję kosztuje: wpisowe, bilety, nocleg. Dowiedz się jakie są zasady pozyskiwania takich środków na Twojej uczelni.

4. Jeśli masz własny światopogląd, zastanów się nad tym, czy jest kompatybilny ze światopoglądem uczelni
Żebyś nie wstydził się przez zapraszanych gości albo nie zżymał przy religijnych uroczystościach.

5. Fail fast
W przypadku doktoratu warto zastosować zasadę znaną z inżynierii oprogramowania i środowiska start-upów. Jeśli coś się nie zgadza, nie działa – reaguj szybko i w razie czego równie szybko uciekaj. Nie daj się nabrać na regułę utopionych kosztów, która każe kontynuować przedsięwzięcie skazane na niepowodzenie. Studia doktoranckie to kolejne kilka lat Twojego życia – zastanów się, czy wykorzystujesz je najlepiej, jak się da. Wytrwałość nie zawsze jest cnotą.

Parę osobistych słów od autorki

Jak było u mnie? Jakie błędy popełniłam? Co zrobiłabym inaczej?

Po pierwsze,sprawdziłam, czym zajmuje się mój potencjalny promotor, ale nie jaki ma styl pracy. Ostatecznie, przez niedopasowanie na tym polu, przysporzyliśmy sobie nawzajem niemało nerwów. Po drugie, kiedy zorientowałam się, że nie najlepiej funkcjonuję w tym środowisku, było mi żal poświęconego roku… więc włożyłam w to jeszcze trzy!!!

Ostatecznie nie wyszło źle. W mojej drugiej po uczelni pracy zajmowałam się dokładnie tym samym, czym w rozprawie doktorskiej (agentami dialogowymi), w związku z czym już na starcie otrzymałam dość wysokie stanowisko i przyzwoitą pensję. Praca dydaktyczna do dzisiaj sprawie mi ogromną przyjemność (w umiarkowanej ilości). W pewnym momencie rozważałam nawet powrót na uczelnię… Ale to już zupełnie inna historia 🙂

Wyrażenia regularne w Javie – figle i psikusy

To trzeci (i na jakiś czas ostatni) z serii wpisów na temat wyrażeń regularnych w Javie, po O wyrażeniach regularnych. Podstępna różnica pomiędzy find i matches oraz Wyrażenia regularne dla nieprogramistów. Historycznie ten jest najwcześniejszy – to zaktualizowana wersja tekstu z mojego poprzedniego bloga.

Poruszam tu bardzo podstawowe kwestie, które potrafią jednak dać się we znaki. Rozwiązanie tych paru niewinnych problemików kosztowało mnie niemało czasu i nerwów. Liczę, że kiedy jakaś zbłąkana dusza znajdzie się w tej samej sytuacji, Google zaprowadzi ją prosto w moje troskliwe ramiona.

Artykuł powstał podczas mojej pracy nad narzędziem do przekształcania metadanych.

Psikus 1: znaki ucieczki w wyrażeniach wczytywanych z zewnętrznego pliku

Załóżmy, że wyrażenie (które chcemy wczytać z zewnętrznego pliku) w zwykłym kodzie Javy wygląda tak:

Linia przedstawia zakres wieków, do którego dopasuje się na przykład linia:

Proste, prawda?

Prawda – ale do czasu. Problemy pojawiły się, kiedy zaczęłam wczytywać wyrażenia regularne zapisane w zewnętrznym pliku. Wczytywałam między innymi następujący fragment:

Wszystko przestało działać. Łańcuchy znaków, które bez najmniejszych wątpliwości powinny były dopasować się do wyrażenia, przechodziły niezauważone. Po godzinie analiz niebezpiecznie zbliżałam się do stanu, w którym myślałam, że oszalał albo świat dokoła mnie. Wtedy na szczęście nadeszła pora lunchu. Opowiedziałam o problemie nad talerzem naleśników, a jeden z kolegów zadał oczywiste w sumie pytanie – czy na pewno dobrze wyeskejpowałam (przepraszam!!!) wszystkie znaki specjalne. I wtedy wreszcie nadeszło olśnienie: nie, nie zrobiłam tego dobrze. Przeeskejpowałam je.

Znaki specjalne, takie jak d, w wyrażeniu regularnym oznaczające cyfrę, należy poprzedzić tzw. symbolem ucieczki, czyli w tym wypadku backslashem (ukośnikiem wstecznym). W łańcuchach znaków w kodzie Javy konieczne jest wprowadzenie dodatkowego backslasha, gdyż musimy jeszcze odebrać specjalne znaczenie samemu backslashowi (musimy poprzedzić znak ucieczki znakiem ucieczki…). Tyle razy widziałam te dwa ukośniki w parze, że zupełnie zapomniałam o tym, że w zewnętrznym pliku należy użyć tylko jednego!

Psikus 2: flagi

To bardzo proste. Załóżmy, że wyrażenie nie ma brać pod uwagę wielkość liter. Normalnie oznaczamy to tak:

Świetnie, tylko jak przekazać tę flagę, jeśli wyrażenie jest wczytywane z zewnątrz? Wychodzi na to, że flagę, poprzedzoną znakiem zapytania, należy umieścić w nawiasie na początku wyrażenia. Ignorowanie wielkości liter (przy okazji, poznałam ostatnio nowe słowo – kasztowość) to literka i, zatem dodajemy (?i). Ostatecznie, w kodzie wyrażenie wygląda tak:

a poza kodem, z pojedynczymi ukośnikami, tak:

Psikus 3: String.replaceAll

W pewnym brzegowym przypadku mój kod, w wyniku wczytania wyrażeń regularnych z pliku, wykonywał operację, którą można w uproszczeniu zapisać tak:

Po wykonaniu się tego kodu spodziewałam się, że treść zostanie całkowicie zastąpiona, czyli wartością s będzie:

skoro * jest zachłannym kwantyfikatorem, to .* powinno dopasować się do całego napisu niezależnie od okoliczności.

Wyobraźcie sobie moje zaskoczenie (czy raczej przerażenie), gdy okazało się, że s przyjęło wartość:

Próbowałam użyć jeszcze bardziej zaborczego kwantyfikatora *+, ale efekt był ten sam. Byłabym mniej zaskoczona, gdyby .* zostało dopasowane do każdej litery w łańcuchu. Jakim cudem dopasowało się dokładnie dwa razy?

Dalsze śledztwo wykazało, że przebieg akcji jest następujący:

  1. Cały łańcuch dopasowuje się do .* i jest zamieniany na łańcuch „nowa treść”.
  2. Po dopasowaniu z oryginalnego łańcucha znaków nie zostaje nic, a raczej zostaje łańcuch "". Metoda replaceAll jeszcze raz sprawdza możliwość dopasowania i okazuje się, że "" także pasuje do .*, zatem pusty łańcuch również zostaje wymieniony.
  3. Zasadniczo można by kontynuować i w nieskończoność dodawać na końcu "nowa zawartość", jednak na szczęście (?) dana pozycja w łańcuchu znaków jest traktowana jako sprawdzona i wykonanie metody kończy się.

Pozdrawiam siostry i braci w cierpieniu.

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?

O wyrażeniach regularnych. Podstępna różnica pomiędzy find i matches

Wyrażenia regularne to jedno z zagadnień dzielących programistów. Są tacy, którzy je uwielbiają i ci, którzy szczerze ich nienawidzą.

Sama zaliczam się do pierwszej grupy, być może z powodu upodobań lingwistycznych (wyrażenia regularne ≈  języki regularne ≈ automaty skończone). Wyrażenia regularne pozwalają na bardzo zwięzły i precyzyjny zapis warunków wyszukiwania, które – gdyby ograniczyć się do tradycyjnych konstrukcji zawartych w danym języku programowania – mogłyby zająć wiele linii. Po stronie minusów należy zapisać trudność zrozumienia dłuższych wyrażeń regularnych, zwłaszcza, jeśli są dziełem kogoś innego.

W tym wpisie chcę podzielić się swoją niedawną przygodą optymalizacyjną. W najbliższym czasie (czyli przed końcem roku) wrzucę jeszcze stary tekst o pułapkach, w które można wpaść pisząc wyrażenia regularne w Javie oraz nowy o tym, jak regeksy mogą przydać się nieprogramistom w ich codziennych zadaniach.

Do rzeczy.

Napisałam ostatnio kod analizujący treść stron internetowych. Mniejsza z tym, po co to robił. Stanowił część większej całości (moduł mavenowy) i podobnie jak reszta kodu korzystał m.in. z Javy 8 i biblioteki JSoup. Napisałam masę testów jednostkowych, testowałam na kilkuset stronach… Jednak prawdziwa próba ognia miała nadejść kilka dni po oddaniu przeze mnie projektu, podczas uruchomienia pełnego łańcucha przetwarzania na kilkudziesięciu (kilkuset?) tysiącach stron.

W pięciu przypadkach mój kod zawiesił się na ponad dobę.

Naprawa, kiedy już do niej zasiadłam zajęła mi niecałą godzinę. Co się okazało? W kilku miejscach w moim kodzie użyłam metody Element::getElementsByAttributeValueMatching i dałam się zwieść nazwie. Na swoją obronę mam to, że Javadoc też wprowadza w błąd. Otóż wyobraziłam sobie, że gdzieś w głębinach metoda wywołuje metodę Matcher::matches, dlatego szukany przeze mnie fragment otoczyłam znakami ".*" przed i po właściwym wzorcu.

Skoro już wszystko się zapętliło, zajrzałam do środka, a tam:

Podstawowa różnica pomiędzy wspomnianą już Matcher::matches a Matcher::find jest taka, że matches szuka pełnych dopasowań (cały łańcuch znaków musi pasować do wzorca), a find zadowoli się dopasowaniem w środku łańcucha znaków (i może takich dopasowań zwrócić wiele).

Czyli jeśli nasz wzorzec ma postać "[abc]e", to find dopasuje go do łańcucha "cel", w przeciwieństwie do metody matches:

Jeśli dodam na początku i na końcu wzorca uniwersalne symbole ".*" (uzyskując ".*[abc]e.*") to również metoda matches uzna, że mamy dopasowanie:

Jednak jednak użyjemy metody find przy odpowiednio złożonym i zagnieżdzonym wyrażeniu regularnym z opcjonalnymi elementami i przy odpowiednio długim tekście, pojawi się tyle możliwości dopasowania wyrażenia do łańcucha znaków, że wejdziemy na obszar tzw. Catastrophic Backtracking (katastrofalne nawracanie?).

Moja poprawka sprowadziła się, oczywiście, do usunięcia czterech znaków: ".*" z początku i końca wyrażenia przekazanego jako argument metodzie Element::getElementsByAttributeValueMatching.

Jaka z tego nauczka? Rutynowo zaglądać w cudzy kod, niestety.

PS. Polecam krzyżówki regeksowe: Regex Crossword.

W ramach Strajku Kobiet: 5 mitów na temat aborcji

3 października, dzień Ogólnopolskiego Strajku Kobiet, to zarazem mój pierwszy dzień w nowej pracy. Strajk popieram całym sercem, ale zamierzam stawić się w pracy, bo nie zapracowałam jeszcze na takie zaufanie moich szefów. Próbowałam podpytać dział HR o plany związane ze strajkiem, założywszy (po seksistowsku), że będzie to najbardziej sfeminizowana sekcja firmy. Niestety, HR-y będą tego dnia w zagranicznej delegacji… Być może uda mi się dotrzeć na Plac Mickiewicza w ramach przedłużonej przerwy.

Postanowiłam dołączyć do akcji poprzez, prywatnego w końcu, bloga. Ktoś go przecież (jeszcze) czyta. Dla osób, które nie rozumieją, dlaczego wredne baby nie zgadzają się na proponowane zmiany w prawie, omawiam tu pięć mitów na temat aborcji, z którymi spotykam się najczęściej. Początkowo wybrałam siedem, ale odrzuciłam dwa związane głównie z religią i polityką, bo o fakty tu chodzi, a nie o wiarę i jątrzenie.

1. Istnieją zwolennicy aborcji

To największa bzdura i potężna manipulacja. Kobiety, które w poniedziałek protestują, nie są zwolenniczkami aborcji. Nikt nie jest zwolennikiem aborcji, tak samo jak, przy zachowaniu proporcji, nikt nie jest zwolennikiem amputacji. Żadna kobieta nie zachodzi w ciążę po to, żeby zrobić sobie aborcję. Żaden lekarz nie studiuje medycyny ciesząc się, że będzie usuwał płody albo odpiłowywał ludziom nogi. A jednak są okoliczności, w których taki zabieg jest po prostu najlepszym, jeśli nie jedynym możliwym wyjściem.

Jak większość moich koleżanek i kolegów, jestem zwolenniczką prawa do aborcji, prawa wyboru. Jak większość moich koleżanek i kolegów, mam nadzieję, że nigdy nie stanę wobec tego wyboru i nie będę z tego prawa korzystać.

Autor: Tomek Pastuszka
Autor: Tomek Pastuszka

2. Z każdego zarodka powstaje dziecko

Nie, nie i jeszcze raz nie. Po pierwsze, według badań, nawet 50% ciąż kończy się poronieniem, z czego większość (80%) ma miejsce w pierwszym trymestrze – nierzadko zanim kobieta zorientuje się, że w ogóle jest w ciąży.

Po drugie, zarodki potrafią rozwinąć się w twory niemające zbyt wiele wspólnego z człowiekiem w znanej nam postaci. Z zarodka może na przykład powstać zaśniad groniasty, pięknie opisany na blogu Patolodzy na klatce. Chciałam wrzucić bardzo wymowne zdjęcie takiego „dziecka”, ale widok nie dla każdego byłby znośny (a przecież niektórym rośnie to w środku!), dlatego zostawiam tylko link. Przygoda z zaśniadem może kończyć się nawet chemioterapią.

3. Na miejscu ciężarnej, każdy poświęciłby życie dla (minimalnej szansy) uratowania innego

Z reguły nie wrzucam wszystkich mężczyzn do jednego worka, ale tutaj trzeba. Nie wiadomo, co przyniesie przyszłość, ale do tej pory żaden mężczyzna nie znalazł się jeszcze w sytuacji, w której perspektywa kontynuacji ciąży wiązałaby się z ryzykiem jego śmierci. Z tego powodu uważam za niedopuszczalne, żeby prawem aborcyjnym zajmowali się głównie mężczyźni. Być może część z nich jest gotowa na takie poświęcenie (swoich partnerek i córek).

Ostatnio natknęłam się na świetne rozwinięcie tego tematu. Bo właściwie to istnieje sytuacja, w której każdy człowiek, w tym mężczyzna albo kobieta w wieku niereprodukcyjnym, może oddać albo narazić swoje życie, żeby ratować czyjeś – na przykład oddając swoje organy, by ratować życie dzieci, które urodziły się bez nich. A jednak nie widać kolejek osób chcących oddać płuco albo nerkę, nie wspominając już o sercu. W praktyce problem jest nawet ze szpikiem albo krwią, których oddanie jest o wiele mniej problematyczne.

Jak sądzicie, czy ustawa nakazująca obywatelom obojga płci oddawanie zdublowanych organów do przeszczepu ma szansę przegłosowania w polskim sądzie?

4. Usuwa się dzieci o takim kształcie i wielkości

Kolejna manipulacja to antyaborcyjne grafiki organizacji pro-life, które (o ile nie prezentują krwawych strzępów) pokazują kobietę na oko w dziewiątym miesiącu ciąży i sugerują, że aborcji dokonuje się na tym etapie. Aborcji na późniejszym etapie ciąży można dokonać jedynie, jeśli ciąża zagraża życiu lub zdrowiu kobiety. W przypadku ciąży powstałej w wyniku czynu zabronionego granicą jest 12 tygodni.

12072791_738297619647876_6407113363341519943_n

5. Zakaz aborcji zmniejsza liczbę zgonów i chroni życie

Obecnie w Polsce wykonuje się około tysiąca legalnych aborcji rocznie. Według szacunków zajmujących się tą tematyką organizacji (w zależności od opcji politycznej) aborcji nielegalnych jest od dziesięciu do ponad stu tysięcy rocznie. Do tego dochodzi turystyka aborcyjna do krajów, w których aborcja jest legalna.

Kobieta, która nie chce urodzić dziecka, prawie na pewno tego dziecka nie urodzi. Jeśli nie otrzyma odpowiedniej opieki medycznej, wykona aborcję chałupniczo albo skorzysta z usług niemoralnego szarlatana, ryzykując utratę zdolności reprodukcyjnych a nawet  własnego życia. Taka kobieta – martwa albo z uszkodzoną macicą – więcej obywateli na pewno nie urodzi.

Nie wiem, czy ochotę na kolejne ciąże mają matki, które ktoś zmusił do urodzenia zdeformowanych dzieci z wadami skazującymi je na śmierć kilka dni po porodzie.

Doświadczenia z całego świata uczą bez cienia wątpliwości, że delegalizacja aborcji wcale aborcji nie eliminuje, natomiast naraża życie i zdrowie tysięcy kobiet. W tym temacie polecam nagrodzony Złotą Palmą rumuński film 4 miesiące, 3 tygodnie i 2 dni.

Posłowie

Na koniec chcę się jeszcze podzielić refleksją na temat podejścia polskiego społeczeństwa nawet nie tyle do kwestii aborcji, co samej ciąży. Przez ponad 30 lat życia tutaj zdążyłam się zorientować, że dla wielu moich rodaków ciąża to nie jest stan błogosławiony ani stan fizjologiczny, ani nawet jedyna znana metoda przedłużenia gatunku. Ciąża to kara (dla kobiety) za uprawianie seksu. Najłatwiej przekonać się o tym w komunikacji miejskiej, gdzie słaniająca się na nogach ciężarna dowiaduje się od (najczęściej) tłustych starych kobiet, że nie należy się jej miejsce siedzące, bo „nie trzeba się było puszczać”. Zgodnie z tą logiką, aborcja to nic innego, jak łatwy sposób na uniknięcie (boskiej) kary. Wiadomo, żeby szaleć dalej.

PS

Polecam bardzo ciekawy wywiad z ginekologiem Romualdem Dębskim, do którego linkowałam w jednym z usuniętych punktów .

PS2

Dawno nie spotkałam się z taką ilością internetowego mansplainingu, jaką można zaobserwować w fejsbukowych wydarzeniach związanych ze Strajkiem Kobiet. „Dałyście się zmanipulować”, „w międzyczasie rząd przepchnął coś naprawdę ważnego – TTIP i CETA”. Tak, umowy TTIP i CETA są złe i przerażające. Organizujcie ile protestów się da, a ja chętnie się do nich przyłącze. Pozwólcie jednak,  że na pierwszym planie postawię bezpośrednie zagrożenie życia mojego i mojej córki.

PS3

Wyłączyłam komentarze, bo wiem, co potrafi się dziać pod wpisami na ten temat.

Eksperyment: rekrutacja (2/2)

czyli: drugie pięć z moich dziesięciu rekrutacyjnych oświeceń
czyli: nigdy więcej tą drogą

To druga część wpisu rekrutacyjnego, którego rozmiar wymknął się nieco spod kontroli. W poprzednim odcinku zdradziłam trochę informacji o pracodawcach, do których aplikowałam i przedstawiłam pierwszą połowę moich rekrutacyjnych „oświeceń”. Dotykały one tematów dość uniwersalnych. W tej części przedstawiam odkrycia bardziej osobiste oraz wyjaśniam, jak się to wszystko skończyło.

Lista 10 odkryć, ciekawostek i sensacji

Miejsca 6-10.

(to oczywiście nie jest moje zdjęcie, tylko screen z serialu Misfits)
(Ekipa przy pracy. Oczywiście nie jest to moje zdjęcie, tylko scena z serialu. Którego pierwsza połowa była całkiem niezła. Tak samo może być w przypadku tego wpisu.)

6. Facepalm. Operacja odczytu z HashMapy nie jest bezpieczna dla wątków

Miałam kilka takich technicznych eurek. Jeden rekruter na etapie programowania live wymusił na mnie użycie interfejsu funkcyjnego, dzięki czemu zrozumiałam, co w nim fajnego (można zaimplementować go jedną lambdą!). Inny przypomniał mi podstawowe fakty na temat modelu pamięci w języku, który uważam za ulubiony. Ale najbardziej wstrząsający był moment, w którym młodszy ode mnie o jakieś dziesięć lat* chłopak opowiedział mi o dziurze w moim kodzie. Wielowątkowy kod synchronizował dostęp do metody zapisującej dane w javowyom obiekcie HashMap, ale nie ograniczał odczytu. Efekt: możliwość zgubienia obiektu przy pobieraniu go z mapy, jeżeli w międzyczasie dodanie nowej wartości powoduje zmianę podziału obiektów pomiędzy kubełki. Yeah.

7. Państwowa uczelnia to świat po drugiej stronie lustra

Startując w konkursie na adiunkta wiedziałam, że mam do czynienia z budżetówką. Zero benefitów, skromniejsze płace. Po stronie plusów, w moim wyobrażeniu: inspirujące towarzystwo mądrych ludzi, wymiana wiedzy, prowadzenie badań bez dyszących w kark terminów wdrożeń. Zakończenie tej historii relacjonuję w ostatniej części tego tekstu. Tu przedstawiam „czerwone flagi”, które mimo mojej początkowej ekscytacji i perspektywy pracy z osobami, które podziwiam i uwielbiam, odwiodły mnie od pracy w tym miejscu:

  • Flaga 1: poczta pantoflowa, zwana inaczej wiedzą plemienną. Większość istotnych informacji nie jest dostępna publicznie. Gdyby nie znajomości na wydziale, nie wiedziałabym na przykład o tym, że…
  • Flaga 2: petenci czekają w kolejce. Dzień przed kwalifikacjami podano mi godzinę. Tę samą podano pozostałym kandydatom. Było nas, nomen omen, siedmioro… Wchodziliśmy do sali w kolejności alfabetycznej. Moje nazwisko zaczyna się od litery „W”. Cień nadziei zamigotał w postaci kandydata na „Ż”, ale ponieważ akurat trwały narodziny jego dziecka, poproszono go jako pierwszego. Na czekaniu spędziłam trzy owocne godziny, podczas których moim dzieckiem opiekowała się dobrze opłacona niania. #optymalnewykorzystanieczasu
  • Flaga 3: cisza. Pomyślnego nieoficjalnego wyniku konkursu gratulowano mi jeszcze tego samego dnia, ale musiał on zostać oficjalnie zatwierdzony przez rektora. Przez kolejne półtora miesiąca instytucja, która (jak się ostatecznie okazało) zdecydowała się mnie zatrudnić, nie wystosowała żadnego komunikatu na ten temat. Nie odebrałam maila, pisma ani telefonu, mimo że podałam te dane w dokumentach aplikacyjnych, tuż obok numeru PESEL i stanu cywilnego.

8. Odkrycie personalne: patologicznie nienawidzę rozczarowywać

Pierwszy sygnał pojawił się już w styczniu, kiedy zaczęłam przepytywać potencjalne nianie. Do sprawy podeszłam biznesowo – wystawiłam ogłoszenie, przejrzałam odpowiedzi, umówiłam spotkania. W pracy regularnie prowadziłam rozmowy kwalifikacyjne – była to da mnie emocjonalnie obojętna rutyna. Okazało się jednak, że kiedy nie mogę się zasłonić firmą, sprawy mają się zgoła inaczej, .

Podczas spotkań poznałam kilka ciepłych, doświadczonych, zdeterminowanych, bezrobotnych (lub pracujących na ochronie), kobiet, spośród których wybrać mogłam tylko jedną. Było to dla mnie naprawdę trudne do zniesienia. Pod koniec modliłam się, żeby staropolskim zwyczajem kilka kandydatek bez uprzedzenia nie pojawiło się na umówionej rozmowie.

Obiecałam sobie ten temat przepracować. Zanim się jednak do tego zabrałam, ruszyłam we własne tournée rekrutacyjne. A tam czekała mnie powtórka z rozrywki.

Rozumiem, że korporacje są bezduszne. Że w razie przejściowych kłopotów (czy relokacji) większość z nich nie będzie miała wobec mnie żadnych skrupułów. A jednak nie potrafię tej przerośniętej empatii dezaktywować. Prowadząc równoległe rozmowy z różnymi firmami, które nie zdążyły nawet jednoznacznie określić swoich intencji, i tak czułam się jak zdrajca. Wcześniej wyobrażałam sobie, jak siedzę z lampką wina nad stertą propozycji. W praktyce nie potrafiłam z pokerową twarzą odpowiadać na powtarzające się pytanie „co przekonałoby panią do pracy w naszej firmie”, zwłaszcza kiedy czułam już, gdzie najbardziej mi się podoba. Ostatecznie przez to nie wszystkie procesy doprowadziłam do końca.

9. Najtrudniejsze pytanie

Jak wyżej.

Kilka razy na końcowym etapie rekrutacji usłyszałam pytanie, jaka byłaby moja wymarzona praca, albo jak firma mogłaby przygotować stanowisko dla mnie.

Od lat jednym z moich największych problemów jest to, że interesuje mnie za dużo rzeczy i w zbyt wielu dziedzinach jestem w miarę dobra. Do niedawna nazywało się to „słomiany zapał” (ewentualnie „trzymanie pięciu srok za ogon”), ale w tym roku poznałam o wiele lepiej brzmiące słowo „multipotencjalista”. Myślę, że wkrótce napiszę o tym więcej.

W każdym razie, wyobrażałam sobie, że dostanę gotowe oferty i wybiorę najciekawszą. Programowanie, prowadzenie projektów, wykładanie – chciałam zobaczyć komplet propozycji i wtedy zdecydować. Zadawane w dobrej wierze pytania o moje osobiste preferencje przymuszały mnie do przejęcia inicjatywy i dokonania wyborów, przed którymi od dawna uciekam.

10. Tygodnie maglowania pozwalają lepiej poznać samego siebie

Kolejne sztampowe i okryte niesławą pytanie rekruterów to „gdzie widzisz siebie za pięć lat?”. Plan pięcioletni próbowałam w swoim życiu stworzyć więcej niż raz. Efekt zawsze wyglądał jak pajęczyna, z masą strzałek, warunków, wyjątków i zastrzeżeń. A jednak kiedy to pytanie wróciło do mnie na sam koniec, i kiedy musiałam dokonać wyboru pomiędzy dwoma proponowanymi mi dość różnymi stanowiskami, okazało się, że tygodnie maglowania i wytrącania mnie ze strefy komfortu pozwoliły mi odkryć kilka prawd swój temat. Podczas zupełnie ostatniej rozmowy byłam już w stanie uczciwie i ze sporym przekonanie na to pytanie odpowiedzieć. Co uważam za jedną z największych wartości w całej tej przygodzie.

(to z kolei z wpisu o rekrutacji do przedszkola)
(cudze  materiały rekrutacyjne)

I żyli długo i szczęśliwie

Stworzyłam sobie następujący plan A: uczelnia w połączeniu ze zdalną pracą w polskim startupie o ugruntowanej pozycji, zajmującym się dokładnie „moją” naukową dziedziną. Plan legł jednak w gruzach przez problemy opisane w punkcie 7, a doprawione wymianą kilku maili z dziekanatem. Nie jestem gotowa na skoki ciśnienia o takiej amplitudzie.

W dalszej kolejności nie bez żalu wycofałam się także z długoterminowej współpracy ze wspomnianym startupem. Zdalny etat przestał być kuszący w zestawieniu z nową pracą mojego męża, w której spędza trzy lub cztery dni w tygodniu poza Poznaniem. Cały dzień w domu, przy biurku, cały wieczór w domu, nad śpiącym dzieckiem… Mój ekstrawertyzm potrzebuje ujścia.

W ramach mocnego planu B zgłosiłam się na finalizację rozmów do najfajniejszej z odwiedzonych przeze mnie poznańskich firm. Na szczęście się na mnie nie obrazili. W październiku, a więc już za kilka dni, zaczynam nową pracę jako Technical Product Manager w firmie z fajnym produktem, miłymi ludźmi, wygodnym biurem, w odległości 15 minut na rowerze od mojego domu. Już nie mogę się doczekać!

I mam nadzieję, że przez wiele najbliższych lat nie będę musiała kolejny raz przechodzić przez rekrutacyjną mękę.

Notatka na przyszłość

Szalenie ciekawe doświadczenie. Szansa na odkrycia na temat siebie, rynku pracy, innych ludzi. Nigdy więcej nie robić tego w ten sposób.

Przypisy

* Ponieważ dzisiaj jest to mój kolega z pracy, wiem już, że jest ode mnie młodszy o jedyne cztery wiosny.

Eksperyment: rekrutacja (1/2)

Czyli pierwsze pięć z moich dziesięciu rekrutacyjnych oświeceń.
Czyli chcę największy kawałek tortu.

O tym, że po urlopie macierzyńskim będę szukała nowej pracy, wiedziałam od dawna. Data pojawienia się na świecie mojego dziecka zbiegła się z datą relokacji biura, w którym pracowałam, z Poznania do Warszawy. Gdybyfm już miała gdzieś się przenosić, na pewno nie wybrałabym miasta oddalonego o trzysta kilometrów od domu i przyjaciół. Trzy albo osiem tysięcy –o, to byłaby zupełnie inna rozmowa.

Postanowiłam podejść do sprawy metodycznie. Nie zdawać się na przypadek, nie ograniczać się do firm, które akurat nasłały na mnie headhunterów. Skoro firmom wolno przepytywać wielu kandydatów na to samo stanowisko – kombinowałam – to ja mogę porozmawiać z wieloma firmami i wybrać najbardziej do mnie dopasowaną spośród nich. No, wiadomo, spośród tych, które będą chciały współpracować ze mną. Akcję rozpoczęłam z czteromiesięcznym wyprzedzeniem.

Przygoda była długa i obfitowała w zwroty akcji. Dowiedziałam się sporo o sobie, innych ludziach, technologii, rynku pracy IT. Poniżej krótki bilans i parę moich przemyśleń / odkryć.

Zdecydowałam podzielić ten wpis na dwie części, kiedy rozlał się na piątą stronę i dziesiąty ekran.

Bilans

Ostatecznie wdałam się w rozmowy z siedmioma (!) potencjalnymi pracodawcami. Nie zależy mi przesadnie na utrzymaniu w tajemnicy ich tożsamości, ale nie chcę, żeby ten wpis pojawił się wśród wyników wyszukiwania informacji o którejkolwiek z nich. Odpowiem na dobrze uargumentowane pytania osób, które w tej chwili same szukają pracy. Zadbałam o to, żeby moja lista była zróżnicowana, choć koncentrowałam się na stanowiskach wymagających znajomości Javy, NLP i zarządzania zespołami. Na liście znalazły się, między innymi: dwie firmy pozwalające na pracę zdalną, jedna wymagająca relokacji do innego miasta, jeden polski startup, dwaj światowi giganci, jeden znany gracz wagi średniej, jedna państwowa uczelnia, dwa software houses z ambicjami.

Wyniki rekrutacji: jedna z firm odrzuciła moją kandydaturę na ostatnim etapie rekrutacji, nie oferując żadnej informacji zwrotnej, co uważam za dość perfidne i co stanowi oczywiście bogatą podstawę do wpadnięcia w obsesję. W pozostałych przypadkach zapoznałam się z ofertą lub przerwałam rekrutację w momencie, kiedy podjęłam decyzję o przyjęciu innej propozycji. Decyzja została potem poddana korekcie… Ale o tym poniżej.

Lista (5 z) 10 odkryć, ciekawostek i sensacji

1. Rekruterzy mogą walić drzwiami i oknami, ale większość z nich i tak chce przepuścić kandydata przez wszystkie etapy rekrutacyjnego młyna

Mimo że w większości przypadków to nie ja nawiązywałam kontakt, a szukająca pracownika firma, większość z nich i tak oczekiwała, że kandydat przejdzie przez wszystkie etapy czasem bardzo złożonego rekrutacyjnego sita. W zależności od przypadku, procesy rekrutacyjne obejmowały:

  • Od jednego do pięciu spotkań testujących rozmaite aspekty umiejętności i charakteru kandydata, oczywiście z nieśmiertelnym „dlaczego wybrała pani naszą firmę?”
  • Sprawdzanie umiejętności programowania poprzez: zadania domowe, zadania na sprawdzarce, płatne mini-zadania na rzecz firmy, programowanie flamastrem na tablicy, programowanie na kartce, programowanie przy kimś (sędzia i kibic w jednej osobie), pisemne testy.
  • Sprawdzanie determinacji kandydata poprzez wymaganie własnego, rozbuchanego formatu CV.

Przy odrobinie determinacji na pewno można wynegocjować pominięcie części etapów. Tak było zresztą było przy mojej poprzedniej zmianie pracy. Czułam się na tyle dobrze tam, gdzie byłam, że nie zdecydowałabym się na udział w rozbudowanej rekrutacji do innej firmy. Decyzja zapadła wtedy po jednym spotkaniu. Więc się da.

2. Przepływ informacji pomiędzy działami HR i technicznymi często pozostawia wiele do życzenia

Zapowiedzi osób z HR nie zawsze pokrywały się z rzeczywistym przebiegiem spotkań, na które byłam zapraszana. Nie zgadzały się nazwiska osób z którymi rozmawiałam, zapowiadana długość spotkań, tematy. W najbardziej ekstremalnych przypadkach:

  • Spotkanie trwało dwie i pół godziny zamiast jednej, przez co zresztą dostałam mandat za parkowanie (anulowano mi go w końcu, ale to temat na osobną opowieść).
  • Na „luźnym, nietechnicznym spotkaniu” (upewniałam się dwa razy po wcześniejszych przygodach) położono przede mną test z programowania i baz danych.
  • Nieobecnego menedżera zespołu zastąpiono programistą – kolegą z byłej pracy. Szalenie niekomfortowa sytuacja.

3. O symetrię trudno

Nieliczne firmy pytają wprost o to, czy kandydat uczestniczy równolegle w innej rekrutacji. Robią to głównie po to, żeby potencjalny pracownik nie zrezygnował przez terminy narzucane w drugiej firmie zgodnie z zasadą „lepszy wróbel w garści”.

Właściwie nie do końca wiadomo, jaka jest dobra odpowiedź na to pytanie. (Pewnie prawdziwa). Czy to plus, że mam inne opcje i trzeba się o mnie postarać? A może minus, bo po kosztownym i żmudnym procesie mogę na koniec podjąć inną decyzję?

W tej odsłonie rekrutacyjnych przygód moje wyznanie, że prowadzę rozmowy z kilkoma pracodawcami, spośród których chcę wybrać najbardziej dopasowanego, z którym zostanę dobrych kilka lat, dawało prawie zawsze ten sam efekt. Chwila konsternacji, podziękowanie za szczerość, a następnie kompletne tej informacji ignorowanie.

4. W Poznaniu istnieją biura doskonałe

Podczas swojego krótkiego tournée napotkałam: prysznice w biurze, parkingi dla rowerów, kuchnię z darmowym jedzeniem (screen z odcinka girls), biurka z elektrycznie podnoszonymi blatami, muzykę w wc, piłkarzyki i instrumenty muzyczne (wiem, że akurat na ten temat opinie są mieszane), możliwość przyprowadzenia do pracy dziecka albo psa.

Może nie aż tak, jak u Hanny...
Może nie aż tak, jak u Hanny…

5. Mroczne widmo GitHuba

Wolne oprogramowanie jest super. Dostępność kodu prawdziwych, wdrożonych projektów jest nie do przecenienia z edukacyjnego punktu widzenia. GitHub jest także coraz częściej wykorzystywany przez portale takie jak Coursera jako miejsce, w którym uczestnicy kursów mogą wzajemnie oceniać swoją pracę w procesie peer evaluation. Jednak ta otwartość ma swoje minusy. Jeden (tylko jeden, co w sumie zaskakuje) z rekruterów skrupulatnie przyjrzał się mojej githubowej twórczości – na tyle skrupulatnie, że wytknął mi błąd z obszaru synchronizacji wątków. Jezu, co za wstyd! Na GitHubie trzymam głównie wprawki – kod, który tworzę „na poważnie” w ramach pracy rzadko kiedy jest dostępny, a po pracy lubię zająć się hobby z nieco innej dziedziny. Tak czy inaczej, chcesz czy nie, GitHub staje się oficjalną wizytówką programisty.

W następnym odcinku

Kolejne pięć odkryć, w tym kilka na własny temat, oraz informacja o tym, jak się to wszystko skończyło.

Eksperyment: rekrutacja (2/2)

Bonus: czego szukają rekruterzy

W miarę wiadomo: wiedzy, pomysłowości, umiejętności pracy w zespole i radzenia sobie z nienapotkanymi wcześniej problemami.

Podczas mojej odysei udało mi się wyciągnąć z jednego z kierowników ciekawą informację na temat wymagań, które jego firma stawia programistom. Kandydaci dostają kartkę z opisem kilku zadań i chwilę na ich przemyślenie, a potem, już w obecności pracownika firmy, muszą zaproponować rozwiązania. Jedno z zadań zawiera przydługi opis systemu, który należy zaprojektować. Według relacji, większość potencjalnych programistów bardzo pobieżnie czyta tekst, po czym ochoczo zabiera się za projektowanie. Co z tego wychodzi – wiadomo. Pięknie zaprojektowany, zgodny z wzorcami, pełen fajerwerków projekt, który nie ma nic wspólnego ze specyfikacją.

Warto mieć na uwadze.

Spring Boot: autoryzacja użytkowników w oparciu o bazę danych

O logowaniu użytkowników pisałam wcześniej w następujących postach:

Dzisiaj dodałam do mojej raczkującej aplikacji funkcjonalność logowania użytkowników zapisanych wcześniej w bazie danych.

Poniżej przedstawiam zmiany, które musiałam w tym celu wprowadzić do mojej aplikacji.

a)  Wersja podstawowa

W klasie User, która od teraz ma być nie tylko klasą przechowującą dane, ale także bazą do autoryzacji użytkowników, muszę zaimplementować interfejs UserDetails:

W klasie SecurityConfiguration opisuję nowy sposób logowania:

Brakuje mi odpowiedniej metody do pobrania obiektu użytkownika po jego nazwie (getUserByUsername) w klasie UserRepository. Do tej pory szukałam użytkowników jedynie na podstawie confirmationId (co opisałam tutaj: Aktywacja konta poprzez email). Na szczęście dzięki Spring Data nie muszę jej nawet implementować, wystarczy, że dodam następującą linię:

b) Wersja rozszerzona. Przecież ja szyfruję hasła!

W tym celu muszę zarejestrować odpowiedni bean szyfrujący:

Jego właśnie muszę użyć do zaszyfrowania hasła przy tworzeniu nowego użytkownika:

Należy też wspomnieć o nim w konfiguracji:

Klasa BCryptPasswordEncoder implementuję metodę matches z interfejsu PasswordEncoder, która sprawdza, czy hasło w czystej postaci pasuje do jego zahaszowanej wersji przechowywanej w bazie danych.

Już.

PS. Podczas testowania mój dostawca domeny i serwera zablokował mi konto email, przekonany, że ktoś się na nie włamał i rozsyła spam

Milsza strona programowania