Nasza strona używa cookies. Korzystając ze strony, wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki. Rozumiem

Rekrutacja techniczna w C++ - na co zwracać uwagę

Karol Kontny Programmer C++
Poznaj 10 ważnych zagadnień technicznych, o które powinieneś zapytać przyszłego pracodawcę na rozmowie kwalifikacyjnej na przykładzie C++.
Rekrutacja techniczna w C++ - na co zwracać uwagę

Podczas moich pierwszych rekrutacji podczas rozmowy w końcu dochodziło do momentu kiedy to ja mogłem zadawać pytania, niestety wtedy nie potrafiłem wymyślić nic sensownego, o co mógłbym zapytać. Zdobywając doświadczenie i widząc (najczęściej) różne problemy i niedociągnięcia we własnej firmie, dowiedziałem się, o co pytać kolejnego potencjalnego pracodawcę, żeby nie trafić do organizacji, w której jest co najmniej tak samo kiepsko, jak w tej, w której aktualnie pracowałem. 

W tym artykule chcę się zająć rzeczami stricte technicznymi, głównie związanymi z C++ — językiem, w którym głównie programuję. Poza tymi pytaniami są jeszcze inne, których nie będę w tym artykule omawiał — mam nadzieję opisać je w przyszłości, przy innej okazji. Jeżeli nie jesteś programistą C++, to i tak zachęcam do przeczytania tego tekstu — część z tych zagadnień pewnie dość łatwo odnieść do innych technologii i na tej podstawie stworzyć własną listę pytań.

Przede wszystkim musimy rozmawiać z osobą techniczną — najlepiej członkiem zespołu, do którego mamy trafić, jeżeli przejdziemy rekrutację. Taka osoba będzie umiała najbardziej kompetentna. Osoby rekrutujące i zarządzające, z którymi mamy kontakt na różnych etapach rekrutacji, najczęściej nie znają się na technologiach, więc nie będą umieć odpowiedzieć na szczegółowe pytania. Warto dopytywać nawet o rzeczy, które zostały napisane w ogłoszeniu. Czasami, te technologie okazują się czym innym w rzeczywistości i są wpisywane dla reklamy, często niestety reklama wygląda znacznie lepiej niż rzeczywistość.


1. Standard języka używanego w projekcie

To chyba najważniejsza informacja dla nas. Oprócz oczywistej rzeczy, w jakim języku (C++) będziemy programować, jakiej biblioteki standardowej używać — mówi to sporo o projekcie i podejściu osób odpowiedzialnych za dobór technologii. Dziś kiedy, kończy się rok 2021, oczekiwałbym, że do tworzenia oprogramowania będziemy używać wersji co najmniej C++17 - jest ona dobrze wspierana przez każdy poważny kompilator, stanowi też spore ulepszenie od C++14 - ten standard to sporo przydatnych nowości.

Oczywiście najlepiej byłoby gdyby projekt był tworzony przy użyciu C++20 (dziś), albo najnowszego dostępnego standardu w kompilatorze (mam nadzieję, że ten tekst będzie czytany także w przyszłości). Ogólnie podejście do standardu C++ mówi bardzo dużo o firmie, projekcie, liderach technicznych itp. Przykrym standardem jest podejście "Jak ten projekt startował 4 lata temu, to wzięliśmy nowy kompilator, biblioteki i od tego czasu nie były one aktualizowane". Od takich projektów i podejścia radzę się trzymać z daleka.

Bieżąca aktualizacja kompilatorów i bibliotek to oznaka, że w firmie poważnie podchodzą to tematu zmian w technologiach, chęci rozwijania umiejętności (która to w niektórych firmach to tylko puste hasło) oraz po prostu ułatwiania sobie pracy przez najnowsze dostępne rozwiązania. Podejście "działa, to nie ruszać" jest najgorszym z możliwych.bOwszem, czasami zmiana kompilatora na nowszy powoduje, że nasz kod nie działa, ale to w prawie zawsze oznacza, że to u nas jest coś nie tak i nowe narzędzie po prostu nam to sygnalizuje.

