Anty-wzorce, których powinieneś unikać w swoim kodzie

Każdy programista chce pisać ustrukturyzowany, prosto zaplanowany i ładnie skomentowany kod. Istnieje nawet mnóstwo wzorców projektowych, które dają nam jasne zasady, których należy przestrzegać, i ramy, o których należy pamiętać.

Ale nadal możemy znaleźć anty-wzorce w oprogramowaniu, które zostało napisane jakiś czas temu lub zostało napisane zbyt szybko.

Nieszkodliwy podstawowy sposób na szybkie rozwiązanie problemu może stworzyć precedens w Twojej bazie kodu. Można go skopiować w wielu miejscach i zamienić w anty-wzorzec, którym należy się zająć.

Więc co to jest anty-wzór?

W oprogramowaniu anty-wzorzec to termin, który opisuje, jak NIE rozwiązywać powtarzających się problemów w kodzie. Anty-wzorce są uważane za zły projekt oprogramowania i zwykle są nieefektywnymi lub niejasnymi poprawkami.  

Zwykle dodają również „dług techniczny” - czyli kod, na który trzeba później wrócić i odpowiednio naprawić .

Sześć anty-wzorców, które omówię w tym artykule to Spaghetti Code , Golden Hammer , Boat Anchor , Dead Code , Proliferation of Code i God Object .

Kod Spaghetti

Kod spaghetti jest najbardziej znanym anty-wzorcem. Jest to kod o strukturze od małej do zera.

Nic nie jest zmodularyzowane. W losowych katalogach znajdują się losowe pliki. Cały strumień jest trudny do nadążenia i jest całkowicie splątany (jak spaghetti).

Zwykle jest to problem, w którym ktoś nie przemyślał wcześniej dokładnie przebiegu swojego programu i dopiero zaczął kodować.

Co to robi?! Nie mogę tego śledzić

image.png

To nie tylko koszmar konserwacji, ale prawie niemożliwe jest dodanie nowej funkcjonalności.

Będziesz nieustannie psuć rzeczy, nie rozumieć zakresu swoich zmian ani podawać dokładnych szacunków dotyczących swojej pracy, ponieważ nie można przewidzieć niezliczonych problemów, które pojawiają się podczas wykonywania takiej archeologii / domysłów.

Możesz przeczytać więcej o anty-wzorze Spaghetti Code .

Złoty młot

- Przypuszczam, że kuszące jest traktowanie wszystkiego tak, jakby to był gwóźdź, jeśli jedynym narzędziem, jakie masz, jest młotek. Abraham Maslow

Wyobraź sobie scenariusz ze mną: Twój zespół programistów jest bardzo, bardzo kompetentny w zupełnie nowej architekturze Hammer. To zadziałało fantastycznie w przypadku wszystkich poprzednich problemów. Jesteś wiodącym na świecie zespołem architektonicznym Hammera.

Ale teraz, jakoś, wszystko zawsze kończy się na tej architekturze. Śruba z łbem płaskim? Młotek. Śruba z łbem krzyżakowym? Młotek. Potrzebujesz klucza imbusowego? Nie, nie masz, młotkuj to.

Zaczynasz stosować podejście architektoniczne, które nie do końca pasuje do tego, czego potrzebujesz, ale wykonuje zadanie. Zbytnio polegasz na jednym schemacie i musisz nauczyć się najlepszego narzędzia do najlepszej pracy.

Cały Twój program może zakończyć się poważnym spadkiem wydajności, ponieważ próbujesz wbić kwadrat w kształt koła. Wiesz, że tworzenie kodu i wykonanie programu przy użyciu architektury młotkowej zajmuje dwa razy więcej czasu, ale jest to łatwiejsze i to jest to, z czym czujesz się komfortowo.

Nie jest też zbyt przewidywalne. Różne języki mają wspólne sposoby rozwiązywania problemów i własne standardy. Nie możesz bez żadnych problemów zastosować każdej reguły, która działała dobrze w jednym języku w drugim.

Nie zaniedbuj konsekwentnego uczenia się w swojej karierze. Wybierz odpowiedni język dla swojego problemu. Pomyśl o architekturze i wypchnij swoją strefę komfortu. Badaj i badaj nowe narzędzia i nowe sposoby rozwiązywania problemów, z którymi się borykasz.

Możesz przeczytać więcej o anty-wzorze Golden Hammer tutaj .

Kotwica do łodzi

Boat Anchor anty-wzorzec jest gdzie programiści zostawić kod w kodzie, ponieważ mogą go potrzebować później.

Zakodowali coś poza specyfikacją i nie jest to jeszcze potrzebne, ale są pewni, że w przyszłym miesiącu to zrobią. Więc nie chcą go usunąć. Wyślij go do produkcji, a później, gdy będzie potrzebny, szybko zacznie działać.

Ale to powoduje koszmary związane z konserwacją w bazie kodu, która zawiera cały ten przestarzały kod. Ogromnym problemem jest to, że ich koledzy będą mieli trudności z ustaleniem, który kod jest przestarzały i nie zmienia przepływu, w porównaniu z kodem, który to robi.

Wyobraź sobie, że masz problem i desperacko próbujesz dowiedzieć się, co jest odpowiedzialne za wysyłanie danych kart klientów do API w celu wypłaty środków z ich banku. Możesz tracić czas na czytanie i debugowanie przestarzałego kodu, nie zdając sobie sprawy, że nie jesteś nawet we właściwym miejscu w bazie kodu.

