window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster już istnieje') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() Zastosowanie wzorca przypadków użycia w Railsach - The Codest
The Codest
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Branże
    • Fintech i bankowość
    • E-commerce
    • Adtech
    • Healthtech
    • Produkcja
    • Logistyka
    • Motoryzacja
    • IOT
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
  • O nas
  • Nasze Usługi
    • Software Development
      • Frontend Development
      • Backend Development
    • Zespoły IT
      • Programiści frontendowi
      • Backend Dev
      • Inżynierowie danych
      • Inżynierowie rozwiązań chmurowych
      • Inżynierowie QA
      • Inne
    • Konsultacje IT
      • Audyt i doradztwo
  • Wartość dla
    • CEO
    • CTO
    • Delivery Managera
  • Nasz zespół
  • Case Studies
  • Nasze Know How
    • Blog
    • Meetups
    • Webinary
    • Raporty
Kariera Skontaktuj się z nami
Strzałka w tył WSTECZ
2022-04-05
Software Development

Stosowanie wzorca przypadków użycia w Railsach

Nicolas Nisoria

Częstym problemem podczas pracy z Railsami jest decyzja, gdzie umieścić logikę naszych funkcji.

Logika jest często umieszczana w kontrolerach, modelach lub, jeśli mamy szczęście, w obiektach usług. Jeśli więc mamy obiekty usługowe, to po co nam Use Cases?

Śledź mnie w tym artykule, aby odkryć zalety tego wzoru.

Przypadek użycia

Definicja

Przypadek użycia to lista działań lub kroków zdarzeń zazwyczaj definiujących interakcje między rolą a systemem w celu osiągnięcia celu.

Warto wspomnieć, że wzór ten jest stosowany na wiele różnych sposobów i ma alternatywne nazwy. Możemy go znaleźć jako Interaktorzy, Operatorzy lub Poleceniaale w Ruby społeczność, której się trzymamy Przypadek użycia. Każda implementacja jest inna, ale ma ten sam cel: służyć przypadkowi użycia systemu przez użytkownika.

Nawet jeśli w naszym projekt nie definiujemy wymagań przy użyciu Przypadek użyciai UML ten wzorzec jest nadal przydatny do strukturyzowania logiki biznesowej w praktyczny sposób.

Zasady

Nasz Przypadki użycia musi być:

  • Framework agnostic
  • Niezależność od bazy danych
  • Odpowiedzialny tylko za jedną rzecz (zdefiniowanie kroków do osiągnięcia celu użytkownika)

Korzyści

  • Czytelność: Łatwy do przeczytania i zrozumienia, ponieważ kroki są jasno określone.
  • Oddzielenie: Przeniesienie logiki z kontrolerów i modeli i stworzenie nowego poziomu abstrakcji.
  • Widoczność: Baza kodu ujawnia funkcje dostępne w systemie.

W praktyce

Weźmy przykład użytkownika, który chce coś kupić w naszym systemie.

moduł UseCases
  moduł Kupujący
    klasa Zakup
      def initialize(buyer:, cart:)
        @buyer = buyer
        @cart = cart
      end
      def call
        return unless check_stock
        return unless create_purchase
notify end
private
      attr_reader :buyer, :cart
      def check_stock
        Services::CheckStock.call(cart: cart)
end
      def create_purchase
        Services::CreatePurchase.call(buyer: buyer, cart: cart).call
      end
      def notify

         Services::NotifyBuyer.call(buyer: buyer)
       end
     end
   end
 end

Jak można zobaczyć w tym kod przykład, utworzyliśmy nowy Przypadek użycia o nazwie Purchase. Zdefiniowaliśmy tylko jedną publiczną metodę połączenie. Wewnątrz metody wywołania znajdujemy dość podstawowe kroki, aby dokonać zakupu, a wszystkie kroki są zdefiniowane jako metody prywatne. Każdy krok wywołuje obiekt usługi, w ten sposób nasz Przypadek użycia definiuje tylko kroki do dokonania zakupu, a nie samą logikę. Daje nam to jasny obraz tego, co można zrobić w naszym systemie (dokonać zakupu) i kroków, aby to osiągnąć.

Teraz jesteśmy gotowi do wywołania naszego pierwszego Przypadek użycia z kontrolera.

klasa Kontroler
  def purchase
    UseCases::Buyer::Purchase.new(
      buyer: purchase_params[:buyer],
      cart: purchase_params[:cart]
    ).call

    ...
  end

  ...
koniec

Z tej perspektywy Przypadek użycia wygląda podobnie do obiektu usługi, ale jego przeznaczenie jest inne. Obiekt usługi wykonuje zadanie niskiego poziomu i wchodzi w interakcje z różnymi częściami systemu, takimi jak baza danych, podczas gdy obiekt usługi Przypadek użycia tworzy nową abstrakcję wysokiego poziomu i definiuje kroki logiczne.

Ulepszenia

Nasz pierwszy Przypadek użycia działa, ale mogłoby być lepiej. Jak moglibyśmy to poprawić? Skorzystajmy z suchy klejnoty. W tym przypadku będziemy używać sucha transakcja.

