Rails frontend

69 views
Skip to first unread message

elVanja

unread,
May 24, 2012, 4:12:49 PM5/24/12
to rub...@googlegroups.com
Bok!
Imam jedan problem koji me muci opako u zadnje vrijeme, pa ako netko ima volje pomoć, bilježim se sa štovanjem :-)

Enivej, u zadnje vrijeme istrazujem opciju u kojoj bi railsi bili samo frontend / delivery mehanizam, dok bi se sve vezano za poslovna pravila i samu perzistenciju odvijalo "negdje drugdje".
Ustvari, inspirirano je http://confreaks.com/videos/759-rubymidwest2011-keynote-architecture-the-lost-years govorom od Uncle Boba i cijelom pričom proizašlom iz iste.
Super mi je kako se kroz neki gem lako gradi poslovna logika koja je neopterećena web frameworkom pa čak ni perzistencijom.
Tu sam si našao nekako put koji bi bio OK i ugodan za rad.

Ono što me muči je uglavljivanje te priče u delivery mehanizam odnosno railse.
Htio bi doći do neke priče u kojoj se ti PORO objekti mogu lako ugraditi u iste, a da mogu iskoristiti rails điđe transparentno, kao da je riječ o AR modelima.
Tu nekako nailazim na dvije verzije priče:
* zaljepiti AR ponašanje na te objekte
* koristiti REST backend za sve

Prva verzija radi, uz malo problema da se napraviti da bazične CRUD operacije šljakaju.
Međutim, čini mi se malo bez veze imati direktni pristup u business layer, pogotovo jer imam potrebu imati i neki API koji bi trebao biti svjestan CRUD izmjena nastalih kroz rails dio priče.
Pa stoga ideja da se sve napravi kroz sam REST API, ali vidim da tu priča nije baš tako jednostavna, odnosno postoje neki mehanizmi ali nisu baš nešto dobro opisani.
Active Resource bi mogao biti rješenje ali je malo limitiran, a sa drugima (npr Roar iz gornjeg primjera) nemam iskustva.

Pa eto, ako netko ima koju smjernicu / preporuku, zahvaljujem unaprijed!
Vanja

elVanja

unread,
May 24, 2012, 4:18:17 PM5/24/12
to rub...@googlegroups.com
P.S. REST pristup se čini super, ali recimo i autor knjige "Service oriented design with ruby" kaže da možda uzaludno baš sve CRUD operacije raditi kroz servise

Goran Peretin

unread,
May 24, 2012, 5:01:07 PM5/24/12
to rub...@googlegroups.com
Bok Vanja,
kod mene na poslu se vec duze vrijeme bavimo takvim razvojem pa evo moja iskustva.
Btw, mi radimo u Pythonu, ali stvar je poprilicno slicna.

Prvo rijec-dvije o tehnologijama, mi koristimo Flask za web framework (to je recimo kao Sinatra iz Ruby svijeta) i SQLAlchemy kao ORM (to je recimo datamapper iz Ruby svijeta). Koristili smo Django, ali smo pobjegli od toga jer nam "magija" koju sa sobom donosi takav jedan all-in framework nikako nije pasala s ovim principom, previse smo bili "zavezani" za framework, a osnovna poanta ovog principa je da jezgra aplikacije (aplikacijska logika) ne zna za nista oko sebe.

Ne znam jesi li vidio hexagonal architecture clanak od Alistaira Cockburna, mislim da je s tim zapravo krenula ta prica (http://alistair.cockburn.us/Hexagonal+architecture), jako dobor stivo.

Sto se tice tvojeg pitanja, mi radimo nesto slicno prvoj opciji koju si naveo. Kazem nesto slicno zato sto ne lijepimo AR ponasanje na te modele (po nalijepiti vjerojatno mislis da ti modeli naslijede ActiveRecord pa prema tome ih coupleas na framework) nego koristimo repository modele. To se moze poistovjetiti s repository patternom iz DDD (Domain Driven Design) terminologije, ali nikako s repository patternom kojeg vidjas po netu, najcesce u Java implementaciji. Ono sto hocu reci je da to nije klasa koja nasljeduje AR i zove se kao model kojeg mapiras + Repository (dakle, ako u bazu spremas model User, ovo bi se zvalo UserRepository), nego se pokusava nazvati i implementirati nesto smislenije. Ovo je malo tesko objasniti, ali ako pratis screencaste Garya Bernhardta (www.destroyallsoftware.com) to mozes vidjeti na hrpu mjesta. Npr. covjek je trebao perzistirati nekakvu Score klasu, pa je taj repository model nazvao CachedScore (zapravo je bazu koristio kao cache). Zasto bi ovo netko radio, samo smo prebacili coupling s jedne klase na drugu? Ovo radis zato sto je poslovna logika ostala na ovom prvom, PORO modelu. To se onda moze lako i brzo testirati u izolaciji. Za modele koji komuniciraju s bazom ionako moras testirati (ako testiras i to) u integraciji s bazom pa odmah znas da ce ti testovi biti sporiji.

Ovo sto kazes u vezi business layera, mi za to imamo ovo sto Uncle Bob zove interactor, Gary Bernhardt i ostala Ruby ekipa to zovu app logic sloj. Sve sto radis na aplikaciji ide kroz taj sloj, konkretno u web aplikaciji iz controllera ces zvati interactor i predati mu podatke koji mu trebaju. Dobro mjerilo koje spominju ljudi koji promoviraju ovu delivery mechanism/hexagonal arhitekturu je i to da se pitas da li mozes svoju aplikaciju koristiti iz konzole. Teoretski bi trebao moci upaliti konzolu i kroz interactor/app logic sloj raditi sve sto treba na aplikaciji. Onda mozes tvrditi da si decouplean od web frameworka. Kazem teoretski, jer to obicno nije tako... :)

