Jak współcześnie wygląda sytuacja programisty C++?
Streszczenie odcinka:
⚫️ Jak wyglądała Twoja droga do zostania programistą?
⚫️ Czym się zajmujesz na co dzień? W jakich technologiach pracujesz?
⚫️ Jak wygląda rynek pracy dla programistów C++?
⚫️ Jakie są możliwe ścieżki zawodowe osoby ze znajomością C++?
⚫️ W jakich branżach przeważa C++?
⚫️ Czy C++ ewoluuje? Jaka jest historia C++ zmian w tym języku?
⚫️ Jak wygląda wykorzystanie najnowszych standardów (C++14, C++17) w praktyce?
⚫️ Dlaczego C++ dobrze sprawdza się w branży automotive i systemach wbudowanych?
⚫️ W jaki sposób można zostać programistą systemów embedded? Jak się do tego przygotować?
⚫️ Czym jest framework Qt i dlaczego warto go używać?
⚫️ Na ile rozbudowane jest środowisko narzędziowe dla C++? Czy jest ono porównywalne z Javą?
⚫️ Jakie są perspektywy rozwoju C++ w kolejnych latach?
Transkrypcja odcinka:
Cześć, z tej strony Łukasz Kobyliński. Witam Was serdecznie w kolejnym odcinku podcastu „Stacja IT”. Mamy przyjemność porozmawiać o kolejnym języku programowania, tym razem jest to C++, czyli język, który w dzisiejszych czasach jest trochę mniej znany czy używany szerszej publiczności, budzi więcej kontrowersji. Dziś spotykamy się ze specjalistą od tego języka – Witoldem Wysotą.
Cześć! Wielkie dzięki, że zgodziłeś się porozmawiać dzisiaj z nami. Na początek powiedz kilka słów o sobie. Skąd zainteresowanie językiem C++ i jak to się stało, że zacząłeś programować?
Cześć! Zaczęło się bardzo śmiesznie, bo od wyjazdów nad morze z rodzicami. Pamiętam, że były tam automaty z grami i chodziłem z ojcem, by sobie pograć. Spowodowało to, że potem rodzice kupili mi pierwszy komputer, ośmiobitowe Atari, w którym później jako nieduże dziecko programowałem w BASIC-u. To wszystko się rozwijało, a ja starałem się programować coraz więcej. W końcu skończyłem studia z zakresu informatyki i rozpocząłem pracę zawodową z tym związaną. A dlaczego C++? Tak naprawdę powiedziałbym, że trochę z przypadku. W czasach, kiedy zaczynałem poważniejszą zabawę z programowaniem, to C i C++ były podstawowymi językami programowania. Tak naprawdę każdy musiał je znać, żeby być w stanie zrobić coś sensownego. Nie było jeszcze ani Javy, ani Pythona. HTML wyglądał zupełnie inaczej niż teraz. JavaScript – podobnie. C++ był naturalnym wyborem, a potem przy nim zostałem.
Pamiętam, że na studiach C++ był podstawą, Java wydawała się nowinką, którą jeszcze niewiele wykładowców było w stanie wykładać. Zajęcia z Javy prowadzili wykładowcy z zewnątrz. Ciekawe jest to, że coś, co wydawało się podstawą dydaktyczną uczenia programowania, w tej chwili jest trochę na innej pozycji. Czym teraz się zajmujesz?
Teraz zajmuję się kilkoma rzeczami. Jeśli chodzi o rzeczy niezwiązane bezpośrednio z programowaniem, to jestem asystentem na Politechnice Warszawskiej, w której uczę programowania. Nie programuję, tylko uczę. Oprócz tego zajmuję się programowaniem głównie w języku C++, a moim głównym narzędziem pracy jest framework Qt, który służy do programowania różnego rodzaju aplikacji w C++, natomiast jego głównym czy najpopularniejszym zastosowaniem jest tworzenie graficznych interfejsów użytkownika w aplikacjach.
Jak wygląda obecnie rynek pracy dla programistów C++? Czy ta kompetencja jest nadal poszukiwana? Czy trudno znaleźć takie oferty pracy? Czy przez to, że mniej ludzi uczy się C++, ci, którzy go dobrze znają, są bardziej poszukiwani na rynku pracy?
Może nie widać tego na pierwszy rzut oka, ale tak naprawdę ofert pracy w C++ jest mnóstwo. Jest bardzo duże zapotrzebowanie na programistów tego typu. Rzeczywiście jest tak, że popularność innych języków programowania spowodowała mniejszy zalew tych programistów niżej poziomowych, typu C++ na rynku. Przez to ciężej jest znaleźć dobrego specjalistę w tej dziedzinie. Więc jeśli ktoś prezentuje w miarę sensowny poziom C++, bez problemu znajdzie pracę.
Jesteś też zaangażowany w dydaktykę na Politechnice Warszawskiej. Jak to wygląda teraz w programach studiów informatycznych? Czy nadal jest to mocna pozycja, czy raczej mówi się coraz częściej o innych językach i mniej osób wychodzi z tą umiejętnością po studiach wyższych?
Tak naprawdę C++ cały czas jest podstawowym narzędziem, które jest uczone w ramach studiów. Natomiast prawdą jest to, że to tylko narzędzie. Gdy pojawiają się przedmioty dotyczące konkretnych dziedzin, to już nie ma większego znaczenia, czy ktoś używa C++, czy innego języka programowania. Ten wybór jest bardziej dowolny. Rzeczywiście spotykam się coraz częściej z sytuacją, w której studenci pytają, czy mogą coś zrobić w innym języku, nawet jeżeli C++ jest podstawą. Natomiast wydaje mi się, że istotne jest to, aby mimo wszystko, nawet jeśli nie wiążą swojej przyszłości bezpośrednio z tym językiem, poznali go. Pomimo używania innych języków programowania C++ też się kiedyś może przydać.
Wydaje się, że C++ jest jednym z ostatnich bastionów programowania blisko sprzętu. Bo wszystkie inne popularne obecnie języki – czy to oparte na JVM, czy Pythonie – mocno nas od tego izolują, więc tak naprawdę zapominamy, jaką maszynę programujemy.
Często tak jest, natomiast trzeba pamiętać, że nawet jeśli programujemy w języku typu Python, to używamy modułów, które są napisane w C czy C++. Bywa, że musimy sami taki moduł napisać i wtedy trzeba sięgnąć po język niższego poziomu, który da programiście większą kontrolę nad tym, co dzieje się ze sprzętem, na którym działa jego oprogramowanie.
W jakich branżach i typach zatrudnienia możemy wykorzystać C++?
W zasadzie mamy pełen przekrój zatrudnienia. Możemy je znaleźć zarówno na rynku serwerowym, w którym tworzy się bardzo duże aplikacje, które potem działają na olbrzymich serwerach, z których korzystać będzie wiele osób, jak i w systemach biurkowych, które w tej chwili stanowią największy udział w rynku oprogramowania tworzonego w języku C++, czyli programy, z którymi tak naprawdę stykamy się na co dzień. Bardzo dużo z nich napisane jest w C++, może ostatnimi czasy mniej, szczególnie jeśli używamy Windowsów, bo tam są środowiska typu .Net, które w tej chwili szturmem zdobyły rynek, kończąc na urządzeniach małych, czyli embedded, gdzie C, C++ – te dwa języki wymieniam jednocześnie, bo one mają wspólną bazę, wspólną historię i zastosowania – niepodzielnie królują. Jeżeli mamy małe urządzenia, których produkujemy milion lub dwa miliony, to zależy nam na tym, żeby jak najmniej zainwestować w sprzęt i jak najbardziej wydajnie go kontrolować. Bo jeżeli na jednym urządzeniu zaoszczędzimy 5 dol., to na milionie urządzeń zaoszczędzimy 5 mln dol., a to niebagatelna kwota.
Mówiłeś o zastosowaniach przy aplikacjach serwerowych. Co masz tu na myśli? Czy możesz podać przykłady tych aplikacji?
Jeżeli mamy serwer, to możemy go rozpatrywać na różnych płaszczyznach, np. takiej, która udostępnia usługi na zewnątrz – i pewnie do tego nadają się inne języki niż C++ – natomiast schodząc niżej, dochodzimy do poziomów, gdzie dosyć istotne staje się dla nas połączenie z jakimś sprzętem, bo serwer to nie tylko obrabianie danych, ale również ewentualnie dostęp do zasobów sprzętowych, a takie rzeczy realizuje się w językach typu C++.
Czyli wiemy, że jest zapotrzebowanie, natomiast jaki jest obecnie status C++ jako języka? Bo przez wiele lat C++ w zasadzie się nie zmieniał. Wydawało się, że zostaje w tyle pod tym względem, mniej pojawia się konstrukcji czy takich możliwości, jakie dają inne języki ułatwiające programowanie tudzież przyspieszające ten proces. Była jakaś zmiana w 2011 r.
Ciężko mówić, że akurat w danym roku była zmiana, ona została wtedy sfinalizowana, natomiast prace trwały dużo dłużej.
Czy to jest tak, że teraz język jako standard zmienia się częściej, że te przeglądy odbywają się częściej i więcej z elementów, które znamy z innych języków programowania, pojawia się też w C++?
Tak. Nad rozwojem języka C++ czuwa cały czas komitet standaryzacyjny. O ile rzeczywiście na początku obecnego stulecia niewiele ten komitet wyprodukował na zewnątrz, o tyle od 2011 r., kiedy pokazał się standard C++11, który był przełomem, jeśli chodzi o język C++, prace trwają nieprzerwanie i nowe standardy opracowywane są średnio co trzy lata. Mieliśmy je w 2014 r., w 2017 r., a następne planowane są na lata: 2020 i 2023. Rzeczywiście pojawia się coraz więcej nowoczesnych rozwiązań czerpiących często z innych języków.
Jak wygląda kwestia kompatybilności kodu wstecz? Czy mamy możliwość kompilowania kodu, który znajduje się w starszym standardzie, w nowszym kompilatorze?
Kod, który powstał 10–15 lat temu, cały czas jest poprawnym kodem w języku C++. Skompiluje się z każdym standardowym kompilatorem. Używając kompilatora, wybieramy wersję standardu, którą kompilator ma obsługiwać. Każdy porządny kompilator ma możliwość podania również wstecznych wersji standardu, gdybyśmy chcieli sobie to ograniczyć. Wygląda to tak, że przy danej wersji kompilatora pewien standard uznany jest za domyślny – i ten jest włączony domyślnie – i wcale nie musi być to najnowszy standard, przeważnie jest to przynajmniej jeden wstecz. Natomiast możemy sobie włączyć standard nowszy – raczej w tę stronę to działa, niż że będziemy chcieli używać standardu starszego, bo nie ma takiej potrzeby, C++ jest kompatybilny wstecz.
Jak wygląda adopcja tych standardów? Czy kiedy nowy standard się pojawi, to wszyscy starają się przełączyć produkcję swojego kodu na nowe rozwiązania, czy raczej środowisko jest tu konserwatywne i wszyscy piszą w C++11 bądź w starszym?
To bardzo dobre pytanie. Jest dokładnie tak, jak powiedziałeś na końcu. Większość ludzi używa starego C++ z różnych powodów. Często z niewiedzy, bo przeskok między C++03 a C++11 wymaga pewnego wysiłku, żeby się tego nauczyć. Wynika to też z tego, że firmy mają do dyspozycji wyłącznie stare kompilatory i nie mogą wspierać tych nowszych. Natomiast wydaje mi się, że do nas jako programistów należy to, żeby forsować jak największą adaptację nowych standardów programowania. Ja sam staram się używać nowych standardów. I tak nie jestem w tym mistrzem, bo mam znajomych, którzy używają wszystkiego, co najnowsze – i ma to sens. Jeżeli mamy do dyspozycji nowszy standard bądź starszy, użyjmy nowszego, bo jest przyjemniejszy w użyciu. Oprócz tego, że nowsze standardy wprowadzają nowe możliwości języka, powodują też, że kod, który piszemy, który robi to samo, co moglibyśmy napisać, korzystając z funkcji ze starszego standardu, jest łatwiejszy w napisaniu. Czyli przyjemniej korzysta się z języka. Po co się męczyć, skoro można się nie męczyć? Dlatego lepiej korzystać z C++11, niż męczyć się C++03. Natomiast zdaję sobie sprawę z tego, że nie zawsze jest taka możliwość i wtedy należy dążyć do tego, aby używać C++11. Wydaje mi się, że po tych siedmiu latach od wprowadzenia standardu jest już najwyższa pora, aby się na to przestawić.
Powiedz o przykładowych czy kluczowych elementach, które zmieniły się od najstarszego C++. Jak to odnowienie wyglądało i jakie ciekawe elementy doszły?
Najważniejszą rzeczą, która pojawiła się w C++11, była tzw. semantyka przeniesienia. Wiązało się to z czymś, co nazywa się Rvalue References. Dało nam to narzędzie, dzięki któremu możemy dużo więcej zrobić, ponieważ funkcje, które wcześnie nie były dla nas dostępne, nagle stały się dostępne. Tu chodzi m.in. o optymalizacje związane z kopiowaniem obiektów. Zamiast bez potrzeby kopiować obiekty, co często jest czasochłonne, bo im więcej danych do skopiowania, tym więcej to trwa, bardzo często tej kopii można uniknąć. Semantyka przeniesienia, w której chodzi o to, że przenosimy zawartość jednego obiektu do innego obiektu, pozwala nam po pierwsze zoptymalizować pewne rzeczy, a po drugie wykorzystać ten mechanizm do realizacji takich rzeczy jak ułatwione zarządzanie pamięcią, które w pewnym sensie było zmorą języków typu C++. Dzięki tym mechanizmom mamy możliwość pozbyć się tego obciążenia i milej korzystać z tego języka.
Czy jest jakiś przykład typowej konstrukcji programistycznej, w której się to wykosztuje, tak żeby np. przez porównanie z językiem typu Java powiedzieć, co tu dostajemy?
Jest coś takiego, co nazywa się „inteligentnym wskaźnikiem”. To właśnie używa tego mechanizmu, o którym przed chwilą powiedzieliśmy. Polega na tym, że jeśli wcześnie zaalokowaliśmy sobie jakąś pamięć, to byliśmy odpowiedzialni za to, aby ją zwolnić, a inteligentne wskaźniki powodują, że korzystając z mechanizmu RAII – Resource Acquisition is Initialization, czyli pozyskanie zasobu jest jego inicjalizacją – wiążemy czas życia tego zasobu. Przez to rozumiemy tę zaalokowaną pamięć – z czasem życia jakiegoś obiektu w naszym programie. I tym obiektem jest właśnie ten inteligentny wskaźnik. On powoduje, że w momencie kiedy wskaźnik jest usuwany, usuwa tę pamięć, która gdzieś tam jest przez niego przechowywana.
Mamy różne rodzaje takich wskaźników, np. tylko jeden inteligentny wskaźnik może mieć dostęp do zaalokowanego bloku pamięci, czyli mówimy o tym, że on jest jego właścicielem. Albo jest taki, w przypadku którego własność może być współdzielona pomiędzy wiele wskaźników. W tym momencie ostatni wskaźnik, który przestanie używać tego bloku pamięci, automatycznie powoduje, że pamięć jest zwalniana. Tak naprawdę ciężko to porównać do mechanizmów typu javowego, bo w Javie naszym głównym dostępnym mechanizmem zarządzania pamięcią jest garbage collector, który działa troszeczkę inaczej. Natomiast porównując do Pythona, to Python ma zarówno garbage collector, jak i zliczanie referencji, które działa dokładnie tak samo jak te inteligentne wskaźniki w C++, o których powiedzieliśmy.
Wiem, że z tą wersją C++11 wiązano duże nadzieje, że to jest comeback C++, bo już wtedy zauważalny był trend przechodzenia do języków prostszych do nauczenia się, codziennego pisania czy zastosowania. Czy ta wersja to odnowienie i kolejne wersje C++ spowodowały, że wróciło szersze zainteresowanie językiem, czy jednak większość zastosowań, z którymi mamy obecnie do czynienia, powoduje, że firmy czy programiści wybierają inne języki?
Należałoby się zastanowić, czy to zainteresowanie kiedykolwiek odeszło, czy tylko może się ukryło. Wydaje mi się, że raczej się tylko ukryło. Eksplozja nowoczesnych języków programowania spowodowała, że zainteresowanie językami rozproszyło się na więcej z nich, natomiast nie zmienia to tego, że są pewne zastosowania, szczególnie związane z miniaturyzacją urządzeń, która zdecydowanie postępuje w dzisiejszym świecie, a to właśnie języki typu C czy C++ będą królowały albo będą istotnym uczestnikiem tego rynku. Dlatego wydaje mi się, że C++ zszedł raczej do podziemi, niż że znikło zainteresowanie nim.
Gdybyś miał komuś doradzić, czy warto uczyć się C++, i gdybyś dopytał, o jakiej karierze ten ktoś myśli w ramach IT, to co byś mu podpowiedział?
Na to pytanie można różnie odpowiedzieć w zależności od tego, jaki efekt chce się uzyskać. Zacząłbym od tego, że nigdy nie należy inwestować tylko w jeden język oprogramowania. Trzeba mieć dosyć szeroki warsztat, i to zarówno z języków ogólnego zastosowania, jak i np. z języków skryptowych. Natomiast jeśli mielibyśmy pójść w kierunku języka C++, to zdecydowanie uważam, że jest to dobra inwestycja. Rynek zdecydowanie nie zaniknie w najbliższym czasie. Wszystkie urządzenia, jak np. samochody czy AGD, stają się coraz bardziej inteligentne. A ta inteligencja pociąga za sobą to, że musi być w nich coraz więcej oprogramowania, które najczęściej pisane jest w języku C++. Jeżeli spojrzymy na rynek samochodów, to eksplozja nowoczesnych systemów typu IVI, czyli In-Vehicle Infotainment, przeważnie jest związana z tym, że te systemy realizuje się w C++.
Powiedzmy o obszarze zastosowań C++, czyli o systemach wbudowanych, o branży automotive. Czy są tam jasne przesłanki, dla których firmy podejmują decyzje, że korzystają właśnie ze stosu opartego o C++ albo innego? Bo korzysta się także z Pythona i Javy. Ma to na pewno związek z wydajnością tych rozwiązań. Czy ma to związek ze sprzętem, który jest tam wykorzystywany? Domyślam się, że jeżeli w tego rodzaju systemach wykorzystujemy sprzęt, który mocno różni się nawet między generacjami czy produktami, to programowanie tego na poziomie bliskim sprzętu może się bardzo różnić między tymi generacjami czy różnymi sprzętami. Czy decyzja może tu polegać na tym, że są jakieś izolujące biblioteki tego poziomu sprzętowego, co nam pozwala na jakąś „przenośność” kodu, czy ten element nie jest tu kluczowy?
Sam język C++ jako taki jest przenośny. Napisanie programu w gołym C++ spowoduje uruchomienie zarówno na jednym sprzęcie, jak i na innym, oczywiście po skompilowaniu odpowiednim kompilatorem. A więc to nie jest wielki problem. Moglibyśmy przyjrzeć się temu, co dzieje się na poziomie sprzętu. Mianowicie język C++ daje nam pełną kontrolę nad tym, jak ten program jest potem wykonywany. Czyli ta izolacja, o której powiedzieliśmy sobie dużo wcześniej – nazwałbym to tym, że programista nie musi martwić się o pewne szczegóły, jak wtedy, gdy korzysta z języków typu Java czy Python – bo robi to za niego sam język. W C++ często chcemy mieć tę kontrolę. Wchodząc na poziom sprzętu, zaczynamy zastanawiać się na tym, jak wygląda dostęp procesora do danych przy takiej albo innej implementacji. Jeżeli możemy mieć bardzo ścisły wpływ na to, jak ta implementacja działa na procesorze, to możemy uzyskiwać dużo większą wydajność niż w innym przypadku.
Natomiast wracając do twojego ostatniego pytania, rzeczywiście jest tak, że C++ jest tylko bazą i często musimy nabudowywać na nim jakąś dodatkową funkcjonalność. Istnieją frameworki, które pozwalają nam cieszyć się szerszą gamą możliwości, niż daje sam język. Ja używam frameworku, który nazywa się Qt, który jest dosyć mocno wykorzystywany w systemach typu embedded, w systemach biurkowych, czyli do takiego programowania na co dzień. Pewnie jest mniej wykorzystywany przy takich olbrzymich systemach, ponieważ tam zastosowania programowania są troszeczkę inne. Qt jest znane głównie z tego, że służy do implementacji graficznych interfejsów użytkownika, ale nie jest to jedyna funkcjonalność tego zestawu instrumentów. Mamy dosyć szeroką gamę możliwości, które są niezależne od platformy, na której programujemy, z tym że tę platformę rozumiałbym nie w sensie sprzętowym, tylko połączenia sprzętowo-programowego, czyli jako platformę możemy rozumieć system Windows albo Linux. Jeżeli używamy tego typu rozwiązań, to możemy mieć jeden kod źródłowy, który działa zarówno tu, jak i tu, i robi coś więcej, niż pozwala na to C++.
Czy zgodziłbyś się z takim stwierdzeniem, że od strony biznesowej decyzja o realizacji naszej aplikacji w systemie wbudowanym z C++ versus Python czy Java jest związana z tym, czy chcemy więcej zainwestować w czas programistów podczas tworzenia tego rozwiązania, być może trochę mniej dostępnych, ale później mieć aplikację, która może wykorzystać pełne spektrum tego sprzętu i działać efektywniej niż aplikacje w innych językach, natomiast gdybyśmy podjęli decyzję o programowaniu w języku wyższego poziomu czy interpretowanym, to wtedy bardziej liczylibyśmy na to, że to wystarczy i dzięki temu zaoszczędzimy czas na etapie implementacji?
Kiedyś było takie poczucie, że sprzęt był drogi, programista był tani. Wtedy programista musiał się bardziej nastarać, ponieważ miał dostępny sprzęt taki, jaki miał, i nie mógł liczyć na to, że dostanie lepszy. Teraz sytuacja się odwróciła i bardziej jest tak, że sprzęt jest tani, a programista – drogi. Często bardziej opłaca się dołożyć te 100-200 dol. czy nawet 20 tys. dol. do tego, aby kupić lepszy sprzęt, niż męczyć się dużo dłużej czy dużo drożej z oprogramowaniem tego sprzętu. W momencie gdy mówimy o jednym serwerze, może rzeczywiście lepiej wydać te 20 tys. dol. Natomiast jeśli mówimy o 100 mln samochodów, to sytuacja jest zupełnie inna. Wtedy opłaca się przyciąć na sprzęcie, a zapłacić więcej dobremu programiście. Nam się może wydawać, że w samochodach, które są nowoczesne, jest nie wiadomo jak mocny sprzęt – bo jesteśmy przyzwyczajeni do telefonów komórkowych, które mają naprawdę mocny sprzęt w sobie. Ale zapewniam, że to, co jest w telefonie, jest dużo mocniejsze niż to, co potem ląduje np. w telewizorze czy w samochodzie. Oszczędność na tym sprzęcie jest ogromna. Trochę mniej ma to znaczenie w przypadku systemów biurkowych. Natomiast wydaje mi się, że tu rolę odgrywa stabilność i przewidywalność tego oprogramowania. Wydaje mi się, że oprogramowanie napisane w językach ogólnie niższego poziomu jest bardziej stabilne niż takie, które jest napisane z większym użyciem abstrakcji, już np. nie wchodząc w to, jak działa Java, która w dowolnym momencie może sobie postanowić, że teraz będzie zwalniała pamięć i przyblokuje nam korzystanie z programu w sposób bardziej lub mniej widoczny. Im mocniejszy mamy sprzęt, tym będzie to mniej widoczne, ale jeżeli mamy przeciętny sprzęt, to możemy takie zacięcie odczuć. W przypadku C++ nie ma takiej możliwości, ponieważ to my sami jako programiści odpowiadamy za moment, kiedy tę pamięć możemy zwolnić. Oczywiście możemy korzystać z mechanizmów zarządzania pamięcią przez te inteligentne wskaźniki, natomiast koniec końców to ja jako programista podejmuję decyzję, że to jest dobry moment na zwolnienie pamięci, i to ja biorę za to odpowiedzialność.
Jaka jest ścieżka kariery dla osoby, która właśnie chciałaby podjąć pracę przy programowaniu takich systemów jak embedded czy właśnie w samochodach. Jeżeli mamy aplikacje webowe, to wszyscy wiedzą, jakie technologie można poznać, wszyscy mają tego samego Springa w Javie czy framework typu Angular, generalnie jest na ten temat mnóstwo podręczników i materiałów i wszyscy piszą w tym samym. Natomiast jeśli pójdziemy do firmy X produkującej samochody, to ona ma własne rozwiązania. W jaki sposób programiści mają się przygotować do tego rodzaju pracy, zdobyć doświadczenie, dojść do takiego etapu, w którym staną się pełnoprawnymi programistami zatrudnionymi do takiego zadania i będą efektywnie wykonywać swoją pracę?
Na szczęście nie jest tak źle, że co firma, to w ogóle co innego. Jeśli chodzi o rynek samochodów, to jest coś takiego jak inicjatywa GENIVI, która wzięła sobie za cel ustandaryzowanie rynku automotive i pewne standardy oprogramowania, jak co powinno wyglądać, są tam zdefiniowane. Jeżeli chcemy zajmować się akurat tym konkretnym rynkiem, to zakres technologii, który musimy poznać, w zasadzie jest znany. Oczywiście nie wszyscy stosują ten standard. Ale pewnie ci najwięksi gracze na rynku starają się albo dostosowywać do tego, albo wręcz kreować ten standard, bo to jest moim zdaniem częstszy przypadek. Na innym rynku, z którym mam do czynienia, czyli na rynku transportu publicznego, też coś podobnego w tej chwili właśnie ma miejsce. Firmy, które są w to zaangażowane, starają się kreować standardowe rozwiązania, żeby kupując różne komponenty od różnych dostawców, koniec końców ten autobus, w którym to wszystko ląduje, był w stanie dogadać ze sobą te wszystkie części, by to działało. Jeśli akurat ktoś jest tym zainteresowany, to może sobie znaleźć odpowiednie dokumenty w Internecie, będzie miał pewien zakres technologii, które musi poznać.
Natomiast niezależnie od tego pewną bazę zawsze warto znać. Uważam, że jeśli chodzi o język C++, to warto uczyć się tych najnowszych standardów, również tych, które są przed nami, ponieważ czekają nas bardzo duże i bardzo istotne zmiany, zarówno w roku 2020, jak i w tym 2023. Jeśli ktoś świetnie pozna standardy, to potem nauczenie się jednego czy drugiego frameworku czy biblioteki nie będzie stanowiło dla niego problemu, bo będzie zarówno zaznajomiony ze sposobem czytania dokumentacji i rozumienia jej, jak i będzie musiał mieć pewnie trochę styczności ze sprzętem. Zawsze można zainwestować naprawdę nieduże pieniądze w rozwiązania typu Raspberry Pi, Arduino czy całą inną gamę dostępnych na rynku urządzeń, bardziej bądź mniej zabawowych, otworzyć sobie YouTube’a na komputerze, wklepać odpowiednie hasła do wyszukiwarki i wyjdzie mnóstwo projektów, które można zrealizować, często gotowych przepisów od A do Z, od których można zacząć robić różne ciekawe urządzenia typu inteligentne lustro, które do ciebie rano gada i mówi, co masz dzisiaj zaplanowane – sam widziałem takie rozwiązania. Można bawić się w takie rzeczy jak zrobienie automatycznej kolejki dla dziecka – gdy ono sobie coś powciska, to ona będzie się zatrzymywać i jechać, semafor będzie się podnosił i opuszczał. Nie jest to takie trudne, a zaznajamia ze sprzętem, dzięki temu czujemy się swobodniej w tym środowisku.
Powiedziałeś, że warto mieć tę bazę opanowaną. Czy stanowi ją C++ ze standardami, czy są jeszcze jakieś biblioteki? Wspominałeś o Qt. Czy to uważa się teraz za na tyle często używane, że warto je poznać jako taki podstawowy zbiór narzędzi programisty czy to systemów wbudowanych, czy innych, które w C++ wykorzystujemy?
Qt rzeczywiście nie jest standardem. Natomiast po pierwsze stara się być zgodne ze standardami i używać tych nowych technologii, które w C++ się pojawiają, a tak naprawdę jest bardzo często wykorzystywanym rozwiązaniem na różnych rynkach, od tych najmniejszych do największych. Uważam, że zdecydowanie warto poznać ten framework, nie jest on trudny do nauczenia się w stopniu pozwalającym na w miarę swobodne korzystanie, a daje nam duże możliwości. Sam pamiętam, gdy na studiach miałem zrobić projekt z czegokolwiek i potem trzeba było zaprezentować jakoś te wyniki. Człowiek zastanawiał się, jak to zrobić. Zaczynało się od próby ASCII-Arta i wypisywania w konsoli. Miałem taką sytuację, że nawet generowałem stronę HTML w programie i potem ją otwierałem w przeglądarce. Ale zamiast tego można po prostu wykorzystać rozwiązanie, które do tego służy – a Qt jest świetnym rozwiązaniem do tworzenia interfejsów graficznych – i po pierwsze, zaoszczędzić sobie pracy, a po drugie, mamy tę wartość dodaną, że to, co zrobiliśmy, wygląda i działa sensownie, można komuś to pokazać i się nie wstydzić.
Dodatkowo, jeśli chodzi o ten konkretny framework, w tej chwili istotną jego częścią jest coś, co nazywa się Qt Quick i o ile nie jest związane z samym C++, tylko bardziej właśnie z technologiami nowoczesnymi typu Java Script, to możemy łączyć ze sobą tę technologię, która daje nam możliwość kreowania nowoczesnych, migających, poruszających się interfejsów graficznych, często związanych z urządzeniami dotykowymi, z całą tą bazą, w której logikę mamy zaimplementowaną w języku C++.
Powiedz mi jeszcze kilka słów na temat samego Qt. Stwierdziłeś, że to w dużej mierze jest kwestia interfejsu graficznego, ale nie tylko. Czy jest to interfejs okienkowy w takich systemach jak Windows czy Linux, czy w innego rodzaju systemach, czy właśnie w systemach wbudowanych, gdzie być może te urządzenia do wyświetlania czy do zbierania feedbacku od użytkownika są bardziej ograniczone i ten interfejs wygląda jakoś inaczej?
Zdecydowanie są to różne urządzenia. Z takimi, które normalnie mamy na biurku, wchodzimy w interakcje za pomocą myszki, klawiatury. Zaczyna pojawiać się interfejs dotykowy – mamy ekrany dotykowe – ale te programy, te interfejsy są złożone, składają się z wielu elementów. Jeżeli spojrzymy na edytory tekstów, które mają mnóstwo różnych ikonek, mnóstwo elementów, które możemy złapać, przesunąć, to ten interfejs jest bardzo skomplikowany. Takie rzeczy lepiej robi się w technologiach klasycznych. Często określa się je jako widżet, czyli to są takie elementy, gdzie prostokąty zawarte są w prostokątach, czyli możemy podzielić sobie ekran na pewien zestaw obszarów prostokątnych i każdy taki obszar rozpatrywać oddzielnie. Natomiast jeśli chodzi o zminiaturyzowane urządzenia, typu tablety, zegarki, telefony, panele różnych sterowniczych urządzeń, które dotykamy palcem, to musimy mieć świadomość, że palec ma pewną wielkość. Jeżeli te elementy będą bardzo blisko siebie, to nie będziemy w stanie wejść z nimi w interakcję. Siłą rzeczy te interfejsy muszą być prostsze. Natomiast czego innego od nich oczekujemy. Jeżeli przesuniemy palec na ekranie, to oczekujemy, że to, co jest pod nim, przesunie się razem z nim. Te interfejsy są bardziej dynamiczne, ruchome. Oczekujemy, że to, jak będzie się taki interfejs zachowywał, zbliżone będzie bardziej do świata fizycznego, który obserwujemy, a wiadomo, że w prawdziwym świecie nic nie pojawia się znienacka, prędkość jest ograniczona i jeśli coś ma się pojawić, to musi na początku pojawić się mniej, potem więcej, wjechać albo się wyłonić z niebytu.
Te interfejsy zupełnie inaczej się zachowują, dlatego technologie, których możemy chcieć używać, są inne. I o ile w przypadku Qt będziemy używać widżetów, o tyle w przypadku nowoczesnym będziemy używać właśnie Qt Quicka, który jest oparty na języku QML – to jest język deklaratywny, więc nie mówimy w nim, co krok po kroku ma się wydarzyć, tylko bardziej opisujemy efekt, który chcemy osiągnąć. Czyli że w tym miejscu ma być kwadrat, który jest czerwony i ma się obracać. Już samo środowisko ma wiedzieć, jak ma to zrealizować, i my się tym nie zajmujemy. Czyli poziom abstrakcji jest dużo wyższy i bardziej zbliżony do języków nowoczesnych, jak Java Script czy Python. Język QML jest wspomagany przez JavaScript, a o programistów JavaScript jest teraz łatwo, dlatego możemy wspomagać się takimi osobami. Dobrze jednak by było, gdybyśmy troszeczkę warsztatu z tego mieli. Interfejs użytkownika tworzymy więc w tym, a dane do tego interfejsu eksponujemy z poziomu C++. Czyli tak naprawdę taki nowoczesny interfejs użytkownika jest zorientowany na to, żeby był sterowany danymi, które nam się pojawiają. Jeżeli mamy piekarnik i w nim coś się dzieje, to otrzymujemy z niego pewne dane: temperaturę, długość trwania pieczenia, co w środku jest albo co robimy. I te dane wysterowują nam interfejs użytkownika, mówią, co my chcemy pokazać użytkownikowi. Właśnie na tym polega deklaratywność interfejsu użytkownika. Języki typu Python, Java, C++ to są języki imperatywne, czyli krok po kroku mówimy, co program ma wykonać, jaki algorytm ma zrealizować. To programowanie jest zupełnie inne, więc musimy rozróżnić to jako dwa różne światy, ale powinniśmy uczestniczyć i w jednym, i w drugim.
Ale Qt to nie tylko interfejs. Co jeszcze Qt nam daje i jak ułatwia tworzenie aplikacji?
To jest cała gama różnych technologii, począwszy od fundamentów, które są związane z obsługą zdarzeń, z tym, że możemy łatwo przetłumaczyć aplikację na różne języki, dzięki czemu możemy użytkownikom w różnych językach ją pokazać. Na tym mamy nabudowany interfejs graficzny, obok tego mamy dostęp do sieci, czyli możemy tworzyć klientów czy serwery sieciowe, mieć dostęp do webserwisów, dzięki którym możemy pobierać dane bądź aktywować jakieś zdalne funkcjonalności. W Qt mamy też moduł związany z obsługą baz danych, dzięki czemu w taki sposób „agnostyczny” do tej samej bazy danych możemy się z nią komunikować. Mamy moduły związane z dostępem do konkretnego sprzętu, np. chcemy obsłużyć Bluetooth czy NFC, które w tej chwili są bardzo popularnymi technologiami – mamy do tego odpowiednie rzeczy. Chcemy sczytać dane z GPS, które są urządzeniem wbudowanym – jest taka możliwość. Chcemy wyświetlić film czy puścić dźwięk – mamy gdzieś daną abstrakcję. Implementacja na wszystkie platformy, które Qt obsługuje, też mamy daną. Dzięki temu, gdybyśmy chcieli, to ten sam kod napisany na jedną platformę, czyli np. na platformę biurkową, moglibyśmy odpalić na platformie z Androidem, na iPhonie czy na innych urządzeniach.
Czy Qt jest monopolistą w świecie C++, jeśli chodzi o tego rodzaju biblioteki czy frameworki, czy są jakieś alternatywy równie popularne?
Nie jest monopolistą. Jeśli chodzi o świat widżetów, to są alternatywy, natomiast jako całość ma najszerszą gamę możliwości. Tak naprawdę mamy wybór taki, że albo użyjemy 10 różnych technologii i spróbujemy pożenić je ze sobą, albo użyjemy jednej technologii i będziemy mieli to samo, co mamy w tych dziesięciu. Wybór należy tu do konkretnej osoby czy zespołu, który ma zrealizować konkretną rzecz. Bo czasami jest tak, że mamy pewne technologie narzucone, a czasami jest tak, że mamy wybór. Tam, gdzie mamy wybór, wybierzmy to, w czym najmniej się narobimy. Wydaje mi się, że łatwiej jest nam pracować z jedną wspólną technologią, która robi te wszystkie 10 rzeczy, niż męczyć się z tym – a czasami to jest naprawdę męczarnia – żeby połączyć ze sobą rzeczy, które zostały tak zaprojektowane, że nie bardzo ze sobą współgrają, bo jedno ma pewną naturę, a drugie – zupełnie inną. Okazuje się, że prawidłowe połączenie tych technologii jest problematyczne.
Jak wygląda współczesny warsztat w programistyce C++? Czy środowisko narzędziowe jest tak samo rozbudowane jak w przypadku takich języków jak Java, w sensie: inteligentne idee, narzędzia do analizy kodu czy jakieś biblioteki i narzędzia do testowania? Czy tu ta łatwość dla programisty w tej codziennej pracy rozwijania kodu, testowania go i np. syntaktycznego wykrywania błędu zbliża się do tego, co mamy w innych językach, czy tych narzędzi jest jednak mniej?
Narzędziowo jest bardzo bogata, ponieważ to są języki z dużą tradycją – jak np. C++. Te narzędzia też mają dużą tradycję i jak najbardziej są takie zintegrowane środowiska, które zajmują się tymi językami. Często są to te same środowiska, których używamy w Javie. Najbardziej typowe środowiska programistyczne dla języka C++ to Visual Studio Microsoftu, Eclipse, Qt Creator, pewnie moglibyśmy wymienić jeszcze kilka z nich. Wszystkie mają te standardowe rzeczy, które dobre środowisko developerskie powinno mieć. Czyli mają podświetlanie składni, pomagają programiście wybierać funkcje, które są zgodne z tym, co on zamierza zrobić, które mają wbudowany Debugger, czyli pozwalają nam krok po kroku śledzić, co robi program, korzystając ze wsparcia sprzętowego procesora. Mają narzędzia do statycznej czy dynamicznej analizy kodu, potrafią nam w tej chwili powiedzieć, jaki błąd zrobiliśmy, zanim w ogóle będziemy próbowali cokolwiek skompilować i uruchomić. Często potrafią nam podpowiedzieć, w jaki sposób zrefakturyzować kod. Narzędziownia jest bardzo bogata zarówno pod takim względem, jak i np. pod względem testowania. Jest bardzo dużo bibliotek do testów jednostkowych. Qt też ma własną, bardziej lub mniej ograniczoną. Bardzo popularną biblioteką do testów jednostkowych jest biblioteka opracowana przez Google.
Tych wszystkich rozwiązań jest bardzo dużo. Zarówno mamy testowania na poziomie jednostkowym, jak i na wyższym poziomie integracyjnym, systemowym. To wszystko jest. Nie jest tak, że czegoś brakuje. Narzędzia nie są tak naprawdę wielkim problemem do napisania. Bardziej liczy się pomysł na to, co to narzędzie miałoby robić: czy ono robi to dla tego języka, czy innego, tak naprawdę ma drugorzędne znaczenie. Technologie migrują w jedną i drugą stronę. Jeżeli mówimy o technologiach webowych, to w pewnym momencie pojawiły się takie rzeczy jak inspektor kodu, coś, co pozwala nam przejrzeć, jak wygląda drzewo w JavaScripcie, w HTML-u. Pozwala nam zobaczyć, jak wygląda alokacja pamięci przez program javaskryptowy. To samo w zasadzie mamy w językach C++. Powiedziałbym nawet, że w tych językach niskopoziomowych jest łatwiej, ponieważ jesteśmy bliżej sprzętu i możemy zbierać więcej danych związanych z połączeniem pomiędzy sprzętem a programem. Często ludzie, którzy patrzą na kod asemblerowy, czyli taki naprawdę najniższego możliwego poziomu, który z tego kodu C++ w pewnym sensie automatycznie dostajemy, widzą konkretne instrukcje, które ten procesor wykonuje. Są w stanie zobaczyć, co się tam dzieje. Zresztą na pewnym poziomie musimy patrzeć na rzeczy związane ze sprzętem, wiedzieć, jak działa stos, sterta, czyli te różne obszary w alokacji pamięci, które mają różne charakterystyki. W językach typu JavaScript nie zastanawiamy się nad stosem czy stertą, ale one też tam są.
Wspominałeś, że wiele języków wyższego poziomu, w szczególności Python, tak naprawdę pod spodem często używa fragmentów kodu czy bibliotek C++ ze względu na wydajność. To jest stosowane szczególnie w Pythonie, w bibliotekach numerycznych. Czy to jest taka sytuacja, która powtarza się często w pracy nad aplikacjami, które rozwijałeś? Czy w realnej pracy zdarza się, że zespół jest podzielony i w związku z tym, że jest więcej programistów Pythona, przygotowuje się dla nich jakieś niskopoziomowe fragmenty w C++, z których oni później dalej korzystają w Pythonie? Czy raczej z takimi sytuacjami mamy do czynienia właśnie na poziomie bibliotek, jak w Pythonie?
Jedna rzecz, o której trzeba wspomnieć, to to, że Python nie wziął się znikąd, tylko wymaga interpretera, który jest napisany typowo w C++. Jeżeli mówimy o maszynie wirtualnej Javy, to ona mogłaby być napisana w Javie, ale gonimy własny ogon. W pewnym momencie z tej Javy trzeba wyjść. I w czym jest napisana? W C++. Mówiąc o JavaScripcie, mamy na myśli przeglądarki internetowe. Bardzo polarnym silnikiem przeglądarki jest Chromium. Jest to silnik rozwijany przez Google, na którym chodzi Google Chrome. On jest napisany w C++. Wszystkie tego typu rozwiązania muszą korzystać z języków niższego poziomu. Zawsze, korzystając z Pythona – nawet jak nie korzystamy z bibliotek zewnętrznych, które napisane są w C++ – i tak korzystamy z C++, bo w bibliotekach, które nawet są napisane w Pythonie, pod spodem C czy C++ jest obecny.
Jeśli chodzi o moją pracę, to bardziej bym powiązał ją z JavaScriptem niż z Pythonem. Nieprzypadkowo powiedziałem o silniku Chromium. W jednej z moich ostatnich prac my jako programiści C++ pracowaliśmy nad modyfikacjami do tego silnika związanymi z platformami telewizyjnymi, czyli jako programiści C++ dostarczaliśmy środowisko, które tak naprawdę realizuje silnik javascriptowy, silnik HTML z rozszerzeniami, które potrzebne są do tego, aby coś na tym telewizorze robić związanego z telewizją. Potem firmy, które kupowały od nas ten produkt, mogły już wykorzystywać swoich programistów JavaScript do tego, żeby coś na tym robić.
Jakie są perspektywy na przyszłość, jeśli chodzi o rozwój języka C++?
Tendencja jest taka, żeby C++ coraz więcej robił w trakcie kompilacji programu, a nie w trakcie jego uruchomienia. Czyli jeżeli da się coś policzyć wcześniej raz, to policzmy to wcześniej, miejmy już w kodzie wykonywalnym programu wynik tych obliczeń, a nie że za każdym razem będziemy to liczyć. Te ostatnie standardy już poczyniły kilka ważnych kroków, aby to ułatwić. Najbliższe standardy, które nas czekają w latach 2020 i 2023, wprowadzają takie istotne rozwiązania jak koncepty i metaklasy. Koncept jest to coś, co pozwala nam bardziej abstrakcyjnie myśleć o algorytmach, które implementujemy i które rzeczywiście w dużej mierze będą się wykonywały w trakcie budowania programu, a nie jego wykonywania. Natomiast metaklasy to jest ogólnie taki mechanizm, który jest obecny w różnych językach programowania i, jak sama nazwa wskazuje, słowo „metaklasa” mówi coś o klasie. Ona pozwala nam w bardziej abstrakcyjny sposób budować klasy, czyli to są te główne bloczki, z których składa się oprogramowanie w C++. Dzięki temu będziemy mieli większy zakres możliwości i większy wpływ na to, co np. kompilator będzie nam generował podczas budowania programów. W tej chwili te rzeczy są określone na sztywno w standardzie C++, natomiast chodzi o to, żeby te sztywne ramy rozluźnić. Metaklasy, których używałem w Pythonie, pozwalają nam w taki bardziej abstrakcyjny sposób tworzyć to oprogramowanie. A im większy coś ma stopień abstrakcji, tym do większej liczby zastosowań się nadaje. Zdecydowanie jest to krok w dobrą stronę.
Druga rzecz, która wydaje mi się równie istotna, to właśnie takie uprzyjemnienie korzystania z C++, bo nastąpił taki moment, kiedy używanie C++ stało się względnie trudne, i może z tym moglibyśmy wiązać przejście C++ do podziemia, w tym sensie, że ta krzywa uczenia się nagle zrobiła się dosyć stroma, bo trzeba było zrozumieć dosyć zaawansowane składniowo koncepcje z tego języka. Natomiast właśnie te zmiany, w których kierunku idziemy, pozwalają nam łatwiej i bardziej abstrakcyjnie widzieć to oprogramowanie, te konstrukcje, które mniej wyglądają jak jakiś bełkot, a bardziej wyglądają jak zdania w języku naturalnym – to jest coś, z czego szczyci się Python, że kod napisany w tym języku jest niezupełnie poprawnym, ale w miarę poprawnym składniowo zdaniem w języku angielskim.
Czy popularność takich urządzeń, które na każdym kroku spotykamy, które są programowalne, a kiedyś nie były – samochody, kawiarki, zegarki, głowice termostatyczne – spowoduje, że wrócimy do trendu programowania bardziej niskopoziomowego i w związku z tym zapotrzebowanie na programistów znających te koncepcje jeszcze wzrośnie, czy też postępująca szybkość sprzętu, która w tych wbudowanych systemach jest wykorzystywana, spowoduje, że tak czy siak będzie się tu wykorzystywać takie języki interpretowane czy wyższego poziomu?
Jeśli chodzi o wydajność sprzętu, to przy obecnej technologii powoli docieramy do ściany. W nieskończoność nie da się tego skalować, zmniejszać procesu technologicznego, więc to nie będzie tak, że procesory z czterech gigaherców będą miały częstotliwości 40 gigaherców. Problem tak naprawdę nie jest w częstotliwości procesora, tylko w prędkości odprowadzania ciepła z niego. Tu naprawdę trafiliśmy na ścianę. To spowodowało, że pierwsza ściana została odsunięta tym, że pojawiły się procesory wielordzeniowe. One powodują, że możemy mieć podobną moc obliczeniową przy dużo mniejszym wygenerowaniu ciepła. Ale to jest tylko odsunięcie tej ściany i na pewno nie da się do urządzenia typu zegarek zamontować mocnego procesora, który będzie się mocno grzał, bo użytkownik to zauważy. Ma z tym kontakt cały czas i nie da się tego ciepła odprowadzić, bo ono nie zniknie, praw fizyki nie zmienisz.
Można powiedzieć, że znajomość niskopoziomowych koncepcji programistycznych zawsze będzie w cenie, bo nawet jeśli jesteśmy programistami języków wysokopoziomowych, to wiedza o tym, jak ta maszyna pod spodem działa i jak to się programuje, nie zaszkodzi nam, a raczej sprawi, że dzięki temu będziemy lepszymi programistami, a być może poszerzą się perspektywy programowania systemów wbudowanych czy innych, gdzie jest to wręcz często koniecznością.
Witold, dzięki za rozmowę. Podzieliłeś się mnóstwem ciekawych informacji, szczególnie dla tych, którzy odeszli od tego rodzaju systemów czy tego rodzaju języków. Przybliżyłeś trochę inną część IT. Jeszcze raz dzięki za rozmowę i do usłyszenia następnym razem!
Ja również dziękuję i do usłyszenia!