Przejdź do Treści

PODCAST TechChatter
Odcinek 9

TechChatter Odcinek 9. W obronie Pythona!

Mówi się, że Python jest jednym z najprostszych do nauki języków, a jego zastosowanie jest uniwersalne. W Pythonie można programować zarówno proste skrypty, jak i złożone środowiska machine learning. Python posiada też sporo bibliotek, z których można bardzo łatwo skorzystać, więc programista już od pierwszych minut pracy z tym językiem ma pod ręką ogrom możliwości i rozwiązań.

Jednak z drugiej strony do każdej kluczowej cechy Pythona można też dołożyć jakiś zarzut, a przy każdej zalecie dodać “ale”.

Zapraszamy do słuchania!

W dzisiejszym odcinku Kacper i Rafał wymieniają znalezione w sieci zarzuty w stronę Pythona i starają się je zripostować.

Rozmawiają m.in. o:

  • powolnym działaniu programów
  • dużej konsumpcji pamięci
  • braku różnic między Pythonem 3, a Pythonem 2
  • zarządzaniu zależnościami
  • braku multiplatformowości

Eksperci Capgemini:

Kacper Szmigiel – Programista z powołania, z Pythonem ma do czynienia od sześciu lat. Poza pracą w Capgemini studiuje na drugim stopniu Informatyki na Politechnice Łódzkiej, . W wolnych chwilach trenuje trójbój siłowy i sporty walki.

Rafał Kukawski – Python developer, fanatyk FOSS, Linux i cyberbezpieczeństwa. Programując w pythonie tworzy głównie technologie internetowe i NLP. 

Więcej o pracy w Capgemini:

https://www.capgemini.com/pl-pl/kariera/

Linki do materiałów wspomnianych w odcinku:

https://www.pypy.org/

https://github.com/python/cpython

https://cython.org/

https://docs.python.org/3/library/gc.html

https://rushter.com/blog/python-garbage-collector/

https://man7.org/linux/man-pages/man3/malloc_trim.3.html

https://stackoverflow.com/questions/7857462/dealing-with-fragmentation-in-a-memory-pool

https://virtualenv.pypa.io/en/latest/

Jeśli odcinek Ci się spodobał, daj nam o tym znać wystawiając ocenę w Spotify lub Apple Podcasts.

Podcast Capgemini Polska

Produkcja: Cleverhearted Showrunners