Najpierw zdefiniujmy naszą klasę bazową.

class UseCase
  include Dry::Transaction

  class << self
    def call(**args)
      new.call(**args)
    end
  end
end

Pomoże nam to przekazać atrybuty do transakcji UseCase i wykorzystać je. Następnie jesteśmy gotowi do ponownego zdefiniowania naszego Purchase Use Case.

moduł UseCases
  moduł Kupujący
    klasa Purchase
      def initialize(buyer:, cart:)
        @buyer = buyer
        @cart = cart
      end

      def call
        return unless check_stock
        return unless create_purchase
        notify
      end

      private

      attr_reader :buyer, :cart

      def check_stock
        Services::CheckStock.call(cart: cart)
      end

      def create_purchase
        Services::CreatePurchase.call(buyer: buyer, cart: cart).call
      end

      def notify
        Services::NotifyBuyer.call(buyer: buyer)
      end
    end
   end
 end

Dzięki nowym zmianom możemy w przejrzysty sposób zobaczyć, jak zdefiniowane są nasze kroki i możemy zarządzać wynikiem każdego kroku za pomocą funkcji Success() i Failure().

Jesteśmy gotowi do wywołania naszego nowego przypadku użycia w kontrolerze i przygotowania odpowiedzi w zależności od wyniku końcowego.

klasa Kontroler
  def purchase
    UseCases::Buyer::Purchase.new.call(
      buyer: purchase_params[:buyer],
      cart: purchase_params[:cart]
    ) do |result|
      result.success do
        ...
      end
      result.failure do
        ...
      end
    end

    ...
  end

  ...
koniec

Ten przykład można jeszcze bardziej ulepszyć za pomocą walidacji, ale to wystarczy, aby pokazać moc tego wzorca.

Wnioski

Bądźmy szczerzy. Wzorzec przypadku użycia jest dość prosty i wygląda podobnie do obiektu usługi, ale ten poziom abstrakcji może spowodować duże zmiany w aplikacji.

Wyobraźmy sobie, że nowy programista dołącza do projektu i otwiera folder use_cases, a na pierwszy rzut oka będzie miał listę wszystkich funkcji dostępnych w systemie, a po otwarciu jednego przypadku użycia zobaczy wszystkie niezbędne kroki dla tej funkcji bez zagłębiania się w logikę. To poczucie porządku i kontroli jest główną zaletą tego wzorca.

Zabierz to do swojej skrzynki z narzędziami, a być może w przyszłości zrobisz z tego dobry użytek.

Powiązane artykuły

Software Development

Modularyzacja Ruby on Rails za pomocą Packwerk Episode I

Ludziom trudno jest zobaczyć szerszy obraz problemu bez poświęcania dużej ilości czasu i wysiłku. Dzieje się tak zwłaszcza podczas pracy z dużymi i złożonymi aplikacjami....

Nicolas Nisoria
Software Development

Modularyzacja Ruby on Rails za pomocą Packwerk Episode II

W drugim odcinku naszej modularyzacji Ruby on Rails z Packwerk przyjrzymy się bliżej koncepcji aplikacji jako pakietu.

Nicolas Nisoria
Software Development

Szyny i inne środki transportu

Rails to framework kompatybilny z Rack, skupiający się na szybkim tworzeniu aplikacji. Niestety, podejście "wszystko po wyjęciu z pudełka" i ślepe zachowanie Rails-way często powodują, że kod aplikacji traci na jakości,...

The Codest
Krzysztof Buszewicz Senior Software Engineer

Subskrybuj naszą bazę wiedzy i bądź na bieżąco!

    O nas

    The Codest - Międzynarodowa firma programistyczna z centrami technologicznymi w Polsce.

    Wielka Brytania - siedziba główna

    • Office 303B, 182-184 High Street North E6 2JA
      Londyn, Anglia

    Polska - lokalne centra technologiczne

    • Fabryczna Office Park, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Warszawa, Polska

      The Codest

    • Strona główna
    • O nas
    • Nasze Usługi
    • Case Studies
    • Nasze Know How
    • Kariera
    • Słownik

      Nasze Usługi

    • Konsultacje IT
    • Software Development
    • Backend Development
    • Frontend Development
    • Zespoły IT
    • Backend Dev
    • Inżynierowie rozwiązań chmurowych
    • Inżynierowie danych
    • Inne
    • Inżynierowie QA

      Raporty

    • Fakty i mity na temat współpracy z zewnętrznym partnerem programistycznym
    • Z USA do Europy: Dlaczego amerykańskie startupy decydują się na relokację do Europy?
    • Porównanie centrów rozwoju Tech Offshore: Tech Offshore Europa (Polska), ASEAN (Filipiny), Eurazja (Turcja)
    • Jakie są największe wyzwania CTO i CIO?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Warunki korzystania z witryny

    Copyright © 2025 by The Codest. Wszelkie prawa zastrzeżone.

    pl_PLPolish
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench arArabic it_ITItalian jaJapanese ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek pl_PLPolish