Ovo sve decouplanje nema uvijek smisla ako mene pitas, neki put ti to jednostavno nije potrebno. Situacija kad je taj pristup veliki fail (iz osobnog iskustva) je ako nemas poslovne logike u aplikaciji. Vidim gore spominjes CRUD aplikacije, ako ti treba samo CRUD, ovo je ogroman overkill i definitivno se ne isplati. S druge strane ako ti je app logika kompleksna, ovo svo decouplanje se jako isplati, prvenstveno zato sto mozes testirati sve u izolaciji.

Malo sam oduzio, dosta toga sam vjerojatno i nejasno napisao pa pitaj ako nesto nije jasno. :)

Goran

elVanja

unread,
May 24, 2012, 6:19:32 PM5/24/12
to rub...@googlegroups.com
Bok!
Hvala na opširnom odgovoru :-)

OK, dakle vezano za perzistenciju, tu mi je čini mi se stvar više manje jasna.
Nisam još u svom projektu došao do točke u kojoj bi se odlučio za neki ORM ili drugu opciju, ali je taj dio ionako izdvojen/izoliran u obliku gem-a koji radi sve u memoriji, a koji ću zamjeniti sa nečim konkretnim kad dođe vrijeme. Taj dio priče oko perzistencije ima sigurno još momenata i stvari koje će trebati doraditi ali recimo da mi je taj dio priče na mjestu, a o brzini testova da i ne pričam !!!

Nekoliko resursa na tu temu:
https://github.com/elvanja/gedankenexperiment/tree/master/persistence_decoupling - neka moja razmišljanja na temu, malo zastarjela ali ipak
http://www.confreaks.com/videos/672-rubyconf2011-pure-ruby-gui - priča o cijelom sistemu odvajanja business layera od ostatka svijeta, na zivom primjeru (uncle bob i njegov sin pokazuju jednu ruby app koju su tako napravili), jako fora, a kod za to se može naći na https://github.com/slagyr/cleantracker te https://github.com/slagyr/cleananalytics_rb

Ono što me muči je kako to užičiti u railse. Kod mene je konkretno stvar da imam neki JSON API koji treba svoj administracijski i reporting web.
Railsi bi mi trebali dakle biti neki delivery mehanizam za taj dio priče, odnosno to mi je ideja.
Ali neznam kako pametno napraviti da railsi rade sve sa business layer slojem.

Prva opcija koju spominjem je recimo ovo:
class RailsBusinessObject < BusinessLayer::BusinessObject
  extend ActiveModel::Naming
  include ActiveModel::Conversion

  attr_accessor :persisted

  def initialize(*)
    super
    @persisted = true if @persisted.nil?
  end

  def to_param
    id
  end

  def self.from_param(param)
    find_by_id(param)
  end

  def persisted?
    @persisted
  end
end

I onda na mogu to dalje voziti kroz railse kao da je riječ o normalnom modelu na koji smo navikli (AR, mapper, ...).
To ukljucuje CRUD operacije ali i taj reporting i slicno (dakle nije samo trivijalni CRUD u pitanju).
Ali, taj nacin mi se cini i dalje malo blesav, a i čitajući o SOA arhitekturi, ima smisla da rails dio stvarno bude samo frontend a da sve ide kroz taj API.
Stoga je ideja bila (inspirirano roar gem-om i SOA pričom) da se to zavrti kroz REST, i tu zapinjem :-)

