Minustakin dojo oli mainio. Lisää jäi kaipaamaan, varsinkin kun
aloimme juuri päässeet kunnolla vauhtiin, kun aika jo loppui.
> eilen oli hauska dojo Tampereella rspecin parissa. Dojossa ei tehty
> Railsia mutta käytetyt BDD-tekniikat liittyvät tietysti Railsiin.
Sinänsä eiliset tekniikat eivät muistaakseni liittyneet mitenkään
Railsiin erityisesti, olkoonkin, että sekä StoryRunner ja RSpec ovat
molemmat hyvin suosittuja noissa ympyröissä. Käsitin ehkä väärin,
mutta siis mitenkään Rails-spesifistä eilinen koodi ei ollut.
Tarinoiden (stories) ja speksien/yksikkötestien erosta: on totta, että
pelkillä tarinoilla voisi periaatteessa pärjätä. Testaamisesta tulisi
tosin vaikeampaa ja hitaampaa, koska tarinoissa joutuu usein
kirjoittamaan enemmän kontekstia, jotta halutun tilanteen voi testata.
Hitaus taas tulee erityisesti siitä, että koska mitään olioita ei
mockata/stubata[1], niin viestit menevät raskaiden alijärjestelmien
lävitse (Rails), tehdään levy-IO:ta, lähetetään sanomia verkon yli
yms.
Mutta on väärin, _just plain wrong_ puhua testaamisesta tai
testikattavuudesta. Se ei ole lainkaan BDD:n tai TDD:n idea, vaan se,
että testien(=speksien!) kirjoittaminen auttaa ajattelemaan sitä,
miten toteutus tulisi tehdä. Ja juuri siinä integrointitestit tai
tarinat auttavat yleensä varsin vähän, koska ne ovat usein
seuraavanlaisia:
...
report = Report.build_from_form_params(params)
report.subfrobnications.should == 42
...
Report.build_from_form_params ei kerro lainkaan, miten
yksinkertaisista avain-arvopareista luodaan mutkikas raportti, jossa
voi olla vaikka mitä analyysejä. Eikä sen kuulukaan näkyä tarinoissa:
siellä kiinnostaa lopputulos, ei miten se saadaan aikaan. Mutta TDD:n
ja BDD:n suurin anti on nimenomaan eri olioiden välisessä viestinnässä
eli käyttäytymisessä; sitä on BDD:n _behaviour_. Lopputulos ei ole
niin kiinnostava, koska se ei opeta meille useinkaan mitään.
Englanniksi keskeinen termi on "interface discovery[2]". BDD:ssä
mock-oliot ovat keskeisessä roolissa, koska niillä kirjoitetaan
odotukset sille, miten speksattava olio viestii ympäristönsä kanssa.
Speksattavaa oliota itseään ei kuitenkaan mockata (tätä sääntöä saa
IMO rikkoa, mutta sitten vasta kun osaa ja ymmärtää säännöt) vaan ne
oliot, joiden kanssa olio viestii. Toisin sanoen silloin kun
kuvittelemme vain kirjoittavamme mukavia mock-odotuksia ja stubeja,
suunnitelemme itse asiassa speksattavan olion kanssa viestivien
olioiden rajapinnan. Ja nyt ao. rajapinta tulee toteutettua sen
mukaan, millaisia rooleja oliolta edellytetään (outside in) sen
sijaan, että meillä olisi ensiksi sopivan tuntuinen rajapinta ja
sitten miettisimme miten sitä käyttämällä jokin joukko palveluita
voidaan toteuttaa (inside out).
Viitteistä: [2] kannattanee lukea ajatuksella läpi ainakin kaksi
kertaa siten, että lukukertojen välillä on väliä. Itselleni
keskeisin ajatus (eli se mitä otsikko sanoo) valkeni kunnolla vasta
toisella kerralla. YMMV.
[1] Mocks Aren't Stubs: http://martinfowler.com/articles/mocksArentStubs.html
[2] Mock Roles, not Objects: http://www.jmock.org/oopsla2004.pdf
PS. TDD/BDD auttaa toki testauksessa sikäli, että sattuneesta syystä
olioiden testattavuus paranee huomattavasti, ja toisaalta myös
kaikille ominaisuuksille tulee kirjoitettua vähintään yksi testi,
jolloin saadaan hyvä alustava testipeite (testausta BDD ei kuitenkaan
korvaa, eikä sen ole tarkoituskaan).
PPS. inside out ei ole aina huono vaihtoehto. Esim.
ohjelmistokirjastoissa voisi kuvitella, että rajapinnasta saadaan
puhtaampi ja intuitiivisempi tekemällä siitä mahdollisimman
ortogonaalinen ja siisti -- tavoite, johon on vaikea päästä jos ko.
olioilta vaadittuja rooleja käytetään vain tietyssä asiayhteydessä
yhdessä sovelluksessa. Mutta hyvien kirjastojen tekeminen onkin wanhan
sanonnan mukaan 3x vaikeampaa kuin sovellusohjelmien.
--
"One day, when he was naughty, Mr Bunnsy looked over the hedge into
Farmer Fred's field and it was full of fresh green lettuces. Mr
Bunnsy, however, was not full of lettuces. This did not seem fair."
-- Terry Pratchett, Mr. Bunnsy Has An Adventure
Ja erityisesti BDD on prosessi, outside in, jossa ulomman kerroksen
speksaaminen mock-olioiden avulla auttaa alemman kerroksen luokkien
rajapinnan kehittämisessä.
Railsin kanssa tämä on suhteellisen suoraviivaista:
1) Valitse tärkein ominaisuus, joka järjestelmässä on toteutettava.
2) Kirjoita tälle ominaisuudelle user story.
3) Toteuta storyn ensimmäinen askel => FAIL
4) Kirjoita askeleen vaatima view spec => FAIL
5) Toteuta näkymään askeleen vaatima toiminnallisuus => view spec
menee läpi, storyn steppi (ehkä) edelleen FAIL
5b) Refaktoroi näkymää tarpeen mukaan. Tämä saattaa vaatia
toiminnallisuuden siirtämistä helpereihin (ja niiden speksaamista).
6) Kirjoita askeleen vaatimalle controller-toiminnolle speksi.
Rajapinta toiminnolle saadaan siitä, mitä näkymän speksissä on
jouduttu mockaamaan.
7) Toteuta toiminnallisuus controlleriin niin, että askeleen vaatimat
controller-speksit menevät läpi.
7b) Refaktoroi
8) Kirjoita askeleessa käytettäville ActiveRecord-luokille speksit,
joiden avulla ne toteuttavat kohdissa 4 ja 6 mockatut rajapinnat.
9) Toteuta edellisen kohdan speksit toteuttava toiminnallisuus.
9b) Refaktoroi tarpeen mukaan.
10) palaa kohtaan kolme ja seuraavaan askeleeseen.
Lisähuomioita:
* kohdat 4-5b, 6-7b ja 8-9b ovat periaatteessa perinteisiä TDD-
iteraatioita.
* joissain askeleissa kohdasta 5 (tai 7) voidaan hypätä suoraan
takaisin kohtaan 3, koska askeleen toteuttaminen vaatii vain muutoksia
näkymään (+ kontrolleriin).
* Olen huomannut, että yo. prosessi auttaa pitämään kontrollerit
laihoina ja siirtämään toiminnallisuutta enemmän Model-tasolle (mikä
on hyvä asia), koska se helpottaa merkittävästi kontrollerien
speksaamista. Eli jos kontrollereja speksatessa tuntuu, että joutuu
tekemään spekseihin oudontuntuisia kiertoteitä ja mockeja, se on usein
merkki siitä, että kontrollerissa on bisneslogiikkaa, joka kuuluu
Model-tasolle.
--
Jarkko Laine
http://jlaine.net
http://dotherightthing.com
http://www.railsecommerce.com
http://odesign.fi
Toi Jarkon "prosessikuvaus" vaikuttaa juuri siltä mitä olen tässä
ollut hakemassa Railsin kanssa devaamiseen. En tiedä sitten tekeekö
muut täällä järjestyksessä V->C->M tai kenties toisin päin, mutta
omaan tarinapohjaiseen lähestymistapaan toi tuntuu järkevältä.
Kiitos kaikille dojo-kävijöille! Se, että tällaiseen sessioon tulee
junamatkan päästä ihmisiä, antaa potkua samanlaisten tempausten
tekemiseen jatkossakin.
BDD-prosessikysymyksessä olen samaa mieltä Edin ja Jarkon kanssa. Tätä
kohtaa Edin kirjoituksessa en kuitenkaan ihan ymmärtänyt:
> [Tarinoissa] kiinnostaa lopputulos, ei miten se saadaan aikaan.
> Mutta TDD:n ja BDD:n suurin anti on nimenomaan eri olioiden
> välisessä viestinnässä eli käyttäytymisessä; sitä on BDD:n
> _behaviour_. Lopputulos ei ole niin kiinnostava, koska se ei opeta
> meille useinkaan mitään.
Kyse on kai siitä, mitä BDD tarkoittaa. Ed taitaa ajatella määritelmää
"BDD is TDD done right." joka on tietenkin oikein, koska sitä
kaikkialla toistetaan. Itse olen kuitenkin mm. Jarkon puheiden
seurauksena alkanut ajatella, että BDD takoittaa lisäksi sitä koko
prosessia, jolla korkean tason vaatimuksista saadaan integrointi- ja
yksikkötestien kautta toimivaa koodia.
Mun mielestä asiat kasvavat tärkeysjärjestyksessä kun mennään
lähemmäksi asiakasta. Tarinat ovat siksi kaikista tärkeimpiä, ja koko
muu prosessi tuottaa tavallaan vain teknisiä päätöksiä.
Vaikka model on kaikista sisimpänä, sen speksit ovat mun mielestä
tärkeimmät yksikköspeksit. Model on nimittäin asiakasta lähellä
toisella tavalla: sovellusalueen ymmärtäminen tulee yleensä
asiakkaalta ja hyvä model pyrkii kuvaamaan sovellusaluetta
mahdollisimman tarkasti.
Disclaimer: Toisin kuin Jarkko ja Ed, mä pystyn käyttämään
päivittäisessä työssäni BDD:tä aika harvoin.
Antti T.
> Kiitos kaikille dojo-kävijöille! Se, että tällaiseen sessioon tulee
> junamatkan päästä ihmisiä, antaa potkua samanlaisten tempausten
> tekemiseen jatkossakin.
Kyllä :)
> > Mutta TDD:n ja BDD:n suurin anti on nimenomaan eri olioiden
> > välisessä viestinnässä eli käyttäytymisessä; sitä on BDD:n
> > _behaviour_. Lopputulos ei ole niin kiinnostava, koska se ei opeta
> > meille useinkaan mitään.
> Kyse on kai siitä, mitä BDD tarkoittaa. Ed taitaa ajatella määritelmää
> "BDD is TDD done right." joka on tietenkin oikein, koska sitä
> kaikkialla toistetaan. Itse olen kuitenkin mm. Jarkon puheiden
Siksi tuo "...suurin anti". Superlatiivin käyttö on ehkä liioittelua,
koska muuten BDD:n näkökulma jää liian suppeaksi.
Antin viittaama korkean tason prosessiajattelu jää kuitenkin usein
BDD:ssä huomiotta, joten huomautus oli paikallaan.
> Mun mielestä asiat kasvavat tärkeysjärjestyksessä kun mennään
> lähemmäksi asiakasta. Tarinat ovat siksi kaikista tärkeimpiä, ja koko
> muu prosessi tuottaa tavallaan vain teknisiä päätöksiä.
No siinä mielessä kyllä. Eli kyse on siitä, ajatellaanko BDD:tä prosessi- vai
suunnittelumenetelmänä (oikeasti se kai on kumpaakin).
> Disclaimer: Toisin kuin Jarkko ja Ed, mä pystyn käyttämään
> päivittäisessä työssäni BDD:tä aika harvoin.
No joo, mutta olet tehnyt sitä yhteenlaskien enemmän kuin minä :)
Janyssehommaloppuuumultakingngngngnn.