Dlatego też warto pracować na zaktualizowanych narzędziach. W takim wypadku należy po prostu siąść i błąd naprawić. Jeżeli projekt, do którego mamy trafić wykorzystuje starszy standard, to należy dopytać, dlaczego jeszcze tego nie zmieniono (czasem trafi się naprawdę dobry argument), czy są w najbliższej przyszłości takie plany lub, czy będzie można się osobiście tym zająć, jeżeli będziemy zainteresowani współpracą z daną firmą. Na pewno radzę uciekać jeżeli usłyszycie coś w stylu "bo klient tak chce" albo "aktualizacja wymagałaby dużo pracy".


2. Kompilatory

Wiąże się mocno z punktem 1, ale to troszkę inna rzecz: jakie i w jakich wersjach są używane kompilatory w projekcie. Czy projekt powstaje na wiele platform (np. na Windowsa używamy MSVC, a na Linuxa GCC)? Jeżeli tak to na jakie? Często w projektach powstających na wiele platform, przy użyciu wielu kompilatorów wybierany jest dość niski standard C++ "taki na wszystkim działa", jednak w ostatnich latach nawet kompilator Microsoftu, który wcześniej mocno odstawał od GCC i Clanga pod względem wsparcia dla nowych standardów, poszedł mocno do przodu i często implementuje nowe funkcjonalności przed konkurencją.

Kompilowanie kodu wieloma kompilatorami, ma tę zaletę, że może wyłapać nam więcej błędów i potencjalnych problemów. Niestety czasami w kompilatorach są błędy i poprawny z punktu widzenia standardu kod nie działa, wtedy jest to problem i trzeba sobie z nim radzić. Używanie jednego, zwłaszcza w antycznej wersji może prowadzić do niechęci do zmian, gdyż każda wywołałaby potrzebę naprawiania dużej ilości kodu.


3. Podejście do funkcjonalności C++, paradygmat programowania

C++ jest bardzo skomplikowanym językiem, który w wielu aspektach nie narzuca stylu programowania, także bardzo szerokim, jeżeli chodzi o funkcjonalności, który udostępnia programistom bardzo wiele narzędzi, których mogą używać. Zespół musi sam wybrać, jakiego sposobu programowania, których funkcjonalności będzie używał. Najczęściej mamy do czynienia z paradygmatem obiektowym programowania, ale C++ nie jest ściśle obiektowym językiem, więc są inne możliwości lub używanie różnych paradygmatów na różnych poziomach architektury projektu. Więc pytanie, czy korzystamy z podejścia obiektowego albo na przykład Data Driven jest bardzo zasadne. 

Funkcjonalności, czyli jakie jest podejście do takich spraw jak na przykład używanie słowa kluczowego "auto" - w środowisku C++ jest wiele zupełnie sprzecznych opinii kiedy, jak i ile powinno się z tej funkcjonalności korzystać. W tym momencie nie będę starał się argumentować za i przeciw (osobiście jestem gorącym zwolennikiem użycia auto, gdzie jest to możliwe), tylko zwrócę uwagę, że łatwiej nam będzie pracować w środowisku, które ma podobne poglądy do naszych albo chociaż potrafi przedstawić rozsądne argumenty za swoją opinią.

Kolejną dużą funkcjonalnością, co do której są różne podejścia, są szablony. Pamiętam sytuację kiedy kod kolegi, który rozwiązał problem dzięki technikom metaprogramowania w szablonach został podczas code review skrytykowany właśnie za użycie tych technik. Pojawiły się argumenty, że to skomplikowane i wiele osób tego nie zrozumie. Ostatecznie implementacja została przepisana na kod działający w runtimie, a nie czasie kompilacji, obiektywnie gorszy, co oczywiście jest bez sensu.

Oczywiście techniki szablonowe, które rzeczywiście są dość skomplikowane, należy używać tam, gdzie jest sens, gdzie rozwiązują dobrze jakiś problem, nie w każdym możliwym miejscu, ale argumentacja, która w tym przypadku została przedstawiona, świadczy o tym, że poziom techniczny w tamtym zespole był dość niski i pewnie rzeczywiście wiele osób nie rozumiało szablonów w C++. Pewnie nie chcemy pracować z ludźmi, którzy nie za bardzo ogarniają język, w którym programują i nie wymagają od zespołu, żeby podwyższał swoje kompetencje.


