Kwalifikacja: INF.04 - Projektowanie, programowanie i testowanie aplikacji
Rozpoczęcie: 7 czerwca 2026 22:57
Zakończenie: 7 czerwca 2026 23:05
Egzamin niezdany
Wynik: 18/40 punktów (45,0%)
Wymagane minimum: 20 punktów (50%)
Twój wynik na tle innych
Twój wynik jest lepszy niż 16% podejść do kwalifikacji INF.04.
Porównanie z 22430 zakończonymi podejściami do tej kwalifikacji (dane zbiorcze, bez wyników indywidualnych).
Poprzednio 57,5%, teraz 45,0% (-12,5 p.p.).
Zachowaj ten wynik na koncie
Załóż darmowe konto albo zaloguj się - ten egzamin przypiszemy do Twojego konta, więc wrócisz do swoich błędów, będziesz śledzić postęp i dostaniesz powtórki dobrane do Twoich odpowiedzi.
A. Służą jako konstruktory w zależności od liczby argumentów.
B. Zawierają błąd, ponieważ nazwy metod powinny być różne.
C. Zawierają przeciążenie operatora.
D. Są przeciążone.
Metody przeciążone mogą mieć tę samą nazwę – różnią się sygnaturą, czyli liczbą i typami argumentów, co jest zgodne z zasadami programowania obiektowego. Przeciążenie metod to nie to samo co przeciążenie operatorów, które polega na definiowaniu nowego sposobu działania operatorów (np. +, -, *). Pełnienie funkcji konstruktorów to inny mechanizm i dotyczy głównie klas i ich instancjonowania, nie przeciążania metod.
Pytanie 2
Zamieszczony fragment kodu w Android Studio wdraża metodę nasłuchującą dla obsługi zdarzenia:
Kod wykorzystuje metodę setOnClickListener, która jest podstawowym sposobem przypisywania reakcji na kliknięcie przycisku (Button) w Androidzie. To taki klasyczny wzorzec nasłuchiwania zdarzeń, w tym przypadku – kliknięcia użytkownika. Moim zdaniem, ta konstrukcja pojawia się praktycznie w każdym większym projekcie Androidowym, bo trudno sobie wyobrazić interfejs bez przycisków, które coś faktycznie robią. Co ciekawe, korzystając z setOnClickListener, przekazujemy obiekt anonimowej klasy implementującej interfejs View.OnClickListener, a w jej metodzie onClick() umieszczamy kod, który ma się wykonać po naciśnięciu przycisku. To bardzo elastyczne rozwiązanie, bo możemy tu zarówno wyświetlić Toast, przejść do innego activity, wysłać dane do internetu czy nawet ukryć inny widok. Warto pamiętać, że praktycznie wszystkie kontrolki dziedziczące po View mogą mieć własnych listenerów, ale Button to najbardziej naturalny przypadek użycia. To taka podstawa obsługi UI w Android Studio i moim zdaniem każdy, kto chce pisać apki na Androida, powinien mieć to opanowane na pamięć. Dodatkowo, od wersji Android API 26 można używać także lambda expressions, co jeszcze bardziej skraca kod, ale sama idea zostaje ta sama – reagujemy na kliknięcie przycisku.
Pytanie 3
Na ilustracji pokazano fragment emulacji iOS z elementem kontrolnym. Który fragment kodu XAML opisuje ten element?
A. <Entry IsPassword= "true" />
B. <Slider Maximum= "255" />
C. <Stepper Increment= "1" />
D. <Switch IsToggled= "true" />
Kontrolka <Switch IsToggled= "true" /> w XAML to taki przełącznik. Ma dwa stany: włączony (true) i wyłączony (false). Można to porównać do zwykłego włącznika, tylko że w aplikacjach. Fajnie się z tego korzysta, bo pozwala szybko zmieniać ustawienia, nie trzeba nic więcej wpisywać. To jest dosyć intuicyjne dla użytkowników, więc można nim łatwo zarządzać funkcjami aplikacji.
Pytanie 4
Z analizy złożoności obliczeniowej algorytmów sortowania dla dużych zbiorów danych (powyżej 100 elementów) wynika, że najefektywniejszą metodą jest algorytm sortowania:
sortowanie bąbelkowe
O(n²)
sortowanie przez wstawianie
O(n²)
sortowanie przez scalanie
O(n log n)
sortowanie przez zliczanie
O(n)
sortowanie kubełkowe
O(n²)
A. bąbelkowego
B. kubełkowego
C. przez zliczanie
D. przez scalanie
Sortowanie bąbelkowe jest jednym z najwolniejszych algorytmów i rzadko jest używane w praktyce ze względu na złożoność O(n^2). Sortowanie kubełkowe może być szybkie, ale jego efektywność zależy od równomiernego rozkładu danych. Sortowanie przez scalanie jest bardziej uniwersalne, ale ma większą złożoność obliczeniową niż Counting Sort i może być mniej efektywne dla dużych zbiorów danych o ograniczonym zakresie.
Pytanie 5
Wynikiem wykonania poniższego fragmentu kodu jest wyświetlenie liczb z zakresu od 2 do 20, które są
Podzielność przez zmienną test lub check oznacza, że liczby są wielokrotnościami określonej wartości, ale niekoniecznie są liczbami pierwszymi. Liczby parzyste to liczby dzielące się przez 2, co oznacza, że tylko 2 jest liczbą pierwszą w tym zbiorze. Algorytmy wykrywające liczby parzyste lub wielokrotności nie są używane do znajdowania liczb pierwszych, ponieważ ich zakres i zastosowanie są zupełnie inne.
Pytanie 6
Zaprezentowany diagram Gantta odnosi się do projektu IT. Przy założeniu, że każdy członek zespołu dysponuje wystarczającymi umiejętnościami do realizacji każdego z zadań oraz że do każdego zadania można przypisać jedynie jedną osobę, która poświęci na zadanie pełny dzień pracy, to minimalna liczba członków zespołu powinna wynosić:
A. 5 osób
B. 2 osoby
C. 4 osoby
D. 1 osobę
Wybrana odpowiedź jest trafna, bo minimalna liczba członków zespołu wynosi właśnie 2 osoby. W projekcie przedstawionym na diagramie Gantta, kluczowe jest zwrócenie uwagi na to, ile zadań nakłada się w danym tygodniu – a nie łączna liczba zadań. Największe obciążenie zespołu wypada na okresy, gdzie równolegle realizowane są dwa zadania, np. w pierwszym tygodniu są to Projekt aplikacji i Grafika, później w ostatnim tygodniu dwie aplikacje: front-end i back-end. W żadnym momencie nie występuje potrzeba, by więcej niż dwie osoby pracowały równolegle nad różnymi zadaniami. To bardzo praktyczna sytuacja – w realnych projektach IT planuje się obłożenie pracą właśnie przez analizę diagramu Gantta, by nie generować sztucznego przestoju lub nadmiaru ludzi. Moim zdaniem taka optymalizacja zespołu to podstawa w IT, bo pozwala ograniczyć koszty i lepiej zarządzać zasobami. Warto pamiętać, że zgodnie z dobrymi praktykami zarządzania projektami, np. w metodykach PMBOK czy Prince2, zawsze analizuje się ścieżki krytyczne i równoległość zadań, dokładnie w taki sposób, żeby nie dublować niepotrzebnie rąk do pracy. Świetnie, jeśli już na etapie planowania potrafisz to zauważyć i wyciągnąć praktyczne wnioski – to naprawdę przydaje się potem przy rozpisywaniu harmonogramów na czasach rzeczywistych projektów.
Pytanie 7
Jakie kwestie związane z percepcją są uwzględnione w rekomendacjach standardu WCAG 2.0?
A. zapewnienia odpowiedniego czasu na zapoznanie się i przetworzenie informacji
B. umożliwienia interakcji między elementami użytkownika za pomocą klawiatury
C. prezentacji elementów interfejsu użytkownika
D. jasności i dokładności w dostarczonych treściach na stronie
Odpowiedzi odnoszące się do zapewnienia odpowiedniego czasu na zapoznanie się z informacjami, umożliwienia interakcji poprzez klawiaturę czy jasności i dokładności treści są ważne w kontekście dostępności stron, ale nie dotyczą bezpośrednio percepcji według standardu WCAG 2.0. Często zdarza się, że osoby uczące się mylą pojęcia percepcji z innymi zasadami WCAG, na przykład zrozumiałością (understandable) czy funkcjonalnością (operable). Percepcja w WCAG skupia się na tym, jak treści są postrzegane przez zmysły – głównie wzrok i słuch, ale czasem też dotyk, gdy mowa np. o wyświetlaczach brajlowskich. Zapewnienie odpowiedniego czasu i interakcji klawiaturą to typowe wymagania dla użytkowników z ograniczeniami motorycznymi, i chociaż są one bardzo istotne, to WCAG klasyfikuje je w innych kategoriach niż percepcja. Jasność i dokładność treści to cecha istotna dla zrozumiałości, jednak nie gwarantuje, że użytkownik w ogóle tę treść zauważy lub rozpozna – do tego potrzebna jest właśnie prawidłowa prezentacja elementów interfejsu. Tu najczęściej pojawia się błąd myślowy: zakłada się, że jak coś jest napisane jasno, to każdy to zobaczy i zrozumie, ale wielu użytkowników ma problemy z odbiorem samych wizualnych aspektów strony. WCAG 2.0 podkreśla, żeby nie polegać tylko na jednym kanale percepcji, np. kolorze, dźwięku czy obrazie. Dopiero dbałość o prezentację elementów interfejsu – kontrast, czytelność, alternatywy tekstowe – sprawia, że strona jest dostępna percepcyjnie. Warto zapamiętać, że kategorie WCAG są celowo podzielone właśnie w ten sposób, aby każda istotna kwestia była rozpatrywana osobno i nie mieszana z innymi.
Pytanie 8
Jakie środowisko jest natywne do tworzenia aplikacji desktopowych w języku C#?
A. MS Visual Studio
B. Eclipse
C. NetBeans
D. PyCharm
W branży często spotykam się z przekonaniem, że każde większe środowisko programistyczne nada się do wszystkiego, ale to nie do końca prawda, szczególnie jeśli chodzi o C# i aplikacje desktopowe. Eclipse kojarzy się głównie z Javą i choć można doinstalować różne wtyczki, to w praktyce wsparcie dla C# jest tam bardzo ograniczone, zwłaszcza w kontekście aplikacji desktopowych pod Windows. NetBeans to podobna historia – projektowano go pod kątem Javy i Swinga, a rozwiązania dla C# są bardzo niszowe i raczej eksperymentalne. PyCharm natomiast to świetne narzędzie do Python’a, ale nie ma natywnego wsparcia dla C# czy .NET Framework. Często początkujący zakładają, że „duży edytor” to od razu uniwersalne środowisko, jednak rzeczywistość jest taka, że tylko Visual Studio zapewnia pełną integrację z narzędziami Microsoftu oraz obsługą platformy Windows. Dla aplikacji desktopowych w C# ważne jest wsparcie dla Windows Forms, WPF czy nowoczesnych rozwiązań typu .NET MAUI – a tego nie dostaniemy w Eclipse, NetBeans czy PyCharm. Warto pamiętać, że wybierając nieodpowiednie IDE, można sobie skomplikować życie już na starcie, bo konfiguracja i debugowanie aplikacji może być bardzo uciążliwe, a nawet często niemożliwe bez natywnego wsparcia. Zdarza się też, że mylenie środowisk wynika z tego, że na uczelniach promuje się Eclipse czy NetBeans przez pryzmat Javy, stąd czasami ktoś próbuje używać ich do C#, ale to naprawdę nie jest efektywna droga. W praktyce, jeśli zależy nam na solidnych narzędziach i szybkim wdrażaniu gotowych aplikacji na Windows, Visual Studio jest właściwym wyborem i tak też uczą tego na kursach oraz szkoleniach branżowych.
Pytanie 9
Algorytm przedstawiony powyżej może zostać zaimplementowany w języku Java z wykorzystaniem instrukcji:
A. while
B. switch
C. if
D. try
Instrukcja 'switch' to coś, co służy do wyboru pomiędzy kilkoma opcjami, więc nie da się jej użyć do powtarzania czegoś. 'if' to z kolei taki sposób na sprawdzenie warunku raz, a 'try' to konstrukcja do obsługi wyjątków, a nie do pętli. Chociaż 'if' może czasem być używane w bardziej złożonych pętlach, to nie jest to jego główna rola.
Fragment kodu, który tutaj analizujemy, nie jest zwykłą strukturą danych w sensie ogólnym, bo to za mało precyzyjne określenie – praktycznie wszystko w programowaniu to jakaś struktura danych, od prostych zmiennych przez listy, aż po bardziej złożone zbiory czy słowniki. W przykładzie nie mamy też do czynienia ani ze stosem, ani z kolejką LIFO. Stos (ang. stack) to struktura, gdzie elementy dodaje się i usuwa na zasadzie ostatni wszedł, pierwszy wyszedł (Last-In-First-Out). Kolejki działają zwykle na zasadzie FIFO, ale tu pojawiła się kolejka LIFO, która w praktyce jest po prostu nazwą stosu, więc to takie trochę mieszanie pojęć. W Pythonie typ dictionary (dict) jest fundamentalnym narzędziem do przechowywania danych powiązanych przez klucz – hasła, ustawienia aplikacji, tłumaczenia na różne języki, wszystko to korzysta z tej zasady. Często błędnie utożsamia się tablice asocjacyjne z listami – tymczasem listy przechowują dane pod indeksem liczbowym, a słowniki pod dowolnym kluczem niezmienniczym. To jest właśnie esencja tablicy asocjacyjnej, bo nie trzeba znać kolejności ani pozycji, wystarczy klucz. W pytaniu łatwo się pomylić, bo teoretycznie wszystkie wymienione typy są strukturami danych, ale tylko słownik oddaje sens kodu. Na marginesie, spotkałem się nieraz z próbą użycia stosu czy kolejki tam, gdzie trzeba mapować jedne wartości na drugie – to zawsze kończy się niepotrzebnym komplikowaniem projektu i traceniem czasu na obsługę błędów, które słownik rozwiązuje w locie. Takie zrozumienie podstawowych różnic jest kluczowe dla efektywnej pracy z kodem, bo wybór nieodpowiedniej struktury danych to proszenie się o kłopoty w większych projektach.
Pytanie 11
Celem zastosowania wzorca Obserwator w tworzeniu aplikacji WEB jest:
A. informowanie obiektów o modyfikacji stanu innych obiektów
B. monitorowanie działań użytkownika oraz generowanie wyjątków
C. zarządzanie funkcjami synchronicznymi w kodzie aplikacji
D. dostosowanie interfejsu użytkownika do różnych kategorii użytkowników
Wzorzec projektowy Obserwator (ang. Observer) to jeden z klasyków ze świata programowania obiektowego i frontendu. Główna jego rola polega na tym, by pozwalać obiektom (obserwatorom) reagować na zmiany stanu innych obiektów (podmiotów) bez sztywnego powiązania tych klas ze sobą. W praktyce, w aplikacjach webowych bardzo często wykorzystuje się ten wzorzec w architekturach typu MVC czy MVVM, gdzie widoki muszą się automatycznie aktualizować po zmianie modelu danych. Przykład: w Reactcie używasz hooka useState lub useEffect – i Twoje komponenty „obserwują” stan aplikacji. Gdy stan się zmienia, komponenty same się przebudowują, a Ty nie musisz ręcznie wywoływać każdej aktualizacji. Podobnie działa np. EventEmitter w Node.js, Redux z subskrypcjami store czy nawet WebSockety, gdzie klient „słucha” na zmiany po stronie serwera. Dzięki temu komunikacja pomiędzy różnymi częściami systemu staje się luźno powiązana, co ułatwia utrzymanie i rozbudowę kodu. Moim zdaniem bez zrozumienia tego wzorca trudno ogarnąć nowoczesny frontend, bo większość bibliotek UI gdzieś pod spodem go wykorzystuje. Przy okazji: Observer to wzorzec zalecany przez GOF (Gang of Four), więc to nie jest tylko „fajna technika”, ale sprawdzony standard branżowy. Warto wiedzieć, że podejście to minimalizuje ryzyko błędów w synchronizacji danych i pozwala naturalnie reagować na zmiany bez pisania stosów callbacków. To spora oszczędność czasu i kodu.
C. sortującego ciąg od znaku o najniższym kodzie ASCII do znaku o najwyższym kodzie
D. odwracającego ciąg
Kod przedstawiony w zadaniu nie realizuje ani wyszukiwania konkretnej litery w ciągu, ani nie sprawdza, czy tekst jest palindromem, ani też nie sortuje znaków po kodzie ASCII. Często spotyka się mylenie tych koncepcji z prostym odwracaniem tekstu, bo wszystkie operacje dotyczą łańcuchów znaków, jednak ich logika jest zupełnie inna. Przykładowo, sprawdzanie palindromu najczęściej polega na porównywaniu znaków od początku i końca tekstu, aż do środka – nie wymaga to budowania nowego odwróconego tekstu, tylko ew. jednej pętli z warunkami. Jeśli chodzi o wyszukiwanie litery, tam szukamy, czy dany znak występuje w ciągu – sprawdza się to za pomocą pętli i instrukcji warunkowej, ale nie tworzy się nowego łańcucha, tylko ewentualnie zwraca pozycję znaku lub informację o jego obecności. Sortowanie znaków w napisie według kodu ASCII wymagałoby innego podejścia – należałoby przenieść znaki do np. tablicy znaków, użyć algorytmu sortowania (chociażby Arrays.sort()), a potem złożyć łańcuch z posortowanych znaków. W tym kodzie nie ma żadnych operacji porównywania kodów znaków ani przestawiania ich miejscami zgodnie z wartościami ASCII. Typowym błędem jest też sugerowanie się samą obecnością pętli i manipulacji na Stringu bez dokładnego prześledzenia, co dzieje się w każdej iteracji. Metoda fun1 po prostu dokleja kolejne znaki od końca oryginalnego napisu do nowego łańcucha, co wyraźnie wskazuje na typowo szkolny algorytm odwracania ciągu. To podejście jest bardzo przydatne do nauki podstaw przetwarzania tekstów i zrozumienia, jak można budować nowe napisy na bazie istniejących danych, ale nie spełnia żadnej z wymienionych innych funkcjonalności.
Pytanie 13
Jakie cechy powinien posiadać skuteczny negocjator?
A. intuicja, cierpliwość, asertywność
B. lojalność, nieśmiałość, uczciwość
C. dobra reputacja, przekora, porywczość
D. asertywność, pesymizm, buta
Skuteczny negocjator powinien mieć zestaw cech, które pozwolą mu osiągać kompromisy, rozwiązywać konflikty i dążyć do korzystnych rozwiązań dla obu stron. Intuicja pozwala wyczuć nastroje rozmówcy, wychwycić niewerbalne sygnały i przewidywać możliwe zagrożenia czy okazje jeszcze zanim druga strona je wprost zasygnalizuje. Cierpliwość jest kluczowa, bo proces dochodzenia do porozumienia bywa żmudny, a presja czasu często prowadzi do pochopnych decyzji. Często miałem okazję obserwować, że ci, którzy potrafią zaczekać na ruch drugiej strony, zyskują przewagę negocjacyjną. Asertywność natomiast pozwala jasno wyrażać swoje oczekiwania i granice, bez agresji i bez uległości – to klasyka wśród dobrych praktyk negocjacyjnych, choć nadal niedoceniana w wielu branżach. Asertywność pomaga uniknąć niedomówień i manipulacji, a także buduje szacunek. W praktyce, na sali negocjacyjnej czy nawet przy codziennych rozmowach z klientami, zestaw tych trzech cech daje naprawdę mocną pozycję. Moim zdaniem nie ma jednego uniwersalnego szablonu, ale właśnie intuicja, cierpliwość i asertywność pojawiają się prawie zawsze w podręcznikach czy na szkoleniach dedykowanych profesjonalistom. Warto je ćwiczyć na co dzień, nawet poza pracą, bo to się po prostu opłaca.
Pytanie 14
Zasada programowania obiektowego, która polega na ukrywaniu elementów klasy tak, aby były one dostępne wyłącznie dla metod tej klasy lub funkcji zaprzyjaźnionych, to
A. wyjątki
B. hermetyzacja
C. polimorfizm
D. dziedziczenie
Hermetyzacja to taka esencja programowania obiektowego, która polega na ukrywaniu szczegółów implementacyjnych wewnątrz klasy. Dzięki temu tylko wybrane fragmenty kodu mają dostęp do danych czy metod, które faktycznie powinny być widoczne na zewnątrz. W praktyce sprowadza się to do korzystania z modyfikatorów dostępu, takich jak private, protected czy public, co jest podstawą w językach takich jak Java, C++ czy C#. Daje to ogromną przewagę, bo ochrania dane przed przypadkowymi (albo celowymi!) zmianami z zewnątrz. Z mojego doświadczenia wynika, że dobrze zaprojektowana hermetyzacja sprawia, że kod jest bardziej przejrzysty i łatwiejszy do testowania i utrzymania. Przykład? Załóżmy, że mamy klasę KontoBankowe i chcemy, żeby saldo dało się zmieniać tylko poprzez wpłatę i wypłatę, a nie żeby każdy mógł ustawić dowolną kwotę. Wtedy pole 'saldo' robimy private, a dostęp dajemy przez metody public wpłata() i wypłata(). Branżowe praktyki, np. SOLID, wręcz podkreślają wagę hermetyzacji. Ułatwia to też refaktoryzację – jeśli coś zmienisz w środku klasy, a interfejs zewnętrzny zostaje taki sam, reszta programu nawet nie zauważy. Także, moim zdaniem, bez hermetyzacji nie ma sensownego programowania obiektowego – to absolutna podstawa.
Pytanie 15
Modyfikator dostępu znajdujący się przed definicją metody Dodaj() w klasie Kalkulator sprawia, że:
protectedvoidDodaj() {}
A. jest ona możliwa do wykorzystania w programie głównym i można ją wywołać na instancji klasy Kalkulator
B. nie jest ona osiągalna w klasach, które dziedziczą po klasie Kalkulator
C. nie jest ona dostępna z poziomu klas, które są zaprzyjaźnione z klasą Kalkulator
D. jest ona dostępna zarówno w samej klasie, jak i w klasach dziedziczących po klasie Kalkulator
Modyfikator protected w językach takich jak C# czy Java oznacza, że metoda jest dostępna zarówno w tej samej klasie, jak i w każdej klasie, która po niej dziedziczy — niezależnie od tego, w którym miejscu projektu ta klasa pochodna się znajduje. To jest bardzo praktyczne, bo pozwala pisać tzw. szkieletowe klasy bazowe, udostępniając pewne funkcjonalności tylko klasom potomnym, a jednocześnie ukrywając je przed kodem zewnętrznym. Takie podejście umożliwia budowanie bezpiecznych i elastycznych struktur dziedziczenia, gdzie konkretne działania mogą być modyfikowane lub rozszerzane tylko tam, gdzie trzeba. Bardzo często spotyka się protected w dużych projektach, gdzie kluczowe funkcje mają być używane wyłącznie w rodzinie klas, a nie dostępne dla całego świata. Moim zdaniem, to świetny sposób na wymuszanie architektury i porządku w kodzie, no bo wiadomo, jak każdy miałby dostęp do wszystkiego, to zaraz byłby bałagan. Przykład praktyczny: pisząc klasę bazową Kalkulator, możesz mieć protected Dodaj(), a publicznie udostępnić tylko ogólną metodę Oblicz(). Dzięki temu masz większą kontrolę, co i jak jest wykorzystywane. Branżowo przyjęło się, że protected to taki złoty środek pomiędzy public a private, gwarantując odpowiednią enkapsulację i możliwość dziedziczenia. Warto to stosować świadomie, żeby potem nie mieć niespodzianek w dużych projektach.
Pytanie 16
Podstawowym celem środowisk IDE takich jak: IntelliJ IDEA, Eclipse, NetBeans jest programowanie w języku:
A. C++
B. Python
C. C#
D. Java
IDE, czyli Zintegrowane Środowiska Programistyczne, takie jak IntelliJ IDEA, Eclipse czy NetBeans, od lat są uznawane za najważniejsze narzędzia do tworzenia aplikacji w języku Java. Te środowiska zostały od podstaw zaprojektowane właśnie z myślą o programistach Javy – wspierają typowe projekty Java SE, Java EE czy nawet JavaFX. Moim zdaniem, ich integracja z narzędziami takimi jak Maven, Gradle, testami jednostkowymi JUnit albo debuggerami Javy to prawdziwy game-changer. Na co dzień korzysta się tam z podpowiedzi składni, automatycznego refaktoringu, generatorów kodu i systemów kontroli wersji. Przykładowo, większość firm w Polsce, które tworzą oprogramowanie korporacyjne, wybiera właśnie te IDE do pracy z Java Spring Boot czy Hibernate. Nawet podczas nauki w technikum często pierwsze projekty Java robi się właśnie w Eclipse albo IntelliJ. Pewnie, można dorzucić pluginy do innych języków, ale to Java jest sercem tych środowisk i to dla niej są one najbardziej zaawansowane, zgodnie z najlepszymi wzorcami branżowymi. Jak patrzę na ogłoszenia o pracę, to praktycznie każda oferta na programistę Java zakłada znajomość choć jednego z tych IDE. To jasno pokazuje, że ich podstawowym celem jest ułatwienie i przyspieszenie tworzenia oprogramowania właśnie w tym języku.
Pytanie 17
Wartości składowych RGB koloru #AA41FF zapisane w systemie szesnastkowym po przekształceniu na system dziesiętny są odpowiednio
A. 160, 65, 255
B. 160, 64, 255
C. 170, 64, 255
D. 170, 65, 255
Kolor zapisany w postaci szesnastkowej #AA41FF to jeden z najpopularniejszych formatów wykorzystywanych np. w CSS i projektowaniu graficznym. Składa się z trzech dwucyfrowych wartości: AA dla czerwonego (R), 41 dla zielonego (G) i FF dla niebieskiego (B). Zamiana tych wartości na system dziesiętny jest kluczowa, żeby lepiej zrozumieć jak działa model RGB – czyli mieszanie trzech podstawowych barw światła w różnych proporcjach. AA w szesnastkowym to 170 w dziesiętnym (bo A=10, więc 10*16+10=170), 41 to 4*16+1=65, a FF to 15*16+15=255. Taka konwersja przydaje się w codziennej pracy z grafiką czy front-endem – na przykład podczas ręcznego tworzenia palet kolorów lub dostosowywania barw ikon w interfejsach użytkownika. Co ciekawe, w wielu narzędziach do projektowania można dowolnie przełączać się między tymi zapisami, żeby precyzyjnie ustawić wybrane odcienie. Moim zdaniem, zrozumienie tej konwersji pomaga lepiej ogarnąć, jak komputery interpretują kolory i jak potem wyświetlają je na ekranie. Praktyka pokazuje, że większość błędów przy pracy z kolorami wynika właśnie z nieprawidłowego przeliczania wartości. No i taka wiedza to prawdziwy fundament dla każdego, kto myśli poważnie o pracy z grafiką czy programowaniem front-endu – nie da się jej pominąć w żadnym sensownym kursie.
Pytanie 18
Jaką strukturę danych można zrealizować, korzystając jedynie z wymienionych poniżej metod:
push(arg) – dodaje element
pop() – usuwa ostatnio dodany element
peek() – zwraca ostatnio dodany element bez usuwania
isEmpty() – sprawdza czy istnieją dane w strukturze
A. drzewo binarne
B. tablica
C. kolejka
D. stos
Pomyłka przy tym pytaniu jest dość zrozumiała, bo wiele osób myli dostępne operacje ze strukturą, którą zamierzają użyć. Metody push, pop, peek i isEmpty wskazują wyraźnie na stos, jednak nietrudno ulec wrażeniu, że można je zastosować także w tablicy czy nawet kolejce. Problem w tym, że tablica daje bezpośredni dostęp do dowolnego elementu (indeksowanie), a tych operacji tutaj nie mamy — bez get(index) czy set(index, value) nie da się użyć jej w typowy sposób, więc zamienia się bardziej w zwykły pojemnik, niż prawdziwą tablicę. Kolejka natomiast wymaga operacji typu enqueue (dodanie na koniec) i dequeue (usunięcie z początku), czyli tzw. FIFO (First-In-First-Out), czego tutaj nie zrealizujesz samymi push i pop - one zawsze odnoszą się do końca struktury, nie do jej początku. Drzewo binarne to już zupełnie inna para kaloszy: wymaga rozbudowanych operacji na węzłach i gałęziach, a dostępne tu metody nawet nie zbliżają się do tego typu funkcjonalności — nie ma dodawania dzieci, przeszukiwania czy sprawdzania położenia w strukturze. Typowym błędem jest też utożsamianie samych nazw operacji z ogólną strukturą danych, bez zastanowienia się, jaki dokładnie model dostępu do danych one umożliwiają. Warto zapamiętać, że jeśli dostępne masz tylko push, pop, peek i isEmpty, to jesteś w świecie stosu - i tylko jego.
Pytanie 19
W języku C# szablon List umożliwia korzystanie z listy. Z definicji obiektu kolekcji wynika, że jego elementami mogą być:
List<int> wykaz= newList<int>();
A. elementy o nieokreślonym typie
B. liczby rzeczywiste
C. liczby całkowite
D. elementy typu List
Jeżeli chodzi o kolekcje generyczne w C#, to List<int> jest przykładem bardzo konkretnego zastosowania. Ten zapis oznacza, że tworzymy listę, której elementami mogą być wyłącznie liczby całkowite – dokładnie takie, jakie reprezentuje typ int w .NET (czyli 32-bitowe liczby całkowite ze znakiem). Wynika to z idei generyczności: typ podany w nawiasach ostrych (<int>) precyzyjnie narzuca typ przechowywanych danych. To daje nam bezpieczeństwo typów, na które zwracają uwagę wszyscy programiści C# – nie da się przez pomyłkę dodać tam np. napisu czy obiektu innego typu. Z mojego doświadczenia mogę powiedzieć, że to bardzo upraszcza życie, bo kompilator od razu wychwyci próby niewłaściwego użycia. Praktycznie, gdy tworzysz List<int>, możesz ją wykorzystać np. do przechowywania identyfikatorów, wyników testów, liczb losowych – wszędzie tam, gdzie operujesz właśnie na liczbach całkowitych. Warto dodać, że generyczność jest jednym z filarów nowoczesnych języków, pozwalając pisać kod elastyczny i bezpieczny zarazem. Trochę jak z pudełkiem na śrubki: jak wrzucisz inne rzeczy, to od razu się pogubisz i zrobi się bałagan. Tutaj jest bardzo jasno – List<int> to zawsze lista liczb całkowitych i już. Dobre praktyki branżowe podpowiadają, żeby zawsze stosować jak najbardziej precyzyjne typy w generycznych kolekcjach, bo to ułatwia późniejsze utrzymanie kodu i ogranicza potencjalne błędy.
Pytanie 20
Zastosowanie typu DECIMAL języka SQL wymaga wcześniejszego zdefiniowania długości (liczby cyfr) przed przecinkiem oraz długości cyfr po przecinku. Jest to zapis:
A. stałoprzecinkowy
B. zmiennoprzecinkowy
C. logicznym
D. łańcuchowym
Poprawnie – typ DECIMAL w SQL to typ stałoprzecinkowy. Oznacza to, że już przy definicji kolumny musisz podać dwie wartości: całkowitą liczbę cyfr (PRECISION) oraz liczbę cyfr po przecinku (SCALE), np. DECIMAL(10,2). W praktyce oznacza to, że możesz przechowywać liczby z maksymalnie 10 cyframi, z czego 2 są po przecinku, czyli zakres jest kontrolowany i przewidywalny. Moim zdaniem to jest kluczowa cecha: stała dokładność i brak „pływania” wyniku. W relacyjnych bazach danych DECIMAL jest używany wszędzie tam, gdzie pieniądze, kursy walut, stawki VAT, ilości w magazynie itp. – wszędzie, gdzie liczy się precyzja i nie można sobie pozwolić na błędy zaokrągleń typowe dla typów zmiennoprzecinkowych (FLOAT, DOUBLE). Standard SQL właśnie dla takich zastosowań przewiduje typy numeryczne dokładne (exact numeric types), do których należy DECIMAL/NUMERIC. Dobre praktyki branżowe mówią wprost: kwoty finansowe trzymaj w DECIMAL, a nie w FLOAT. Warto też wiedzieć, że DECIMAL jest przechowywany w sposób „cyfrowy”, a nie binarny jak float, więc operacje arytmetyczne dają wyniki dokładne w zadanej skali. To bardzo ułatwia raportowanie, księgowość, rozliczenia między systemami. W wielu firmach spotkasz standardy projektowe w stylu: „wszystkie kwoty w systemie mają typ DECIMAL(18,2)” albo podobny. Taki zapis daje spójność danych, przewidywalne zużycie miejsca w bazie i mniejsze ryzyko błędów biznesowych. W skrócie: DECIMAL = stałoprzecinkowy, z góry określona liczba cyfr i powtarzalne wyniki obliczeń, co w systemach produkcyjnych jest bardzo ważne.
Pytanie 21
Zaprezentowany fragment kodu w języku C# tworzy hasło. Wskaż zdanie PRAWDZIWE dotyczące charakterystyki tego hasła:
A. Może zawierać zarówno małe, jak i wielkie litery, cyfry oraz symbole
B. Ma co najmniej 8 znaków oraz zawiera małe i wielkie litery oraz cyfry
C. Jest maksymalnie 7-znakowe, co wynika z wartości zmiennej i
D. Może zawierać małe i wielkie litery oraz cyfry
Patrząc na pozostałe odpowiedzi, nietrudno zauważyć typowe pomyłki, które pojawiają się przy analizie kodu generującego hasła. Często spotykam się z błędnym założeniem, że jeśli mamy losowy wybór ze znacznej puli znaków, to automatycznie generowane hasło może zawierać symbole czy inne znaki specjalne. W tym przypadku pulaZnakow wyraźnie ogranicza się tylko do liter – małych i wielkich – oraz cyfr, stąd nie ma możliwości, by pojawił się jakikolwiek symbol, co już obala pierwszą odpowiedź. Następna rzecz – twierdzenie, że hasło ma co najmniej 8 znaków – jest nieścisłe: kod ustawia pętlę for na osiem powtórzeń, więc hasło będzie miało zawsze dokładnie 8 znaków, ani więcej, ani mniej (chyba że ręcznie zmodyfikujemy kod), więc nie jest to 'co najmniej'. Sformułowanie o długości „maksymalnie 7-znakowej” wynika najpewniej z nieuważnego czytania zakresu powtórzeń pętli: for (int i = 0; i < 8; i++) oznacza 8 iteracji, czyli 8 znaków, a nie 7. Często w praktyce ludzie gubią się w liczeniu zakresów, bo zaczynają od zera, ale liczba iteracji jest tu bezpośrednio związana z warunkiem i<wartość>. To są pomyłki, które łatwo popełnić, gdy nie czyta się kodu bardzo uważnie albo nie ćwiczyło się podobnych przypadków na własnych przykładach. Wreszcie, niektóre odpowiedzi próbują dodać jakieś cechy hasła (np. obecność symboli), których w kodzie po prostu nie ma, bo pulaZnakow na to nie pozwala. W branży bezpieczeństwa takie detale są bardzo istotne i weryfikacja puli znaków to pierwszy krok przy analizie generatorów haseł. Zawsze warto szczegółowo patrzeć, co faktycznie znajduje się w zmiennej określającej dostępne znaki, a nie zakładać, że kod jest bardziej zaawansowany, niż jest w rzeczywistości.
Pytanie 22
Programista może wykorzystać framework Angular do realizacji aplikacji:
A. rodzaju back-end
B. mobilnej
C. na komputerze
D. rodzaju front-end
Aplikacje back-endowe zazwyczaj pisze się w innych frameworkach, jak na przykład Express.js albo Django. Wiadomo, że Angular zajmuje się warstwą kliencką. A jak mówimy o aplikacjach mobilnych czy desktopowych, to częściej korzysta się z takich rzeczy jak Flutter, React Native czy Electron. Więc to już nie jest to samo co Angular.
Pytanie 23
Jakie metody pozwalają na przesłanie danych z serwera do aplikacji front-end?
A. formatu JSON
B. biblioteki jQuery
C. protokołu SSH
D. metody POST
Wśród zaproponowanych odpowiedzi pojawiło się kilka nieporozumień technicznych, które niestety są dość często spotykane u początkujących programistów. Przede wszystkim, biblioteka jQuery sama w sobie nie jest metodą przesyłania danych – to narzędzie, które może ułatwić pobieranie i wysyłanie danych na front-endzie, ale bez określonego formatu danych (np. JSON) jej obecność niewiele znaczy w kontekście komunikacji z serwerem. Moim zdaniem stąd czasem bierze się mylne przekonanie, że jQuery "przesyła dane", ale to tylko narzędzie, a nie metoda czy format wymiany informacji. Jeśli chodzi o protokół SSH, to jest on zupełnie niepowiązany z komunikacją webową – SSH służy głównie do bezpiecznego zdalnego zarządzania serwerami i nie jest wykorzystywany do przesyłania danych pomiędzy serwerem a przeglądarką. SSH dobrze się sprawdza przy pracy zdalnej na terminalu, ale nie przy typowej wymianie danych w aplikacjach webowych. Z kolei metoda POST to jeden z typów żądań HTTP, który określa sposób przesłania danych do serwera, ale nie precyzuje formatu tych danych. Możemy wysłać w POST-cie tekst, plik, dane binarne, XML czy JSON – nie jest to więc format, tylko sposób komunikacji. Bardzo często początkujący mylą metodę HTTP z formatem danych, co prowadzi do niedokładnych odpowiedzi. Odpowiednie rozróżnienie między narzędziem, protokołem, metodą żądania a formatem danych jest kluczowe w codziennej pracy webdevelopera. W praktyce to właśnie wybór formatu – a nie tylko metody żądania czy użytej biblioteki – decyduje o tym, jak łatwo aplikacje front-end i back-end będą w stanie się "dogadać". JSON jest tu najlepszym przykładem takiego uniwersalnego sposobu wymiany danych.
Pytanie 24
Co należy do zadań interpretera?
A. przekładanie kodu na kod maszynowy
B. ulepszanie większej części kodu, aby przyspieszyć jego wykonanie
C. sprawdzanie składni całego programu przed jego uruchomieniem
D. wykonanie skryptu instrukcja po instrukcji
Często spotykam się z myleniem interpretera z kompilatorem i optymalizatorami kodu, co prowadzi do błędnych wyobrażeń o jego działaniu. Zacznijmy od podstaw: przekładanie kodu źródłowego na kod maszynowy to domena kompilatorów, które analizują cały program, optymalizują go i generują plik wykonywalny, który można uruchomić niezależnie od środowiska. Interpreter natomiast nie zajmuje się takim tłumaczeniem, tylko odczytuje kod i wykonuje go na bieżąco, bez zapisywania gotowego programu w formie binarnej. Kolejna kwestia to ulepszanie kodu w celu przyspieszenia jego wykonania – to zadanie specjalistycznych narzędzi optymalizujących, często wbudowanych w kompilatory. Interpreter rzadko kiedy ingeruje w optymalizację kodu, bo jego głównym zadaniem jest wierne odtworzenie logiki programu krok po kroku, a nie poprawianie jego wydajności. Jeżeli chodzi o sprawdzanie składni całego programu przed uruchomieniem, to znów domena kompilatorów – interpreter najczęściej wykrywa błędy dopiero w momencie, gdy dociera do konkretnej instrukcji podczas wykonywania skryptu. To właśnie sprawia, że łatwiej eksperymentować, ale też czasem trudniej jest znaleźć błędy, które ujawniają się dopiero w trakcie działania aplikacji. W mojej ocenie te nieporozumienia wynikają z utożsamiania terminów używanych w teorii kompilacji – warto rozróżniać narzędzia na podstawie ich faktycznej roli w cyklu życia programu. Praktyka pokazuje, że zrozumienie różnicy pomiędzy interpretacją a kompilacją jest kluczowe przy wyborze technologii do realizacji konkretnego projektu. Jeżeli zależy nam na szybkim prototypowaniu lub pracy z kodem interaktywnym – interpreter jest świetny, ale nie będzie generował kodu maszynowego ani zaawansowanie go optymalizował.
Pytanie 25
Cytat przedstawia charakterystykę metodyki RAD. Pełne znaczenie tego skrótu można przetłumaczyć na język polski jako:
...(RAD)..., is both a general term for adaptive software development approaches, and the name for James Martin's method of rapid development.
In general, RAD approaches to software development put less emphasis on planning and more emphasis on an adaptive process. Prototypes are often used in addition to or sometimes even instead of design specifications.
Źródło: https://en.wikipedia.org/
A. środowisko szybkiego rozwoju aplikacji
B. środowisko refaktoryzacji aplikacji
C. zintegrowane środowisko programistyczne
D. prototypowanie wsparte testami jednostkowymi
RAD, czyli Rapid Application Development, tłumaczy się na polski najczęściej jako „środowisko szybkiego rozwoju aplikacji” albo „metodyka szybkiego wytwarzania oprogramowania”. To podejście stawia na błyskawiczne prototypowanie i szybkie iteracje zamiast długiego, formalnego planowania. Bardziej niż na dokumentacji, skupia się na tworzeniu działających wersji aplikacji, które można testować i na bieżąco modyfikować zgodnie z tym, czego oczekuje klient lub zespół użytkowników. W praktyce, przykładowy projekt w RAD to np. budowa aplikacji, gdzie klient dostaje wstępny prototyp po tygodniu, a nie po miesiącu – i od razu może zgłaszać uwagi. Bardzo często stosuje się narzędzia typu CASE (Computer-Aided Software Engineering), które pozwalają szybko generować kod i prototypy GUI bez żmudnego pisania wszystkiego od zera. W świecie profesjonalnych firm IT, RAD jest chętnie wykorzystywany, kiedy czas wdrożenia jest kluczowy, na przykład w startupach, które muszą szybko przetestować swój pomysł rynkowy. Moim zdaniem, nawet jeśli nie wszystkie projekty się do tego nadają, to znajomość RAD jest bardzo przydatna dla każdego programisty – pozwala lepiej zrozumieć, jak można pracować zwinnie i elastycznie, bez zbędnego formalizmu. RAD to nie tylko metodyka, ale też praktyczny styl myślenia o aplikacjach – szybciej, więcej, elastyczniej. Warto się tym zainteresować, szczególnie jeśli komuś zależy na czasie i wczesnych efektach pracy.
Pytanie 26
Mobilna aplikacja przedstawia listę, w której każdy element można dotknąć palcem, aby zobaczyć jego detale. Zdarzenie, które odpowiada tej czynności, to
A. tapped.
B. toggled.
C. value changed.
D. button clicked.
Zdarzenie 'toggled' mówi o przełącznikach, czyli o tych małych suwakach, co zmieniają stan. 'Value changed' to w sumie zmiana wartości w różnych kontrolkach, takich jak suwaki czy pola tekstowe. A 'Button clicked' dotyczy przycisków, a nie elementów z listy. Każde z tych zdarzeń ma swój cel w interfejsie, więc warto o tym pamiętać.
Pytanie 27
Aplikacje webowe stworzone z użyciem frameworka Angular lub biblioteki React, działające na standardowych portach, można uruchomić na lokalnym serwerze, wpisując w przeglądarkę
A. localhost:8080 (React) lub localhost:8000 (Angular)
B. localhost:8000 (React) lub localhost:49887 (Angular)
C. localhost:3000 (React) lub localhost:4200 (Angular)
D. localhost:5001 (React) lub localhost:8080 (Angular)
React domyślnie startuje na porcie 3000, a Angular na 4200 – to są takie standardy, które praktycznie wszyscy w branży znają i stosują. Kiedy zaczynasz nowy projekt w React, korzystając na przykład z create-react-app, serwer deweloperski po prostu nasłuchuje na http://localhost:3000. Analogicznie, jak generujesz projekt w Angular CLI i odpalasz ng serve, wtedy aplikacja wystartuje na http://localhost:4200. To są domyślne porty – nie musisz nic specjalnie ustawiać, wystarczy wpisać te adresy w przeglądarce. Z mojego doświadczenia, dobrze jest zapamiętać te ustawienia, bo praktycznie na każdym warsztacie czy bootcampie te adresy padają od ręki. Jeśli chodzi o praktykę, czasami port jest już zajęty i wtedy narzędzie zaproponuje inny, ale te wartości startowe to taka baza. Warto pamiętać, że zmiana portu wynika zazwyczaj z konfliktu, a nie z jakiejś specjalnej potrzeby. Dodatkowo, rozpoznanie tych portów pozwala szybciej debugować problemy z uruchomieniem aplikacji – jak coś nie wstaje na tych adresach, to od razu wiadomo, gdzie szukać. Ogólnie rzecz biorąc, korzystanie z tych domyślnych portów przyspiesza współpracę w zespole, bo każdy wie, gdzie szukać aplikacji, więc nie trzeba się rozpisywać w README, na jakim porcie coś działa. Moim zdaniem, to jeden z tych drobnych szczegółów, które składają się na dobre nawyki programistyczne.
Pytanie 28
W dwóch przypadkach opisano mechanizm znany jako Binding. Jego celem jest
A. przetwarzanie zdarzeń kontrolek interfejsu użytkownika przez wywoływanie odpowiednich funkcji
B. zarządzanie mechanizmem obietnic (promises) lub obserwatora (observable) w programowaniu asynchronicznym
C. wiązanie oraz eksportowanie plików z różnych modułów aplikacji
D. wiązać właściwości (property) elementu interfejsu użytkownika z danymi lub właściwością innego obiektu
Bardzo często można natknąć się na nieporozumienia dotyczące roli mechanizmu binding w nowoczesnych aplikacjach. Wiele osób błędnie utożsamia binding z obsługą zdarzeń, czyli na przykład automatycznym wywoływaniem funkcji po kliknięciu przycisku czy zmianie wartości na jakimś polu. Owszem, w interfejsach użytkownika obsługa zdarzeń jest istotna, ale binding to zupełnie inny poziom – on „przyczepia” dane (np. wartość liczbową, tekst, stan checkboxa) do właściwości elementów UI, tak by zmiana w jednym miejscu od razu aktualizowała drugie. Drugim typowym błędem jest mylenie bindingu z mechanizmami programowania asynchronicznego, jak promises czy observable – to trochę inna bajka. Promisy służą do obsługi operacji asynchronicznych, np. pobierania danych z sieci, a obserwatory pozwalają reagować na strumienie zdarzeń, jednak sam binding nie jest tym samym i nie odpowiada bezpośrednio za asynchroniczne zarządzanie danymi. Kolejnym nieporozumieniem bywa traktowanie bindingu jako coś związanego z eksportowaniem plików czy ogólnie zarządzaniem modułami aplikacji – to już w ogóle inny obszar, bardziej związany z organizacją środowiska, budowaniem aplikacji czy strukturą projektów. Z mojego doświadczenia wynika, że takie pomieszanie pojęć wynika głównie z powierzchownego poznania frameworków i chęci uproszczenia sobie obrazu działania aplikacji. Binding to fundament nowoczesnych interfejsów, ale nie zastępuje ani obsługi zdarzeń, ani nie jest narzędziem do zarządzania plikami czy asynchronicznością. On po prostu pozwala utrzymać spójność pomiędzy warstwą logiki a widokiem, co w praktyce czyni kod mniej podatnym na błędy i bardziej „żywym”, reagującym na zmiany.
Pytanie 29
W sekcji, która odpowiada za obsługę wyjątku wygenerowanego przez aplikację, należy to zdefiniować
A. finally
B. throw
C. catch
D. try
Wiele osób myli poszczególne sekcje obsługi wyjątków, co jest całkiem zrozumiałe, bo składnia bywa myląca, zwłaszcza na początku nauki. Sekcja finally jest często używana do sprzątania po operacjach, które mogą zgłaszać wyjątki, takich jak zamykanie plików czy połączeń sieciowych, ale nie służy do przechwytywania wyjątków – jej kod wykonuje się zawsze, niezależnie od tego, czy wyjątek wystąpił, czy nie. To taka gwarancja, że 'posprzątasz' po swojej operacji. Słowo throw natomiast wykorzystuje się do generowania własnych wyjątków – służy do 'wyrzucenia' wyjątku, a nie do jego obsługi. Czasami to dobre rozwiązanie, jak chcesz np. zakomunikować, że coś poszło nie tak w Twojej własnej logice, ale tym nie przechwycisz wyjątku. Try z kolei to miejsce, gdzie umieszczasz kod, który potencjalnie może rzucić wyjątek – stanowi on początek bloku obsługi wyjątków, ale sam nie przechwytuje, tylko wskazuje, co trzeba monitorować. Programiści czasami błędnie zakładają, że try automatycznie coś obsługuje, ale to tak nie działa – bez catch nie przechwycisz ani jednego wyjątku. Z mojego doświadczenia wynika, że najczęstszy błąd to mylenie throw z catch, bo oba występują w kontekście wyjątków, ale ich rola jest zupełnie inna. Throw inicjuje wyjątek, catch go przechwytuje. W dobrych praktykach branżowych jednoznacznie się podkreśla, że sekcję catch stosuje się do obsługi i reagowania na wyjątki, a try i finally to tylko części tej układanki. Takie rozróżnienie pomaga potem pisać bardziej przewidywalny i stabilny kod, a to według mnie w pracy programisty bywa kluczowe.
Pytanie 30
W środowisku IDE przeznaczonym do tworzenia aplikacji okienkowych zdefiniowano okno Form1. Aby wprowadzić zmiany w ustawieniach, w kolejności: tytuł okna na górnym pasku, standardowy kursor na strzałkę oraz kolor tła okna, należy dostosować następujące pola w oknie Properties:
A. (Name), UseWaitCursor, BackgroundImage
B. Text, Cursor, BackColor
C. Text, UseWaitCursor, BackColor
D. (Name), Cursor, BackgroundImage
W pracy z IDE do aplikacji okienkowych, bardzo łatwo pomylić znaczenie niektórych właściwości formularza, bo wiele z nich brzmi podobnie albo wydaje się spełniać podobną funkcję. Przykładowo, pole (Name) w oknie Properties nie ma żadnego wpływu na to, co widzi użytkownik w tytule okna – to jest nazwa techniczna obiektu w kodzie, czyli identyfikator, którym odwołujemy się do formularza w trakcie programowania. To megaważna różnica! BackgroundImage natomiast służy do ustawienia grafiki jako tła, a nie koloru – czasem ktoś myli BackColor z BackgroundImage, bo oba dotyczą wyglądu, ale BackColor to czysty kolor, bez obrazków. UseWaitCursor to kolejny haczyk – ta właściwość aktywuje specjalny kursor oczekiwania (taki kręcący się kółek lub klepsydrę), a nie domyślny wskaźnik w kształcie strzałki. Ustawienie tego pola na true sprawia, że użytkownik ma wrażenie, iż aplikacja coś przetwarza – super przydatne w operacjach długotrwałych, ale nie do standardowej obsługi okna. Cursor daje pełną kontrolę nad rodzajem kursora i to jest najlepszy wybór, gdy chodzi o standardowego pointera. Wreszcie, częsty błąd to branie pod uwagę właściwości, które po prostu nie dotyczą zadanego aspektu wizualnego formularza – na przykład mylenie tego, co widzi użytkownik, z tym, jak programista nazywa obiekt. Moim zdaniem, to taki typowy skrót myślowy: patrzymy na nazwę w oknie Properties i wydaje nam się, że to musi być to, co się zmienia na ekranie, a tu czasem logika IDE płata figle. W praktyce, poprawne podejście to zawsze zajrzeć do dokumentacji lub przeprowadzić szybki test – zmienić wartość i zobaczyć, co się realnie dzieje w oknie podglądu. To podstawowa umiejętność każdego, kto na serio chce projektować wygodne i profesjonalne interfejsy, zamiast działać na ślepo.
Pytanie 31
Jakie narzędzie można wykorzystać do stworzenia mobilnej aplikacji cross-platform w języku C#?
A. bibliotekę React Native
B. platformę Xamarin
C. środowisko XCode
D. środowisko Android Studio
Platforma Xamarin to naprawdę ciekawe narzędzie, które pozwala tworzyć aplikacje mobilne na różne platformy (np. Android, iOS) przy użyciu języka C#. Z mojego doświadczenia wynika, że Xamarin jest bardzo ceniony wśród programistów, którzy już znają .NET, bo w zasadzie pozwala używać tej samej logiki biznesowej w kodzie na wszystkie ważne systemy mobilne. To znacznie przyspiesza pracę, bo nie musisz oddzielnie pisać aplikacji na iOS i Androida, tylko duża część kodu jest współdzielona – zwłaszcza modele danych, logika, a nawet część interfejsu jeśli korzystasz z Xamarin.Forms. Przykładowo, budując prostą aplikację do zarządzania zadaniami, można stworzyć praktycznie cały kod w C#, a potem tylko lekko dostosować szczegóły UI pod każdą platformę. Co ważne, Xamarin udostępnia dostęp do natywnych API każdego systemu przez tzw. bindings, więc nie jesteś ograniczony do najprostszych scenariuszy. Microsoft mocno wspiera to rozwiązanie, a jego integracja z Visual Studio jest naprawdę wygodna. Moim zdaniem, jeśli ktoś zna C# i chce robić mobilki, to Xamarin jest jednym z rozsądniejszych wyborów. Oczywiście, obecnie coraz większą popularność zdobywa .NET MAUI, czyli następca Xamarin.Forms, który idzie jeszcze dalej i oferuje wsparcie również dla desktopów. Ale w praktyce, znajomość Xamarina to wciąż bardzo przydatna rzecz.
Pytanie 32
Metoda przeszukiwania w uporządkowanych tablicach, która polega na podzieleniu tablicy na kilka części i wykonywaniu wyszukiwania liniowego tylko w tej części, gdzie może znajdować się poszukiwany element, w języku angielskim jest określana jako
A. Jump search
B. Exponential search
C. Ternary search
D. Binary search
Jump search to faktycznie ta metoda, która polega na przeszukiwaniu uporządkowanej tablicy przez podział jej na bloki o określonej długości (zazwyczaj o rozmiarze pierwiastka kwadratowego z n, gdzie n to liczba elementów w tablicy). Najpierw skaczemy po tych blokach, żeby szybko ograniczyć obszar poszukiwań, a potem wykonujemy liniowe przeszukiwanie już tylko w wybranym przedziale. To sprawia, że jump search jest czymś pomiędzy wyszukiwaniem liniowym a binarnym – daje przyzwoity kompromis między prostotą a wydajnością, szczególnie gdy dostęp do pamięci jest kosztowny albo tablica jest zbyt duża, by od razu dzielić ją na pół jak w binary search. W praktyce jump search czasem się wykorzystuje tam, gdzie dane są przechowywane na przykład na dyskach magnetycznych czy SSD, a koszt losowego odczytu jest znacznie wyższy od odczytu sekwencyjnego. To jest też niezła opcja, gdy masz narzucone ograniczenia na algorytmy lub nie możesz sobie pozwolić na pełne binarne wyszukiwanie z różnych powodów technicznych. Warto też zauważyć, że jump search dobrze ilustruje ogólną ideę ograniczania przestrzeni poszukiwań bez konieczności przechodzenia przez wszystkie elementy – czyli bardzo praktyczne podejście, które daje się rozwinąć w innych algorytmach. Szczerze? Moim zdaniem, każdy, kto myśli o optymalizacji prostych operacji na dużych zbiorach danych, powinien przynajmniej raz przetestować jump search na własnych danych – efekty bywają zaskakująco dobre, zwłaszcza przy większych strukturach.
Pytanie 33
Jaka jest składnia komentarza jednoliniowego w języku Python?
A. ""
B. #
C. //
D. !
W programowaniu bardzo ważne jest rozróżnianie składni danego języka, bo nawet drobny błąd może skutkować tym, że kod nie zadziała albo zachowa się nieprzewidywalnie. Jeśli chodzi o komentarze jednoliniowe, Python stosuje do tego wyłącznie znak #. Często osoby zaczynające naukę Pythona mylą ten język np. z C#, C++ czy Javą, gdzie do komentarzy jednoliniowych używa się dwóch ukośników, czyli //. Takie podejście w Pythonie niestety nie działa – interpreter potraktuje // jako operator dzielenia całkowitego, a nie jako sygnał zignorowania reszty linii. Z kolei cudzysłowy, czyli "", są w Pythonie używane do oznaczania łańcuchów znaków (stringów), natomiast pojedynczy wykrzyknik (!) nie ma żadnego specjalnego zastosowania w kontekście komentarzy. To typowy błąd początkujących: mylą składnię z innych języków lub próbują zgadywać, zamiast sprawdzić dokumentację. Przy projektach zespołowych takie nieporozumienia mogą spowodować, że kod staje się mniej czytelny albo wręcz wywołuje błędy. Warto pamiętać, że dobry komentarz to nie tylko kwestia znaków – to też wyjaśnienie intencji i logiki działania kodu dla siebie i innych. W standardzie Pythona (PEP 8) jasno określono, że jedyną poprawną formą komentarza jednoliniowego jest użycie #. Pomijanie tej reguły może skutkować nie tylko błędami, ale też nieczytelnością kodu i trudnościami w jego utrzymaniu. W praktyce im szybciej wypracuje się nawyk poprawnego komentowania, tym lepiej dla całego procesu programowania i wspólnej pracy nad projektem.
Pytanie 34
Przedstawione logo praw Creative Commons umożliwia bezpłatne użytkowanie dzieła:
A. w celu modyfikacji lub remiksowania
B. w działaniach komercyjnych
C. pod warunkiem zachowania go w oryginalnej formie
D. pod warunkiem udostępnienia go na tej samej zasadzie licencyjnej
To, że odpowiedź dotycząca modyfikacji i remiksowania jest poprawna, wynika bezpośrednio z zasad licencji Creative Commons, a w tym przypadku – oznaczenia BY-NC. Licencja ta pozwala na używanie utworów, w tym także ich przerabianie i tworzenie nowych dzieł pochodnych, pod warunkiem podania autora i nieużywania do celów komercyjnych. W praktyce oznacza to, że możesz wziąć na przykład czyjąś grafikę na tej licencji, przerobić ją, dodać coś od siebie, zrobić z tego plakat na szkolną wystawę lub użyć fragmentu w prezentacji – o ile tylko przestrzegasz warunków. Z mojego doświadczenia wynika, że wiele osób myli się co do tego, że modyfikacja jest zabroniona – a właśnie Creative Commons daje tutaj spore pole do popisu. Zasada remiksowania jest wręcz promowana, bo pozwala rozwijać kulturę. Oczywiście, cały czas trzeba pamiętać o atrybucji twórcy i nie używać dzieła do zarabiania, bo wtedy łamiesz warunki licencji. W środowisku technicznym to jest bardzo praktyczne – możesz wzorować się na czyjejś pracy, rozwijać ją i poprawiać, co w branży IT, grafiki czy edukacji jest na porządku dziennym. Warto też zerkać do oficjalnych wytycznych Creative Commons: one wprost potwierdzają, że modyfikacja i adaptacja są dozwolone przy BY-NC, pod warunkiem braku komercji. W sumie – świetna opcja na rozwój własnych projektów!
Pytanie 35
Kod XAML zaprezentowany powyżej zostanie wyświetlony jako:
A. A
B. B
C. C
D. D
Wybrałeś dokładnie taką odpowiedź, jaką powinien wskazać każdy, kto dobrze rozumie XAML i układ StackLayout. Zobacz, co tu się dzieje: dwa pola Entry wyświetlają się jedno pod drugim, co daje klasyczną strukturę formularza – najpierw pole "Imię", potem "Nazwisko". Dalej mamy StackLayout z orientacją poziomą (Horizontal), więc etykieta "Zgoda RODO" oraz przełącznik Switch pojawiają się obok siebie – to bardzo typowy sposób na prezentację zgody na coś w aplikacjach, bo nie ma sensu rozdzielać tego na dwie linie. Po nich pojawia się Slider z ustawionym Value na 0.5 i kolorami MinimumTrackColor oraz MaximumTrackColor, czyli dokładnie tak jak widać na obrazku – jeden kolor po lewej, drugi po prawej i kółko pośrodku. Na końcu jest Button "Zapisz". Moim zdaniem, taki układ to wręcz klasyka budowy prostych formularzy w aplikacjach mobilnych opartych na XAML. Swoją drogą, to świetny przykład, jak StackLayout pozwala na szybkie i czytelne układanie elementów na ekranie, bez zbędnego komplikowania interfejsu. W praktyce warto jeszcze pamiętać, że oddzielenie pól Entry podnosi czytelność, a stosowanie układów poziomych sprawdza się wtedy, gdy chcesz, żeby użytkownik od razu widział etykietę i jej kontrolkę. Widać tu też dbałość o kolory i spójność wizualną. Według mnie, warto od razu testować takie formularze na różnych urządzeniach, bo StackLayout zachowuje się przewidywalnie, ale warto mieć na uwadze responsywność – no i nie zapomnij, że Slider i Switch mają swoje domyślne wartości, które można łatwo sterować z kodu.
Pytanie 36
Do stworzenia zbioru danych potrzebnego do uruchomienia algorytmu sortowania bąbelkowego tablicy, wymagane są przynajmniej następujące typy:
A. jeden tablicowy, jeden liczbowy do nadzorowania pętli, dwa do zamiany miejscami elementów
B. jeden tablicowy, dwa liczbowe do nadzorowania pętli, jeden do zamiany miejscami elementów
C. dwa tablicowe, jeden liczbowy do nadzorowania pętli
D. dwa tablicowe, dwa do zamiany miejscami elementów
Analizując temat tworzenia zbioru danych do sortowania bąbelkowego, nietrudno zauważyć kilka typowych nieporozumień. Spotykam się z nimi dość często, szczególnie u początkujących. Przede wszystkim, używanie jedynie jednego indeksu liczbowego do sterowania pętlą to stanowczo za mało – bubble sort opiera się przecież na dwóch przebiegach przez tablicę: zewnętrznym i wewnętrznym. Jedna zmienna sterująca nie jest w stanie ogarnąć tego mechanizmu, bo tracimy kontrolę nad porównywaniem odpowiednich elementów. Z drugiej strony, stosowanie dwóch tablic do sortowania tego samego zbioru to zupełnie niepotrzebne komplikacje i nieefektywność pamięciowa. Algorytm sortowania bąbelkowego sortuje 'in-place', czyli bez przenoszenia danych między różnymi tablicami – całość odbywa się w jednej strukturze danych. Często pojawia się też przekonanie, że do zamiany elementów trzeba dwóch oddzielnych zmiennych, co jest trochę błędnym tropem. Do zamiany miejscami wystarcza jedna zmienna tymczasowa; bardziej rozbudowane podejścia niepotrzebnie zaśmiecają kod. Pewną pułapką jest także myślenie, że liczba zmiennych sterujących pętlami można ograniczyć – w praktyce dla pełnej kontroli i zachowania standardów potrzebujemy dwóch liczbowych indeksów. Wśród branżowych dobrych praktyk przyjęło się nie tylko używanie minimum niezbędnych zmiennych, ale także dbanie o czytelność kodu i unikanie zbędnych komplikacji – bo to ułatwia późniejsze utrzymanie i zrozumienie algorytmu, zwłaszcza gdy kod przekazywany jest dalej. Moim zdaniem, te nieporozumienia wynikają z chęci uproszczenia algorytmu lub braku doświadczenia z klasycznymi, zagnieżdżonymi pętlami. Warto poświęcić chwilę, żeby prześledzić działanie sortowania bąbelkowego krok po kroku na kartce – wtedy od razu widać, ile i jakich zmiennych naprawdę potrzeba, żeby całość działała sprawnie i zgodnie ze sztuką programowania.
Pytanie 37
Który z wymienionych algorytmów działających na tablicy jednowymiarowej ma złożoność obliczeniową \( O(n^2) \)?
A. Wyświetlenie elementów
B. Wyszukiwanie metodą binarną
C. Sortowanie bąbelkowe
D. Sortowanie szybkie
Wypisanie elementów tablicy ma złożoność O(n), bo po prostu przechodzimy przez tablicę raz. Wyszukiwanie binarne, z drugiej strony, to coś, co ma złożoność O(log n) i działa w posortowanej tablicy – nie ma tu mowy o sortowaniu. A jeśli chodzi o sortowanie szybkie, to jego złożoność to O(n log n) i jest jednym z najszybszych sposobów sortowania. Więc nie pomylić sortowania z wyszukiwaniem, bo to dwie różne bajki.
Pytanie 38
Celem mechanizmu obietnic (ang. promises) w języku JavaScript jest
A. zastąpienie mechanizmu dziedziczenia w programowaniu obiektowym
B. zarządzanie funkcjonalnością związaną z kodem asynchronicznym
C. ulepszenie czytelności kodu synchronicznego
D. zarządzanie przechwytywaniem błędów aplikacji
Często można się pogubić, czym dokładnie są promises w JavaScript, zwłaszcza jeśli ktoś kojarzy je luźno z innymi mechanizmami programowania obiektowego czy obsługą błędów. Promises mają swoje korzenie w potrzebie efektywnego zarządzania asynchronicznością, czyli wykonywaniem operacji, które nie kończą się od razu, na przykład pobieraniem danych z sieci czy operacjami wejścia-wyjścia. To, że promises jakoś „ulepszają czytelność kodu synchronicznego”, jest trochę nadinterpretacją – bo one nie poprawiają kodu synchronicznego, tylko asynchroniczny czynią bardziej czytelnym. Dziedziczenie w programowaniu obiektowym, zarówno prototypowe, jak i klasyczne, to zupełnie inna para kaloszy – promises nie mają nic wspólnego z zastępowaniem tych mechanizmów, bo ich zadaniem nie jest kształtowanie struktury obiektów, a raczej kontrolowanie przepływu kodu w czasie. Zarządzanie przechwytywaniem błędów też nie jest głównym celem promises – choć rzeczywiście pozwalają na łatwiejszą obsługę błędów w kodzie asynchronicznym poprzez catch(), to jednak nie są uniwersalnym systemem zarządzania wyjątkami. Typowym błędem myślowym jest też mylenie promises z callbackami lub myślenie, że rozwiązują one wszystkie problemy związane z błędami – a to nie do końca prawda, bo promise jedynie porządkuje asynchroniczność i pozwala na prostsze reakcji na sukcesy i porażki asynchronicznych operacji. W praktyce promises to nie magiczna broń na wszystko, tylko bardzo sprytne narzędzie do ogarnięcia operacji nieblokujących w sposób czytelny, przewidywalny i zgodny ze współczesnymi standardami branżowymi.
Pytanie 39
Która z właściwości przycisków typu Radio-button opisanych w przedstawionym fragmencie dokumentacji jest poprawna?
Radio-button label
... The label can be positioned before or after the radio-button by setting the labelPosition property to 'before' or 'after'.
Radio groups
Radio-buttons should typically be placed inside of an <mat-radio-group> unless the DOM structure would make that impossible ... The radio-group has a value property that reflects the currently selected radio-button inside of the group.
A. Właściwość labelPosition może przyjmować jedną z dwóch opcji
B. Przyciski radio-button są organizowane w elemencie o nazwie <radio-group>
C. Wartość właściwości value grupy radio przechowuje tekst etykiety dla każdego radio-button
D. Etykieta (label) może być umieszczona wyłącznie po przycisku radio-button
Często się zdarza, że osoby pracujące z radio-buttonami skupiają się na nazwie elementu grupującego albo mieszają pojęcia związane z etykietami i wartościami. No właśnie – typowy błąd to przekonanie, że grupa radio to <radio-group>, podczas gdy np. w Angular Material używa się <mat-radio-group>. Standardy webowe nie definiują takiego elementu jak <radio-group>, to raczej wynalazek niektórych bibliotek. Kolejna kwestia to mechanizm value w grupie radio. On nie przechowuje tekstów etykiet, tylko wartość wybranego przycisku, czyli to, co deweloper przypisał do konkretnego radio-buttona (np. id, liczbę albo string techniczny). Gdyby wartość była powiązana z tekstem etykiety, trudno byłoby obsłużyć przypadki, gdy etykieta i wartość mają się różnić (a to się zdarza bardzo często, chociażby przy tłumaczeniach). Z mojego doświadczenia wynika, że zamieszanie powstaje też wokół samej etykiety – niektórzy sądzą, że label w radiobuttonach zawsze znajduje się po prawej stronie. W rzeczywistości dobre biblioteki dają wybór właśnie poprzez labelPosition – możemy bezproblemowo wyrenderować label z dowolnej strony guzika, wystarczy jeden parametr. Zresztą, to nie tylko kwestia wygody, ale też dostępności i zgodności ze standardami WCAG. Podsumowując: warto rozumieć fundamentalne różnice między etykietą, wartością i sposobem grupowania, bo to eliminuje wiele nieporozumień, które potem skutkują błędami zarówno w kodzie, jak i w interfejsie użytkownika.
Pytanie 40
Jaką nazwę elementu interfejsu należy wprowadzić w pierwszej linii kodu, na miejscu <??? aby został on wyświetlony w podany sposób?
Switch to bardzo charakterystyczny element interfejsu Androida, który służy do przełączania między dwoma stanami, np. włącz/wyłącz, tak/nie. Na screenie wyraźnie widać typowy suwak z okrągłym przyciskiem, który przemieszcza się na boki – dokładnie tak działa Switch. W kodzie XML także pojawiają się atrybuty takie jak text, textOff, textOn – one są właściwe właśnie dla komponentu Switch, bo pozwalają podpisać każdy ze stanów na przełączniku. Praktycznie w każdej nowoczesnej aplikacji spotyka się Switcha do wyrażania zgody, akceptacji regulaminu albo przełączania opcji (np. tryb ciemny). Z mojego doświadczenia to jest dużo wygodniejsze dla użytkownika niż klasyczne checkboxy, bo od razu widać, który stan jest aktywny – a UX-owcy też bardzo to chwalą. Warto pamiętać, że Switch ma swoje domyślne style zgodne z Material Design, więc aplikacja wygląda nowocześnie bez dodatkowej pracy. Dobrą praktyką jest wykorzystywanie Switcha właśnie wtedy, gdy potrzebujemy zmiany binarnej, a nie kilku opcji do wyboru. Jeśli ktoś myśli o bardziej zaawansowanych interfejsach, to Switch pozwala łatwo reagować na zmianę stanu w kodzie Java/Kotlin poprzez listener OnCheckedChangeListener. No i jest to jeden z tych komponentów, które naprawdę warto znać, bo są podstawą w każdym projekcie mobilnym.