Pięć projektów w języku Rust przeznaczonych do nauki, z kamieniami milowymi i ograniczeniami zapewniającymi bezpieczeństwo dzięki AI
Jak wybrać projekt w Rust, który zmusi cię do nauki koncepcji własności, obsługi asynchroniczności i równoległości, przy użyciu pięciu określonych pomysłów, etapowych celów oraz zasad korzystania z AI podczas nauki.
Źródła: 5 Rust Projects That Can Teach You More Than a Course
Rust wprowadza z góry wiele koncepcji: własność, pożyczanie, czas trwania, cechy, obsługę błędów, równoległość, asynchroniczność oraz ekosystem pakietów, którym trzeba się zapoznać, zanim cokolwiek przydatnego zostanie uruchomione. Wielu uczących się reaguje na to zbieraniem tutoriali, ale nadal utykają przed pustym plikiem main.rs. Bardziej skuteczną drogą jest wybór projektu na tyle trudnego, aby każda z tych koncepcji stanowiła problem do rozwiązania, a nie tylko rozdział do przeczytania. Ten przewodnik opisuje pięć takich projektów, czego każdy z nich cię nauczy, jak stworzyć pierwszą wersję, którą można ukończyć, oraz jak korzystać z pomocy sztucznej inteligencji, aby przyspieszyła ci pracę, nie zastępując przy tym twojego uczenia się.
Dlaczego trudny projekt jest lepszy od innego kursu
Kurs przedstawia koncepcje w kolejności wybranej przez kogoś innego, przy czym trudność jest już usunięta. Prawdziwy projekt robi coś przeciwnego – napotykasz przeszkodę, a ona podpowiada ci, jaką koncepcję musisz teraz poznać. Po drodze czytasz rzeczywistą dokumentację, podejmujesz decyzje architektoniczne, których później żałujesz, dekodujesz mylące błędy kompilatora, zauważasz problemy wydajnościowe i uczysz się, jak różne komponenty współpracują ze sobą. To właśnie takie umiejętności są przydatne w pracy zawodowej i trudno je nabyć pasywnie.
Pięć poniższych projektów zostało wybranych, ponieważ każdy z nich wykorzystuje jednocześnie kilka aspektów języka. Jeśli szukasz szerszego katalogu pomysłów, nasz wcześniejszy artykuł na temat uczenia się Rust poprzez dziesięć projektów obejmuje szerszy zakres tematyczny; tutaj nacisk kładziony jest na takie ukształtowanie każdego projektu, aby pozostał on edukacyjny, a nie przytłaczający.
Projekt 1: Twój własny agent do programowania w terminalu
Asystenci do programowania oparte na sztucznej inteligencji w linii poleceń to jeden z najbardziej dynamicznie rozwijających się obszarów narzędzi dla programistów. Narzędzia takie jak Claude Code, Codex oraz różne alternatywy open-source umożliwiają programiście określenie celu, a następnie agentowi sprawdzenie plików, wywołanie narzędzi, edycję kodu i przekazanie informacji zwrotnych, zamiast aby programista ręcznie wydawał każde polecenie. Uproszczona wersja tego cyklu stanowi doskonałe ćwiczenie z języka Rust, ponieważ obejmuje jednocześnie sieciowanie, procesy, system plików oraz interfejs użytkownika.
Cykl podstawowy jest prosty: użytkownik wpisuje tekst do interfejsu terminala, program przekazuje tę rozmowę modelowi językowemu, model może odpowiedzieć z prośbą o użycie narzędzia, kod w języku Rust uruchamia to narzędzie, a wynik wraca do modelu w celu wykonania kolejnego kroku.
You → Terminal UI → LLM → Tool Request → Your Rust Program → Result → LLM
Ciekawą kwestią jest strzałka idąca od modelu z powrotem do twojego programu. Model nigdy nie dotyka bezpośrednio twojego komputera; może jedynie pytać, a twój kod decyduje, czy i w jaki sposób należy zareagować. W tym obszarze granicznym znajduje się większość pracy nad projektowaniem.
Pierwsza wersja, którą możesz ukończyć
Zacznij od kilku narzędzi i niczego więcej:
- otwarcie i odczytanie pliku
- stworzenie lub nadpisanie pliku
- wyszukiwanie w katalogu
- wykonanie polecenia w shellu
- podanie podstawowych informacji o projekcie
- odesłanie wyniku każdego narzędzia z powrotem do modelu
Gdy ten pętla będzie działać poprawnie od początku do końca, rozwijaj ją stopniowo: przechowuj historię rozmów między kolejnymi krokami, przesyłaj odpowiedzi w momencie ich otrzymania, dodawaj sprawdzanie uprawnień przed wykonywaniem działań niszczących, opisuj narzędzia za pomocą wyraźnych schematów, umożliwiaj anulowanie trwającego kroku oraz poprawiaj sposób wyświetlania wyników w terminalu. Sprawdzanie uprawnień wymaga szczególnej uwagi – agent, który może wykonywać dowolne polecenia na twoim komputerze, powinien pytać przed zapisywaniem plików poza folderem projektu lub uruchamianiem czegokolwiek, czego wcześniej nie wykonywał.
Czego się nauczy
- async Rust oraz klienty HTTP do komunikacji z API modelu
- serializację i deserializację JSON dla żądań, odpowiedzi oraz wywołań narzędzi
- obsługę odpowiedzi przesyłanych strumieniowo
- tworzenie i zarządzanie procesami potomnymi
- API systemu plików
- modelowanie pętli agenta jako maszyny stanowej
Kolejną zaletą jest to, że projekt tak naprawdę nigdy się nie kończy. Można go dalej udoskonalać przez miesiące, co czyni z niego doskonałe środowisko testowe długoterminowe. Jeśli chcesz zobaczyć, jak ten sam mechanizm wygląda z perspektywy produktu i bezpieczeństwa, nasz artykuł na temat tworzenia osobistego agenta AI z uzyskanym dostępem omawia kwestię zaufania bardziej szczegółowo.
Zdecyduj, co chcesz optymalizować
Zanim napiszesz jakikolwiek kod, bądź szczery co do celu. Uczenie się Rusta, tworzenie projektu do portfolio, wypuszczanie narzędzia, którego będziesz używać codziennie, eksperymentowanie z sztuczną inteligencją oraz przygotowywanie się do pracy w dziedzinie systemów – wszystko to prowadzi do różnych decyzji. Projekt do portfolio wymaga dopracowania; codzienne narzędzie wymaga niezawodności; projekt edukacyjny wymaga wysiłku.
Jeśli priorytetem jest nauka, unikaj pozwalania asystentowi na stworzenie całego kodu. Usunięcie frustrujących części oznacza również utratę większości wiedzy, jaką te części mogłyby przynieść. Prośba o wyjaśnienie błędu w sprawdzaczu pożyczek lub uporządkowanie niejasnego fragmentu dokumentacji jest w porządku. Delegowanie projektowania, zanim zrozumiesz system, nie jest dobrym pomysłem. Projekt, którego zrozumienie zajmuje trzy dni, zazwyczaj uczy o wiele więcej niż ten stworzony w ciągu trzech godzin.
Projekt 2: aplikacja desktopowa z Tauri
Rust jest powszechnie kojarzony z serwerami, narzędziami wiersza poleceń oraz kodem niskopoziomowym, ale stanowi również doskonały wybór dla oprogramowania do biurka. Tauri łączy interfejs oparty na sieci z backendem w języku Rust, dzięki czemu można stworzyć aplikację przypominającą nowoczesne oprogramowanie biurowe pod względem wyglądu i funkcjonalności, przy czym kluczowa logika jest realizowana w Rust. Jeśli rozważasz Tauri w porównaniu z innymi opcjami, nasze porównanie frameworków JavaScript do biurka przedstawia zalety i wady każdego z nich.
Pomijaj ogólne listy zadań i stwórz coś, czego faktycznie używałbyś codziennie. Jednym konkretnym pomysłem jest lokalny asystent produktywności, który nagrywa dźwięk, przepisuje mowę na tekst, przechowuje notatki na twoim dysku i odczytuje wybrany tekst z powrotem do ciebie. Inne dobrych rozwiązań to osobisty organizator plików, środowisko pracy Markdown, panel dewelopera, narzędzie do obsługi mediów lub lokalne narzędzie AI.
Idea ma mniejsze znaczenie niż spójność pomiędzy interfejsem internetowym a lokalnym backendem. Każdy przycisk w interfejsie użytkownika ostatecznie stanowi żądanie przekazywane przez tę granicę, więc prawdziwą lekcją jest dobre zaprojektowanie tego interfejsu. Rozsądnym pierwszym celem jest dostarczenie jednej komendy z implementacji w Rust, wywoływanej z frontendu, która wykonuje coś, czego przeglądarka sama nie może zrobić, np. odczytuje listę plików w folderze.
Czego się nauczy
- strukturyzowanie aplikacji w Rust z więcej niż jedną warstwą
Ogólnie rzecz biorąc, oprogramowanie staje się znacznie trudniejsze, gdy musi współpracować z rzeczywistym systemem operacyjnym. Odczytanie pliku to prosta operacja. Bezpieczne obsługiwanie plików, klarowne raportowanie błędów, utrzymanie responsywności podczas wolnych operacji oraz zachowanie się tak samo na różnych maszynach to zupełnie inny problem, a właśnie ta różnica stanowi cenną lekcję.
Projekt 3: gra typu tower defense w Bevy
Gra jest jednym z niewielu projektów, które mogą sprawić, że zapomnisz o nauce. Jest też wymagającym nauczycielem, ponieważ w każdej kadrze musi działać jednocześnie wiele systemów: entity’y, dane od gracza, fizyka, renderowanie, synchronizacja czasowa, przejścia między stanami oraz ograniczenia wydajnościowe, które utrzymują wszystko w ryzach.
Bevy doskonale pasuje do osób uczących się Rust, ponieważ jest zbudowany na bazie systemu Entity Component System (ECS). Zamiast dużych obiektów, które łączą we sobie wszystkie zachowania, entytet to w zasadzie tylko identyfikator z dołączonymi komponentami, a systemy to funkcje, które działają na każdym entytecie posiadającym określony zestaw komponentów. Projektil może mieć pozycję, prędkość i wartość szkody; system ruchu aktualizuje wszystko związane z pozycją i prędkością, a system kolizji zajmuje się wszystkim, co powoduje szkodę. Ta zmiana z obiektów na dane w połączeniu z funkcjami to jeden z najcenniejszych modeli myślowych, jakie Rust i Bevy mogą ci zapewnić.
Dlaczego konkretnie gatunek obrony wieży
Gatunek ten szybko zwiększa liczbę entytetów, co właśnie sprawia, że jest tak edukacyjny. Jedna mapa może zawierać:
- setki wrogów jednocześnie
- wielokrotne wieże o różnych zachowaniach
W takim skali poprawność nie jest już jedynym pytaniem. Zaczyna się zastanawiać, ile pracy wykonuje gra na każdym kadru. To pytanie naturalnie prowadzi do profilowania, układu danych, planowania działania systemów, wykorzystania pamięci oraz doboru algorytmów, które nie przestają działać wraz ze wzrostem liczby elementów. Dobrym pierwszym celem jest stworzenie pojedynczego wroga poruszającego się po ustalonej ścieżce oraz pojedynczej wieży, która do niego strzela; wszystko inne można dodać po ustabilizowaniu tego cyklu.
Czego się nauczy
- jak jest zorganizowany system Entity Component System
- cykl gry i timing kadrów
- reagowanie na zdarzenia
- zarządzanie stanem pomiędzy menu, poziomami a końcem gry
- profilowanie wydajności
- projektowanie zorientowane na dane
- zarządzanie zasobami
- zasady renderowania
- obsługa danych wejściowych
- optymalizacja
Gry uczą również czegoś, czego rzadko potrafią zrobić tutoriale: jak kilka niezależnych systemów współpracuje, gdy program staje się naprawdę złożony, oraz jak małe zmiany w jednym systemie wpływają na pozostałe.
Projekt 4: urządzenie wbudowane z ML w miejscu obliczeń
Dokładnie tutaj, przy ograniczonym sprzęcie, Rust staje się jeszcze ciekawszy: mało pamięci, niewielki budżet mocy oraz ograniczony czas działania CPU. Zamiast celować w laptopa, skup się na mikrokontrolerze lub małym urządzeniu brzegowym.
Prawdziwym przykładem jest urządzenie, które obserwuje swoje otoczenie i reaguje na zmiany. Może mierzyć:
- temperaturę
- wilgotność
- poziom oświetlenia
- ruch
- dźwięk
- inne wartości z czujników
Ponadto można dodać kompaktowy model uczenia maszynowego do jednego konkretnej zadania: wykrywania anomalii, rozpoznawania gestów lub słuchania specjalnego słowa aktywującego. Model powinien być prosty; prawdziwe wyzwanie polega na dopasowaniu wszystkiego do ograniczonego sprzętu.
Aby zacząć, nie potrzeba drogiego sprzętu. Emulator lub symulator wystarczą do zapoznania się z architekturą i technikami programowania, a na fizyczną płytę można przejść, gdy oprogramowanie będzie działać poprawnie.
Dlaczego Rust w zastosowaniach wbudowanych wydaje się inny
Program na komputerze stacjonarnym korzysta z pełnej biblioteki standardowej, dużej ilości pamięci, szybkiego procesora oraz systemu operacyjnego, który zajmuje się niezliczonymi detalami na niskim poziomie. W rozwoju oprogramowania wbudowanego większość z tego jest usuwana, co rodzi nowy zestaw zagadnień:
no_stdw Rust, gdy biblioteka standardowa nie jest dostępna- praca w ścisłych ograniczeniach pamięci
- interfejsy sprzętowe
To jeden z najjaśniejszych przykładów wyjaśniających, dlaczego Rust ma znaczenie poza zwykłymi aplikacjami. Trzeba zrozumieć, co naprawdę robi maszyna, ponieważ nie ma nic pod spodem, co mogłoby to ukryć. Praca w obszarze systemów wbudowanych łączy również Rust z robotyką, systemami samochodowymi, urządzeniami przemysłowymi oraz innymi dziedzinami wymagającymi dużych zasobów sprzętowych.
Projekt 5: adaptacyjny balanser obciążeń
Dla programistów zajmujących się backendem, kolejna API typu CRUD rzadko znacząco rozszerza ich umiejętności. Budowa infrastruktury natomiast tak robi. Dobrym przykładem jest balanser obciążeń – znajduje się pomiędzy klientami a zbiorem serwerów backendowych i dla każdego przychodzącego żądania decyduje, który z pracowników powinien je obsłużyć, zamiast kierować cały ruch do jednej maszyny.
Bazowa struktura jest prosta: klienci łączą się z procesem napisanym w Rust, a ten przekazuje każde żądanie do jednego z kilku pracowników.
┌─────────────┐
│ Clients │
└──────┬──────┘
│
▼
┌─────────────────┐
│ Rust Load │
│ Balancer │
└───────┬─────────┘
┌───┴───┐
▼ ▼
┌────────┐ ┌────────┐
│Worker 1│ │Worker 2│
└────────┘ └────────┘
Etapy rozwoju od prostego do adaptacyjnego
Zacznij od zwykłej rotacji żądań, przy której każde żądanie trafia kolejno do następnego pracownika. Jest to proste do zrozumienia i stanowi podstawę. Następnie stopniowo dodawaj elementy inteligencji:
- mierz czas odpowiedzi i wskaźniki błędów dla każdego pracownika
- wykrywaj niesprawne pracowniki i przestań kierować do nich żądania
- wdrażaj limity połączeń
Ostatecznie balanser może dostosować swoje zachowanie do rzeczywistych warunków ruchu zamiast postępować według sztywnej zasady.
Gdzie pojawiają się trudności
Załóżmy, że jeden z procesorów nagle zwalnia. Czy nowe żądania powinny nadal trafiać tam? Prawie na pewno nie. Jeszcze trudniej jest sobie wyobrazić sytuację, gdy kilka procesorów pogarsza swoją wydajność jednocześnie, z różnych powodów: jeden jest przeciążony, u drugiego problematyczny jest połączenie sieciowe, a trzeci zajmuje się sprzątaniem pamięci. System musi obserwować to, co się dzieje, i szybko podejmować decyzje, nie stając się samym wąskim gardłem. Rozwiązywanie tego problemu wymaga znajomości:
- konkurencji
- podstaw sieciowych
- TCP i HTTP
- odwrotnego proxyingu
- sprawdzania stanu i czasów wygaśnięcia
- gromadzenia połączeń do procesorów
- zbierania metryk
- rozdzielonego rozkładu obciążenia
- opór przy dużym obciążeniu, gdy wszystkie procesory są zajęte
- grzeczne radzenie sobie z awariami
- myślenie w kategoriach systemów rozproszonych
Można eksperymentować z polityką routingu wspomaganą przez sztuczną inteligencję, ale traktować to ściśle jako eksperyment. Infrastruktura krytyczna nigdy nie powinna ślepo polegać na decyzjach modelu – zawsze musi istnieć deterministyczne rozwiązanie awaryjne. Sama sztuczna inteligencja nic nie dodaje; celem jest sprawdzenie, czy faktycznie poprawia system w porównaniu z prostą, dobrze zrozumianą strategią.
Co łączy te projekty
Wspólnym elementem nie jest składnia. To złożoność, której nie da się uniknąć.
Tutorial może pokazać, jak działa Arc<Mutex<T>>; projekt sprawia, że samodzielnie odkrywasz, dlaczego stan wspólny w ogóle wymaga synchronizacji, zazwyczaj po tym, jak kompilator odmawia umożliwienia jego niebezpiecznego udostępniania. Funkcje asynchroniczne łatwo jest wyjaśnić na papierze; prawdziwa aplikacja pokazuje, co się dzieje, gdy kilka zadań ze sobą wchodzi w interakcję, gdy żądanie zostaje anulowane w połowie lub gdy łącze sieciowe się rozrywa. Książka może wyjaśnić koncepcję własności; projekt zmusza cię do projektowania struktur, w których każdy zasób ma właściwego właściciela i jest zwalniany we właściwym czasie. To właśnie ta luka stanowi różnicę między znajomością języka a umiejętnością budowania oprogramowania przy jego użyciu.
Wybierz projekt, który jest nieco trudny
Korzystna zasada wyboru: wybierz coś nieco ponad twoje obecne umiejętności. Nie powinno to być niemożliwe, ani coś, co już potrafisz zbudować. Dobry projekt sprawia, że wielokrotnie uświadamiasz sobie, iż nadal nie wiesz, jak działa jakaś jego część.
To uczucie jest dobrym znakiem. Bądź przygotowany na czytanie dużej ilości dokumentacji, łamanie kodu, błędne interpretowanie interfejsów API, pisanie abstrakcji, które okazują się nieskuteczne i późniejszą ich zastąpienie, a także na kłótnie z kompilatorem więcej niż raz. Po kilku dniach coś, co wydawało się niemożliwe, stanie się zrozumiałe. Takiego doświadczenia bardzo trudno odtworzyć, oglądając kolejny tutorial.
Wykorzystywanie sztucznej inteligencji bez zlecania nauki innym
Sposób, w jaki korzystasz z pomocy sztucznej inteligencji, może bardziej wpłynąć na to, ile projekt cię nauczy, niż jakikolwiek inny czynnik. Współczesne asystenci są naprawdę przydatne: wyjaśniają komunikaty o błędach, skracają długą dokumentację, proponują rozwiązania i pomagają w analizie błędów. Kluczowe jest odróżnienie korzystania z sztucznej inteligencji jako narzędzia od używania jej jako zamiennika dla rzeczywistego zrozumienia.
Dla projektu skupionego na nauce, przydatna dyscyplina wygląda następująco:
- napisz pierwszą wersję sam
- przeczytaj odpowiednią dokumentację przed proszeniem o pomoc
- spróbuj rozwiązać każdy problem sam przed zapytaniem o rozwiązanie
- gdy utkniesz, poproś o wyjaśnienie zamiast gotowego kodu
- wdroż sam poprawkę, nawet jeśli już wiesz, jak powinna wyglądać
- upewnij się, że potrafisz wyjaśnić każdą ważną część systemu bez szukania informacji
To wszystko nie oznacza unikania sztucznej inteligencji. Oznacza to upewnienie się, że to ty nadal myślisz.
Dopasowanie projektu do twoich celów
Pozwól, by rodzaj inżyniera, którym chcesz zostać, naprowadził cię przy wyborze:
- Sztuczna inteligencja i narzędzia deweloperskie: stwórz agenta do programowania w terminalu
- Oprogramowanie desktopowe: stwórz aplikację Tauri
- Gry i wydajność: stwórz grę typu tower-defense w Bevy
- Robotyka, sprzęt lub praca na niskim poziomie: stwórz urządzenie wbudowane
- Infrastruktura backendowa i systemy rozproszone: adaptacyjny balanser obciążeń
Niezależnie od wyboru, nie dąż do doskonałości. Uruchom najprostszą działającą wersję, a następnie ją udoskonalaj.
Główne wnioski
- Wybieraj projekty, których trudność zmusza cię do zajmowania się zarządzaniem własnością danych, równoczesnym wykonywaniem zadań, obsługą asynchroniczności i błędów, zamiast czytać o tym tylko w teorii.
- Zdefiniuj mały pierwszy etap dla każdego projektu i rozwijaj go stopniowo; działający prosty cykl uczy więcej niż ambitny projekt, który nigdy nie zostanie uruchomiony.
- Zdecyduj z góry, czy uczysz się, tworzysz element portfolio, czy wdrażasz narzędzie, ponieważ każdy cel wymaga innych sposobów skrócenia drogi.
- Wykorzystuj sztuczną inteligencję do wyjaśniania, a nie do tworzenia treści, skupiając się na nauce, oraz zachowaj metody awaryjne tam, gdzie model podejmuje decyzje w rzeczywistym systemie.
- Cykl tworzenia, łamania, badania, przeprojektowania i optymalizacji jest źródłem większości wiedzy o Rust, a tydzień pracy nad nim może przewyższyć wartość wielu godzin spędzonych na pasywnych tutorialach.
Literatura pokrewna
- Uczenie się Rust poprzez dziesięć projektów, od narzędzi CLI do usług inferencji — Stopniowa ścieżka dziesięciu projektów w języku Rust, od narzędzia do skanowania logów do klonu Redis, środowiska wiersza poleceń oraz usługi inferencji, z wyjaśnieniem tego, czego każdy z nich uczy na temat zarządzania pamięcią, równoległości i radzenia sobie z awariami.
- Budowanie bezpiecznych agentów AI za pomocą LangChain Guardrails i middleware — Dowiedz się, w jaki sposób mechanizmy deterministyczne i oparte na modelach działają w LangChain, aby wykrywać wycieki danych osobowych, egzekwować zasady biznesowe oraz dodawać kroki zatwierdzenia przez człowieka do agentów AI.