Kochasz pisać kod? Ja tak, uwielbiam. Jest to pewny rodzaj sztuki. Sztuki komunikacji człowieka z komputerem. Sztuki czytelności naszej komunikacji. Sztuki przejrzystości. Sztuki architektury. Sztuki minimalizacji. Sztuki napisania/opowiedzenia wszystkiego w jak najkrótszej możliwej formie.

Osiągniecie większości efektów zajmuje czas – naszej praktyki, prób i błędów. Im więcej piszemy tym lepiej potrafimy pewne rzeczy opisać. Praktyka czyni z nas mistrzów – lokalnych, regionalnych, światowych. A im więcej czasu spędzamy z kodem, tym bardziej dążymy do minimalizmu – to przejrzystości, łatwości przyswajania i czystości kod.

Czasami jednak w dążeniu do perfekcji gubimy się. Tracimy horyzont. Zaczynamy inaczej postrzegać pewne hasła, wzorce, zalecenia. Jednym z takich zaleceń/wzorców jest Don’t Repeat Yourself (DRY). Bardzo często traktujemy to jako wyznacznik, czyli jak napiszemy raz pewny kod pobierający dane z bazy to możliwe, że to będziemy chcieli wykorzystać go w innym miejscu. Zaczynamy jak szaleni wyciągać wszystko przed nawias twierdząc, że tak trzeba, nie rozumiejąc co tak naprawdę siedzi pod powtarzalnością. Często patrzymy na nasz kod dostępu do danych, logiki w danym miejscu, logiki w kontrolerze itp. i wyciągamy to tak by “się kod nie powtarzał”.

Popełniamy wtedy błąd, wyciągamy coś co jest specyficzne dla danego kontrolera w danej chwili. Sądząc, że to się nie zmieni i że wszystkie kontrolery będą się tak samo zachowywać. Nic bardziej mylnego. W każdej chwili dany kontroler może będzie musiał zwracać inaczej dane? Wykonać inne zadanie? To się może zmienić. I ma prawo się zmienić. A skoro może i ma prawo, to się zmieni :)

Zaś to co jest w naszym kodzie powtarzalne, jest niezauważalne. Te fragmenty które najczęściej wykorzystujemy to są fragmenty porównywania pewnych wartości do siebie, formatowania, pobierania daty w formacie lokalnym, mnożenia, konwersji, ustawiania globalnych wartości itp. Wszystkie te fragmenty kodów istnieją wielokrotnie skopiowane, często prowadzące do kłopotów błędnego jednego zapisu (testy pomagają).

Dla przykładu:

if(x == TestEnum.Open|| x == TestEnum.InProgress) {}

// in every action
ViewBag.UserId = "test";

string.Format("{0}, {1}", v1, v2);

Większość tych rzeczy jesteśmy wstanie z refaktoryzować pod nasz projekt. Skoro wiemy, że dla każdej akcji ustawiamy ViewBag, to może warto to wrzucić globalnie – jako konwencja, nawet jak będzie widok który nie będzie potrzebował UserId to nic się nie stanie jak UserId zostanie ustawiony na Guid.Empty. Często porównujemy czy coś ma dwie konkretne wartości? To czemu nie napisać rozszerzenia załatwiającego tego za nas? Jeżeli cały czas wykonujemy ?: to może warto to zamienić na extension method ValueOrDefault() ?

Nie tylko nasz kod stanie się czytelniejszy, nabierze on zupełnie innego znaczenia, dla przykładu:

if(x == TestEnum.Open|| x == TestEnum.InProgress) {}
if(x.IsActive()) {}

string.Format("{0}, {1}", v1, v2);
"{0}, {1}.Format(v1, v2);

string.Format("{0} {1}", user.FirstName, user.LastName);
user.FullName()

Po tych zmianach zyskamy coś jeszcze, single point of failure dla każdego z przypadków. Jeżeli wiemy, że FullName jest źle formatowy, wiemy gdzie i jak mamy to zmodyfikować. Nie musimy szukać tysięcy miejsc w kodzie gdzie tak się dzieje. Dosłownie tak samo wiemy co znaczy IsActive.

Takie małe refaktoringi jesteśmy wstanie wprowadzać wszędzie. Daje to przejrzystość i czytelność jak i ułatwia zrozumienie kodu przez zastosowanie odpowiednich nazw funkcji. Nie wierzycie? Sprawdźcie u siebie w projekcie. Ile macie takich miejsc które w ten sposób można z optymalizować? Najlepsze jest to, że to jest tak naprawdę ten, powtarzalny kod, ten który możemy i powinniśmy się pozbyć.

Jak wam idzie stosowanie się do DRY, co robicie by nie było duplikacji i co uważacie za duplikacje?