Widzieliście już nową serię filmów na moim kanale YT? To jest coś, czego do tej pory brakowało w świecie embedded. Pokazuję w niej prawdziwy projekt. Nie tylko z ostateczną wersją kodu, ale również z całą ewolucją, decyzjami i czynnikami wpływającymi na te decyzje. A wszystko to bez zbędnego lania wody – same konkrety. Aby utrzymać zwięzłość materiału zdecydowałem się nagrać to w formie filmów, a nie live.

W tym poście napiszę więcej o samym projekcie i kulisach jego powstawania. A jeżeli chcesz od razu przejść do oglądania – poniżej znajdziesz playlistę ze wszystkimi opublikowanymi do tej pory odcinkami.

Dlaczego projekt?

Nieraz mi zgłaszaliście, że chcecie się uczyć na bazie projektów. Chcecie zobaczyć od razu jak wykorzystać wiedzę w praktyce. To jest niesamowicie ważne. Zastrzyk dopaminy kiedy widzimy, że nasz projekt działa zgodnie z założeniami to jedna z większych motywacji do nauki.

Jednak każdy kij ma dwa końce. Pewne aspekty nauki na bazie projektów mogą być jednocześnie zaletami i wadami. Na przykład – w projekcie musimy od razu mieć wiedzę z wielu różnych dziedzin. Z jednej strony to dobrze, bo uczymy się ich jednocześnie oraz rozwiązujemy problemy na styku np. hardware’u i kodu. Ale z drugiej strony nie możemy tak bardzo wgłębić się w szczegóły konkretnego tematu. Każdy projekt pomaga lepiej radzić sobie ze specyficznymi grupami problemów. Aby poznać inne grupy, trzeba robić inne projekty. Między innymi dlatego dojście do poziomu seniora zajmuje wiele lat i wymaga wielu projektów.

Projekt to zwykle kompromis między rozwiązaniem idealnym, a wystarczająco dobrym biorąc pod uwagę koszty, ramy czasowe i wiele innych czynników. Podczas nauki ma to swoje wady. Nie jesteśmy w stanie w ten sposób nauczyć się jasnych zasad i dobrych praktyk skoro będą co chwilę naginane w imię kompromisów projektowych. Ale ma również swoje zalety – w końcu tak wygląda realna praca jako programista. Musimy znać różne opcje, podejmować decyzje i je argumentować. To ważna umiejętność, ale wszystko powinno mieć swoje miejsce i czas oraz odbywać się w odpowiednim kontekście.

Właśnie dlatego projekty są nieodzowną częścią nauki systemów embedded, ale nie jedyną. U mnie znajdziecie już całkiem sporo wchodzenia głębiej w pojedyncze tematy. A analizy projektów trochę brakowało. Pora to zmienić!

Dlaczego ten projekt jest wyjątkowy?

Przecież w internecie jest sporo tutoriali przedstawiających powstawanie różnych projektów. Sam nawet robiłem kiedyś podobny projekt zegara szachowego na live. Ale zawsze jest coś, co sprawia, że nie przedstawiają one faktycznego procesu pracy nad projektem.

Wiele tutoriali opisuje proste projekty, gdzie od razu wiemy, co chcemy zrobić. Nie ma procesu błądzenia i dochodzenia do optymalnego rozwiązania. Autor po prostu pokazuje ścieżkę do zrealizowania projektu.

Czasami mamy też do czynienia z większymi projektami, gdzie jest pokazywane docelowe rozwiązanie. Nie ma natomiast procesu dochodzenia do tego rozwiązania. To znaczy w procesie tworzenia pewnie był. Natomiast wersja opublikowana w internecie już go nie zawiera. W ten sposób powstaje w naszych głowach błędny obraz, że najpierw wszystko planujemy, a potem wdrażamy bez żadnych niespodzianek.

Potem kiedy siadamy do własnego projektu dochodzimy do ściany. Nasze pomysły nie są tak sprecyzowane (bo nie mamy jeszcze takiej wiedzy o systemie) i nie jesteśmy w stanie od razu wpaść na docelowe rozwiązanie. Prawdziwy projekt to również próby i błędy, które zwykle w takich tutorialach nie są widoczne.

Z kolei projekty, gdzie są omawiane decyzje i pokazywane wszystkie kroki często nie są doprowadzane do końca, albo mocno rozpraszają się na wątki poboczne. Dokładnie taki problem miałem z poprzednią wersją zegara szachowego.

Założenia

Właśnie dlatego ten projekt ma jasne założenia i swoje decyzje projektowe motywuję jak najefektywniejszą ich realizacją. Jakie to założenia?

Przede wszystkim to prototyp. Celem projektu jest jak najszybsza implementacja wszystkich wymagań i zidentyfikowanie możliwych trudności. Prototyp ma odpowiedzieć nam na pytanie, czy będziemy w stanie zrealizować wersję produkcyjną. Dlatego dopieszczanie szczegółów zostawiamy na później. Wpływ tego założenia widać na każdym kroku!

A teraz więcej o założeniach funkcjonalnych. Chcę zrobić zegar szachowy umożliwiający grę turniejową we wszystkich popularnych trybach. Muszę więc obsłużyć upływ czasu, dodawanie sekund na ruch i bonus po wykonaniu zadanej liczby posunięć. Do tego zegar ma umożliwiać konfigurację początkową, edycję czasu przez sędziego w trakcie partii i być w miarę podobny do istniejących rozwiązań.

Jak przystało na prototyp – hardware robię wykorzystując gotowe płytki i układy połączone na płytce stykowej. Docelowe PCB, ładna obudowa, ergonomiczne przyciski, czytelne wyświetlacze – to wszystko tematy na wersję produkcyjną. Wpływ głównego celu widzicie już tutaj – na poziomie formułowania wymagań.

