Skip to content

Instantly share code, notes, and snippets.

@paneq
Last active December 15, 2015 01:09
Show Gist options
  • Save paneq/5178264 to your computer and use it in GitHub Desktop.
Save paneq/5178264 to your computer and use it in GitHub Desktop.
Wywód o walidacji

O walidacjach AR i ich problemach

Wstęp

Załóżmy, że mamy do zaimplementowania delegowanie jakiejś sprawy między dwoma współpracownikami. Reguła biznesowa jest taka, że użytkownicy muszą pełnić tą samą rolę by oddelegować do kogoś zadanie.

To jest nasz punkt wyjścia. Dyskusyjne rozwiązanie ale przyjmijmy, że działa.

class Delegation < ActiveRecord::Base
  belongs_to :problem
  belongs_to :new_user, class_name: :User
  belongs_to :old_user, class_name: :User

  validate :new_user_role_and_identity

  private

  def new_user_role_and_identity
    errors.add(:new_user, :invalid) unless possible_new_users.include?(new_user)
  end

  def possible_new_users
    User.with_role_of(old_user).where(
      User.arel_table[:id].not_eq(old_user.id)
    )
  rescue
    []
  end
end

Problem

Sytuacja wygląda teraz tak, że za każdym razem kiedy chce sobie w testach porobić coś z moim Delegation muszę użyć #create zamiast #build ponieważ moja walidacja korzysta z bazy danych. W ten sposób testy z czasem robią się wolne a my jako programiści jesteśmy mniej wydajni.

Pseudo-rozwiązanie

Mogę zestubować prywatną metodę new_user_role_and_identity albo possible_new_users. Bullshit! Nie powinno się stubować prywatnych metod. Mamy je w dupie. Dlaczego miałbym to robić ?

Ok, to zestubujmy wywołania metod na User. Jeszcze większy bullshit. Co jak się zmienią. Dlaczego każdy kto chce skorzystać z Delegation w testach miałby się tym przejmować i wiedzieć co ona pod spodem robi. Brzmi równie źle i głupio.

Walidatory jako zewnętrzne narzędzie względem walidowanego obiektu

Ok, więc myślę sobie, o tym co opowiadałem na DRUGu po wroc_love.rb i walidatory powinny być zewnętrzne względem obiektu. Jak w Aequitas.

Więc napiszmy sobie jakiś prosty pseudo-walidator.

class DelegationValidator
  def valid?(delegation)
    possible_new_users(delegation).include? delegation.new_user
  end

  private

  def possible_new_users(delegation)
    User.with_role_of(delegation.old_user).where(
      User.arel_table[:id].not_eq(delegation.old_user.id)
    )
  rescue
    []
  end
end

Co się zmieniło ? Aktualnie nic, problem dalej jest ten sam tylko przeniesiony gdzie indziej.

Zależność

Może sytuacja byłaby prostsza gdyby ten walidator dostawał te dane, które są potrzebne do sprawdzenia?

class DelegationValidator
  def initialize(possible_new_users)
    @possible_new_users = possible_new_users
  end
  def valid?(delegation)
    @possible_new_users.include? delegation.new_user
  end
end

Nie takie złe. Teraz mamy inny problem. Każde miejsce, które chciałoby sprawdzić obiekt Delegation musiałoby tworząc taki DelegationValidator podawać mu listę dobrych osób do oddelegowania zadania. Doh. Jeśli takie miejsce jest jedno to nie niekoniecznie problem (wciąż, czy to dobrze miejsce jedną warstwę wyżej np Controller by takie obliczenia przeprowadzać i dostarczać? Chyba niekoniecznie). Jeśli takich miejsc jest więcej to mielibyśmy powtórzoną logikę tego. Wciąż fail.

Inna zależność

Czyli może zatem DelegationValidator powinien zamiast korzystać z gotowego zestawu użytkowników, to kooperować z jakimś obiektem, który by mu tą wiedzę dostarczył w zależności od potrzeb ?

Boom:

