Dzisiaj pół żartem, a pół serio. Jeśli widzisz w legacy code plik, który ma w nazwie helper, util, manager, to istnieje duże prawdopodobieństwo, że jeśli tam spojrzysz to zobaczysz masę anty wzorców. Sprawdź kiedy Twoja klasa nie jest helper-em.
Problem helperów
O helperach można napisać wielostronicową księgę, ale nie o tym, jak je implementować czy używać, ale o tym dlaczego powinno się je stosować z rozwagą lub też w ogóle ich nie stosować. Często widujemy sytuacje, gdzie wszystko, co nie pasuje jako: kontroler, serwis, model, czy cokolwiek innego, to staje się to helperem, managerem albo utilsem. Naprawdę, ciężko stwierdzić dlaczego tak się dzieje, ale cytując Pana Tadeusza Sznuka z 1 z 10: „Nie wiem, choć się domyślam”.
Jak to powinno wyglądać?
Funkcje bądź klasy pomocniczne, to w zamyśle małe fragmenty kodu wykorzystywane przez wiele modułów, w różnych miejscach. Nie powinny one nieść ze sobą żadnej wartości biznesowej, a być jedynie małym uzupełnieniem większej logiki. Uzupełnienie to powinno być tak małe i nie związane tematycznie z usługą, że nie nadaje się do wydzielenia osobnej metody w serwisie, a jest szerzej używane.
Widzimy tutaj prostą funkcję pomocniczą generującą pseudo losowe cyfry. Funkcja jest wykorzystywana np. przy generowaniu jednorazowych haseł dostępu. Wszyscy zgodzimy się chyba, że takie użycie w kontekście globalnym ma trochę sensu.
export const randomNumberGenerator = (digits: number): number =>
Math.floor(Math.random() * (9 * Math.pow(10, digits))) + Math.pow(10, digits);
Garść przykładów „anty”
Polećmy teraz z tzw. „grubej rury” i pokażmy sobie anty-przykłady. Bez opisu, ponieważ nie ma tutaj nawet czego opisywać.
To nie jest helper:
export class MailHelper {
async sendNewPassword(user: UserEntity, password: string): Promise<void> {
this.mailService.setApiKey(config.get('sendgrid').apiKey);
const message = {
to: user.email,
from: config.get('mail').from,
subject: 'New password',
text: `New password: ${password}`,
}
this.mailService.sendMultiple(message);
}
}
To nie jest manager:
export class UserManager {
private static readonly defaultPasswordLength = 8;
async generateNewPassword(user: UserEntity): Promise<UserEntity> {
const password =
Math.floor(Math.random() * (9 * Math.pow(10, UserManager.defaultPasswordLength))) +
Math.pow(10, UserManager.defaultPasswordLength);
user.password = password;
await user.save();
MailHelper.sendNewPassword(user, password);
return user;
}
}
Jeżeli chciałabyś, chciałbyś więcej takich przykładów, to gwarantuję Ci, że wystarczy przeszukać GitHuba – uwierz, że znajdziesz taki lub podobny kod bardzo szybko. Nie wiem czy jest coś więcej do powiedzenia na ten temat. Jeśli Twój kod jest podobny do anty-przykładów, które pokazałem, to proszę zastanów się nad swoim postępowaniem.
Podsumowując
- Funkcje / klasy pomocniczne nie powinny nieść za sobą żadnej wartości biznesowej.
- Ideą helperów jest dostarczanie nieskomplikowanej logiki, która wykorzystywana jest w szerszym zakresie.
- Przed dodaniem kodu, którego chcemy ochrzcić mianem manager, utils czy helper, powinniśmy się 3 razy zastanowić nad jego sensem.
Dodaj komentarz