4. IDE 

Warto wiedzieć, czy jest jakieś narzucone IDE (np. MSVS, QtCreator) czy możemy sobie wybrać swoje ulubione narzędzie i czy projekt będzie w nim dobrze działał (patrz punkt kolejny). Tutaj często wychodzi podejście pracodawcy do kupienia swoim pracownikom licencji na narzędzia do pracy. Na przykład: nie kupimy wam CLiona czy MSVC, mimo że znacznie lepiej by się z tym pracowało, bo musimy zaoszczędzić jakieś marne grosze (w porównaniu z wypłatą programisty). Skoro macie śrubokręty, to po co Wam wkrętarka, przecież można oboma tymi narzędziami osiągnąć to samo? Cóż, takie firmy są, nawet nierzadkie. Uciekać.


5. Build system 

Czyli w jaki sposób budowany jest projekt, nad którym będziemy pracować. Niestety ten temat jest w C++ straszną bolączką, gdyż C++ powstawał w czasach kiedy nikt jeszcze nie myślał o takich rzeczach jak np. menadżery pakietów i dlatego budowanie projektów w C++ bywa co najmniej uciążliwe. Czy w projekcie jest używane jakieś w miarę popularne i uznawane za standardowe narzędzie np. CMake - (mimo wszystkich wad i skomplikowania, to jest dobre narzędzie, które działa), Bazel albo jakieś "magiczne" skrypty w Makefilach czy Pythonie.

Te pierwsze rozwiązania są wieloplatformowe oraz dają się w miarę łatwo integrować z jakimiś zewnętrznymi bibliotekami. W tym drugim przypadku wiedza o tym jak takie wynalazki działają, często jest znana tylko autorom tych skryptów, może być trudno je zintegrować z jakimiś bibliotekami albo działają one tylko na jednej platformie. Ja generalnie preferuję rozwiązania w miarę standardowe, dobrze i szeroko przyjęte w społeczności programistów oraz szeroko udokumentowane w Internecie.


6. Formatowanie kodu, wytyczne stylu 

Dziś w 2021 roku, standardem powinno być używanie narzędzia clang-format do automatycznego formatowania kodu. W różnych firmach wytyczne stylu będą różne, czasami lepsze, czasami gorsze. Jednak najważniejsze, żeby jakieś był i były jasno zdefiniowane za pomocą tego narzędzia, żebyśmy nie musieli zajmować się sprawami takimi jak, pamiętanie o tym czy postawić spację, tu czy tam, gdzie złamać linię, jak zorganizować includy w pliku.

W dzisiejszych czasach nie ma żadnego powodu, żeby nie zautomatyzować tego, używając do tego clang-formata i przestać się przejmować głupotami. Jeżeli dziś w projekcie nie używa się tego narzędzia, źle świadczy to o projekcie. Jeżeli ludzie w zespole nie potrafią dogadać się jaki styl jest akceptowalny dla wszystkich (wiadomo, każdy ma jakieś preferencje), to kiepsko świadczy o potencjalnych współpracownikach.

W tym punkcie dorzucę jeszcze słowo o popularnym w projektach z branży motoryzacyjnej standardzie MISRA (AUTOSARU nie znam — nie wypowiem się), osobiście nie spotkałem w życiu nic gorszego. Ten standard zakłada, że programiści są niekompetentni i trzeba bardzo dużo rzeczy im zabronić, żeby każdy (niekompetentny) programista był w stanie zrozumieć kod. Co najmniej kilka reguł z tego standardu jest wi


7. Testy 

To bardzo ważny punkt, dopytajmy o biblioteki, sposoby, poziomy testowania oprogramowania w firmie. Najbardziej popularnymi bibliotekami do testowania jednostkowego w świecie C++ to GTest oraz Catch2. Jako programiści najczęściej jesteśmy odpowiedzialni co najmniej za testy jednostkowe oraz często za jakieś testy wyższego poziomu np. funkcjonalne.