class DelegationValidator
  attr_reader :delegation_users_provider
  delegate :possible_new_users_for, to: :delegation_users_provider

  def initialize(delegation_users_provider = DelegationAllowedUsers.new)
    @delegation_users_provider = delegation_users_provider
  end

  def valid?(delegation)
    possible_new_users_for(delegation).include? delegation.new_user
  end
end

class DelegationAllowedUsers
  def possible_new_users_for(delegation)
    User.with_role_of(delegation.old_user).where(
      User.arel_table[:id].not_eq(delegation.old_user.id)
    )
  rescue
    []
  end
end

Czyżbym odkrył i zlokalizował dependency w toku tych rozważań ? Wygląda i brzmi nieźle. DelegationAllowedUsers wydaje się spełniać SRP. DelegationValidator ma jasno zdeklarowaną zależność, którą mogę w testach podstawiać dowolnie i być może nie będę musiał dzięki temu dotykać bazy bo mogę podstawić jakiś stub/mock, który powie true/false albo przeprowadzi to samo obliczenie w pamięci.

Jeśli więc miałem na początku trzy testy dla Delegation. Jeden sprawdzający, że dostanę informację o błędzie w sytuacji X a drugi w sytuacji, gdy oddelegowano do użytkownika o tej odmiennej roli w systemie a trzeci o braku błędu gdy o takiej samej. To za każdym razem musiałem tykać bazy.

Teraz mogę w każdym z testów podstawić odpowiednią spreparowaną zależność do DelegationValidator. Natomiast sam DelegationAllowedUsers przetestować w sytuacji pozytywnej i negatywnej osobno w innych testach, które niech im tam będzie, używają bazy. Im więcej testów walidacji nie związanych z samym przypadkiem badania, czy osoby mają taką samą rolę czy nie, tym większy win wydajnościowy.

Podsumowanie ?

  • Czy naprawdę wygrałem ?
  • Czy to jest lepszy kod niż hakerskie rozwiązania zaproponowane na początku ?
    • Wg Ciebie ?
    • Wg Fowlera ?
    • Wg DHH ?

Czy walidacje zaimplementowane tak jak w AR mają jakikolwiek sens jeśli nie ma prostych sposobów na ekstrakcję takich dependency ? No chyba, że mówimy o:

class Delegation < ActiveRecord::Base
  attr_accessor :delegation_users_provider
  validate :new_user_role_and_identity

  def new_user_role_and_identity
    errors.add(:new_user, :invalid) unless possible_new_user?(new_user)
  end

  def possible_new_user?(new_user)
    delegation_users_provider.possible_new_users.include?(new_user)
  end
end

i ustawianiu tej wartości na obiekcie klasy Delegation samym w sobie: delegation.delegation_users_provider = DelegationAllowedUsers.new; delegation.valid?. Co śmierdzi mi na kilometr również ...

Co sądzicie ?

*

  • Wywód zakłada, że nie możemy sprawdzić new_user.role == old_user.role ;)
  • Czemu nie hackpad? Bo nie ma tam ładnego kodu.
@paneq
Copy link
Author

paneq commented Mar 16, 2013