RAFAŁ: Cześć, jestem Rafał. W Capgemini pracuję chyba od roku i tam przede wszystkim się zajmuję Pythonem, backend i ETL pipelines. 
KACPER: Ja nazywam się Kacper. W Capgemini pracuję około pół roku. Specjalizuję się we wszystkim właściwie co związane z Pythonem, ale w szczególności z technologiami backendowymi i bazami danych. 
RAFAŁ: Dobra, to może ja z góry chcę przeprosić za kaleczenie polszczyzny. Postaram się, ale będzie, będzie czasami trudno zwłaszcza z technicznymi jakimiś słowami. 
KACPER: Okej, dzisiaj chcielibyśmy pogadać trochę na temat związany z tym, dlaczego Python jest zły i dlaczego tak wielu ludzi na niego narzeka? I na ile te wszystkie zarzuty są zasadne?
RAFAŁ: Zniszczymy hejterów. 
KACPER: Zniszczymy hejterów. No, to się jeszcze okaże, ale przynajmniej się postaramy. Przygotowaliśmy sobie kilka zagadnień, które najczęściej się przewijały, gdy robiliśmy research do tego odcinka i chcielibyśmy je wszystkie po kolei rozpracować i na każdy z tych zarzutów zaproponować chociaż jedno rozwiązanie, które pozwala obejść tutaj te trudności, jakie narzuca niejako czasami Python. Może zacznijmy od tego, co przewija się w sumie najczęściej, czyli tego, że Python jest powolny, czyli ma sporo ograniczeń związanych z tym, jak szybko wykonują się programy. Rafał, co o tym sądzisz? 
RAFAŁ: Co prawda tak, Python jest dość powolny i osobiście też miałem kilka z tym problemów. Za mną właśnie chodzi serwer, co pracuje na 100-150 GB danych i rzeczywiście trochę przymula. Robiąc research do tego trochę wpadłem w taki rabbit hole różnych rozwiązań. Z tego co widziałem, ja osobiście zacząłem używać PyPy, co jest 16 razy szybszy od zwykłego Pythona. Dosłownie inny interpreter. 
KACPER: Ale na jakiej zasadzie to jest? To jest po prostu inny interpreter?
RAFAŁ: To się właśnie używa just-in-time compiling. Z tym jest właśnie… Nie rozumiem, dlaczego dokładnie Python… Dlaczego to nie jest jakby priorytetem numer jeden Pythona, deweloperów Pythona oficjalnych, bo tak wydaje mi się to być dość ważnym, ten just-in-time compiling. Ale właśnie dlatego są alternatywy. 
KACPER: Z jednej strony masz rację, ale z drugiej trzeba by się było zastanowić na ile to, żeby ten język był szybki, jest faktycznie jego celem i głównym założeniem. No bo tutaj właśnie poruszymy kilka takich tematów. Na przykład dynamic typing. Też mamy to tutaj wylistowane. W latach ‘90., gdy Guido Van Rossum projektował Pythona, no to ich założeniem było to, żeby był to język typowany dynamicznie. I dlatego tego typowania po prostu, są też narzędzia, które pozwalają to oczywiście obejść jak MyPy, który teraz już obecnie jest oficjalną częścią języka, jeśli się nie mylę, przynajmniej jest hostowany na tym samym repo co Python, to akurat sprawdziłem. I sprawdza się bardzo dobrze, więc zależy czego tak naprawdę poszukujemy i co chcemy osiągnąć, tak? No bo jeżeli potrzebujemy szybkiego języka, no to już sięgniemy po Rasta, po C, ewentualnie C++, Golang ostatnio jest bardzo popularny. To tak trochę jakby wiesz, kupić Fiata Punto i narzekać, że jest wolny. No bo Fiat Punto z założenia nie ma być szybki, więc it is what it is. 
RAFAŁ: Fajnie, że wspomniałeś o tym dynamic typing. To była zresztą następna kwestia, że ludzie mówią, że Python jest tylko dobry dla małych projektów, bo brakuje właśnie tego dynamic typing. Wspomniałeś coś o MyPy? 
KACPER: Tak, jest to narzędzie, które pozwala na dodanie statycznego, to jest statyczny type checker po prostu, pozwala na statyczną kontrolę typów w Pythonie i on też nie jest idealnym rozwiązaniem, o czym sam się przekonałem. 
RAFAŁ: Tak? 
KACPER: Tak. Przeszło niecałe trzy lata temu, bo w ramach takiego programu Google Summer of Code pracowałem nad dodaniem statycznej kontroli typów dla frameworka Django właśnie z użyciem MyPy i powodowało to mnóstwo problemów, w szczególności dla klasy generowanych gdzieś tam dynamicznie w runtime. Natomiast nie jest to niemożliwe, przynajmniej do takich podstawowych zastosowań jakąś tam kontrolę typów możemy sobie dodać. To czego mi brakuje osobiście, to właśnie, wiesz, sprawdzanie tych typów runtime, czyli żeby crashowało na przykład w momencie, gdy funkcja dostanie niewłaściwy typ czy coś takiego. To by wiele uprościło z całą pewnością, ale znowu wracamy do tego, że to nie od tego jest Python w zasadzie. No nie?
RAFAŁ: Ale jednak jest też Cython i CPython praktycznie, jeśli to dobrze rozumiem. Dopiero tak trochę się z tym bawiłem, bo do tej pory nie musiałem, ale to jest pass-through do C i właśnie to definiowanie typów i wtedy się tym obchodzisz jak w C zamiast jak w Pythonie. To zresztą spoko, podoba mi się pomysł. 
KACPER: Ja tutaj przyznaję się bez bicia, że nigdy nie miałem z tym do czynienia tak bezpośrednio. 
RAFAŁ: No właśnie tak jak patrzyłem, jak sprawdzałem w Ogam Connectors i takich tam to właśnie tak się wpadłem do rabbit hole z CPython i Cython. Fajny patent, na bank będę chyba dalej będę z tego. Może w ogóle się przeskoczę na Cython i CPython dla prywatnych projektów. 
KACPER: Spoko, brzmi dobrze. Jeśli chodzi o właśnie, bo poruszyłeś też kwestię tego, że Python rzekomo nie nadaje się do dużych projektów, właśnie przez dynamiczne typowanie i tutaj rozwiązanie jest moim zdaniem dość proste, mianowicie pokrycie kodu testami w taki sposób, żeby przy jakimkolwiek większym refaktorze po prostu wszystko nie zaczęło się sypać i żebyśmy dalej mieli dość sprawnie działający kod bez żadnych tam kolizji związanych właśnie z typami. Więc tutaj pisanie testów jest wymogiem.
RAFAŁ: Właśnie chciałem powiedzieć, jedyny problem z tym jest pisanie testów. I kto ma na to czas i komu się chce. Mi nie, nie wiem jak Tobie. 
KACPER: To jest akurat kwestia tego, w jakim projekcie pracujesz, bo są projekty faktycznie przynajmniej takie, na których ostatnio w Capgemini miałem okazję pracować, że ten czas na testy faktycznie jest. I ten test coverage jest na poziomie 80-90% i jest to bardzo dobry wynik biorąc pod uwagę to, jak duże są tu projekty. Także da się, da się, i nie jest łatwo, ale nie jest to niemożliwe. Dobra, a tutaj patrzę sobie na tą listę rzeczy, które… 
RAFAŁ: Szczerze? Jedno co mnie właśnie strasznie kręciło, to to o co chodzi z tym global and capital log i multithreading. Trochę też sam w to wpadłem przez ten memory usage. Ty co o tym wiesz? Jak to obejść i jak do tego podejść najlepiej? 
KACPER: Obchodzi się to bardzo prosto. To prosto zamiast tworzyć programy wielowątkowe, to zaczyna się pisać, wiesz, multi procesowo. Czyli zamiast korzystać z wątków, to korzystamy z osobnych procesów i na to sobie rozbijamy nasze programy. Global interpreter log, no okej, on jest upierdliwy i poniekąd sprawia, że ten multithreading w Pythonie nie istnieje. Jest bezużyteczny. Natomiast mamy lipkę w bibliotece standardowej, pakiet multiprocessing, który jest banalny w obsłudze w mojej ocenie i sprawdza się bardzo dobrze.
RAFAŁ: Jak się nazywa? 
KACPER: Multiprocessing. 
RAFAŁ: A, Multiprocessing, okej. 
KACPER: Tak, tak i tam wiesz, rozbicie sobie programu na, jakichś tam bardziej złożonych operacji, na kilka procesów po prostu nie stanowi dużego wyzwania, jeżeli wiemy co robimy. Nie wiem, na ile ten multithreading to jest takie faktyczne issue. To jest po prostu coś za coś, no nie, a niekoniecznie jest to jakiś ogromny bloker. Poza tym też tego akurat bardzo nie zgłębiałem, nie miałem okazji, ale wiem też, że w Pythonie przecież mamy cały mechanizm do realizacji, wiesz, async await, no nie? I tam sobie deklarujemy nasze tam core routines i rzeczy po prostu dzieją się asynchronicznie. I jeżeli mamy jakieś tam oprogramowanie zależne od jakichś third parties, czyli musimy poczekać aż coś się wydarzy, no to czemu mielibyśmy z tego nie skorzystać, jeżeli już tak bardzo nam zależy na tym, żeby nasz program składał się z jednego procesu i z jakiegoś powodu nie chcemy tego multiprocessing używać. Kolejny zarzut, z jakim tutaj spotkaliśmy się, przygotowując się do odcinka, to konsumpcja pamięci.
RAFAŁ: Mam dwie odpowiedzi praktycznie, krótką i długą. Krótka, jak ci matka przychodzi do pokoju sprzątać i ty nie masz prawa potem narzekać, że źle sprzątnięte. Pierwsza to, można zawsze po prostu delete variable i wywołać funkcję collect na obiekcie i masz sprzątnięte, masz tak sprzątnięte jak chcesz. Garbage Collector oczywiście nie jest idealny i są oczywiście problemy z fragmentacją i zwalnianiem pamięci z powrotem do systemu. I szczerze jak czytałem o tym, to wpadłem w taki rabbit hole, że siedziałem wczoraj do trzeciej. Czasami się wkręcam w najdziwniejsze rzeczy. Ten Garbage Collector został wprowadzony w wersji Pythona 2 i rzeczywiście tam są jakieś takie dziwne sytuacje, gdzie się fragmentuje pamięć i Python jakby nie oddaje całej pamięci, co powinien oddać. Rzeczywiście jest taki problem, ale znowu ta sama sprawa. Oczywiście można zawsze dostać pointer od Garbage Collector i samemu wyczyścić pamięć tak jak chcesz, tak jak byś to robił w C. Osobiście tego nie robiłem nigdy, nie musiałem tego robić, ale teoretycznie jest to możliwe. 
KACPER: Wiesz co? Ja też trochę wczoraj zgłębiałem ten temat przygotowując się do odcinka. Trafiłem na coś takiego, bo w sumie wszystko w Pythonie jest obiektem, no nie? I taka jest definicja tego, jak Python to object-oriented programming realizuje. 
RAFAŁ: Tak, i ten Garbage Collector zbiera obiekty, które już nie są dostępne. To robi cyklicznie co ileś tam, clock sekund, czy coś.
KACPER: Tak, ale co z tego wynika to to, że nawet zmienna typu int poniekąd również jest obiektem. I tak jak w Golang, int w zależności od tego o jakim incie mówimy, bo int, intowi nierówny, ale ma zazwyczaj gdzieś 4 bajty. To wiesz, jak sprawdziłem sobie w Pythonie, to ma 24. To jest 6-krotnie więcej, więc tutaj to jest obrażanie się na Pythona za to, że jest w Pythonem, że zajmuje dużo pamięci. No zajmuje, bo tak jest skonstruowany i tak jest w sumie jego założenia. Oczywiście można by było tutaj narzekać na ten Garbage Collector, ale z tego co mi wiadomo na ten moment, to też nie jest to w ogóle issue dlatego core teamu, który rozwija Pythona i go tworzy. Jest to też chyba, wydaje mi się, podyktowane względami praktycznymi, ponieważ czas programisty jest znacznie droższy niż sprzęt obecnie. Więc o wiele bardziej opłaca się i tak skorzystać z języka, który będzie prosty w obsłudze i po prostu będzie łatwo i szybko można stworzyć oprogramowanie i je utrzymywać potem i właśnie dokupić RAM-u, niż korzystać z jakichś edge’owych rozwiązań, które okej będą wydajne, oczywiście można pisać wszystko w C, tylko po co? Jeżeli sprinty wtedy by nie trwały 2 tygodnie, tylko 2 miesiące. Żeby zrobić cokolwiek. 
RAFAŁ: Racja, a żeby do tego też dołożyć, PyPy jest dużo bardziej eficjentny w pamięci też. Dużo, dużo bardziej eficjentny. W ogóle te 150 GB na moim komputerze dosłownie zbudowanych ze śmieci, nie przesadzam, normalnie chodzi na PyPy, bo na Pythonie by mi chodziło. Zawiesił się po prostu komputer, bo nie starczyło pamięci, wszystko zjadał i… Ale PyPy chodzi, więc mam 4 GB RAM-u.
KACPER: To tyle co mój telefon. 
RAFAŁ: I na tym serwer prowadzam, więc da się, da się. [śmiech]
KACPER: To może przejdźmy sobie trochę dalej. Dla mnie temat w ogóle ezoteryczny, Python 2 i narzekanie na to, że Python 3 od Python 2 się, bardzo, że właśnie niewiele się różni, bo na początku to były w ogóle takie głosy, że jedyna różnica to było zrobienie z printa funkcji zamiast instrukcji, tak jak było w Pythonie 2.
RAFAŁ: No, nie, nie, są jakieś różnice. 
KACPER: No, oczywiście, że są, tylko mógłbyś o tym trochę więcej jeszcze opowiedzieć. 
RAFAŁ: Szczerze, był trochę chaos z migracją z Pythona 2 do 3. Wystarczająco był chaosów z migracji z Pythona 2 do 3, że nie pamiętam, jaka była dystrybucja. Chyba Ubuntu się kompletnie wycofał z używania Pythona, że już [niezrozumiałe 00:14:21] nie publikowali Ubuntu chyba z Pythonem 2 zainstalowanym nie pamiętam. Ale był, jest trochę chaos, jest trochę rzeczywiście takiego, trzeba się zacząć tym bawić, ale jednak jest bardzo łatwe rozwiązanie, są dwa pakiety, się nazywa PyEnv i VirtualEnv. Mi się wydaje, że VirtualEnv i tak powinien być stackiem, co się używa przez cały czas do programowania, nawet jak jest początkującym i nawet coraz więcej widać w takich tutorialach dla początkujących VirtualEnv. 
KACPER: Wiem, konteneryzacja obecnie już, wiesz, Docker jest na tyle prosty w obsłudze, że wrzucenie czegoś do kontenera nie jest jest to rapid science. 
RAFAŁ: Tak, ale mi się wydaje, że VirtualEnv jest mały, it’s not bloated. Docker to już tak ściągasz cały system operacyjny, żeby… 
KACPER: Właśnie, nie. Z Kernela dalej korzystasz z hosta. 
RAFAŁ: No tak, ale jest wciąż więcej danych, jest więcej bloat, jest większy overhead. Jeśli ci już przeszkadza overhead w Pythonie, to dlaczego ci nie przeszkadza overhead w Dockerze. Zwłaszcza na takim serwerze ze śmieci odczuwać różnice, tak rzeczywiście odczuć, da się odczuć różnice, czy używasz VirtualEnv czy Docker, jest poważna różnica. Mówimy tutaj o 2-3 sekundy wolniej. 
KACPER: To jest dobry argument. 
RAFAŁ: Ale VirtualEnv jest idealne. Zwłaszcza jak zacznie się tak trochę płynniej korzystać z terminalu, to nie widzę, jak to po polsku, downside. I jeśli do tego dołożymy PyEnv, to w ogóle nie widzę problemu. Się instaluje po prostu wersja taką, jaką chcesz i gotowe. It just works. 
KACPER: No spoko, ale widzisz, stąd można przejść łatwo do zarządzania zależnościami w Pythonie. W ogóle o tym wczoraj pomyślałem, że ile razy miałem jakąś sytuację, że właśnie nie korzystałem z VirtualEnv i instalowałem jakąś tam nową paczkę. I wiesz, i cała reszta mi się sypała z tego względu, że jak masz w zależnościach swojego programu jakąś paczkę w jakiejś wersji, nie wiem, CO PG2 na przykład, które dotychczas chyba najwięcej problemów mi sprawiało pod tym kątem i masz w swoich zależnościach inną paczkę, która również ma w swoich zależnościach tę samą paczkę co ty, ale inną wersję, to w momencie, gdy to będziesz pipe instalował, to to po prostu zostanie nadpisane. I stąd wynika niejako ta konieczność korzystania z VirtualEnv, ale one też nie rozwiązują tych wszystkich problemów, bo ta paczka i tak ostatecznie zostanie nadpisana. To jest poważny zarzut moim zdaniem. I to jest ciężko wybronić. 
RAFAŁ: Zgadzam się.
KACPER: O wiele lepiej wydaje mi się, że w Node jest to rozwiązane, gdzie wszystko jest instalowane lokalnie. Nie wiem, jak tam konflikty są rozwiązywane. Nie pracuję z tym na co dzień. Ale wydaje mi się to o wiele bardziej rozsądne i instalowanie rzeczy lokalnie by default w folderze projektu, czy to memiczne Node_modules, które zajmuje pół dysku. Tak, to faktycznie zajmuje pół dysku i instaluje się nierzadko kilkanaście minut, ale działa, tak? I działa tak jak powinno i o wiele lepiej spełnia oczekiwania, wydaje mi się, niż to co niestety mamy w Pythonie. Cóż nie wszystko da się chyba wykonać.
RAFAŁ: No szczerze też nie mam idealnej odpowiedzi na to. Ale może jednak jest jakieś rozwiązanie, żeby mieć kilka VirtualEnvi w jakiś momencie… Nie wiem, nie ma dobrego rozwiązania. 
KACPER: No ale to i tak nie jest rozwiązanie, tylko hakowanie tego.
RAFAŁ: Potato potato. Jeden to nazywa hakowanie, inny to nazywa rozwiązanie. Nie ważne. 
KACPER: Okej. No i multiplatformowość i te wszystkie zarzuty związane z tym, że nie wszystkie pakiety działają tak, jak powinny na wszystkich systemach chociażby. Tkinter jest takim przykładem, który zresztą omawialiśmy sobie. To, że on działa dobrze bodajże na Windowsie i na pewno na Macu, bo miałem w ramach studiów wątpliwą przyjemność korzystać z tego pakietu w jednym z projektów i wiesz na Macu to działało dobrze, z tego co wiem, na Windowsie też. 
RAFAŁ: Na Linuxie już nie działa.
KACPER: Natomiast nie działa na Linuxie. No właśnie. Ale pytanie, na ile to jest problem też związany z samym Pythonem per se, a na ile po prostu z ekosystemem. Bo tutaj należałoby wymagać tak naprawdę od ludzi, którzy tworzą to wszystko wokół całego Pythona, wokół tego core’u, żeby testowali wszystko na wszystkich możliwych platformach. No a na ile to jest realne, no sądzę, że nie bardzo. A na ile to jest w takim razie zarzut w stronę Pythona? No bardziej zarzut w stronę ekosystemu Pythona, niż jeżeli samego języka. 
RAFAŁ: Mówimy tu o samym języku. W ogóle jeszcze to przegapiliśmy. Funkcje dunder i potrzebna memoryzacja podstawowych randomly defined variable names, that you just have to memorize. Niektórzy ludzie mówią, że to jest podstawowa problem z Pythonem, że tego jest niepotrzebnie dużo. Co Ty myślisz? 
KACPER: No okej są, ale w jakim języku ich nie ma. I pytanie na ile jest to w ogóle problem i ilu z nich się tak naprawdę korzysta. Przy dzisiejszych ID, z których tam można sobie też korzystać i podejrzeć docstringi po prostu najeżdżając na nazwę funkcji i zobaczyć co się w niej dzieje i po prostu nie musieć grzebać w dokumentacji. To nie ważne, czy ich będzie 69 czy 690, to dalej nie będzie to jakiś ogromny problem. Są też magic methods, czyli te, które Double underscorze tworzy, z których korzystają wszystkie obiekty. Mamy te inity, różne dele chyba, konstruktory, dekonstruktory i tak dalej. Zastanawiam się, na ile to jest w ogóle zarzut. W sensie no są, no i co, i z ilu z nich faktycznie się korzysta. Nie spotkałem się jeszcze z sytuacją, gdzie wymienienie dosłownie pięciu na rozmowie rekrutacyjnej byłoby niewystarczające. W praktyce i tak, sądzę, że warto wiedzieć, że w ogóle istnieją, ale czy trzeba pamiętać, że wiesz, jak działa każda z nich, co dokładnie robi. 
RAFAŁ: No Init trzeba wiedzieć na bank, Init to na bank.
KACPER: No tak to zdecydowanie, ale całą resztę ewentualnie można podejrzeć w dokumentacji. Jeszcze wracając do Top Level Functions, to to co chciałem napomknąć, to istnieje taki język programowania, świetny jak PHP. Defaultowo wszystko jeśli się nie mylę, oczywiście dawno w nim nie pracowałem bardzo. Może coś się zmieniło w tej ostatniej chyba siódmej wersji, tak? Wiesz, kiedyś w tym pracowałem, bo byłem młody i potrzebowałem pieniędzy.
RAFAŁ: I was young and I was stupid and desperate. I did horrible things. 
KACPER: W każdym razie tam defaultowo chyba wszystkie funkcje, które sobie definiujemy, one trafiają do tych Top Level Functions tak i są dostępne z każdego miejsca w skrypcie, jeżeli się tutaj nie mylę. Możliwe, że mówię tutaj coś bardzo naiwnego. Ale wiesz, jeżeli mamy do czynienia z czymś takim i tak jest to szeroko używany dalej język programowania, to tutaj te 60 kilka funkcji, z którymi mamy do czynienia w Pythonie, to naprawdę nie jest dużo i nie powinno to stanowić problemu. 
RAFAŁ: A mówiąc o różnych opcjach, używasz taby czy spacje?
KACPER: Taby for life. 
RAFAŁ: Yes. Fuck loading exiles, tab, no spaces. [śmiech]
KACPER: I właśnie tutaj też kolejny zarzut odnośnie samej składni to to, że te identy są wymuszone.
RAFAŁ: Szczerze, ja dużo bardziej wolę identy niż curly braces. 
KACPER: Ja tak samo. 
RAFAŁ: JavaScript mnie po prostu zabija. Jak po prostu się jakoś nie domknę jednego curly braces, bo na samym dole mam 3000 tych curly braces i nie wiadomo co się dzieję. Wolę Python, to jest takie piękne. To tyle lepsze. 
KACPER: Tak, to jest po pierwsze czytelniejsze, a po drugie wiesz ostatecznie i tak wszyscy korzystają z identów, niezależnie od tego w jakim języku piszą. 
RAFAŁ: Najgorsze co się może stać, że po prostu we’ve noticed inconsistent use of tabs and spaces. I to po prostu na przykład w ciągu 5 minut jest gotowe. Tak absolutnie. 
KACPER: Poniekąd racja. Myślę, że powoli będziemy kończyć. 
RAFAŁ: Muszę jeszcze jedną rzecz. Tak sobie myślę. Może być też interesujący dla innych ludzi. Jak sobie radzisz ze syndromem impostora? Tak z ciekawości. 
KACPER: Jak ja sobie radzę? Ja sobie nie radzę zupełnie. Nawet nie próbuję. W zeszłym tygodniu, dokładnie tydzień temu, obroniłem pracę inżynierską i pokazała mi ona, jak wiele jeszcze nie wiem w ogóle na temat dziedziny, którą się zajmuję poniekąd od 10 lat. Więc nie, nawet sobie nie próbuję z tym radzić. O wiele bardziej tutaj raczej kwestie jakiegoś wypalenia są dla mnie istotne i żeby czasem porobić coś innego, pouczyć się czegoś innego, popracować w innej technologii i dalej mieć jakby fun z tej pracy. Wiesz to, że będzie mi się wydawało, że wiem, że nic nie wiem, no to cóż it is what it is. 
RAFAŁ: The same. Nie mam zresztą lepszego rozwiązania niż chodzenie biegać. Zdarza się, że potrzebuję po prostu przerwy w środku dnia, żeby pójść biegać, bo jeśli nie to mi się po prostu robi mętlik w głowie. Tak samo. 
KACPER: Dobra, no to sądzę, że to by było na tyle. Dziękujemy Wam bardzo za wysłuchanie naszego podcastu i do zobaczenia w następnych odcinkach. 
RAFAŁ: Dziękuję za słuchanie podcastu i zapraszamy. 
KACPER: Jeżeli temat Was zainteresował i chcielibyście dalej go zgłębiać, to zajrzyjcie do opisu odcinka, w którym znajdziecie linki do materiałów, z których korzystaliśmy, przygotowując się do niego.