Zasady, którymi kieruję się po 20 latach programowania
Programuję od 1999 roku, a w tym roku to moja oficjalna 20 rocznica pracy w programowaniu. Zaczynałem od Basic, ale szybko przeskoczyłem do Pascala i C, a następnie nauczyłem się programowania obiektowego (OOP) z Delphi i C++. W 2006 roku zacząłem pracować z Javą, a w 2011 z JavaScriptem. Pracowałem z wieloma firmami w zakresie robotyki, technologii finansowej, technologii medycznej, przez media po telekomunikację. Czasami zajmowałem się również innymi rzeczami. Byłem badaczem, CTO, TPM (technical product manager), nauczycielem, architektem systemu lub TL (technical leader), ale od zawsze zajmowałem się kodowaniem.
Pracowałem nad produktami, które służyły milionom ludzi, a także takimi, które zaliczyły upadek jeszcze przed wypuszczeniem na rynek. Pracowałem jako konsultant, a nawet miałem swój własny startup. Spędziłem mnóstwo czasu na projektach o kodzie zamkniętym i projektach typu open source (zastrzeżony kod, który jest rozwijany przez społeczność wewnątrz firmy). Pracowałem z maleńkimi mikrokontrolerami przez aplikacje mobilne i desktopowe aż po serwery w chmurze i ostatnio serverless.
Z okazji mojej 20 rocznicy programowania zdecydowałem się wymienić najważniejsze zasady, które nagromadziłem przez lata, jako przewodnie zasady w całej mojej karierze.
- Nie walcz z narzędziam i: bibliotekami, językiem, platformą itp. Używaj jak najwięcej natywnych konstruktów. Nie naginaj technologii, ale nie naginaj też problemu. Wybierz odpowiednie narzędzie do pracy lub będziesz musiał znaleźć odpowiednią pracę dla narzędzia, które wybrałeś.
- Nie piszesz kodu dla maszyn, piszesz go dla swoich kolegów i przyszłego siebie (chyba że jest to projekt do wyrzucenia lub piszesz assembly). Napisz to tak, jakbyś pisał dla juniorów.
- Każde znaczące i satysfakcjonujące oprogramowanie jest wynikiem pracy zespołowej. Komunikuj i otwarcie mów o różnych kwestiach. Zaufaj innym i zdobądź ich zaufanie. Szacunek do ludzi jest ważniejszy niż kod. Świeć przykładem. Niech Twoi zwolennicy zostaną również liderami.
- Dziel i rządź. Napisz wyodrębnione moduły z podziałem odpowiedzialności, które są luźno powiązane. Przetestuj każdą część osobno i razem. Zachowaj testy zbliżone do rzeczywistości, ale przetestuj również przypadki brzegowe.
- Bądź nazbyt skromny. Nie bądź całkowicie odpowiedzialny za kod. Zoptymalizuj go dla innych, aby mogli znaleźć swoją drogę, naprawiając błędy i dodając funkcje do kodu. Pozwól sobie przejść dalej do następnego projektu/firmy. Nie bądź właścicielem kodu, bo nigdy nie będziesz mógł rozwinąć się dalej.
- Bezpieczeństwo ma charakter warstwowy: każda warstwa musi być oceniana indywidualnie, ale także w odniesieniu do całości. Ryzyko jest decyzją biznesową i ma bezpośredni związek z podatnością i prawdopodobieństwem. Każdy produkt/organizacja ma inny apetyt na ryzyko (ryzyko, które są skłonni podjąć dla większej wygranej). Bardzo często te 3 obawy rywalizują ze sobą: UX, bezpieczeństwo, wydajność.
- Uświadom sobie, że każdy kod ma swój cykl życia i kiedyś umrze. Czasami umiera w zalążku, zanim ujrzy światło produkcji. Pozwól sobie na odpuszczanie. Powinieneś znać różnicę między 4 kategoriami funkcji i wiedzieć, gdzie poświęcić swój czas i energię:
Rdzeń: jak silnik w samochodzie. Bez niego produkt jest pozbawiony sensu. Niezbędne: jak koło zapasowe w samochodzie. Jest rzadko używane, ale kiedy jest potrzebne, jego funkcja decyduje o sukcesie systemu. Wartość dodana: jak uchwyt na kubek w samochodzie. Miło jest to mieć, ale produkt doskonale nadaje się do użytku bez niego. Unikatowa cecha produktu: główny powód, dla którego ludzie powinni kupić Twój produkt, a nie produkt konkurencji. Przykładowo, Twój samochód jest najlepszym pojazdem terenowym. - Nie wiąż swojej tożsamości z kodem. Nie wiąż tożsamości kogokolwiek z ich kodem. Bądź świadom faktu, że ludzie to nie artefakty, które sami tworzą. Nie bierz krytyki kodu osobiście, ale bądź bardzo ostrożny, kiedy krytykujesz kod innych osób.
- Dług technologiczny jest jak fast food. Sporadycznie jest to akceptowalne, ale jeśli się do tego przyzwyczaisz, zabije to produkt szybciej, niż myślisz (i będzie to bolesne doświadczenie).
- Podczas podejmowania decyzji dotyczących rozwiązania wszystkie elementy wydają się równe, wybierz taki wariant pierwszeństwa:
Bezpieczeństwo > Niezawodność > Użyteczność (dostępność i UX) > Łatwość utrzymania > Prostota (DX) > Zwięzłość (długość kodu) > Finanse > Wydajność. Ale nie idź z tym na oślep, ponieważ jest to zależne od charakteru produktu. Jak w każdej karierze, im więcej zdobywasz doświadczenia, tym bardziej jesteś w stanie znaleźć odpowiednią równowagę dla każdej sytuacji. Na przykład przy projektowaniu silnika gry wydajność ma najwyższy priorytet, ale przy tworzeniu aplikacji bankowej najważniejsze jest bezpieczeństwo. - Genitalia bugów to nic innego jak kopiuj-wklej. Tak się właśnie reprodukują. Zawsze czytaj to, co kopiujesz, zawsze sprawdzaj to, co importujesz. Bugi chronią się w złożoności. „Magia” jest w porządku w mojej zależności, ale nie w moim kodzie.
- Nie pisz kodu tylko dla szczęśliwego zakończenia. Pisz dobre błędy, które odpowiadają na pytanie, dlaczego to się stało, jak to zostało wykryte i co można zrobić, aby to rozwiązać. Sprawdzaj wszystkie dane wejściowe systemu (w tym dane wejściowe użytkownika): popełniaj błędy i jak najszybciej je naprawiaj. Zakładaj, że użytkownik przykłada ci spluwę do głowy: włóż wystarczająco dużo wysiłku w naprawianie błędów w kodzie, aby jednak przekonać ich do strzelania w coś innego niż twoja głowa!
- Nie używaj zależności, chyba że koszt importu, utrzymania, radzenia sobie z ich przypadkami brzegowymi/błędami i refaktoryzacji, gdy nie spełniają potrzeb, jest znacznie mniejszy niż kodu, który posiadasz.
- Trzymaj się z dala od rozwoju napędzanego przez hype. Ucz się jednak wszystkich możliwych rzeczy. Dobrze jest mieć swoje ulubione projekty.
- Wyjdź ze swojej strefy komfortu. Ucz się każdego dnia. Przekazuj zdobytą wiedzę. Jeśli już jesteś ekspertem, to już się nie uczysz. Wystawiaj się na inne języki, technologie, kulturę i bądź ciekawy świata.
- Dobry kod nie potrzebuje dokumentacji, świetny kod jest dobrze udokumentowany, aby każdy, kto nie był częścią tej ewolucji, procesu prób i błędów oraz wymagań, które doprowadziły do obecnego stanu, mógł być na bieżąco z całością. Nie udokumentowana funkcja to funkcja, która nie istnieje. Nieistniejąca funkcja nie powinna mieć kodu.
- Unikaj nadpisywania, dziedziczenia i nadmiernej mądrości, kiedy tylko to możliwe. Pisz czyste funkcje. Są one łatwiejsze do przetestowania i rozumowania. Każda funkcja, która nie jest czysta, powinna być klasą. Każdy konstrukt kodu, który ma inną funkcję, powinien mieć inną nazwę.
- Nigdy nie zaczynaj kodować (tworzyć rozwiązania), jeśli nie rozumiesz w pełni problemu. To bardzo normalne, że spędzamy więcej czasu na słuchaniu i czytaniu niż na wklepywaniu kodu. Musisz zrozumieć dziedzinę jeszcze przed rozpoczęciem kodowania. Problem jest jak labirynt. Powinieneś stopniowo przejść przez cykl koduj-testuj-ulepszaj i zbadać przestrzeń problemu, aż zrozumiesz wszystko do końca.
- Nie rozwiązuj problemu, który nie istnieje. Nie zajmuj się programowaniem spekulacyjnym. Spraw, by kod był rozszerzalny tylko wtedy, gdy istnieje szansa, że będzie potrzeba jego rozszerzenia. Istnieje prawdopodobieństwo, że gdy zostanie rozszerzony, definicja problemu będzie wyglądać całkowicie inaczej niż w momencie pisania kodu. Nie przesadzaj z inżynierią: skup się na rozwiązaniu problemu, który jest w zasięgu ręki i skutecznym rozwiązaniu zaimplementowanym w efektywny sposób.
- Przyjemniej tworzy się oprogramowanie wspólnie. Zbuduj trwałą społeczność. Słuchaj. Inspiruj. Edukuj się. Udostępnij dalej!
Nie twierdzę, że jestem autorytetem w dziedzinie rozwoju oprogramowania. Są to tylko moje mądrości, które zdobyłem w czasie mojej 20 letniej kariery. Jestem pewien, że po kolejnych 20 latach ta lista jeszcze bardziej dojrzeje.