Ta organizacija me muči, gdje šta smjestiti, kako povezati a da bude DRY i slično.

E, hvala na onom linku za hexagonal architecture, obavezno pročitam!
I daj please ako može me uputi na DAS epizodu sa tom CachedScore pričom? (pratim njegove screencaste od nedavno)

Hvala! 

P.S. Možda bi imalo smisla napraviti neku oglednu app, ništa komplicirano, a što bi nam dalo nešto konkretno o čemu možemo pričati...
Pa eto, ako ima zainteresiranih...

Goran Peretin

unread,
May 25, 2012, 12:44:36 AM5/25/12
to rub...@googlegroups.com
Bok,
zasto konkretno te brine kako to uziciti u Railse? Railsi bi trebali biti kao i bilo koji drugi framework. Imas li problem bas s Railsima ili bi taj problem imao i da koristis neki drugi framework?
Ono kako mi to radimo je da web framework pozove metodu (Ili vise njih, ali cilj je da je jedna metoda, inace si mozda fulao razinu apstrakcije) na interactor/app logic sloju s parametrima koje je izvadio iz requesta. Kad ta metoda vrati rezultat, web framework to pretoci u response i vrati nazad.
Cilj je upravo ne raditi ovo sto si napravio u primjeru koda, dakle ne zelis da ti business objekti budu zavezani za framework.

Ne znam jesam dobro skuzio pitanje pa je ovo mozda krivi odgovor. :)

Btw, slazem se za primjer koda/demo app, to bi bilo korisno. DAS epizoda gdje se radi ono sto sam opisao u proslom mailu je #55  https://www.destroyallsoftware.com/screencasts/catalog/sucks-rocks-5-a-bug-and-a-model
Osim te, obavezno "stivo" je #40 Web apps: what to test in isolation. :)

Goran

elVanja

unread,
May 25, 2012, 5:09:43 AM5/25/12
to rub...@googlegroups.com
Ej, 
pa ovo za Railse me muci jer bi htio postici da mogu u istima sa mojim business objektima koristiti sve "helpere" koje railsi nude, recimo, *_path, rute za resurse i slicno.
Ovaj gornji primjer nije zabetonirao rails ponasanje u business objekte, samo sam u samim railsima naljepio potrebno ponasanje da railsi kuze te business objekte na "rails" nacin.
Recimo, BusinessLayer::BusinessObject je implementiran u nekom mom gem-u, dok je gornji kod prisutan samo u railsima (ajmo rec da je dekorator iako koristi nasljeđivanje). Slazem se da se moze bolje to napraviti, ali nije sad bio cilj to već samo ilustrirati tu ideju.

Mozda grijesim u pristupu? Ja nekako brijem da sa tim izdvojenim gemom sa business pravilima imam upravo tu izdvojenu logiku koja mi treba (i koju lako testiram).
I sad me muci kako to najelegantnije uziciti u railse, a da pri tome koliko god mogu iskoristim mehanizme koji u railsima već postoje (sa idejom: zašto da izmišljam toplu vodu).
Vjerojatno nisam skuzio komentar :-)

Nis, kuzim jedino da je tesko ovako "u zraku" pricati o svemu...
Pa ce bit najbolje da smislim neki primjer i bacim na github.
I bit će tako, čim ulovim vremena za sloziti nesto sto koliko toliko ima smisla.

I hvala za pointere na DAS epizode, obavezno pogledam.
Muchas gracias!

Goran Peretin

unread,
May 26, 2012, 1:21:47 AM5/26/12
to rub...@googlegroups.com
Ah sad kuzim.
Nisam siguran kako to u Railsima radi, ono sto bih ja napravio je tretirao svaki taj helper kao vanjski servis te za njega napisao adapter.
Mislim da ne grijesis sto hoces to zapakirati u gem, mene samo zbunio ovaj dio gdje extendas i includeas Rails stvari.

Definitivno bi trebali imati code sample :)
Nema na cemu za filmice!

Pozdrav,
Goran

elVanja

unread,
Jun 10, 2012, 2:38:23 PM6/10/12
to rub...@googlegroups.com
Mali update, koga zanima:
ima i nastavak, za sada samo "teorija" ali bit će valjda i primjera

Također, nešto na tragu ovog o čemu smo pričali:

Borna Novak

unread,
Sep 20, 2012, 4:18:03 PM9/20/12
to rub...@googlegroups.com
Ovaj clanak me progoni od kako sam ga procitao:

http://thedailywtf.com/Articles/The-Mythical-Business-Layer.aspx
Reply all
Reply to author
Forward
0 new messages