Warto wiedzieć jakim narzędziem testujemy kod, pod jakim względem (poprawność, wydajność), czy są jakieś "cele" np. projekt ma wymaganie pokrycia jakiegoś procenta kodu. Często takie wymagania są trochę bez sensu i kończą się produkowaniem testów, które w zasadzie nic nie robią, tylko po to, żeby cyferki w jakimś raporcie dla kadry zarządzającej się zgadzały, generalnie to raczej nie jest dobry znak.

Sanitizery — kompilatory C++ umożliwiają tworzenie specjalnych buildów, w których sprawdzana jest poprawność programów pod względem synchronizacji (thread sanitizer), błędów pamięci (adress sanitizer) czy używania niedzefiniowanych zachowań (undefined behavior sanitizer). Są to narzędzia, które służą wychwytywaniu błędów w programach, które mogą być trudne do znalezienia — często błędy synchronizacji czy pamięci potrafią być ukryte i bardzo skomplikowane. Zapytajmy, czy w projekcie te narzędzia są używane, również w automatycznych testach — to będzie dobry znak.

CI - kolejnym istotnym tematem związanym z tematem testów jest Continous Integration, jak, kiedy, ile razy jest puszczany. Czy zmiany testowane są po każdym commicie (najlepiej)? Jakie testu, buildy są puszczane po każdej zmianie, a jakie rzadziej. Albo tylko jakieś nightly buildy? To zdarza się w mniejszych firmach, czy projektach, gdzie nie ma tyle infrastruktury i niekoniecznie od razu musi to skreślać projekt. Czasami build całego projektu trwa kilkadziesiąt minut, nawet używając mocnego serwera o kilkudziesięciu procesorach.

W takim przypadku trochę nie ma siły — będziemy musieli obyć się bez tego. Ważne, żeby jakieś rozwiązanie tego typu było, ważna jest też informacja, kto takim CI zarządza, czy zespół programistów, albo dedykowany administrator. Dzięki tej informacji będziemy wiedzieć, czy będzie od nas oczekiwane zajmowanie się naprawianiem, czy konfiguracją CI. Wielu programistów C++, raczej nie są zaznajomieni z takimi względnie wysokopoziomowymi sprawami lub zupełnie nie są tym zainteresowani — to robota dla administratora.


8. Biblioteki 

Warto wiedzieć, jakie (w szczególności popularne) biblioteki Open Source są używane w projekcie. Takie rzeczy, są oczywiście często zależne od tematu, mało jest uniwersalnych bibliotek pasujących do wszystkich projektów. Natomiast jeżeli znamy tematykę projektu, to często wiadomo, jakie są typowe dla tej dziedziny typowe popularne biblioteki, które można by w nim użyć. Na przykład tworzymy aplikację wykorzystującą OpenGL do renderowania — praktycznie na pewno będziemy potrzebować jakiejś biblioteki matematycznej.

Co w takim projekcie jest używane: bardzo popularny GLM, czy inna tego typu biblioteka, czy jakiś wewnątrzfirmowy wynalazek. Być może taka firmowa biblioteka ma jakieś zalety, np. jeżeli osoba, z którą rozmawiamy — powie, że używają jej, bo jest 50% szybsze od wszystkiego, co jest dostępne powszechnie z GitHuba, to jest to dobry powód.

Gorzej, jeżeli takiego powodu nie ma i taki wynalazek jest używany "przez zasiedzenie" (napisaliśmy to 5-10 lat temu i w sumie nie wiemy, czy jest coś lepszego, nie obchodzi nas to). Wtedy możemy podejrzewać, że podejście do nowoczesnych, dobrze przetestowanych narzędzi w firmie kuleje. Warto przy okazji również zapytać, czy biblioteki OpenSource są (i jak często) aktualizowane. Bardzo wiele przedsięwzięć cierpi na syndrom "działa, nie ruszać" i NIGDY, przez lata nie aktualizuje się tam zewnętrznych bibliotek, mimo że mają nowe, często lepsze wersje, poprawione błędy itp. Takie podejście jest również formą zaciągania długu technicznego oraz brakiem chęci rozwoju technicznego.


