Klasa / funkcja pomocnicza – Helper

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.
Autor wpisu

blog@orbisbit.com

Komentarze

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

Sprawdź również
  • CQRS – Command Query Responsibility Segregation

    Command Query Responsibility Segregation czyli CQRS. Jest to wzorzec projektowy, który rozdziela zadania odczytu i zapisu do osobnych modeli. Sprawdź ten wpis, aby dowiedzieć się kiedy i jak z niego skorzystać.

    Zobacz wpis

  • GRASP – kolejny zbiór zasad Clean Code do zapamiętania

    Pewnie większość z Was słyszała o zasadach SOLID. Są one bardzo rozpowszechnione i dosyć często stosowane, ale czy słyszeliście o GRASP? General Responsibility Assignment Software Patterns, to kolejna dawka zasad czystego kodu do zapamiętania.

    Zobacz wpis

  • Wzorzec strategia (strategy pattern)

    Jeżeli masz dość if-ologii w swoim kodzie, to konieczne sprawdź czym jest czynnościowy wzorzec projektowy strategia. Pozwala on mądrze obsługiwać różne scenariusze w procesie i jednocześnie być fancy pod względem zasad SOLID.

    Zobacz wpis