Ostatnim problemem jest to, że przestarzały kod wydłuża czas kompilacji i możesz pomylić działający i przestarzały kod. Możesz nawet nieumyślnie „włączyć to” w produkcji.

Teraz prawdopodobnie widzisz, dlaczego nazywa się to anty-wzorcem kotwicy łodzi - jest ciężki do przenoszenia (dodaje dług techniczny), ale nic nie robi (dosłownie, kod nie służy celowi, nie działa).

Możesz przeczytać więcej o anty-wzorze kotwicy łodzi .

Martwy kod

Czy kiedykolwiek musiałeś spojrzeć na kod napisany przez kogoś, kto już nie pracuje w Twojej firmie? Jest funkcja, która nie wygląda, jakby coś robiła. Ale dzwoni zewsząd! Pytasz i nikt inny nie jest całkiem pewien, co robi, ale wszyscy są zbyt zmartwieni, aby to usunąć.

Czasami możesz zobaczyć, co robi, ale brakuje kontekstu. Potrafisz czytać i rozumieć przepływ, ale dlaczego? Wygląda na to, że nie musimy już trafiać do tego punktu końcowego. Odpowiedź jest zawsze tą samą odpowiedzią dla każdego innego użytkownika.

Jest to powszechnie określane jako anty-wzorzec martwego kodu . Kiedy nie możesz zobaczyć, jaki jest „rzeczywisty” kod niezbędny do przepływu i pomyślnego wykonania programu, w porównaniu z tym, co było potrzebne zaledwie 3 lata temu, a nie teraz.

Ten konkretny anty-wzorzec jest bardziej powszechny w przypadku dowodu koncepcji lub kodu badawczego, który trafił do produkcji.

Pewnego razu na spotkaniu technicznym spotkałem faceta, który miał dokładnie ten problem. Miał mnóstwo martwego kodu, o którym wiedział, że jest martwy, i wiele, o których podejrzewał, że nie żyje. Ale nie mógł uzyskać zgody kierownictwa na usunięcie całego martwego kodu.

Odniósł się do swojego podejścia jako testowanie na małpach, gdzie zaczął komentować i wyłączać rzeczy, aby zobaczyć, co wybuchło w produkcji. Może trochę zbyt ryzykowne!

If you don't fancy Monkey testing your production app, try to frame technical debt to management as "technical risk" to better explain why you think it's so important to tidy up.

Or even write down everything your particular module/section does you want to re-write, and take an iterative approach to remove piece by piece the dead code. Checking every time you haven't broken anything.

You don't have to drop a huge rewrite with thousands of changes. But you will either understand why it's so crucial and document why it's needed, or delete the dead code as you desired.

You can read more here about the Dead code anti-pattern.

Proliferation of Code

Objects or modules regularly communicate with others. If you have a clean, modularised codebase you often will need to call into other separate modules and call new functions.

The Proliferation of Code anti-pattern is when you have objects in your codebase that only exist to invoke another more important object. Its purpose is only as a middleman.

This adds an unnecessary level of abstraction (adds something that you have to remember) and serves no purpose, other than to confuse people who need to understand the flow and execution of your codebase.

A simple fix here is to just remove it. Move the responsibility of invoking the object you really want to the calling object.

You can read more here about the Proliferation of Code anti-pattern.

God Object

If everywhere in your codebase needs access to one object, it might be a God object.

God objects do too much. They are responsible for the user id, the transaction id, the customer's first and last name, the total sum of the transaction, the item/s the user is purchasing...you get the picture.

It is sometimes called the Swiss Army Knife anti-pattern because you only really need it to cut some twine, but it also can be a nail file, saw, pair of tweezers, scissors, bottle opener and a cork screw too.

In this instance you need to separate out and modularise your code better.

Programmers often compare this problem to asking for a banana, but receiving a gorilla holding a banana. You got what you asked for, but more than what you need.

The SOLID principles explicitly discuss this in object orientated languages, to help us model our software better (if you don't know what the SOLID principles are, you can read this article).

The S in the acronym stands for Single Responsibility - every class/module/function should have responsibility over one part of the system, not multiple.

You can see this problem over and over again, how about the below interface?

interface Animal { numOfLegs: string; weight: number; engine: string; model: string; sound: string; claws: boolean; wingspan: string; customerId: string; } 

Can you see by even just briefly scanning this interface that the responsibility of this is far too broad, and needs refactoring? Whatever implements this has the potential to be a God object.

How about this?

 interface Animal { numOfLegs: string; weight: number; sound: string; claws: boolean; } interface Car { engine: string; model: string; } interface Bird { wingspan: string; } interface Transaction { customerId: string; } 

Interface segregation will keep your code clear about where the responsibilities lie, and stop forcing classes that only need wingspan to also implement the engine, customerId and model  and so on.

Możesz przeczytać więcej o anty-wzorcu obiektu Boga .

Wniosek

W każdej dużej bazie kodów istnieje stała równowaga między zarządzaniem długiem technicznym, rozpoczynaniem nowego rozwoju i zarządzaniem kolejką błędów w produkcie.

Mam nadzieję, że ten artykuł dał ci oko do zauważenia, kiedy możesz schodzić do króliczej nory anty-wzoru, i kilka narzędzi do rozwiązania tego problemu.

Udostępniam moje teksty na Twitterze, jeśli podobał Ci się ten artykuł i chcesz zobaczyć więcej.