9. Podejście do Open Source 

Tutaj poruszę trochę inną sprawę niż w poprzednim punkcie. Mianowicie chodzi o tworzenie OS, a nie korzystanie z nich. Warto wiedzieć, czy firma tworzy jakieś rozwiązania Open Source — jeżeli tak, to bardzo dobry znak. Możemy wtedy zajrzeć do takiego kodu i zobaczyć jak on wygląda — dużo nam to powie o standardach technicznych panujących w takiej firmie.

Czy kod wygląda dobrze, jak jest testowany, formatowany itp.? Da to nam praktyczną odpowiedź, na w zasadzie, wszystkie poprzednie punkty, które omawiałem. Firmy, które wiedzą, że ich kod wygląda średnio, raczej nie decydują się na upublicznianie go, więc takie rozwiązania tworzą (co do zasady, oczywiście nie zawsze tak jest) firmy, które mają standardy produkcji oprogramowania "powyżej średniej".

Jest tu jeszcze inna sprawa, czyli jak wygląda możliwość naszego wkładu do Open Source. Czasami może zdarzyć się, że w naszej pracy zaleziemy jakiś błąd w jakiejś zewnętrznej bibliotece albo potrzebujemy dodać to niej jakąś funkcję. Czy w takim przypadku nie będzie problemów z wystawieniem PRki do repozytorium z naszą pracą?

Niestety miałem doświadczenie, że firma traktowała takie właśnie drobne poprawki, jakby były one warte miliony dolarów technologią. Chęć wystawienia PRki do pewnej popularnej biblioteki z implementacją funkcji (notabene przepisanej z podręcznika matematyki — żadna tajna technologia) wiązało się ze skomplikowaną procedurą, która miała sprawdzić, czy nie udostępniamy do przestrzeni publicznej tajnej wartościowej technologii.

Chyba nie muszę mówić, że takie podejście jest śmieszne, w normalnej firmie, nie powinniśmy mieć żadnych problemów z commitowaniem poprawek i ulepszeń do bibliotek OS, jeżeli takie coś tworzymy w ramach potrzeb naszego projektu. Oczywiście nie chodzi, żebyśmy w czasie pracy siedzieli nad jakąś biblioteką czy rozwiązaniami niezwiązanymi z naszymi bieżącymi zadaniami.


10. Podejście do refaktoryzacji i usprawnień 

W wielu projektach istnieje podejście "działa, to nie ruszać" oraz "to nie było w twoim zadaniu". Czyli nie możesz wprowadzać różnych, często drobnych poprawek w kodzie (np. zauważyłeś, że warunek w wyrażeniu można uprościć albo kod napisany dwukrotnie wrzucić do funkcji).

Na każdą zmianę w kodzie aplikacji masz mieć pozwolenie oraz zgłoszenie w jakimś systemie do zarządzania projektami. Uważam, że stała refaktoryzacja, pielęgnacja kodu, wprowadzanie ulepszeń jest konieczne, żeby nie dopuścić do zaciągnięcia takiego długu technicznego, który będzie bardzo trudny do rozwiązania. W takim momencie praca z kodem będzie męczarnią.


Podsumowanie

Podsumowując, większość tych punktów sprowadza się do otrzymania informacji, jakich narzędzi używa się w projekcie, czy są one aktualne oraz, czy są one na bieżąco aktualizowane. W dobrych firmach raczej rak będzie, w kiepskich znacznie częściej spotkamy się z przestarzałymi i większa będzie niechęć do ich aktualizacji. Kilka innych punktów sprowadza się do pytania, czy używa się popularnych, szeroko rozpowszechnionych (industry standard) narzędzi, czy wewnąrzfirmowych "wynalazków", których jakość jest przeważnie (choć nie zawsze) wątpliwa.

Rozpocznij dyskusję

Lubisz dzielić się wiedzą i chcesz zostać autorem?

Podziel się wiedzą z 160 tysiącami naszych czytelników

Dowiedz się więcej