Kilka pomysłów na kod, który łatwiej zrozumieć

Ostatnio dość sporo siedziałem w starym, odziedziczonym kodzie – nie tylko cudzym, ale i swoim. Sporo czasu zeszło mi na próby zrozumienia co autor miał na myśli… Na szczęście mogłem sobie pozwolić na wykonanie odpowiedniej refaktoryzacji z marszu – ok, część tego czego się domyśliłem umieściłem tylko w komentarzach ale tam gdzie się dało usprawnić kod od ręki – tam to zrobiłem.

Przy tej okazji chciałbym się podzielić kilkoma koncepcjami: zarówno starymi i dobrze znanymi jak i kilkoma, na które wpadłem – niekoniecznie ostatnio – zastanawiając się jak można pewne rzeczy sformułować lepiej… Ogólny zamysł przyświecającym tym ideom jest jeden – łatwiej zrozumieć co się dzieje w kodzie, także przy ewentualnym braku wsparcia ze strony VS (np. podczas łączenia gałęzi w repozytorium kodu…) gdy kod jest samo-dokumentujący. Że banał? Jasne. Tym niemniej zapraszam do lektury.

Magiczne liczby

Wszyscy niby wiemy, że magiczne numerki są złe. Bardzo złe… Dość oczywiste przykłady:

string libName = columnData.Substring(20, 13);
Item itm = collection.GetElementAt(indexRequested - 1);
// ...

Takie rzeczy zwykliśmy załatwiać za pomocą stałych, odpowiednich komentarzy, obiektów z konfiguracją itp.

Ale wszystkie one kręcą się wokół jednej rzeczy – co oznacza dany argument – skąd jego wartość, co ona oznacza dla aplikacji. Czyli np. w drugim przykładzie “1” oznacza (zazwyczaj) “korektę między systemem numeracji kolekcji, z którego korzysta algorytm dostarczający wartość zmiennej “indexRequested” do systemu numeracji wykorzystywanego przez samą kolekcję “collection“. W pierwszym przykładzie mamy jednak już dwa problemy jednocześnie – nie tylko co oznaczają podane argumenty ale jaką rolę pełnią odpowiednie parametry w wywołanej funkcji? (Ok, Susbstring() jest trywialnym przykładem – wszyscy ją znamy, ale chodzi mi o zasadę :P).

Czasami rozwiązując pierwszy problem, możemy jednocześnie rozwiązać i drugi. Np. w ten sposób:

string libName = columnData.Substring(libColumnDefinition.StartIndex, libColumnDefinition.Width);

Jednocześnie pozbywamy się magicznych liczb i umieszczamy je w konfiguracji (nawet jeśli nadal jest ona zakodowana na sztywno, to będąc trzymaną w jednym miejscu niesie o wiele więcej spójnej informacji) ale jednocześnie wskazujemy na znaczenie poszczególnych wartości dla Funkcji Substring().

Są jednak przypadki, gdy usunięcie magicznej liczby nie jest za bardzo możliwe. Np.

Timespan serviceTimeout = configuration.GetServiceTimeout(this.ServiceName) ?? new Timespan(0, 10, 0);

Continue reading Kilka pomysłów na kod, który łatwiej zrozumieć