Więcej o założeniach w dedykowanym odcinku:

A dlaczego dopiero w drugim, a nie w pierwszym? O tym za chwilę.

Jak powstawał projekt?

Wpływ głównego celu jeszcze lepiej widać w kolejnych odcinkach, gdzie omawiam poszczególne etapy pisania kodu.

Zawsze najpierw wybieram najprostszą drogę, która może zadziałać. Potem refactor dopiero, kiedy jest potrzebny. Czyli kiedy aktualna struktura kodu tak przeszkadza mi w dodaniu kolejnych rzeczy, że łatwiej będzie przejść na inne rozwiązanie.

Dlatego zacząłem od wyklikania projektu w STM32 Cube. Posłużyłem się również Czatem GPT. Jeżeli uda się zrealizować wszystkie założenia prototypu w ten sposób – super. Osiągnę cel i nie stracę czasu na konfigurację. Jeżeli nie – dodaję konkretne narzędzia wtedy, kiedy są mi potrzebne. Znajdziecie to w odcinku nr 1:

Natomiast później wchodzą moduły, interfejsy i różne wzorce projektowe.

Szczerze mówiąc – na początku jeszcze nie wiedziałem, że będę robić projekt zegara. Chciałem pobawić się czatem GPT i sprawdzić jego możliwości na prostym projekcie. Potem miałem kod, prototyp na płytce stykowej i dwa tygodnie wolnego czasu w okolicach Bożego Narodzenia i Nowego Roku. Postanowiłem napisać prototyp zegara dla własnej satysfakcji. Prace szły szybko, projekt się rozszerzał. Widziałem jak ewoluuje pod wpływem decyzji projektowych.

Dokładnie tak samo potraktowałem wprowadzanie do projektu narzędzi. Nie ma nic gorszego niż trwający tygodniami setup na samym początku. Bo konfigurujemy edytor, build system, continuous integration, automatyzację testów itd. W efekcie nigdy nie dochodzimy do kodu, a konfiguracji nawet nie użyjemy w praktyce.

Prace szły szybko, projekt się rozszerzał. Widziałem jak ewoluuje pod wpływem decyzji projektowych. Pojawiają się moduły, interfejsy, wzorce projektowe. W końcu przechodzę z STM32 Cube na VS Code + CMake. Następnie dodaję testy automatyczne.

Dlatego stwierdziłem, że może z niego powstać świetny materiał edukacyjny. Mając realny projekt mogę dużo lepiej wytłumaczyć kiedy i dlaczego stosować różne techniki programistyczne. Widząc kod przed i po zmianie od razu wiemy, co dostajemy. Widać to na przykład w odcinku nr 3, gdzie po raz pierwszy pojawiają się interfejsy:

Szczególnie ciekawe rzeczy dopiero pojawią się w późniejszych odcinkach.

Gdzie znajdę ten projekt?

Na dzień dzisiejszy ukazały się 4 odcinki (premiera piątego jutro):

Możecie również zobaczyć cała playlistę (uzupełnianą na bieżąco o nowe odcinki).

Kolejne odcinki będą się ukazywać dwa razy w tygodniu. Łącznie będzie ich 12. Projekt prototypu został zrealizowany już wcześniej. Dopiero później wziąłem się za uwiecznianie go w formie wideo. Oczywiście to nie jest tak, że z góry planowałem akurat 12 odcinków. Po prostu tyle mi zajęła realizacja początkowych założeń i wytłumaczenie poszczególnych decyzji.

Z kolei na GitHubie znajdziesz kod dla całego projektu.

Możesz tam znaleźć kolejne commity pokazujące poszczególne kroki prac nad projektem. Dodałem również tagi oznaczające kod na początku każdego odcinka.

Dzięki temu możesz sobie dokładniej przeanalizować poszczególne zmiany w kodzie. Możesz również przeglądać kod razem z oglądaniem wideo, pauzować nagranie i wszystko na spokojnie analizować. Taką formę przedstawiania projektu stosowałem już w kursie TDD Embedded do biblioteki Modbus i fajnie się to sprawdzało.

Co dalej?

Założenia dotyczące prototypu zostały zrealizowane. Oczywiście z tego miejsca mogę projekt pociągnąć dalej. Jak by to wyglądało w praktyce? Zrobiliśmy przykładową implementację głównych elementów systemu. Wiemy, że dalej sobie poradzimy. Teraz projekt przeszedłby w fazę dopieszczania szczegółów i ewolucji z prototypu do komercyjnego produktu.

To właśnie ten moment, kiedy możemy dodać kolejne narzędzia np. analizę statyczną, continuous integration. Możemy usiąść nad docelowym PCB, czy projektem mechanicznym Możemy też dodać nowe funkcjonalności po stronie programu np. nowe tryby, rozbudowanie istniejących, integracja z systemem do transmisji partii na żywo, bootloader, info o poziomie baterii, zapamiętywanie konfiguracji w EEPROM. Więcej o tym mówię w odcinku nr 12 (który dopiero się ukaże).

W komercyjnym projekcie tak właśnie byśmy zrobili. Taki tryb pracy można spokojnie stosować również we własnych hobbystycznych projektach. Możemy wtedy sami decydować czy wolimy dopracowywać ten projekt, czy może zająć się kolejnym.

Ja wybrałem bramkę nr 2. Projekt zrealizował swój cel i nie będę go w najbliższym czasie dalej rozwijać. Za to jeżeli ta seria przypadnie Wam do gustu – przygotuję w podobny sposób kolejne projekty