Wielu z nas obiła się o uszy teoria 10 000 godzin. Zakłada ona, że aby osiągnąć mistrzostwo – albo pierwszy, najniższy stopień mistrzostwa, czymkolwiek on jest – trzeba nad czymś spędzić przynajmniej tyle czasu. Oznaczano ją już jako mit, oznaczano jako prawdę objawioną. Czy faktycznie potrzeba aż takiego nakładu? Nie wiemy, ale ryzyko błędów dobrze dostrzec na początku. Rozmawiam z naszym programistą Marcinem Lesińskim.
![](https://botland.com.pl/blog/wp-content/uploads/2020/11/kodowanie.jpg)
Czytelnicy bloga Botland znają Marcina m.in. z artykułów o druku 3D, projektów inteligentnego domu na bazie Raspberry czy tworzenia własnego oświetlenia ambient dla telewizorów. Mogliście zobaczyć go także na naszym kanale YouTube.
Oskar: Prosto z mostu. Czego musi unikać początkujący programista?
Marcin: Myślę, że zamiast mówić o tym, czego musi się wystrzegać początkujący programista, należy raczej zająć się tym, na co powinien zwracać uwagę. Podstawą udanego kodowania jest dbałość o szczegóły oraz umiejętność myślenia przyczynowo-skutkowego. To, po dodaniu szczypty kreatywności, daje nam przepis na programistę. Podstawowe atuty dobrego kodu to... cóż, najpierw czytelność. Musimy mieć pewność, że jakakolwiek zmiana w programie nie zmusi nas do szukania fragmentu odpowiedzialnego za daną funkcję nawet przez kilka godzin. Starajmy się też być konsekwentni w używaniu odpowiednio usystematyzowanych nazw zmiennych.
Mówisz o dbałości o szczegóły. Rozumiem, że wyjątkowo częste są błędy z nieuwagi.
Tak, nieuwaga, pośpiech i ponawiane próby interpretacji sensu programu sprawiają, że łatwo o pomyłkę lub powolny kod. Często elementem składowym kodu, który sprawia największe problemy, są tabulatory w kodzie. Mówimy tutaj o języku Python, nie rzadziej zdarza się zapomnieć średnika, czy źle definiować daną funkcję.
"Powolny kod"?
Każdy, który wykonuje się wolno, a mógłby szybciej. Przez zbędnie dużą objętość generuje obliczenia i zajmuje procesor. Przekombinowany.
Wspomniałeś o języku Python, który uchodzi za niewybaczający najmniejszych pomyłek. Wiąże się to pewnie z doborem odpowiedniego języka dla siebie.
Tak, masz rację, jednak nie bójmy się takich języków. Większość z nas zaczynała od tworzenia prostych stron w HTML, a kończyła kilka lat później pisząc oprogramowania zakrawające o obsługę sztucznej inteligencji czy uczenia maszynowego. Ale to tak bardziej o mnie (śmiech). Uważam, że każdy język programowania jest dobry - warto zaczynać od prostych przykładów i zastanowić się nad tym, do czego użyjemy danego języka. Patrząc na przykład stworzonego na naszym blogu projektu systemu dla inteligentnego domu możemy pomyśleć, że jedynym rozwiązaniem będzie Python, ale dlaczego? Bo jest popularny wśród użytkowników Raspberry Pi? Bzdura. To zbędne utrudnienie, korzystamy tutaj z PHP i odwołań do bazy danych w MySQL, i stworzyliśmy tym sposobem dużo bardziej składny kod niż w przypadku tworzenia każdej kondygnacji kodu w osobnym pliku. Wracając do samych podstaw programowania najlepiej zacząć od nauki podstaw języka angielskiego, oczywiście na szczeblu technicznym. Wybór samego języka to kwestia indywidualna, nie chciałbym tutaj doradzać.
Konwencja dzisiejszej rozmowy to poszukiwanie pułapek. Co z kodem nieskładnym? Czym grozi zabałaganiony lub zbyt skomplikowany kod w praktyce?
O ile wiemy, że z kodu będziemy korzystać tylko my i będzie on działał najwyżej kilka dni, to tak naprawdę niczym. Jednak zwracajmy uwagę na dobre nawyki i od początku wyjaśnijmy, na czym polega ta bolączka. Zbyt skomplikowany kod to niesamowicie częsty problem początkujących, często funkcja która może być zawarta w kilku linijkach kodu jest rozwijana do kilkudziesięciu lub nawet kilkuset linijek. Nieprzejrzysty kod może być jak język małego dziecka, który rozumieją tylko rodzice. A co, jeżeli ktoś usiądzie do tego kodu ktoś inny?
Dlaczego? A raczej: skąd to się bierze?
Wynika to najczęściej z niewiedzy i nieznajomości funkcji danego języka lub wątpliwych prób ulepszenia kodu. Jednak prawda jest taka, że im szerzej próbujemy opisać coś w kodzie, tym gorzej to wychodzi. Dodatkowo pamiętajmy o tym, że im więcej kodu jest do przetworzenia, tym więcej czasu zajmie to procesorowi. Oczywiście pisząc program, który będzie sterował światłem w domu, nie będzie to zauważalne. Natomiast przy obsłudze bazy danych, w której jest kilka tysięcy rekordów, program zostanie mocno spowolniony, tam zauważymy to na pewno. Jeśli mówimy o bałaganie w kodzie, to powód, dla którego warto regularnie “sprzątać kod”, jest tylko jeden - łatwiej będzie nam cokolwiek w nim znaleźć i w razie potrzeby usunąć lub poprawić.
Z Twoich słów wynika, że stawiający pierwsze kroki w środowisku chcą na nowo wynajdować koło. Biorą się za zadania naprawdę trudne. Co sądzisz na przykład o zabieraniu się za pisanie własnej biblioteki?
Zuchwałe rzemiosło. Myślę, że to błąd, strata czasu i zupełnie niepotrzebne działanie, o ile nie tworzymy komercyjnego projektu, który ma być idealnie dopasowany pod konkretne potrzeby. Żyjemy w dobie Internetu. Trudno znaleźć problem, który nie był już gdzieś opisany. Oczywiście mówię o projektach tworzonych przez początkujących, na wyższych poziomach bywa ciężej.
Okej, rozróżnijmy jeszcze na prostym przykładzie praktycznym co robi biblioteka, a co kod.
Tak, warto rozróżnić czym jest kod, a czym biblioteka, której w nim używamy. Biblioteka jest również kodem, jednak napisanym w celu ułatwienia konkretnych czynności. Spróbujmy podać przykład wyświetlania danych na jakimkolwiek wyświetlaczu, może być to nawet proste LCD w wersji alfanumerycznej. Aby wyświetlić tu jakikolwiek piksel musimy znaleźć jego adres i sposób wywołania konkretnego stanu. Biblioteka robi to za nas, wystarczy, że w kodzie wywołamy jej funkcję i wpiszemy znaki alfanumeryczne, a biblioteka zajmie się transkrypcją tablicy znaków na bity wysyłane do wyświetlacza.
Zapomnieć średnika albo popełnić literówkę w nazwie zmiennej to jedno. Rozumiem, że z pełni zoptymalizowanego kodu tworzy się wówczas wypluwana lista debuggera. Wróćmy do tematu porządku w kodzie. Możesz podać jakiś przykład dobrej i złej praktyki w tym wypadku? Choćby na szczeblu podstawowym.
Pewnie. Najłatwiejszym sposobem na utrzymanie porządku w kodzie jest podział na sekcje. Oczywiście kod często możemy napisać w jednej linii, jednak wtedy szukanie jakiegokolwiek fragmentu zajmie nam lata. Lepiej dzielić wszystko na sekcje odpowiedzialne za dane funkcjonalności kodu, najłatwiej za pomocą tabulatorów i klawisza Enter.
Opiszesz największy horror programisty? Mile widziane Twoje własne doświadczenia.
Moim zdaniem największym problemem jest właśnie szukanie błędów w nieuporządkowanym kodzie, szczególnie gdy kod tworzony jest przez cały zespół. Często znalezienie jednego błędu sprawia, że musimy wertować i poprawiać inne fragmenty programu. Dlatego tak chętnie sugeruję dbanie o porządek i standaryzację wszystkiego co robimy. Kiedyś na pewno wróci to do nas z podwójną siłą - i praktyki dobre, i praktyki złe.
OK, Marcinie. Podsumujemy. Co zalecasz młodszym w programowaniu koleżankom i kolegom?
Pewnie. Pierwszą radą jest to, abyście nie bali się pytać. Nikt nie wie wszystkiego, a najgorsze, co może być, to siedzenie z rozłożonymi rękami. Oczywiście nie zachęcam tutaj do wyręczania się innymi, ale do wyczuwania takich momentów blokady. Kolejna rada dotyczy budowania założeń co do konkretnego projektu. Program to lista poleceń dla procesora i o tym musimy pamiętać. Warto przed napisaniem programu wziąć kartkę i długopis, albo odpalić notepada, i wypisać listę założeń dla danego programu. Łatwiej będzie rozpoznać, co będzie czynnikiem wywoławczym dla danej funkcji. Pamiętajmy również o dogłębnym testowaniu naszego softu tak, aby nawet w zupełnie innych warunkach program działał tak samo. Program ma działać wszędzie, nie tylko na komputerze, na którym jest pisany. Nie możemy bać się wyzwań, są one podstawą do naszego rozwoju i tego musimy się trzymać.
Niezależnie od poziomu zaawansowania i narzędzia życzymy Wam powodzenia w kodowaniu. Warto najpierw zjeść zęby na poprawkach, aby później umiejętnie zjadać niepotrzebne fragmenty poleceń. Nie ma kodu bez głodu!
Książki dla programistów
Jak oceniasz ten wpis blogowy?
Kliknij gwiazdkę, aby go ocenić!
Średnia ocena: 5 / 5. Liczba głosów: 2
Jak dotąd brak głosów! Bądź pierwszą osobą, która oceni ten wpis.
Jedna odpowiedź
C, embedded, C dla RTOS:
– brak komentarzy i dokumentacji kodu (!!!)
– nieczytelny kod, dziwne formatowanie kodu
– niewiedza w rozróżnianiu sterty od stosu
– brak wiedzy, gdzie lądują, w której pamięci zmienne
– błędy typu wielkie tablice w funkcjach, które zżerają stos (no bo na PC z dużą ilością RAM można wszystko)
– niewiedza jak działa malloc (no bo new w C++…..)
– niewiedza, że w RTOS alokacja pamięci powinna być tylko na starcie (po szkolnym kursie C++)
– niewiedza jak operować na stringach (po szkolnym kursie C++)
– brak synchronizacji dostępu do danych
– przeglądanie pamięci od tyłu zamiast do przodu (cache powinien przyśpieszać, a nie być wczytywany za każdym razem od zera)
– pisanie kodu w 1 pliku, nieumiejętność radzenia sobie w środowisku wieloplikowym
– zakładanie, że mój kod w C nigdy nie będzie kompilowany z kodem C++ (brak potencjalnych #ifdef __cplusplus extern “C” w plikach .h)
– brak myślenia o konieczności testów modułowych (bo po co?)
– funkcje zwracające nic (void), zamiast jakikolwiek status, który można wykorzystać w testach modułowych czy kontroli błędów.
– przy Misra C: w funkcji powinien być tylko 1 return (a nie 4), kod z zagłębieniem powyżej 4 powinien być rozbity na oddzielne funkcje, tak samo nie robić zagłębionego podwójnego switch/case w jednej funkcji
– fantazja przy nazywaniu typów zmiennych i nazw zmiennych
– na procesorach 32 i 64 bitowych uporczywe trzymanie się zmiennych uint8/uint8_t np. przy indeksowaniu tablicy. Na stosie zawsze jest kładziona zmienna 32/64 bitowa. Zostawmy uint8_t wewnątrz struktur czy buforów (tablica uint8_t) tylko.
– przy Misra C: nie przejdzie pakowanie kodu do define(), analiza statyczna kodu wywali możliwość potencjalnie niebezpiecznej podmiany zawartości define’a