22:45 < RobertPanko> | https://gist.github.com/paneq/5178264
22:45 < RobertPanko> | chetnie poslucham dyskusji
23:25 <      teamon> | brak kontekstu, eot ;]
23:27 < RobertPanko> | teamon: kontekst
23:27 < RobertPanko> | Delegetion.new(...).valid?.should == true/false gdy costam
23:28 < RobertPanko> | i chcesz jak najmniej dotykac bazy by testy byly szybkie
23:28 <      teamon> | chilwa, doczytam cale ;]
23:28 <      teamon> | imho to powinno byc na innym poziomie
23:28 <      teamon> | memory db
23:28 <      teamon> | czy cos
23:28 < RobertPanko> | teamon: to znaczy co ?
23:29 <      teamon> | to znaczy ze kod jest taki sam
23:29 <      teamon> | ale nie uzywa bazy
23:29 <      teamon> | tylko np hasha ;]
23:29 <      teamon> | ze jak robisz User.create
23:29 <      teamon> | to masz STORE == {:users => [user1] }
23:29 <      teamon> | bo do testow i tak musisz stowrzyc usera zeby bylo na czym operowac
23:29 < RobertPanko> | teamon: ale na jakim poziomie bys chcial to miec
23:29 < AndrzejKrzy> | https://gist.github.com/andrzejkrzywda/5178595
23:29 < AndrzejKrzy> | (to jest offtop od glownej dyskusji)
23:30 < RobertPanko> | teamon: czy jak uzyje sqlite in db to spelnia twoja zaleznosc ?
23:30 < AndrzejKrzy> | ale ja bym to tak w PORO zrobil, z grubsza
23:30 <      teamon> | tak
23:30 <      teamon> | btw, czemu "Wywód zakłada, że nie możemy sprawdzić new_user.role == old_user.role" ?
23:30 <      teamon> | (brb, ide do sklepu)
23:31 < RobertPanko> | teamon: bo inaczej nie bylo by dyskusji
23:31 < RobertPanko> | teamon: to wez duza klasyczna apke railsowa odpal jej testy na sqlite w db i zobaczysz ze nie beda wciaz szybkie
23:31 < AndrzejKrzy> | teamon: to samo pytanie mialem :) w mojej implementacji zrobilem company wyzej, zeby to mialo sens z rolami.
23:31 < RobertPanko> | teamon: jak uzywasz mysql/postgres to one maja w pamieci takie bufory ze to tez sie dzieje in-memory a jest wolne
23:32 < RobertPanko> | teamon: bo masz caly SQL-shit narzut
23:32 < RobertPanko> | teamon: wiec nie kupuje tego argumentu zupelnie
23:32 < RobertPanko> | AndrzejKrzywda: twoje rozwiazanie jest ladne ale jak rzeklem zupelnie obok tego co mamy teraz w Railsach
23:32 <      teamon> | inny level
23:32 <      teamon> | w sensie
23:32 <      teamon> | nie na poziomie sql
23:32 <      teamon> | tylko ciut wyzej
23:32 < RobertPanko> | teamon: imho to wciaz bedzie zle
23:32 <      teamon> | USer.create == HASH.insert(…)
23:32 <      teamon> | itp
23:33 <      teamon> | tylko tu jest bubel
23:33 <      teamon> | bo jak masz gdzies sqla/arela
23:33 <      teamon> | no to nie ma opcji ;]
23:33 < RobertPanko> | teamon: ok jak sie ma to do railsow
23:33 <      teamon> | to jest tak jak FakeFS
23:33 < RobertPanko> | teamon: no to mam Arela/SQL w moim rozwiazaniu ale jako dependency ktore moge zmieniac
23:34 < RobertPanko> | AndrzejKrzywda: czyli reasumujac biorac pod uwage twoje rozwiazanie zgadzasz sie ze to co daje nam AR jest złe ?
23:34 <      teamon> | possible_new_users ma depsa na model + baze
23:34 < RobertPanko> | teamon: nie rozumiem
23:34 <      teamon> | no jak zmienisz model/baze
23:34 <      teamon> | to musisz zmienic implementacje possible_new_users
23:34 < AndrzejKrzy> | AR jest dobre do manipulowania baza. jest slabe do robienia logiki
23:34 <      teamon> | (serio brb bo mi sklep zakmna ;])
23:35 < RobertPanko> | teamon: dalej cie troche nie rozumiem. co to za argument. jak cos zmienie to cos bede musial zmienic
23:35 < AndrzejKrzy> | przyklad jest swietny, jesli dodamy tam to company wyzej, zeby nie bylo tego dziwnego ograniczenia, ze rol nie mozna porownac.
23:35 < RobertPanko> | teamon: pokaz mi rozwiazanie czegokolwiek co jak zmienie to nic nie musze zmieniac
23:35 < AndrzejKrzy> | implementacja i pierwsze i ostatnia sa ... takie sobie, delikatnie mowiac
23:36 < AndrzejKrzy> | delegation_users_provider - so weird
23:37 < AndrzejKrzy> | ale to pewnie na poboczu dyskusji, bo apparently PORO sa trudne do zrozumienia i lepiej miec delegation_users_provider ;)
23:37 < RobertPanko> | AndrzejKrzywda: ty po prostu nie potrafisz sobie wyobrazic tego wszystkiego co jest nad tym
23:38 < RobertPanko> | nad tym sa klasyczne railsy
23:38 < RobertPanko> | Delegation.new(params[:delegation]).save
23:38 < RobertPanko> | i ja w takim kontekscie to wszystko opowiadam
23:39 < AndrzejKrzy> | nie wiem, dlaczego zakladasz, ze ja to robie poza railsami.
23:39 < RobertPanko> | nie chodzi o to ze to juz jest zrobione
23:39 < AndrzejKrzy> | krok przed jest zaladowanie tej czesci danych, ktora pozwoli mi zbudowac Company, Employee i ten stan potrzebny
23:39 < RobertPanko> | w railsach
23:39 < RobertPanko> | klasycznie
23:39 < RobertPanko> | nie masz zadnego PORO ani nic
23:39 < AndrzejKrzy> | krok po jest zapisanie do bazy, ze delegacja sie udala, za pomoca AR
23:39 < RobertPanko> | twoje PORO moge sprobowac w nowym projekcie
23:39 < RobertPanko> | a ja chce uciec z tego co mam step 1
23:40 < RobertPanko> | z kalsycznych railsow
23:40 < RobertPanko> | w strone rozwiazan ktore szybko / szybciej ? dadza testy ktore nie beda wolne
23:40 < RobertPanko> | AndrzejKrzywda: czy twoim zdaniem pojscie w PORO to dobra droga
23:40 < RobertPanko> | jakis totalny rewrite kilkuletnich apek ?
23:40 < RobertPanko> | AndrzejKrzywda: albo inaczej
23:41 < RobertPanko> | czy mozna PORO stopniowo do railsow wprowadzac
23:41 < RobertPanko> | masz dziesiat obiektow AR i myslisz
23:41 < RobertPanko> | bylem glupi
23:41 < RobertPanko> | chce byc madry
23:41 < RobertPanko> | PORO
23:41 < AndrzejKrzy> | ale ja tutaj nie pokazuje zadnych rewolucji
23:41 < RobertPanko> | AndrzejKrzywda-Way
23:41 <      teamon> | jestem
23:41 < AndrzejKrzy> | tak, to mozna stopniowo robic
23:41 < RobertPanko> | czy moge jakos latwo zaczac na poczatek
23:41 < AndrzejKrzy> | wlasnie pokazalem w moim giscie, jakbym zrobil delegations/create
23:42 < AndrzejKrzy> | tylko bez kroku ladowania danych i zapisywania
23:42 < AndrzejKrzy> | ale to trywialne sprawy
23:42 < RobertPanko> | no nie wiem :) ty bys zrobil ladowanie i zapisywanie aspektami
23:42 < AndrzejKrzy> | i to ze bym tak zrobil delegations/create nie oznacza, ze trzeba nagle przepisac cala appke
23:42 < RobertPanko> | to sa dla ciebie trywialne sprawy
23:42 < AndrzejKrzy> | nigdzie w tej dyskusji tak nie powiedzialem
23:43 <      teamon> | anyway wracajac do tematu - pytanie gdzie ma dziac sie logika
23:43 < RobertPanko> | AndrzejKrzywda: nie powiedziales, to byla moja hipoteza z ktora sie nie zgodziles :)
23:43 <      teamon> | czy w apce czy w bazie
23:43 <      teamon> | bo tu ewidentnie dzieje sie w bazie
23:43 < RobertPanko> | teamon: jak w bazie ? w bazie jest tu tylko query
23:43 < RobertPanko> | teamon: w bazie to by byla jakby constraint to ogarnial
23:44 <      teamon> | err dobra,
23:44 <      teamon> | zle spojzalem
23:44 <      teamon> | tu jest tylko po idku
23:44 <      teamon> | anyway
23:44 <      teamon> | jak masz ta nieszczesna metode possible_new_users
23:44 <      teamon> | to gdzie jej nie wyciagniesz
23:44 <      teamon> | to i tak bedzie problem
23:45 <      teamon> | co za roznica czy to jest jako public private czy jakis Provider
23:45 <      teamon> | jak dla mnie jeden ch*
23:45 < RobertPanko> | teamon: ale ja ci tam dokladnie opisalem jaka jest roznica i jaki jest win
23:45 < RobertPanko> | na poczatku jak mam 10 testow dla Delegation to kazdy tyka bazy
23:45 < RobertPanko> | na koncu 2 testy dla zaleznosci sprawdzaja, a 10 moich testow nie tyka bazy
23:46 < RobertPanko> | chcesz to zanegowac ?
23:46 < RobertPanko> | chcesz stwierdzic ze oddala mnie to od celu przyspieszenia testow ?
23:46 <      teamon> | przede wszystkim, to to jest pisanie kodu tylko pod testy
23:46 <      teamon> | co jest imho failem sporym z zalozenia
23:46 <      teamon> | ale rozumiem cel ;)
23:46 < AndrzejKrzy> | teamon: +1
23:46 <    DRUG-bot> | AndrzejKrzywda gave +1 for *teamon*
23:47 <      teamon> | bo to
23:47 <      teamon> |  def initialize(delegation_users_provider = DelegationAllowedUsers.new)
23:47 <      teamon> | to jest ewidentnie hack
23:47 <      teamon> | zeby w testach dalo sie podac cos innego
23:47 <      teamon> | bo normalnei w kodzie nigdy tego nie uzywasz
23:47 < RobertPanko> | dependency w konstruktorze to hak
23:47 < RobertPanko> | lol
23:47 <      teamon> | no w tym kontekscie tak
23:47 < RobertPanko> | napisalem default value by bylo latwiej zrozumiec
23:47 <      teamon> | bo gdybys nie mial testow to bys tego nie potrzebowal :)
23:48 < RobertPanko> | teamon: ale je mam
23:48 < RobertPanko> | i potrzebuje
23:48 < RobertPanko> | to zle ?
23:48 < RobertPanko> | kurcze ja chyba zle rzeczy czytalem
23:48 < RobertPanko> | :)
23:48 < RobertPanko> | czyz nie poto mamy dependencies by w zaleznosci od potrzeb podstawiac co potrzebne ?
23:48 <      teamon> | tego nie powiedzial em ;]
23:48 <      teamon> | tak
23:48 < RobertPanko> | czy testy to nie jedna z potrzeb ?
23:49 <      teamon> | tak mozna bardzo latwo utonac w zaleznosciach
23:49 <      teamon> | ale stuby sa jeszcze gorsze
23:49 < AndrzejKrzy> | RobertPankowecki: obejrzyj w wolnej chwili http://www.infoq.com/interviews/coplien-martin-tdd Coplien fajnie tam trolluje o tym ze testy sa niepotrzebne tak bardzo
23:49 < AndrzejKrzy> | #offtop
23:49 < RobertPanko> | teamon: powiedz mi wiecej o tonieciu w zaleznosciach
23:49 <      teamon> | AndrzejKrzywda: zwiekszaja koszt i tylko sie wkurwiasz? ;]
23:50 < AndrzejKrzy> | mniej wiecej
23:50 <      teamon> | RobertPankowecki: ja sie zastanawiam tylko
23:50 <      teamon> | czemu pociales ta logike
23:50 < AndrzejKrzy> | testy nie sa celem
23:50 <      teamon> | bo jak dla mnie
23:50 <      teamon> | to tupowinno byc delegation_valid_for(user1, user2)
23:50 <      teamon> | jako niepodzielne
23:51 < RobertPanko> | teamon: validator opisuje blad, sprawdza czy wystapil
23:51 < RobertPanko> | teamon: ten drugi obiekt mowi czy te obiekty sa ok dla tej delegacji czy nie
23:51 < RobertPanko> | pierwszy potrzebuje ten drugi albo sam to robi
23:52 <      teamon> | generalnie to co potrzebujesz to
23:52 < RobertPanko> | czuje sie bardzo niekomfortowo prowadzac ta dyskusje bo imho to rozwiazanie zmierza w dobrym kierunku, jest pomocne
23:52 < RobertPanko> | a wy mi mowicie: wszystko zle idz do domu :)
23:52 <      teamon> | User => List[User] => User => Boolean
23:52 <      teamon> | to nie tak ;]
23:53 <      teamon> | er
23:53 <      teamon> | chwila
23:53 <      teamon> | czy interesuje cie ta lista userow?
23:53 <      teamon> | bo pytanie co tak naprawde chcesz przetestowac i na ktorym poziomie
23:54 <      teamon> | albo lepiej powiedz jaki jest real case bo ciezko mi tu troche rozkminiac majac w glowie new_user.role == old_user.role ;)
23:54 < RobertPanko> | chce przetestowac ze jak delegation stworze z userami ktorzy nie maja tej samej roli to bedzei invalid
23:54 < RobertPanko> | teamon: wyobraz sobie ze role dostaje z api
23:54 < RobertPanko> | baza danych to tez api
23:55 < RobertPanko> | no musisz wyjsc z tej banki delegation i 2 userow ktorych ona posiada by stwierdzic czy jest valid czy nie
23:55 < AndrzejKrzy> | RobertPankowecki: zbudowales dziwny swiat, gdzie nie mozna latwo sprawdzic jaka role ma user. ja to hejtuje glownie :) cala reszta to takie krecenie w kolko. pociales kod na mniejsze kawalki. testy przyspieszysz, wiec twoj cel osiagniety. ale dla mnie ostateczny wynik jest trudny do zrozumienia.
23:55 < RobertPanko> | AndrzejKrzywda: dla mnie jest mega latwy do zrozumienia
23:56 < AndrzejKrzy> | pierwotny przyklad byl latwiejszy w czytaniu i zrozumieniu, dla mnie
23:56 < RobertPanko> | stwierdzilem ze sprawdzenie czy Delegation jest poprawne wymaga kontaktu z jeszcze jednym 4tym obiektem
23:56 <      teamon> | ale dla kogos kto mialby to czytac to ani troche
23:56 < RobertPanko> | wyciagnalem go jako zaleznosc
23:56 < RobertPanko> | pierwotna wersja ukrywala ten fakt wewnatrz Delegation
23:57 < RobertPanko> | wiem wiecej o swojej domenie, jeste delegation, new user, old user i ktos jeszcze
23:57 < RobertPanko> | ten ktos powie mi cos o tych uzytkownikach
23:57 < RobertPanko> | i ja uzyje tej wiedzy by stwierdzic czy delegation moze powstac
23:57 <      teamon> | no czyli masz
23:58 <      teamon> | def valid = check(blackbox.info, user1, user2)
23:58 < RobertPanko> | AndrzejKrzywda: ty mowisz ze to cos wie Company
23:58 < RobertPanko> | teamon: nazwal to blackboxem
23:58 < AndrzejKrzy> | ok, to ten 4 obiekt ma ci dostarczyc liste userow czy moze po prostu odpowiedziec na pytanie czy user ma role? czy wg ciebie to nie ma znaczenia?
23:58 < RobertPanko> | bardzo fajna nazwa
23:59 <      teamon> | <troll>jak sie usunie z rownania obiekt i zostawi same funkcje/dane to jest meeega prosto wyciagac zaleznosci</troll>
23:59 < RobertPanko> | AndrzejKrzywda: to juz zalezy od przykladu. ja ma taki ze on umie odpowiadac o userow o danej roli
23:59 < RobertPanko> | moze jakby umial odpowiadac czy user ma ta role
23:59 < RobertPanko> | jako API, jako Company, whatever
--- Day changed Sun Mar 17 2013
00:00 < RobertPanko> | to faktycznie przyklad bylby lepszy
00:00 < RobertPanko> | pewnie tak )
00:00 < RobertPanko> | tak :)
00:00 <      teamon> | railsy: erros.add(..) if Validator(blackbox, user1, user2)
00:00 < RobertPanko> | teamon: ale gdzie ? wewnatrz Delegation, w kontrolerze
00:00 <      teamon> | w Delegation na razie
00:01 < RobertPanko> | w jakims serwisie, gdzie ?
00:01 < RobertPanko> | teamon: wtedy testy wciaz wolne :(
00:01 <      teamon> | sec
00:01 < RobertPanko> | teamon: wiec na poczatek w delegation, a co dalej
00:02 < AndrzejKrzy> | RobertPankowecki: dla mnie tl;dr twojego rozwiazania jest taki, ze poswiecasz czytelnosc na rzecz szybszych testow. pewnie sa sytuacje, gdzie to ma sens, ale bylbym ostrozny. oczywiscie "czytelnosc" to miara subiektywna i to moze jest gorsze tylko w mojej bance.
00:03 < RobertPanko> | AndrzejKrzywda: to jest ciekawa konkluzja ze odkryc ze by zadecydowac o tej sprawie potrzebuje 4 obiekty a nie 3 prowadzi twoim zdaniem do mniejszej czytelnosci
00:03 <      teamon> | poor man stub - http://dl.dropbox.com/u/70986/Screenshots/j.png
00:04 < AndrzejKrzy> | RobertPankowecki: ta moja wypowiedz to tylko na bazie gista.
00:04 <      teamon> | ale to na jedno wychodzi tak czy tak
00:04 < AndrzejKrzy> | validator...
00:04 < AndrzejKrzy> | czy myslicie ze w tych dziedzinach takie pojecie funkcjonuje?
00:05 <      teamon> | tzn?
00:05 <      teamon> | A => Boolean
00:05 < RobertPanko> | teamon: super, przetestowales nie ten validator
00:05 < AndrzejKrzy> | ja watpie, zeby siedzialo dwoch ludzi gdzie istnieje problem delegacji i sobie mowia "ty, stary, nie mozesz mi tego delegowac bo validator nie przepuszcza"
00:05 <      teamon> | RobertPankowecki: i tak i nie
00:05 < AndrzejKrzy> | ddd
00:05 < RobertPanko> | AndrzejKrzywda: Validator =~ Policy ?
00:05 <      teamon> | eerr
00:05 <      teamon> | sory
00:05 <      teamon> | zabraklo jednego
00:05 <      teamon> | class TestDValidator < DValidator
00:05 <      teamon> | tego
00:05 < RobertPanko> | heh :)
00:06 <      teamon> | ale to tak czy tak jest inny zapis tego samego
00:06 < RobertPanko> | teamon: ok czyli wolisz dziedziczenie od delegacji. to juz ustalilismy :)
00:06 < AndrzejKrzy> | przyjmujac dane z mojego gista, bardziej sobie wyobrazam, ze wpada szef i mowi "co wy kurwa z tym delegaowaniem zadania, przeciez robert nie kuma devopowania i nie moze robic infra checklisty"
00:06 < AndrzejKrzy> | no offence, RobertPankowecki ;)
00:07 < RobertPanko> | AndrzejKrzywda: no spoko, ale jesli biznesowych regul jest kilka
00:07 < RobertPanko> | tak ze w koncu warto moze je ubrac w obiekt ktory je sprawdzi
00:07 < RobertPanko> | to nie skonczymy tam gdzie moj przyklad
00:07 < RobertPanko> | moj przyklad sprawdza jedna walidacje
00:07 < RobertPanko> | ale ich dajmy to 10
00:07 <      teamon> | sounds like 6. Extract Policy Objects http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
00:07 < RobertPanko> | wiec ma sens ze jest 1 obiekt odpowiedzialny za sprawdzenie tych regul
00:07 < AndrzejKrzy> | to nadal nie nazwa tego validatorem
00:07 < RobertPanko> | czy nie ?
00:08 < AndrzejKrzy> | to juz policy predzej, faktycznie
00:08 < RobertPanko> | AndrzejKrzywda: no dobra, to hejtujesz moj przyklad bo mam terminologie rails ? :)
00:08 <      teamon> | najlepsze jest to ze kazdy z tych przykladow z codeclimate to sa po prostu funkcje
00:08 <      teamon> | tylko ze podzielone (bezsensu) na dwa etapy new + cos
00:09 < RobertPanko> | ah, fp vs oop
00:09 < RobertPanko> | teraz jedziemy
00:09 < RobertPanko> | spoko :)
00:09 < AndrzejKrzy> | RobertPankowecki: wiem, ze to jest nielatwa decyzja, zeby zmieniac terminologie, ale bralbym ja pod uwage
00:09 < RobertPanko> | cieszy mnie ze drug na ircu zyje
00:09  * teamon nie mogl sie powstrzymac
00:09 <      teamon> | anyway
00:09 <      teamon> | paradoksalnie
00:09 < RobertPanko> | AndrzejKrzywda: akurat to najprostsze w tym wszystkim
00:10 <      teamon> | jak sie wykmini jak to zrobic pure fp
00:10 <      teamon> | to latwo potem z tego porobic sobie ladne obiekty
00:10 < RobertPanko> | teamon: mysle w FP, koduje w obiektach ? :)
00:10 <      teamon> | nom
00:10 < AndrzejKrzy> | RobertPankowecki: ja sobie prowadze dyskusje na boku o innym problemie niz twoj. twoj problem szybkich testow rozwiazales. wg mnie kosztem czytelnosci. wiec przy tych zalozeniach jest spoko
00:11 < RobertPanko> | AndrzejKrzywda: nie moge sie zgodzic ze wyekstrachowanie dependency zmniejsza czytelnosc
00:11 < AndrzejKrzy> | problem wymysliles swietny, praktyczny i nietrywialny (zakladajac, ze jest company :P )
00:12 < RobertPanko> | AndrzejKrzywda: teamon: jak sie zgodzicie to zrobilbym przeklejke z loga z tej dyskusji tam
00:12 <      teamon> | sure
00:12 < AndrzejKrzy> | spoko
00:12 < RobertPanko> | i udostepnil na forum. jeszcze ich bym posluchal
00:12 <      teamon> | :D
00:12 < RobertPanko> | AndrzejKrzywda: abstrachujac od wszystkie chyba skumalem moj najwiekszy problem i co chcialem pokazac, dowiedziec sie sam
00:13 <      teamon> | ja bym to raczej zrobil
00:13 < AndrzejKrzy> | RobertPankowecki: i co to bylo?
00:13 < RobertPanko> | problemem validatorow railsowych jest wlasnie to ze nie moge im nic injectnac i to sie konczy pisaniem z dupy rzeczy wewnatrz klasy ktora chce zwalidowac
00:13 <      teamon> | Policy.new(delegation, possible_user_provider)
00:13 < RobertPanko> | bo tylko w niej to moge napisac
00:13 <      teamon> | gdzie possible_user_provider to User => List[User]
00:13 < RobertPanko> | AndrzejKrzywda: bo jedyne co moge zroic w rails to to co napisalem na samym koncuuu ze mi smierdzi na kilometr
00:14 <      teamon> | object.errors.add(…) ?:)
00:14 <      teamon> | no bo to jest z dupy ze errory sa jako dane obiektu
00:14 < RobertPanko> | teamon: tak tak, to juz na blogu pisalem :)
00:14 < RobertPanko> | teamon: i mowilem o tym tez na ostatnim drugu
00:14 < RobertPanko> | totalnie sie tutaj zgadzamy
00:14 <      teamon> | obiekt ma to w dupie, albo masz Success(delegation) albo Failure(errors)
00:15 < RobertPanko> | teamon: to juz norbert mowil za to :)
00:15 <      teamon> | no to jest Validation :)
00:15 < AndrzejKrzy> | wiec zamienilismy norberta na tymona i mamy ta sama debate co na drugu
00:15 < RobertPanko> | ok, dzieki za dyskusje panowie
00:15 < AndrzejKrzy> | gdzie ja sie dorzucilem z exceptionem, tak jak w moim kodzie :)
00:16 < AndrzejKrzy> | love exceptions
00:16 < RobertPanko> | AndrzejKrzywda: no to jak teamon nadgonil to na drugu mozna kontynowac w kilka osob od tego samego miejsca
00:16 < RobertPanko> | :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment